[置顶] 安卓高手之路之ClassLoader(二)

来源:互联网 发布:cda数据分析师考试书籍 编辑:程序博客网 时间:2024/05/17 02:15

因为ClassLoader一定与虚拟机的启动有关系,那么必须从Zygote的启动开始看代码。下面就分析一下这些代码,行数不多:

int main(int argc, const char* const argv[]){    // These are global variables in ProcessState.cpp    //ProcessState.cpp中可能要用到一些main函数。    mArgC = argc;    mArgV = argv;    mArgLen = 0;    for (int i=0; i<argc; i++) {        mArgLen += strlen(argv[i]) + 1;    }    mArgLen--;    AppRuntime runtime;    const char* argv0 = argv[0];    // Process command line arguments    // ignore argv[0]    argc--;    argv++;    // Everything up to '--' or first non '-' arg goes to the vm    int i = runtime.addVmArguments(argc, argv);    // Parse runtime arguments.  Stop at first unrecognized option.    bool zygote = false;    bool startSystemServer = false;    bool application = false;    const char* parentDir = NULL;    const char* niceName = NULL;    const char* className = NULL;    while (i < argc) {        const char* arg = argv[i++];        if (!parentDir) {            parentDir = arg;        } else if (strcmp(arg, "--zygote") == 0) {            zygote = true;            niceName = "zygote";        } 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 = arg + 12;        } else {            className = arg;            break;        }    }    if (niceName && *niceName) {        setArgv0(argv0, niceName);        set_process_name(niceName);    }    runtime.mParentDir = parentDir;    if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit",                startSystemServer ? "start-system-server" : "");    } else if (className) {        // Remainder of args get passed to startup class main()        runtime.mClassName = className;        runtime.mArgC = argc - i;        runtime.mArgV = argv + i;        runtime.start("com.android.internal.os.RuntimeInit",                application ? "application" : "tool");    } 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;    }}

 分析完之后发现如下参数规律:

 

    1. argv[0]:用这个修改了进程名称。

    2. 虚拟机参数:前面的选项参数都是以“-”打头。被放入了runtime。这些参数被称为是虚拟机参数。

    3.“--”打头的参数是zygote参数。有如下几种,排列顺序如下:

          -runtimearg[0]

         -runtimearg[1]

         。。。。

          parentDir //这个也是runtime使用的,也就是VM使用的。

          className//这个也是runtime使用的,也就是VM使用的。

 

          --zygote

          --start-system-server

          --application

          --nice-name=

 

然后,如果是zygote,那么进入下面这句话

    

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

 

 

如果有类名,那么进入下面这句话:

   

  runtime.mClassName = className;     runtime.mArgC = argc - i; //className,包括className以后的参数个数。   runtime.mArgV = argv + i; //截止到className的参数个数  runtime.start("com.android.internal.os.RuntimeInit",                application ? "application" : "tool");

 

 

第一部分:那么开机第一次启动的就一定是,

  

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

 其中startSystemServer 由init.rc指定,在目录android40\system\core\rootdir中的init.rc.

   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 media
    onrestart restart netd

 

第二部分:从ActivityManagerService可以看出,--application并没有指定,这句话也就相当于:

runtime.start("com.android.internal.os.RuntimeInit", "tool");

 现在代码分成了两部分。

 

那么先分析第一部分。

那么zygote启动到底配置了那些参数呢,我们就看一看:

   service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

根据上面说的参数序列图,可以看出。

   runtime.mParentDir  为/system/bin

   runtime的一个arg为-Xzygote

那么这个这个start函数就变成:

runtime.start("com.android.internal.os.ZygoteInit",  "start-system-server");

 

 

代码进入到base/core/jni目录的AndroidRuntime.cpp里面。这个函数还不算长,就直接贴出来看一下,注意注释,由此可以看出这个就是启动虚拟机的代码所在啊。那么既然Zygote进程也是这么启动的,那么我们就有理由断定Zygote也是个Dalvik虚拟机!事情是不是这样呢?那么就带着这个疑问去分析一下:

 

/* * 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 char* options){    LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",            className != NULL ? className : "(unknown)");    blockSigpipe();    /*     * 'startSystemServer == true' means runtime is obsolete and not run from     * init.rc anymore, so we print out the boot start event here.     */    if (strcmp(options, "start-system-server") == 0) {        /* track our progress through the boot sequence */        const int LOG_BOOT_PROGRESS_START = 3000;        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));    }    const char* rootDir = getenv("ANDROID_ROOT");    if (rootDir == NULL) {        rootDir = "/system";        if (!hasDir("/system")) {            LOG_FATAL("No root directory specified, and /android does not exist.");            return;        }        setenv("ANDROID_ROOT", rootDir, 1);    }    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");    //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);    /* start the virtual machine */    JNIEnv* env;    if (startVm(&mJavaVM, &env) != 0) {        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) {        LOGE("Unable to register all android natives\n");        return;    }    /*     * We want to call main() with a String array with arguments in it.     * At present we have two arguments, the class name and an option string.     * Create an array to hold them.     */    jclass stringClass;    jobjectArray strArray;    jstring classNameStr;    jstring optionsStr;    stringClass = env->FindClass("java/lang/String");    assert(stringClass != NULL);    strArray = env->NewObjectArray(2, stringClass, NULL);    assert(strArray != NULL);    classNameStr = env->NewStringUTF(className);    assert(classNameStr != NULL);    env->SetObjectArrayElement(strArray, 0, classNameStr);    optionsStr = env->NewStringUTF(options);    env->SetObjectArrayElement(strArray, 1, optionsStr);    /*     * Start VM.  This thread becomes the main thread of the VM, and will     * not return until the VM exits.     */    char* slashClassName = toSlashClassName(className);    jclass startClass = env->FindClass(slashClassName);    if (startClass == NULL) {        LOGE("JavaVM unable to locate class '%s'\n", slashClassName);        /* keep going */    } else {        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",            "([Ljava/lang/String;)V");        if (startMeth == NULL) {            LOGE("JavaVM unable to find main() in '%s'\n", className);            /* keep going */        } else {            env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0            if (env->ExceptionCheck())                threadExitUncaughtException(env);#endif        }    }    free(slashClassName);    LOGD("Shutting down VM\n");    if (mJavaVM->DetachCurrentThread() != JNI_OK)        LOGW("Warning: unable to detach main thread\n");    if (mJavaVM->DestroyJavaVM() != 0)        LOGW("Warning: VM did not shut down cleanly\n");}

 

linux的POSIX (Portable Operating System Interface of Unix)我不懂。但是从直观上看,可能是一种禁止打断进程的方法:

 

    LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",            className != NULL ? className : "(unknown)");    blockSigpipe();

 下面这句话毫无意义,就是打印log

  

if (strcmp(options, "start-system-server") == 0) {        /* track our progress through the boot sequence */        const int LOG_BOOT_PROGRESS_START = 3000;        LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,                       ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));    }

 下面这句话定义androidroot的目录

 

  

   const char* rootDir = getenv("ANDROID_ROOT");    if (rootDir == NULL) {        rootDir = "/system";        if (!hasDir("/system")) {            LOG_FATAL("No root directory specified, and /android does not exist.");            return;        }        setenv("ANDROID_ROOT", rootDir, 1);    }

 对照init.rc可以知道,就是/system

 

 

# setup the global environment    export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin    export LD_LIBRARY_PATH /vendor/lib:/system/lib    export ANDROID_BOOTLOGO 1    export ANDROID_ROOT /system    export ANDROID_ASSETS /system/app    export ANDROID_DATA /data    export ASEC_MOUNTPOINT /mnt/asec    export LOOP_MOUNTPOINT /mnt/obb    export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/filterfw.jar

 

主要是下面这两句话

 

  /* start the virtual machine */    JNIEnv* env;    if (startVm(&mJavaVM, &env) != 0) {        return;    }    onVmCreated(env);    /*     * Register android functions.     */    if (startReg(env) < 0) {        LOGE("Unable to register all android natives\n");        return;    }

 

 

 一个启动虚拟机,一个启动注册安卓本地方法。虚拟机的启动流程,最终调用的是

JNI_CreateJavaVM 在framework/base/core/jni/AndroidRuntime.cpp下。JNI_CreateJavaVM 调用的是:

 然后调用dalvik/vm/Jni.cpp的JNI_CreateJavaVM 方法:

 

jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;    if (args->version < JNI_VERSION_1_2) {        return JNI_EVERSION;    }    // TODO: don't allow creation of multiple VMs -- one per customer for now    /* zero globals; not strictly necessary the first time a VM is started */    memset(&gDvm, 0, sizeof(gDvm));    /*     * Set up structures for JNIEnv and VM.     */    JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));    memset(pVM, 0, sizeof(JavaVMExt));    pVM->funcTable = &gInvokeInterface;    pVM->envList = NULL;    dvmInitMutex(&pVM->envListLock);    UniquePtr<const char*[]> argv(new const char*[args->nOptions]);    memset(argv.get(), 0, sizeof(char*) * (args->nOptions));    /*     * Convert JNI args to argv.     *     * We have to pull out vfprintf/exit/abort, because they use the     * "extraInfo" field to pass function pointer "hooks" in.  We also     * look for the -Xcheck:jni stuff here.     */    int argc = 0;    for (int i = 0; i < args->nOptions; i++) {        const char* optStr = args->options[i].optionString;        if (optStr == NULL) {            dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);            return JNI_ERR;        } else if (strcmp(optStr, "vfprintf") == 0) {            gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;        } else if (strcmp(optStr, "exit") == 0) {            gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;        } else if (strcmp(optStr, "abort") == 0) {            gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;        } else if (strcmp(optStr, "sensitiveThread") == 0) {            gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;        } else if (strcmp(optStr, "-Xcheck:jni") == 0) {            gDvmJni.useCheckJni = true;        } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {            char* jniOpts = strdup(optStr + 10);            size_t jniOptCount = 1;            for (char* p = jniOpts; *p != 0; ++p) {                if (*p == ',') {                    ++jniOptCount;                    *p = 0;                }            }            char* jniOpt = jniOpts;            for (size_t i = 0; i < jniOptCount; ++i) {                if (strcmp(jniOpt, "warnonly") == 0) {                    gDvmJni.warnOnly = true;                } else if (strcmp(jniOpt, "forcecopy") == 0) {                    gDvmJni.forceCopy = true;                } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {                    gDvmJni.logThirdPartyJni = true;                } else {                    dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",                            jniOpt);                    return JNI_ERR;                }                jniOpt += strlen(jniOpt) + 1;            }            free(jniOpts);        } else {            /* regular option */            argv[argc++] = optStr;        }    }    if (gDvmJni.useCheckJni) {        dvmUseCheckedJniVm(pVM);    }    if (gDvmJni.jniVm != NULL) {        dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");        return JNI_ERR;    }    gDvmJni.jniVm = (JavaVM*) pVM;    /*     * Create a JNIEnv for the main thread.  We need to have something set up     * here because some of the class initialization we do when starting     * up the VM will call into native code.     */    JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);    /* Initialize VM. */    gDvm.initializing = true;    std::string status =            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);    gDvm.initializing = false;    if (!status.empty()) {        free(pEnv);        free(pVM);        LOGW("CreateJavaVM failed: %s", status.c_str());        return JNI_ERR;    }    /*     * Success!  Return stuff to caller.     */    dvmChangeStatus(NULL, THREAD_NATIVE);    *p_env = (JNIEnv*) pEnv;    *p_vm = (JavaVM*) pVM;    LOGV("CreateJavaVM succeeded");    return JNI_OK;}

 

 

  然后调用Jni.cpp中的

 

/* * Create a new JNIEnv struct and add it to the VM's list. * * "self" will be NULL for the main thread, since the VM hasn't started * yet; the value will be filled in later. */JNIEnv* dvmCreateJNIEnv(Thread* self) {    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;    //if (self != NULL)    //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);    assert(vm != NULL);    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));    newEnv->funcTable = &gNativeInterface;    if (self != NULL) {        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);        assert(newEnv->envThreadId != 0);    } else {        /* make it obvious if we fail to initialize these later */        newEnv->envThreadId = 0x77777775;        newEnv->self = (Thread*) 0x77777779;    }    if (gDvmJni.useCheckJni) {        dvmUseCheckedJniEnv(newEnv);    }    ScopedPthreadMutexLock lock(&vm->envListLock);    /* insert at head of list */    newEnv->next = vm->envList;    assert(newEnv->prev == NULL);    if (vm->envList == NULL) {        // rare, but possible        vm->envList = newEnv;    } else {        vm->envList->prev = newEnv;    }    vm->envList = newEnv;    //if (self != NULL)    //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);    return (JNIEnv*) newEnv;}

 

 

   好吧,这些全是些乱七八糟的东西。真正启动的是这句话,Jni.cpp中:

  

 std::string status =            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);

 

 

 在Dalvik/vm/Init.cpp中

* * VM initialization.  Pass in any options provided on the command line. * Do not pass in the class name or the options for the class. * * Returns 0 on success. */std::string dvmStartup(int argc, const char* const argv[],        bool ignoreUnrecognized, JNIEnv* pEnv){    ScopedShutdown scopedShutdown;    assert(gDvm.initializing);    LOGV("VM init args (%d):", argc);    for (int i = 0; i < argc; i++) {        LOGV("  %d: '%s'", i, argv[i]);    }    setCommandLineDefaults();    /*     * Process the option flags (if any).     */    int cc = processOptions(argc, argv, ignoreUnrecognized);    if (cc != 0) {        if (cc < 0) {            dvmFprintf(stderr, "\n");            usage("dalvikvm");        }        return "syntax error";    }#if WITH_EXTRA_GC_CHECKS > 1    /* only "portable" interp has the extra goodies */    if (gDvm.executionMode != kExecutionModeInterpPortable) {        LOGI("Switching to 'portable' interpreter for GC checks");        gDvm.executionMode = kExecutionModeInterpPortable;    }#endif    /* Configure group scheduling capabilities */    if (!access("/dev/cpuctl/tasks", F_OK)) {        LOGV("Using kernel group scheduling");        gDvm.kernelGroupScheduling = 1;    } else {        LOGV("Using kernel scheduler policies");    }    /* configure signal handling */    if (!gDvm.reduceSignals)        blockSignals();    /* verify system page size */    if (sysconf(_SC_PAGESIZE) != SYSTEM_PAGE_SIZE) {        return StringPrintf("expected page size %d, got %d",                SYSTEM_PAGE_SIZE, (int) sysconf(_SC_PAGESIZE));    }    /* mterp setup */    LOGV("Using executionMode %d", gDvm.executionMode);    dvmCheckAsmConstants();    /*     * Initialize components.     */    dvmQuasiAtomicsStartup();    if (!dvmAllocTrackerStartup()) {        return "dvmAllocTrackerStartup failed";    }    if (!dvmGcStartup()) {        return "dvmGcStartup failed";    }    if (!dvmThreadStartup()) {        return "dvmThreadStartup failed";    }    if (!dvmInlineNativeStartup()) {        return "dvmInlineNativeStartup";    }    if (!dvmRegisterMapStartup()) {        return "dvmRegisterMapStartup failed";    }    if (!dvmInstanceofStartup()) {        return "dvmInstanceofStartup failed";    }    if (!dvmClassStartup()) {        return "dvmClassStartup failed";    }    /*     * At this point, the system is guaranteed to be sufficiently     * initialized that we can look up classes and class members. This     * call populates the gDvm instance with all the class and member     * references that the VM wants to use directly.     */    if (!dvmFindRequiredClassesAndMembers()) {        return "dvmFindRequiredClassesAndMembers failed";    }    if (!dvmStringInternStartup()) {        return "dvmStringInternStartup failed";    }    if (!dvmNativeStartup()) {        return "dvmNativeStartup failed";    }    if (!dvmInternalNativeStartup()) {        return "dvmInternalNativeStartup failed";    }    if (!dvmJniStartup()) {        return "dvmJniStartup failed";    }    if (!dvmProfilingStartup()) {        return "dvmProfilingStartup failed";    }    /*     * Create a table of methods for which we will substitute an "inline"     * version for performance.     */    if (!dvmCreateInlineSubsTable()) {        return "dvmCreateInlineSubsTable failed";    }    /*     * Miscellaneous class library validation.     */    if (!dvmValidateBoxClasses()) {        return "dvmValidateBoxClasses failed";    }    /*     * Do the last bits of Thread struct initialization we need to allow     * JNI calls to work.     */    if (!dvmPrepMainForJni(pEnv)) {        return "dvmPrepMainForJni failed";    }    /*     * Explicitly initialize java.lang.Class.  This doesn't happen     * automatically because it's allocated specially (it's an instance     * of itself).  Must happen before registration of system natives,     * which make some calls that throw assertions if the classes they     * operate on aren't initialized.     */    if (!dvmInitClass(gDvm.classJavaLangClass)) {        return "couldn't initialized java.lang.Class";    }    /*     * Register the system native methods, which are registered through JNI.     */    if (!registerSystemNatives(pEnv)) {        return "couldn't register system natives";    }    /*     * Do some "late" initialization for the memory allocator.  This may     * allocate storage and initialize classes.     */    if (!dvmCreateStockExceptions()) {        return "dvmCreateStockExceptions failed";    }    /*     * At this point, the VM is in a pretty good state.  Finish prep on     * the main thread (specifically, create a java.lang.Thread object to go     * along with our Thread struct).  Note we will probably be executing     * some interpreted class initializer code in here.     */    if (!dvmPrepMainThread()) {        return "dvmPrepMainThread failed";    }    /*     * Make sure we haven't accumulated any tracked references.  The main     * thread should be starting with a clean slate.     */    if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0)    {        LOGW("Warning: tracked references remain post-initialization");        dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");    }    /* general debugging setup */    if (!dvmDebuggerStartup()) {        return "dvmDebuggerStartup failed";    }    if (!dvmGcStartupClasses()) {        return "dvmGcStartupClasses failed";    }    /*     * Init for either zygote mode or non-zygote mode.  The key difference     * is that we don't start any additional threads in Zygote mode.     */    if (gDvm.zygote) {        if (!initZygote()) {            return "initZygote failed";        }    } else {        if (!dvmInitAfterZygote()) {            return "dvmInitAfterZygote failed";        }    }#ifndef NDEBUG    if (!dvmTestHash())        LOGE("dvmTestHash FAILED");    if (false /*noisy!*/ && !dvmTestIndirectRefTable())        LOGE("dvmTestIndirectRefTable FAILED");#endif    if (dvmCheckException(dvmThreadSelf())) {        dvmLogExceptionStackTrace();        return "Exception pending at end of VM initialization";    }    scopedShutdown.disarm();    return "";}

 代码真长。寻找其中最具价值的部分

       

插入代码:

 

          

   if (!dvmAllocTrackerStartup()) {        return "dvmAllocTrackerStartup failed";    }    if (!dvmGcStartup()) {        return "dvmGcStartup failed";    }    if (!dvmThreadStartup()) {        return "dvmThreadStartup failed";    }    if (!dvmInlineNativeStartup()) {        return "dvmInlineNativeStartup";    }    if (!dvmRegisterMapStartup()) {        return "dvmRegisterMapStartup failed";    }    if (!dvmInstanceofStartup()) {        return "dvmInstanceofStartup failed";    }    if (!dvmClassStartup()) {        return "dvmClassStartup failed";    }

 经分析,这些都没有建立gc线程,gc线程的建立是在如下方法:

 

 

dvmInitAfterZygote

 

  由于跟得太深,东西很多,就不一一列举。仅仅跟一下dvmClassStartup,最终调用到了dalvik/vm/oo/Class.cpp中的方法:

 

/* * Initialize the bootstrap class loader. * * Call this after the bootclasspath string has been finalized. */bool dvmClassStartup(){    /* make this a requirement -- don't currently support dirs in path */    if (strcmp(gDvm.bootClassPathStr, ".") == 0) {        LOGE("ERROR: must specify non-'.' bootclasspath");        return false;    }    gDvm.loadedClasses =        dvmHashTableCreate(256, (HashFreeFunc) dvmFreeClassInnards);    gDvm.pBootLoaderAlloc = dvmLinearAllocCreate(NULL);    if (gDvm.pBootLoaderAlloc == NULL)        return false;    if (false) {        linearAllocTests();        exit(0);    }    /*     * Class serial number.  We start with a high value to make it distinct     * in binary dumps (e.g. hprof).     */    gDvm.classSerialNumber = INITIAL_CLASS_SERIAL_NUMBER;    /*     * Set up the table we'll use for tracking initiating loaders for     * early classes.     * If it's NULL, we just fall back to the InitiatingLoaderList in the     * ClassObject, so it's not fatal to fail this allocation.     */    gDvm.initiatingLoaderList = (InitiatingLoaderList*)        calloc(ZYGOTE_CLASS_CUTOFF, sizeof(InitiatingLoaderList));    /*     * Create the initial classes. These are the first objects constructed     * within the nascent VM.     */    if (!createInitialClasses()) {        return false;    }    /*     * Process the bootstrap class path.  This means opening the specified     * DEX or Jar files and possibly running them through the optimizer.     */    assert(gDvm.bootClassPath == NULL);    processClassPath(gDvm.bootClassPathStr, true);    if (gDvm.bootClassPath == NULL)        return false;    return true;}

 根据注释,Initialize the bootstrap class loader.
这个函数告诉我们,他建立了boottrap classloader。

createInitialClasses加载了9大基本类型。而后的processClassPath则建立了基本的classloader。分析过后,比较失望。可能是为后续的boottrapclassloader做一些前期准备工作。

startVM就到这里。

 

好吧。现在又回到了最初的App_main.cpp中。进入了com.android.internal.os.ZygoteInit.java的main

 

    public static void main(String argv[]) {        try {            // Start profiling the zygote initialization.            SamplingProfilerIntegration.start();            registerZygoteSocket();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,                SystemClock.uptimeMillis());            preload();            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,                SystemClock.uptimeMillis());            // Finish profiling the zygote initialization.            SamplingProfilerIntegration.writeZygoteSnapshot();            // Do an initial gc to clean up after startup            gc();            // If requested, start system server directly from Zygote            if (argv.length != 2) {                throw new RuntimeException(argv[0] + USAGE_STRING);            }            if (argv[1].equals("start-system-server")) {                startSystemServer();            } else if (!argv[1].equals("")) {                throw new RuntimeException(argv[0] + USAGE_STRING);            }            Log.i(TAG, "Accepting command socket connections");            if (ZYGOTE_FORK_MODE) {                runForkMode();            } else {                runSelectLoopMode();            }            closeServerSocket();        } catch (MethodAndArgsCaller caller) {            caller.run();        } catch (RuntimeException ex) {            Log.e(TAG, "Zygote died with exception", ex);            closeServerSocket();            throw ex;        }    }

 

 

 回过头来继续看一下ZygoteInit.java这个类是如何初始化的,看如下代码:

/* * Create a new JNIEnv struct and add it to the VM's list. * * "self" will be NULL for the main thread, since the VM hasn't started * yet; the value will be filled in later. */JNIEnv* dvmCreateJNIEnv(Thread* self) {    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;    //if (self != NULL)    //    LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);    assert(vm != NULL);    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));    newEnv->funcTable = &gNativeInterface;    if (self != NULL) {        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);        assert(newEnv->envThreadId != 0);    } else {        /* make it obvious if we fail to initialize these later */        newEnv->envThreadId = 0x77777775;        newEnv->self = (Thread*) 0x77777779;    }    if (gDvmJni.useCheckJni) {        dvmUseCheckedJniEnv(newEnv);    }    ScopedPthreadMutexLock lock(&vm->envListLock);    /* insert at head of list */    newEnv->next = vm->envList;    assert(newEnv->prev == NULL);    if (vm->envList == NULL) {        // rare, but possible        vm->envList = newEnv;    } else {        vm->envList->prev = newEnv;    }    vm->envList = newEnv;    //if (self != NULL)    //    LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);    return (JNIEnv*) newEnv;}

 

 

 

 最重要的是gNativeInterface 我们看定义,太长了,我们找到其中的FindClass。

 

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;}

 

 

在dalvik/vm/Init.cpp中的方法对gVM的bootpath进行了初始化:

 

 

static void setCommandLineDefaults(){    const char* envStr = getenv("CLASSPATH");    if (envStr != NULL) {        gDvm.classPathStr = strdup(envStr);    } else {        gDvm.classPathStr = strdup(".");    }    envStr = getenv("BOOTCLASSPATH");    if (envStr != NULL) {        gDvm.bootClassPathStr = strdup(envStr);    } else {        gDvm.bootClassPathStr = strdup(".");    }    gDvm.properties = new std::vector<std::string>();    /* Defaults overridden by -Xms and -Xmx.     * TODO: base these on a system or application-specific default     */    gDvm.heapStartingSize = 2 * 1024 * 1024;  // Spec says 16MB; too big for us.    gDvm.heapMaximumSize = 16 * 1024 * 1024;  // Spec says 75% physical mem    gDvm.heapGrowthLimit = 0;  // 0 means no growth limit    gDvm.stackSize = kDefaultStackSize;    gDvm.concurrentMarkSweep = true;    /* gDvm.jdwpSuspend = true; */

 

现在明白了,在init.rc中指定的BOOTCLASSPATH赋值给了gDvm.bootClassPathStr 。

而下面这个地方,则对FindClass进行了初始化。还是在dalvik/vm/Init.cpp中

     */    if (!dvmFindRequiredClassesAndMembers()) {        return "dvmFindRequiredClassesAndMembers failed";    }

initDirectMethodReferences 把方法gDvm.methDalvikSystemNativeStart_main与NativeStart进行了对应。

 { &gDvm.methDalvikSystemNativeStart_main, "Ldalvik/system/NativeStart;", "main", "([Ljava/lang/String;)V" },

 

主要分析FindClass方法:

 nativeLoad标示从System.loadlibrary加载。那么Zygote的dvmGetCurrentJNIMethod是哪个呢。我猜测,这个一定是没有的,也就是里面的成员变量全为空。哈哈。这意味着,最终调用到了

dvmFindClassNoInit方法中。

然后是ClassObject* dvmFindSystemClassNoInit(const char* descriptor)
{
    return findClassNoInit(descriptor, NULL, NULL);
}
然后是findClassNoInit

ZygoteInit这个类根本是没有ClassLoader的。而是直接从包里面查找得到的。

进入ZygoteInit后。就是java代码了。

 

 

原创粉丝点击