Android系统启动流程-Zygote分析


zygote是通过app_process或者app_process64命令行程序启动的.

先来看下app_process的流程:

app_process

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

    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

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

strdup():返回一个字符串指针,指向新复制的字符串

int strncmp ( const char * str1, const char * str2, size_t n ): 比较两个字符串的前n个字符,如果相等,则返回0

app_process 根据传入参数不同分为两种模式:

  • zygote模式,用于启动zygote进程
    传入–zygote

  • 非zygote模式,用于启动普通的java程序
    比如常用的adb shell 下的命令,如am,monkey,appwidget等:

    #!/system/bin/sh
    
    if [ "$1" != "instrument" ] ; then
        cmd activity "$@"
    else
        base=/system
        export CLASSPATH=$base/framework/am.jar
        exec app_process $base/bin com.android.commands.am.Am "$@"
    fi

系统启动的时候,我们分析zygote模式.

实际上不管哪个模式,都会执行AndroidRuntime::start()方法,区别是传入的启动类不同:

AndroidRuntime

JavaVM* AndroidRuntime::mJavaVM = NULL;

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{

    /* 启动虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
        return;
    }
    onVmCreated(env);

    /*
     * 注册Android Native JNI方法
     */
    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);
    }

    /*
     * 当前线程是VM的主线程,当VM销毁时线程才会退出 
     */
    char* slashClassName = toSlashClassName(className != NULL ? 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 {
            // 这里是真实调用main()方法的地方
            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");
}

AndroidRuntime启动过程主要做了三件事:

  • 启动Android虚拟机,即ART Runtime
  • 注册一些内置的Native方法(JNI)
  • 通过JNI调用执行ZygoteInitmain()方法

虚拟机是如何启动的,Native方法是如何注册的,这里暂时不分析,重点关注Zygote进程的启动.

ZygoteInit#main()

    public static void main(String argv[]) {
        ZygoteServer zygoteServer = null;

        // 用程序自己的进程id和进程组id
        Os.setpgid(0, 0);

        Runnable caller;
        try {

            if (!enableLazyPreload) {
                preload(bootTimingsTraceLog);
            }

            gcAndFinalize();
            Zygote.initNativeState(isPrimaryZygote);
            zygoteServer = new ZygoteServer(isPrimaryZygote);

            if (startSystemServer) {
                // 为fork system_server进程初始化一些参数
                Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

                // zygote进程中r== null,不会执行下面的代码
                // system_server 进程r != null,会执行下面的代码
                if (r != null) {
                    r.run();
                    return;
                }
            }

            Log.i(TAG, "Accepting command socket connections");

            // The select loop returns early in the child process after a fork and
            // loops forever in the zygote.
            caller = zygoteServer.runSelectLoop(abiList);
        } catch (Throwable ex) {
            Log.e(TAG, "System zygote died with exception", ex);
            throw ex;
        } finally {
            if (zygoteServer != null) {
                zygoteServer.closeServerSocket();
            }
        }

        // We're in the child process and have exited the select loop. Proceed to execute the
        // command.
        if (caller != null) {
            caller.run();
        }
    }

这里主要做以下几件事:

  • 创建ZygoteServer,利用local socket + file descriptor 机制响应应用的fork请求
  • 预加载一些jar包中的class,classloader,一诶Android资源,共享库,图形驱动等
  • 启动完之后运行几次GC清理下资源
  • 从Zygote进程中使用fork方式创建system server进程

Local socket + fd 这一套机制暂时还不熟悉,后面再总结一下.

预加载的有以下内容:

  • /system/etc/preloaded-classes 文件中记录的类

    包括Android Framework中的类,通过Class.forName(className,true,null)加载

  • 缓存一些非启动类的classloader

    比如HIDL和Android test相关的

  • 公共资源,让所有进程可以共享

    • com.android.internal.R.array.preloaded_drawables 中的内容

    • com.android.internal.R.array.preloaded_color_state_lists

    • com.android.internal.R.bool.config_freeformWindowManagement

  • HAL库

  • 图像库驱动,比如OpenGL 或者 Vulkan驱动

  • 加载共享的动态库

    • libandroid.so
    • libcompiler_rt.so
    • libjnigraphics.so
  • TextView的字体资源

  • WebView相关的so库,libwebviewchromium_loader.so

创建system_server进程

在ZygoteInit##forSystemServer方法中:

    private static Runnable forkSystemServer(String abiList, String socketName,
            ZygoteServer zygoteServer) {

        /* Hardcoded command line to start the system server */
        String args[] = {
                "--setuid=1000",
                "--setgid=1000",
                "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
                        + "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
                "--capabilities=" + capabilities + "," + capabilities,
                "--nice-name=system_server",
                "--runtime-args",
                "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
                "com.android.server.SystemServer",
        };
        int pid;
        try {
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.mUid, parsedArgs.mGid,
                    parsedArgs.mGids,
                    parsedArgs.mRuntimeFlags,
                    null,
                    parsedArgs.mPermittedCapabilities,
                    parsedArgs.mEffectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* system_server进程执行 */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }
            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

        return null;
    }

可以看到首先会初始化一些参数,比如uid,gid等.然后从Zygote进程利用fork方式创建system_server进程:

    public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
            int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
        ZygoteHooks.preFork();

        int pid = nativeForkSystemServer(
                uid, gid, gids, runtimeFlags, rlimits,
                permittedCapabilities, effectiveCapabilities);

        // Set the Java Language thread priority to the default value for new apps.
        Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

        ZygoteHooks.postForkCommon();
        return pid;
    }

其中的native方式是一个JNI调用,源码在frameworks/base/core/jni/com_android_internal_os_Zygote.cpp中,所使用的还是localsocket + fd的那一套机制.

在system_server 创建成功之后,会执行handleSystemServerProcess方法:

    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
        // set umask to 0077 so new files and directories will default to owner-only permissions.
        Os.umask(S_IRWXG | S_IRWXO);

        // 设置进程名为system_server
        if (parsedArgs.mNiceName != null) {
            Process.setArgV0(parsedArgs.mNiceName);
        }

        // /system/framework 下面的jar包
        final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
        if (systemServerClasspath != null) {
            //为这些jar执行dex opt,加快执行速度
            performSystemServerDexOpt(systemServerClasspath);
        }

        if (parsedArgs.mInvokeWith != null) {   
            // 使用app_process64去执行命令:使用app_process64启动nicename进程
            WrapperInit.execApplication(parsedArgs.mInvokeWith,
                    parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);

            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else {
            ClassLoader cl = null;
            if (systemServerClasspath != null) {
                // 为哪些jar中的class创建PathClassLoader
                cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
                Thread.currentThread().setContextClassLoader(cl);
            }

            /*
             * Pass the remaining arguments to SystemServer.
             */
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mDisabledCompatChanges,
                    parsedArgs.mRemainingArgs, cl);
        }

        /* should never reach here */
    }

这里会设置进程的名字,dex opt 一些system_server相关的jar,并设置PathClassLoader,最终会执行到RuntimeInit中,并找到
SystemServer.java的main方法,并执行:

    protected static Runnable findStaticMain(String className, String[] argv,
            ClassLoader classLoader) {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        return new MethodAndArgsCaller(m, argv);
    }

到这个时候system_server进程已经创建完毕,后面开始执行SystemServer中的一序列操作了.

总结

  1. Zygote进程的入口其实在ZygoteInit中;
  2. Zygote进程是通过app_process进程启动的
  3. zygote fork出其他进程依赖了localsocket + fd的机制
  4. 在启动Zygote进程之前,会先启动虚拟机,然后注册一些Native/JNI方法
  5. Android中每个进程都只有一个虚拟机,每个线程代表了着一个JNIEnv
  6. Zygote可以说是第一个Java进程
  7. system_server进程严格意义上并不是zygote主动启动的,而是创建zygote进程的过程中,一起fork出来的,只不过是zygote fork的.

文章作者: 姜康
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 姜康 !
评论
 上一篇
AOSP构建-Android.bp的理解 AOSP构建-Android.bp的理解
C/C++是一种非常古老的编程语言,在大型项目开发管理过程中,单靠MAKE,CMAKE等工具已经不满足需求了,因此催生出了各种个样的构建工具,比如Google自家的GN,Bazel等,还有CMake,XMake,Vcpkg等.工具虽然多种
2020-06-25
下一篇 
Linux查看进程和线程信息 Linux查看进程和线程信息
psps -T -p 查看进程下所有线程信息 top 查看整体线程情况 top -H 查看指定进程的线程运行情况 top -H -p 查看当前活跃的进程 top
2020-06-24
  目录