栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

android中的jni

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

android中的jni

https://www.jianshu.com/p/91321134207b

1基本要点

JavaVM:表示Java虚拟机。JNIEnv:表示JNI环境的上下文,例如注册、查找类、异常等。jclass:在JNI中表示的Java类。jmethodID:在JNI中表示的Java类中的方法。jfiledID:在JNI中表示的Java类中的属性。线程:JNI中通过AttachCurrentThread和DetachCurrentThread方法,实现和Java线程的结合。

它们都在一个叫jni.h的头文件中,这个头文件是JNI机制中很重要的一个头文件

/libnativehelper/include/nativehelper/jni.h

在libnativehelper目录下的源文件,编译后会生成一个libnativehelper.so的动态库。其实,jni.h是Android根据Java本地调用的标准写成的一个头文件,在它里面包括了基本类型(类型的映射),以及JavaVM,JNIEnv,jclass,jmethodID,jfiledID等数据结构的定义。

JavaVM对应于jni.h中JNIInvokeInterface结构体,表示虚拟机。JNIEnv对应于JNINativeInterface结构体,表示JNI的环境。在JNI的使用过程中,所调用的功能大都来自JNINativeInterface结构体。例如,处理Java属性和方法的查找,Java属性的访问,Java方法的调用等功能。另外,在JNINativeInterface结构体中,涉及到的一个JNINativeMethod结构体,它表示在本地实现的一个方法,即native方法,后面进行JNI注册的时候会用到。

在Android框架中,JNI库是一些普通的本地动态库,被放置在目标系统的/system/lib目录中。Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni。 这里面的代码会生成一个libandroid_runtiem.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。

2. android 中的jni

在Android框架中,JNI库是一些普通的本地动态库,被放置在目标系统的/system/lib目录中。
Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni。
这里面的代码会生成一个libandroid_runtiem.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。

2.1framework base/core/jni 机制

Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni,编译生成libandroid_runtiem.so的动态库

以Log为例:

/frameworks/base/core/java/android/util/Log.java 都会走println_native->android_util_Log_println_native

//frameworks/base/core/jni/android_util_Log.cpp。

static const JNINativeMethod gMethods[] = {
    
    { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
    { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
    { "logger_entry_max_payload_native",  "()I", (void*) android_util_Log_logger_entry_max_payload_native },
};
//android_util_Log.h
typedef struct {
    const char* name;  //native方法名
    const char* signature; //参数,返回值,jni签名为了支持函数重载  (参数1类型标示;参数2类型标示;参数3类型标示...)返回值类型标示
    void*       fnPtr;//函数指针,指向这个natve对应的jni函数
} JNINativeMethod;

println_native------>jni实现函数android_util_Log_println_native()---->native 的liblog库 __android_log_buf_write()

jni注册

//android_util_Log.cpp
int register_android_util_Log(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, "android/util/Log");

    levels.verbose = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "VERBOSE", "I"));
  levels.debug = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "DEBUG", "I"));
    levels.info = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "INFO", "I"));
  levels.warn = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "WARN", "I"));
    levels.error = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ERROR", "I"));
    levels.assert = env->GetStaticIntField(clazz, GetStaticFieldIDOrDie(env, clazz, "ASSERT", "I"));
//RegisterMethodsOrDie()函数做了什么  后文分析
    return RegisterMethodsOrDie(env, "android/util/Log", gMethods, NELEM(gMethods));
}

register_android_util_Log 被谁调用?

cgrep register_android_util_Log 搜索

/frameworks/base/include/android_runtime/AndroidRuntime.h。
/frameworsk/base/core/jni/AndroidRuntime.cpp。

//AndroidRuntime.cpp  ,gRegJNI数组
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_util_MemoryIntArray),
    //省略
}


 int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
...
	//gRegJNI
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalframe(NULL);
        return -1;
    }
    return 0;
}
//frameworks/base/core/jni/core_jni_helpers.h
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
                                       const JNINativeMethod* gMethods, int numMethods) {
    int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods);
    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
    return res;
}
//最终调用  libnativehelper/JNIHelp.cpp  的jniRegisterNativeMethods方法
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
    const JNINativeMethod* gMethods, int numMethods)
{
    JNIEnv* e = reinterpret_cast(env);

    ALOGV("Registering %s's %d native methods...", className, numMethods);

    return 0;
}
//startReg哪里来的呢zygote->AndroidRuntime::start()->AndroidRuntime::startReg()
if (zygote) {
    runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
    runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
    fprintf(stderr, "Error: no class name or --zygote supplied.n");
    app_usage();
    LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    return 10;
}

此外还有一种方式,

因为只在启动的时候注册必要的部分,其他部分在使用时随着加载过程进行动态注册。注意 registerNativeMethods JNI_OnLoad,且看后面详解。

//frameworks/base/service/core/jni/onload.cpp
extern "C" jint JNI_onLoad(JavaVM* vm, void* )
{
    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_HardwarePropertiesManagerService(env);


    return JNI_VERSION_1_4;
}

//frameworks/base/media/jni/android_media_MediaPlayer.cpp
jint JNI_onLoad(JavaVM* vm, void* )
{
    JNIEnv* env = NULL;
    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        ALOGE("ERROR: GetEnv failedn");
        goto bail;
    }
    assert(env != NULL);

    if (register_android_media_ImageWriter(env) != JNI_OK) {
        ALOGE("ERROR: ImageWriter native registration failed");
        goto bail;
    }

    if (register_android_media_ImageReader(env) < 0) {
        ALOGE("ERROR: ImageReader native registration failed");
        goto bail;
    }

    if (register_android_media_MediaPlayer(env) < 0) {
        ALOGE("ERROR: MediaPlayer native registration failedn");
        goto bail;
    }
    // 省略

    
    result = JNI_VERSION_1_4;

bail:
    return result;
}


另外一种方式

先看下java框架组成

java框架库,framework.jar 系统核心,定义并实现andorid中大多数的java类,也提供作为标准

java服务库 service.jar,包含一些复杂服务,为框架层提供一部分功能的实现,服务库也具有java框架层中一个主要的程序入口,进入此入口运行后,服务库将形成java框架层一个在后台长时间运行的程序。

资源包 framework-res.apk 没有java代码,纯资源组成的包,资源包是java框架层唯一的包含资源和工程描述文件的包。框架层所有的资源和组件定义均包含在资源包中。

三个库之间耦合性比较像,且相互依赖。
总结下上一节。

framework.jar 系统核心,

framework/base/core是主要目录,core目录下,jni包是同目录下java包中对应的jni实现,

/frameworks/base/core/java/android/util/Log.java

/frameworks/base/core/jni/android_util_Log.cpp

frameworks/base/core/jni/android_util_Log.cpp 实现jni,会生成一个libandroid_runtime.so动态库。启动zygote时,实例化AndroidRuntime.cpp类,将其中jni函数注册到虚拟机,所以core,media(部分),opengl等相关的JNI会在系统启动的时候进行注册

service.jar

Java框架层服务库部分的目录为:frameworks/base/services/java,同级目录下的Android.mk会将这个包编译,生成services.jar

frameworks/base/services/java/com/android/server中只包含一个入口部分的类 SystemServer.java SystemConfigService.java

frameworks/base/services/core/java/com/android/server 其他类在这个目录下

service.jar的jni实现在frameworks/base/service/core/jni/com_android_server_xxx.cpp,其中内容生成libandroid_server.so的动态库。为service提供本地支持,这个库在frameworks/base/services/java/SystemServer.java类中被加载。注册示例:

//frameworks/base/services/core/jni/com_android_server_ConsumerIrService.cpp
namespace android {
static jboolean getHidlHalService(JNIEnv * , jobject ) {。。。。}
static const JNINativeMethod method_table[] = {
    
        {"getHidlHalService", "()Z", (void *)getHidlHalService},
        {"halTransmit", "(I[I)I", (void *)halTransmit},
        {"halGetCarrierFrequencies", "()[I", (void *)halGetCarrierFrequencies},
};
int register_android_server_ConsumerIrService(JNIEnv *env) {
    return jniRegisterNativeMethods(env, "com/android/server/ConsumerIrService",
            method_table, NELEM(method_table));
}
。。。。
}

生成libandroid_servers.so动态库,SystemServer main函数中加载libandroid_servers,调用其Onload,frameworks/base/service/core/jni/onload.cpp,将jni方法注册到java虚拟机中。

//frameworks/base/services/core/jni/onload.cpp
extern "C" jint JNI_onLoad(JavaVM* vm, void* )
{
   register_android_server_ConsumerIrService(env);     
}

此外,android框架层还包含其他jni实现库,比如,多媒体一部分jni实现在frameworks/base/media/jni/android_media_xxx.cpp,(一部分在libandroid_runtime.so中),生成libmedia.so,为framework.jar提供部分本地支持,(media目录划在了框架层的framework.jar部分)。这个动态库是在frameworks/base/media/java/android/media/MediaPlayer.java类中加载,加载本地库后,会执行其中的**JNI_onLoad()**函数,进行JNI方法的注册。也就是说,程序在使用的时候进行加载,并进行jni注册。谷歌这样么做,是因为想在启动时注册必要的部分(zygote启动时实例化AndroidRuntime.cpp),其他部分随着加载so过程进行动态注册。

//frameworks/base/media/jni/android_media_MediaPlayer.cpp
	  jint JNI_onLoad(JavaVM* vm, void* )
	  {
	      JNIEnv* env = NULL;
	      jint result = -1;
	  
	      if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
	          ALOGE("ERROR: GetEnv failedn");
	          goto bail;
	      }
	      assert(env != NULL);
	  
	      if (register_android_media_ImageWriter(env) != JNI_OK) {
	          ALOGE("ERROR: ImageWriter native registration failed");
	          goto bail;
	      }
	      // 省略
	      result = JNI_VERSION_1_4;
	  
	  bail:
	      return result;
	  }
	  //frameworks/base/media/java/android/media/MediaPlayer.java
	  static {
	      System.loadLibrary("media_jni");
	      native_init();
	  }

Java层调用System.loadLibrary()方法加载动态函数库时,执行JNI_onLoad()函数,完成各个JNI方法的动态注册,这和前面Log相关的JNI方法注册稍有不同

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/736096.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号