目录
一、JNI介绍
二、Android中的JNI利用
三、新增设备调用
一、接口文件编写
一、Android AIDL简介
二、Android AIDL编写
二、编写service
三、systemserver
四、JNI文件编写
一、JNI包含硬件操作
二、JNI不包含硬件操作
一、JNI
二、HAL
五、noload
一、JNI介绍
JNI(Java Native Interface)是Java语言中用于与本地C/C++代码交互的特性,答应Java代码调用本地代码。JNI全称Java Native Interface,是Java语言与本地C/C++代码交互的尺度方法。通过JNI,Java代码可以调用本地方法,这些方法以C或C++编写。这种机制使得Java步伐能够充分利用底层系统功能,如图形处理、音频处理等。JNI的重要优点包罗扩展Java步伐的功能、进步性能以及保护代码安全。JNI也是Android的重要构成部分。
利用方法如下:
JNIDemo.java
- public class JNIDemo {
- static { /* 1. load */
- System.loadLibrary("native"); /* libnative.so */
- }
- public native int[] hello(int[] a);
- public static void main (String args[]) {
- JNIDemo d = new JNIDemo();
- int [] a = {1, 2, 3};
- int [] b = null;
- int i;
- /* 2. map java hello <-->c c_hello */
- /* 3. call */
- b = d.hello(a);
- for (i = 0; i < b.length; i++)
- System.out.println(b[i]);
- }
- }
复制代码 native.c
- #include <jni.h> /* /usr/lib/jvm/java-1.7.0-openjdk-amd64/include/ */
- #include <stdio.h>
- #include <stdlib.h>
-
- #if 0
- typedef struct {
- char *name; /* Java里调用的函数名 */
- char *signature; /* JNI字段描述符, 用来表示Java里调用的函数的参数和返回值类型 */
- void *fnPtr; /* C语言实现的本地函数 */
- } JNINativeMethod;
- #endif
- jintArray c_hello(JNIEnv *env, jobject cls, jintArray arr)
- {
- jint *carr;
- jint *oarr;
- jintArray rarr;
-
- jint i, n = 0;
- carr = (*env)->GetIntArrayElements(env, arr, NULL);
- if (carr == NULL) {
- return 0; /* exception occurred */
- }
- n = (*env)->GetArrayLength(env, arr);
- oarr = malloc(sizeof(jint) * n);
- if (oarr == NULL)
- {
- (*env)->ReleaseIntArrayElements(env, arr, carr, 0);
- return 0;
- }
- for (i = 0; i < n; i++)
- {
- oarr[i] = carr[n-1-i];
- }
-
- (*env)->ReleaseIntArrayElements(env, arr, carr, 0);
- /* create jintArray */
- rarr = (*env)->NewIntArray(env, n);
- if (rarr == NULL)
- {
- return 0;
- }
- (*env)->SetIntArrayRegion(env, rarr, 0, n, oarr);
- free(oarr);
-
- return rarr;
- }
- static const JNINativeMethod methods[] = {
- {"hello", "([I)[I", (void *)c_hello},
- };
- /* System.loadLibrary */
- JNIEXPORT jint JNICALL
- JNI_OnLoad(JavaVM *jvm, void *reserved)
- {
- JNIEnv *env;
- jclass cls;
- if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
- return JNI_ERR; /* JNI version not supported */
- }
- cls = (*env)->FindClass(env, "JNIDemo");
- if (cls == NULL) {
- return JNI_ERR;
- }
- /* 2. map java hello <-->c c_hello */
- if ((*env)->RegisterNatives(env, cls, methods, 1) < 0)
- return JNI_ERR;
- return JNI_VERSION_1_4;
- }
复制代码 二、Android中的JNI利用
1.system sever.java文件文件中利用 System.loadLibrary 函数加载C库。
文件路径:frameworks/base/services/java/com/android/server/SystemServer.java
- System.loadLibrary("android_servers");
复制代码 2.onload.cpp中利用JNI_OnLoad函数对所有硬件进行本地注册(JNI文件)。
- 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_VibratorService(env); //示例如下查找对应的类注册本地方法。
-
- ......
- }
复制代码 3.每个硬件都注册本都方法,在对应的hal文件中对本地方法进行详细的操作(open,close),为什么不在JNI文件中直接进行详细的操作,缘故起因如下:
1.方便编译,修改hal层之后直接编译hal层(硬件抽象层)
2.为了保密利用用,可直接向上层提供库文件即可。
文件名称:com_android_server_VibratorService.cpp
- int register_android_server_VibratorService(JNIEnv *env) {
- sMethodIdOnComplete = GetMethodIDOrDie(env,
- FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
- "onComplete", "()V");
- jclass primitiveClass = FindClassOrDie(env,
- "android/os/VibrationEffect$Composition$PrimitiveEffect"); //查找对应的类
- gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
- gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
- gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
- return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
- method_table, NELEM(method_table)); //注册本地方法,映射java与C库函数
复制代码 4.hal层文件来调用open,close来详细的操作硬件。
5.每个硬件都有一个service.java,然后add service。他来利用第三步中注册的本地方法。比方VibratorService服务中他会实例化一个VibratorService对象。之后通过addService把这个服务告诉系统。这个对象中会调用映射的本地方法。
system sever是一个进程。告诉什么什么系统呢?(servivce_manger.c),servivce_manger他管理者系统的所有服务
在SystemServer.java文件中startOtherServices界说了各种服务。
- private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
- t.traceBegin("startOtherServices");
- final Context context = mSystemContext;
- VibratorService vibrator = null;
- ........
- vibrator = new VibratorService(context);
- ServiceManager.addService("vibrator", vibrator);
- }
复制代码 6.应用层app可以从servivce_manger查询获取各种servivce。
7.app必要对底层操作时对每一个硬件的system sever提供的接口发送指令。
总结:整个操作过程涉及三个进程,第一个为system sever,第二个为servivce_manger,第三个为app进程。进程间的通讯是通过binder driver驱动。
1.(JNI文件)写一个CPP文件注册本地方法(映射函数),他会加载hal层的C文件。
2.写一个hal层的C文件,他会对应CPP文件中的C库函数,C文件中会调用open,close来操作硬件。
3.修改noload.cpp中调用第一步中注册的本地方法的函数。
4.修改systemserver.java。new一个实例化对象用于操作JNI文件中映射的JAVA方法。并将他添加值service_manger中。
5.第四步必要对象类的实现,写一个类(***service.Java)。他来实现JNI中对应的方法。
6.写一个 Iservice.Java接口文件,给APP利用。
三、新增设备调用
一、接口文件编写
一、Android AIDL简介
在Android开发中,AIDL(Android interace Defnition Language)是一种用于界说客户端与服务端之间通讯接口的语言。在利用AIDL时,我们必要先编写AIDL文件,然后通过工具生成对应的Java文件,用于实现客户端和服务端之间的通讯。
二、Android AIDL编写
AIDL文件他会直接生成Java的设备接口文件。这个文件中好比实现接口(实现哪一盏灯,什么状态),写好一个aidl文件后放置雷同目录,参考如下文件:frameworks/base/core/java/android/os/IVibratorService.aidl
- package android.os;
- import android.os.VibrationEffect;
- import android.os.VibrationAttributes;
- import android.os.IVibratorStateListener;
- /** {@hide} */
- interface IVibratorService
- {
- boolean hasVibrator();
- boolean isVibrating();
- boolean registerVibratorStateListener(in IVibratorStateListener listener);
- boolean unregisterVibratorStateListener(in IVibratorStateListener listener);
- boolean hasAmplitudeControl();
- int[] areEffectsSupported(in int[] effectIds);
- boolean[] arePrimitivesSupported(in int[] primitiveIds);
- boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect,
- in VibrationAttributes attributes);
- void vibrate(int uid, String opPkg, in VibrationEffect effect,
- in VibrationAttributes attributes, String reason, IBinder token);
- void cancelVibrate(IBinder token);
- }
- /*********************************/
- //eg:
- 文件名称:ILedService.aidl
- package android.os;
- interface ILedService
- {
- int LedCtrl(int which, int status);
- }
复制代码 放置雷同路径之后,必要修改对应的编译规则,查找Android.mk文件中关键字IVibratorService模仿加入,led相干。编译在frameworks/base目录下实行mmm下令,或者在bsp目录下实行mmm下令加文件路径。如 mmm frameworks/base,修改的Android.mk在base下。
编译出的java文件是不能修改的,接口利用方法:
- private final IVibratorService mService
- mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));
-
-
- .......
- mService.hasAmplitudeControl(); //可以直接使用接口文件中提供的函数
- .......
复制代码 二、编写service
service文件的作用是操作本地方法来操作硬件,在此文件中必要实现aidl文件中界说的方法。参考文件frameworks/base/services/core/java/com/android/server/VibratorService.java编写。
- package com.android.server;
- import android.os.ILedService;
- public class LedService extends ILedService.Stub {
- private static final String TAG = "LedService";
- /* call native c function to access hardware */
- public int ledCtrl(int which, int status) throws android.os.RemoteException
- {
- return native_ledCtrl(which, status);
- }
- public LedService() {
- native_ledOpen(); //构造方法中打开设备。
- }
- public static native int native_ledOpen();
- public static native void native_ledClose();
- public static native int native_ledCtrl(int which, int status);
- }
复制代码 三、systemserver
文件路径:frameworks/base/services/java/com/android/server/SystemServer.java
- //模仿添加服务
- t.traceBegin("StartLedService")//方便调调试的打印
- ;
- ServiceManager.addService("vibrator", new LedService(context)); //创建类对象并通知service_manger
- t.traceEnd();
复制代码 四、JNI文件编写
一、JNI包含硬件操作
编写com_android_server_****Service.cpp文件,实现service文件调用的方法,必要修改编译规则,open, close临时在JNI文件中调用,未编写hal层C文件。
文件存放路径:frameworks/base/services/core/jni/
- #define LOG_TAG "LedService"
- #include "jni.h"
- #include "JNIHelp.h"
- #include "android_runtime/AndroidRuntime.h"
- #include <utils/misc.h>
- #include <utils/Log.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <hardware/led_hal.h>
- jint ledOpen(JNIEnv *env, jobject cls)
- {
- return 0;
- }
- void ledClose(JNIEnv *env, jobject cls)
- {
- //ALOGI("native ledClose ...");
- //close(fd);
- }
- jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
- {
- ALOGI("native ledCtrl %d, %d", which, status);
- return 0
- }
- static const JNINativeMethod methods[] = {
- {"native_ledOpen", "()I", (void *)ledOpen},
- {"native_ledClose", "()V", (void *)ledClose},
- {"native_ledCtrl", "(II)I", (void *)ledCtrl},
- };
-
- int register_android_server_LedService(JNIEnv *env)
- {
- return jniRegisterNativeMethods(env, "com/android/server/LedService",
- methods, NELEM(methods));
- }
- }
复制代码 二、JNI不包含硬件操作
当JNI不包含硬件操作时,JNI不仅必要向上提供本地接口还必要加载hal文件并调用hal文件中提供的函数用于硬件操作。JNI文件加载hal文件的实质就是怎么利用dlopen加载动态库。Android中对dlopen函数进行了封装利用hw_get_module函数。
一、JNI
- JNI的步伐中会利用hw_get_module函数获取一个hw_module_t布局体(详细介绍见:hw_get_module详解-CSDN博客)。
- 根据得到hw_module_t布局体调用module->methods->open(module,device_name,&device),他会获取一个HW_device_t布局体(open函数的第三个参数),并将这个布局体转换为设备自界说的布局体,返回布局体的类型就根据传入的device_name来确认。
- #define LOG_TAG "LedService"
- #include "jni.h"
- #include "JNIHelp.h"
- #include "android_runtime/AndroidRuntime.h"
- #include <utils/misc.h>
- #include <utils/Log.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <hardware/led_hal.h>
- namespace android
- {
- static led_device_t* led_device;
- jint ledOpen(JNIEnv *env, jobject cls)
- {
- jint err;
- hw_module_t* module;
- hw_device_t* device;
- ALOGI("native ledOpen ...");
- /* 1. hw_get_module */
- err = hw_get_module("led", (hw_module_t const**)&module);
- if (err == 0) {
- /* 2. get device : module->methods->open */
- err = module->methods->open(module, NULL, &device);
- if (err == 0) {
- /* 3. call led_open */
- led_device = (led_device_t *)device;
- return led_device->led_open(led_device);
- } else {
- return -1;
- }
- }
-
- return -1;
- }
- void ledClose(JNIEnv *env, jobject cls)
- {
- //ALOGI("native ledClose ...");
- //close(fd);
- }
- jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
- {
- ALOGI("native ledCtrl %d, %d", which, status);
- return led_device->led_ctrl(led_device, which, status);
- }
- static const JNINativeMethod methods[] = {
- {"native_ledOpen", "()I", (void *)ledOpen},
- {"native_ledClose", "()V", (void *)ledClose},
- {"native_ledCtrl", "(II)I", (void *)ledCtrl},
- };
-
- int register_android_server_LedService(JNIEnv *env)
- {
- return jniRegisterNativeMethods(env, "com/android/server/LedService",
- methods, NELEM(methods));
- }
- }
复制代码 二、HAL
- hal文件中必要构建hw_module_t布局体。
- JNI中会调用open函数,这里必要构建open函数。他的第一个成员为hw_module_t,第二个参数确认返回布局体类型,第三个参数HW_device_t布局体。
编写的hal层文件放置:hardware/libhardware/include/hardware(头文件),hardware/libhardware//modules(文件)必要编写编译规则
- #define LOG_TAG "LedHal"
- /* 1. 实现一个名为HMI的hw_module_t结构体 */
- /* 2. 实现一个open函数, 第三个参数返回led_device_t结构体 */
- /* 3. 实现led_device_t结构体 */
- /* 参考 hardware\libhardware\modules\vibrator\vibrator.c
- */
- #include <hardware/vibrator.h>
- #include <hardware/hardware.h>
- #include <cutils/log.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <hardware/led_hal.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <utils/Log.h>
- static int fd;
- /** Close this device */
- static int led_close(struct hw_device_t* device)
- {
- close(fd);
- return 0;
- }
- static int led_open(struct led_device_t* dev)
- {
- fd = open("/dev/leds", O_RDWR);
- ALOGI("led_open : %d", fd);
- if (fd >= 0)
- return 0;
- else
- return -1;
- }
- static int led_ctrl(struct led_device_t* dev, int which, int status)
- {
- int ret = ioctl(fd, status, which);
- ALOGI("led_ctrl : %d, %d, %d", which, status, ret);
- return ret;
- }
- static struct led_device_t led_dev = {
- .common = {
- .tag = HARDWARE_DEVICE_TAG,
- .close = led_close,
- },
- .led_open = led_open,
- .led_ctrl = led_ctrl,
- };
- static int led_device_open(const struct hw_module_t* module, const char* id,
- struct hw_device_t** device)
- {
- *device = &led_dev;
- return 0;
- }
- static struct hw_module_methods_t led_module_methods = {
- .open = led_device_open,
- };
- struct hw_module_t HAL_MODULE_INFO_SYM = {
- .tag = HARDWARE_MODULE_TAG,
- .id = "led",
- .methods = &led_module_methods,
- };
复制代码 五、noload
noload.cpp文件修改,申明调用注册本地方法。
- register_android_server_LedService(env);
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |