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.3.2 JNI层分析 - 图1

图 10-1 MS相关类示意图

其中比较费解的是MyMSC对象。它们有什么用呢?这个问题真是一言难尽。下面通过processDirectory来探寻其中的原因,这回得进入PVMediaScanner的领地了。