定制Android系统开发之六——系统服务JNI的实现分析

来源:互联网 发布:js实现的简单的小特效 编辑:程序博客网 时间:2024/06/05 17:18

通过前面的几篇文章,已经将接口写到了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函数一一对应,也就是说,一个不能多,一个不能少,不然的话,虽然编译能通过,但是一运行起来,就会崩掉了。

0 0
原创粉丝点击