Android系统源码情景分析-学习笔记-11

概述:

     在Android系统中,所有的应用程序进程,以及用来运行系统关键服务的System进程都是由Zygote进程负责创建的,因此,我们将它成为进程孵化器。Zygote进程是通过复制自身的方式来创建System进程和应用程序进程。由于Zygote进程在启动时会在内部创建一个虚拟机实例,因此,通过复制Zygote进程而得到的System进程和应用程序进程可以快速地在内部获得一个虚拟机实例拷贝。
     Zygote进程启动完成以后,会马上将system进程启动起来,以便它可以将系统关键服务启动起来。

init 进程概述:

init进程是Android启动后的,由内核启动的第一个用户级进程
Android 的init进程提供四大功能:

  1. init进程处理子进程的终止与再启动
  2. init 进程分析init.rc 启动脚本文件,并根据相关中包含的内容,执行相应的功能;
  3. init进程提供属性服务;
  4. init进程生成设备节点文件

11. 1 zygote进程的启动脚本

     Zygote进程是由Android系统的第一个进程init启动起来的。init进程是在内核加载完成之后就启动起来的(也就是用户空间的第一个进程),它的启动过程中,会读取根目录下的一个脚本文件init.rc,以便可以将其他需要开启的进程也一起启动起来。

     Zygote进程在脚本文件init.rc 中的启动脚本

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

     第一行表示Zygote进程是以服务的形式启动的,并且它所对应的应用程序文件为 /system/bin/app_process。接下来的四个选项是Zygote进程的启动参数,其中,
最后一个参数 "--start-system-server" 表示Zygote进程在启动完成之后,需要马上将System进程也启动起来。

     第二行表示Zygote进程在启动的过程中,需要再内部创建一个名称为 "zygote" 的socket。这个Socket是用来执行进程间通信的,
它的访问权限被这只为666,即所有用户都可以对它进行读写。

     由于Zygote进程在脚本文件init.rc中配置了以服务的形式来启动,因此,init进程在启动时,就会调用函数service_start来启动它,

11.2 Zygote 进程的启动过程

app_main.cpp # main

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

    // Next arg is startup classname or "--zygote"
    if (i < argc) {
        arg = argv[i++];
        // zygote 启动流程  
        if (0 == strcmp("--zygote", arg)) {
            bool startSystemServer = (i < argc) ? 
                    strcmp(argv[i], "--start-system-server") == 0 : false;
            setArgv0(argv0, "zygote");
            set_process_name("zygote");
            runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer);
        } else {
            ....
        }
    } else {
        ....
    }

}

通过AppRuntime (父类:AndroidRuntime) 来启动java 虚拟机,运行com.android.internal.os.ZygoteInit 的main函数

AndroidRuntime.cpp # start

来启动java 虚拟机,运行com.android.internal.os.ZygoteInit 的main函数

void AndroidRuntime::start(const char* className, const bool startSystemServer)
{

    char* slashClassName = NULL;
    char* cp;
    JNIEnv* env;

    blockSigpipe();

    /* 
     * 'startSystemServer == true' means runtime is obslete and not run from 
     * init.rc anymore, so we print out the boot start event here.
     */
    if (startSystemServer) {
        /* 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.");
            goto bail;
        }
        setenv("ANDROID_ROOT", rootDir, 1);
    }

    //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
    //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

    /* start the virtual machine */
    if (startVm(&mJavaVM, &env) != 0)
        goto bail;

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

    /*
     * We want to call main() with a String array with arguments in it.
     * At present we only have one argument, the class name.  Create an
     * array to hold it.
     */
    jclass stringClass;
    jobjectArray strArray;
    jstring classNameStr;
    jstring startSystemServerStr;

    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);
    startSystemServerStr = env->NewStringUTF(startSystemServer ? 
                                                 "true" : "false");
    env->SetObjectArrayElement(strArray, 1, startSystemServerStr);

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    jclass startClass;
    jmethodID startMeth;

    slashClassName = strdup(className);
    for (cp = slashClassName; *cp != '\0'; cp++)
        if (*cp == '.')
            *cp = '/';

    startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
        ...
    } else {
        startMeth = env->GetStaticMethodID(startClass, "main",
            "([Ljava/lang/String;)V");
        if (startMeth == NULL) {
            ...
        } else {
            env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
        }
    }

    ...

bail:
    free(slashClassName);
}

ZygoteInit # main

    public static void main(String argv[]) {
        try {
            VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024);

            
            // 创建一个Server端Socket, 等待 ActivityManagerservice 的请求来创建新的进程。
            registerZygoteSocket();
           
            preloadClasses();
            //cacheRegisterMaps();
            preloadResources();

            // Do an initial gc to clean up after startup
            gc();
            
            if (argv[1].equals("true")) {
                // 启动 system server
                startSystemServer();
            } 
            // ZYGOTE_FORK_MODE 的值默认为true
            if (ZYGOTE_FORK_MODE) {
                // 调用这个函数,来等待ActivityManagerService 请求Zygote进程创建新的应用程序。
               // 不过,这种情况下,对于每一个请求,Zygote进程都会创建一个新的进程来处理,这样会浪费大量的进程资源。
              // 因此, 为了让所有的创建应用程序进程请求都在同一个进程中处理,我们将ZygoteInit类的静态成员变量 ZYGOTE_FORK_MODE 设置为false
                runForkMode();
            } else {
                runSelectLoopMode();
            }

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) { ... } catch (RuntimeException ex) { ... }
    }

ZygoteInit#startSystemServer

启动System Server 进程

    /**
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        // System Server 进程的启动参数 
        /* 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,3001,3002,3003",
            "--capabilities=130104352,130104352",
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
        ZygoteConnection.Arguments parsedArgs = null;

        int pid;

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

            /*
             * Enable debugging of the system process if *either* the command line flags
             * indicate it should be debuggable or the ro.debuggable system property
             * is set to "1"
             */
            int debugFlags = parsedArgs.debugFlags;
            if ("1".equals(SystemProperties.get("ro.debuggable")))
                debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;

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

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

        return true;
    }

System Server 进程的启动

由于System进程复制了Zygote进程的地址空间,因此它就会获得Zygote进程在启动过程中创建的一个socket。System进程不需要使用这个Socket,因此,需要调用closeServerSocket 来关闭它。
接下来需要调用RuntimeInit 的 zygoteInit 来进一步启动System进程。

    /**
     * Finish remaining work for the newly forked system server process.
     */
    private static void handleSystemServerProcess(
            ZygoteConnection.Arguments parsedArgs)
            throws ZygoteInit.MethodAndArgsCaller {

        closeServerSocket();

        /*
         * Pass the remaining arguments to SystemServer.
         * "--nice-name=system_server com.android.server.SystemServer"
         */
        RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
        /* should never reach here */
    }

RuntimeInit # zygoteInit

    /**
     * The main function called when started through the zygote process. This
     * could be unified with main(), if the native code in finishInit()
     * were rationalized with Zygote startup.<p>
     *
     * Current recognized args:
     * <ul>
     *   <li> --nice-name=<i>nice name to appear in ps</i>
     *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
     * </ul>
     *
     * @param argv arg strings
     */
    public static final void zygoteInit(String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        // 设置System进程的回去和键盘布局等通用信息
        commonInit();
        // 在System进程中启动一个Binder线程池
        zygoteInitNative();

        int curArg = 0;
        for ( /* curArg */ ; curArg < argv.length; curArg++) {
            String arg = argv[curArg];

            if (arg.equals("--")) {
                curArg++;
                break;
            } else if (!arg.startsWith("--")) {
                break;
            } else if (arg.startsWith("--nice-name=")) {
                String niceName = arg.substring(arg.indexOf('=') + 1);
                Process.setArgV0(niceName);
            }
        }

        if (curArg == argv.length) {
            Slog.e(TAG, "Missing classname argument to RuntimeInit!");
            // let the process exit
            return;
        }

        // Remaining arguments are passed to the start class's static main

        String startClass = argv[curArg++];
        String[] startArgs = new String[argv.length - curArg];

        System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
        // 启动 com.android.server.SystemServer类的main函数
        invokeStaticMain(startClass, startArgs);
    }

SystemServer # main

进入SystemServer进程的java世界

    public static void main(String[] args) {
        // The system server has to run all of the time, so it needs to be
        // as efficient as possible with its memory usage.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
        
        System.loadLibrary("android_servers");
        // 启动一些使用C++语言开发的系统服务,
        // com_android_server_SystemServer.cpp
        // android_server_SystemServer_init1 方法
        init1(args);
    }

system_init.cpp # system_init

extern "C" status_t system_init()
{
    LOGI("Entered system_init()");
    
    sp<ProcessState> proc(ProcessState::self());
    
    sp<IServiceManager> sm = defaultServiceManager();
    LOGI("ServiceManager: %p\n", sm.get());
    
    sp<GrimReaper> grim = new GrimReaper();
    sm->asBinder()->linkToDeath(grim, grim.get(), 0);
    
    char propBuf[PROPERTY_VALUE_MAX];
    property_get("system_init.startsurfaceflinger", propBuf, "1");
    if (strcmp(propBuf, "1") == 0) {
        // Start the SurfaceFlinger
        SurfaceFlinger::instantiate();
    }

    // Start the sensor service
    SensorService::instantiate();

    // On the simulator, audioflinger et al don't get started the
    // same way as on the device, and we need to start them here
    if (!proc->supportsProcesses()) {

        // Start the AudioFlinger
        AudioFlinger::instantiate();

        // Start the media playback service
        MediaPlayerService::instantiate();

        // Start the camera service
        CameraService::instantiate();

        // Start the audio policy service
        AudioPolicyService::instantiate();
    }

    // And now start the Android runtime.  We have to do this bit
    // of nastiness because the Android runtime initialization requires
    // some of the core system services to already be started.
    // All other servers should just start the Android runtime at
    // the beginning of their processes's main(), before calling
    // the init function.
    LOGI("System server: starting Android runtime.\n");
    
    AndroidRuntime* runtime = AndroidRuntime::getRuntime();

    LOGI("System server: starting Android services.\n");
    runtime->callStatic("com/android/server/SystemServer", "init2");
        
    // If running in our own process, just go into the thread
    // pool.  Otherwise, call the initialization finished
    // func to let this process continue its initilization.
    if (proc->supportsProcesses()) {
        LOGI("System server: entering thread pool.\n");
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
        LOGI("System server: exiting thread pool.\n");
    }
    return NO_ERROR;
}

SystemServer#init2

    public static final void init2() {
        Slog.i(TAG, "Entered the Android system server!");
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
    }

SystemServer#ServerThread#

    @Override
    public void run() {
        Looper.prepare();

        ((ActivityManagerService)ActivityManagerNative.getDefault())
                .systemReady(new Runnable() {
            public void run() {
                Slog.i(TAG, "Making services ready");
                ...
            }
        });

        Looper.loop();
        Slog.d(TAG, "System ServerThread is exiting!");
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容