Establish native Linux ARM64 Android CI and verification gates (#94)
This commit is contained in:
1 parent
1abd75282e
commit
8fa187ab8e
29 files changed
+1862
-56
No files matched your search
@@ -12,7 +12,7 @@ android {
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.minSdk.get().toInt()
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a", "x86_64") }
|
||||
ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") }
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
@@ -22,12 +22,17 @@ android {
|
||||
lint {
|
||||
abortOnError = true
|
||||
warningsAsErrors = true
|
||||
// The user scoped this milestone to ARM Android; x86 ChromeOS is excluded.
|
||||
disable += "ChromeOsAbiSupport"
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(25)
|
||||
compilerOptions { jvmTarget.set(JvmTarget.JVM_17) }
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
allWarningsAsErrors.set(true)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -73,6 +78,12 @@ androidComponents.onVariants { variant ->
|
||||
val nativeOutput = layout.buildDirectory.dir("generated/native/$name/jniLibs")
|
||||
val rawBindings = layout.buildDirectory.dir("generated/bindings-raw/$name")
|
||||
val bindings = layout.buildDirectory.dir("generated/bindings/$name")
|
||||
val rustFlags = listOf(
|
||||
"-D warnings",
|
||||
"-C link-arg=-Wl,-z,max-page-size=16384",
|
||||
"-C link-arg=-Wl,-z,common-page-size=16384",
|
||||
"-C link-arg=-Wl,--build-id=sha1"
|
||||
).joinToString(" ")
|
||||
val native = tasks.register<Exec>("build${title}Rust") {
|
||||
dependsOn(checkRustToolchain)
|
||||
workingDir = workspace
|
||||
@@ -81,22 +92,33 @@ androidComponents.onVariants { variant ->
|
||||
inputs.property("cargoNdk", libs.versions.cargoNdk.get())
|
||||
inputs.property("ndkVersion", libs.versions.ndk.get())
|
||||
inputs.property("minSdk", libs.versions.minSdk.get())
|
||||
inputs.property("rustFlags", rustFlags)
|
||||
inputs.property("abis", listOf("arm64-v8a", "armeabi-v7a"))
|
||||
inputs.property("releaseDebug", "2")
|
||||
inputs.property(
|
||||
"devDebug",
|
||||
providers.environmentVariable("CARGO_PROFILE_DEV_DEBUG").orElse("cargo-default")
|
||||
)
|
||||
inputs.property(
|
||||
"incremental",
|
||||
providers.environmentVariable("CARGO_INCREMENTAL").orElse("cargo-default")
|
||||
)
|
||||
inputs.property(
|
||||
"cargoTargetDirectory",
|
||||
providers.environmentVariable("CARGO_TARGET_DIR").orElse("workspace-default")
|
||||
)
|
||||
outputs.dir(rawNative)
|
||||
environment("RUSTUP_TOOLCHAIN", rustVersion)
|
||||
environment("RUSTC", rustcExecutable.get())
|
||||
environment("ANDROID_NDK_HOME", ndkDirectory.get().asFile.absolutePath)
|
||||
environment("ANDROID_HOME", sdkDirectory.get().asFile.absolutePath)
|
||||
environment(
|
||||
"RUSTFLAGS",
|
||||
"-D warnings -C link-arg=-Wl,-z,max-page-size=16384 -C link-arg=-Wl,-z,common-page-size=16384"
|
||||
)
|
||||
environment("RUSTFLAGS", rustFlags)
|
||||
environment("CARGO_PROFILE_RELEASE_DEBUG", "2")
|
||||
commandLine(
|
||||
listOf(
|
||||
cargoExecutable.get(), "+$rustVersion", "ndk",
|
||||
"--target", "arm64-v8a",
|
||||
"--target", "armeabi-v7a",
|
||||
"--target", "x86_64",
|
||||
"--platform", libs.versions.minSdk.get(),
|
||||
"--output-dir", rawNative.get().asFile.absolutePath,
|
||||
"build", "--locked", "--package", "ironstorage-android", "--lib"
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package de.rfc1437.ironstorage.bridge
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import de.rfc1437.ironstorage.bridge.generated.MobileShellState
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class NativeLoadPerformanceTest {
|
||||
@Test
|
||||
fun reportsNativeLoadAndFirstRustFixtureWithoutSecretData() {
|
||||
val instrumentation = InstrumentationRegistry.getInstrumentation()
|
||||
val runtime = NativeRuntime(instrumentation.targetContext)
|
||||
val started = SystemClock.elapsedRealtimeNanos()
|
||||
val shell = runtime.fixture(MobileShellState.EMPTY)
|
||||
val elapsed = SystemClock.elapsedRealtimeNanos() - started
|
||||
assertTrue(elapsed > 0)
|
||||
assertEquals(5, shell.pages.size)
|
||||
instrumentation.sendStatus(
|
||||
0,
|
||||
Bundle().apply { putLong("ironstorage_native_load_ns", elapsed) }
|
||||
)
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -14,6 +14,7 @@ import de.rfc1437.ironstorage.bridge.generated.MobileTab
|
||||
import de.rfc1437.ironstorage.bridge.generated.UniffiRustCallStatus
|
||||
import de.rfc1437.ironstorage.bridge.generated.uniffiTraitInterfaceCall
|
||||
import java.io.File
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
@@ -102,12 +103,17 @@ class NativeRuntimeTest {
|
||||
@Test
|
||||
fun missingLibraryAndUnsupportedAbiFailBeforeEnteringRust() {
|
||||
val abiFailure = assertThrows(NativeBridgeException::class.java) {
|
||||
NativeRuntime.supportedAbi(listOf("unsupported-fixture-abi"))
|
||||
NativeRuntime.supportedAbi(listOf("x86_64", "unsupported-fixture-abi"))
|
||||
}
|
||||
assertEquals(NativeFailureKind.UnsupportedAbi, abiFailure.kind)
|
||||
assertEquals("arm64-v8a", NativeRuntime.supportedAbi(listOf("x86_64", "arm64-v8a")))
|
||||
val packageFile = File.createTempFile("native-empty-package", ".apk", context.cacheDir)
|
||||
try {
|
||||
ZipOutputStream(packageFile.outputStream()).close()
|
||||
ZipOutputStream(packageFile.outputStream()).use { archive ->
|
||||
// API 26 rejects a ZIP with no entries; keep this valid package free of native code.
|
||||
archive.putNextEntry(ZipEntry("non-native-fixture"))
|
||||
archive.closeEntry()
|
||||
}
|
||||
val info = ApplicationInfo(context.applicationInfo).apply {
|
||||
sourceDir = packageFile.absolutePath
|
||||
splitSourceDirs = null
|
||||
|
||||
@@ -85,7 +85,7 @@ class NativeRuntime(context: Context) {
|
||||
private const val LIBRARY_FILE = "libironstorage_android.so"
|
||||
|
||||
internal fun supportedAbi(deviceAbis: List<String>): String =
|
||||
deviceAbis.firstOrNull { it in setOf("arm64-v8a", "armeabi-v7a", "x86_64") }
|
||||
deviceAbis.firstOrNull { it in setOf("arm64-v8a", "armeabi-v7a") }
|
||||
?: throw NativeBridgeException(NativeFailureKind.UnsupportedAbi)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user