Android系統(tǒng)源碼情景分析-學(xué)習(xí)筆記-11

概述:

???? 在Android系統(tǒng)中巢钓,所有的應(yīng)用程序進(jìn)程,以及用來運(yùn)行系統(tǒng)關(guān)鍵服務(wù)的System進(jìn)程都是由Zygote進(jìn)程負(fù)責(zé)創(chuàng)建的界阁,因此疮跑,我們將它成為進(jìn)程孵化器。Zygote進(jìn)程是通過復(fù)制自身的方式來創(chuàng)建System進(jìn)程和應(yīng)用程序進(jìn)程。由于Zygote進(jìn)程在啟動(dòng)時(shí)會在內(nèi)部創(chuàng)建一個(gè)虛擬機(jī)實(shí)例叠必,因此荚孵,通過復(fù)制Zygote進(jìn)程而得到的System進(jìn)程和應(yīng)用程序進(jìn)程可以快速地在內(nèi)部獲得一個(gè)虛擬機(jī)實(shí)例拷貝。
???? Zygote進(jìn)程啟動(dòng)完成以后纬朝,會馬上將system進(jìn)程啟動(dòng)起來收叶,以便它可以將系統(tǒng)關(guān)鍵服務(wù)啟動(dòng)起來。

init 進(jìn)程概述:

init進(jìn)程是Android啟動(dòng)后的玄组,由內(nèi)核啟動(dòng)的第一個(gè)用戶級進(jìn)程
Android 的init進(jìn)程提供四大功能:

  1. init進(jìn)程處理子進(jìn)程的終止與再啟動(dòng)
  2. init 進(jìn)程分析init.rc 啟動(dòng)腳本文件滔驾,并根據(jù)相關(guān)中包含的內(nèi)容谒麦,執(zhí)行相應(yīng)的功能俄讹;
  3. init進(jìn)程提供屬性服務(wù);
  4. init進(jìn)程生成設(shè)備節(jié)點(diǎn)文件

11. 1 zygote進(jìn)程的啟動(dòng)腳本

???? Zygote進(jìn)程是由Android系統(tǒng)的第一個(gè)進(jìn)程init啟動(dòng)起來的绕德。init進(jìn)程是在內(nèi)核加載完成之后就啟動(dòng)起來的(也就是用戶空間的第一個(gè)進(jìn)程)患膛,它的啟動(dòng)過程中,會讀取根目錄下的一個(gè)腳本文件init.rc耻蛇,以便可以將其他需要開啟的進(jìn)程也一起啟動(dòng)起來踪蹬。

???? Zygote進(jìn)程在腳本文件init.rc 中的啟動(dòng)腳本

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進(jìn)程是以服務(wù)的形式啟動(dòng)的,并且它所對應(yīng)的應(yīng)用程序文件為 /system/bin/app_process臣咖。接下來的四個(gè)選項(xiàng)是Zygote進(jìn)程的啟動(dòng)參數(shù)跃捣,其中,
最后一個(gè)參數(shù) "--start-system-server" 表示Zygote進(jìn)程在啟動(dòng)完成之后夺蛇,需要馬上將System進(jìn)程也啟動(dòng)起來疚漆。

???? 第二行表示Zygote進(jìn)程在啟動(dòng)的過程中,需要再內(nèi)部創(chuàng)建一個(gè)名稱為 "zygote" 的socket刁赦。這個(gè)Socket是用來執(zhí)行進(jìn)程間通信的娶聘,
它的訪問權(quán)限被這只為666,即所有用戶都可以對它進(jìn)行讀寫甚脉。

???? 由于Zygote進(jìn)程在腳本文件init.rc中配置了以服務(wù)的形式來啟動(dòng)丸升,因此,init進(jìn)程在啟動(dòng)時(shí)牺氨,就會調(diào)用函數(shù)service_start來啟動(dòng)它狡耻,

11.2 Zygote 進(jìn)程的啟動(dòng)過程

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 啟動(dòng)流程  
        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) 來啟動(dòng)java 虛擬機(jī),運(yùn)行com.android.internal.os.ZygoteInit 的main函數(shù)

AndroidRuntime.cpp # start

來啟動(dòng)java 虛擬機(jī)猴凹,運(yùn)行com.android.internal.os.ZygoteInit 的main函數(shù)

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

            
            // 創(chuàng)建一個(gè)Server端Socket, 等待 ActivityManagerservice 的請求來創(chuàng)建新的進(jìn)程酝豪。
            registerZygoteSocket();
           
            preloadClasses();
            //cacheRegisterMaps();
            preloadResources();

            // Do an initial gc to clean up after startup
            gc();
            
            if (argv[1].equals("true")) {
                // 啟動(dòng) system server
                startSystemServer();
            } 
            // ZYGOTE_FORK_MODE 的值默認(rèn)為true
            if (ZYGOTE_FORK_MODE) {
                // 調(diào)用這個(gè)函數(shù),來等待ActivityManagerService 請求Zygote進(jìn)程創(chuàng)建新的應(yīng)用程序精堕。
               // 不過孵淘,這種情況下,對于每一個(gè)請求歹篓,Zygote進(jìn)程都會創(chuàng)建一個(gè)新的進(jìn)程來處理瘫证,這樣會浪費(fèi)大量的進(jìn)程資源揉阎。
              // 因此, 為了讓所有的創(chuàng)建應(yīng)用程序進(jìn)程請求都在同一個(gè)進(jìn)程中處理,我們將ZygoteInit類的靜態(tài)成員變量 ZYGOTE_FORK_MODE 設(shè)置為false
                runForkMode();
            } else {
                runSelectLoopMode();
            }

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

ZygoteInit#startSystemServer

啟動(dòng)System Server 進(jìn)程

    /**
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        // System Server 進(jìn)程的啟動(dòng)參數(shù) 
        /* 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 進(jìn)程的啟動(dòng)

由于System進(jìn)程復(fù)制了Zygote進(jìn)程的地址空間背捌,因此它就會獲得Zygote進(jìn)程在啟動(dòng)過程中創(chuàng)建的一個(gè)socket毙籽。System進(jìn)程不需要使用這個(gè)Socket,因此毡庆,需要調(diào)用closeServerSocket 來關(guān)閉它坑赡。
接下來需要調(diào)用RuntimeInit 的 zygoteInit 來進(jìn)一步啟動(dòng)System進(jìn)程。

    /**
     * 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 {
        // 設(shè)置System進(jìn)程的回去和鍵盤布局等通用信息
        commonInit();
        // 在System進(jìn)程中啟動(dòng)一個(gè)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);
        // 啟動(dòng) com.android.server.SystemServer類的main函數(shù)
        invokeStaticMain(startClass, startArgs);
    }

SystemServer # main

進(jìn)入SystemServer進(jìn)程的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");
        // 啟動(dòng)一些使用C++語言開發(fā)的系統(tǒng)服務(wù)么抗,
        // 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!");
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末毅否,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蝇刀,更是在濱河造成了極大的恐慌螟加,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件吞琐,死亡現(xiàn)場離奇詭異捆探,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)站粟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門黍图,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奴烙,你說我怎么就攤上這事助被。” “怎么了缸沃?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵恰起,是天一觀的道長。 經(jīng)常有香客問我趾牧,道長检盼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任翘单,我火速辦了婚禮吨枉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哄芜。我一直安慰自己貌亭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布认臊。 她就那樣靜靜地躺著圃庭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剧腻,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天拘央,我揣著相機(jī)與錄音,去河邊找鬼书在。 笑死灰伟,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的儒旬。 我是一名探鬼主播栏账,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼栈源!你這毒婦竟也來了挡爵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤凉翻,失蹤者是張志新(化名)和其女友劉穎了讨,沒想到半個(gè)月后捻激,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體制轰,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年胞谭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了垃杖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丈屹,死狀恐怖调俘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情旺垒,我是刑警寧澤彩库,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站先蒋,受9級特大地震影響骇钦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜竞漾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一眯搭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧业岁,春花似錦鳞仙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春借笙,著一層夾襖步出監(jiān)牢的瞬間爹梁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工提澎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留姚垃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓盼忌,卻偏偏與公主長得像积糯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子谦纱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容