android中的jni两种注册时机 base/core/jni & base/service/core/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_runtime.so的动态库。接下来要分析的Log中JNI的使用,就在这个目录之中。

2. android 中的jni

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

2.1Framework base/core/jni 机制

  • Java框架层,最主要的JNI内容源代码路径为:/frameworks/base/core/jni,编译生成libandroid_runtime.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。
      /*
       * JNI registration.
       */
      static const JNINativeMethod gMethods[] = {
          /* name, signature, funcPtr */
          { "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),
          //省略
      }
      
      /*
       * Register android native functions with the VM.
       */
      /*static*/ 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<JNIEnv*>(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* /* 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_HardwarePropertiesManagerService(env);


    return JNI_VERSION_1_4;
}

//frameworks/base/media/jni/android_media_MediaPlayer.cpp
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("ERROR: GetEnv failed\n");
        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 failed\n");
        goto bail;
    }
    // 省略

    /* success -- return valid version number */
    result = JNI_VERSION_1_4;

bail:
    return result;
}


2.2 service的jni (另外一种方式)

先看下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 * /* env */, jobject /* obj */) {。。。。}
      static const JNINativeMethod method_table[] = {
          /* name, signature, funcPtr */
              {"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* /* reserved */)
      {
         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* /* reserved */)
	  {
	      JNIEnv* env = NULL;
	      jint result = -1;
	  
	      if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
	          ALOGE("ERROR: GetEnv failed\n");
	          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方法注册稍有不同

下一篇jni详解

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值