Zygote,SystemServer启动分析

内核启动完成之后,Android的Init进程就会接管后续系统的初始化工作。

Zygote,SystemServer启动分析_第1张图片
init进程启动之后,就会开始解析系统的*.rc 脚本,解析完成之后就开始启动各种service服务,然后修改权限,挂载相关目录,创建相关文件,目录。下面下简单介绍一下脚本中相关command和action的对应关系

struct {
    const char *name;
    int (*func)(int nargs, char **args);
    unsigned char nargs;
    unsigned char flags;
} keyword_info[KEYWORD_COUNT] = {
    [ K_UNKNOWN ] = { "unknown", 0, 0, 0 },
#include "keywords.h"
};

结构体keyword_info数组保存command,action的映射关系

int lookup_keyword(const char *s)
{
    switch (*s++) {
    case 'c':
    if (!strcmp(s, "opy")) return K_copy;
        if (!strcmp(s, "apability")) return K_capability;
        if (!strcmp(s, "hdir")) return K_chdir;
        if (!strcmp(s, "hroot")) return K_chroot;
        if (!strcmp(s, "lass")) return K_class;
        if (!strcmp(s, "lass_start")) return K_class_start;
        if (!strcmp(s, "lass_stop")) return K_class_stop;
        if (!strcmp(s, "lass_reset")) return K_class_reset;
        if (!strcmp(s, "onsole")) return K_console;
        if (!strcmp(s, "hown")) return K_chown;
        if (!strcmp(s, "hmod")) return K_chmod;
        if (!strcmp(s, "ritical")) return K_critical;
        break;
    case 'd':
        if (!strcmp(s, "isabled")) return K_disabled;
        if (!strcmp(s, "omainname")) return K_domainname;
        break;
    case 'e':
        if (!strcmp(s, "xec")) return K_exec;
        if (!strcmp(s, "xport")) return K_export;
        break;
    case 'g':
        if (!strcmp(s, "roup")) return K_group;
        break;
    case 'h':
        if (!strcmp(s, "ostname")) return K_hostname;
        break;
    case 'i':
        if (!strcmp(s, "oprio")) return K_ioprio;
        if (!strcmp(s, "fup")) return K_ifup;
        if (!strcmp(s, "nsmod")) return K_insmod;
        if (!strcmp(s, "mport")) return K_import;
        break;
    case 'k':
        if (!strcmp(s, "eycodes")) return K_keycodes;
        break;
    case 'l':
        if (!strcmp(s, "oglevel")) return K_loglevel;
        if (!strcmp(s, "oad_persist_props")) return K_load_persist_props;
        break;
    case 'm':
        if (!strcmp(s, "kdir")) return K_mkdir;
        if (!strcmp(s, "ount_all")) return K_mount_all;
        if (!strcmp(s, "ount")) return K_mount;
        break;
    case 'o':
        if (!strcmp(s, "n")) return K_on;
        if (!strcmp(s, "neshot")) return K_oneshot;
        if (!strcmp(s, "nrestart")) return K_onrestart;
        break;
    case 'p':
        if (!strcmp(s, "owerctl")) return K_powerctl;
    case 'r':
        if (!strcmp(s, "estart")) return K_restart;
        if (!strcmp(s, "estorecon")) return K_restorecon;
        if (!strcmp(s, "mdir")) return K_rmdir;
        if (!strcmp(s, "m")) return K_rm;
        break;
    case 's':
        if (!strcmp(s, "eclabel")) return K_seclabel;
        if (!strcmp(s, "ervice")) return K_service;
        if (!strcmp(s, "etcon")) return K_setcon;
        if (!strcmp(s, "etenforce")) return K_setenforce;
        if (!strcmp(s, "etenv")) return K_setenv;
        if (!strcmp(s, "etkey")) return K_setkey;
        if (!strcmp(s, "etprop")) return K_setprop;
        if (!strcmp(s, "etrlimit")) return K_setrlimit;
        if (!strcmp(s, "etsebool")) return K_setsebool;
        if (!strcmp(s, "ocket")) return K_socket;
        if (!strcmp(s, "tart")) return K_start;
        if (!strcmp(s, "top")) return K_stop;
        if (!strcmp(s, "wapon_all")) return K_swapon_all;
        if (!strcmp(s, "ymlink")) return K_symlink;
        if (!strcmp(s, "ysclktz")) return K_sysclktz;
        break;
    case 't':
        if (!strcmp(s, "rigger")) return K_trigger;
        break;
    case 'u':
        if (!strcmp(s, "ser")) return K_user;
        break;
    case 'w':
        if (!strcmp(s, "rite")) return K_write;
        if (!strcmp(s, "ait")) return K_wait;
        break;
    }
    return K_UNKNOWN;
}

lookup_keyword函数描述了操作名称,操作索引的关系,keywords.h则列举出了具体的操作方法

#define KEYWORD(symbol, flags, nargs, func) K_##symbol,
enum {
    K_UNKNOWN,
#endif
    KEYWORD(capability, OPTION, 0, 0)
    KEYWORD(chdir, COMMAND, 1, do_chdir)
    KEYWORD(chroot, COMMAND, 1, do_chroot)
    KEYWORD(class, OPTION, 0, 0)
    KEYWORD(class_start, COMMAND, 1, do_class_start)
    KEYWORD(class_stop, COMMAND, 1, do_class_stop)
    KEYWORD(class_reset, COMMAND, 1, do_class_reset)
    KEYWORD(console, OPTION, 0, 0)
    KEYWORD(critical, OPTION, 0, 0)
    KEYWORD(disabled, OPTION, 0, 0)
    KEYWORD(domainname, COMMAND, 1, do_domainname)
    KEYWORD(exec, COMMAND, 1, do_exec)
    KEYWORD(export, COMMAND, 2, do_export)
    KEYWORD(group, OPTION, 0, 0)
    KEYWORD(hostname, COMMAND, 1, do_hostname)
    KEYWORD(ifup, COMMAND, 1, do_ifup)
    KEYWORD(insmod, COMMAND, 1, do_insmod)
    KEYWORD(import, SECTION, 1, 0)
    KEYWORD(keycodes, OPTION, 0, 0)
    KEYWORD(mkdir, COMMAND, 1, do_mkdir)
    KEYWORD(mount_all, COMMAND, 1, do_mount_all)
    KEYWORD(mount, COMMAND, 3, do_mount)
    KEYWORD(on, SECTION, 0, 0)
    KEYWORD(oneshot, OPTION, 0, 0)
    KEYWORD(onrestart, OPTION, 0, 0)
    KEYWORD(powerctl, COMMAND, 1, do_powerctl)
    KEYWORD(restart, COMMAND, 1, do_restart)
    KEYWORD(restorecon, COMMAND, 1, do_restorecon)
    KEYWORD(rm, COMMAND, 1, do_rm)
    KEYWORD(rmdir, COMMAND, 1, do_rmdir)
    KEYWORD(seclabel, OPTION, 0, 0)
    KEYWORD(service, SECTION, 0, 0)
    KEYWORD(setcon, COMMAND, 1, do_setcon)
    KEYWORD(setenforce, COMMAND, 1, do_setenforce)
    KEYWORD(setenv, OPTION, 2, 0)
    KEYWORD(setkey, COMMAND, 0, do_setkey)
    KEYWORD(setprop, COMMAND, 2, do_setprop)
    KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
    KEYWORD(setsebool, COMMAND, 2, do_setsebool)
    KEYWORD(socket, OPTION, 0, 0)
    KEYWORD(start, COMMAND, 1, do_start)
    KEYWORD(stop, COMMAND, 1, do_stop)
    KEYWORD(swapon_all, COMMAND, 1, do_swapon_all)
    KEYWORD(trigger, COMMAND, 1, do_trigger)
    KEYWORD(symlink, COMMAND, 1, do_symlink)
    KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
    KEYWORD(user, OPTION, 0, 0)
    KEYWORD(wait, COMMAND, 1, do_wait)
    KEYWORD(write, COMMAND, 2, do_write)
    KEYWORD(copy, COMMAND, 2, do_copy)
    KEYWORD(chown, COMMAND, 2, do_chown)
    KEYWORD(chmod, COMMAND, 2, do_chmod)
    KEYWORD(loglevel, COMMAND, 1, do_loglevel)
    KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
    KEYWORD(ioprio, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
    KEYWORD_COUNT,
};

所有的动作都在这里定义了,chmod,mkdir,chmon,mount,service,等等,这里我们主要看service,后面的zygote启动需要用到,在rc 脚本中存在指令service zygote /system/bin/app_process -Xzygote /system/bin –zygote –start-system-server,Init进程在解析完rc 脚本之后会启动app_precess。Init进程的service_start函数会去创建新的进程,并在子进程空间启动app_process进程,但是启动之后进程名称换成zygote了,通过ps指令查看zygote进程的父进程就是Init(PID=1)。

void service_start(struct service *svc, const char *dynamic_args)
{
    ......

    ......

    pid = fork();

    if (pid == 0) {
        ......

        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }

        setpgid(0, getpid());

        ......

        if (!dynamic_args) {
            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
            }
        } else {
            ......
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127);
    }

   ......

    if (properties_inited())
        notify_service_state(svc->name, "running");
}

上面fork创建子进程,新进程空间execve直接启动app_process,接着app_main.c 主函数main会被调用。

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

    ......

    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) {
        ......
    } else {
        ......
    }
}

app_process 通过AppRuntime.start,AndroidRuntime.start 一步步启动虚拟机

void AndroidRuntime::start(const char* className, const char* options)
{
    ......

    JNIEnv* env;
    if (startVm(&mJavaVM, &env) != 0) {
        return;
    }
    onVmCreated(env);

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

    ......

    /* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */
    ......
    if (startClass == NULL) {
        ......
    } 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);

        }
    }
    ......
}

通过反射机制构造ZygoteInit类,获取静态方法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();

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

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

            runSelectLoop();

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

ZygoteInit.main 注册Zygote通信通道,启动SystemServer,使用select监听“/dev/socket/zygote”设备随时准备(runSelectLoop)孵化其它应用进程,下面继续看SystemServer的启动

    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        ......
        /* 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,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

接着Zygote通过forkSystemServer创建SystemServer需要的进程空间,handleSystemServerProcess则在子进程空间构建SystemServer类,并call静态方法main

    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {

        closeServerSocket();

        // set umask to 0077 so new files and directories will default to owner-only permissions.
        Libcore.os.umask(S_IRWXG | S_IRWXO);

        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }

        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    null, parsedArgs.remainingArgs);
        } else {
            /* * Pass the remaining arguments to SystemServer. */
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
        }

        /* should never reach here */
    }

RuntimeInit继续向下走

    public static final void zygoteInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

        redirectLogStreams();

        commonInit();
        nativeZygoteInit();

        applicationInit(targetSdkVersion, argv);
    }

nativeZygoteInit 方法会进入AppRuntime::onZygoteInit启动线程池,而applicationInit进入invokeStaticMain完成最后的动作。

    private static void invokeStaticMain(String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className);
        } 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. */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

invokeStaticMain可以看到先将传进入来的“com.android.server.SystemServer”构建出来,cl.getMethod(“main”, new Class[] { String[].class })完成main的调用,至此SystemServer启动,后续将在进入Android framework层AMS,IMS,PMS,WMS等服务的初始化。

上述有很多进程的创建,关于进程组的设置暂未研究。

你可能感兴趣的:(android,Zygote)