ActivityStart
当手指点击了桌面的App图标时发生了什么 - ProcessOn
AIDL:
frameworks/base/core/java/android/app/IActivityManager.aidl ->
本地进程获取system_server进程中的AMS服务
frameworks/base/core/java/android/app/IApplicationThread.aidl ->
system_server进程调用本地进程ActivtyThread执行 (如LaunchActivityItem创建Activity与ResumeActivityItem走onResume生命周期) 事务发送Handler消息
0x01: 从activity.startActivity到onPuase()
1 | android.app.Activity#startActivity(android.content.Intent) |
————— 应用进程与system_server进程切换的分割线 —————-
切换到system_server进程,由于system_server是隐藏的,故难以debug
一、ActivityManagerService
1 | //以下为system_server中进行的AMS startActivity的流程 |
二、ActivityStarter
1 | //ActivityStarter.java |
三、ActivityStackSupervisor
1 | //ActivityStackSupervisor.java |
四、ActivityStack
1 | //ActivityStack.java |
小结:
从activity.startActivity()到Instrunmentaion中以Binder机制通过ActivityManager.getService().startActivity切换到system_server进程中的ActivityMangerService服务,再到ActivityMangerService中ActivityStarter、ActivityStatckSuperVisor、ActivityStack执行解析生成ActivityRecord(包含AMS、activityInfo、Configuration等信息),最后由ActivityStack通过binder将”pause事务”从AMS传递到应用进程,应用进程handler机制处理该事务,旧Activity pause成功。开始AMS启动新Activity。
1 | 至此的链路简述 |
至此,新Activity的ActivityRecord(AMS中的Activity信息,包括不限于ActivityInfo、ProcessRecord、Configuration,ActivityStackSupervisor、发起跳转的Activity的ActivityRecord和resultTo的ActivityRecord)创建解析完成,旧Activity的pause生命周期被调用执行(见附录ActivityStack#startPausingLocked),接下来就是通过AMS启动新的Activity
0x02: AMS启动新的Activity
1 | com.android.server.am.ActivityStackSupervisor#startSpecificActivityLocked (...) { |
一、startProcessLocked
简述:启动新的进程,即Zygote进程Process.start() fork出新的进程并反射调用其mian方法,走到ActivityThread.main,main方法中主要是初始化looper并启动循环,接着调用ActivityThread.attach()在该方法中初始化Application单例。接下来就是二、实质性启动Activity。
启动新进程承载新Activity,之后继续走realStartActivityLocked常见同进程Activity启动的流程
1 | com.android.server.am.ActivityManagerService#startProcessLocked(java.lang.String, android.content.pm.ApplicationInfo, boolean, int, java.lang.String, android.content.ComponentName, boolean, boolean, boolean) -> |
1、 Zygote 进程fork
Zygote 的fork 过程参考SystemService 的启动流程。Zygote fork 后也是通过反射的方法找到一个main 函数,这时候因为启动的是App 进程。所以这个main 函数为ActivityThread 的main函数。
- App发起进程:当从桌面启动应用,则发起进程便是Launcher所在进程;当从某App内启动远程进程,则发送进程便是该App所在进程。发起进程先通过binder发送消息给system_server进程;
- system_server进程:调用Process.start()方法,通过socket向zygote进程发送创建新进程的请求;
- zygote进程:在执行
ZygoteInit.main()
后便进入runSelectLoop()
循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后fork出新的应用进程; - 新进程:执行handleChildProc方法,最后调用ActivityThread.main()方法。
2、 fork 后的新进程的 ActivityThread
fork 以后启动ActivityThread 的main 函数,在Main 函数中完成Looper的初始化,最重要的一个调用就是 attach
1 | public static void main(String[] args) { |
AMS 的 attachApplication
1 | IActivityManager mgr = ActivityManager.getService(); |
AMS 的attachApplication 依次调用了ApplicationThread 的
- bindApplication // 创建Application
- scheduleTransaction(clientTransaction); // Resume Activity
1 | ActivityMangerService.class: |
realStartActivityLocked 见下
二、realStartActivityLocked
简述:实质性启动Activity,首先AMS推动包含Launch事务和Resume生命周期事务的ClientTransaction,App进程在ActivityThread的handler中接受并处理,调用handleLaunchActivity()->perfomLaunchActivity(),此方法中,首先反射创建了Activity对象,并调用了activity.attach(),之后执行onCreate。
1、创建添加activity事务并通过binder将事务交予应用进程执行
1 | //com.android.server.am.ActivityStackSupervisor#realStartActivityLocked |
————— system_server进程与应用进程切换的分割线 —————-
通过AIDL方式又回到应用进程了,调用了IApplicationThread.scheduleTransaction()
2、回到应用进程后ActivityThread执行事务创建Activity
ApplicationThread.class是 “AIDL接口—— IApplicationThread接口具体实现”,是ActivityThread的内部类,其定义了服务的远程过程调用 (RPC) 接口,即本地进程提供给其他进程通过IPC机制调用的接口:如更新进程状态updateProcessState,scheduleTransaction
System private API for communicating with the application. This is given to the activity manager by an application when it starts up, for the activity manager to tell the application about things it needs to do.
用于与应用程序通信的系统私有API。 这是应用程序在启动时给AMS的,以便AMS告诉应用程序它需要做的事情。
1 |
|
a. LaunchActivityItem/ResumeActivityItem preExecute/execute
1 | /* 见上 |
以启动activity的LaunchActivityItem.execute()中client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
为核心分析应用进程中ActivityThread中启动Activity的流程。
b. handleLaunchActivity()
1 | //ActivityThread.class |
003:Activity.Attach()
简述:首先初始化Window,具体实现类是PhoneWindow。为其设置WindowManger(具体实现类为WindowManagerImpl)
在Activity的attach方法中,很关键的一点就是初始化Window,从这里就能看到,Window的实现类,是PhoneWindow。PhoneWindow的创建对于我们后面的操作很重要。
mWindow是一个Window类型的变量,但实际上它是一个PhoneWindow对象,与Activity的内容显示相关。
1 | final void attach(Context context, ActivityThread aThread, |
004:Activity.onCreate()
简述:onCreate()->setContentView()->PhoneWindow.setContentView(),在这里初始化了最顶层View(FrameLayout)DecorView;并将layoutResID通过LayoutInflate填充后添加到DecorView中。
1 | public void setContentView(View view, ViewGroup.LayoutParams params) { |
005:ActivityThread.handleResumeActivity()
简述:
核心就是先调用onResume(),
然后再调用Window#addView(Window也就是上面activity.attach()中初始化的PhoneWindow)。接下来就是走到WindowManager(具体实现在WindowManagerGlobal中)的addView()。首先创建ViewRootImpl然后调用它的setView,setView中最关键的就是就是调用了requestLayout()然后注册Vsync回调回来后ViewRootImpl.performTraversals(),其中先执行了dispatchAttachToWindow(View.post的缓存action执行),后走了performMeasure、performLayout、performDraw测绘三大流程
performResumeActivity
Window#addView
new ViewRootImpl()
ViewRootImpl.setView()
ViewRootImpl.requestLayout()
ViewRootImpl.scheduleTraversals()
ViewRootImpl.doTraversal();
ViewRootImpl.performTraversals();
0xFF: 附录
附录一 execStartActivity
Android 6.0/9.0/10.0 Instrumentation#execStartActivity
1 | ... |
附录二 startPausingLocked
ActivityStack#startPausingLocked
1 | ActivityStack#startPausingLocked |
ActivityManager : Display
ActivityManager : Display / startActivity Android6/7
简单结论:display 只统计A onPause之后
AMS 启动新ActivityB 并 执行 B的onCreate、onstart、onresume 与 B向WMS注册窗口到编舞者发起的第一次测绘 完成
Activity的启动可以分为三个步骤,以ActivityA启动ActivityB为例,三步骤分别为:
以ActivityA调用startActivity,到ActivityA成功pause为止
displayTimeStart
ActivityB成功初始化,到执行完resume为止
ActivityB向WSM注册窗口,到第一帧绘制完成为止
displayTimeEnd
ActiivtyA Pause流程
当ActivityA使用startActivity方法启动ActivityB时,执行函数链路如下
1 | //Android 6.0/7.0 |
当App请求AMS要启动一个新页面的时候,AMS首先会pause掉当前正在显示的Activity,当然,这个Activity可能与请求要开启的Activity不在一个进程,比如点击桌面图标启动App,当前要暂停的Activity就是桌面程序Launcher。在onPause内执行耗时操作是一种很不推荐的做法,从上述调用链路可以看出,如果在onPause内执行了耗时操作,会直接影响到ActivityManagerNative.getDefault().activityPaused()方法的执行,而这个方法的作用就是通知AMS,“当前Activity已经已经成功暂停,可以启动新Activity了”。
ActivityB Launch流程
在AMS接收到App进程对于activityPaused方法的调用后,执行函数链路如下
1 | //ActivityStack.resumeTopActivityInnerLocked |
AMS在经过一系列方法调用后,通知App进程正式启动一个Actviity,注意如果要启动Activity所在进程不存在,比如点击桌面图标第一次打开应用,或者App本身就是多进程的,要启动的新页面处于另外一个进程,那就需要走到ActivityManagerService.startProcessLocked流程,等新进程启动完毕后再通知AMS,这里不展开。按照正常流程,会依次走过Activity生命周期内的onCreate、onRestoreInstanceState、onStart、onResume方法,这一步的耗时基本也可以看成就是这四个方法的耗时,由于这四个方法是同步调用的,所以可以通过以onCreate方法为起点,onResume方法为终点,统计出这一步骤的总耗时。
ActivityB Render流程
在ActivityB执行完onResume方法后,就可以显示该Activity了,调用流程如下
1 | WindowManager.addView-> |
这一步的核心实际上是Choreographer.postCallback,向Choreographer注册了一个回调,当Vsync事件到来时,就会执行下面的回调进行ui的渲染
1 | ViewRootImpl.doTraversal-> |
这里分别执行了performMeasure、performLayout、performDraw,实际上就是对应到DecorView的测量、布局、绘制三个流程。由于Android的UI是个树状结构,作为根View的DecorView的测量、布局、绘制,会调用到所有子View相应的方法,因此,这一步的总耗时就是所有子View在测量、布局、绘制中的耗时之和,如果某个子View在这三个方法中如果进行了耗时操作,就会拖慢整个UI的渲染,进而影响Activity第一帧的渲染速度。
从Window视角看ActivityStart
当从Window的角度看待Activity的启动过程时,可以看到以下流程:
在目标进程中,执行Activity.handleLaunchActivity方法,会先获取AMS服务,之后调用Activity.performLaunchActivity
回调目标Activity的onAttach方法,初始化Window及Window相关对象,如PhoneWindow、Token等。
mWindow = new PhoneWindow(this, window, activityConfigCallback);
之后回调目标Activity的onCreate方法,然后通过setContentView方法创建一个DecorView对象;
在目标进程中,执行Activity.handleResumeActivity方法,会回调目标Activity的onResume方法,然后调用目标Activity的makeVisible方法;在makeVisible方法中,会调用WindowManagerImpl.addView方法绘制View,并通过Binder远程调用WMS添加Window。
ViewManager wm = getWindowManager();wm.addView(mDecor, getWindow().getAttributes());
ActivityStart