深入理解Dalvik虚拟机- Android应用进程启动过程分析

来源:互联网 发布:windows http 编辑:程序博客网 时间:2024/05/02 01:10

Android的应用进程启动是apk在manifest里申明的Activity,Service,BroadcastReceiver等组件被调起时而触发的。我们以Activity为例,当点击桌面上的应用图标时,桌面会调用startActivity,启动manifest里申明的相应Launcher的Activity,而Activity的startActivity会通过Binder调用来到ActivityManagerService(AMS)里。AMS是system_server的一个服务,负责管理Android系统的所有Activity的栈,逻辑比较复杂,在这里就不详细分析,以后专门写AMS的专题。AMS里startActivity的时候,如果发现这个应用进程没有启动,那么就会通过Zygote创建出这个进程。 

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java:

private final void startProcessLocked(ProcessRecord app,            String hostingType, String hostingNameStr) {   ...   ...   Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, null);   ...   ...}

显然是通过调用Process.start来启动进程,”android.app.ActivityThread” 这个参数是整个进程启动的入口类,后续的分析可以看到,进程被fork出来之后,就会调用android.app.ActivityThread的main函数。

frameworks/base/core/java/android/os/Process.java:

    public static final ProcessStartResult start(final String processClass,                                  final String niceName,                                  int uid, int gid, int[] gids,                                  int debugFlags, int mountExternal,                                  int targetSdkVersion,                                  String seInfo,                                  String[] zygoteArgs) {        try {            return startViaZygote(processClass, niceName, uid, gid, gids,                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);        } catch (ZygoteStartFailedEx ex) {            Log.e(LOG_TAG,                    "Starting VM process through Zygote failed");            throw new RuntimeException(                    "Starting VM process through Zygote failed", ex);        }    }    private static ProcessStartResult startViaZygote(final String processClass,                                  final String niceName,                                  final int uid, final int gid,                                  final int[] gids,                                  int debugFlags, int mountExternal,                                  int targetSdkVersion,                                  String seInfo,                                  String[] extraArgs)                                  throws ZygoteStartFailedEx {        synchronized(Process.class) {            ArrayList<String> argsForZygote = new ArrayList<String>();            // --runtime-init, --setuid=, --setgid=,            // and --setgroups= must go first            argsForZygote.add("--runtime-init");            argsForZygote.add("--setuid=" + uid);            argsForZygote.add("--setgid=" + gid);            if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {                argsForZygote.add("--enable-jni-logging");            }            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {                argsForZygote.add("--enable-safemode");            }            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {                argsForZygote.add("--enable-debugger");            }            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {                argsForZygote.add("--enable-checkjni");            }            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {                argsForZygote.add("--enable-assert");            }            if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {                argsForZygote.add("--mount-external-multiuser");            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {                argsForZygote.add("--mount-external-multiuser-all");            }            argsForZygote.add("--target-sdk-version=" + targetSdkVersion);            //TODO optionally enable debuger            //argsForZygote.add("--enable-debugger");            // --setgroups is a comma-separated list            if (gids != null && gids.length > 0) {                StringBuilder sb = new StringBuilder();                sb.append("--setgroups=");                int sz = gids.length;                for (int i = 0; i < sz; i++) {                    if (i != 0) {                        sb.append(',');                    }                    sb.append(gids[i]);                }                argsForZygote.add(sb.toString());            }            if (niceName != null) {                argsForZygote.add("--nice-name=" + niceName);            }            if (seInfo != null) {                argsForZygote.add("--seinfo=" + seInfo);            }            argsForZygote.add(processClass);            if (extraArgs != null) {                for (String arg : extraArgs) {                    argsForZygote.add(arg);                }            }            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);        }    }

    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {            try {                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);            } catch (IOException ioe) {                throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);            }        }        if (primaryZygoteState.matches(abi)) {            return primaryZygoteState;        }        // The primary zygote didn't match. Try the secondary.        if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {            try {            secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);            } catch (IOException ioe) {                throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);            }        }        if (secondaryZygoteState.matches(abi)) {            return secondaryZygoteState;        }        throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);    }

调用startViaZygote函数,从代码可以看到,Zygote创建进程是socket跨进程的调用。通过LocalSocket通信,来完成进程的创建,所以这里的Process.start只是一个Client端
的调用,实际是由Server端的接收到消息后处理的。
Server端是app_process这个进程里,这是个常驻的系统服务。

frameworks/base/cmds/app_process/app_main.cpp

class AppRuntime : public AndroidRuntime{}

AppRuntime继承自AndroidRuntime,AndroidRuntime类是libandroid_runtime.so里导出的,frameworks/base/core/jni/AndroidRuntime.cpp。
app_process这个进程在init.rc里会创建,

#init.rcservice zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

app_process以zygote作为进程名,这个adb shell进入手机ps一下就可以看到zygote。

这个进程的main函数里有如下初始化代码片段:

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

 第一个if是正常的Zygote进程启动,执行AndroidRuntime::start,会调用ZygoteInit的类main函数。app_process的初始化就在ZygoteInit里,监听本地的socket,接收ZygoteClient的请求,当有请求来的时候,调用ZygoteConnection::runOnce,从而调用Zygote.forkAndSpecialize来创建新的进程,并且调用RuntimeInit.zygoteInit做进程的初始化,初始化过程就会调用ActivityThread.main

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)....../*     * 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) {        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 {            env->CallStaticVoidMethod(startClass, startMeth, strArray);#if 0            if (env->ExceptionCheck())                threadExitUncaughtException(env);#endif        }    }...}
第二个当指定了className的时候,则用com.android.internal.os.RuntimeInit作为入口,指定className的场景是用am命令创建的进程的时候:

exec app_process $base/bin com.android.commands.am.Am "$@" 

 而我们正常的Zygote进程则走的是ZygoteInit。

AndroidRuntime.start函数会调用startVm,frameworks/base/core/jni/AndroidRuntime.cpp

    int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv){    ...    initArgs.version = JNI_VERSION_1_4;    initArgs.options = mOptions.editArray();    initArgs.nOptions = mOptions.size();    initArgs.ignoreUnrecognized = JNI_FALSE;    /*     * Initialize the VM.     *     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.     * If this call succeeds, the VM is ready, and we can start issuing     * JNI calls.     */    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {        ALOGE("JNI_CreateJavaVM failed\n");        goto bail;    }}

startVm会初始化JavaVm和JNIEnv,最终是通过JNI_CreateJavaVM实现的,JNI_CreateJavaVM是个接口,不同的虚拟机有不同的实现。

Dalvik虚拟机相关的代码主要在下面几个目录下: 
libcore/libdvm
libcore/dalvik
dalvik/vm/

Dalvik的JNI_CreateJavaVM在dalvik/vm/Jni.cpp 里实现:

jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;    if (dvmIsBadJniVersion(args->version)) {        ALOGE("Bad JNI version passed to CreateJavaVM: %d", args->version);        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*) calloc(1, 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);                    free(pVM);                    free(jniOpts);                    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");        free(pVM);        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);        ALOGW("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;    ALOGV("CreateJavaVM succeeded");    return JNI_OK;}

malloc完了之后,会调用dvmStartup完成虚拟机的启动,dvmStartup定义在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);    ALOGV("VM init args (%d):", argc);    for (int i = 0; i < argc; i++) {        ALOGV("  %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) {        ALOGI("Switching to 'portable' interpreter for GC checks");        gDvm.executionMode = kExecutionModeInterpPortable;    }#endif    /* Configure group scheduling capabilities */    if (!access("/dev/cpuctl/tasks", F_OK)) {        ALOGV("Using kernel group scheduling");        gDvm.kernelGroupScheduling = 1;    } else {        ALOGV("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 */    ALOGV("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)    {        ALOGW("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";        }        dvmPostInitZygote();    } else {        if (!dvmInitAfterZygote()) {            return "dvmInitAfterZygote failed";        }    }#ifndef NDEBUG    if (!dvmTestHash())        ALOGE("dvmTestHash FAILED");    if (false /*noisy!*/ && !dvmTestIndirectRefTable())        ALOGE("dvmTestIndirectRefTable FAILED");#endif    if (dvmCheckException(dvmThreadSelf())) {        dvmLogExceptionStackTrace();        return "Exception pending at end of VM initialization";    }    scopedShutdown.disarm();    return "";}

dvmStartup调用了很多初始化接口,比如dvmClassStartup:

/* * 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) {        ALOGE("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;}

这个类初始化gDvm的bootClassPath,这样就能执行最早看到的ActivityThread的main函数。

具体的调用栈为:ActivityThread.main -> ActivityThread.attach ->  ActivityThread.bindApplication -> Activity.handleBindApplication.

到目前的分析,应用的ClassLoader还是BootClassPath,只包含了Java和Android的类,Apk自身的类是找不到的,会报ClassNotFound,接下来就是介绍ClassLoader的加载过程。

handleBindApplication会初始化ApplicationInfo对象,通getPackageInfo初始化LoadedApk,而LoadedApk则会创建这个apk对应的ClassLoader,这个ClassLoader是集成自BaseDexClassLoader,加载了apk的dex。 

ApplicationInfo instrApp = new ApplicationInfo();instrApp.packageName = ii.packageName;instrApp.sourceDir = ii.sourceDir;instrApp.publicSourceDir = ii.publicSourceDir;instrApp.dataDir = ii.dataDir;instrApp.nativeLibraryDir = ii.nativeLibraryDir;LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,    appContext.getClassLoader(), false, true);ContextImpl instrContext = ContextImpl.createAppContext(this, pi);try {    java.lang.ClassLoader cl = instrContext.getClassLoader();    mInstrumentation = (Instrumentation)    cl.loadClass(data.instrumentationName.getClassName()).newInstance();} catch (Exception e) {    throw new RuntimeException(        "Unable to instantiate instrumentation + data.instrumentationName + ": " + e.toString(), e);}

ContextImpl和Instrumentation的ClassLoader都已经初始化为apk对应的BaseDexClassLoader,在这之后的类加载,都会从这个ClassLoader对象里找。ClassLoader是个树状结构,查找规则是先从父节点查找,如果类已经加载,则直接返回加载好的Class<?>。
类的加载时机有两个,一个是new操作符创建对象的,一个是直接调用ClassLoader的loadClass的时候,new操作符的代码在dalvik解释器里,我们下一个专题会讲,最后会调用dvmResolveClass(dalvik/vm/oo/Resolve.cpp)来加载类。loadClass的实现如下:
libcore/libdvm/src/main/java/java/lang/ClassLoader.java

protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {        Class<?> clazz = findLoadedClass(className);        if (clazz == null) {            try {                clazz = parent.loadClass(className, false);            } catch (ClassNotFoundException e) {                // Don't want to see this.            }            if (clazz == null) {                clazz = findClass(className);            }        }        return clazz;}

它首先看自己的parent是否已经加载过class了,加载了就返回,没有就调用BaseDexClassLoader的findClass。

@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {        List<Throwable> suppressedExceptions = new ArrayList<Throwable>();        Class c = pathList.findClass(name, suppressedExceptions);        if (c == null) {            ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);            for (Throwable t : suppressedExceptions) {                cnfe.addSuppressed(t);            }            throw cnfe;        }        return c;}

BaseDexClassLoader的findClass,实际是调用了DexPathList的findClass。

上面的整个过程就是Android的apk从启动,一直到ClassLoader被初始化完,之后就是走Android的Activity正常生命周期了。

下篇介绍一下Dalvik虚拟机的解析器的工作原理。


作者简介:

田力,网易彩票Android端创始人,小米视频创始人,现任roobo技术经理、视频云技术总监

欢迎关注微信公众号 磨剑石,定期推送技术心得以及源码分析等文章,谢谢


0 0