在上一篇文章中对JNI简单介绍了,在这篇文章中将对JNI原理进行介绍。本篇文章将以JNI执行环境、JNI数据类型、JNI注册方式、JNI引用、JNI变量共享以及JNI调用方式来介绍JNI原理。
jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
#if defined(__cplusplus)
typedef _JavaVM JavaVM; //C++的JavaVM定义
#else
typedef const struct JNIInvokeInterface* JavaVM; //C的JavaVM定义
#endif
/*
* JNI invocation interface.
*/
struct JNIInvokeInterface {
void* reserved0;//保留
void* reserved1;//保留
void* reserved2;//保留
jint (*DestroyJavaVM)(JavaVM*); // 销毁Java虚拟机并回收资源
jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);//链接到当前Java线程
jint (*DetachCurrentThread)(JavaVM*); //从当前Java线程中分离
jint (*GetEnv)(JavaVM*, void**, jint);// 获得当前线程的Java运行环境
jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*); // 将当前线程作为守护线程
};
/*
* C++ version.
*/
struct _JavaVM {
const struct JNIInvokeInterface* functions;
#if defined(__cplusplus)
jint DestroyJavaVM()
{ return functions->DestroyJavaVM(this); }
jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
{ return functions->AttachCurrentThread(this, p_env, thr_args); }
jint DetachCurrentThread()
{ return functions->DetachCurrentThread(this); }
jint GetEnv(void** env, jint version)
{ return functions->GetEnv(this, env, version); }
jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
{ return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
#endif /*__cplusplus*/
};
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;//C++定义
#else
typedef const struct JNINativeInterface* JNIEnv;//C定义
#endif
/*
* Table of interface function pointers.
*/
//C JNIEnv定义
struct JNINativeInterface {
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
jclass (*FindClass)(JNIEnv*, const char*);
jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*,const char*);
.......
jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*, jint); //注册本地方法
jint (*UnregisterNatives)(JNIEnv*, jclass); //反注册本地方法
jint (*GetJavaVM)(JNIEnv*, JavaVM**); //获取对应的JavaVM对象
......
}
/*
* C++ object wrapper.
*
* This is usually overlaid on a C struct whose first element is a
* JNINativeInterface*. We rely somewhat on compiler behavior.
*/
//C++的JNIEnv定义
struct _JNIEnv {
const struct JNINativeInterface* functions;
#if defined(__cplusplus)
jclass FindClass(const char* name)
{ return functions->FindClass(this, name); }
.......
}
Java类型
|
Native类型 |
JNI类型
|
描述
|
boolean |
unsigned char
|
jboolean
|
无符号8比特
|
byte |
signed char
|
jbyte
|
有符号8比特 |
char |
unsigned short
|
jchar
|
无符号16比特
|
short
|
short
|
jshort
|
有符号16比特
|
int
|
int
|
jint
|
有符号32比特
|
long
|
long long
|
jlong
|
有符号64比特
|
float
|
float
|
jfloat
|
32比特
|
double
|
double
|
jdouble
|
64比特
|
void |
void
|
void
|
N/A
|
typedef unsigned char jboolean; /* unsigned 8 bits */
typedef signed char jbyte; /* signed 8 bits */
typedef unsigned short jchar; /* unsigned 16 bits */
typedef short jshort; /* signed 16 bits */
typedef int jint; /* signed 32 bits */
typedef long long jlong; /* signed 64 bits */
typedef float jfloat; /* 32-bit IEEE 754 */
typedef double jdouble; /* 64-bit IEEE 754 */
typedef jint jsize;
需要注意的是jchar代表的是Java的char类型,对应于C/C++中的却是unsigned short类型,因为Java中的char类型是两个字节,jchar相当于C/C++的宽字符。如果需要在本地方法中定义一个jchar类型的数据,规范的写法应该是jchar = L'C'。
#ifdef __cplusplus
/*
* Reference types, in C++
*/
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};
//在C++中定义的引用类型
typedef _jobject* jobject;
typedef _jclass* jclass;
typedef _jstring* jstring;
typedef _jarray* jarray;
typedef _jobjectArray* jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray* jbyteArray;
typedef _jcharArray* jcharArray;
typedef _jshortArray* jshortArray;
typedef _jintArray* jintArray;
typedef _jlongArray* jlongArray;
typedef _jfloatArray* jfloatArray;
typedef _jdoubleArray* jdoubleArray;
typedef _jthrowable* jthrowable;
typedef _jobject* jweak;
#else /* not __cplusplus */
//在C语言中定义的JNI引用类型
/*
* Reference types, in C.
*/
typedef void* jobject;
typedef jobject jclass;
typedef jobject jstring;
typedef jobject jarray;
typedef jarray jobjectArray;
typedef jarray jbooleanArray;
typedef jarray jbyteArray;
typedef jarray jcharArray;
typedef jarray jshortArray;
typedef jarray jintArray;
typedef jarray jlongArray;
typedef jarray jfloatArray;
typedef jarray jdoubleArray;
typedef jobject jthrowable;
typedef jobject jweak;
#endif /* not __cplusplus */
Java类型 |
JNI类型签名
|
boolean
|
Z
|
btye
|
B
|
char
|
C
|
short
|
S
|
int
|
I
|
long
|
J |
float
|
F
|
double
|
D
|
Class类 |
L
|
void |
V
|
数组[]
|
[ |
boolean[] | [Z |
byte[] | [B |
char[]
|
[C |
short[]
|
[S
|
int[]
|
[I |
long[] |
[J
|
float[] |
[F
|
double[] |
[D
|
typedef struct {
const char* name;//方法名字
const char* signature;//方法签名
void* fnPtr;//本地方法名字
} JNINativeMethod;
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
int main(int argc, char* const argv[])
{
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));//创建AppRuntime
.........
bool zygote = false;
bool startSystemServer = false;
...........
++i;
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;//启动Zygote进程
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;//启动SystemServer进程
}
........
}
Vector args;
if (!className.isEmpty()) {
.........
} else {
if (startSystemServer) {
args.add(String8("start-system-server"));//添加启动SystemServer的参数
}
............
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//启动Zygote进程
}
............
}
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength)
, mClass(NULL)
{ }
}
而AndroidRuntime类定义在AndroidRuntime.cpp文件中,代码路径在frameworks/base/core/jni/AndroidRuntime.cpp路径下。
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
SkGraphics::Init();
mOptions.setCapacity(20);
assert(gCurRuntime == NULL); // one per process
gCurRuntime = this; //将Runtime保存到一个全局变量中
}
static AndroidRuntime* gCurRuntime = NULL;
AndroidRuntime* AndroidRuntime::getRuntime()
{
return gCurRuntime;
}
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
.......
static const String8 startSystemServer("start-system-server");
........
// 1.启动虚拟机VM
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
//2.注册JNI函数
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
//准备启动Zygote进程的参数
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
// 3.启动Zygote进程,调用ZygoteInit.main()方法。
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
//通过JNI调用java方法,具体是通过找到ZygoteInit类,以及ZygoteInit类的静态方法main,
//最后通过CallStaticVoidMethod调用ZygoteInit类的main方法。
// "com.android.internal.os.ZygoteInit"是通过app_main中main方法传递过来的参数。
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);//通过JNI调用ZygoteInit的main方法
}
}
free(slashClassName);
// 虚拟机退出了才会执行到这里
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
/*
* Start the Dalvik Virtual Machine.
*
* Various arguments, most determined by system properties, are passed in.
* The "mOptions" vector is updated.
*
* Returns 0 on success.
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
JavaVMInitArgs initArgs;
//准备创建JVM的参数
.........
// 初始化VM,
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
// 设置创建线程的方法为javaCreateThreadEtc,该方法定义在AndroidRuntime.h中
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
......
env->PushLocalFrame(200);
//注册gRegJNI数组中的函数
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}
可以看到startReg函数最后调用的是
register_jni_procs函数将gRegJNI数组中的函数注册到VM中。gRegJNI是一个包含JNI函数的数组,定义如下:
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
// 设置创建线程的方法为javaCreateThreadEtc,该方法定义在AndroidRuntime.h中
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
......
env->PushLocalFrame(200);
//注册gRegJNI数组中的函数
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}
可以看到startReg函数最后调用的是register_jni_procs函数将gRegJNI数组中的函数注册到VM中。gRegJNI是一个包含JNI函数的数组,定义如下:
//一个包含JNI函数的数组
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
....
}
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
//循环调用gRegJNI数组中的JNI函数,每一个方法都对应于一个类的jni映射。
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
return -1;
}
}
return 0;
}
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
{ "nativeSetExitWithoutCleanup", "(Z)V",
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
methods, NELEM(methods));
}
jniRegisterNativeMethods方法的作用是将本地方法注册到JNI中,JNINativeMethod是定义本地方法的一个数据结构在jni.h文件中定义。
typedef struct {
const char* name;//Java方法名字
const char* signature;//方法签名
void* fnPtr;//Java方法对应的本地函数指针
} JNINativeMethod;
至此,介绍完了JNI方法在系统启动过程中的注册流程。其流程如下图所示:
/*
* 加载libname指定的本地库
*/
@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}
在
java/lang/Runtime.java类中
/*
* 通过给定的ClassLoader搜索和加载指定的共享库文件
*/
void loadLibrary(String libraryName, ClassLoader loader) {
//loader不为空,进入该分支处理
if (loader != null) {
//查找库所在路径
String filename = loader.findLibrary(libraryName);
if (filename == null) {
throw new UnsatisfiedLinkError(loader + " couldn't find \"" +
System.mapLibraryName(libraryName) + "\"");
}
//加载库文件
String error = doLoad(filename, loader);
if (error != null) {
throw new UnsatisfiedLinkError(error);
}
return;
}
//loader为空,则进入该分支处理
// 返回平台相关库文件名字,在Android中,如果共享库为MyLibrary,则返回的共享库名字为“libMyLibrary.so”。
String filename = System.mapLibraryName(libraryName);
List candidates = new ArrayList();
String lastError = null;
//在/system/lib/和/vendor/lib/下查找指定的filename文件
for (String directory : mLibPaths) {
String candidate = directory + filename;
candidates.add(candidate);
if (IoUtils.canOpenReadOnly(candidate)) {
// 找了对应的库文件,加载库文件
String error = doLoad(candidate, loader);
if (error == null) {
return; // We successfully loaded the library. Job done.
}
lastError = error;
}
}
if (lastError != null) {
throw new UnsatisfiedLinkError(lastError);//没有找到满足条件的,报错
}
throw new UnsatisfiedLinkError("Library " + libraryName + " not found; tried " + candidates);
}
// mLibPaths是保存库文件路径,用来查找native库文件
private final String[] mLibPaths = initLibPaths();
/*
*搜索JNI库文件的路径,通过"java.library.path"读取出来的属性值为/vendor/lib:/system/lib/。
*其中/system/lib/路径存放的是系统应用使用的so库文件,/vendor/lib/路径存放的是第三方应用的so库文件。*/
private static String[] initLibPaths() {
String javaLibraryPath = System.getProperty("java.library.path");
if (javaLibraryPath == null) {
return EmptyArray.STRING;
}
String[] paths = javaLibraryPath.split(":");
// Add a '/' to the end of each directory so we don't have to do it every time.
for (int i = 0; i < paths.length; ++i) {
if (!paths[i].endsWith("/")) {
paths[i] += "/";
}
}
return paths;
}
private String doLoad(String name, ClassLoader loader) {
String ldLibraryPath = null;
if (loader != null && loader instanceof BaseDexClassLoader) {
ldLibraryPath = ((BaseDexClassLoader) loader).getLdLibraryPath();
}
synchronized (this) {
//最后调用nativeLoad方法加载库文件
return nativeLoad(name, loader, ldLibraryPath);
}
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
JNIEnv* env = NULL;
jint result = -1;
// 1.通过JavaVM获取JNIEnv,指定JNI的版本为1.4。
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto bail;
}
assert(env != NULL);
...
// 2.注册JNI方法
if (register_android_media_MediaPlayer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto bail;
}
...
/* success -- return valid version number */
// 3.返回JNI版本号
result = JNI_VERSION_1_4;
bail:
return result;
}
// 调用registerNativeMethods方法注册本地方法
static int register_android_media_MediaPlayer(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
static const JNINativeMethod gMethods[] = {
...
{"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"_start", "()V", (void *)android_media_MediaPlayer_start},
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
{"_pause", "()V", (void *)android_media_MediaPlayer_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
{"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
{"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer_release},
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
{"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
....
};
在framework/core/jni/AndroidRuntime.cpp文件中实现了registerNativeMethods方法,并最终调用jniRegisterNativeMethods方法。
/*
* Register native methods using JNI.
*/
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods)
{
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
JNIEnv* e = reinterpret_cast(env);
scoped_local_ref c(env, findClass(env, className));
...
// 调用RegisterNatives()方法完成注册
if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
...
}
return 0;
}
RegisterNatives方法在jni.h文件中定义。
struct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
...
jint RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods){
return functions->RegisterNatives(this, clazz, methods, nMethods);
}
....
}
functions是一个JNINativeInterface的指针,也将调用RegisterNatives()方法,再往下面就是虚拟机的内部实现了,在此不再详述。
struct JNINativeInterface {
void* reserved0;
void* reserved1;
void* reserved2;
void* reserved3;
....
jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,jint);
....
}
当不需要这些映射关系时,或者需要更新映射关系时,则需要调用
UnregisterNatives函数,来删除这些映射关系。
jint (*UnregisterNatives)(JNIEnv*, jclass);
至此,介绍了通过System.loadLibrary()方法注册JNI函数的过程。整体的流程如下图所示:
|
局部引用
|
全局引用
|
作用范围 |
本地方法内
|
全局范围 |
回收时机
|
本地方法返回时,自动回收
|
显式通知GC回收
|
适用范围
|
只在当前线程中有效 |
可以跨越多个线程
|
创建引用函数
|
jobject (*NewLocalRef)(JNIEnv*, jobject)
|
jobject (*NewGlobalRef)(JNIEnv*, jobject)
|
销毁引用函数 | void (*DeleteLocalRef)(JNIEnv*, jobject) |
void (*DeleteGlobalRef)(JNIEnv*, jobject)
|
jobject (*NewLocalRef)(JNIEnv*, jobject);
void (*DeleteLocalRef)(JNIEnv*, jobject);
jobject (*NewGlobalRef)(JNIEnv*, jobject);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);
void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);
jobject (*NewLocalRef)(JNIEnv*, jobject);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
jstring Jstring2CStr(JNIEnv* env, jstring jstr)
{
....
jclass clsstring = (*env)->FindClass(env,"java/lang/String");//局部变量
jstring native_desc = env->NewStringUTF(" I am Native");//局部变量
...
}
JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{ ....
jclass clazz = env->GetObjectClass(thiz);//局部引用
....
mClass = (jclass)env->NewGlobalRef(clazz);//创建全局引用并指向局部引用
...
mObject = env->NewGlobalRef(weak_thiz);//创建全局引用
}
JNIMediaPlayerListener::~JNIMediaPlayerListener()
{
// remove global references
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mObject);//移除全局引用
env->DeleteGlobalRef(mClass);//移除全局引用
}
当本地方法不再需要使用全局引用时,应该通过
DeleteGlobalRef方法来释放全局引用。否则的话,JVM不会回收被全局引用的对象。
static void android_media_MediaPlayer_native_init(JNIEnv *env,jobject obj)
{ ....
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类
jfieldID name = env->GetFieldID(clazz,"name","Ljava/lang/String;");//获取MediaPlayer类的域name的ID
jstring newName = env->NewStringUTF("media player");//创建一个新的字符串
env->setObjectField(obj,name,newName);//将MediaPlayer类中的name属性更新
....
}
static void android_media_MediaPlayer_start(JNIEnv *env, jobject obj)
{
....
jclass clazz;
clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类
jfieldID name = env->GetFieldID(clazz,"name","Ljava/lang/String;");//获取MediaPlayer类的域name的ID
jstring mediaName = (jstring)env->getObjectField(obj,name);//读取在android_media_MediaPlayer_native_init方法中更新的name对象值
...
}
public class JavaToNative{
static{
System.loadLibrary(“java_to_native”); // 通过System.loadLibrary()来加载本地代码库
}
private static native String hello(); // 声明native方法
public static void main(String args[]){
System.out.println(JavaToNative.hello()); // 调用native方法
}
}
jclass FindClass(const char* name);
name为类的全名,包含了类的完整路径,即包名+类名,以"/"代替"."分割符。例如:
jclass newStr = env->FindClass("java/lang/String");
还有一种方法是通过Object对象来获取其对应的类class对象,所调用的方法为
GetObjectClass,定义如下:
jclass GetObjectClass(jobject obj);
obj代表Java传递过来的对象,通过该方法可以获取该对象的类类型,其功能如同Object.getClass()方法。
struct _jfieldID; /* opaque structure */
typedef struct _jfieldID* jfieldID; /* field IDs */
struct _jmethodID; /* opaque structure */
typedef struct _jmethodID* jmethodID; /* method IDs */
在jni.h文件中,定义了获取属性ID和方法ID的方法:
//获取Java对象的属性ID
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig);
//获取Java类的静态属性ID
jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig)
//获取Java对象的方法ID
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
//获取Java类的静态方法ID
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig);
jclass clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类class
jfieldID name = env->GetFieldID(clazz,"name","Ljava/lang/String;");//获取MediaPlayer对象的属性name的ID
jmethodID getHost = env->GetMethodID(clazz, "getHost", "(V)Ljava/lang/String;");//获取MediaPlayer对象方法getHost()的ID
jfieldID port = env->GetStaticFieldID(clazz,"port","I");//获取MediaPlayer类的静态属性port的ID
jmethodID getPort = env->GetStaticMethodID(clazz,"getPort","(V)I");//获取MediaPlayer类的静态方法getPort()的ID
jobject GetObjectField(jobject obj, jfieldID fieldID);
jboolean GetBooleanField(jobject obj, jfieldID fieldID);
jint GetIntField(jobject obj, jfieldID fieldID);
...
void SetObjectField(jobject obj, jfieldID fieldID, jobject value);
void SetBooleanField(jobject obj, jfieldID fieldID, jboolean value);
void SetIntField(jobject obj, jfieldID fieldID, jint value);
...
jobject GetStaticObjectField(jclass clazz, jfieldID fieldID);
jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID);
jint GetStaticIntField(jclass clazz, jfieldID fieldID);
...
void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value);
void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value);
void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value);
....
static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
...
jclass clazz = env->GetObjectClass(thiz);//获取MediaPlayer类class
//获取和设置Java对象的属性
jfieldID name = env->GetFieldID(clazz,"name","Ljava/lang/String;");//获取MediaPlayer对象的属性name的ID
jstring newStr = env->NewStringUTF("local media player");
env->SetObjectField(thiz,name,newStr);//设置MediaPlayer对象的属性name的值
//获取和设置类的静态属性
jfieldID port = env->GetStaticFieldID(clazz,"port","I");//获取MediaPlayer类的静态属性port的ID
jint portNum = env->GetStaticIntField(claszz,port);//获取MediaPlayer类静态属性port的值
env->SetStaticIntField(clazz,port,portNum + 100);//设置MediaPlayer类静态属性port的值
...
}
void CallVoidMethod(jobject obj, jmethodID methodID, ...);
void CallVoidMethodV(jobject obj, jmethodID methodID, va_list args);
void CallVoidMethodA(jobject obj, jmethodID methodID, jvalue* args);
void CallStaticVoidMethod(jclass clazz, jmethodID methodID, ...);
void CallStaticVoidMethodV(jclass clazz, jmethodID methodID, va_list args);
void CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue* args);
static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
...
jclass clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类class
jmethodID getHost = env->GetMethodID(clazz, "getHost", "(V)Ljava/lang/String;");//获取MediaPlayer对象方法getHost()的ID
jmethodID getPort = env->GetStaticMethodID(clazz,"getPort","(V)I");//获取MediaPlayer类的静态方法getPort()的ID
env->CallObjectMethod(this,getHost);//调用MediaPlayer的成员方法getHost()
env->CallStaticIntMethod(clazz,getPort);//调用MediaPlayer类的静态方法getPort()
...
}
jobject NewObject(jclass clazz, jmethodID methodID, ...);
jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args);
jobject NewObjectA(jclass clazz, jmethodID methodID, jvalue* args);
jclass clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类class
jmethodID ctor = env->GetMethodID(clazz,"","(V)V");//获取默认构造方法ID
jobject mediaPlayer = env->NewObject(clazz,ctor);//调用构造函数创建MediaPlayer对象
jstring NewString(const jchar* unicodeChars, jsize len);
jstring NewStringUTF(const char* bytes);
const char* GetStringUTFChars(jstring string, jboolean* isCopy);
const jchar* GetStringChars(jstring string, jboolean* isCopy);
typedef unsigned short jchar; /* unsigned 16 bits */
void ReleaseStringChars(jstring string, const jchar* chars);
void ReleaseStringUTFChars(jstring string, const char* utf);
const char *tmp = env->GetStringUTFChars(path, NULL);
env->ReleaseStringUTFChars(path, tmp);
jsize GetArrayLength(jarray array);//获取数组的长度
jobjectArray NewObjectArray(jsize length, jclass elementClass,jobject initialElement);//创建Object对象数组
jobject GetObjectArrayElement(jobjectArray array, jsize index);//相当于array[index]
void SetObjectArrayElement(jobjectArray array, jsize index, jobject value);//相当于arry[index] = value
jcharArray NewCharArray(jsize length);
jchar* GetCharArrayElements(jcharArray array, jboolean* isCopy);
void ReleaseCharArrayElements(jcharArray array, jchar* elems,jint mode);
static void android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
{
jclass clazz = env->FindClass("android/media/MediaPlayer");//获取MediaPlayer类class
jfieldID arrayID = env->GetFieldID(clazz,"arrays", "[I");
jintArray array = (jintArray)(env->GetObjectField(thiz, arrayID));
jint* int_array = env->GetIntArrayElements(arr, NULL);
jsize len = env->GetArrayLength(array);
env->ReleaseIntArrayElements(array, int_array, JNI_ABORT);
}