# Building and using a locally-modified version of JNA

Java Native Access is an important dependency for the Application Services components on Android, as it provides the low-level interface from the JVM into the natively-compiled Rust code.

If you need to work with a locally-modified version of JNA (e.g. to investigate an apparent JNA bug) then you may find these notes helpful.

The JNA docs do have an Android Development Environment guide that is a good starting point, but the instructions did not work for me and appear a little out of date. Here are the steps that worked for me:

• Modify your environment to specify $NDK_PLATFORM, and to ensure the Android NDK tools for each target platform are in your $PATH. On my Mac with Android Studio the config was as follows:

export NDK_ROOT="$HOME/Library/Android/sdk/ndk/25.2.9519653" export NDK_PLATFORM="$NDK_ROOT/platforms/android-25"
export PATH="$PATH:$NDK_ROOT/toolchains/llvm/prebuilt/darwin-x86_64/bin"
export PATH="$PATH:$NDK_ROOT/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin"
export PATH="$PATH:$NDK_ROOT/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/bin"
export PATH="$PATH:$NDK_ROOT/toolchains/x86-4.9/prebuilt/darwin-x86_64/bin"
export PATH="$PATH:$NDK_ROOT/toolchains/x86_64-4.9/prebuilt/darwin-x86_64/bin"


You will probably need to tweak the paths and version numbers based on your operating system and the details of how you installed the Android NDK.

• Install the ant build tool (using brew install ant worked for me).

• Checkout the JNA source from Github. Try doing a basic build via ant dist and ant test. This won't build for Android but will test the rest of the tooling.

• Adjust ./native/Makefile for compatibility with your Android NSK install. Here's what I had to do for mine:

• Adjust the $CC variable to use clang instead of gcc: CC=aarch64-linux-android21-clang. • Adjust thd $CCP variable to use the version from your system: CPP=cpp.
• Add -landroid -llog to the list of libraries to link against in \$LIBS.
• Build the JNA native libraries for the target platforms of interest:

• ant -Dos.prefix=android-aarch64
• ant -Dos.prefix=android-armv7
• ant -Dos.prefix=android-x86
• ant -Dos.prefix=android-x86-64
• Package the newly-built native libraries into a JAR/AAR using ant dist. This should produce ./dist/jna.aar.

• Configure build.gradle for the consuming application to use the locally-built JNA artifact:

// Tell gradle where to look for local artifacts.
repositories {
flatDir {
dirs "/PATH/TO/YOUR/CHECKOUT/OF/jna/dist"
}
}

// Tell gradle to exclude the published version of JNA.
configurations {
implementation {
exclude group: "net.java.dev.jna", module:"jna"
}
}

// Take a direct dependency on the local JNA AAR.
dependencies {
implementation name: "jna", ext: "aar"
}

• Rebuild and run your consuming application, and it should be using the locally-built JNA!

If you're trying to debug some unexpected JNA behaviour (and if you favour old-school printf-style debugging) then you can this code snippet to print to the Android log from the compiled native code:

#ifdef __ANDROID__
#include <android/log.h>
#define HACKY_ANDROID_LOG(...) __android_log_print(ANDROID_LOG_VERBOSE, "HACKY-DEBUGGING-FOR-ALL", __VA_ARGS__)
#else
#define HACKY_ANDROID_LOG(MSG)
#endif

HACKY_ANDROID_LOG("this will go to the android logcat output");
HACKY_ANDROID_LOG("it accepts printf-style format sequences, like this: %d", 42);