天天看点

android R版本应用程序启动过程源码分析

        应用启动方式包括四种:Activity、Broadcast、Service、Provider四种安卓组件被唤醒和拉起时都可以造成进程启动。下面先主要以Activity启动为例来做个简要分析。

一、冷启动跳转新应用

1、 startActivity阶段       

        常见的Activity启动一般由startActivity发起,以桌面点击图库冷起为例,startActivity函数执行过程如下(冷启动执行reusedTask为空分支): 

android R版本应用程序启动过程源码分析

08-24 20:58:18.744  1982  7944 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.wtf.gallery3d/.app.MainActivity bnds=[48,1681][294,1992] (has extras)} from uid 10100

startActivity执行到系统侧时一般第一行日志输出的关键字是“START u”,u0代表要启动的页面是主用户0的,子用户就是u10、u11这种(子用户从10开始计算),该行日志还会打印发起请求的intent信息,表明所启动的组件目标,from uid代表发起startActivity的发起者的uid,可以根据命令adb shell ps -A|findstr u0_a100查询到uid是10100的进程是哪个,10100要转成u0_a100,a代表10000,如果是子用户进程就是u10_a100这种一次类推。

在打印START u日志之后,ATMS这块会查找复用栈,由于冷起,所以没有复用栈,此时会新建ActivityRecord、ActivityStack(R版本开始全屏、悬浮窗等非分屏场景的ActivityStack就是作为Task在使用,二者是同一个对象,ActivityStack继承Task),这一点从以下dump信息也可以看出来:

android R版本应用程序启动过程源码分析

创建完ActivityStack对象后会打印以下events日志,该日志表面栈id是3405:

08-24 20:58:18.759  1982  7944 I wm_stack_created: 3405

一个ActivityStack在构造时就会加到栈顶,此时并没有wm_focused_stack的events日志打印,因为创建完成后加到栈顶时传入的updateLastFocusedStackReason是null,不会造成events日志输出,而且即便紧接着还有一次moveToFront但由于栈顶对象还是刚才新创建的stack,所以也不会打印该events日志。

android R版本应用程序启动过程源码分析

在将ActivityStack作为一个Task对象后,会打印以下events日志:

08-24 20:58:18.763  1982  7944 I wm_create_task: [0,3405]

注意,虽然前面很早就新建了ActivityRecord,但是wm_create_activity这个events日志并不是构造ActivityRecord时打印的,而是在wm_create_task之后才打印出来:

08-24 20:58:18.763  1982  7944 I wm_create_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity,android.intent.action.MAIN,NULL,NULL,270532608]

在创建好各级数据结构并关联好上下级关系之后,才会真正去尝试resumeTopActivity去resume栈顶的ActivityRecord(此时栈顶就是要启动的图库应用),注意这个地方是尝试去resume,不代表真正能去resume成功,因为此时会判断是否有需要执行不可见的ActivityRecord要被pause,从桌面点击启动图库,显然需要把桌面pause掉,此时逻辑代码如下:

android R版本应用程序启动过程源码分析

该处有两个pause尝试,pauseBackStacks代表要去把display上的其他栈尝试计算可见性判别是否需要pause,比如桌面点击图库跳转不同栈时,就需要执行这一步把桌面栈pause掉;而紧接着的startPausingLocked判断条件要求当前要resume的stack具有mResumedActivity,也就是说当前栈在前台可见了,只是栈内部有activity跳转,也就是说应用内部进行跳转执行这个pause。这两个pause动作无论执行哪一个都会有以下日志输出,当然这个仅仅是系统侧的分发pause的日志,还没到app侧执行onPause:

08-24 20:58:18.765  1982  7944 I wm_pause_activity: [0,225436362,com.wtf.launcher/.Launcher,userLeaving=true]

在发起对上一个应用也就是桌面的pause操作时,判断要resume的next也就是图库页面是没有进程存在的,需要新启动一下进程,此时会异步执行图库的进程拉起,至此startActivity函数就执行完毕了,其实可以看出来,startActivity此时执行了个寂寞,仅仅发起了对上一个应用的pause(异步,所有的生命周期调度到应用侧的都是oneway异步不等待的,参见IApplicationThread类带有oneway标记)和启动要拉起的页面的进程(异步),除此之外,别无他物。

android R版本应用程序启动过程源码分析

刚才说到因为要启动图库,所以要把桌面栈pause,那么异步分发到桌面栈的进程ActivityThread上的pause消息会根据桌面主线程(四大组件的生命周期调度基本都是在主线程执行的,广播注册时使用了独立looper的handler时则是例外场景)的消息调度得到执行,最终执行完onPause生命周期,这个过程已经跟图库那边的进程启动没有关联了,除非桌面在onPause阶段执行了一些系统服务比如对ams的请求,才有可能造成跟图库进程启动竞争ams锁。此时会有桌面的pause日志,且该日志代表onPause执行完毕,日志如下:

08-24 20:58:18.778 11190 11190 I wm_on_paused_called: [225436362,com.wtf.launcher.Launcher,performPause]

2、activityPaused阶段

        在执行完每一个pause动作时,被pause的activity所在应用会执行服务端atms的activityPaused告知系统已经pause完成,atms服务会接下来再次尝试一下看看能否resumeTop成功,并把被pause完成的页面加到stopping列表,等待后续执行stop动作。activityPaused流程较为复杂,此处针对冷起场景走的是以下途图中“!next.attachedToProcess”分支,走到该分支会执行mStackSupervisor.startSpecificActivity,该函数是每个activity被冷起时(不等价于冷起进程,比如应用进程存在但启动了一个栈里不存在的新activity也叫做冷起)必经之路。该函数内部又分为两个分支:1)进程存在且已经attachApplication完毕,执行realStartActivityLocked去执行activity的冷启动;2)进程存在但还处于启动过程中未执行attachApplication的场景,或者进程不存在的冷起场景,执行mService.startProcessAsync去启动进程。走1)还是2)取决于startActivity阶段发起的mService.startProcessAsync启动进程和activityPaused的先后顺序,如果startActivity阶段启动进程先完成则activityPaused调度时执行1);若startActivity阶段启动进程后完成,则activityPaused调度时执行2),此时2)属于无用的重复执行,在执行过程中会检测到前一次发起进程启动的命令正在执行过程中,此时2)这次重复操作会直接返回。桌面冷起场景就属于执行2)的场景。在执行完2)之后,activityPaused后续动作就是把被pause完成的activity加到stopping列表中,events日志如下:

08-24 20:58:18.784  1982  7944 I wm_add_to_stopping: [0,225436362,com.wtf.launcher/.Launcher,makeInvisible]

当然,由于此时resumeTop执行的“!next.attachedToProcess”分支,不会触发ensureActivitiesVisible流程,所以依靠的是completePaused结束的那次ensure来触发makeInvisible并加到stopping列表。

android R版本应用程序启动过程源码分析

另外,可能存在有些app主线程卡顿导致activityPaused迟迟无法通知到系统,此时系统有个500ms保底操作,即系统每次发起pause操作时最多等待对端应用程序500ms,若对端无法在500ms内执行完onPause并通知系统,则会走超时机制强行执行activityPaused动作。

先附上activityPaused流程图,后面介绍热启复用栈和页面场景时继续分析流程。

android R版本应用程序启动过程源码分析

 3、startProcess阶段

         前面提到startActivity阶段会触发冷启动的应用启动进程,完整的startProcessAsync流程如下:

android R版本应用程序启动过程源码分析

启动进程过程中系统侧有几个关键的events和applogcat日志,首先看events日志,在创建好ProcessRecord对象(进程此时还没被启动,仅仅创建了ProcessRecord,其中的pid是0),会紧接着打印以下events日志,表明马上要向zygote发起进程启动,启动进程之前的准备工作已完成:

08-24 20:58:18.769  1982  2298 I am_uid_running: 10180

在打印完以上events日志后,会紧接着post一个异步消息到专门负责进程孵化的mProcStartHandler中,在该handler中向zygote发起start进程的命令,等待zygote返回孵化的进程pid后,会输出以下events日志和applogcat日志:

08-24 20:58:18.787  1982  2354 I am_proc_start: [0,31491,10180,com.wtf.gallery3d,pre-top-activity,{com.wtf.gallery3d/com.wtf.gallery3d.app.MainActivity}]

08-24 20:58:18.787  1982  2354 I ActivityManager: Start proc 31491:com.wtf.gallery3d/u0a180 for pre-top-activity {com.wtf.gallery3d/com.wtf.gallery3d.app.MainActivity}

至此进程孵化完毕,但是仅仅是表明进程的pid产生,ProcessRecord对象还未关联到应用端的ActivityThread。

在zygote孵化出进程时,被启动的应用进程的ActivityThread会执行main函数,流程如下:

android R版本应用程序启动过程源码分析

被拉起的图库进程在执行main函数时会通知到ams,并把应用进程的IApplicationThread传递给ams去关联绑定到ProcessRecord,作为后续系统到应用ActivityThread的aidl通信的媒介,关联绑定完成时会输出以下events日志:

08-24 20:58:18.810  1982  7944 I am_proc_bound: [0,31491,com.wtf.gallery3d]

在执行完绑定IApplicationThread到ProcessRecord后,系统侧会紧接着执行IApplicationThread.bindApplication通知图库的ActivityThread去执行绑定Application的动作(oneway非阻塞式通知),然后继续调度ATMS去执行图库activity的真正启动realStartActivityLocked。应用端bindApplication也是post消息到ActvityThread的主线程(前面讲过生命周期调度全是post消息到主线程去依次执行),消息处理时会依次执行:创建Application对象,创建Provider对象,执行provider的onCreate,执行Application的onCreate。当然provider装载还要通知ams侧进行记录provider,便于其他应用查找和使用该Provider,此处暂不赘述。

4、realStartActivity阶段

        在执行完startActivity、pause完上一个activity、目标activity所在进程启动完毕等步骤之后,atms要动真格得了,会执行realStartActivityLocked去把之前startActivity阶段放到栈顶的图库ActivityRecord执行拉起操作,具体流程图如下:

android R版本应用程序启动过程源码分析

冷起一个Activity时,会输出以下events日志:

08-24 20:58:18.815  1982  7944 I wm_restart_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity]

此处有个比较容易混淆的概念,activity的冷启动(非复用activity场景)系统侧会有wm_restart_activity的events日志,但是应用端却不会执行onRestart;只有后台stop过的的activity重新到前台resume的热启动场景才会有应用端的onRestart,但是该热启在系统侧有没有wm_restart_activity的过程。

输出wm_restart_activity日志后,系统侧会创建LaunchActivityItem和ResumeActivityItem异步通知到图库所在进程ActivityThread,让应用进程执行onCreate、onStart、onResume生命周期(系统侧其实只有Launch和Resume两个item,这两个代表onCreate和onResume,但是由于生命周期调度有个循环过程,必须经历onStart,所以会补齐执行onStart,详见TransactionExecutorHelper.getLifecyclePath函数逻辑),再发送完异步消息给ActivityThread后,系统侧在设置完ActivityRecord的resume状态后(注意此时仅仅是系统侧的ActivityRecord的状态变成了resume,并不代表应用端真正执行到了resume阶段)会打印输出以下events日志,冷起页面场景wm_set_resumed_activity的原因是minimalResumeActivityLocked:

08-24 20:58:18.818  1982  7944 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,minimalResumeActivityLocked]

系统侧分发异步的LaunchActivityItem和ResumeActivityItem消息给ActivityThread后,应用端继续在主线程中依次执行onCreate、onStart、onResume等生命周期,且输出以下events日志:

08-24 20:58:19.013 31491 31491 I wm_on_create_called: [14228247,com.wtf.gallery3d.app.MainActivity,performCreate]

08-24 20:58:19.040 31491 31491 I wm_on_start_called: [14228247,com.wtf.gallery3d.app.MainActivity,handleStartActivity]

08-24 20:58:19.054 31491 31491 I wm_on_resume_called: [14228247,com.wtf.gallery3d.app.MainActivity,RESUME_ACTIVITY]

wm_on_xxx_called的应用端events日志都是在相应的onXxx执行完之后才会打印。

应用端执行完onResume,会通知到系统侧去执行idle消息触发之前被pause的activity执行stop。

5、activityIdle阶段

        activityIdle由activity在应用端onResume完成之后在主线程bind通信到atms,其流程如下:

android R版本应用程序启动过程源码分析

该阶段系统侧会找到上一个pause完成并被加到stopping列表里的页面(即本文中的桌面)去真正发起stop动作,系统侧会先输出events日志表面即将异步发起stop命令给应用端ActivityThread:

08-24 20:58:19.323  1982  6072 I wm_stop_activity: [0,225436362,com.wtf.launcher/.Launcher]

应用端在主线程执行此消息,并最终执行activity的onStop函数,输出应用端events日志:

08-24 20:58:19.331 11190 11190 I wm_on_stop_called: [225436362,com.wtf.launcher.Launcher,STOP_ACTIVITY_ITEM]

当然,部分应用(微信)的某些页面执行完onResume是没有activityIdle到系统侧的,这种属于app自己的hook行为,代理了ActivityThread的主线程的消息队列,导致无法正常通知系统侧通过idle去stop上一个pause的页面,此类异常情况由以下流程得以保证(另外系统还有个10s强制idle的机制)。

android R版本应用程序启动过程源码分析

至此,冷启动一个应用程序的页面流程分析完毕。

附完整的events日志:

08-24 20:58:18.759  1982  7944 I wm_stack_created: 3405

08-24 20:58:18.763  1982  7944 I wm_create_task: [0,3405]

08-24 20:58:18.763  1982  7944 I wm_create_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity,android.intent.action.MAIN,NULL,NULL,270532608]

08-24 20:58:18.765  1982  7944 I wm_pause_activity: [0,225436362,com.wtf.launcher/.Launcher,userLeaving=true]

08-24 20:58:18.769  1982  2298 I am_uid_running: 10180

08-24 20:58:18.778 11190 11190 I wm_on_paused_called: [225436362,com.wtf.launcher.Launcher,performPause]

08-24 20:58:18.784  1982  7944 I wm_add_to_stopping: [0,225436362,com.wtf.launcher/.Launcher,makeInvisible]

08-24 20:58:18.787  1982  2354 I am_proc_start: [0,31491,10180,com.wtf.gallery3d,pre-top-activity,{com.wtf.gallery3d/com.wtf.gallery3d.app.MainActivity}]

08-24 20:58:18.810  1982  7944 I am_proc_bound: [0,31491,com.wtf.gallery3d]

08-24 20:58:18.815  1982  7944 I wm_restart_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity]

08-24 20:58:18.818  1982  7944 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,minimalResumeActivityLocked]

08-24 20:58:19.013 31491 31491 I wm_on_create_called: [14228247,com.wtf.gallery3d.app.MainActivity,performCreate]

08-24 20:58:19.040 31491 31491 I wm_on_start_called: [14228247,com.wtf.gallery3d.app.MainActivity,handleStartActivity]

08-24 20:58:19.054 31491 31491 I wm_on_resume_called: [14228247,com.wtf.gallery3d.app.MainActivity,RESUME_ACTIVITY]

08-24 20:58:19.323  1982  6072 I wm_stop_activity: [0,225436362,com.wtf.launcher/.Launcher]

08-24 20:58:19.331 11190 11190 I wm_on_stop_called: [225436362,com.wtf.launcher.Launcher,STOP_ACTIVITY_ITEM]

二、热启动跳转新应用

1、 startActivity阶段       

        仍然以桌面点击图库为例,不同的是此时图库栈本身已存在在后台,startActivity函数执行过程图示如前图(不同的是,热启动执行reusedTask非空分支)。只要发起startActivity都会打印START u日志,无论热起冷起。

08-24 21:03:01.022  1982  6193 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.wtf.gallery3d/.app.MainActivity bnds=[48,1681][294,1992] (has extras)} from uid 10100

在打印START u日志之后,会查找复用栈,此时找到了图库的复用栈,找到复用栈之后会将复用栈stack移到栈顶,输出以下events日志:

08-24 21:03:01.023  1982  6193 I wm_focused_stack: [0,0,3405,1,positionChildAtTop]

移完栈后设置焦点app,不同于冷起activity设置焦点是在resumeTop流程,此处设置焦点的原因是bringingFoundTaskToFront:

08-24 21:03:01.025  1982  6193 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,bringingFoundTaskToFront]

设置完焦点app,会继续输出一条task移到栈顶的日志,其实全屏栈Task和ActivityStack为同一对象,以下日志可以不用关注。

08-24 21:03:01.025  1982  6193 I wm_task_to_front: [0,3405]

执行完移栈、设置焦点动作之后,同样需要去尝试resumeTopActivity去resume栈顶的ActivityRecord(此时栈顶就是要启动的图库应用),由于此时图库是复用栈热启拉到前台,不需要启动进程,但是仍然需要去pause桌面,而且是跨栈pause场景:

08-24 21:03:01.026  1982  6193 I wm_pause_activity: [0,225436362,com.wtf.launcher/.Launcher,userLeaving=true]

发起pause桌面的命令后,startActivity函数执行完毕,同样也没有真的把图库resume起来,需要等待桌面的pause完成才能真正resume图库。

前面说到pause命令是异步通知到应用端,桌面主线程执行完此命令会输出以下events日志:

08-24 21:03:01.037 11190 11190 I wm_on_paused_called: [225436362,com.wtf.launcher.Launcher,performPause]

2、activityPaused阶段   

        桌面onPause执行完毕,同样也是执行activityPaused通知系统atms,atms服务会再次尝试一下看看能否resumeTop成功,此时resumeTop走的是next.attachedToProcess分支,因为是热启,本身栈已经启动过,这次只是从后台拉到前台,已经绑定进程,在该分支中先设置ActivityRecord的状态为RESUMED,进而引发焦点app的设置,且此次设置焦点app的原因是resumeTopActivityInnerLocked:

08-24 21:03:01.041  1982  6193 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,resumeTopActivityInnerLocked]

设置完焦点app,接着会执行ensureVisibilityAndConfig、ensureActivitiesVisible然后触发将pause完成的桌面页面加到stopping列表里(热启加到stopping列表不需要依赖completePauseLocked结束那次):

08-24 21:03:01.041  1982  6193 I wm_add_to_stopping: [0,225436362,com.wtf.launcher/.Launcher,makeInvisible]

执行完ensureVisibilityAndConfig后,会打印以下events日志去准备发起resume命令到应用端,构造ResumeActivityItem触发应用端去执行resume流程:

08-24 21:03:01.041  1982  6193 I wm_resume_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity]

3、resumeActivity阶段

        系统侧发送resume指令到应用端,此时应用端的生命周期处于onStop,从onStop到onResume,需要补齐onRestart、onStart、onResume(详见TransactionExecutorHelper.getLifecyclePath函数逻辑),并在执行完对应生命周期后输出events日志:

08-24 21:03:01.075 31491 31491 I wm_on_restart_called: [14228247,com.wtf.gallery3d.app.MainActivity,performRestartActivity]

08-24 21:03:01.082 31491 31491 I wm_on_start_called: [14228247,com.wtf.gallery3d.app.MainActivity,handleStartActivity]

08-24 21:03:01.083 31491 31491 I wm_on_resume_called: [14228247,com.wtf.gallery3d.app.MainActivity,RESUME_ACTIVITY]

4、activityIdle阶段

        activityIdle与前文冷起流程一模一样,都是先系统侧拿到stopping列表去发起stop命令到应用端,系统侧和应用端分别输出以下events日志:

08-24 21:03:01.313  1982  2298 I wm_stop_activity: [0,225436362,com.wtf.launcher/.Launcher]

08-24 21:03:01.328 11190 11190 I wm_on_stop_called: [225436362,com.wtf.launcher.Launcher,STOP_ACTIVITY_ITEM]

至此,热启动一个应用程序复用栈流程分析完毕。

附完整的events日志:

08-24 21:03:01.023  1982  6193 I wm_focused_stack: [0,0,3405,1,positionChildAtTop]

08-24 21:03:01.025  1982  6193 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,bringingFoundTaskToFront]

08-24 21:03:01.025  1982  6193 I wm_task_to_front: [0,3405]

08-24 21:03:01.026  1982  6193 I wm_pause_activity: [0,225436362,com.wtf.launcher/.Launcher,userLeaving=true]

08-24 21:03:01.037 11190 11190 I wm_on_paused_called: [225436362,com.wtf.launcher.Launcher,performPause]

08-24 21:03:01.041  1982  6193 I wm_set_resumed_activity: [0,com.wtf.gallery3d/.app.MainActivity,resumeTopActivityInnerLocked]

08-24 21:03:01.041  1982  6193 I wm_add_to_stopping: [0,225436362,com.wtf.launcher/.Launcher,makeInvisible]

08-24 21:03:01.041  1982  6193 I wm_resume_activity: [0,14228247,3405,com.wtf.gallery3d/.app.MainActivity]

08-24 21:03:01.075 31491 31491 I wm_on_restart_called: [14228247,com.wtf.gallery3d.app.MainActivity,performRestartActivity]

08-24 21:03:01.082 31491 31491 I wm_on_start_called: [14228247,com.wtf.gallery3d.app.MainActivity,handleStartActivity]

08-24 21:03:01.083 31491 31491 I wm_on_resume_called: [14228247,com.wtf.gallery3d.app.MainActivity,RESUME_ACTIVITY]

08-24 21:03:01.313  1982  2298 I wm_stop_activity: [0,225436362,com.wtf.launcher/.Launcher]

08-24 21:03:01.328 11190 11190 I wm_on_stop_called: [225436362,com.wtf.launcher.Launcher,STOP_ACTIVITY_ITEM]

至此冷起和热启复用栈这两个大的流程分析完毕!!!