10.3.2 JNI层分析
现在分析MS的JNI层。在Java层中,有三个函数涉及JNI层,它们是:
native_init,这个函数由MediaScanner类的static块调用。
native_setup,这个函数由MediaScanner的构造函数调用。
processDirectory,这个函数由MS扫描文件夹时调用。
分别来分析它们。
1.ative_init函数分析
下面是native_init对应的JNI函数,其代码如下所示:
[—>android_media_MediaScanner.cpp]
static void
android_media_MediaScanner_native_init(JNIEnv*env)
{
jclass clazz;
clazz=env->FindClass("android/media/MediaScanner");
//取得Java中MS类的mNativeContext信息。待会创建的Native对象的指针会保存
//到Java MS对象的mNativeContext变量中。
fields.context=env->GetFieldID(clazz,"mNativeContext","I");
……
}
native_init函数没什么新意,这种把Native对象的指针保存到Java对象中的做法,已经屡见不鲜了。下面看第二个函数native_setup。
2.native_setup函数分析
native_setup对应的JNI函数如下所示:
[—>android_media_MediaScanner.cpp]
android_media_MediaScanner_native_setup(JNIEnv*env,jobject thiz)
{
//创建Native层的MediaScanner对象。
MediaScanner*mp=createMediaScanner();
……
//把mp的指针保存到Java MS对象的mNativeContext中去。
env->SetIntField(thiz,fields.context,(int)mp);
}
//下面的createMediaScanner这个函数将创建一个Native的MS对象。
static MediaScanner*createMediaScanner(){
if BUILD_WITH_FULL_STAGEFRIGHT
char value[PROPERTY_VALUE_MAX];
if(property_get("media.stagefright.enable-scan",value,NULL)
&&(!strcmp(value,"1")||!strcasecmp(value,"true"))){
return new StagefrightMediaScanner;//使用Stagefright的MS。
}
endif
ifndef NO_OPENCORE
return new PVMediaScanner();//使用Opencore的MS,我们会分析这个。
endif
return NULL;
}
native_setup函数将创建一个Native层的MS对象,不过可惜的是,它使用的还是Opencore提供的PVMediaScanner,所以后面不可避免地还会和Opencore“正面交锋”。
3.processDirectory函数分析
来看processDirectory函数,它对应的JNI函数代码如下所示:
[—>android_media_MediaScanner.cpp]
android_media_MediaScanner_processDirectory(JNIEnv*env,jobject thiz,
jstring path,jstring extensions,jobject client)
{
/*
注意上面传入的参数,path为目标文件夹的路径,extensions为MS支持的媒体文件后缀名集合,client为Java中的MediaScannerClient对象。
*/
MediaScannermp=(MediaScanner)env->GetIntField(thiz,fields.context);
const char*pathStr=env->GetStringUTFChars(path,NULL);
const char*extensionsStr=env->GetStringUTFChars(extensions,NULL);
……
//构造一个Native层的MyMediaScannerClient,并使用Java那个Client对象做参数。
//这个Native层的Client简称为MyMSC。
MyMediaScannerClient myClient(env,client);
//调用Native的MS扫描文件夹,并且把Native的MyMSC传进去。mp->processDirectory(pathStr,extensionsStr,myClient,ExceptionCheck,env);
……
env->ReleaseStringUTFChars(path,pathStr);
env->ReleaseStringUTFChars(extensions,extensionsStr);
……
}
processDirectory函数本身倒不难,但又冒出了几个我们之前没有接触过的类型,下面先来认识一下它们。
4.到底有多少种对象?
图10-1展示了MediaScanner所涉及的相关类和它们之间的关系:
为了便于理解,所以将Java和Native层的对象都画于图中了。从上图可知:
Java MS对象通过mNativeContext指向Native的MS对象。
Native的MyMSC对象通过mClient保存Java层的MyMSC对象。
Native的MS对象调用processDirectory函数的时候会使用Native的MyMSC对象。
另外,图中Native MS类的processFile是一个虚函数,需要派生类来实现。
图 10-1 MS相关类示意图
其中比较费解的是MyMSC对象。它们有什么用呢?这个问题真是一言难尽。下面通过processDirectory来探寻其中的原因,这回得进入PVMediaScanner的领地了。