网页网站设计公司,钢材技术支持东莞网站建设,网站风险怎么解决方案,wordpress 大不开一. 简要 #x1f34e; JNI是Java Native Interface的缩写#xff0c;它提供了若干的API实现了Java和其他语言的通信#xff08;主要是CC#xff09;。从Java1.1开始#xff0c;JNI标准成为java平台的一部分#xff0c;它允许Java代码和其他语言写的代码进行交互。J…一. 简要 JNI是Java Native Interface的缩写它提供了若干的API实现了Java和其他语言的通信主要是CC。从Java1.1开始JNI标准成为java平台的一部分它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言尤其是C和C而设计的但是它并不妨碍你使用其他编程语言只要调用约定受支持就可以了。 在Android中JNI主要用于实现一些性能较高的功能如图像处理、音频处理、视频处理等。同时JNI也可以用于实现一些特殊的功能如与硬件交互、与系统服务交互等。
二. Java层
在某个对象中添加如下代码例如我在/frameworks/base/services/core/java/com/android/server/keepalive/KeepAliveManagerService.java中去使用native方法
public class KeepAliveManagerService extends IKeepAliveManager.Stub {private static final String TAG KeepAliveManagerService leilei;private final Context mContext;private final ActivityManagerService mActivityManagerService;private WindowManagerService mWindowManagerService;private boolean mSystemReady false;**public static native int resumeNative(int v);****public static native int pauseNative(int v);****public static native String stopNative(String v);**// 应用保活方法简单的调用了三个native方法resumeNativepauseNativestopNativeOverridepublic boolean keepAliveApplicationByPackage(String packageName) throws RemoteException {Log.d(TAG, keepAliveApplicationByPackage.packageName:packageName);if (TextUtils.isEmpty(packageName) || mActivityManagerService null|| mContext null || !mSystemReady){return false;}int s resumeNative(1);int s1 pauseNative(2);String s2 stopNative(leilei);Log.d(TAG, leilei keepAliveApplicationByPackage: onResumeNative:s);Log.d(TAG, leilei keepAliveApplicationByPackage: onPauseNative:s1);Log.d(TAG, leilei keepAliveApplicationByPackage: stopNative:s2);int curCallingUid Binder.getCallingUid();return keepAliveApplicationByPackage(packageName,curCallingUid);}
}至此java层的代码就写好了
三. C/C层 JNI文件创建 因为我写jni方法是需要在我的service对象里使用所以我frameworks/base/services/core/jni/目录下创建为需要的文件如下代码所示 #include string
#include dlfcn.h
#include pthread.h
#include chrono
#include thread
#include jni.h
#include nativehelper/JNIHelp.h
#include android/binder_manager.h
#include android/binder_stability.h
#include android/hidl/manager/1.2/IServiceManager.h
#include binder/IServiceManager.h
#include hidl/HidlTransportSupport.h
#include incremental_service.h
#include memtrackproxy/MemtrackProxy.h
#include schedulerservice/SchedulingPolicyService.h
#include sensorservicehidl/SensorManager.h
#include stats/StatsAidl.h
#include stats/StatsHal.h
#include bionic/malloc.h
#include bionic/reserved_signals.h
#include android-base/properties.h
#include utils/Log.h
#include utils/misc.h
#include utils/AndroidThreads.h
#ifdef LOG_TAG
#undef LOG_TAG
#define LOG_TAG leilei
#endif// jni静态注册
/*extern C jstring
Java_com_android_server_keepalive_KeepAliveManagerService_onResumeNative(JNIEnv *env, jclass thiz, jlong value) {// 进行本地处理生成返回值std::string hello Hello from C;jstring result env-NewStringUTF(hello.c_str());return result;
}*/// jni动态注册
namespace android {
static jint pauseNative(JNIEnv* env, jobject thiz, jint value){ALOGD(The leilei message is onPauseNative %d:,value);return value;
}static jint resumeNative(JNIEnv *env, jobject thiz, jint value){ALOGD(The leilei message is onResumeNative %d:,value);return value;
}static jstring stopNative(JNIEnv *env, jobject thiz,jstring value){const char* ptr env-GetStringUTFChars(value, NULL);ALOGD(The leilei message is stopNative %s:,ptr);return value;
}// 对应native的方法注册表
static const JNINativeMethod gKeepAliveManagerMethods[] {/* name, signature, funcPtr */{pauseNative,(I)I,(void *)pauseNative},{resumeNative,(I)I,(void *)resumeNative},{stopNative,(Ljava/lang/String;)Ljava/lang/String;,(void*) stopNative},
};// 自己实现一个跟jniRegisterNativeMethods一样的功能
int registerNativeMethods(JNIEnv *env,std::string name,const JNINativeMethod *methods) {// 反射拿到java对象jclass klass env-FindClass(name.c_str());if (klass NULL) {return -1;}// 第一个参数反射拿到的对象// 第二个参数类中的native方法--注册表// 第三个参数native方法对象的个数return env-RegisterNatives(klass, methods,3);
}// onload.cpp中调用了JNI_OnLoad,然后调用了register_android_server_KeepAliveManager进行注册
// jniRegisterNativeMethods对RegisterNatives封装了所以可以很方便的使用,我们手动来实现一下
// JNI_OnLoad是jni.h中的对象只有调用JNI_OnLoad和RegisterNatives才是动态注册
int register_android_server_KeepAliveManager(JNIEnv* env) {// return jniRegisterNativeMethods(env, com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods, NELEM(gKeepAliveManagerMethods));return registerNativeMethods(env,com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods);
}
};文件名称必须规范com.android.server.keepalive.KeepAliveManagerService.cpp由包名类名组成然后实现对应上层的native方法即可方法名称最好相同也可以不同只要在注册函数的第一个参数中对应起来就行例如下方法三个参数中前两个参数必须有而且不能变—JNIEnv和jobject static jint pauseNative(JNIEnv* env, jobject thiz, jint value){...
}然后就是开始动态注册jni方法如下代码所示由于aosp已经封装好了jniRegisterNativeMethods方法可以直接使用来注册jni方法但是为了更深刻的理解我们手动来实现registerNativeMethods // native方法注册表
static const JNINativeMethod gKeepAliveManagerMethods[] {/* name, signature, funcPtr */{pauseNative,(I)I,(void *)pauseNative},{resumeNative,(I)I,(void *)resumeNative},{stopNative,(Ljava/lang/String;)Ljava/lang/String;,(void*) stopNative},
};// 自己实现一个跟register_android_server_KeepAliveManager一样的功能
int registerNativeMethods(JNIEnv *env,std::string name,const JNINativeMethod *methods) {jclass klass env-FindClass(name.c_str());if (klass NULL) {return -1;}// 第一个参数反射拿到的对象// 第二个参数类中的native方法--注册表// 第三个参数native方法对象的个数return env-RegisterNatives(klass, methods,3);
}int register_android_server_KeepAliveManager(JNIEnv* env) {// return jniRegisterNativeMethods(env, com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods, NELEM(gKeepAliveManagerMethods));return registerNativeMethods(env,com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods);
}先实现一个native方法注册表代表需要对应java层native方法返回的对象是JNINativeMethod该对象属于jni.h里的结构如下 typedef struct {const char* name;const char* signature;void* fnPtr;
} JNINativeMethod;第一个参数对应了java native方法的名称第二个参数代表native方法里面的参数和返回值第三个参数代表jni方法 回到registerNativeMethods方法主要就是通过env的FindClass反射获取Java对象然后通过RegisterNatives(klass, methods,3);进行注册即可第二个参数就是native方法gKeepAliveManagerMethods注册表 **思考一下**既然需要注册jni,那么调用register_android_server_KeepAliveManager函数的注册的入口又在哪里下文分析 JNI文件引入和注册流程 android.bp引入编译 需要让我们的jni文件参与编译需要在frameworks/base/services/core/jni/Android.bp中添加该文件如下所示 cc_library_static {name: libservices.core,defaults: [libservices.core-libs],cpp_std: c2a,cflags: [-Wall,-Werror,-Wno-unused-parameter,-Wthread-safety,-DEGL_EGLEXT_PROTOTYPES,-DGL_GLEXT_PROTOTYPES,],srcs: [BroadcastRadio/JavaRef.cpp,BroadcastRadio/NativeCallbackThread.cpp,BroadcastRadio/BroadcastRadioService.cpp,BroadcastRadio/Tuner.cpp,BroadcastRadio/TunerCallback.cpp,BroadcastRadio/convert.cpp,BroadcastRadio/regions.cpp,gnss/GnssConfiguration.cpp,gnss/GnssMeasurement.cpp,gnss/GnssMeasurementCallback.cpp,gnss/Utils.cpp,stats/SurfaceFlingerPuller.cpp,**com.android.server.keepalive.KeepAliveManagerService.cpp,**include_dirs: [frameworks/base/libs,frameworks/native/services,system/gatekeeper/include,system/memory/libmeminfo/include,],header_libs: [bionic_libc_platform_headers,],
}在此模块添加**“com.android.server.keepalive.KeepAliveManagerService.cpp”**,即可模块名为libservices.core会生成对应的so库 JNI注册入口声明 在frameworks中上文分析了如何调用jni注册native方法但是调用注册的入口在哪里就是通过frameworks/base/services/core/jni/onload.cpp文件进行调用的需要在此文件中声明我们的注册入口如下代码所示 namespace android {
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputManager(JNIEnv* env);
**int register_android_server_KeepAliveManager(JNIEnv* env);**
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
int register_android_server_PowerStatsService(JNIEnv* env);
int register_android_server_HintManagerService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
}
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_broadcastradio_BroadcastRadioService(env);register_android_server_broadcastradio_Tuner(vm, env);register_android_server_PowerManagerService(env);register_android_server_PowerStatsService(env);register_android_server_HintManagerService(env);register_android_server_SerialService(env);register_android_server_InputManager(env);**register_android_server_KeepAliveManager(env);}**
}只需要在namespace android中声明注册入口函数**register_android_server_KeepAliveManager**此函数在我们创建的jni文件中会实现。 然后在JNI_OnLoad函数中添加**register_android_server_KeepAliveManager(env);**目的是为了方法可以被正确调用以及传递了env对象jni里的东西再来看一遍我创建的jni文件,frameworks/base/services/core/jni/com.android.server.keepalive.KeepAliveManagerService.cpp ...
int **register_android_server_KeepAliveManager**(JNIEnv* env) {// return jniRegisterNativeMethods(env, com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods, NELEM(gKeepAliveManagerMethods));return registerNativeMethods(env,com/android/server/keepalive/KeepAliveManagerService,gKeepAliveManagerMethods);
}
};**思考一下**为什么需要在extern C jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)方法中调用jni注册逻辑呢这涉及到jni动态注册原理了后面再分析jni分为静态注册和动态注册 JNI注册表分析 Andoird 中使用了一种不同传统Java JNI的方式来定义其native的函数。其中很重要区别是Andorid使用了一种Java 和 C 函数的映射表数组并在其中描述了函数的参数和返回值。这个数组的类型是JNINativeMethod——该结构体位于jni.h中结构如下 typedef struct {const char* name;const char* signature;void* fnPtr;
} JNINativeMethod;三个参数代表着native方法名称签名—用字符串是描述了Java中函数的参数和返回值jni函数对象-指向了java的native方法 具体用法如下 static const JNINativeMethod gKeepAliveManagerMethods[] {/* name, signature, funcPtr */{pauseNative,(I)I,(void *)pauseNative},{resumeNative,(I)I,(void *)resumeNative},{stopNative,(Ljava/lang/String;)Ljava/lang/String;,(void*) stopNative},
};第三个参数前面必须带有(void *)这里主要分析第二个参数()代表native方法的参数()外面部分代表着返回值I代表着java的int,jni的jint具体如下 字符c/c类型Java类型VvoidvoidZjbooleanbooleanIjintintJjlonglongDjdoubledoubleFjfloatfloatBjbytebyteCjcharcharSjshortshort以上都是基本数据类如果是数组则用[代表如整型数值 [I来表示具体如下 名称c/c类型Java类型[IjintArrayint[][FjfloatArrayfloat[][BjbyteArraybyte[][CjcharArraychar[][SjshortArrayshort[][DjdoubleArraydouble[][JjlongArraylong[][ZjbooleanArrayboolean[]那如果native参数中是对象呢需要用如下方法表示—参数解释 // 参数解释
() 中的字符表示参数小括号后面的则代表返回值。
()V 就表示native void Fun();
(II)V 表示native void Func(int a, int b);参数是俩个整型。
(Ljava/lang/String;)Ljava/lang/String; 就表示native Sting Func(String value);所以如果要用对象作为参数或者返回值需要在前面加个”L”中间是用”/ 隔开后面跟包名和类名以及分号即可。如果是对象数组则在前面加个[即可