Skip to content

Commit

Permalink
Merge pull request #1967 from bugsnag/PLAT-11486/ndk-read-primitives
Browse files Browse the repository at this point in the history
NDK read primitives
  • Loading branch information
lemnik authored Jan 31, 2024
2 parents 0be7ef4 + d32ec1a commit 2223c41
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,42 @@ import kotlin.math.min

private const val UTF_REPLACEMENT_CHAR = '\uFFFD'

/**
* Read a value of the C type `int`, not to be confused with `getInt` which will always read
* * a Java `int`.
*/
internal fun ByteBuffer.getNativeInt(): Int = getInt()
internal fun ByteBuffer.getNativeLong(): Long = getLong()

/**
* Read a value of the C type `long`, not to be confused with `getLong` which will always read
* a Java `long`.
*/
internal fun ByteBuffer.getNativeLong(): Long =
if (NativeArch.is32bit) getInt().toLong() else getLong()

/**
* Read a value of type `time_t`, the resolution of the value returned *is not defined*. Some of
* our properties are in seconds, others are in milliseconds.
*/
internal fun ByteBuffer.getNativeTime(): Long =
if (NativeArch.is32bit) getInt().toLong() else getLong()

/**
* Read a value of type `size_t`
*/
internal fun ByteBuffer.getNativeSize(): Long = getNativeLong()

/**
* Read a value of type `bool`
*/
internal fun ByteBuffer.getNativeBool(): Boolean = get().toInt() and 0xff != 0

// -------------------------------------------------------------------------------------------------
// Read functions for fixed-width primitives
// -------------------------------------------------------------------------------------------------

internal fun ByteBuffer.getULong(): ULong = getLong().toULong()
internal fun ByteBuffer.getUInt(): UInt = getInt().toUInt()

/**
* Decode [allocatedByteCount] as a null-terminated sequence of modified UTF-8 bytes. This reads
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.bugsnag.android.ndk

import android.os.Build
import androidx.annotation.VisibleForTesting

internal object NativeArch {
@JvmField
@VisibleForTesting
@Suppress("ObjectPropertyNaming")
var _is32Bit: Boolean? = null

@JvmField
@VisibleForTesting
@Suppress("DEPRECATION")
val supportedAbis: Array<String> = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> Build.SUPPORTED_ABIS
else -> arrayOf(Build.CPU_ABI, Build.CPU_ABI2)
}

val is32bit: Boolean
get() {
var result = _is32Bit
if (result == null) {
result = !supportedAbis.any { it.contains("64") }
_is32Bit = result
}

return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.bugsnag.android.ndk

import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import java.nio.ByteBuffer
import java.nio.ByteOrder

class CPrimitivesTest32Bit {
private val sample32BitData = byteArrayOf(
0x0d, 0, 0, 0, 0, 0, 0, 0, // taken from an event_header (int, int)
0xf4.toByte(), 0x10, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration int64_t
0xa0.toByte(), 0x0f, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration_in_foreground int64_t
0x54, 0x01, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration_ms_offset int64_t
0x54, 0x01, 0, 0, // bsg_app_info.duration_in_foreground_ms_offset time_t
0x01, // bsg_app_info.in_foreground
0x00, // bsg_app_info.is_launching
)

@Before
fun setupArchitecture() {
NativeArch._is32Bit = true
}

@After
fun unsetupArchitecture() {
NativeArch._is32Bit = null
}

@Test
fun test32BitPrimitives() {
val data = ByteBuffer.wrap(sample32BitData)
data.order(ByteOrder.LITTLE_ENDIAN)
assertEquals(13, data.getNativeInt())
assertEquals(0, data.getNativeInt())

assertEquals(4340, data.getLong())
assertEquals(4000, data.getLong())
assertEquals(340, data.getLong())
assertEquals(340, data.getNativeTime())
assertEquals(true, data.getNativeBool())
assertEquals(false, data.getNativeBool())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.bugsnag.android.ndk

import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import java.nio.ByteBuffer
import java.nio.ByteOrder

class CPrimitivesTest64Bit {
private val sample64BitData = byteArrayOf(
0x0d, 0, 0, 0, 0, 0, 0, 0, // taken from an event_header (int, int)
0xf4.toByte(), 0x10, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration int64_t
0xa0.toByte(), 0x0f, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration_in_foreground int64_t
0x54, 0x01, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration_ms_offset int64_t
0x54, 0x01, 0, 0, 0, 0, 0, 0, // bsg_app_info.duration_in_foreground_ms_offset time_t
0x01, // bsg_app_info.in_foreground
0x00, // bsg_app_info.is_launching
)

@Before
fun setupArchitecture() {
NativeArch._is32Bit = false
}

@After
fun unsetupArchitecture() {
NativeArch._is32Bit = null
}

@Test
fun test64BitPrimitives() {
val data = ByteBuffer.wrap(sample64BitData)
data.order(ByteOrder.LITTLE_ENDIAN)
assertEquals(13, data.getNativeInt())
assertEquals(0, data.getNativeInt())

assertEquals(4340, data.getLong())
assertEquals(4000, data.getLong())
assertEquals(340, data.getLong())
assertEquals(340, data.getNativeTime())
assertEquals(true, data.getNativeBool())
assertEquals(false, data.getNativeBool())
}
}
Binary file not shown.

0 comments on commit 2223c41

Please sign in to comment.