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[[email protected]];

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开发常用的类、方法及接口

时间: 2024-08-08 01:15:06

Android M中 JNI的入门学习的相关文章

Android项目中JNI技术生成并调用.so动态库实现详解

生成 jni方式有两种:一种是通过SWIG从C++代码生成过度的java代码:另一种是通过javah的方式从java代码自动生成过度的C++代码.两种方式下的步骤流程正好相反. 第一种方式:由于需要配置SWIG环境,有点麻烦了,所以往往大家不采用这个途径,参照博文http://my.oschina.net/liusicong/blog/314162. 第二种方式:javah的方式则通过shell指令就可以完成整个流程,该过程大概包括以下步骤: 编写 Java 代码.我们将从编写 Java 类开始

android studio 中jni底层日志的打印

1 添加ndk对log支持若需要添加ndk对log的支持,只需要通过以下2步即可实现. 1.1 修改Android.mk如生成的库文件是".so文件",则在Android.mk中添加如下内容:LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog如生成的库文件是".a文件",则在Android.mk中添加如下内容:LOCAL_LDLIBS:=-llog 1.2 在.c或.cpp文件中引用log头文件添加如下内容:// 引入log头文件#in

Android Studio中JNI -- 2 -- 编写c文件

继上一篇,我们在native接口中编写了2个方法 生成的相应.h文件 这时,需要我们自己去完善.c文件 /* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>#include <android/log.h>#include <stdio.h>#include <string.h>#include <stdlib.h> /* Header for class led

Android Studio中JNI -- 1 -- 配置方法

1.配置NDK 1.1 下载NDK Android Studio 1.2 配 android-ndk-r10e,不同版本的Studio需要配置不同的ndk,下载完成后,随便解压放至某个文件目录下 1.2 指定NDK目录 1.3 修改build.gradle配置 需要修改的是在<Project>\app\build.gradle 2. 添加native接口 2.1 添加native 2.2 执行build -> Make Project 确定程序无错误,并生成.class文件 2.3 通过

Linux中的syslog 入门学习教程

syslog是linux系统中默认的日志守护进程,默认的syslog配置文件是/etc/syslog.conf文件.程序.守护进程和内核提供了访问系统的日志信息.任何希望生成日志信息的程序都可以向syslog接口呼叫产生该信息. 几乎所有的网络设备都可以通过syslog协议,将日志信息通过udp方式传送到远端的服务器,而远端的服务器通过syslogd监听udp的514端口,并且根据syslog.conf配置文件中的配置进行处理,接受访问系统的日志信息,把指定的事件写入到特定的文件中,供后台数据库

android JNI入门-学习笔记

JNI入门-学习笔记 可执行文件 Windows - *.exe | linux - *.elf c函数库文件 Windows - *.dll | linux - *.so 批处理文件 Windows - *.bat | linux - *.sh 工具 NDK -- native developer kits Cygwin -- Linux系统模拟器 安装过程要点: --安装时可以联网安装也可以通过本地文件安装(如果有本地文件) --Select Packages:没必要全部安装,安装Devel

android的JNI 、 NDK 学习!

转载的! Java Native Interface (JNI)标准是java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C.C++ 和汇编语言)编写的应用程序和库进行交互操作. 1.从如何载入.so档案谈起 由于Android的应用层的类都是以Java写的,这些Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Mac

JNI入门-学习笔记

JNI入门-学习笔记 可执行文件 Windows - *.exe | linux - *.elf c函数库文件 Windows - *.dll | linux - *.so 批处理文件 Windows - *.bat | linux - *.sh 工具 NDK -- native developer kits Cygwin -- Linux系统模拟器 安装过程要点: ——安装时可以联网安装也可以通过本地文件安装(如果有本地文件) ——Select Packages:没必要全部安装,安装Devel

Android jni 编程入门

本文将介绍如何使用eclipse和ndk-build来编写一个基于Android4.4版本的包含有.so动态库的安卓程序. 前提是已经安装和配置好了诸如SDK,NDK等编译环境.下面开始编程! 1 程序逻辑 我们要编写的程序包含两部分:java部分--负责界面和调用JNI native函数:JNI native 部分--负责native函数的具体实现(本文使用C语言). native 函数伪代码如下: ? 1 2 3 4 5 6 7 8 /* funtion: 传入两个整形变量,计算他们之和 r