App启动流程
系統的啟動過程
在學習APP的啟動之前先簡單了解下系統的啟動,有助于我們更好的學習APP的啟動。系統的啟動過程很復雜,這里簡單化,只關心大致流程和涉及到的一些名詞以及相關類的作用
APP的啟動可以簡單總結為一下幾個流程:
加載BootLoader --> 初始化內核 --> 啟動init進程 --> init進程fork出Zygote進程 --> Zygote進程fork出SystemServer進程
- 系統中的所有經常進程都是由Zygote進程fork出來的
- SystemServer進程是系統進程,很多系統服務,例如ActivityManagerService、PackageManagerService、WindowManagerService…都是存在該進程被創建后啟動
- ActivityManagerServices(AMS):是一個服務端對象,負責所有的Activity的生命周期,AMS通過Binder與Activity通信,而AMS與Zygote之間是通過Socket通信
- ActivityThread:本篇的主角,UI線程/主線程,它的main()方法是APP的真正入口
- ApplicationThread:一個實現了IBinder接口的ActivityThread內部類,用于ActivityThread和AMS的所在進程間通信
- Instrumentation:可以理解為ActivityThread的一個工具類,在ActivityThread中初始化,一個進程只存在一個Instrumentation對象,在每個Activity初始化時,會通過Activity的Attach方法,將該引用傳遞給Activity。Activity所有生命周期的方法都有該類來執行
APP的啟動過程
APP的啟動,我們使用一張圖來說明這個啟動過程,順便也總結下上面所說的ActivityThread的main方法執行到Activity的創建之間的流程。圖是從網上盜的…
APP啟動過程的部分代碼思考
在上面學習APP的啟動過程中,看源碼的同時注意到一個代碼,就是主線程Handler在接收到LAUNCH_ACTIVITY創建Activity的消息后,創建Activity的部分代碼如下:
主線程Handler接收到創建Activity的消息LAUNCH_ACTIVITY后,最終會調用performLaunchActivity方法performLaunchActivity方法會通過反射去創建一個Activity,然后會調用Activity的各個生命周期方法private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...ContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {這里是反射創建Activityjava.lang.ClassLoader cl = appContext.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state != null) {r.state.setClassLoader(cl);}}try {這里注意,又調用了一次Application的創建方法,但是前面分析過,Application是個單例,所以這里的實際上是獲取Application實例,但是這里為什么會再次調用創建Application的方法呢?Application app = r.packageInfo.makeApplication(false, mInstrumentation);...} ...return activity;}在上面的代碼中,簡單注釋了一下在Activity的創建方法中,會再次調用Application的創建方法(第一次調用是在接收到BIND_APPLICATION消息的時候),個人覺得這里再次調用Application的創建方法,除了獲取已經存在的Application實例這種情況,另外一種情況還有可能是要創建的這個Activity屬于另外一個進程,當去啟動這個新進程中的Activity時,會先去創建新進程和Application實例,因為我們知道一個常識:
那么這兩點的關系就是,因為新進程中Application實例會為空,所以會再次去創建Application實例,這也就是第一點中我們所說的常識:APP中有幾個進程,Application會被創建幾次
創建Application的方法public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {如果存在Application的實例,則直接返回,這也說明Application是個單例if (mApplication != null) {return mApplication;}Application app = null;...創建Applicationreturn app;}那么依次類推,Service作為四大組件之一,類似于Activity的創建和啟動,創建Service的方法中會不會也調用了創建Application的方法(makeApplication方法),答案是肯定的!和Activity的創建類似,當我們調用startService的時候,也是通過Binder向AMS發送創建Service的請求,AMS準備后再向APP進程發送scheduleCreateService的請求,然后主線程handle收到CREATE_SERVICE的消息,調用handleCreateService創建Service的方法。在創建Service的方法handleCreateService中也調用了創建Application的方法,具體代碼看源碼吧。所以我們也徹底明白了為什么APP中有幾個進程,Application會被創建幾次,以及Application為什么是個單例。
源碼解析:
可以把Android系統想象成一個幼兒園,里面有一個老師,一個班長,一個班干部,以及一大堆小朋友。
-
一個老師:Z老師(Zygote進程)
-
一個班長:小A(ActivityManagerService)
-
一個班干部:小L(Launcher桌面應用)
-
一大堆小朋友:所有應用,包括音樂小朋友,聊天小朋友,日歷小朋友等等。
?
?
應用啟動過程就像一個小朋友被叫醒一樣,開機之后呢,Z老師會依次叫醒班長和班干(SystemServer#ActivityManagerService,Launcher),小L醒了之后就會去了解手表里有哪些小朋友,長什么樣(icon,name),家庭信息(包名,androidmanifest)等等,然后一個個把小朋友的照片(icon)貼到自己的身上。比如有音樂小朋友,聊天小朋友,日歷小朋友,其實也就是你手表上這個桌面啦。
這時候你要點開一個音樂小朋友呢(startActivity),小L就會通知班長小A(Binder),小A知道了之后,讓小L自己休息下(Paused),然后就去找Z老師了。Z老師就負責叫音樂小朋友起床了(fork進程,啟動ActivityThread),音樂小朋友起來后就又找小A帶她去洗臉刷牙(啟動ApplicationThread,Activity),都弄完了就可以進行各種表演了,唱歌啊,跳舞啊。
Android系統就像一個幼兒園,有一個大朋友叫Launcher,身上會貼很多其他小朋友的名片。這個Launcher就是我們的桌面了,它通過PackageManagerService獲知了系統里所有應用的信息,并展示了出來,當然它本身也是一個應用。
通過點擊一個應用圖標,也就是觸發了點擊事件,最后會執行到startActivity方法。這里也就和啟動Activity步驟重合上了。那么這個startActivity干了啥?是怎么通過重重關卡喚醒這個應用的?
首先,介紹下系統中那些重要的成員,他們在app啟動流程中都擔任了重要的角色.
系統成員介紹
-
init進程,Android系統啟動后,Zygote并不是第一個進程,而是linux的根進程init進程,然后init進程才會啟動Zygote進程。
-
Zygote進程,所有android進程的父進程,當然也包括SystemServer進程
-
SystemServer進程,正如名字一樣,系統服務進程,負責系統中大大小小的事物,為此也是啟動了三員大將(ActivityManagerService,PackageManagerService,WindowManagerService)以及binder線程池。
-
ActivityManagerService,主要負責系統中四大組件的啟動、切換、調度及應用進程的管理和調度等工作,對于一些進程的啟動,都會通過Binder通信機制傳遞給AMS,再處理給Zygote。
-
PackageManagerService,主要負責應用包的一些操作,比如安裝,卸載,解析AndroidManifest.xml,掃描文件信息等等。
-
WindowManagerService,主要負責窗口相關的一些服務,比如窗口的啟動,添加,刪除等。
-
Launcher,桌面應用,也是屬于應用,也有自己的Activity,一開機就會默認啟動,通過設置Intent.CATEGORY_HOME的Category隱式啟動。
搞清楚這些成員,就跟隨我一起看看怎么過五關斬六將,最終啟動了一個App。
第一關:跨進程通信,告訴系統我的需求
首先,要告訴系統,我Launcher要啟動一個應用了,調用Activity.startActivityForResult方法,最終會轉到mInstrumentation.execStartActivity方法。 由于Launcher自己處在一個單獨的進程,所以它需要跨進程告訴系統服務我要啟動App的需求。 找到要通知的Service,名叫ActivityTaskManagerService,然后使用AIDL,通過Binder與他進行通信。
這里的簡單說下ActivityTaskManagerService(簡稱ATMS)。原來這些通信工作都是屬于ActivityManagerService,現在分了一部分工作給到ATMS,主要包括四大組件的調度工作。也是由SystemServer進程直接啟動的,相關源碼可見ActivityManagerService.Lifecycle.startService方法,感興趣朋友可以自己看看。
接著說跨進程通信,相關代碼如下:
//Instrumentation.javaint result = ActivityTaskManager.getService().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);//ActivityTaskManager.java public static IActivityTaskManager getService() {return IActivityTaskManagerSingleton.get();}private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =new Singleton<IActivityTaskManager>() {@Overrideprotected IActivityTaskManager create() {final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);return IActivityTaskManager.Stub.asInterface(b);}};//ActivityTaskManagerService.javapublic class ActivityTaskManagerService extends IActivityTaskManager.Stubpublic static final class Lifecycle extends SystemService {private final ActivityTaskManagerService mService;public Lifecycle(Context context) {super(context);mService = new ActivityTaskManagerService(context);}@Overridepublic void onStart() {publishBinderService(Context.ACTIVITY_TASK_SERVICE, mService);mService.start();}}startActivity我們都很熟悉,平時啟動Activity都會使用,啟動應用也是從這個方法開始的,也會同樣帶上intent信息,表示要啟動的是哪個Activity。
另外要注意的一點是,startActivity之后有個checkStartActivityResult方法,這個方法是用作檢查啟動Activity的結果。當啟動Activity失敗的時候,就會通過這個方法拋出異常,比如有我們常見的問題:未在AndroidManifest.xml注冊。
public static void checkStartActivityResult(int res, Object intent) {switch (res) {case ActivityManager.START_INTENT_NOT_RESOLVED:case ActivityManager.START_CLASS_NOT_FOUND:if (intent instanceof Intent && ((Intent)intent).getComponent() != null)throw new ActivityNotFoundException("Unable to find explicit activity class "+ ((Intent)intent).getComponent().toShortString()+ "; have you declared this activity in your AndroidManifest.xml?");throw new ActivityNotFoundException("No Activity found to handle " + intent);case ActivityManager.START_PERMISSION_DENIED:throw new SecurityException("Not allowed to start activity "+ intent);case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:throw new AndroidRuntimeException("FORWARD_RESULT_FLAG used while also requesting a result");case ActivityManager.START_NOT_ACTIVITY:throw new IllegalArgumentException("PendingIntent is not an activity");//...}}第二關:通知Launcher可以休息了
ATMS收到要啟動的消息后,就會通知上一個應用,也就是Launcher可以休息會了,進入Paused狀態。
//ActivityStack.javaprivate boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {//...ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);//...boolean pausing = getDisplay().pauseBackStacks(userLeaving, next, false);if (mResumedActivity != null) {if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Pausing " + mResumedActivity);pausing |= startPausingLocked(userLeaving, false, next, false);}//...if (next.attachedToProcess()) {//應用已經啟動try {//...transaction.setLifecycleStateRequest(ResumeActivityItem.obtain(next.app.getReportedProcState(),getDisplay().mDisplayContent.isNextTransitionForward()));mService.getLifecycleManager().scheduleTransaction(transaction);//...} catch (Exception e) {//...mStackSupervisor.startSpecificActivityLocked(next, true, false);return true;}//...// From this point on, if something goes wrong there is no way// to recover the activity.try {next.completeResumeLocked();} catch (Exception e) {// If any exception gets thrown, toss away this// activity and try the next one.Slog.w(TAG, "Exception thrown during resume of " + next, e);requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,"resume-exception", true);return true;}} else {//冷啟動流程mStackSupervisor.startSpecificActivityLocked(next, true, true);} }這里有兩個類沒有見過:
- ActivityStack,是Activity的棧管理,相當于我們平時項目里面自己寫的Activity管理類,用于管理Activity的狀態啊,如棧出棧順序等等。
- ActivityRecord,代表具體的某一個Activity,存放了該Activity的各種信息。
startPausingLocked方法就是讓上一個應用,這里也就是Launcher進入Paused狀態。 然后就會判斷應用是否啟動,如果已經啟動了,就會走ResumeActivityItem的方法,看這個名字,結合應用已經啟動的前提,是不是已經猜到了它是干嗎的?沒錯,這個就是用來控制Activity的onResume生命周期方法的,不僅是onResume還有onStart方法,具體可見ActivityThread的handleResumeActivity方法源碼。
如果應用沒啟動就會接著走到startSpecificActivityLocked方法,接著看。
第三關:是否已啟動進程,否則創建進程
Launcher進入Paused之后,ActivityTaskManagerService就會判斷要打開的這個應用進程是否已經啟動,如果已經啟動,則直接啟動Activity即可,這也就是應用內的啟動Activity流程。如果進程沒有啟動,則需要創建進程。
這里有兩個問題:
- 怎么判斷應用進程是否存在呢?如果一個應用已經啟動了,會在ATMS里面保存一個WindowProcessController信息,這個信息包括processName和uid,uid則是應用程序的id,可以通過applicationInfo.uid獲取。processName則是進程名,一般為程序包名。所以判斷是否存在應用進程,則是根據processName和uid去判斷是否有對應的WindowProcessController,并且WindowProcessController里面的線程不為空。代碼如下:
- 還有個問題就是怎么創建進程?還記得Z老師嗎?對,就是Zygote進程。之前說了他是所有進程的父進程,所以就要通知Zygote去fork一個新的進程,服務于這個應用。
可以看到,這里其實是通過socket和Zygote進行通信,BufferedWriter用于讀取和接收消息。這里將要新建進程的消息傳遞給Zygote,由Zygote進行fork進程,并返回新進程的pid。
可能又會有人問了?fork是啥?為啥這里又變成socket進行IPC通信,而不是Bindler了?
- 首先,fork()是一個方法,是類Unix操作系統上創建進程的主要方法。用于創建子進程(等同于當前進程的副本)。
- 那為什么fork的時候不用Binder而用socket了呢?主要是因為fork不允許存在多線程,Binder通訊偏偏就是多線程。
問題總是在不斷產生,總有好奇的朋友會接著問,為什么fork不允許存在多線程?
- 防止死鎖。其實你想想,多線程+多進程,聽起就不咋靠譜是不。假設多線程里面線程A對某個鎖lock,另外一個線程B調用fork創建了子進程,但是子進程卻沒有了線程A,但是鎖本身卻被fork了出來,那么這個鎖沒人可以打開了。一旦子進程中另外的線程又對這個鎖進行lock,就死鎖了。
第四關:ActivityThread閃亮登場
剛才說到由Zygote進行fork進程,并返回新進程的pid。其實這過程中也實例化ActivityThread對象。一起看看是怎么實現的:
//RuntimeInit.javaprotected 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);}//...return new MethodAndArgsCaller(m, argv);}原來是反射!通過反射調用了ActivityThread 的 main 方法。ActivityThread大家應該都很熟悉了,代表了Android的主線程,而main方法也是app的主入口。這不對上了!新建進程的時候就調用了,可不是主入口嘛。來看看這個主入口。
public static void main(String[] args) {//...Looper.prepareMainLooper();ActivityThread thread = new ActivityThread();thread.attach(false, startSeq);//...if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}//...Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}main方法主要創建了ActivityThread,創建了主線程的Looper對象,并開始loop循環。除了這些,還要告訴AMS,我醒啦,進程創建好了!也就是上述代碼中的attach方法,最后會轉到AMSattachApplicationLocked方法,一起看看這個方法干了啥:
//ActivitymanagerService.javaprivate final boolean attachApplicationLocked(IApplicationThread thread,int pid, int callingUid, long startSeq) {//...ProcessRecord app;//...thread.bindApplication(processName, appInfo, providers, null, profilerInfo,null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.isPersistent(),new Configuration(app.getWindowProcessController().getConfiguration()),app.compat, getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial, autofillOptions, contentCaptureOptions);//...app.makeActive(thread, mProcessStats);//...// 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;}}//... }//ProcessRecord.javapublic void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {//...thread = _thread;mWindowProcessController.setThread(thread);}這里主要做了三件事:
- bindApplication方法,主要用來啟動Application。
- makeActive方法,設定WindowProcessController里面的線程,也就是上文中說過判斷進程是否存在所用到的。
- attachApplication方法,啟動根Activity。
第五關:創建Application
接著上面看,按照我們所熟知的,應用啟動后,應該就是啟動Applicaiton,啟動Activity。看看是不是怎么回事:
//ActivityThread#ApplicationThreadpublic final void bindApplication(String processName, ApplicationInfo appInfo,List<ProviderInfo> providers, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableBinderTracking, boolean trackAllocation,boolean isRestrictedBackupMode, boolean persistent, Configuration config,CompatibilityInfo compatInfo, Map services, Bundle coreSettings,String buildSerial, AutofillOptions autofillOptions,ContentCaptureOptions contentCaptureOptions) {AppBindData data = new AppBindData();data.processName = processName;data.appInfo = appInfo;data.providers = providers;data.instrumentationName = instrumentationName;data.instrumentationArgs = instrumentationArgs;data.instrumentationWatcher = instrumentationWatcher;data.instrumentationUiAutomationConnection = instrumentationUiConnection;data.debugMode = debugMode;data.enableBinderTracking = enableBinderTracking;data.trackAllocation = trackAllocation;data.restrictedBackupMode = isRestrictedBackupMode;data.persistent = persistent;data.config = config;data.compatInfo = compatInfo;data.initProfilerInfo = profilerInfo;data.buildSerial = buildSerial;data.autofillOptions = autofillOptions;data.contentCaptureOptions = contentCaptureOptions;sendMessage(H.BIND_APPLICATION, data);}public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));switch (msg.what) {case BIND_APPLICATION:Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");AppBindData data = (AppBindData)msg.obj;handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);break;}}可以看到這里有個H,H是主線程的一個Handler類,用于處理需要主線程處理的各類消息,包括BIND_SERVICE,LOW_MEMORY,DUMP_HEAP等等。接著看handleBindApplication:
private void handleBindApplication(AppBindData data) {//...try {final ClassLoader cl = instrContext.getClassLoader();mInstrumentation = (Instrumentation)cl.loadClass(data.instrumentationName.getClassName()).newInstance();}//...Application app;final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();try {// If the app is being launched for full backup or restore, bring it up in// a restricted environment with the base application class.app = data.info.makeApplication(data.restrictedBackupMode, null);mInitialApplication = app;// don't bring up providers in restricted mode; they may depend on the// app's custom Application classif (!data.restrictedBackupMode) {if (!ArrayUtils.isEmpty(data.providers)) {installContentProviders(app, data.providers);}}// Do this after providers, since instrumentation tests generally start their// test thread at this point, and we don't want that racing.try {mInstrumentation.onCreate(data.instrumentationArgs);}//...try {mInstrumentation.callApplicationOnCreate(app);} catch (Exception e) {if (!mInstrumentation.onException(app, e)) {throw new RuntimeException("Unable to create application " + app.getClass().getName()+ ": " + e.toString(), e);}}}//...}這里信息量就多了,一點點的看:
- 首先,創建了Instrumentation,也就是上文一開始startActivity的第一步。每個應用程序都有一個Instrumentation,用于管理這個進程,比如要創建Activity的時候,首先就會執行到這個類里面。
- makeApplication方法,創建了Application,終于到這一步了。最終會走到newApplication方法,執行Application的attach方法。
attach方法有了,onCreate方法又是何時調用的呢?馬上來了:
instrumentation.callApplicationOnCreate(app);public void callApplicationOnCreate(Application app) {app.onCreate();}也就是創建Application->attach->onCreate調用順序。
等等,在onCreate之前還有一句重要的代碼:
installContentProviders這里就是啟動Provider的相關代碼了,具體邏輯就不分析了。
第六關:啟動Activity
說完bindApplication,該說說后續了,上文第五關說到,bindApplication方法之后執行的是attachApplication方法,最終會執行到ActivityThread的handleLaunchActivity方法:
public Activity handleLaunchActivity(ActivityClientRecord r,PendingTransactionActions pendingActions, Intent customIntent) {//...WindowManagerGlobal.initialize();//...final Activity a = performLaunchActivity(r, customIntent);//...return a;}首先,初始化了WindowManagerGlobal,這是個啥呢? 沒錯,就是WindowManagerService了,也為后續窗口顯示等作了準備。
繼續看performLaunchActivity:
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//創建ContextImplContextImpl appContext = createBaseContextForActivity(r);Activity activity = null;try {java.lang.ClassLoader cl = appContext.getClassLoader();//創建Activityactivity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);}try {if (activity != null) {//完成activity的一些重要數據的初始化activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window, r.configCallback,r.assistToken);if (customIntent != null) {activity.mIntent = customIntent;}//設置activity的主題int theme = r.activityInfo.getThemeResource();if (theme != 0) {activity.setTheme(theme);}//調用activity的onCreate方法if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}}}return activity;}哇,終于看到onCreate方法了。穩住,還是一步步看看這段代碼。
首先,創建了ContextImpl對象,ContextImpl可能有的朋友不知道是啥,ContextImpl繼承自Context,其實就是我們平時用的上下文。有的同學可能表示,這不對啊,獲取上下文明明獲取的是Context對象。來一起跟隨源碼看看。
//Activity.javaContext mBase;@Overridepublic Executor getMainExecutor() {return mBase.getMainExecutor();}@Overridepublic Context getApplicationContext() {return mBase.getApplicationContext();}這里可以看到,我們平時用的上下文就是這個mBase,那么找到這個mBase是啥就行了:
protected void attachBaseContext(Context base) {if (mBase != null) {throw new IllegalStateException("Base context already set");}mBase = base;}//一層層往上找final void attach(Context context, ActivityThread aThread,Instrumentation instr, IBinder token, int ident,Application application, Intent intent, ActivityInfo info,CharSequence title, Activity parent, String id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor) {attachBaseContext(context);mWindow = new PhoneWindow(this, window, activityConfigCallback);mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {mWindow.setSoftInputMode(info.softInputMode);}}這不就是,,,剛才一開始performLaunchActivity方法里面的attach嗎?太巧了,所以這個ContextImpl就是我們平時所用的上下文。
順便看看attach還干了啥?新建了PhoneWindow,建立自己和Window的關聯,并設置了setSoftInputMode等等。
ContextImpl創建完之后,會通過類加載器創建Activity的對象,然后設置好activity的主題,最后調用了activity的onCreate方法。
總結
再一起捋一遍App的啟動流程:
- Launcher被調用點擊事件,轉到Instrumentation類的startActivity方法。
- Instrumentation通過跨進程通信告訴AMS要啟動應用的需求。
- AMS反饋Launcher,讓Launcher進入Paused狀態
- Launcher進入Paused狀態,AMS轉到ZygoteProcess類,并通過socket與Zygote通信,告知Zygote需要新建進程。
- Zygote fork進程,并調用ActivityThread的main方法,也就是app的入口。
- ActivityThread的main方法新建了ActivityThread實例,并新建了Looper實例,開始loop循環。
- 同時ActivityThread也告知AMS,進程創建完畢,開始創建Application,Provider,并調用Applicaiton的attach,onCreate方法。
- 最后就是創建上下文,通過類加載器加載Activity,調用Activity的onCreate方法。
至此,應用啟動完畢。
當然,分析源碼的目的一直都不是為了學知識而學,而是理解了這些基礎,我們才能更好的解決問題。 學習了App的啟動流程,我們可以再思考下一些之前沒理解透的問題,比如啟動優化。
分析啟動過程,其實可以優化啟動速度的地方有三個地方:
- Application的attach方法,MultiDexApplication會在方法里面會去執行MultiDex邏輯。所以這里可以進行MultiDex優化,比如今日頭條方案就是單獨啟動一個進程的activity去加載MultiDex。
- Application的onCreate方法,大量三方庫的初始化都在這里進行,所以我們可以開啟線程池,懶加載等等。把每個啟動任務進行區分,哪些可以子線程運行,哪些有先后順序。
- Activity的onCreate方法,同樣進行線程處理,懶加載。或者預創建Activity,提前類加載等等。
?
?
轉載:https://juejin.im/post/6867744083809419277
? ? ? ? ??https://blog.csdn.net/hzwailll/article/details/85339714
?
?
總結
- 上一篇: fcpx插件Stupid Raisins
- 下一篇: QualNet收发包过程分析(一)