以下是基于 Android4.0.4
在 zygote 启动一篇中
if(zygote){
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
}
其中便是在 runtime.start( )中启动 zygote 进程中的 Dalvik,启动完成用使用 JNI 机制执行void main(String[ ]) @com.android.internal.os.ZygoteInit
在 start( )@AndroidRuntime.cpp 中,关键有这几点
JavaVM* AndroidRuntime::mJavaVm = NULL;
void AndroidRuntime::start(const char* className, const char* options){
...
JNIEnv* env;
startVm(&mJavaVm, &env);
onVmCreated(env);
startReg(evn);
..
//然后 JNI 执行 className 对应的 main 方法
}
先看定义的数据结构,需要关注的有 JavaVm, JNIEnv,JavaVmExt
struct JNIEnvExt {
const struct JNINativeInterface* funTable;
const struct JNINativeInterface* baseFuncTable;
u4 envThreadId;
Thread* self;
int critical;
struct JNIEnvExt* prev;
struct JNIEnvExt* next;
}
struct JavaVmExt{
const struct JNIInvokeInterface* funcTable;
const struct JNIInvokeInterface* baseFuncTable;
JNIEnvExt* envList;
pthread_mutex_t envListLock;
}
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvoleInterface* JavaVM;
//
/*static*/ JNIEnv* AndroidRuntime::getJNIEnv()
{
JNIEnv* env;
JavaVM* vm = AndroidRuntime::getJavaVM();
assert(vm != NULL);
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)
return NULL;
return env;
}
根据数据结构可以看到,在 Dalvik 内部,JNIEnvExt可以强转为JNIEnv使用,只要访问不超出 JNIEnv 的内存空间。同理 JavaVMExt 可以强转为 JavaVM 使用,只要访问不超出 JavaVM 定义的内存空间。当然内部也是这样去转换的。在文章最后再来看
JavaVmExt 代表是是Dalvik 虚拟机实例,JNIEnvExt 代表是 JNI 环境,每个线程拥有一个自身相关的 JNI 环境,并且 JavaVmExt 中以双链的形式保存 JNI 环境。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv){
...
//利用 property_get()方法解析 Dalvik 虚拟机的启动项
...
//获得Dalvik 启动项后,开始创建虚拟机实例 JavVmExt
JNI_CreateJavaVM(pJavaVm, pEnv, &initArgs);
}
@.../dalvik/vm/Jni.cpp
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args){
//参数
const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_arsg;
//检查版本号
if(args->version < JNI_VERSION_1_2){
return JNI_EVERSION;
}
//gDvm 的一个全局变量,保存着 Dalvik 的所有信息。在此处初始化内存
memset(&gDvm, 0, sizeof(gDvm));
//为 Dalvik 实例分配内存
JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
//初始化内存
memset(pVM, 0, sizeof(JavaVMExt));
//函数表
pVM->funcTable = &gInvokeInterface;
...
//参数处理
...
//将 Dalvik 实例 JavaVMExt 作为全局变量
gDvmJni.jniVM = (JavaVM*) pVM;
//初始化虚拟机环境,这里参数 NULL 表示初始化Dalvik主线程
JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
gDvm.initializing = true;
//虚拟机初始化,初始化了各个模块
//包括线程管理,类加载,解释器,内存管理,即时编译,本地方法调用,反射机制实现,调试支撑等
std::string status = dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
}
//主要是创建一个 JNIEnv,设置 JNI 方法表,并且添加到 JavaVMExt->envList
JNIEnv* dvmCreateJNIEnv(Thread* self){
//全局 Dalvik 实例
JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
//JNI 环境分配内存
JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
//本地接口函数表,形如 FinClass( )等 JNI 函数的函数入口表
newEnv->funcTable = &gNativeInterface;
if(self != NULL){
//在这里说明是初始化非主线程,将 JNI 环境关联线程
dvmSetJniEnvThreadId((JNIEnv*)newEnv, self);
}else{
//想要关联的是主线程,先设置值,表示延后关联
newEnv->envThreadId = 0x77777775;
newEnv->self = (Thread*)0x7777779;
}
...
// 将自身 JNIEnv 添加到 JavaVM 的 JNI 列表
newEnv->next = vm->envList;
if(vm->envList == NULL){
vm->envList = newEnv;
}else{
vm->envList->prev = newEnv;
}
vm->envList = newEnv;
return (JNIEnv*) newEnv;
}
函数表
//被赋值到 JNIEnvExt.funcTable
static const struct JNINativeInterface gNativeInterface = {
NULL,
NULL,
NULL,
NULL,
GetVersion,
DefineClass,
FindClass,
FromReflectedMethod,
FromReflectedField,
ToReflectedMethod,
GetSuperclass,
IsAssignableFrom,
ToReflectedField,
Throw,
ThrowNew,
ExceptionOccurred,
ExceptionDescribe,
ExceptionClear,
FatalError,
PushLocalFrame,
PopLocalFrame,
NewGlobalRef,
DeleteGlobalRef,
DeleteLocalRef,
IsSameObject,
NewLocalRef,
EnsureLocalCapacity,
AllocObject,
NewObject,
NewObjectV,
NewObjectA,
GetObjectClass,
IsInstanceOf,
GetMethodID,
CallObjectMethod,
CallObjectMethodV,
CallObjectMethodA,
CallBooleanMethod,
CallBooleanMethodV,
CallBooleanMethodA,
CallByteMethod,
CallByteMethodV,
CallByteMethodA,
CallCharMethod,
CallCharMethodV,
CallCharMethodA,
CallShortMethod,
CallShortMethodV,
CallShortMethodA,
CallIntMethod,
CallIntMethodV,
CallIntMethodA,
CallLongMethod,
CallLongMethodV,
CallLongMethodA,
CallFloatMethod,
CallFloatMethodV,
CallFloatMethodA,
CallDoubleMethod,
CallDoubleMethodV,
CallDoubleMethodA,
CallVoidMethod,
CallVoidMethodV,
CallVoidMethodA,
CallNonvirtualObjectMethod,
CallNonvirtualObjectMethodV,
CallNonvirtualObjectMethodA,
CallNonvirtualBooleanMethod,
CallNonvirtualBooleanMethodV,
CallNonvirtualBooleanMethodA,
CallNonvirtualByteMethod,
CallNonvirtualByteMethodV,
CallNonvirtualByteMethodA,
CallNonvirtualCharMethod,
CallNonvirtualCharMethodV,
CallNonvirtualCharMethodA,
CallNonvirtualShortMethod,
CallNonvirtualShortMethodV,
CallNonvirtualShortMethodA,
CallNonvirtualIntMethod,
CallNonvirtualIntMethodV,
CallNonvirtualIntMethodA,
CallNonvirtualLongMethod,
CallNonvirtualLongMethodV,
CallNonvirtualLongMethodA,
CallNonvirtualFloatMethod,
CallNonvirtualFloatMethodV,
CallNonvirtualFloatMethodA,
CallNonvirtualDoubleMethod,
CallNonvirtualDoubleMethodV,
CallNonvirtualDoubleMethodA,
CallNonvirtualVoidMethod,
CallNonvirtualVoidMethodV,
CallNonvirtualVoidMethodA,
GetFieldID,
GetObjectField,
GetBooleanField,
GetByteField,
GetCharField,
GetShortField,
GetIntField,
GetLongField,
GetFloatField,
GetDoubleField,
SetObjectField,
SetBooleanField,
SetByteField,
SetCharField,
SetShortField,
SetIntField,
SetLongField,
SetFloatField,
SetDoubleField,
GetStaticMethodID,
CallStaticObjectMethod,
CallStaticObjectMethodV,
CallStaticObjectMethodA,
CallStaticBooleanMethod,
CallStaticBooleanMethodV,
CallStaticBooleanMethodA,
CallStaticByteMethod,
CallStaticByteMethodV,
CallStaticByteMethodA,
CallStaticCharMethod,
CallStaticCharMethodV,
CallStaticCharMethodA,
CallStaticShortMethod,
CallStaticShortMethodV,
CallStaticShortMethodA,
CallStaticIntMethod,
CallStaticIntMethodV,
CallStaticIntMethodA,
CallStaticLongMethod,
CallStaticLongMethodV,
CallStaticLongMethodA,
CallStaticFloatMethod,
CallStaticFloatMethodV,
CallStaticFloatMethodA,
CallStaticDoubleMethod,
CallStaticDoubleMethodV,
CallStaticDoubleMethodA,
CallStaticVoidMethod,
CallStaticVoidMethodV,
CallStaticVoidMethodA,
GetStaticFieldID,
GetStaticObjectField,
GetStaticBooleanField,
GetStaticByteField,
GetStaticCharField,
GetStaticShortField,
GetStaticIntField,
GetStaticLongField,
GetStaticFloatField,
GetStaticDoubleField,
SetStaticObjectField,
SetStaticBooleanField,
SetStaticByteField,
SetStaticCharField,
SetStaticShortField,
SetStaticIntField,
SetStaticLongField,
SetStaticFloatField,
SetStaticDoubleField,
NewString,
GetStringLength,
GetStringChars,
ReleaseStringChars,
NewStringUTF,
GetStringUTFLength,
GetStringUTFChars,
ReleaseStringUTFChars,
GetArrayLength,
NewObjectArray,
GetObjectArrayElement,
SetObjectArrayElement,
NewBooleanArray,
NewByteArray,
NewCharArray,
NewShortArray,
NewIntArray,
NewLongArray,
NewFloatArray,
NewDoubleArray,
GetBooleanArrayElements,
GetByteArrayElements,
GetCharArrayElements,
GetShortArrayElements,
GetIntArrayElements,
GetLongArrayElements,
GetFloatArrayElements,
GetDoubleArrayElements,
ReleaseBooleanArrayElements,
ReleaseByteArrayElements,
ReleaseCharArrayElements,
ReleaseShortArrayElements,
ReleaseIntArrayElements,
ReleaseLongArrayElements,
ReleaseFloatArrayElements,
ReleaseDoubleArrayElements,
GetBooleanArrayRegion,
GetByteArrayRegion,
GetCharArrayRegion,
GetShortArrayRegion,
GetIntArrayRegion,
GetLongArrayRegion,
GetFloatArrayRegion,
GetDoubleArrayRegion,
SetBooleanArrayRegion,
SetByteArrayRegion,
SetCharArrayRegion,
SetShortArrayRegion,
SetIntArrayRegion,
SetLongArrayRegion,
SetFloatArrayRegion,
SetDoubleArrayRegion,
RegisterNatives,
UnregisterNatives,
MonitorEnter,
MonitorExit,
GetJavaVM,
GetStringRegion,
GetStringUTFRegion,
GetPrimitiveArrayCritical,
ReleasePrimitiveArrayCritical,
GetStringCritical,
ReleaseStringCritical,
NewWeakGlobalRef,
DeleteWeakGlobalRef,
ExceptionCheck,
NewDirectByteBuffer,
GetDirectBufferAddress,
GetDirectBufferCapacity,
GetObjectRefType
};
//赋值到JavaVMExt.funcTable
static const struct JNIInvokeInterface gInvokeInterface = {
NULL,
NULL,
NULL,
DestroyJavaVM,
AttachCurrentThread,
DetachCurrentThread,
GetEnv,
AttachCurrentThreadAsDaemon,
};
eg:当 JNI 调用 Java 函数时,在查找 jclass 的时候使用的是 env->FindClass( );
这个函数入口定义在gNativeInterface中(Jni.cpp),下面看一个 FinClass( )的具体实现,其他JNI 函数的实现也可以在 Jni.cpp 中看到
static jclass FindClass(JNIEnv* env, const char* name) {
ScopedJniThreadState ts(env);
const Method* thisMethod = dvmGetCurrentJNIMethod();
assert(thisMethod != NULL);
Object* loader;
Object* trackedLoader = NULL;
if (ts.self()->classLoaderOverride != NULL) {
/* hack for JNI_OnLoad */
assert(strcmp(thisMethod->name, "nativeLoad") == 0);
loader = ts.self()->classLoaderOverride;
} else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
thisMethod == gDvm.methDalvikSystemNativeStart_run) {
/* start point of invocation interface */
if (!gDvm.initializing) {
loader = trackedLoader = dvmGetSystemClassLoader();
} else {
loader = NULL;
}
} else {
loader = thisMethod->clazz->classLoader;
}
char* descriptor = dvmNameToDescriptor(name);
if (descriptor == NULL) {
return NULL;
}
ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
free(descriptor);
jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
dvmReleaseTrackedAlloc(trackedLoader, ts.self());
return jclazz;
}
同理,在 AndroidRuntime::getJNIEnv( )中看看到,有 vm->GetEnv( )函数,函数入口在 gInvokeInterface(Jni.cpp)中。
转载于:https://www.jianshu.com/p/7ecf0d314da8