Android JNI使用简介

本文介绍了JNI在Android系统中的两种使用方式,一种是通过framework层的SystemServer注册本地方法,另一种是在RuntimeInit中注册本地方法。详细展示了如何通过JNI实现Java与C/C++的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 sources
include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)

LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES

LOCAL_MODULE:= libandroid_servers

include $(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.cpp

LOCAL_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, ClassL
oader 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类以及包含映射信息的结构体作为参数)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值