The following is based on Android4.0.4
Start in a zygote
if(zygote){
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
}
Start zygote which is in the process of Dalvik () in runtime.start, starting @ com.android.internal.os.ZygoteInit complete execution void main (String []) with the use JNI mechanisms
In the start () @ AndroidRuntime.cpp, the key there is these points
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 方法
}
Look at the data structure definition, we need to focus on 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;
}
According to the data structure can be seen inside the Dalvik, JNIEnvExt be strong into JNIEnv use, as long as the visit does not exceed JNIEnv memory space. Similarly JavaVMExt be strong into JavaVM to use, as long as the visit does not exceed JavaVM defined memory space. Of course, this is also to internal conversion. Finally, look at the article
On behalf of JavaVmExt is a Dalvik virtual machine instances, on behalf of JNIEnvExt is JNI environment, each thread has its own associated with a JNI environment, and JavaVmExt save JNI environment in double-stranded form.
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;
}
Function table
//被赋值到 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,
};
![3012162-742c23ace92a997b.png](https://upload-images.jianshu.io/upload_images/3012162-742c23ace92a997b.png)
eg: when calling Java JNI function, use in the lookup jclass time is env-> FindClass ();
This function entry in the definition embodied in gNativeInterface (Jni.cpp), see below a FinClass (), and other JNI functions the implementation can also be seen in 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;
}
Similarly, () seen see AndroidRuntime :: getJNIEnv, there vm-> GetEnv () function, function entry in gInvokeInterface (Jni.cpp).
Reproduced in: https: //www.jianshu.com/p/7ecf0d314da8