« All posts

Mastering Custom C++ Kernels for Edge AI on Android via NDK

A technical look at bypassing Kotlin's abstraction tax for on-device LLMs using JNI, zero-copy buffers, and NPU-aligned C++ kernels via the Android NDK.

As large language models like Gemini Nano begin running directly on Android devices, the managed-memory abstraction that Kotlin and ART provide turns from a convenience into a serious performance liability. The source explains how garbage collection, SIMD alignment requirements, and hardware accelerator access clash during compute-intensive tasks like token generation, and argues for implementing performance-critical 'kernels' in C++ via the NDK instead.

It details how every JNI crossing incurs real costs — context switching, argument marshalling, and safety checks — making coarse-grained delegation (passing large buffer pointers instead of making per-element calls) essential. To avoid costly data copies between the JVM and native layers, the piece recommends direct ByteBuffers combined with GetDirectBufferAddress(), enabling true zero-copy access to large model weights.

The content also frames Google's AICore as a CameraX-like abstraction layer over diverse NPU hardware, offering memory deduplication across apps, seamless model updates, and elevated hardware permissions. It walks through hardware-specific optimization techniques: NEON vectorization on the CPU, minimizing kernel launch overhead on the GPU, and strict byte alignment requirements on the NPU to avoid costly fallbacks to the CPU. Finally, it covers how Kotlin 2.x features like coroutines, callbackFlow, and context receivers help bridge native, blocking C++ kernels with Kotlin's asynchronous, reactive programming model.

For mobile AI engineers, these techniques are becoming essential not just for raw throughput, but for delivering the low-latency, real-time streaming experiences users now expect from on-device AI.