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

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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值