In this week, I found a great POC to run a pure Java standalone app (command line tool, no apk) on Android. But what about running a standalone application using JNI (with .so files) on Android like this?
Java app with JNI
Imagine there is a Java program that loads the JNI shared native library to run and use some Android APIs :
if (!version) { LOGE("Unable to get version string"); } else { LOGI("Build Version - %s\n", version); (*env)->ReleaseStringUTFChars(env, buildVersion, version); } (*env)->DeleteLocalRef(env, buildVersion);
return (*env)->NewStringUTF(env, "Hello from JNI ! Compiled with ABI " ABI "."); } // ...
The working directory structure
1 2 3
. ├── Helloworld.java └── hello-jni.c
Compile and deploy
Now we need to compile both the Java and C sources for Android.
Using javac and dx to compile for a jar file which Android can read:
1 2 3 4 5 6 7
export BUILD_DIR=$PWD/build export JARFILE=helloworld.jar export JAVAC_OPTS=-source 1.8 -target 1.8 -cp .:$ANDROID_HOME/platforms/android-30/android.jar # Compile .java to .class javac $JAVAC_OPTS -d $BUILD_DIR/classes Helloworld.java # Convert .class file into a dex file and embedded in a jar file $ANDROID_HOME/build-tools/30.0.2/dx --output=$BUILD_DIR/$JARFILE --dex ./$BUILD_DIR/classes
Cross-compile the C to Android shared native library via NDK:
my_tool(38364) MallocStackLogging: stack logs being written to /private/tmp/stack-logs.38364.103f3a000.my_tool.19n2JH.index my_tool(38364) MallocStackLogging: recording malloc and VM allocation stacks to disk using standard recorder
需要注意的是,在程序退出时,这个调用日志文件会被自动删除:
my_tool(38364) MallocStackLogging: stack logs deleted from /private/tmp/stack-logs.38364.103f3a000.my_tool.19n2JH.index
所以需要将程序在结束时最好 block 住,以便分析日志文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<iostream> staticvoidwait_for_input() { std::cout << "Press Enter to exit." << std::endl; char b[1]; std::cin.read(b, 1); } intmain(int argc, constchar **argv) { auto *p = newint(10); // other codes ... p = nullptr; // leaked // ...
// blocking program for analyzing malloc stack history wait_for_input(); return0; }