Java框架层中有很多地方使用JNI机制,每一个部分的框架层代码,都可能有与之对应的JNI库。先了解Java框架层的组成,继续看一下JNI在框架层中的使用。
Java框架层的组成
Java框架层的实体内容,主要分三个部分:
- java框架库:framework.jar
- java服务库:services.jar
- 资源包:framework-res.apk
framework.jar是系统的核心,其中定义并实现了Android中大多数的Java类,也提供作为标准接口的框架层API。
services.jar包含了一些复杂的服务,为框架层提供一部分功能的实现。服务库也具有Java框架层中一个主要的程序入口。进入此入口运行后,服务库将形成Java框架层一个在后台长时间运行的程序。
framework-res.apk,其中没有Java代码,基本由纯资源组成的包。资源包是Java框架层唯一的包含资源和工程描述文件的包,框架层所有的资源和组件定义均包含在资源包中。
Java框架层的3个库之间耦合性比较强,具有相互依赖,主要看看framework.jar和services.jar中的JNI使用情况。
1. framework.jar
框架库主要分布在frameworks/base的以下目录:
- core:Android核心包。
- graphics:图形处理包。
- opengl:Android OpenGL 3D实现。
- telephony:电话部分。
- media:多媒体和音频。
- wifi:无线局域网相关。
其中core是主要的目录,实现了Android系统所定义的大部分Java类。其中core目录下,jni包是同目录下java包中对应的JNI实现。我们的Log相关的Java类和JNI实现,就分别在这两个包中。上一篇写过frameworks/base/core/jni目录下的JNI实现,会生成一个libandroid_runtiem.so的动态库。并且启动zygote时,会实例化其中的AndroidRuntime.cpp类,对其中的JNI函数进行注册,所以core,media(部分),opengl等相关的JNI会在系统启动的时候进行注册。
2. services.jar
Android中Java框架层服务库部分的目录为:frameworks/base/services/java,同级目录下的Android.mk会将这个包编译,生成services.jar。
其中frameworks/base/services/java/com/android/server中只包含一个入口部分的类,其他的类在frameworks/base/services/core/java/com/android/server目录下。
services.jar中的JNI实现在frameworks/base/service/core/jni目录下,其中的内容生成名称为libandroid_servers.so的动态库,为services.jar提供本地支持。这个库在frameworks/base/services/java/SystemServer.java类中被加载。
此外,Android框架层还包含了其他JNI实现库。例如多媒体另一部分的JNI实现在frameworks/base/media/jni这个目录下(一部分在libandroid_runtime.so中),生成libmedia_jni.so,它也是为framework.jar提供部分的本地支持(media目录划在了框架层的framework.jar部分)。这个动态库是在frameworks/base/media/java/android/media/MediaPlayer.java类中加载,加载本地库后,会执行其中的JNI_OnLoad()函数,进行JNI方法的注册。也就是说,它是在我们程序中使用的时候进行加载的,谷歌工程师把它们放在这,或许是因为只在启动的时候注册必要的部分,其他部分在使用时随着加载过程进行动态注册。
例如:
frameworks/base/service/core/jni/onload.cpp中的JNI_OnLoad()函数:
extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("GetEnv failed!");
return result;
}
ALOG_ASSERT(env, "Could not retrieve the env!");
register_android_server_ActivityManagerService(env);
register_android_server_PowerManagerService(env);
register_android_server_SerialService(env);
register_android_server_InputApplicationHandle(env);
register_android_server_InputWindowHandle(env);
register_android_server_InputManager(env);
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_UsbDeviceManager(env);
register_android_server_UsbMidiDevice(env);
register_android_server_UsbHostManager(env);
register_android_server_vr_VrManagerService(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GnssLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
register_android_server_tv_TvUinputBridge(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_Watchdog(env);
register_android_server_HardwarePropertiesManagerService(env);
return JNI_VERSION_1_4;
}
frameworks/base/media/jni/android_media_MediaPlayer.cpp中的JNI_OnLoad()函数:
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
if (register_android_media_ImageWriter(env) != JNI_OK) {
ALOGE("ERROR: ImageWriter native registration failed");
goto bail;
}
if (register_android_media_ImageReader(env) < 0) {
ALOGE("ERROR: ImageReader native registration failed");
goto bail;
}
if (register_android_media_MediaPlayer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
}
// 省略
/* success -- return valid version number */
result = JNI_VERSION_1_4;
bail:
return result;
}
当Java层调用System.loadLibrary()方法加载动态函数库时,执行JNI_OnLoad()函数,完成各个JNI方法的动态注册,这和前面Log相关的JNI方法注册稍有不同。