Skip to main content

Android Performance

Finding

The Android application migration candidate passes on the audited Pixel 9 Pro Fold. Three independent, non-debuggable release AndroidX Microbenchmark invocations ran 30 measurements each against the exact packaged boundary used by the application migration. The authored SDK facade is faster than the released Kotlin/Bouncy Castle implementation for every matched median and p95.

The 64-KiB migration result has substantial margin:

  • encryption is 27.55% faster at the median and 43.07% faster at p95; and
  • decryption is 29.54% faster at the median and 52.06% faster at p95.

The gate requires at most 1.25x legacy latency. The audited Pixel therefore passes with margin, but one additional production Android device is still required before the two-device gate closes.

Audit identity

FieldValue
Date2026-07-27
Device classPixel 9 Pro Fold
OSAndroid API 37, userdebug device build
Benchmark targetnon-debuggable release AndroidX Benchmark
Architecturearm64
Semantic AAR source27e135eac626951507bdeb623d7c56cf6fe88216
Benchmark harness4a2989372af41e43d40c793f8674997336c83a58
Legacy Android baselinea5edacccee3d62757a08dadeceeb3d29a4f4eac6
Independent invocations3, with 30 measurements each
Configurationcompilation mode speed, profiling disabled

Legacy and SDK measurements ran as deterministic adjacent pairs to limit ordering and thermal bias. Values below are the median of the three run medians; p95 is the median of the three run p95 values. Negative deltas mean the SDK is faster.

Released implementation comparison

OperationLegacy median nsSDK median nsMedian deltaLegacy p95 nsSDK p95 nsp95 delta
Import identity124,37586,495-30.46%187,016185,094-1.03%
NIP-44 encrypt, 32 B208,89760,070-71.24%338,28560,760-82.04%
NIP-44 decrypt, 32 B206,38858,397-71.71%306,49158,850-80.80%
NIP-44 encrypt, 1,024 B223,63569,465-68.94%272,37089,512-67.14%
NIP-44 decrypt, 1,024 B342,75585,990-74.91%528,42987,162-83.51%
NIP-44 encrypt, 64,000 B1,263,063915,071-27.55%2,492,8021,419,039-43.07%
NIP-44 decrypt, 64,000 B1,180,058831,496-29.54%2,638,0781,264,750-52.06%
Sign NIP-01 event596,576250,899-57.94%896,739265,611-70.38%
Parse and verify NIP-01 event491,143195,887-60.12%681,859214,374-68.56%
Create durable NIP-59 gift wrap2,067,755729,211-64.73%3,264,869770,049-76.41%
Authenticate and unwrap NIP-591,758,557497,447-71.71%4,297,929526,557-87.75%

Every SDK median and p95 is faster than its paired legacy measurement. Attachment streaming, which has no legacy equivalent, measured 1,247,319 ns at the median, 1,337,767 ns at p95, and 668 allocations for 64,000 bytes.

One invocation triggered AndroidX Benchmark's automatic 90-second thermal recovery. All 30 measurements then completed, but the cross-run variation confirms that these values remain descriptive until unchanged-revision and production-device calibration is complete.

Layer isolation

The 64-KiB measurements identify where time is spent:

LayerEncrypt median nsDecrypt median nsPurpose
Native Rust552,598540,325Crypto and Rust allocation floor
Generic string FFI round trip950,105n/aEchoes a 64-KiB string across UniFFI/JNA
Generic string FFI consume/produce641,840 consume303,735 produceIsolates one-way conversion cost
Authored JNI facade915,071831,496Public SDK call with byte-array bridge
Released Kotlin1,263,0631,180,058Adjacent migration baseline

The earlier regression was boundary cost, not the native cipher. The authored Android path now sends UTF-8 byte arrays through a narrow JNI bridge and constructs the Kotlin value once, while generic UniFFI remains the portable JVM path. Absolute values moved with device state between audits, which is why the decision uses paired SDK/legacy results from the same invocation.

Allocation result

AndroidX allocation medians also favor the authored facade:

OperationLegacy allocationsSDK allocationsDelta
Import identity1,785.0201.9-88.69%
NIP-44 encrypt, 32 B2,594.07.0-99.73%
NIP-44 decrypt, 32 B2,581.05.0-99.81%
NIP-44 encrypt, 64,000 B2,594.17.0-99.73%
NIP-44 decrypt, 64,000 B2,582.06.0-99.77%
Sign NIP-01 event5,415.0384.6-92.90%
Parse and verify event4,292.0374.5-91.27%
Create gift wrap16,245.8499.0-96.93%
Unwrap13,881.0358.0-97.42%

These are benchmark allocation counts, not heap-retention or PSS measurements.

Developer guidance

  • Import one SoftchatIdentity per signed-in session and retain its cached publicKey.
  • Run crypto, event verification, wrapping, and large parsing away from the Android main thread.
  • Use the authored com.softcose.softchat.protocol API. Do not call the JNI bridge or generated UniFFI package directly.
  • Pass complete bounded messages. Repeated small FFI calls lose the advantage of the coarse facade.
  • Keep Room, WorkManager, HTTP, sockets, and file lifecycle in the Android layer. Persist a delivery intent before sending it through a relay session.
  • Ship the release AAR with its consumer rules and symbols. The verified package contains arm64-v8a and x86_64 libraries with 16-KiB page alignment and passes an R8-minified external consumer.

Remaining Android work

  • Reproduce median and p95 on one additional production-build device.
  • Isolate SDK and legacy PSS, startup, energy, and sustained thermal behavior.
  • Calibrate five unchanged-revision runs before turning descriptive numbers into automatic device-class gates.
  • Exercise Room persistence, process death, migration, quarantine, resume, and rollback through an application integration.

Run the complete build, install, three-run collection, and sanitized aggregate with the commands in the Performance Benchmarks source guide.