通过前面的几篇文章,已经将接口写到了XXXManagerService里面,下面的两篇博文将介绍怎么把接口的实现写到JNI里。
SystemServer.java
在前面,我提到过SystemServer.java文件。回顾一下,在这个文件中,我们通过
try {
Slog.i(TAG, "radio service");
radioManagerService = new com.android.server.RadioManagerService(context);
ServiceManager.addService(Context.RADIO_MANAGER_SERVICE, radioManagerService);
} catch (Throwable e) {
reportWtf("starting iflytek radio service", e);
}
完成了服务的注册。
现在我们来看一下它的main函数。
public static void main(String[] args) {
//此处省略很多行
System.loadLibrary("android_servers");
Slog.i(TAG, "Entered the Android system server!");
// Initialize native services.
nativeInit();
// This used to be its own separate thread, but now it is
// just the loop we run on the main thread.
ServerThread thr = new ServerThread();
thr.initAndLoop();
}
此处通过System.loadLibrary()这个库函数载入了android_servers这个jni库。这个jni库在哪里呢?在源码中grep一下“android_servers”这个字符串,可以定位到framework/base/services/jni/Android.mk这个文件:
LOCAL_MODULE:= libandroid_servers
看一下它的LOCAL_SRC_FILES:
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_AssetAtlasService.cpp \
com_android_server_ConsumerIrService.cpp \
com_android_server_input_InputApplicationHandle.cpp \
com_android_server_input_InputManagerService.cpp \
com_android_server_input_InputWindowHandle.cpp \
com_android_server_LightsService.cpp \
com_android_server_power_PowerManagerService.cpp \
com_android_server_SerialService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbDeviceManager.cpp \
com_android_server_UsbHostManager.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
com_android_server_location_FlpHardwareProvider.cpp \
com_android_server_connectivity_Vpn.cpp \
onload.cpp
就是由这些文件编译成了libandroid_servers.so。
onload.cpp
java中函数与jni中函数的映射一般有两种方法,一种是通过函数名,也就是在jni函数的函数命中包含java函数所在的完整类名。另外一种就是在JNI_OnLoad()函数中注册。
在java中通过System.loadLibrary()函数载入lib的时候,JNI_OnLoad()函数将被调用。我们看一下这个函数。这个函数在on_load.cpp里面。
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_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_UsbHostManager(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
return JNI_VERSION_1_4;
}
首先它通过全局唯一的JavaVM获取JNIEnv的引用,然后调用一堆register方法。我们跟踪一下其中的一个方法。
int register_android_server_PowerManagerService(JNIEnv* env) {
int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService",
gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
// Callbacks
jclass clazz;
FIND_CLASS(clazz, "com/android/server/power/PowerManagerService");
GET_METHOD_ID(gPowerManagerServiceClassInfo.wakeUpFromNative, clazz,
"wakeUpFromNative", "(J)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.goToSleepFromNative, clazz,
"goToSleepFromNative", "(JI)V");
GET_METHOD_ID(gPowerManagerServiceClassInfo.userActivityFromNative, clazz,
"userActivityFromNative", "(JII)V");
// Initialize
for (int i = 0; i <= USER_ACTIVITY_EVENT_LAST; i++) {
gLastEventTime[i] = LLONG_MIN;
}
gScreenOn = true;
gScreenBright = true;
gPowerManagerServiceObj = NULL;
gPowerModule = NULL;
return 0;
}
在这个函数中,第一步就是注册jni函数:
int res = jniRegisterNativeMethods(env, "com/android/server/power/PowerManagerService", gPowerManagerServiceMethods, NELEM(gPowerManagerServiceMethods));
这个函数的第一个参数是JNIEnv对象,第二个参数是定义native方法的java类的完整类名,第三个参数是一个数组(重要,马上就会讲),第四个参数我也不知道是什么,反正这么写就对了。
我们来看一下gPowerManagerServiceMethods这个数组的定义:
static JNINativeMethod gPowerManagerServiceMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit", "()V",
(void*) nativeInit },
{ "nativeSetPowerState", "(ZZ)V",
(void*) nativeSetPowerState },
{ "nativeAcquireSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeAcquireSuspendBlocker },
{ "nativeReleaseSuspendBlocker", "(Ljava/lang/String;)V",
(void*) nativeReleaseSuspendBlocker },
{ "nativeSetInteractive", "(Z)V",
(void*) nativeSetInteractive },
{ "nativeSetAutoSuspend", "(Z)V",
(void*) nativeSetAutoSuspend },
};
这就是一个二位数组,也就是说,这个数组的每个元素都是一个数组,用来表示java中定义的一个native函数。第一个元素是java中定义的函数名,第二个元素是这个native函数的签名,第三个元素是对应的jni函数的函数指针。
通过这样的一种注册机制,就完成了java函数到jni函数的映射。当调用java中的native函数时,就会执行对应的jni函数。需要注意的是,在gPowerManagerServiceMethods中,必须和java中定义的每一个native函数一一对应,也就是说,一个不能多,一个不能少,不然的话,虽然编译能通过,但是一运行起来,就会崩掉了。