Dalvik 的啟動(dòng)

以下是基于 Android4.0.4

在 zygote 啟動(dòng)一篇中

if(zygote){
  runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
}

其中便是在 runtime.start( )中啟動(dòng) zygote 進(jìn)程中的 Dalvik,啟動(dòng)完成用使用 JNI 機(jī)制執(zhí)行void main(String[ ]) @com.android.internal.os.ZygoteInit


在 start( )@AndroidRuntime.cpp 中,關(guān)鍵有這幾點(diǎn)

JavaVM* AndroidRuntime::mJavaVm = NULL;

void AndroidRuntime::start(const char* className, const char* options){
  ...
  JNIEnv* env;
  startVm(&mJavaVm, &env);
  onVmCreated(env);
  startReg(evn);
  ..
  //然后 JNI 執(zhí)行 className 對應(yīng)的 main 方法
}

先看定義的數(shù)據(jù)結(jié)構(gòu),需要關(guān)注的有 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;
}

根據(jù)數(shù)據(jù)結(jié)構(gòu)可以看到,在 Dalvik 內(nèi)部,JNIEnvExt可以強(qiáng)轉(zhuǎn)為JNIEnv使用,只要訪問不超出 JNIEnv 的內(nèi)存空間。同理 JavaVMExt 可以強(qiáng)轉(zhuǎn)為 JavaVM 使用,只要訪問不超出 JavaVM 定義的內(nèi)存空間。當(dāng)然內(nèi)部也是這樣去轉(zhuǎn)換的。在文章最后再來看


JavaVmExt 代表是是Dalvik 虛擬機(jī)實(shí)例,JNIEnvExt 代表是 JNI 環(huán)境,每個(gè)線程擁有一個(gè)自身相關(guān)的 JNI 環(huán)境,并且 JavaVmExt 中以雙鏈的形式保存 JNI 環(huán)境。

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv){
  ...
  //利用 property_get()方法解析 Dalvik 虛擬機(jī)的啟動(dòng)項(xiàng)
  ...
  //獲得Dalvik 啟動(dòng)項(xiàng)后,開始創(chuàng)建虛擬機(jī)實(shí)例 JavVmExt
  JNI_CreateJavaVM(pJavaVm, pEnv, &initArgs);
}
@.../dalvik/vm/Jni.cpp
jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args){
  //參數(shù)
  const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_arsg;
  //檢查版本號
  if(args->version < JNI_VERSION_1_2){
    return JNI_EVERSION;
  }
  //gDvm 的一個(gè)全局變量,保存著 Dalvik 的所有信息。在此處初始化內(nèi)存
  memset(&gDvm, 0, sizeof(gDvm));
   //為 Dalvik 實(shí)例分配內(nèi)存
  JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
  //初始化內(nèi)存
  memset(pVM, 0, sizeof(JavaVMExt));
  //函數(shù)表
  pVM->funcTable = &gInvokeInterface;
  ...
  //參數(shù)處理
  ...
  //將 Dalvik 實(shí)例 JavaVMExt 作為全局變量
  gDvmJni.jniVM = (JavaVM*) pVM;
  //初始化虛擬機(jī)環(huán)境,這里參數(shù) NULL 表示初始化Dalvik主線程
  JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
  gDvm.initializing = true;
  //虛擬機(jī)初始化,初始化了各個(gè)模塊
  //包括線程管理,類加載,解釋器,內(nèi)存管理,即時(shí)編譯,本地方法調(diào)用,反射機(jī)制實(shí)現(xiàn),調(diào)試支撐等
  std::string status = dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
}

 //主要是創(chuàng)建一個(gè) JNIEnv,設(shè)置 JNI 方法表,并且添加到 JavaVMExt->envList
JNIEnv* dvmCreateJNIEnv(Thread* self){
  //全局 Dalvik 實(shí)例
  JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
  //JNI 環(huán)境分配內(nèi)存
  JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
  //本地接口函數(shù)表,形如 FinClass( )等 JNI 函數(shù)的函數(shù)入口表
  newEnv->funcTable = &gNativeInterface;
  if(self != NULL){
    //在這里說明是初始化非主線程,將 JNI 環(huán)境關(guān)聯(lián)線程
    dvmSetJniEnvThreadId((JNIEnv*)newEnv, self);
  }else{
    //想要關(guān)聯(lián)的是主線程,先設(shè)置值,表示延后關(guān)聯(lián)
    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;
}

函數(shù)表

//被賦值到 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,
};
Dalvik 啟動(dòng)

eg:當(dāng) JNI 調(diào)用 Java 函數(shù)時(shí),在查找 jclass 的時(shí)候使用的是 env->FindClass( );
這個(gè)函數(shù)入口定義在gNativeInterface中(Jni.cpp),下面看一個(gè) FinClass( )的具體實(shí)現(xiàn),其他JNI 函數(shù)的實(shí)現(xiàn)也可以在 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( )函數(shù),函數(shù)入口在 gInvokeInterface(Jni.cpp)中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容