前言:
百度一搜能找到很多講APP啟動(dòng)流程的,但是往往要么就是太老舊(還是基于android6去分析的),要么就是不全(往往只講了整個(gè)流程的一小部分)。所以我結(jié)合網(wǎng)上現(xiàn)有的文章,以及源碼的閱讀和調(diào)試,耗費(fèi)了3整天的時(shí)間,力求寫出一篇最完整,最詳細(xì),最通俗易懂的文章,來講清楚在android上,APP是如何啟動(dòng)的。
?該文屬于安卓源碼探究專欄中的文章,專欄中很多類似源碼分析的文章,歡迎大家閱讀。
鏈接如下:
安卓源碼研究
一、APP啟動(dòng)流程概覽
涉及到四個(gè)進(jìn)程之間的通信,分別是Laucher進(jìn)程(桌面APP),SystemServer進(jìn)程(AMS所屬進(jìn)程),Zygote進(jìn)程(系統(tǒng)和所有APP的創(chuàng)建進(jìn)程),APP進(jìn)程。
APP簡(jiǎn)要的啟動(dòng)流程是這樣的:
1.Laucher進(jìn)程會(huì)通過binder的方式通知SystemServer進(jìn)程。
2.然后SystemServer進(jìn)程中的AMS會(huì)查詢對(duì)應(yīng)的Activity棧信息,如果對(duì)應(yīng)APP進(jìn)程不存在則會(huì)加載占位圖。然后通過socket的方式通知Zygote去創(chuàng)建APP進(jìn)程。
3.APP進(jìn)程創(chuàng)建后會(huì)執(zhí)行main方法,然后通知AMS
4.AMS收到信息后會(huì)繼續(xù)通知APP去創(chuàng)建Application,并且接下來會(huì)通知APP進(jìn)程取拉起Activity。
5.APP進(jìn)程依次收到通知后,會(huì)依次完成加載APK,初始化Application,執(zhí)行Activtiy生命周期等操作。最終會(huì)把首屏展示出來。
流程圖如下,建議雙擊放大后觀看:
?
接下來的幾章,會(huì)按照上面的流程逐一拆解分析:
二、Launcher通知AMS啟動(dòng)APP
Launcher進(jìn)程其實(shí)和普通APP是一樣的,甚至我們可以把自己的APP設(shè)置為桌面APP。
2.1 Launcher獲取到AMS的binder
而Launcher通知AMS的流程和正常APP也是一樣的,通過ServiceManager獲取到AMS的binder引用。這里提到了ServiceManager,其實(shí)ServiceManagerService也是單獨(dú)的一個(gè)進(jìn)程,其存儲(chǔ)了所有APP所需要的binder引用。而且其地址是固定的,所以獲取ServiceManager可以直接獲取。
2.2 通知ActivityManagerService
Launcher通過上述獲取到的binder通知到AMS,調(diào)用的方式是startActivityWithFeature。
而由于AMS實(shí)現(xiàn)了IActivityManager.Stub的實(shí)現(xiàn),所以其startActivityWithFeature方法會(huì)收到launcher發(fā)過來的通知。
2.3?系統(tǒng)進(jìn)程加載占位圖
AMS中,會(huì)交由ActivityTaskManagerService去進(jìn)行對(duì)應(yīng)啟動(dòng)任務(wù)的處理。最終會(huì)交給ActivityStart進(jìn)行處理。
ActivityStart中,首先會(huì)進(jìn)行一個(gè)邏輯判斷,如果進(jìn)程不存在,則首先會(huì)加載APP中MainActivity的主題作為背景圖,顯示到屏幕上。這一步操作是發(fā)生在SystemServer進(jìn)程的,APP進(jìn)程還未創(chuàng)建。
android11開始支持啟動(dòng)動(dòng)畫,邏輯也是在這里處理的。
2.4 AMS進(jìn)行啟動(dòng)操作
一個(gè)進(jìn)程中會(huì)有多個(gè)任務(wù)棧,棧對(duì)應(yīng)的是Task類。
一個(gè)任務(wù)棧中會(huì)有多個(gè)Activity對(duì)象,這個(gè)Activity對(duì)象在AMS中使用ActivityRecord記錄。
這一塊的具體邏輯,我會(huì)單獨(dú)寫一篇Activity的啟動(dòng)邏輯來進(jìn)行描述。
這里暫時(shí)先簡(jiǎn)單描述下,如果AMS發(fā)現(xiàn)進(jìn)程不存在,會(huì)去通知Zygote的進(jìn)行進(jìn)程fork就好,對(duì)應(yīng)的fork邏輯在下一章。
三、Zygote創(chuàng)建APP進(jìn)程
3.1 AMS中內(nèi)部邏輯執(zhí)行
ActivityTaskManagerService調(diào)用startProcessAsync方法會(huì)去負(fù)責(zé)創(chuàng)建APP進(jìn)程,這是異步的,通過handler轉(zhuǎn)發(fā)后最終會(huì)調(diào)用到LocalService.startProcess()方法。
然后會(huì)通知到ProcessList.startProcessLocked方法,這個(gè)方法中,會(huì)構(gòu)造一個(gè)對(duì)象ProcessRecord對(duì)象,然后把各種信息添加到這個(gè)對(duì)象中。
接下來會(huì)調(diào)用到ProcessList.startProcessLocked這個(gè)方法,這個(gè)方法主要是負(fù)責(zé)把各種信息轉(zhuǎn)換為runtimeFlags標(biāo)記位,連同上面構(gòu)造的ProcessRecord繼續(xù)傳入下一層。
最終通知到Process.start方法,然后交由ZygoteProcess.start方法,最終傳遞到startViaZygote方法。
3.2 請(qǐng)求參數(shù)拼接成字符串發(fā)送給Zygote
startViaZygote這個(gè)方法中,會(huì)把各種配置參數(shù)拼接為字符串。
最終在ZygoteProcess.attemptUsapSendArgsAndGetResult方法中,通過LocalSocket的方式把上面拼接的字符串內(nèi)容傳遞給Zygote進(jìn)程。并且從socket中讀取返回值,返回值的PID>0則證明進(jìn)程創(chuàng)建成功。
3.3?Zygote進(jìn)程邏輯
在了解Zygote進(jìn)程如何解析AMS發(fā)送過來的請(qǐng)求之前,我們先簡(jiǎn)單了解下Zygote進(jìn)程創(chuàng)建后的一些基本邏輯。如下圖:
一。Zygote進(jìn)程創(chuàng)建后,最開始的入口是在C層,app_main.cpp文件的main方法(該進(jìn)程由Init進(jìn)程啟動(dòng),這里就不擴(kuò)展了),在main方法中會(huì)配置一些JVM的參數(shù),這個(gè)和JAVA的虛擬機(jī)參數(shù)配置類似。最終會(huì)調(diào)用到AndroidRuntime.cpp中的start函數(shù),去啟動(dòng)JVM虛擬機(jī)。
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
二。虛擬機(jī)創(chuàng)建之后,會(huì)通過native層反射找到main函數(shù),并調(diào)用ZygoteInit類的main函數(shù)。
AndroidRumtime.cpp的start方法中:
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 {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
三。ZygoteInit類的main方法中,會(huì)做如下幾件事:
第一步,把自身的進(jìn)程ID設(shè)置為0,并且沒有parent進(jìn)程。
第二步,會(huì)進(jìn)行一系列的初始化操作,比如加載native環(huán)境,加載JVM環(huán)境,加載系統(tǒng)類,加載系統(tǒng)資源等等。都在其preload方法中。
第三步,如果是首次執(zhí)行,則會(huì)創(chuàng)建SystemServer進(jìn)程。這也是Zygote進(jìn)程的大兒子。AMS,WMS都屬于SystemServer進(jìn)程。
第四步,會(huì)創(chuàng)建zygoteServer對(duì)象,并且調(diào)用其runSelectLoop方法。監(jiān)聽socket不斷的接傳遞過來的信息
第五步,Zygote進(jìn)程的fork,其實(shí)是復(fù)制一個(gè)原原本本的自己。runSelectLoop方法中其實(shí)會(huì)去執(zhí)行fork操作,這個(gè)后面會(huì)講,我們這里只需要知道,執(zhí)行到caller.run();這一句的時(shí)候,已經(jīng)處于APP進(jìn)程狀態(tài)了。
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
...
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//2.初始化操作
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
//3.首次啟動(dòng)時(shí),會(huì)啟動(dòng)系統(tǒng)進(jìn)程
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
//4.啟動(dòng)無限循環(huán)監(jiān)聽socket
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal 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) {
//5.這里的調(diào)用已經(jīng)是在APP進(jìn)程了,zygote進(jìn)程永遠(yuǎn)不會(huì)執(zhí)行到這里
caller.run();
}
}
3.4 收到通知后去fork產(chǎn)生APP進(jìn)程
runSelectLoop方法中,會(huì)開啟一個(gè)無限循環(huán)。如果收到了消息
如果收到了消息,則會(huì)調(diào)用ZygoteConnection.processCommand去處理。
Runnable runSelectLoop (String abiList){
// ...
while (true) {
// ...
try {
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
//收到消息,處理消息并且返回runnable。
final Runnable command =
connection.processCommand(this, multipleForksOK);
// TODO (chriswailes): Is this extra check necessary?
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}
//子進(jìn)程執(zhí)行,子進(jìn)程的mIsForkChild會(huì)被設(shè)置為true,則返回command
return command;
} else {
//Zygote進(jìn)程執(zhí)行,則繼續(xù)執(zhí)行循環(huán)
// ...
}
}
}
}
而在processCommand中,會(huì)解析收到的參數(shù),最終調(diào)用Zygote.forkAndSpecialize去fork一個(gè)新進(jìn)程。這個(gè)方法雖然只會(huì)調(diào)用一次,返回因?yàn)檫M(jìn)程是拷貝的,所以實(shí)際上會(huì)有兩次返回,返回兩個(gè)pid。pid為0時(shí)為子進(jìn)程,設(shè)置標(biāo)記為子進(jìn)程。反之仍就還是Zygote進(jìn)程。
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
3.5?調(diào)用ActivityThread.main方法
調(diào)用到handleChildProc方法時(shí),已經(jīng)處于APP進(jìn)程的狀態(tài)。
該方法掉調(diào)用到ZygoteInit.zygoteInit()方法,相關(guān)代碼如下:
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
...
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
第一步,把System.out的輸出重定向到Logcat中;
第二步,在commonInit方法中,設(shè)置Thread的UncaughtExceptionPreHandler和DefaultUncaughtExceptionHandler。用于應(yīng)用發(fā)生異常時(shí)的處理,這里稍微擴(kuò)展下,DefaultUncaughtExceptionHandler設(shè)置的是RuntimeInit.KillApplicationHandler,所以所有最終未處理的異常都會(huì)走到這個(gè)類中。
第三步,native中進(jìn)行相關(guān)的初始化。
最后一步,做VM虛擬機(jī)的一些配置,然后就會(huì)調(diào)用findStaticMain方法。
接下來,我們看下findStaticMain方法:
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);
}
這里只看到出現(xiàn)了main方法,并沒有看到ActivityThread類的聲明。所以,是如何最終選擇啟動(dòng)類類中的main方法呢?其實(shí)原理很簡(jiǎn)單,這個(gè)方法中有一個(gè)className參數(shù),這個(gè)其實(shí)就是ActivityThread類,它是通過socket傳遞過來的一個(gè)參數(shù),其定義在ProcessList的startProcessLocked方法中
所以最后返回的其實(shí)是一個(gè)runnable接口實(shí)現(xiàn)類,而這個(gè)runnable中實(shí)現(xiàn)了調(diào)用ActivityThread中main方法的邏輯。
還記得3.3中Zygote創(chuàng)建后的邏輯嗎?最后一句是調(diào)用?caller.run();
是的,這個(gè)caller就是最后返回的runnable接口實(shí)現(xiàn)類,去完成調(diào)用main方法的操作。
四、APP進(jìn)程創(chuàng)建初始化操作
app進(jìn)程初始化的操作比較簡(jiǎn)單,主要做了兩件事,初始化looper,以及通知AMS。(注意,這里只是APP進(jìn)程創(chuàng)建了,但是還沒有加載APK中的任何類)
4.1 初始化MainLooper
調(diào)用main方法的線程,會(huì)被設(shè)置為主線程,Looper此時(shí)會(huì)開啟無限循環(huán)。
main(){
//looper綁定主線程
Looper.prepareMainLooper();
//通知AMS
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//looper開啟無限循環(huán)讀取消息
Looper.loop();
}
4.2 通知AMS
ActivityThread.attach方法中,實(shí)現(xiàn)邏輯也是比較簡(jiǎn)單的,直接通過binder通知AMS,并且把自身的binder(ApplicationThread)也傳遞給AMS。
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
這里AMS的binder是直接通過ServierManager的方式獲取的。ServierManager存儲(chǔ)了所有的binder引用,注冊(cè)的形式,AMS在啟動(dòng)的時(shí)候去注冊(cè)。
五、AMS通知APP進(jìn)程進(jìn)行各種生命周期操作
5.1 喚起APP初始化并拉起APP首屏
ActivityManagerService的attachApplication方法會(huì)收到APP傳遞過來的消息,然后交由attachApplicationLocked處理。
attachApplicationLocked中主要負(fù)責(zé)兩件事:
1.通知APP進(jìn)程進(jìn)行初始化操作;
2.進(jìn)行一些列操作,最終通知APP拉起指定的MainActivity。
說到這,問一個(gè)問題1,為什么明明是串行通知APP去執(zhí)行的,而APP那邊不會(huì)出現(xiàn)先加載Activity,再去初始化應(yīng)用的情況呢?答案在下一小節(jié)。
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
if (app.getIsolatedEntryPoint() != null) {
...
} else if (instr2 != null) {
//1通知APP進(jìn)行初始化操作
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass,
profilerInfo, instr2.mArguments,
instr2.mWatcher,
instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap);
} else {
...
同上
}
...
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
//拉起
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
...
return true;
}
5.2?APP進(jìn)行初始化操作
ActivityThread中ApplicationThread的bindApplication會(huì)收到通知,通過handler交給主線程去處理。所以我們也就知道上面問題1的答案了,無論是初始化APP,還是拉起Activity,都是最終交給Handler切換到主線程處理的。所以哪怕初始化APP是耗時(shí)操作,拉起Activity的任務(wù)也得排隊(duì)等到前面任務(wù)執(zhí)行完了才能執(zhí)行。
最終通過handler是交給handleBindApplciation去完成APP的初始化邏輯的。主要包含下面幾個(gè)操作:
1.使用classLoader去加載APK中的DEX文件。
2.加載APK中的資源。
3.反射生成Application類,并調(diào)用其attachBaseApplication方法。
4.調(diào)用Application的onCreate方法。
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
//1.classLoader加載APK中的dex,并且加載APK的資源
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// Continue loading instrumentation.
//2.生成代理類
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
Application app;
//3.聲明application
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
//4.調(diào)用Application的onCreate
mInstrumentation.onCreate(data.instrumentationArgs);
}
onCreate創(chuàng)建完成后并不會(huì)通知AMS,因?yàn)閍ctivity的拉起操作和初始化Application在AMS中是串行的。
5.3 AMS中處理Activity啟動(dòng)邏輯
5.1中講到attachApplicationLocked會(huì)最終通知APP去拉起Activity,那么整個(gè)流程是怎樣的呢?
會(huì)執(zhí)行下面這樣的調(diào)用順序。
ActivityManagerService.attachApplicationLocked->
ActivityTaskManagerService.LocalService.attachApplication->
RootWindowContainer.attachApplication->
RootWindowContainer.startActivityForAttachedApplicationIfNeeded->
ActivityTaskSupervisor.realStartActivityLocked
到了realStartActivityLocked這一步,正好對(duì)應(yīng)2.4所講的。APP進(jìn)程存在的也會(huì)調(diào)用這個(gè)方法,而不存在則先創(chuàng)建進(jìn)程,最終也會(huì)執(zhí)行到這一步。
realStartActivityLocked中創(chuàng)建Activity的生命周期事務(wù),最終通過ClientLifecycleManager.scheduleTransaction通過binder發(fā)送到APP進(jìn)程的ApplicationThread.scheduleTransaction方法中,則AMS流程就完成了。
5.4?APP完成Activity的啟動(dòng)
生命周期事務(wù)是安卓8.0之后出現(xiàn)的,簡(jiǎn)單來說就是之前的模式是:
AMS發(fā)一個(gè)協(xié)商好消息,APP收到后,根據(jù)消息內(nèi)存來決定自己去做操作;文章來源:http://www.zghlxwxcb.cn/news/detail-507886.html
而事務(wù)模式下,AMS發(fā)送一系列事務(wù)到APP進(jìn)程,APP收到后,直接去執(zhí)行這一系列的事務(wù)。而這些事務(wù)就是activity的生命周期調(diào)用。文章來源地址http://www.zghlxwxcb.cn/news/detail-507886.html
到了這里,關(guān)于android源碼學(xué)習(xí)- APP啟動(dòng)流程(android12源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!