• Android M中 JNI的入门学习


           

           今年谷歌推出了Android 6.0,作为安卓开发人员,对其学习掌握肯定是必不可少的,今天小编和大家分享的就是Android 6.0中的 JNI相关知识,这是在一个安卓教程网上看到的内容,感觉很不错,一起来看看吧~~

           初学者可能首先就会问,JNI是个什么鬼?

    其实,JNI 的全称 Java Native Interface,Java 本地调用,主要用于实现两种功能:

    1、Java 程序调用 Native(C/C++) 语言写的函数。

    2、Native(C/C++) 程序调用 Java 层函数。

    JNI 是 Java 提供的机制。Java 想要调用 C/C++ 库代码,在中间需要一个 JNI 库,结构像下面这样:

        Java 代码

             ↓

        JNI 库 (lib***_jni.so)

             ↓

        Native (lib***.so)

    Java 中加载 JNI

    在 安卓开发中,需要调用 JNI 的类都要首先对 JNI 库进行加载:

    System.loadLibrary("***_jni");

    通过这个就可以知道某个类是否使用了 JNI 方法。

    大家可以,在 Android 6.0 的代码中搜索一下,有数百处使用到的地方。例如 Android 系统中重要的 SystemServer 类,在其创建的时候就有一句:

    // Initialize native services.

    System.loadLibrary("android_servers");

    看来 SystemServer 用到了 Native 库,其 JNI 库的名字叫 libandroid_servers.so。

    System.loadLibrary 需要在进行 JNI 调用之前调用,先将 JNI 库加载进来。

    JNI 中的 Native 方法,要在 Java 中使用,需要在 Java 中创建带有 native 关键字的同名函数。

    接着在 SystemServer 的代码中搜索 native,只找到一处:

    private static native void startSensorService();

    因是 SystemServer 是用来启动 Android 中关键服务的,它自己加载 libandroid_servers.so 后,其他服务就可以直接声明 JNI 方法使用,而不用重复加载了。

    例如,在 LightsService 中,有:

    private static native long init_native();

    private static native void finalize_native(long ptr);

    static native void setLight_native(long ptr, int light, int color, int mode,

            int onMS, int offMS, int brightnessMode);

    ...

    在 PowerManagerService 中,有:

    private native void nativeInit();

    private static native void nativeAcquireSuspendBlocker(String name);

    private static native void nativeReleaseSuspendBlocker(String name);

    private static native void nativeSetInteractive(boolean enable);

    private static native void nativeSetAutoSuspend(boolean enable);

    private static native void nativeSendPowerHint(int hintId, int data);

    private static native void nativeSetFeature(int featureId, int data);

    ...

    他们都没有再 System.loadLibrary。

    JNI 库的实现

    这么多关键服务都需要 libandroid_servers.so 中的 JNI 方法,这个库也是够神通广大的。实现它的代码在哪里?怎样才能找到呢?

    JNI 库中的函数的命名方式与 Java 中的方法有着严格的对应规则。例如,SystemServer 的类名的全称是 com.android.server.SystemServer,前文说过它自己有唯一一个 JNI 调用 startSensorService,那么 Android 的代码中必然有一个函数为 android_server_SystemServer_startSensorService 。

    它位于 frameworks/base/services/core/jni/com_android_server_SystemServer.cpp ,方法实现为:

    static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {

        char propBuf[PROPERTY_VALUE_MAXIEEWONG@GMAIL.COM];

        property_get("system_init.startsensorservice", propBuf, "1");

        if (strcmp(propBuf, "1") == 0) {

            // Start the sensor service

            SensorService::instantiate();

    }

    我们再来看 LightsService,它的类全称为 com.android.server.lights.LightsService,它用到了一个 JNI 调用为 setLight_native ,那么必然也有一个函数名为 android_server_lights_LightsService_setLight_native ,不过并没有找到 。但是找到了 setLight_native ,即同名的 Native 实现,这就是对应的 JNI 实现,它位于 frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp 下。

    同名是如何做到的呢?我们一起来看看代码就明白了:

    static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,

            jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)

    {

        ...

    }

    static JNINativeMethod method_table[] = {

        { "init_native", "()J", (void*)init_native },

        { "finalize_native", "(J)V", (void*)finalize_native },

        { "setLight_native", "(JIIIIII)V", (void*)setLight_native },

    };

    int register_android_server_LightsService(JNIEnv *env)

    {

        return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",

                method_table, NELEM(method_table));

    }

    它通过一个 table 把前面那一大堆前缀("com/android/server/lights/LightsService")给提前注册了,这样 Java 调用时,JNI 层就知道有同名函数了。

    libandroid_servers.so 是如何生成的?

    通过前面两次 JNI 实现的寻找,我们发现它们位于 frameworks/base/services/core/jni/ 下的不同文件中。他们是怎么组织最终构建出 libandroid_servers.so 的呢?

    首先, libandroid_servers 这个名字肯定是我们在 Makefile 里面起的,在 Android 下就是 Android.mk。在代码中搜索 libandroid_servers ,找到 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)

    其中:

    # include all the jni subdirs to collect their sources

    include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)

    把所有子目录下的 jni 都收集起来,编译为 LOCAL_MODULE libandroid_servers 。并且是以动态库的形式,因为 JNI 库必需动态库。

    至此对于 JNI 的入门学习就算完成了。在接下来学习 Android 代码时,遇到带 native 的、遇到一大堆下划线的方法,来者不拒了 。

    以上 就是Android6.0中JNI的相关知识,这里由于篇幅问题,写得都比较浅,后续将继续为大家分享更深入的相关内容。建议大家可以在本地尝试一下上述介绍的内容,加深掌握。

    相关文章:《29个android开发常用的类、方法及接口

  • 相关阅读:
    关于yyyy-MM-dd格式日期字符串,解析成LocalDateTime遇到的问题
    idea设置代码提示不区分大小写
    不错的Django技术网址
    Django-Rest-Framework 教程: 快速入门
    Djanto static静态文件配置
    Html5 touch event
    Zepto.js touch模块深入分析
    Python单元测试框架之pytest -- fixtures
    Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)
    Nginx基本配置、性能优化指南
  • 原文地址:https://www.cnblogs.com/gaobig/p/5048055.html
Copyright © 2020-2023  润新知