On Android init phase we are running init application that uses its init scripts to start all the code system services. We can add a new daemon easily if we are building a ROM by add an empty folder, adding Android.mk file and C/C++ source file.
In this way we can run C/C++ code but what about Java? The problem with Java is the runtime requirement – java code is running inside java virtual machine(JVM) that provides all the functionality and features such as class loading, garbage collector, security manager etc.
So to run Java code we need to create an Android runtime (ART/Dalvik) and thanks to the fact that Android is open source its very easy
If we follow the Android init phase, we find an important process that do the job for us – app_process (called Zygote on android)
The code is located under /frameworks/base/cmds/app_process
We can see from the code that we have an abstract C++ class – AndroidRuntime , we need to derived from and a simple function start() to run
So to call a main function (static void main) in any Java class we need to write the following code:
class AppRuntime : public AndroidRuntime { public: AppRuntime(): mParentDir(NULL) , mClassName(NULL), mClass(NULL), mArgC(0) , mArgV(NULL){} virtual void onStarted() { sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); AndroidRuntime* ar = AndroidRuntime::getRuntime(); ar->callMain(mClassName, mClass, mArgC, mArgV); IPCThreadState::self()->stopProcess(); } const char* mParentDir; const char* mClassName; jclass mClass; int mArgC; const char* const* mArgV; }; } using namespace android; int main(int argc, char* const argv[]) { AppRuntime runtime; runtime.start("com.android.internal.os.TestJava",""); }
We need to build it as a simple c++ application and it will call the static main function in com.android.internal.os.TestJava class (or any other class we specify), we can also send arguments using the second parameter
The Java code can be simple
public class TestJava { public static void main(String argv[]) { IActivityManager am = ActivityManagerNative.getDefault(); Log.i("tag", "test java code"); // You can create intent // Intent in = new Intent("name"); // and use the ActivityManager to start service, activity, broadcast ... }
To use Android Activities, Services etc you need to create a context and as you can see from the comments you can use the ActivityManagerNative class for it
To learn more about ActivityManagerNative see the source code for the command “am” here
You can find the complete code with Andoid.mk file in our github
1 thought on “Creating a Java VM from Native code”
Comments are closed.
How will you run this native service?
If you are using rc files to run this application, How can you resolve the SE Policy issue.
In Android 9.0, am getting a neverallow in following rule
‘allow mynativeservice mynativeservice_tmpfs:file execute’
The description of this never allow is “Assert that, to the extent possible, we’re not loading executable content fromoutside the rootfs or /system partition except for a few whitelisted domains.”