Android 应用启动全流程分析(源码深度剖析 + Systrace 展示)
Posted 涂程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 应用启动全流程分析(源码深度剖析 + Systrace 展示)相关的知识,希望对你有一定的参考价值。
作者:努比亚技术团队
1.前言
从用户手指点击桌面上的应用图标到屏幕上显示出应用主Activity界面而完成应用启动,快的话往往都不需要一秒钟,但是这整个过程却是十分复杂的,其中涉及了android系统的几乎所有核心知识点。同时应用的启动速度也绝对是系统的核心用户体验指标之一,多少年来,无论是谷歌或是手机系统厂商们还是各个Android应用开发者,都在为实现应用打开速度更快一点的目标而不断努力。但是要想真正做好应用启动速度优化这件事情,我想是必须要对应用启动的整个流程有充分的认识和理解的,所以无论作为Android系统或应用开发者,都有必要好好的学习和了解一下这个过程的。网上有很多介绍应用启动流程源码的文章,但是总感觉大多数都不太全面,很多只是介绍了应用启动过程中的部分流程,而没有总体清晰的认识应用启动过程的总体脉络与系统架构设计思想。所以本文将结合笔者多年来的工作经历,结合systrace分析工具,基于最新Android R AOSP源码完整的分析一下这个从用户手指触控点击屏幕应用图标到应用界面展示到屏幕上的整个应用启动过程,也是对之前所做所学的一个总结与归纳。
2.大纲
-
Android触控事件处理机制
-
Zygote进程启动和应用进程创建流程
-
Handler消息机制
-
AMS的Activity组件管理
-
应用Application和Activity组件创建与初始化
-
应用UI布局与绘制
-
RenderThread渲染
-
SurfaceFlinger合成显示
-
写在最后
-
参考
3. Input触控事件处理流程
3.1 系统机制分析
Android
系统是由事件驱动的,而 input
是最常见的事件之一,用户的点击、滑动、长按等操作,都属于 input
事件驱动,其中的核心就是 InputReader
和 InputDispatcher
。InputReader
和 InputDispatcher
是跑在 SystemServer
进程中的两个 native
循环线程,负责读取和分发 Input
事件。整个处理过程大致流程如下:
InputReader
负责从EventHub
里面把Input
事件读取出来,然后交给InputDispatcher
进行事件分发;InputDispatcher
在拿到InputReader
获取的事件之后,对事件进行包装后,寻找并分发到目标窗口;InboundQueue
队列(“iq”)中放着InputDispatcher
从InputReader
中拿到的input
事件;OutboundQueue
(“oq”)队列里面放的是即将要被派发给各个目标窗口App的事件;WaitQueue
队列里面记录的是已经派发给App
(“wq”),但是App
还在处理没有返回处理成功的事件;PendingInputEventQueue
队列(“aq”)中记录的是应用需要处理的Input
事件,这里可以看到input
事件已经传递到了应用进程;deliverInputEvent
标识App
UI Thread
被Input
事件唤醒;InputResponse
标识Input
事件区域,这里可以看到一个Input_Down
事件 + 若干个Input_Move
事件 + 一个Input_Up
事件的处理阶段都被算到了这里;App
响应处理Input
事件,内部会在其界面View
树中传递处理。
用一张图描述整个过程大致如下:
3.2 结合Systrace分析
从桌面点击应用图标启动应用,system_server
的native
线程InputReader
首先负责从EventHub
中利用linux
的epolle
机制监听并从屏幕驱动读取上报的触控事件,然后唤醒另外一条native线程InputDispatcher
负责进行进一步事件分发。InputDispatcher
中会先将事件放到InboundQueue
也就是“iq”队列中,然后寻找具体处理input
事件的目标应用窗口,并将事件放入对应的目标窗口OutboundQueue
也就是“oq”队列中等待通过SocketPair
双工信道发送到应用目标窗口中。最后当事件发送给具体的应用目标窗口后,会将事件移动到WaitQueue
也就是“wq”中等待目标应用处理事件完成,并开启倒计时,如果目标应用窗口在5S内没有处理完成此次触控事件,就会向system_server
报应用ANR异常事件。以上整个过程在Android
系统源码中都加有相应的systrace tag,如下systrace截图所示:
接着上面的流程继续往下分析:当input
触控事件传递到桌面应用进程后,Input
事件到来后先通过enqueueInputEvent
函数放入“aq”本地待处理队列中,并唤醒应用的UI线程在deliverInputEvent
的流程中进行input
事件的具体分发与处理。具体会先交给在应用界面Window
创建时的ViewRootImpl#setView
流程中创建的多个不同类型的InputStage
中依次进行处理(比如对输入法处理逻辑的封装ImeInputStage
),整个处理流程是按照责任链的设计模式进行。最后会交给ViewPostImeInputStage
中具体进行处理,这里面会从View
布局树的根节点DecorView
开始遍历整个View
树上的每一个子View
或ViewGroup
界面进行事件的分发、拦截、处理的逻辑。最后触控事件处理完成后会调用finishInputEvent
结束应用对触控事件处理逻辑,这里面会通过JNI
调用到native
层InputConsumer
的sendFinishedSignal
函数通知InputDispatcher
事件处理完成,从触发从"wq"队列中及时移除待处理事件以免报ANR
异常。
桌面应用界面View中在连续处理一个ACTION_DOWN
的TouchEvent
触控事件和多个ACTION_MOVE
,直到最后出现一个ACTION_UP
的TouchEvent
事件后,判断属于onClick
点击事件,然后透过ActivityManager
Binder
调用AMS
的startActivity
服务接口触发启动应用的逻辑。从systrace上看如下图所示:
4. 应用进程的创建与启动
4.1 Pause桌面应用
接着上一节继续往下看,桌面进程收到input触控事件并处理后binder
调用框架AMS
的的startActivity
接口启动应用,相关简化代码如下:
/*frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java*/
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants)
...
try
...
// 添加“startActivityInner”的systrace tag
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
// 执行startActivityInner启动应用的逻辑
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);
finally
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
...
...
在执行startActivityInner
启动应用逻辑中,AMS
中的Activity
栈管理的逻辑,检查发现当前处于前台Resume
状态的Activity
是桌面应用,所以第一步需要通知桌面应用的Activity
进入Paused
状态,相关简化代码逻辑如下:
/*frameworks/base/services/core/java/com/android/server/wm/ActivityStack.java*/
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options)
...
// mResumedActivity不为null,说明当前存在处于resume状态的Activity且不是新需要启动的应用
if (mResumedActivity != null)
// 执行startPausingLocked通知桌面应用进入paused状态
pausing |= startPausingLocked(userLeaving, false /* uiSleeping */, next);
...
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming)
...
ActivityRecord prev = mResumedActivity;
...
if (prev.attachedToProcess())
try
...
// 相关执行动作封装事务,binder通知mResumedActivity也就是桌面执行pause动作
mAtmService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
prev.appToken, PauseActivityItem.obtain(prev.finishing, userLeaving,
prev.configChangeFlags, pauseImmediately));
catch (Exception e)
...
...
桌面应用进程这边执行收到pause
消息后执行Activity
的onPause
生命周期,并在执行完成后,会binder
调用AMS
的activityPaused
接口通知系统执行完activity
的pause
动作,相关代码如下:
/*frameworks/base/core/java/android/app/servertransaction/PauseActivityItem.java*/
@Override
public void postExecute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions)
...
try
// binder通知AMS当前应用activity已经执行完pause的流程
ActivityTaskManager.getService().activityPaused(token);
catch (RemoteException ex)
throw ex.rethrowFromSystemServer();
AMS
这边收到应用的activityPaused
调用后,继续执行启动应用的逻辑,判断需要启动的应用Activity
所在的进程不存在,所以接下来需要先startProcessAsync
创建应用进程,相关简化代码如下:
/*frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java*/
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig)
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
...
// 1.如果wpc不为null且hasThread表示应用Activity所属进程存在,直接realStartActivityLocked启动Activity
if (wpc != null && wpc.hasThread())
try
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
catch (RemoteException e)
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
...
...
// 2.否则,调用AMS的startProcessAsync正式开始创建应用进程
mService.startProcessAsync(r, knownToBeDead, isTop, isTop ? "top-activity" : "activity");
以上过程从systrace上看,如下图所示:
- 通知pause桌面应用:
2.确认桌面activityPaused
状态之后,开始创建应用进程:
4.2 创建应用进程
接上一小节的分析可以知道,Android
应用进程的启动是被动式的,在桌面点击图标启动一个应用的组件如Activity
时,如果Activity
所在的进程不存在,就会创建并启动进程。**Android
系统中一般应用进程的创建都是统一由zygote
进程fork
创建的,AMS
在需要创建应用进程时,会通过socket
连接并通知到到zygote
进程在开机阶段就创建好的socket
服务端,然后由zygote
进程fork
创建出应用进程。**整体架构如下图所示:
我们接着上节中的分析,继续从AMS#startProcessAsync
创建进程函数入手,继续看一下应用进程创建相关简化流程代码:
4.2.1 AMS 发送socket请求
/*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/
@GuardedBy("this")
final ProcessRecord startProcessLocked(...)
return mProcessList.startProcessLocked(...);
/*frameworks/base/services/core/java/com/android/server/am/ProcessList.java*/
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
int mountExternal, String seInfo, String requiredAbi, String instructionSet,
String invokeWith, long startTime)
try
// 原生标识应用进程创建所加的systrace tag
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
...
// 调用Process的start方法创建进程
startResult = Process.start(...);
...
finally
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
/*frameworks/base/core/java/android/os/Process.java*/
public static ProcessStartResult start(...)
// 调用ZygoteProcess的start函数
return ZYGOTE_PROCESS.start(...);
/*frameworks/base/core/java/android/os/ZygoteProcess.java*/
public final Process.ProcessStartResult start(...)
try
return startViaZygote(...);
catch (ZygoteStartFailedEx ex)
...
private Process.ProcessStartResult startViaZygote(...)
ArrayList<String> argsForZygote = new ArrayList<String>();
...
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
在ZygoteProcess#startViaZygote
中,最后创建应用进程的逻辑:
openZygoteSocketIfNeeded
函数中打开本地socket
客户端连接到zygote
进程的socket
服务端;zygoteSendArgsAndGetResult
发送socket
请求参数,带上了创建的应用进程参数信息;return
返回的数据结构ProcessStartResult
中会有新创建的进程的pid
字段。
从systrace上看这个过程如下:
4.2.2 Zygote 处理socket请求
其实早在系统开机阶段,zygote
进程创建时,就会在ZygoteInit#main
入口函数中创建服务端socket
,并预加载系统资源和框架类(加速应用进程启动速度),代码如下:
/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
public static void main(String[] argv)
ZygoteServer zygoteServer = null;
...
try
...
// 1.preload提前加载框架通用类和系统资源到进程,加速进程启动
preload(bootTimingsTraceLog);
...
// 2.创建zygote进程的socket server服务端对象
zygoteServer = new ZygoteServer(isPrimaryZygote);
...
// 3.进入死循环,等待AMS发请求过来
caller = zygoteServer.runSelectLoop(abiList);
catch (Throwable ex)
...
finally
...
...
继续往下看ZygoteServer#runSelectLoop
如何监听并处理AMS客户端的请求:
/*frameworks/base/core/java/com/android/internal/os/ZygoteServer.java*/
Runnable runSelectLoop(String abiList)
// 进入死循环监听
while (true)
while (--pollIndex >= 0)
if (pollIndex == 0)
...
else if (pollIndex < usapPoolEventFDIndex)
// Session socket accepted from the Zygote server socket
// 得到一个请求连接封装对象ZygoteConnection
ZygoteConnection connection = peers.get(pollIndex);
// processCommand函数中处理AMS客户端请求
final Runnable command = connection.processCommand(this, multipleForksOK);
Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK)
...
// 1.fork创建应用子进程
pid = Zygote.forkAndSpecialize(...);
try
if (pid == 0)
...
// 2.pid为0,当前处于新创建的子应用进程中,处理请求参数
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
else
...
handleParentProc(pid, serverPipeFd);
finally
...
private Runnable handleChildProc(ZygoteArguments parsedArgs,
FileDescriptor pipeFd, boolean isZygote)
...
// 关闭从父进程zygote继承过来的ZygoteServer服务端地址
closeSocket();
...
if (parsedArgs.mInvokeWith != null)
...
else
if (!isZygote)
// 继续进入ZygoteInit#zygoteInit继续完成子应用进程的相关初始化工作
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, null /* classLoader */);
else
...
以上过程从systrace上看如下图所示:
4.2.3 应用进程初始化
接上一节中的分析,zygote
进程监听接收AMS
的请求,fork
创建子应用进程,然后pid
为0时进入子进程空间,然后在 ZygoteInit#zygoteInit
中完成进程的初始化动作,相关简化代码如下:
/*frameworks/base/core/java/com/android/internal/os/ZygoteInit.java*/
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader)
...
// 原生添加名为“ZygoteInit ”的systrace tag以标识进程初始化流程
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
// 1.RuntimeInit#commonInit中设置应用进程默认的java异常处理机制
RuntimeInit.commonInit();
// 2.ZygoteInit#nativeZygoteInit函数中JNI调用启动进程的binder线程池
ZygoteInit.nativeZygoteInit();
// 3.RuntimeInit#applicationInit中反射创建ActivityThread对象并调用其“main”入口方法
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
应用进程启动后,初始化过程中主要依次完成以下几件事情:
- 应用进程默认的
java
异常处理机制(可以实现监听、拦截应用进程所有的Java crash
的逻辑); JNI
调用启动进程的binder
线程池(注意应用进程的binder
线程池资源是自己创建的并非从zygote
父进程继承的);- 通过反射创建
ActivityThread
对象并调用其“main
”入口方法。
我们继续看RuntimeInit#applicationInit
简化的代码流程:
/*frameworks/base/core/java/com/android/internal/os/RuntimeInit.java*/
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader)
...
// 结束“ZygoteInit ”的systrace tag
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader)
Class<?> cl;
try
// 1.反射加载创建ActivityThread类对象
cl = Class.forName(className, true, classLoader);
catch (ClassNotFoundException ex)
...
Method m;
try
// 2.反射调用其main方法
m = cl.getMethod("main", new Class[] String[].class );
catch (NoSuchMethodException ex)
...
catch (SecurityException ex)
...
...
// 3.触发执行以上逻辑
return new MethodAndArgsCaller(m, argv);
我们继续往下看ActivityThread
的main
函数中又干了什么:
/*frameworks/base/core/java/android/app/ActivityThread.java*/
public static void main(String[] args)
// 原生添加的标识进程ActivityThread初始化过程的systrace tag,名为“ActivityThreadMain”
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
...
// 1.创建并启动主线程的loop消息循环
Looper.prepareMainLooper();
...
// 2.attachApplication注册到系统AMS中
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
...
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
...
private void attach(boolean system, long startSeq)
...
if (!system)
...
final IActivityManager mgr = ActivityManager.getService();
try
// 通过binder调用AMS的attachApplication接口将自己注册到AMS中
mgr.attachApplication(mAppThread, startSeq);
catch (RemoteException ex)
throw ex.rethrowFromSystemServer();
可以看到进程ActivityThread#main
函数初始化的主要逻辑是:
- 创建并启动主线程的
loop
消息循环; - 通过
binder
调用AMS
的attachApplication
接口将自己attach
注册到AMS
中。
以上初始化过程。从systrace上看如下图所示:
5. 应用主线程消息循环机制建立
接上一节的分析,我们知道应用进程创建后会通过反射创建ActivityThread
对象并执行其main
函数,进行主线程的初始化工作:
/*frameworks/base/core/java/android/app/ActivityThread.java*/
public static void main(String[] args)
...
// 1.创建Looper、MessageQueue
Looper.prepareMainLooper();
...
// 2.启动loop消息循环,开始准备接收消息
Looper.loop();
...
// 3.创建主线程Handler对象
final H mH = new H();
class H extends Handler
...
/*frameworks/base/core/java/android/os/Looper.java*/
public static void prepareMainLooper()
// 准备主线程的Looper
prepare(false);
synchronized (Looper.class)
if (sMainLooper != null)
throw new IllegalStateException("The main Looper has already been prepared.");
sMainLooper = myLooper();
private static void prepare(boolean quitAllowed)
if (sThreadLocal.get() != null)
throw new RuntimeException("Only one Looper may be created per thread");
// 创建主线程的Looper对象,并通过ThreadLocal机制实现与主线程的一对一绑定
sThreadLocal.set(new Looper(quitAllowed));
private Looper(boolean quitAllowed)
// 创建MessageQueue消息队列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
主线程初始化完成后,主线程就有了完整的 Looper
、MessageQueue
、Handler
,此时 ActivityThread
的 Handler
就可以开始处理 Message
,包括 Application
、Activity
、ContentProvider
、Service
、Broadcast
等组件的生命周期函数,都会以 Message
的形式,在主线程按照顺序处理,这就是 App
主线程的初始化和运行原理,部分处理的 Message
如下
/*frameworks/base/core/java/android/app/ActivityThread.java*/
class H extends Handler
public static final int BIND_APPLICATION = 110;
@UnsupportedAppUsage
public static final int RECEIVER = 113;
@UnsupportedAppUsage
public static final int CREATE_SERVICE = 114;
@UnsupportedAppUsage
public static final int BIND_SERVICE = 121;
public void handleMessage(Message msg)
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;
...
...
主线程初始化完成后,主线程就进入阻塞状态,等待 Message
,一旦有 Message
发过来,主线程就会被唤醒,处理 Message
,处理完成之后,如果没有其他的 Message
需要处理,那么主线程就会进入休眠阻塞状态继续等待。可以说Android
系统的运行是受消息机制驱动的,而整个消息机制是由上面所说的四个关键角色相互配合实现的(Handler
、Looper
、MessageQueue
、Message
),其运行原理如下图所示:
Handler
:Handler
主要是用来处理Message
,应用可以在任何线程创建Handler
,只要在创建的时候指定对应的Looper
即可,如果不指定,默认是在当前Thread
对应的Looper
。Looper
:Looper
可以看成是一个循环器,其loop
方法开启后,不断地从MessageQueue
中获取Message
,对Message
进行Delivery
和Dispatch
,最终发给对应的Handler
去处理。**MessageQueue**:MessageQueue
就是一个Message
管理器,队列中是Message
,在没有Message
的时候,MessageQueue
借助Linux
的ePoll
机制,阻塞休眠等待,直到有Message
进入队列将其唤醒。**Message**:Message
是传递消息的对象,其内部包含了要传递的内容,最常用的包括what
、arg
、callback
等。
6. 应用Application和Activity组件创建与初始化
6.1 Application的创建与初始化
从前面4.2.3小结中的分析我们知道,应用进程启动初始化执行ActivityThread#main
函数过程中,在开启主线程loop
消息循环之前,会通过Binder
调用系统核心服务AMS
的attachApplication
接口将自己注册到AMS
中。下面我们接着这个流程往下看,我们先从systrace上看看AMS
服务的attachApplication
接口是如何处理应用进程的attach注册请求的:
我们继续来看相关代码的简化流程:
/*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq)
...
if (app.isolatedEntryPoint != null)
...
else if (instr2 != null)
// 1.通过oneway异步类型的binder调用应用进程ActivityThread#IApplicationThread#bindApplication接口
thread.bindApplication(...);
else
thread.bindApplication(...);
...
// See if the top visible activity is waiting to run in this process...
if (normalMode)
try
// 2.继续执行启动应用Activity的流程
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
catch (Exception e)
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
/*frameworks/base/core/java/android/app/ActivityThread.java*/
private class ApplicationThread extends IApplicationThread.Stub
@Override
public final void bindApplication(...)
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
...
// 向应用进程主线程Handler发送BIND_APPLICATION消息,触发在应用主线程执行handleBindApplication初始化动作
sendMessage(H.BIND_APPLICATION, data);
...
class H extends Handler
...
public void handleMessage(Message msg)
switch (msg.what)
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
// 在应用主线程执行handleBindApplication初始化动作
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
...
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data)
...
从上面的代码流程可以看出:AMS
服务在执行应用的attachApplication
注册请求过程中,会通过oneway
类型的binder
调用应用进程ActivityThread#IApplicationThread
的bindApplication
接口,而bindApplication
接口函数实现中又会通过往应用主线程消息队列post BIND_APPLICATION
消息触发执行handleBindApplication
初始化函数,从systrace看如下图所示:
我们继续结合代码看看handleBindApplication的简化关键流程:
/*frameworks/base/core/java/android/app/ActivityThread.java*/
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data)
...
// 1.创建应用的LoadedApk对象
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
...
// 2.创建应用Application的Context、触发Art虚拟机加载应用APK的Dex文件到内存中,并加载应用APK的Resource资源
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
// 3.调用LoadedApk的makeApplication函数,实现创建应用的Application对象
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
// 4.执行应用Application#onCreate生命周期函数
mInstrumentation.onCreate(data.instrumentationArgs);
...
在ActivityThread#**handleBindApplication
初始化过程中在应用主线程中主要完成如下几件事件**:
- 根据框架传入的
ApplicationInfo
信息创建应用APK
对应的LoadedApk
对象; - 创建应用
Application
的Context
对象; - 创建类加载器
ClassLoader
对象并触发Art
虚拟机执行OpenDexFilesFromOat
动作加载应用APK
的Dex
文件; - 通过
LoadedApk
加载应用APK
的Resource
资源; - 调用
LoadedApk
的makeApplication
函数,创建应用的Application
对象; - 执行应用
Application#onCreate
生命周期函数(APP
应用开发者能控制的第一行代码);
下面我们结合代码重点看看APK Dex
文件的加载和Resource
资源的加载流程。
6.1.1 应用APK的Dex文件加载
/*frameworks/base/core/java/android/app/ContextImpl.java*/
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo,
String opPackageName)
if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
// 1.创建应用Application的Context对象
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null,
0, null, opPackageName);
// 2.触发加载APK的DEX文件和Resource资源
context.setResources(packageInfo.getResources());
context.mIsSystemOrSystemUiContext = isSystemOrSystemUI(context);
return context;
/*frameworks/base/core/java/android/app/LoadedApk.java*/
@UnsupportedAppUsage
public Resources getResources()
if (mResources == null)
...
// 加载APK的Resource资源
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
getClassLoader()/*触发加载APK的DEX文件*/, null);
return mResources;
@UnsupportedAppUsage
public ClassLoader getClassLoader()
synchronized (this)
if (mClassLoader == null)
createOrUpdateClassLoaderLocked(null /*addedPaths*/);
return mClassLoader;
private void createOrUpdateClassLoaderLocked(List<String> addedPaths)
...
if (mDefaultClassLoader == null)
...
// 创建默认的mDefaultClassLoader对象,触发art虚拟机加载dex文件
mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
mApplicationInfo.classLoaderName, sharedLibraries);
...
...
if (mClassLoader == null)
// 赋值给mClassLoader对象
mClassLoader = mAppComponentFactory.instantiateClassLoader(mDefaultClassLoader,
new ApplicationInfo(mApplicationInfo));
/*frameworks/base/core/java/android/app/ApplicationLoaders.java*/
ClassLoader getClassLoaderWithSharedLibraries(...)
// For normal usage the cache key used is the same as the zip path.
return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
private ClassLoader getClassLoader(String zip, ...)
...
synchronized (mLoaders)
...
if (parent == baseParent)
...
// 1.创建BootClassLoader加载系统框架类,并增加相应的systrace tag
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent,
targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
...
return classloader;
// 2.创建PathClassLoader加载应用APK的Dex类,并增加相应的systrace tag
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader loader = ClassLoaderFactory.createClassLoader(
zip, null, parent, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return loader;
/*frameworks/base/core/java/com/android/internal/os/ClassLoaderFactory.java*/
public static ClassLoader createClassLoader(...)
// 通过new的方式创建ClassLoader对象,最终会触发art虚拟机加载APK的dex文件
ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
? null
: sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
if (isPathClassLoaderName(classloaderName))
return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
...
从以上代码可以看出:在创建Application
的Context
对象后会立马尝试去加载APK
的Resource
资源,而在这之前需要通过LoadedApk
去创建类加载器ClassLoader
对象,而这个过程最终就会触发Art
虚拟机加载应用APK
的dex
文件,从systrace上看如下图所示:
具体art虚拟机加载dex文件的流程由于篇幅所限这里就不展开讲了,这边画了一张流程图可以参考一下,感兴趣的读者可以对照追一下源码流程:
6.1.2 应用APK的Resource资源加载
/*frameworks/base/core/java/android/app/LoadedApk.java*/
@UnsupportedAppUsage
public Resources getResources()
if (mResources == null)
...
// 加载APK的Resource资源
mResources = ResourcesManager.getInstance().getResources(null, mResDir,
splitPaths, mOverlayDirs, mApplicationInfo.sharedLibraryFiles,
Display.DEFAULT_DISPLAY, null, getCompatibilityInfo(),
getClassLoader()/*触发加载APK的DEX文件*/, null);
return mResources;
/*frameworks/base/core/java/android/app/ResourcesManager.java*/
public @Nullable Resources getResources(...)
try
// 原生Resource资源加载的systrace tag
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
...
return createResources(activityToken, key, classLoader, assetsSupplier);
finally
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
private @Nullable Resources createResources(...)
synchronized (this)
...
// 执行创建Resources资源对象
ResourcesImpl resourcesImpl = findOrCreateResourcesImplForKeyLocked(key, apkSupplier);
if (resourcesImpl == null)
return null;
...
private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked(
@NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier)
...
impl = createResourcesImpl(key, apkSupplier);
...
private @Nullable ResourcesImpl createResourcesImpl(@NonNull ResourcesKey key,
@Nullable ApkAssetsSupplier apkSupplier)
...
// 创建AssetManager对象,真正实现的APK文件加载解析动作
final AssetManager assets = createAssetManager(key, apkSupplier);
...
private @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key,
@Nullable ApkAssetsSupplier apkSupplier)
...
for (int i = 0, n = apkKeys.size(); i < n; i++)
final ApkKey apkKey = apkKeys.get(i);
try
// 通过loadApkAssets实现应用APK文件的加载
builder.addApkAssets(
(apkSupplier != null) ? apkSupplier.load(apkKey) : loadApkAssets(apkKey));
catch (IOException e)
...
...
private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException
...
if (key.overlay)
...
else
// 通过ApkAssets从APK文件所在的路径去加载
apkAssets = ApkAssets.loadFromPath(key.path,
key.sharedLib ? ApkAssets.PROPERTY_DYNAMIC : 0);
...
/*frameworks/base/core/java/android/content/res/ApkAssets.java*/
public static @NonNull ApkAssets loadFromPath(@NonNull String path, @PropertyFlags int flags)
throws IOException
return new ApkAssets(FORMAT_APK, path, flags, null /* assets */);
private ApkAssets(@FormatType int format, @NonNull String path, @PropertyFlags int flags,
@Nullable AssetsProvider assets) throws IOException
...
// 通过JNI调用Native层的系统system/lib/libandroidfw.so库中的相关C函数实现对APK文件压缩包的解析与加载
mNativePtr = nativeLoad(format, path, flags, assets);
...
从以上代码可以看出:系统对于应用APK
文件资源的加载过程其实就是创建应用进程中的Resources
资源对象的过程,其中真正实现APK
资源文件的I/O
解析作,最终是借助于AssetManager
中通过JNI调用系统Native
层的相关C
函数实现。整个过程从systrace上看如下图所示:
6.2 Activity的创建与初始化
我们回到6.1小结中,看看AMS
在收到应用进程的attachApplication
注册请求后,先通过oneway类型的binder调用应用及进程的IApplicationThread
#bindApplication
接口,触发应用进程在主线程执行handleBindeApplication
初始化操作,然后继续执行启动应用Activity
的操作,下面我们来看看系统是如何启动创建应用Activity
的,简化代码流程如下:
/*frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java*/
@GuardedBy("this")
private boolean attachApplicationLocked(...)
...
if (app.isolatedEntryPoint != null)
...
else if (instr2 != null)
// 1.通过oneway异步类型的binder调用应用进程ActivityThread#IApplicationThread#bindApplication接口
thread.bindApplication(...);
else
thread.bindApplication(...);
...
// See if the top visible activity is waiting to run in this process...
if (normalMode)
try
// 2.继续执行启动应用Activity的流程
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
catch (Exception e)
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
/*frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java*/
public boolean attachApplication(WindowProcessController wpc) throws RemoteException
synchronized (mGlobalLockWithoutBoost)
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER))
// 原生标识attachApplication过程的systrace tag
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "attachApplication:" + wpc.mName);
try
return mRootWindowContainer.attachApplication(wpc);
finally
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
/*frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java*/
boolean attachApplication(WindowProcessController app) throws RemoteException
...
final PooledFunction c = PooledLambda.obtainFunction(
// startActivityForAttachedApplicationIfNeeded执行启动应用Activity流程
RootWindowContainer::startActivityForAttachedApplicationIfNeeded, this,
PooledLambda.__(ActivityRecord.class), app,
rootTask.topRunningActivity());
...
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top)
...
try
// ActivityStackSupervisor的realStartActivityLocked真正实现启动应用Activity流程
if (mStackSupervisor.realStartActivityLocked(r, app,
top == r && r.isFocusable() /*andResume*/, true /*checkConfig*/))
...
catch (RemoteException e)
..
/*frameworks/base/services/core/java/com/android/server/wm/ActivityStackSupervisor.java*/
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException
...
// 1.先通过LaunchActivityItem封装Binder通知应用进程执行Launch Activity动作
clientTransaction.addCallback(LaunchActivityItem.obtain(...);
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume)
// 2.再通过ResumeActivityItem封装Binder通知应用进程执行Launch Resume动作
lifecycleItem = ResumeActivityItem.obtain(dc.isNextTransitionForward());
...
clientTransaction.setLifecycleStateRequest(lifecycleItem);
// 执行以上封装的Binder调用
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
...
从以上代码分析可以看到,框架system_server
进程最终是通过ActivityStackSupervisor
#realStartActivityLocked
函数中,通过LaunchActivityItem
和ResumeActivityItem
两个类的封装,依次实现binder调用通知应用进程这边执行Activity
的Launch和Resume动作的,我们继续往下看相关代码流程:
6.2.1 Activity Create
/*frameworks/base/core/java/android/app/servertransaction/LaunchActivityItem.java*/
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions)
// 原生标识Activity Launch的systrace tag
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken, mFixedRotationAdjustments);
// 调用到ActivityThread的handleLaunchActivity函数在主线程执行应用Activity的Launch创建动作
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
/*frameworks/base/core/java/android/app/ActivityThread.java*/
@Override
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent)
...
final Activity a = performLaunchActivity(r, customIntent);
...
/** Core implementation of activity launch. */
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent)
...
// 1.创建Activity的Context
ContextImpl appContext = createBaseContextForActivity(r);
try
//2.反射创建Activity对象
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
catch (Exception e)
...
try
...
if (activity != null)
...
// 3.执行Activity的attach动作
activity.attach(...);
...
// 4.执行应用Activity的onCreate生命周期函数,并在setContentView调用中创建DecorView对象
mInstrumentation.callActivityOnCreate(activity, r.state);
...
...
catch (SuperNotCalledException e)
...
/*frameworks/base/core/java/android/app/Activity.java*/
@UnsupportedAppUsage
final void attach(...)
...
// 1.创建表示应用窗口的PhoneWindow对象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
...
// 2.为PhoneWindow配置WindowManager
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
...
从上面代码可以看出,应用进程这边在收到系统binder调用后,在主线程中创建Activiy
的流程主要步骤如下:
- 创建
Activity
的Context
; - 通过反射创建
Activity
对象; - 执行
Activity
的attach
动作,其中会创建应用窗口的PhoneWindow
对象并设置WindowManage
; - 执行应用
Activity
的onCreate
生命周期函数,并在setContentView
中创建窗口的DecorView
对象;
从systrace上看整个过程如下图所示:
6.2.2 Activity Resume
/*frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java*/
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions)
// 原生标识Activity Resume的systrace tag
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
/*frameworks/base/core/java/android/app/ActivityThread.java*/
@Override
public void handleResumeActivity(...)
...
// 1.执行performResumeActivity流程,执行应用Activity的onResume生命周期函数
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
if (r.window == null && !a.mFinished && willBeVisible)
...
if (a.mVisibleFromClient)
if (!a.mWindowAdded)
...
// 2.执行WindowManager#addView动作开启视图绘制逻辑
wm.addView(decor, l);
else
...
...
public ActivityClientRecord performResumeActivity(...)
...
// 执行应用Activity的onResume生命周期函数
r.activity.performResume(r.startsNotResumed, reason);
...
/*frameworks/base/core/java/android/view/WindowManagerGlobal.java*/
public void addView(...)
// 创建ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
...
try
// 执行ViewRootImpl的setView函数
root.setView(view, wparams, panelParentView, userId);
catch (RuntimeException e)
...
从上面代码可以看出,应用进程这边在接收到系统Binder调用请求后,在主线程中Activiy
Resume
的流程主要步骤如下:
- 执行应用
Activity
的onResume
生命周期函数; - 执行
WindowManager
的addView
动作开启视图绘制逻辑; - 创建
Activity
的ViewRootImpl
对象; - 执行
ViewRootImpl
的setView
函数开启UI界面绘制动作;
从systrace上看整个过程如下图所示:
7. 应用UI布局与绘制
接上一节的分析,应用主线程中在执行Activity
的Resume流程的最后,会创建ViewRootImpl
对象并调用其setView函数,从此并开启了应用界面UI布局与绘制的流程。在开始讲解这个过程之前,我们先来整理一下前面代码中讲到的这些概念,如Activity
、PhoneWindow
、DecorView
、ViewRootImpl
、WindowManager
它们之间的关系与职责,因为这些核心类基本构成了Android系统的GUI显示系统在应用进程侧的核心架构,其整体架构如下图所示:
Window
是一个抽象类,通过控制DecorView
提供了一些标准的UI方案,比如背景、标题、虚拟按键等
,而PhoneWindow
是Window
的唯一实现类,在Activity
创建后的attach流程中创建,应用启动显示的内容装载到其内部的mDecor
(DecorView
);DecorView
是整个界面布局View控件树的根节点,通过它可以遍历访问到整个View控件树上的任意节点;WindowManager
是一个接口,继承自ViewManager
接口,提供了View
的基本操作方法;WindowManagerImp
实现了WindowManager
接口,内部通过组合
方式持有WindowManagerGlobal
,用来操作View
;WindowManagerGlobal
是一个全局单例,内部可以通过ViewRootImpl
将View
添加至窗口
中;ViewRootImpl
是所有View
的Parent
,用来总体管理View
的绘制以及与系统WMS
窗口管理服务的IPC交互从而实现窗口
的开辟;ViewRootImpl
是应用进程运转的发动机,可以看到ViewRootImpl
内部包含mView
(就是DecorView
)、mSurface
、Choregrapher
,mView
代表整个控件树,mSurfacce
代表画布,应用的UI渲染会直接放到mSurface
中,Choregorapher
使得应用请求vsync
信号,接收信号后开始渲染流程;
我们从ViewRootImpl
的setView流程继续结合代码往下看:
/*frameworks/base/core/java/android/view/ViewRootImpl.java*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId)
synchronized (this)
if (mView == null)
mView = view;
...
// 开启绘制硬件加速,初始化RenderThread渲染线程运行环境
enableHardwareAcceleration(attrs);
...
// 1.触发绘制动作
requestLayout();
...
inputChannel = new InputChannel();
...
// 2.Binder调用访问系统窗口管理服务WMS接口,实现addWindow添加注册应用窗口的操作,并传入inputChannel用于接收触控事件
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
...
// 3.创建WindowInputEventReceiver对象,实现应用窗口接收触控以上是关于Android 应用启动全流程分析(源码深度剖析 + Systrace 展示)的主要内容,如果未能解决你的问题,请参考以下文章