Android JNI使用简介

来源:互联网 发布:mac版photoshop快捷键 编辑:程序博客网 时间:2024/06/06 16:43

JNI — Java Native Interface , 允许Java 语言和其它语言进行通信。在安卓系统中主要用于framework层,主要有两种方式:

(1)第一种方式:以frameworks/base/services/java/com/android/server/SystemServer.java为例:

Java文件中需要先声明native方法

/**     * Start the sensor service.     */    private static native void startSensorService();

然后是方法的具体调用:

private void startBootstrapServices() {    ......    startSensorService();}public static void main(String[] args) {    new SystemServer().run();}    private void run() {     ......     // Initialize native services.     System.loadLibrary("android_servers");     ......     startBootstrapServices();}

run()方法中加载了libandroid_servers.so库,执行JNI_Onload()函数(在JNI_Onload()函数中注册JNI本地函数)。

libandroid_servers.so文件的生成是在frameworks/base/services/Android.mk文件中定义的:

# native library# =============================================================include $(CLEAR_VARS)LOCAL_SRC_FILES :=LOCAL_SHARED_LIBRARIES :=# include all the jni subdirs to collect their sourcesinclude $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPESLOCAL_MODULE:= libandroid_serversinclude $(BUILD_SHARED_LIBRARY)


接下来具体看一下frameworks/base/services/core/jni/Android.mk的内容:

LOCAL_SRC_FILES += \    $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \    $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \    $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \    $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \    ......    $(LOCAL_REL_DIR)/onload.cppLOCAL_C_INCLUDES += \    $(JNI_H_INCLUDE) \    frameworks/base/services \    frameworks/base/libs \    frameworks/base/libs/hwui \    ......LOCAL_SHARED_LIBRARIES += \    libandroid_runtime \    libandroidfw \    libbinder \    libcutils     ......


我们可以看到在这个mk文件中引入了很多相关的库文件和cpp文件,这些文件中的方法会与JAVA中的本地方法关联起来。我们前面提到了要在JNI_Onload()函数中注册JNI的本地函数,这个JNI_OnLoad()方法就在onload.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_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_SystemServer(env);    ......    return JNI_VERSION_1_4;}

在这个方法中需要先确定JNI的版本是否为JNI_VERSION_1_4并获取JNI接口函数的指针,这些操作完成后就开始通过register_android_server_~()方法将本地方法映射到libandroid_server.so库中相应的JNI本地函数上。下面我们来看看com_android_server_SystemServer.cpp中的register_android_server_SystemServer()方法。

static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {    char propBuf[PROPERTY_VALUE_MAX];    property_get("system_init.startsensorservice", propBuf, "1");    ......}/* * JNI registration. */static const JNINativeMethod gMethods[] = {    /* name, signature, funcPtr */    { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },};int register_android_server_SystemServer(JNIEnv* env){    return jniRegisterNativeMethods(env, "com/android/server/SystemServer",            gMethods, NELEM(gMethods));}

jniRegisterNativeMethods()方法将指定类的本地方法映射到JNI的本地函数上,即SystemServer.java中的startSensorService对应的是此cpp文件中的android_server_SystemServer_startSensorService()方法,这里利用了方法名和方法签名可以唯一确定一个函数。



(2)第二种方式:以frameworks/base/core/java/com/android/internal/os/RuntimeInit.java为例:

第一步:声明对应的本地方法:

private static final native void nativeZygoteInit();private static final native void nativeFinishInit();private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);

第二步:具体调用:

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)            throws ZygoteInit.MethodAndArgsCaller {    ......    nativeZygoteInit();}

从第一种方式中我们知道需要进行注册才能使Java本地方法映射到JNI的本地方法中,这里的第二种方式就是注册的过程有些改变。

本地方法的注册是在frameworks/base/core/jni/AndroidRuntime.cpp文件中

static const RegJNIRec gRegJNI[] = {    REG_JNI(register_com_android_internal_os_RuntimeInit),    REG_JNI(register_android_os_SystemClock),    REG_JNI(register_android_util_EventLog),    REG_JNI(register_android_util_Log),    ......};

REG_JNI宏用于代码调试。

/* * Register android native functions with the VM. *//*static*/ int AndroidRuntime::startReg(JNIEnv* env){    ATRACE_NAME("RegisterAndroidNatives");    ......    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {        env->PopLocalFrame(NULL);        return -1;    }    env->PopLocalFrame(NULL);}

调用register_jni_procs()方法注册JNI本地函数。

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){    for (size_t i = 0; i < count; i++) {        if (array[i].mProc(env) < 0) {#ifndef NDEBUG            ALOGD("----------!!! %s failed to load\n", array[i].mName);#endif            return -1;        }    }    return 0;}


下面是Java本地方法与JNI本地函数的映射信息

static const JNINativeMethod gMethods[] = {    { "nativeFinishInit", "()V",        (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },    { "nativeZygoteInit", "()V",        (void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },    { "nativeSetExitWithoutCleanup", "(Z)V",        (void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },};int register_com_android_internal_os_RuntimeInit(JNIEnv* env){    return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",        gMethods, NELEM(gMethods));}

在register_com_android_internal_os_RuntimeInit()方法中会调用jniRegisterNativeMethods()方法将Java本地方法与JNI本地函数映射在一起(这里需要以包含待映射的Java本地方法的Java类以及包含映射信息的结构体作为参数)。

原创粉丝点击