App啟動(dòng)流程:?jiǎn)?dòng)App進(jìn)程

目錄

  • 概述
  • 總結(jié)
  • 詳細(xì)過(guò)程
  • 問(wèn)題&主要類說(shuō)明

概述

-1-
在冷啟動(dòng)過(guò)程中,當(dāng)“為App啟動(dòng)做完準(zhǔn)備”之后( <<為目標(biāo)App啟動(dòng)做準(zhǔn)備>>)红淡,就需要檢查App進(jìn)程是否開(kāi)啟了卸伞,如果沒(méi)有則需要先執(zhí)行 App進(jìn)程的創(chuàng)建操作。
-2-
當(dāng)前源碼的分析是基于 Android8.0锉屈。


總結(jié)

應(yīng)用程序進(jìn)程的啟動(dòng)可以是分為2個(gè)部分的。

第一部分:
AMS向Zygote進(jìn)程發(fā)起啟動(dòng)app進(jìn)程的請(qǐng)求垮耳。
1:AMS調(diào)用其內(nèi)部的“startProcessLocked()”來(lái)開(kāi)啟啟動(dòng)app進(jìn)程的入口颈渊。該方法主要做的是:組裝發(fā)給zygote進(jìn)城的用于啟動(dòng)子進(jìn)程的參數(shù)列表(這些參數(shù)包括:uid,gid,entryPoint 參數(shù)等,entryPoint參數(shù)的值為ActivityThread的類全限定名终佛。該參數(shù)用于fork子進(jìn)程之后啟動(dòng)每個(gè)app進(jìn)程的ActivityThread去做初始化操作俊嗽。)
2:通過(guò)層層調(diào)用最終會(huì)執(zhí)行ZygoteProcess.startViaZygote(),該方法首先會(huì)把AMS服務(wù)傳過(guò)來(lái)的參數(shù)封裝到一個(gè)argsForZygote參數(shù)列表中铃彰。
3:調(diào)用ZygoteProcess內(nèi)部的openZygoteSocketIfNeeded()與Zygote進(jìn)程建立Socket連接绍豁。
4:調(diào)用ZygoteProcess的zygoteSendArgsAndGetResult(),該方法主要做的事情是:將請(qǐng)求參數(shù)列表發(fā)送到zygote進(jìn)程牙捉,并接收Z(yǔ)ygote進(jìn)程啟動(dòng)子進(jìn)程的響應(yīng)結(jié)果竹揍。

第二部分:
Zygote接收到AMS請(qǐng)求fork子進(jìn)程過(guò)程
1:Zygote進(jìn)程被init進(jìn)程拉起后,會(huì)通過(guò)反射調(diào)用ZygotInit的main()邪铲,該方法主要做的事情是:
1.1:初始化ZygoteServer并創(chuàng)建服務(wù)端Socket用于接收芬位、執(zhí)行其它進(jìn)程向Zygote進(jìn)程發(fā)起的請(qǐng)求。
1.2:?jiǎn)?dòng)SystemServer進(jìn)程带到。
1.3:最后調(diào)用runSelectLoop()開(kāi)始循環(huán)接收其它進(jìn)程發(fā)起的請(qǐng)求昧碉。
2:如果檢測(cè)到有請(qǐng)求發(fā)過(guò)來(lái),runSlectLoop()中會(huì)把一次Socket封裝成ZygoteConnection揽惹,而后執(zhí)行其runOnce()方法被饿。
3:在runOnce()內(nèi)部會(huì)調(diào)用Zygote.forkAndSpecialize():內(nèi)部調(diào)用native方法進(jìn)行實(shí)際的fork子進(jìn)程操作。fork成功的話則子進(jìn)程pid等于0,不為0則表示fork失敗(fork()采用copy on write技術(shù)搪搏,這是linux創(chuàng)建進(jìn)程的標(biāo)準(zhǔn)方法狭握,調(diào)用一次,返回兩次慕嚷。)哥牍。
4:如果pid為0,則表示當(dāng)前代碼執(zhí)行在子進(jìn)程喝检,需要執(zhí)行handleChildProc(),該方法主要做的是:關(guān)閉與Zygote進(jìn)程的Socket連接,執(zhí)行ZygoteInit.zygoteInit()嗅辣。
5:ZygoteInit.zygoteInit(),該方法主要執(zhí)行"子進(jìn)程"的運(yùn)行時(shí)初始化操作(這些初始化包括:啟動(dòng)Binder線程池、創(chuàng)建VM挠说、以及反射執(zhí)行子進(jìn)程ActivityThread線程等)澡谭。
5.1:RuntimeInit.commonInit():該方法用于執(zhí)行一些“通用工作的初始化操作”(eg:設(shè)置異常捕獲程序(Thread.setDefaultUncaughtExceptionHandler())、設(shè)置默認(rèn)的UA(user agent等等))。
5.2:ZygoteInit.nativeZygoteInit():?jiǎn)?dòng)Binder線程池蛙奖。
5.3:RuntimeInit.applicationInit():設(shè)置虛擬機(jī)參數(shù)潘酗,反射執(zhí)行ActivityThread.main(),對(duì)main線程進(jìn)行初始化雁仲。


詳細(xì)過(guò)程

第一部分:AMS向Zygot進(jìn)程發(fā)起啟動(dòng)app進(jìn)程的請(qǐng)求

1.startSpecificActivityLocked()

總結(jié)
1:通過(guò)AMS.getProcessRecordLocked()根據(jù)“進(jìn)程名仔夺、uid”查詢是否App的進(jìn)程啟動(dòng)了,如果進(jìn)程未創(chuàng)建則返回null(ProcessRecord“用于記錄app所運(yùn)行在的進(jìn)程的信息”)攒砖。
2:通過(guò)ActivityStack.setLaunchTime()記錄下執(zhí)行Activity啟動(dòng)操作的時(shí)間點(diǎn)缸兔。
3:App進(jìn)程未啟動(dòng),通過(guò)AMS.startProcessLocked()繼續(xù)后續(xù)操作吹艇。

源碼

 void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //App進(jìn)程是否已經(jīng)啟動(dòng)了
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        //該時(shí)間被記錄在ActivityStack中惰蜜,記錄何時(shí)執(zhí)行“Activity的啟動(dòng)”操作的。
        //在統(tǒng)計(jì)“冷啟動(dòng)耗時(shí)”與單個(gè)“Activity啟動(dòng)耗時(shí)”時(shí)會(huì)用到受神。
        //見(jiàn)[小節(jié)1.2]
        r.getStack().setLaunchTime(r);
    
        //如果App進(jìn)程已經(jīng)啟動(dòng)了抛猖,則直接激活待啟動(dòng)Activity。
        if (app != null && app.thread != null) {
            try {
                ......

                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                ......
            }

        }
    
        //App進(jìn)程還沒(méi)創(chuàng)建鼻听,則需要先創(chuàng)建App所運(yùn)行在的進(jìn)程
        //見(jiàn)[小節(jié)1.3]
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

1.1.AMS.getProcessRecordLocked()
源碼

final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
    //如果要查找的是系統(tǒng)進(jìn)程
        if (uid == SYSTEM_UID) {
            ......
        }
        ProcessRecord proc = mProcessNames.get(processName, uid);
        ......
        return proc;
    }

1.1.1:ProcessMap.get()

public E get(String name, int uid) {
        SparseArray<E> uids = mMap.get(name);
        //未緩存則返回null
        if (uids == null) return null;
        return uids.get(uid);
    }

1.2.ActivityStack.setLaunchTime()
總結(jié)
1:記錄下執(zhí)行Activity啟動(dòng)操作的時(shí)間點(diǎn)财著。
2:在待啟動(dòng)Activity所在的視圖樹(shù)經(jīng)過(guò)第一次解析、測(cè)量精算、布局瓢宦、繪制之后會(huì)用到存儲(chǔ)在ActivityStack中的這個(gè)時(shí)間點(diǎn)。具體的會(huì)在ActivityRecord.reportLaunchTimeLocked()借助此時(shí)間點(diǎn)來(lái)統(tǒng)計(jì)“當(dāng)前Activity的啟動(dòng)耗時(shí)”灰羽。

源碼
1.2.1:ActivityStack.setLaunchTime()

void setLaunchTime(ActivityRecord r) {
        if (r.displayStartTime == 0) {
            r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
            if (mLaunchStartTime == 0) {
                startLaunchTraces(r.packageName);
        
                //記錄執(zhí)行Activity啟動(dòng)操作的時(shí)間點(diǎn)
                mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
            }
        } else if (mLaunchStartTime == 0) {
            startLaunchTraces(r.packageName);
            //記錄執(zhí)行Activity啟動(dòng)操作的時(shí)間點(diǎn)
            mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis();
        }
    }

1.2.2.ActivityRecord.reportLaunchTimeLocked()

源碼

    private void reportLaunchTimeLocked(final long curTime) {
        ......
        final long thisTime = curTime - displayStartTime;
        final long totalTime = stack.mLaunchStartTime != 0
                ? (curTime - stack.mLaunchStartTime) : thisTime;
        if (SHOW_ACTIVITY_START_TIME) {
            Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
            EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
                    userId, System.identityHashCode(this), shortComponentName,
                    thisTime, totalTime);
            StringBuilder sb = service.mStringBuilder;
            sb.setLength(0);
            sb.append("Displayed ");
            sb.append(shortComponentName);
            sb.append(": ");
            TimeUtils.formatDuration(thisTime, sb);
            if (thisTime != totalTime) {
                sb.append(" (total ");
                TimeUtils.formatDuration(totalTime, sb);
                sb.append(")");
            }
            Log.i(TAG, sb.toString());
        }
        .....
    }

1.3.啟動(dòng)App進(jìn)程
啟動(dòng)應(yīng)用程序的進(jìn)程主要分2個(gè)方面來(lái)分析:
1:AMS向Zygote發(fā)起fork子進(jìn)程的過(guò)程驮履。
2:Zygote接收AMS的請(qǐng)求創(chuàng)建子進(jìn)程過(guò)程。


1.4.AMS向Zygote發(fā)起fork子進(jìn)程的過(guò)程廉嚼。

源碼

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

1.5.AMS.startProcessLocked()

參數(shù):
1:String processName:待啟動(dòng)的進(jìn)程名玫镐。
2:ApplicationInfo info:存儲(chǔ)的是Manifest文件中對(duì)<application>標(biāo)簽中聲明的屬性信息。
3:boolean knownToBeDead:此值為 true怠噪。
4:int intentFlags:此值為0恐似。
5:String hostingType:此值為“activity”。用于表示“是因?yàn)閳?zhí)行什么操作才導(dǎo)致創(chuàng)建進(jìn)程”的嗎傍念?矫夷?
6:ComponentName hostingName:Intent 中保存的待啟動(dòng)Activity的組件信息。其中包括app的包名與待啟動(dòng)Activity的類名憋槐。
7:boolean allowWhileBooting:此值為 false双藕。
8:boolean isolated:此值為 false。
9:int isolatedUid:此值為 0阳仔。
10:boolean keepIfLarge:此值為 true忧陪。
11:String abiOverride:此值為null。
12:String entryPoint:此值為null。

  • entryPoint在啟動(dòng) App 進(jìn)程之前會(huì)被重新賦值為“ActivityThread的全限定名”嘶摊。
  • 在后續(xù)啟動(dòng)完進(jìn)程后延蟹,會(huì)反射執(zhí)行ActivityThread.main()開(kāi)啟ActivityThread表示的主線程并對(duì)其做相應(yīng)初始化操作。

13:String[] entryPointArgs:此值為null叶堆。
14:Runnable crashHandler:此值為null阱飘。

總結(jié)

在啟動(dòng)App進(jìn)程之前,需要先該把保存進(jìn)程信息的ProcessRecord創(chuàng)建并緩存至AMS內(nèi)部的ArrayMap中虱颗。
具體的:執(zhí)行AMS. newProcessRecordLocked()先把保存待啟動(dòng)App進(jìn)程的ProcessRecord創(chuàng)建完畢 并 緩存到AMS內(nèi)部的一個(gè)ArrayMap俯萌。

源碼

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
            boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
            String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
        //isolated為false,所以走這里
        if (!isolated) {
            //獲取每個(gè)進(jìn)程對(duì)應(yīng)的ProcessRecord上枕。
            //因?yàn)榇龁?dòng)App還沒(méi)有運(yùn)行起來(lái),所以獲取的ProcessRecord為null弱恒。
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            ......
        } else {
            app = null;
        }
        ......

        if (app == null) {
            //先把ProcessRecord創(chuàng)建好辨萍,其次緩存至AMS服務(wù)中的“mProcessNames”屬性指向的ProcessMap中( ProcessMap內(nèi)部維護(hù)了一個(gè)ArrayMap來(lái)緩存已經(jīng)啟動(dòng)完畢的進(jìn)程信息)。
            //見(jiàn)[小節(jié)1.6]
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            if (app == null) {
                //如果創(chuàng)建失敗返弹,則退出此次啟動(dòng)進(jìn)程操作锈玉,并返回null表示啟動(dòng)進(jìn)程操作失敗了。
                return null;
            }
            ......
        } else {
            ......
        }

        //AMS服務(wù)已經(jīng)在system_server進(jìn)程中被初始化完畢了义起,mProcessesReady已經(jīng)被賦值為了true裁替。具體請(qǐng)查看`問(wèn)題小節(jié)`毛俏。
        //不會(huì)走這里
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
            ......
            return app;
        }

       ......
       //見(jiàn)[小節(jié)1.7]
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        ......
        return (app.pid != 0) ? app : null;
    }

1.6.AMS.newProcessRecordLocked()
總結(jié):
1:創(chuàng)建保存進(jìn)程信息的ProcessRecord。
2:調(diào)用AMS.addProcessNameLocked()把此ProcessRecord緩存起來(lái)。

源碼

final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid) {
        String proc = customProcess != null ? customProcess : info.processName;
        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
        final int userId = UserHandle.getUserId(info.uid);
        int uid = info.uid;
        if (isolated) {
        ......
        }
        //創(chuàng)建一個(gè)ProcessRecord
        final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
        ......
        //見(jiàn)[小節(jié)1.6.1]
        addProcessNameLocked(r);
        return r;
    

1.6.1.AMS.addProcessNameLocked():把目標(biāo)ProcessRecord緩存起來(lái)

private final void addProcessNameLocked(ProcessRecord proc) {
        ......
        //把ProcessRecord緩存起來(lái)
        mProcessNames.put(proc.processName, proc.uid, proc);
        ......
    }

1.7.AMS.startProcessLocked()
總結(jié)

1:重新對(duì)entryPoint的內(nèi)容賦值固灵,賦值后它存儲(chǔ)的是“ActivityThread類的全限定名”,ActivityThread在后續(xù)進(jìn)程啟動(dòng)完畢后杠巡,系統(tǒng)會(huì)反射執(zhí)行ActivityThread.main()開(kāi)啟ActivityThread表示的主線程并對(duì)其做相應(yīng)初始化操作派歌。
2:繼續(xù)后續(xù)進(jìn)程的創(chuàng)建操作。
3:創(chuàng)建進(jìn)程的系統(tǒng)事件會(huì)被記錄到trace中含滴,方便采用trace工具獲得此事件花費(fèi)的時(shí)間诱渤。進(jìn)程創(chuàng)建完畢后,還會(huì)輸出相應(yīng)信息至logcat谈况。
4:進(jìn)程創(chuàng)建完畢勺美,保存進(jìn)程信息至ProcessRecord(如更新進(jìn)程id只ProcessRecord中)。

源碼

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        //App進(jìn)程還未啟動(dòng)碑韵,此時(shí)pid為0赡茸。
        if (app.pid > 0 && app.pid != MY_PID) {
            ......
        }
        ......
        try {
            //設(shè)置該App是否可debug。
            //應(yīng)用進(jìn)程是否可被調(diào)試泼诱,是由在Manifest文件注冊(cè)Application時(shí)對(duì)<application>添加“android:debuggable”屬性來(lái)支持的坛掠。true是可debug,false是不可以。
            //在打debug包時(shí)屉栓,該屬性是開(kāi)啟的舷蒲。relase包是禁止的。
            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                ......
            }
            ......
            //因?yàn)閑ntryPoint為null友多,所以isActivityProcess為true
            boolean isActivityProcess = (entryPoint == null);
            //因?yàn)閑ntryPoint為null牲平,所以為它賦值為“ActivityThread的全限定名”。
            //entryPoint很重要域滥,用于后續(xù)啟動(dòng)完進(jìn)程后纵柿,開(kāi)啟ActivityThread表示的主線程。
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            //各種系統(tǒng)trace信息启绰,此時(shí)這里開(kāi)始記錄進(jìn)程的創(chuàng)建事件
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            ......
            ProcessStartResult startResult;
            //hostingType被初始化為“activity”昂儒,所以不會(huì)走這里。
            if (hostingType.equals("webview_service")) {
                ......
            } else {
                //見(jiàn)[小節(jié)1.8]
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
            //保存 創(chuàng)建進(jìn)程所花費(fèi)的時(shí)間委可。
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            ......
            //進(jìn)程創(chuàng)建完畢后渊跋,會(huì)輸出相應(yīng)信息至logcat
            StringBuilder buf = mStringBuilder;
            buf.setLength(0);
            buf.append("Start proc ");
            buf.append(startResult.pid);
            buf.append(':');
            buf.append(app.processName);
            buf.append('/');
            UserHandle.formatUid(buf, uid);
            if (!isActivityProcess) {
                buf.append(" [");
                buf.append(entryPoint);
                buf.append("]");
            }
            buf.append(" for ");
            buf.append(hostingType);
            if (hostingNameStr != null) {
                buf.append(" ");
                buf.append(hostingNameStr);
            }
            Slog.i(TAG, buf.toString());
            //進(jìn)程創(chuàng)建完畢,保存進(jìn)程信息至ProcessRecord着倾。
            app.setPid(startResult.pid);
            app.usingWrapper = startResult.usingWrapper;
            app.removed = false;
            app.killed = false;
            app.killedByAm = false;
            ......
        } catch (RuntimeException e) {
            ......
        }
    }

進(jìn)程創(chuàng)建完畢log

04-25 16:40:20.824 1644-3146/? I/ActivityManager: Start proc 7880:sj.com.github_workspace/u0a83 for activity sj.com.github_workspace/.MainActivity


1.8.Process.start()
總結(jié):
1:Process:用于管理操作系統(tǒng)進(jìn)程的工具拾酝。

  • 該類中定義了一些進(jìn)程的uid。例如:系統(tǒng)uid包括 電話,wifi等進(jìn)程卡者。應(yīng)用程序進(jìn)程uid的取值范圍(FIRST_APPLICATION_UID與LAST_APPLICATION_UID之間,也就是[10000,19999])蒿囤。
  • 提供了獲取進(jìn)程uid(應(yīng)用id),userId(用戶id),gid(進(jìn)程組id),pid(進(jìn)程id),ppid(父進(jìn)程id)等信息的工具方法。(關(guān)于uid,userId,gid概念請(qǐng)參考 https://blog.csdn.net/zhanglianyu00/article/details/50253187)

2:Process類內(nèi)部維護(hù)了一個(gè)ZygoteProcess類的實(shí)例崇决,ZygoteProcess“用于保持與Zygote進(jìn)程的通信狀態(tài)材诽。”

參數(shù):
String processClass:ActivityThread類的全限定名恒傻。
String niceName:進(jìn)程名岳守。默認(rèn)的話就是App的包名。
int uid:進(jìn)程的uid碌冶。
int gid:進(jìn)程組id湿痢。
int[] gids:待補(bǔ)充。扑庞。譬重。
int debugFlags:存儲(chǔ)了App進(jìn)程是否可被debug的信息。
int mountExternal:待補(bǔ)充罐氨。臀规。。
int targetSdkVersion:在Manifest文件中聲明的targetSdk版本號(hào)栅隐。
String seInfo:待補(bǔ)充塔嬉。玩徊。。
String abi:待補(bǔ)充谨究。恩袱。。
String instructionSet:
String appDataDir:為存儲(chǔ)App信息的內(nèi)部存儲(chǔ)目錄(Sp文件胶哲、數(shù)據(jù)庫(kù)就存在這里)畔塔。
String invokeWith:此值為null。
String[] extraArgs:此值為null鸯屿。

源碼

    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 abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String invokeWith,
                                  String[] zygoteArgs) {
        //見(jiàn)小節(jié)[1.9]
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

1.9.ZygoteProcess.start()
源碼

    public final Process.ProcessStartResult start(final String processClass,
                                                  final String niceName,
                                                  int uid, int gid, int[] gids,
                                                  int debugFlags, int mountExternal,
                                                  int targetSdkVersion,
                                                  String seInfo,
                                                  String abi,
                                                  String instructionSet,
                                                  String appDataDir,
                                                  String invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            ......
        }
    }

1.10.ZygoteProcess.startViaZygote()

    private Process.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 abi,
                                                      String instructionSet,
                                                      String appDataDir,
                                                      String invokeWith,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // 設(shè)置一些運(yùn)行時(shí)參數(shù)澈吨,這些參數(shù)就是根據(jù)傳遞給該方法的參數(shù)來(lái)設(shè)置的。
        //例如設(shè)置把uid,gid這些信息都封裝到argsForZygote 這個(gè)列表中寄摆。
       ......
        synchronized(mLock) {
            //見(jiàn)[小節(jié)1.11]與[小節(jié)1.12]
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

1.11.ZygoteProcess.openZygoteSocketIfNeeded()
總結(jié):

1:該方法內(nèi)部會(huì)通過(guò)ZygoteState.connect(),打開(kāi)與Zygote進(jìn)程之間的Socket連接.
2:ZygoteState:該類為ZygoteProcess的內(nèi)部類谅辣。表示一次與Zygote進(jìn)程建立的Socket通信過(guò)程。其內(nèi)部維護(hù)了LocalSocket與Zygote進(jìn)程進(jìn)行通信婶恼。


1.12.ZygoteProcess.zygoteSendArgsAndGetResult()
總結(jié)

1:用于將請(qǐng)求參數(shù)列表發(fā)送到zygote進(jìn)程屈藐,并接收Z(yǔ)ygote進(jìn)程啟動(dòng)子進(jìn)程的響應(yīng)結(jié)果。
2:Zygote會(huì)把fork子進(jìn)程的pid返回給AMS 熙尉。(通過(guò)openZygoteSocketIfNeeded()建立好連接之后就需要向Zygote發(fā)送請(qǐng)求數(shù)據(jù),以及響應(yīng) Zygote發(fā)回的響應(yīng)數(shù)據(jù)搓扯。該方法就是用來(lái)做發(fā)送检痰、接受上述事情的。)

源碼

    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // 檢查參數(shù)列表
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }

            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            
            //向Zygote進(jìn)程寫數(shù)據(jù)
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();
            
            //等Zygote進(jìn)程處理完畢后锨推,讀取Zygote進(jìn)程的處理結(jié)果
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();
            
             //pid小于0則表示創(chuàng)建子進(jìn)程失敗的話铅歼,會(huì)拋出異常。
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

第二部分:Zygote接收到AMS請(qǐng)求fork子進(jìn)程過(guò)程

前提:

Zygote進(jìn)程被init進(jìn)程拉起后换可,會(huì)通過(guò)反射調(diào)用ZygotInit的main()進(jìn)行初始化操作椎椰。這些初始化操作主要包括:
1:初始化ZygoteServer并創(chuàng)建服務(wù)端Socket用于接收、執(zhí)行其它進(jìn)程向Zygote進(jìn)程發(fā)起的請(qǐng)求沾鳄。
2:?jiǎn)?dòng)SystemServer進(jìn)程慨飘。
3:最后調(diào)用runSelectLoop()開(kāi)始循環(huán)接收其它進(jìn)程發(fā)起的請(qǐng)求。

關(guān)于Zygote進(jìn)程的初始化操作译荞,請(qǐng)參看<<Zygote進(jìn)程啟動(dòng)過(guò)程學(xué)習(xí)與理解>>

接下來(lái)從Zygote接收來(lái)自運(yùn)行在system_server進(jìn)程的AMS發(fā)送的啟動(dòng)App進(jìn)程請(qǐng)求的地方說(shuō)起瓤的。

2.1.ZygoteServer.runSelectLoop():開(kāi)啟死循環(huán)接收來(lái)自其他進(jìn)程發(fā)起的Socket請(qǐng)求。
源碼

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
       ......
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
       ......
        //開(kāi)啟死循環(huán)接收來(lái)自其他進(jìn)程發(fā)起的Socket請(qǐng)求
        while (true) {
            ......
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
               ......
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //如果接收到來(lái)自其他進(jìn)程的Socket請(qǐng)求吞歼,則會(huì)走執(zhí)行ZygoteConnection.run()
                    //見(jiàn)小節(jié)[2.2]
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

2.2.ZygoteConnection.runOnce():
總結(jié):

1:fork函數(shù)圈膏,調(diào)用一次返回2次,在父進(jìn)程返回子進(jìn)程的實(shí)際pid篙骡,而在子進(jìn)程中則返回0稽坤。這樣做是為了“能夠正確區(qū)分程序是運(yùn)行在父進(jìn)程還是子進(jìn)程丈甸。”
2:調(diào)用Zygote.forkAndSpecialize()通過(guò)native方法創(chuàng)建子進(jìn)程尿褪。
2:子進(jìn)程啟動(dòng)完畢后睦擂,繼續(xù)調(diào)用ZygoteConnection.handleChildProc()對(duì)子進(jìn)程進(jìn)行初始化。

源碼

boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
        ......
        //pid默認(rèn)為-1茫多。
        //AMS通過(guò)ZygoteProcess.zygoteSendArgsAndGetResult()向Zygote進(jìn)程發(fā)送啟動(dòng)App進(jìn)程的請(qǐng)求后祈匙,也會(huì)在該方法中進(jìn)程的pid做檢查,如果小于0天揖,則會(huì)拋出“ZygoteStartFailedEx”提示創(chuàng)建進(jìn)程失敗夺欲。
        int pid = -1;
        ......
            //見(jiàn)小節(jié)[2.3]
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }

        try {
            //1:fork會(huì)“調(diào)用一次,返回兩次”今膊。分別在父進(jìn)程些阅、子進(jìn)程返回。
            //2:在父進(jìn)程返回子進(jìn)程的實(shí)際pid斑唬,而在子進(jìn)程返回的pid為0市埋。這樣做是為了“能夠正確區(qū)分程序是運(yùn)行在父進(jìn)程還是子進(jìn)程∷×酰”
            if (pid == 0) {
                // 這是程序運(yùn)行在新創(chuàng)建的子進(jìn)程中
                //fork()操作出的子進(jìn)程是父進(jìn)程的一個(gè)副本缤谎。父進(jìn)程具備的他都用。自進(jìn)程的虛擬地址空間與父進(jìn)程一樣褐着,代碼等都一致坷澡。那么Zygote進(jìn)程內(nèi)部開(kāi)啟了一個(gè)用于接收AMS發(fā)起的創(chuàng)建子進(jìn)程的操作,該方法就是用來(lái)關(guān)閉“啟動(dòng)的用于接收AMS發(fā)起的Socket服務(wù)”含蓉。
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //見(jiàn)小節(jié)[2.4]
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                //這是運(yùn)行在父進(jìn)程
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            ......
        }
    }

2.3.Zygote.forkAndSpecialize()
源碼

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, String instructionSet, String appDataDir) {
        ......
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, instructionSet, appDataDir);
       ......
        if (pid == 0) {
            //采用trace記錄fork子進(jìn)程的后频敛,執(zhí)行“handleChildProc()”花費(fèi)的時(shí)間
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
        }
        ......
        return pid;
    }

2.4.ZygoteConnection.handleChildProc()(handle child process)

總結(jié):

該方法在fork進(jìn)程完畢后執(zhí)行,用于關(guān)閉與Zygote進(jìn)程的Socket連接馅扣, 執(zhí)行ZygoteInit.zygoteInit()斟赚。

源碼

private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws Zygote.MethodAndArgsCaller {
          //關(guān)閉與Zygote建立的Socket連接
          closeSocket();
         //結(jié)束對(duì)該方法的記錄
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //這個(gè)invokeWidth從AMS向Zygote發(fā)起請(qǐng)求時(shí)指定的值就是null。
        //不會(huì)走這里
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            //見(jiàn)小節(jié)[2.5]
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

2.5.ZygoteInit.zygoteInit()
總結(jié):

1:通過(guò)RuntimeInit.commonInit()對(duì)一些運(yùn)行時(shí)的公共數(shù)據(jù)進(jìn)行初始化操作(eg:設(shè)置異常捕獲程序(Thread.setDefaultUncaughtExceptionHandler())差油、設(shè)置默認(rèn)的UA(user agent等等)拗军。
2:通過(guò)ZygoteInit.nativeZygoteInit(),啟動(dòng)App進(jìn)程的Binder線程池蓄喇。

源碼

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

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();
        
        //一些公共數(shù)據(jù)的初始化
        //eg:設(shè)置異常捕獲程序(Thread.setDefaultUncaughtExceptionHandler())食绿、設(shè)置默認(rèn)的UA(user agent等等)
        RuntimeInit.commonInit();
        //初始化App進(jìn)程的Binder線程池
        ZygoteInit.nativeZygoteInit();
        //見(jiàn)小節(jié)[2.6]
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

2.6.ZygoteInit.applicationInit()
源碼

protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
        
        //設(shè)置虛擬機(jī)參數(shù)        
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        // 反射執(zhí)行ActivityThread.main()
        //見(jiàn)小節(jié)[2.7]
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

2.7.RuntimeInit.invokeStaticMain():反射執(zhí)行ActivityThread.main(),對(duì)main線程進(jìn)行初始化公罕。
源碼

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

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
           ......
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            .......
        } catch (SecurityException ex) {
            ......
        }
        ......
        //見(jiàn)小節(jié)[2.8]
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

2.8.MethodAndArgsCaller .run():
總結(jié)

1:MethodAndArgsCaller是一個(gè)Runnable也是一個(gè)異常器紧。該異常會(huì)在ZygiteInit.()中被捕獲,捕獲之后就會(huì)執(zhí)行其run()楼眷。
2:在run()中铲汪,就是通過(guò)反射來(lái)執(zhí)行ActivityThread.main()來(lái)對(duì)主線程進(jìn)程初始化熊尉。

源碼

public static class MethodAndArgsCaller extends Exception
            implements Runnable {
       ......
        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
               ......
            } catch (InvocationTargetException ex) {
                .....
            }
        }
    }

問(wèn)題:

1:AMS.mProcessesReady屬性是什么意思?systemReady()方法又是干什么的掌腰?
此屬性用于表示“一些初始化的流程是否準(zhǔn)備完畢”狰住。如果該值為 false,那么在創(chuàng)建進(jìn)程時(shí)齿梁,可能“先不會(huì)走實(shí)際創(chuàng)建進(jìn)程的操作”催植。為 true,則才會(huì)走繼續(xù)通知Zygote進(jìn)程fork子進(jìn)程勺择。
system_server被Zygote進(jìn)程拉起后创南,會(huì)執(zhí)行SystemServer.main()對(duì)system_server進(jìn)程做初始化操作。其中像AMS省核、WMS 就是在其中初始化的稿辙,當(dāng)初始化AMS后則會(huì)執(zhí)行其systemReady()去做“一些準(zhǔn)備工作”,等其內(nèi)部相應(yīng)準(zhǔn)備工作準(zhǔn)備好后气忠,則會(huì)更新該值為 true邻储。**

2:操作系統(tǒng)提供的fork()函數(shù)大概是怎么工作的?
1:fork()會(huì)“調(diào)用一次旧噪,返回兩次”吨娜。分別在父進(jìn)程、子進(jìn)程返回淘钟。
2:在父進(jìn)程返回子進(jìn)程的實(shí)際pid宦赠,而在子進(jìn)程返回的pid為0。這樣做是為了“能夠正確區(qū)分程序是運(yùn)行在父進(jìn)程還是子進(jìn)程日月。


重要類說(shuō)明

1:ProcessRecord:用于記錄app進(jìn)程信息。
2:Process:用于管理操作系統(tǒng)進(jìn)程的工具缤骨。
該類中定義了一些進(jìn)程的uid爱咬。例如:系統(tǒng)基礎(chǔ)訥航uid包括 電話,wifi等進(jìn)程。應(yīng)用程序進(jìn)程uid的取值范圍(
FIRST_APPLICATION_UID與
LAST_APPLICATION_UID之間,也就是[10000,19999])绊起。
提供了獲取進(jìn)程uid(用戶id),gid(組id),pid(進(jìn)程id),ppid(父進(jìn)程id)等信息的工具方法精拟。
該類內(nèi)部維護(hù)了一個(gè)ZygoteProcess虱歪,用于通過(guò)ZygoteProcess.start()通知Zygote進(jìn)程來(lái)啟動(dòng)app進(jìn)程蜂绎。

3:ZygoteProcess:用于保持與Zygote進(jìn)程的通信狀態(tài)。
4:ZygoteState:該類為ZygoteProcess的內(nèi)部類笋鄙。表示一次與Zygote進(jìn)程建立的Socket通信過(guò)程师枣。其內(nèi)部維護(hù)了LocalSocket與Zygote進(jìn)程進(jìn)行通信。
5:ZygoteInit:init進(jìn)程啟動(dòng)完Zygote 進(jìn)程之后萧落,會(huì)執(zhí)行該類的main()去做一些其它事情践美。這些事情包括:
1:創(chuàng)建ZygoteServer用于接受AMS發(fā)起的創(chuàng)建應(yīng)用進(jìn)程請(qǐng)求洗贰。
2:?jiǎn)?dòng)SystemServer進(jìn)程。
3:執(zhí)行ZygoteServer.runSelectLoop()開(kāi)始循環(huán)接收其它進(jìn)程發(fā)起的請(qǐng)求陨倡。

ZygoteServer:為Zygote服務(wù)敛滋,用于接收并執(zhí)行來(lái)自AMS向其發(fā)送的Socket請(qǐng)求。
ZygoteConnection:該類表示AMS向Zygote發(fā)起的一起Socket連接請(qǐng)求兴革。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绎晃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子杂曲,更是在濱河造成了極大的恐慌庶艾,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件解阅,死亡現(xiàn)場(chǎng)離奇詭異落竹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)货抄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門述召,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人蟹地,你說(shuō)我怎么就攤上這事积暖。” “怎么了怪与?”我有些...
    開(kāi)封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵夺刑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我分别,道長(zhǎng)遍愿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任耘斩,我火速辦了婚禮沼填,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘括授。我一直安慰自己坞笙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布荚虚。 她就那樣靜靜地躺著薛夜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪版述。 梳的紋絲不亂的頭發(fā)上梯澜,一...
    開(kāi)封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音渴析,去河邊找鬼腊徙。 笑死简十,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撬腾。 我是一名探鬼主播螟蝙,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼民傻!你這毒婦竟也來(lái)了胰默?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤漓踢,失蹤者是張志新(化名)和其女友劉穎牵署,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喧半,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奴迅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挺据。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片取具。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖扁耐,靈堂內(nèi)的尸體忽然破棺而出暇检,到底是詐尸還是另有隱情,我是刑警寧澤婉称,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布块仆,位于F島的核電站,受9級(jí)特大地震影響王暗,放射性物質(zhì)發(fā)生泄漏悔据。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一俗壹、第九天 我趴在偏房一處隱蔽的房頂上張望科汗。 院中可真熱鬧,春花似錦策肝、人聲如沸肛捍。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至依许,卻和暖如春棺禾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峭跳。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工膘婶, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缺前,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓悬襟,卻偏偏與公主長(zhǎng)得像衅码,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脊岳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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

  • 理解Android進(jìn)程創(chuàng)建流程理解Android進(jìn)程啟動(dòng)之全過(guò)程 站在GITYUAN大神的肩膀上學(xué)習(xí)逝段,用一張神圖表...
    小編閱讀 5,221評(píng)論 0 18
  • 在上一節(jié)Activity的啟動(dòng)流程中,當(dāng)app進(jìn)程不存在(第一次啟動(dòng))時(shí)割捅,會(huì)先去創(chuàng)建進(jìn)程奶躯。這里我們通過(guò)源碼來(lái)解讀a...
    第八區(qū)閱讀 535評(píng)論 0 0
  • 應(yīng)用啟動(dòng)流程 Android系統(tǒng)是基于Linux的,所以它的所有應(yīng)用也是基于Linux的Init進(jìn)程創(chuàng)建出來(lái)的亿驾,首...
    SillyMonkey閱讀 2,696評(píng)論 0 51
  • 寫出了我期待的故事嘹黔。 這是某個(gè)人對(duì)我寫的短篇小說(shuō)的評(píng)價(jià)。 我用某個(gè)人期待的寫法寫出了他期待的故事但事實(shí)并不是這樣莫瞬。...
    凈心先生閱讀 139評(píng)論 0 0
  • 奶奶走了儡蔓,就半個(gè)月的時(shí)間。突發(fā)的疾病讓她始終處于昏迷狀態(tài)乏悄。 知道這個(gè)消息浙值,我整個(gè)人像空了一樣。從她入院檩小,我才感受到...
    BIUBIUbiu你閱讀 569評(píng)論 0 0