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类以及包含映射信息的结构体作为参数)。
- Android JNI使用简介
- ANDROID JNI的使用简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- Android JNI知识简介
- structs2工作原理
- struts2值栈取值从源代码中分析
- LeetCode
- 【java】java程序打包工具fatjar在eclipse环境下的安装和使用
- 远程过程调用协议
- Android JNI使用简介
- python 中文iso8859-1编码转utf8编码
- POJ 1182 食物链 (并查集)(需复习!!)
- 【C#机房重构】无法将类型为“JF.DAL.BillDAL”的对象强制转换为类型“JF.IDAL.IBillIDAL”
- 关于卫星的结构分析
- 内存泄露
- Effective C++ Item 16-成对使用new和delete时要采取相同形式
- 数据库FMDB的使用
- Python的orm框架sqlalchemy的查询多条数据只显示第一条!!