- While a 100% pure Java solution is nice in principle, realistically, for an application, there are situations in which you will want to write or use code written in another language. Such code is usually called native code.
- There are three obvious reasons why that may be the right choice:
- You have substantial amounts of tested and debugged code available in that language. Porting the code to the Java programming language would be time consuming, and the resulting code would need to be tested and debugged again.
- Your application requires access to system features or devices, and using Java technology would be cumbersome at best, or impossible at worst.
- Maximizing the speed of the code is essential. For example, the task may be time critical, or it may be code that is used so often that optimizing it has a big payoff. This is actually the least plausible reason. With just-in-time (JIT) compilation, intensive computations coded in the Java programming language are not that much slower than compiled C code.
- In particular, the native code library you are calling must exist on the client machine, and it must work with the client machine architecture.
- In particular, the native code library you are calling must exist on the client machine, and it must work with the client machine architecture. To make calling native methods possible, Java technology comes with hooks for working with system libraries, and the JDK has a few tools to relieve some (but not all) of the programming tedium.
- Keep this in mind: if you use native methods, you lose portability.
- JNI = Java Native Interface
- JNI does not support any direct correspondence between Java platform classes and those in C++.
- The java programming language uses the keyword native for a native method, and you will obviously need to encapsulate the printf function in a class.
- Require a three-step process:
- Genreate a C stub for a function that translate between the Java call and the actual C function. The stub does this translation by taking parameter information off the virtual machine stack and passing it to the compiled C function.
- Create a special shared library and export the stub from it.
- Use a special method, called system.loadLibrary, to tell the Java runtime environment to load library from step 2.
-
1 static void android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) 2 { 3 LOGV("start"); 4 sp<MediaPlayer> mp = getMediaPlayer(env, thiz); 5 if (mp == NULL ) { 6 jniThrowException(env, "java/lang/IllegalStateException", NULL); 7 return; 8 } 9 process_media_player_call( env, thiz, mp->start(), NULL, NULL ); 10 } 11 static JNINativeMethod gMethods[] = { 12 {"_start", "()V", (void *)android_media_MediaPlayer_start}, 13 {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, 14 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, 15 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, 16 {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, 17 {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, 18 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, 19 }; 20 static const char* const kClassPathName = "android/media/MediaPlayer"; 21 // This function only registers the native methods 22 static int register_android_media_MediaPlayer(JNIEnv *env) 23 { 24 return AndroidRuntime::registerNativeMethods(env,"android/media/MediaPlayer", gMethods, NELEM(gMethods)); 25 }
- The native keyword alerts the compiler that the method will be defined externally. Of course, native methods will contain no code in the Java programming language, and the method header is followed immediately by a terminating semicolon. This means, as you saw in the example above, native method declarations look similar to abstract method declarations.
- Native methods can be both static and non-static.
- You have a C or C++ program and would like to make a few calls to Java code, perhaps because the Java code is easier to program. Of course, you know how to call the Java methods. But you still need to add the Java virtual machine to your program so that the Java code can be interpreted. The so-called invocation API enables you to embed the Java virtual machine into a C or C++ program. Here is the minimal code that you need to initialize a virtual machine.
- Calling method created by Java:
- define parameter for JavaVM option, JavaVMInitArgs, jclass, jobjectArrary, jmethodID and so on;
- Create JavaVM by passing VM_arguments;
- Create class that has the API you want; 3. Call methods defined in class. 4. Destroy JavaVM.
- Calling method created by C or C++:
- Define a class with native method in Java;
- In Java class, using system.loadLibrary(“ClassName”) to load library implemented by C;
- Implemented C library by implementing native method defined in Java;
1 JNIEXPORT jobject JNICALL Java_Win32RegKey_getValue(JNIEnv* env,jobject this_obj,jobject name)
- In C code, calling method defined in Java:
- Get object class;
- Get the method ID;
- Call the method by passing object of class and method ID.
-
1 namespace android { 2 extern "C" status_t system_init() 3 { 4 LOGI("Entered system_init()"); 5 sp<ProcessState> proc(ProcessState::self()); 6 sp<IServiceManager> sm = defaultServiceManager(); 7 LOGI("ServiceManager: %p ", sm.get()); 8 sp<GrimReaper> grim = new GrimReaper(); 9 sm->asBinder()->linkToDeath(grim, grim.get(), 0); 10 11 char propBuf[PROPERTY_VALUE_MAX]; 12 property_get("system_init.startsurfaceflinger", propBuf, "1"); 13 if (strcmp(propBuf, "1") == 0) { 14 // Start the SurfaceFlinger 15 SurfaceFlinger::instantiate(); 16 } 17 property_get("system_init.startsensorservice", propBuf, "1"); 18 if (strcmp(propBuf, "1") == 0) { 19 // Start the sensor service 20 SensorService::instantiate(); 21 } 22 LOGI("System server: starting Android runtime. "); 23 AndroidRuntime* runtime = AndroidRuntime::getRuntime(); 24 25 LOGI("System server: starting Android services. "); 26 JNIEnv* env = runtime->getJNIEnv(); 27 if (env == NULL) { return UNKNOWN_ERROR; 28 } 29 jclass clazz = env->FindClass("com/android/server/SystemServer"); 30 if (clazz == NULL) { 31 return UNKNOWN_ERROR; 32 } 33 jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V"); 34 if (methodId == NULL) { 35 return UNKNOWN_ERROR; 36 } 37 env->CallStaticVoidMethod(clazz, methodId); //C code call method of java 38 LOGI("System server: entering thread pool. "); 39 ProcessState::self()->startThreadPool(); 40 IPCThreadState::self()->joinThreadPool(); 41 LOGI("System server: exiting thread pool. "); 42 return NO_ERROR; 43 } 44 static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz) //native method by C 45 { 46 system_init(); 47 } 48 /** 49 * JNI registration. 50 */ 51 static JNINativeMethod gMethods[] = { /** name, signature, funcPtr */ 52 { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 }, 53 }; 54 int register_android_server_SystemServer(JNIEnv* env) 55 { 56 return jniRegisterNativeMethods(env, "com/android/server/SystemServer",gMethods, NELEM(gMethods)); 57 } 58 59 };