In-depth understanding of Android (5)-analyze JNI and mediascannerjni in Android from MediaScanner
The previous articles introduced the JNI and basic usage in Android. This article summarizes the JNI part by analyzing the JNI instance in the Android source code.
1. Bridge to two different worlds
As we have said before, JNI is like a bridge that closely links Java and the Native world. On the Android platform, without the support of the Native layer, it is hard to implement our system, even virtual machines in Java are implemented through Native.
II. Introduction to the MediaScanner class
MediaScannerr scans multimedia files in android. For example, after mediascanner scans the system memory and SD card files, it loads the scan results to the database. The album name displayed in the list of activity in the Music application is the name of the song album, genre, Song length, and other information are all information in the database that is scanned and finally read in the database.
MediaScanner:
1. MediaScannerService (derived from Service) completes the scan task and puts the scan result into the media database.
2. MediaProvider (ContentProvider-derived), which is used to perform related operation requests on the media library. Generally, it is to write, delete, query, and perform more operations.
3. MediaScannerReceiver receives external scanning requests.
3. MediaScanner registration Analysis
Open MediaScnner. java and you can see
static { System.loadLibrary("media_jni"); native_init(); }The dynamic link library is loaded and the native_init () method is called.
private static native final void native_init();
Open android_media_MediaScanner.cpp and you can see the implementation of native_init ().
// This function gets a field ID, which in turn causes class initialization.// It is called from a static block in MediaScanner, which won't run until the// first time an instance of this class is used.static voidandroid_media_MediaScanner_native_init(JNIEnv *env){ LOGV("native_init"); jclass clazz = env->FindClass(kClassMediaScanner); if (clazz == NULL) { return; } fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); if (fields.context == NULL) { return; }}The above registration method is static registration, but there is also a dynamic registration method.
Java native functions correspond to JNI functions one by one. Therefore, in JNI, this relationship is recorded through the JNINativeMethoid structure. The dynamic registry in android_media_MediaScanner.cpp is as follows.
static JNINativeMethod gMethods[] = { { "processDirectory", "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V", (void *)android_media_MediaScanner_processDirectory }, { "processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", (void *)android_media_MediaScanner_processFile }, { "setLocale", "(Ljava/lang/String;)V", (void *)android_media_MediaScanner_setLocale }, { "extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt }, { "native_init", "()V", (void *)android_media_MediaScanner_native_init }, { "native_setup", "()V", (void *)android_media_MediaScanner_native_setup }, { "native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize },};The JNINativeMethod struct is as follows:
type struct{ const char* name; const char* signature; void* fnPtr;}JNINativeMethod;The first attribute is the name of the native function in Java.
The second attribute is the signature of the parameter and return type.
The third attribute is the name of the Native function.
The AndroidRunTime class provides a registerNativeMethods function to complete registration. The implementation is as follows:
/* * Register native methods using JNI. *//*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods, int numMethods){ return jniRegisterNativeMethods(env, className, gMethods, numMethods);}JniRegisterNativeMethods is a help function provided by the Android platform.
In actual applications, dynamic registration can be completed with only two functions.
jclass clazz = (*env)->FindClass(env, className);(*env)->RegisterNatives(env, clazz, gMethods, numMethods);
When the Java layer is installed with the JNI dynamic library through System. loadLibrary, a function called JNI_OnLoad in the library will be searched. If yes, call it, and dynamic registration is done here.
jint JNI_OnLoad(JavaVM* vm, void* reserved){ JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed\n"); goto bail; } assert(env != NULL); if (register_android_media_MediaPlayer(env) < 0) { LOGE("ERROR: MediaPlayer native registration failed\n"); goto bail; } if (register_android_media_MediaRecorder(env) < 0) { LOGE("ERROR: MediaRecorder native registration failed\n"); goto bail; } if (register_android_media_MediaScanner(env) < 0) { LOGE("ERROR: MediaScanner native registration failed\n"); goto bail; } if (register_android_media_MediaMetadataRetriever(env) < 0) { LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); goto bail; } if (register_android_media_AmrInputStream(env) < 0) { LOGE("ERROR: AmrInputStream native registration failed\n"); goto bail; } if (register_android_media_ResampleInputStream(env) < 0) { LOGE("ERROR: ResampleInputStream native registration failed\n"); goto bail; } if (register_android_media_MediaProfiles(env) < 0) { LOGE("ERROR: MediaProfiles native registration failed"); goto bail; } if (register_android_mtp_MtpDatabase(env) < 0) { LOGE("ERROR: MtpDatabase native registration failed"); goto bail; } if (register_android_mtp_MtpDevice(env) < 0) { LOGE("ERROR: MtpDevice native registration failed"); goto bail; } if (register_android_mtp_MtpServer(env) < 0) { LOGE("ERROR: MtpServer native registration failed"); goto bail; } /* success -- return valid version number */ result = JNI_VERSION_1_4;bail: return result;}