Android5.1.1源碼 - 虛擬機的建立

Android5.1.1源碼 - 虛擬機的建立

@(Android研究)[Android|源碼|虛擬機]java


[TOC]android


虛擬機啓動時的函數調用路徑:數組

app_main.cc - main
  |-- AndroidRuntime::start
      |-- AndroidRuntime::startVm
          |-- JNI_CreateJavaVM

當init進程啓動zygote進程時會建立虛擬機,下是zygote代碼的main函數,本文從這裏開始分析虛擬機如何建立,這個函數在文件"frameworks/base/cmds/app_process/app_main.cpp"中,下面是它的源碼:app

int main(int argc, char* const argv[])
{
    ......

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 處理命令行參數
    // 忽略 argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm.
    //
    // The first argument after the VM args is the "parent dir", which
    // is currently unused.
    //
    // After the parent dir, we expect one or more the following internal
    // arguments :
    //
    // --zygote : Start in zygote mode
    // --start-system-server : 啓動系統服務
    // --application : Start in application (stand alone, non zygote) mode.
    // --nice-name : The nice name for this process.
    //
    // For non zygote starts, these arguments will be followed by
    // the main class name. All remaining arguments are passed to
    // the main method of this class.
    //
    // For zygote starts, all remaining arguments are passed to the zygote.
    // main function.
    //
    // Note that we must copy argument string values since we will rewrite the
    // entire argument block when we apply the nice name to argv0.

    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
        runtime.addOption(strdup(argv[i]));
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector<String8> args;
    if (!className.isEmpty()) {
        // We're not in zygote mode, the only argument we need to pass
        // to RuntimeInit is the application argument.
        //
        // The Remainder of args get passed to startup class main(). Make
        // copies of them before we overwrite them with the process name.
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        // We're in zygote mode.
        maybeCreateDalvikCache();

        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }

        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

**runtime.start(...)**語句啓動了Android運行時,在啓動Android運行時的同時會啓動虛擬機。main函數中的局部變量runtime是AppRuntime類的對象,這個類的代碼定義在文件"frameworks/base/cmds/app_process/app_main.cpp"中,AppRuntime類繼承了AndroidRuntime類,而start函數就是AndroidRuntime類的成員函數。ide

AndroidRuntime類定義在文件"frameworks/base/core/jni/AndroidRuntime.cpp"中,下面是AndroidRuntime::start函數的代碼:函數

/*
 * 啓動Android運行時。它啓動虛擬機並調用經過"className"參數所指定的類名中
 * 的"static void main(String[] args)"方法。
 *
 * 向main函數傳入兩個參數:類名和被指定的選項字符串。
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    ALOGD(">>>>>> START %s uid %d <<<<<<\n",
            className != NULL ? className : "(unknown)", getuid());

    ......

    /* 啓動虛擬機。 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);  // 初始化JNI API接口
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);  // 在zygote中這個函數什麼都不作。

    /*
     * Register android functions.
     */
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    /*
     * 咱們要調用main(),將一個字符串數組當作參數傳入。
     * 目前,咱們有兩個參數,類名和一個選項字符串。
     * 建立一個數組來保存它們。
     */
    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);
    }

    /*
     * 啓動Start VM。這個線程成爲VM的主線程,直到VM結束前不會返回。
     * 
     * 對於zygote而言除非設備關機不然這個線程是不會退出的,將zygote
     * 比做服務端,這個服務端會一直等待並處理各類客戶端的請求。
     */
    char* slashClassName = toSlashClassName(className);
    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 {
            // 調用Java方法。
            env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
            if (env->ExceptionCheck())
                threadExitUncaughtException(env);
#endif
        }
    }
    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");
}

這個函數主要作了下面三件事情:ui

  1. 調用**jni_invocation.Init(NULL);**語句初始化JNI API。
  2. 調用startVm函數建立了虛擬機。
  3. env->CallStaticVoidMethod語句調用類的main方法。

這個函數中調用了**onVmCreated(env);**語句,對於zygote來講,這個函數不作任何事情。this

jni_invocation雖然是AndroidRuntime::start函數的局部變量,可是對於zygote而言除非設備關機不然是不會退出AndroidRuntime::start函數的。對於普通APP,除非APP結束不然也不會退出AndroidRuntime::start函數。在另外一篇分析zygote啓動過程的文章中會說明緣由。命令行

JniInvocation::Init這個函數用於初始化JNI調用,這個函數在文件libnativehelper/JniInvocation.cpp中,下面是這個函數的代碼:線程

/**
 * 初始化JNI調用API。參數library應當傳入可供dlopen打開的有效的共享庫,
 * 這個共享庫提供一個JNI調用實現,或者參數library被傳入null則將經過
 * persist.sys.dalvik.vm.lib使用默認值。
 */
bool JniInvocation::Init(const char* library) {
#ifdef HAVE_ANDROID_OS
  char buffer[PROPERTY_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  // 得到共享庫名。
  library = GetLibrary(library, buffer);

  // 加載這個共享庫。
  handle_ = dlopen(library, RTLD_NOW);
  if (handle_ == NULL) {
    if (strcmp(library, kLibraryFallback) == 0) {
      // Nothing else to try.
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
    // Note that this is enough to get something like the zygote
    // running, we can't property_set here to fix this for the future
    // because we are root and not the system user. See
    // RuntimeInit.commonInit for where we fix up the property to
    // avoid future fallbacks. http://b/11463182
    ALOGW("Falling back from %s to %s after dlopen error: %s",
          library, kLibraryFallback, dlerror());
    library = kLibraryFallback;
    handle_ = dlopen(library, RTLD_NOW);
    if (handle_ == NULL) {
      ALOGE("Failed to dlopen %s: %s", library, dlerror());
      return false;
    }
  }

  // 找到符號JNI_GetDefaultJavaVMInitArgs。
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }

  // 找到符號JNI_CreateJavaVM。
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }

  // 找到符號JNI_GetCreatedJavaVMs。
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

這個函數作了下面兩件事情:

  1. 得到包含JNI接口的共享庫名。
  2. 加載這個共享庫。
  3. 從這個共享庫中得到了三個符號的地址:JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM和JNI_GetCreatedJavaVMs。

JniInvocation類中的成員變量handle_保存了共享庫的句柄,成員函數JNI_GetDefaultJavaVMInitArgs_、*JNI_CreateJavaVM_JNI_GetCreatedJavaVMs_*均保存了從共享庫中得到的函數地址。

JniInvocation::Init調用了JniInvocation::GetLibrary函數得到了共享庫名,這個共享庫中有JNI函數的實現,這個函數在文件libnativehelper/JniInvocation.cpp中,下面是它的代碼:

#ifdef HAVE_ANDROID_OS
static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
static const char* kDebuggableSystemProperty = "ro.debuggable";
static const char* kDebuggableFallback = "0";  // Not debuggable.
#endif
static const char* kLibraryFallback = "libart.so";

const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
#ifdef HAVE_ANDROID_OS
  const char* default_library;

  char debuggable[PROPERTY_VALUE_MAX];
  property_get(kDebuggableSystemProperty, debuggable, kDebuggableFallback);

  if (strcmp(debuggable, "1") != 0) {
    // Not a debuggable build.
    // Do not allow arbitrary library.  This
    // will also ignore the default library, but initialize to fallback
    // for cleanliness.
    library = kLibraryFallback;
    default_library = kLibraryFallback;
  } else {
    // Debuggable build.
    // Accept the library parameter. For the case it is NULL, load the default
    // library from the system property.
    if (buffer != NULL) {
      property_get(kLibrarySystemProperty, buffer, kLibraryFallback);
      default_library = buffer;
    } else {
      // 若是沒有指定緩衝區,使用備用的默認值。
      default_library = kLibraryFallback;
    }
  }
#else
  UNUSED(buffer);
  const char* default_library = kLibraryFallback;
#endif
  if (library == NULL) {
    library = default_library;
  }

  return library;
}

能夠發現JniInvocation::GetLibrary函數中默認的庫是kLibraryFallback,而這個變量的值爲libart.so,這個函數的返回值與kLibrarySystemProperty變量也有關係,而這個變量中保存的屬性對應的值一般爲libart.so。因此在這裏我武斷的認定這個函數的返回值總爲libart.so以便後面分析。

對AndroidRuntime::start函數中所執行**jni_invocation.Init(NULL);**語句作一個總結

  1. 它加載了libart.so。
  2. jni_invocation對象中保存了libart.so的句柄。
  3. jni_invocation對象中保存了JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM和JNI_GetCreatedJavaVMs這三個函數的地址。

繼續對AndroidRuntime::start函數進行分析,在執行完**jni_invocation.Init(NULL);**語句後緊接着調用了startVm函數,這個函數啓動了虛擬機。這個函數在文件frameworks/base/core/jni/AndroidRuntime.cpp中,下面是它的源碼:

/*
 * Start the Dalvik Virtual Machine.
 * (PS:這裏翻譯過來是:啓動Dalvik虛擬機,我認爲是這只不過是註釋內容還未被修改,而實際上啓動的已經不是dalvik虛擬機了)
 *
 * Various arguments, most determined by system properties, are passed in.
 * The "mOptions" vector is updated.
 *
 * CAUTION: when adding options in here, be careful not to put the
 * char buffer inside a nested scope.  Adding the buffer to the
 * options using mOptions.add() does not copy the buffer, so if the
 * buffer goes out of scope the option may be overwritten.  It's best
 * to put the buffer at the top of the function so that it is more
 * unlikely that someone will surround it in a scope at a later time
 * and thus introduce a bug.
 *
 * Returns 0 on success.
 */
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    int result = -1;
    JavaVMInitArgs initArgs;

    ......

    // checkjni屬性。
    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* 屬性即不爲真也不爲假;轉到內核參數。 */
        property_get("ro.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
    if (checkJni) {
        /* extended JNI checking */
        addOption("-Xcheck:jni");

        /* 設置JNI全局引用上限 */
        addOption("-Xjnigreflimit:2000");

        /* with -Xcheck:jni, 這提供JNI函數調用跟蹤 */
        //addOption("-verbose:jni");
    }

    // 根據屬性得到虛擬機的執行模式。
    property_get("dalvik.vm.execution-mode", propBuf, "");
    if (strcmp(propBuf, "int:portable") == 0) {
        executionMode = kEMIntPortable;
    } else if (strcmp(propBuf, "int:fast") == 0) {
        executionMode = kEMIntFast;
    } else if (strcmp(propBuf, "int:jit") == 0) {
        executionMode = kEMJitCompiler;
    }

    ......
    
    /* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
    parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:");

    /* Force interpreter-only mode for selected methods */
    parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");

    // 向mOptions中添加執行模式。
    if (executionMode == kEMIntPortable) {
        addOption("-Xint:portable");
    } else if (executionMode == kEMIntFast) {
        addOption("-Xint:fast");
    } else if (executionMode == kEMJitCompiler) {
        addOption("-Xint:jit");
    }

    // libart允許libdvm flags,但反過來不行,因此僅libart的狀況下才傳入一些選項。
    property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
    bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);

    if (libart) {
        ......
    }

    ......

    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;

    /*
     * 初始化VM。
     *
     * JavaVM*做用於每一個進程,JNIEnv*做用於每一個線程(The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.)。
     * 
     * 若是這個調用成功,則VM就緒,and we can start issuing
     * JNI calls.
     */
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        goto bail;
    }

    result = 0;

bail:
    return result;
}

AndroidRuntime::startVm函數主要作了兩件事情:

  1. 解析系統屬性,並將系統屬性添加到mOptions中,而後將mOptions封裝到initArgs中。
  2. 調用JNI_CreateJavaVM函數建立一個Java虛擬機。

系統屬性主要經過property_get函數得到,這個函數會去系統屬性文件中讀取屬性。

當要添加一個新的選項時會調用AndroidRuntime::addOption函數,它向mOptions中添加一個JavaVMOption對象,這個函數在frameworks/base/core/jni/AndroidRuntime.cpp文件中,下面是它的源碼:

void addOption(const char* optionString, void* extra_info = NULL);

void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
{
    JavaVMOption opt;
    opt.optionString = optionString;
    opt.extraInfo = extraInfo;
    mOptions.add(opt);
}

下面開始分析JNI_CreateJavaVM函數,這個定義在libnativehelper/JniInvocation.cpp文件中,下面是它的源碼:

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}

JniInvocation::GetJniInvocation()函數得到的是JniInvocation類的實例,JniInvocation::GetJniInvocation().JNI_CreateJavaVM調用的是JniInvocation類中非靜態成員函數JNI_CreateJavaVM,下面是這個成員函數的源碼:

jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}

JNI_CreateJavaVM_是JniInvocation類中的非靜態成員變量,它指向的是前面所加載的libart.so中的JNI_CreateJavaVM函數,這個成員變量在JniInvocation::Init函數中被賦值。

libart.so中的JNI_CreateJavaVM函數建立了虛擬機,它的源碼art/runtime/jni_internal.cc文件中,下面是這個函數的源碼:

/**
 * 建立虛擬機。
 * 參數p_vm和p_env是輸出參數。
 * 參數vm_args是輸入參數,這個參數保存的是虛擬機建立過程當中須要用到的選項。
 */
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);

  // 檢查Jni版本。
  if (IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    return JNI_EVERSION;
  }

  // 將全部的虛擬機選項均保存到options中。
  RuntimeOptions options;
  for (int i = 0; i < args->nOptions; ++i) {
    JavaVMOption* option = &args->options[i];
    options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
  }

  // 建立運行時環境。
  bool ignore_unrecognized = args->ignoreUnrecognized;
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  // 啓動運行時環境。
  Runtime* runtime = Runtime::Current();
  bool started = runtime->Start();
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    return JNI_ERR;
  }

  // 輸出參數。
  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

JNI_CreateJavaVM函數主要作了兩件事情:

  1. Runtime::Create語句建立運行時環境。
  2. **runtime->Start();**語句啓動運行時環境。

RuntimeOptions類型的定義在文件art/runtime/runtime.h中:

typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;

Runtime::Create函數是一個靜態函數在文件art/runtime/runtime.cc中,下面是它的源碼:

bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
  // TODO: acquire a static mutex on Runtime to avoid racing.
  if (Runtime::instance_ != NULL) {
    return false;
  }
  InitLogging(NULL);  // Calls Locks::Init() as a side effect.
  instance_ = new Runtime;
  if (!instance_->Init(options, ignore_unrecognized)) {
    delete instance_;
    instance_ = NULL;
    return false;
  }
  return true;
}

經過分析上面的代碼能夠發現Runtime類被設計爲單例模式,單例對象保存在instance_中,而後又調用了Init函數。

Runtime::Init函數在文件art/runtime/runtime.cc中,下面是它的源碼:

bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
  CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);

  MemMap::Init();

  std::unique_ptr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));

  ......

  java_vm_ = new JavaVMExt(this, options.get());

  Thread::Startup();

  // ClassLinker needs an attached thread, but we can't fully attach a thread without creating
  // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main
  // thread, we do not get a java peer.
  Thread* self = Thread::Attach("main", false, nullptr, false);

  ......

  VLOG(startup) << "Runtime::Init exiting";
  return true;
}

這個函數中的new JavaVMExt語句建立了JavaVMExt對象,一個虛擬機有且僅有一個JavaVMExt對象,JavaVMExt類型繼承了JavaVM類型,能夠去查看"art/runtime/jni_internal.h"文件。Thread::Attach函數將虛擬機附加到主線程上。

Thread::Attach函數的源碼在文件"art/runtime/thread.cc"文件中,下面是它的源碼:

Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
                       bool create_peer) {
  Thread* self;
  Runtime* runtime = Runtime::Current();
  if (runtime == nullptr) {
    LOG(ERROR) << "Thread attaching to non-existent runtime: " << thread_name;
    return nullptr;
  }
  {
    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
    if (runtime->IsShuttingDownLocked()) {
      ......
    } else {
      Runtime::Current()->StartThreadBirth();
      self = new Thread(as_daemon);
      self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
      Runtime::Current()->EndThreadBirth();
    }
  }

  ......
}

在這個函數中建立了Thread對象,而後調用了Thread::Init函數,在這個函數中建立了當前線程的JNIEnv。

Thread::Init函數的源碼在文件"art/runtime/thread.cc"文件中,下面是這個函數的源碼:

void Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm) {
  ......

  tlsPtr_.jni_env = new JNIEnvExt(this, java_vm);
  
  ......
}

這個函數中建立了JNIEnvExt對象。JNIEnvExt類型繼承了JNIEnv類型,能夠去"art/runtime/jni_internal.h"文件中查看。

如今回到JNI_CreateJavaVM函數中,Runtime::Create函數執行完後,將執行Runtime::Start函數啓動Android運行時,然會調用這兩行語句返回建立的Java虛擬機對象和當前線程的JNI環境:

*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();

Thread::Current函數得到當前線程的對象。

Tread::GetJniEnv()得到當前線程的JNI環境,這個函數的定義在文件"art/runtime/thread-inl.h"中,下面是它的源碼:

// JNI methods
JNIEnvExt* GetJniEnv() const {
  return tlsPtr_.jni_env;
}

Runtime::GetJavaVM()函數得到的是Java虛擬機對象,它的定義在文件"art/runtime/runtime.h"中,下面是它的源碼:

JavaVMExt* GetJavaVM() const {
  return java_vm_;
}

執行完JNI_CreateJavaVM函數後返回到startVM函數中。

執行完startVM成功啓動虛擬機後,將會經過env->CallStaticVoidMethod語句調用"com.android.internal.os.ZygoteInit"這個Java類的main方法,這個Java方法將會啓動zygote服務。

關於如何啓動zygote服務將另寫一篇文章分析。

至此Android5.1源碼虛擬機啓動過程分析完畢。

相關文章
相關標籤/搜索