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 事件驱动,其中的核心就是 InputReaderInputDispatcherInputReaderInputDispatcher 是跑在 SystemServer进程中的两个 native 循环线程,负责读取和分发 Input 事件。整个处理过程大致流程如下:

  1. InputReader负责从EventHub里面把Input事件读取出来,然后交给 InputDispatcher 进行事件分发;
  2. InputDispatcher在拿到 InputReader获取的事件之后,对事件进行包装后,寻找并分发到目标窗口;
  3. InboundQueue队列(“iq”)中放着InputDispatcherInputReader中拿到的input事件;
  4. OutboundQueue(“oq”)队列里面放的是即将要被派发给各个目标窗口App的事件;
  5. WaitQueue队列里面记录的是已经派发给 App(“wq”),但是 App还在处理没有返回处理成功的事件;
  6. PendingInputEventQueue队列(“aq”)中记录的是应用需要处理的Input事件,这里可以看到input事件已经传递到了应用进程;
  7. deliverInputEvent 标识 App UI ThreadInput 事件唤醒;
  8. InputResponse 标识 Input 事件区域,这里可以看到一个 Input_Down 事件 + 若干个 Input_Move 事件 + 一个 Input_Up 事件的处理阶段都被算到了这里;
  9. App 响应处理Input 事件,内部会在其界面View树中传递处理。

用一张图描述整个过程大致如下:

3.2 结合Systrace分析

从桌面点击应用图标启动应用,system_servernative线程InputReader首先负责从EventHub中利用linuxepolle机制监听并从屏幕驱动读取上报的触控事件,然后唤醒另外一条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树上的每一个子ViewViewGroup界面进行事件的分发、拦截、处理的逻辑。最后触控事件处理完成后会调用finishInputEvent结束应用对触控事件处理逻辑,这里面会通过JNI调用到nativeInputConsumersendFinishedSignal函数通知InputDispatcher事件处理完成,从触发从"wq"队列中及时移除待处理事件以免报ANR异常。

桌面应用界面View中在连续处理一个ACTION_DOWNTouchEvent触控事件和多个ACTION_MOVE,直到最后出现一个ACTION_UPTouchEvent事件后,判断属于onClick点击事件,然后透过ActivityManager Binder调用AMSstartActivity服务接口触发启动应用的逻辑。从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消息后执行ActivityonPause生命周期,并在执行完成后,会binder调用AMSactivityPaused接口通知系统执行完activitypause动作,相关代码如下:

  /*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上看,如下图所示:

  1. 通知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中,最后创建应用进程的逻辑:

  1. openZygoteSocketIfNeeded函数中打开本地socket客户端连接到zygote进程的socket服务端
  2. zygoteSendArgsAndGetResult发送socket请求参数,带上了创建的应用进程参数信息
  3. 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);
 

应用进程启动后,初始化过程中主要依次完成以下几件事情:

  1. 应用进程默认的java异常处理机制(可以实现监听、拦截应用进程所有的Java crash的逻辑);
  2. JNI调用启动进程的binder线程池(注意应用进程的binder线程池资源是自己创建的并非从zygote父进程继承的);
  3. 通过反射创建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);
    

我们继续往下看ActivityThreadmain函数中又干了什么:

/*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函数初始化的主要逻辑是:

  1. 创建并启动主线程的loop消息循环;
  2. 通过binder调用AMSattachApplication接口将自己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();

主线程初始化完成后,主线程就有了完整的 LooperMessageQueueHandler,此时 ActivityThreadHandler 就可以开始处理 Message,包括 ApplicationActivityContentProviderServiceBroadcast 等组件的生命周期函数,都会以 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系统的运行是受消息机制驱动的,而整个消息机制是由上面所说的四个关键角色相互配合实现的(HandlerLooperMessageQueueMessage),其运行原理如下图所示:

  1. Handler : Handler 主要是用来处理 Message,应用可以在任何线程创建 Handler,只要在创建的时候指定对应的 Looper 即可,如果不指定,默认是在当前 Thread 对应的 Looper
  2. Looper : Looper 可以看成是一个循环器,loop 方法开启后,不断地从 MessageQueue 中获取 Message,对 Message 进行 DeliveryDispatch,最终发给对应的 Handler 去处理。
  3. **MessageQueue**:MessageQueue 就是一个 Message 管理器,队列中是 Message,在没有 Message 的时候,MessageQueue 借助 LinuxePoll机制,阻塞休眠等待,直到有 Message 进入队列将其唤醒
  4. **Message**:Message 是传递消息的对象,其内部包含了要传递的内容,最常用的包括 whatargcallback 等。

6. 应用Application和Activity组件创建与初始化

6.1 Application的创建与初始化

从前面4.2.3小结中的分析我们知道,应用进程启动初始化执行ActivityThread#main函数过程中,在开启主线程loop消息循环之前,会通过Binder调用系统核心服务AMSattachApplication接口将自己注册到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#IApplicationThreadbindApplication接口,而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初始化过程中在应用主线程中主要完成如下几件事件**:

  1. 根据框架传入的ApplicationInfo信息创建应用APK对应的LoadedApk对象;
  2. 创建应用ApplicationContext对象;
  3. 创建类加载器ClassLoader对象并触发Art虚拟机执行OpenDexFilesFromOat动作加载应用APKDex文件
  4. 通过LoadedApk加载应用APKResource资源
  5. 调用LoadedApkmakeApplication函数,创建应用的Application对象;
  6. 执行应用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);
        
        ...

从以上代码可以看出:在创建ApplicationContext对象后会立马尝试去加载APKResource资源,而在这之前需要通过LoadedApk去创建类加载器ClassLoader对象,而这个过程最终就会触发Art虚拟机加载应用APKdex文件,从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函数中,通过LaunchActivityItemResumeActivityItem两个类的封装,依次实现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的流程主要步骤如下

  1. 创建ActivityContext
  2. 通过反射创建Activity对象;
  3. 执行Activityattach动作,其中会创建应用窗口的PhoneWindow对象并设置WindowManage
  4. 执行应用ActivityonCreate生命周期函数,并在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的流程主要步骤如下

  1. 执行应用ActivityonResume生命周期函数;
  2. 执行WindowManageraddView动作开启视图绘制逻辑;
  3. 创建ActivityViewRootImpl对象;
  4. 执行ViewRootImplsetView函数开启UI界面绘制动作

从systrace上看整个过程如下图所示:

7. 应用UI布局与绘制

接上一节的分析,应用主线程中在执行Activity的Resume流程的最后,会创建ViewRootImpl对象并调用其setView函数,从此并开启了应用界面UI布局与绘制的流程。在开始讲解这个过程之前,我们先来整理一下前面代码中讲到的这些概念,如ActivityPhoneWindowDecorViewViewRootImplWindowManager它们之间的关系与职责,因为这些核心类基本构成了Android系统的GUI显示系统在应用进程侧的核心架构,其整体架构如下图所示:

  • Window是一个抽象类,通过控制DecorView提供了一些标准的UI方案,比如背景、标题、虚拟按键等,而PhoneWindowWindow的唯一实现类,在Activity创建后的attach流程中创建,应用启动显示的内容装载到其内部的mDecorDecorView);
  • DecorView是整个界面布局View控件树的根节点,通过它可以遍历访问到整个View控件树上的任意节点;
  • WindowManager是一个接口,继承自ViewManager接口,提供了View的基本操作方法;WindowManagerImp实现了WindowManager接口,内部通过组合方式持有WindowManagerGlobal,用来操作ViewWindowManagerGlobal是一个全局单例,内部可以通过ViewRootImplView添加至窗口
  • ViewRootImpl是所有ViewParent,用来总体管理View的绘制以及与系统WMS窗口管理服务的IPC交互从而实现窗口的开辟ViewRootImpl是应用进程运转的发动机,可以看到ViewRootImpl内部包含mView(就是DecorView)、mSurfaceChoregraphermView代表整个控件树,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 展示)的主要内容,如果未能解决你的问题,请参考以下文章

史上最全Android渲染机制讲解(长文源码深度剖析)

奈学教育《大数据架构师》课程大纲

深度挖掘RocketMQ底层源码「底层源码挖掘系列」透彻剖析贯穿RocketMQ的消费者端的运行核心的流程(上篇)

奈学教育《大数据架构师》课程大纲

Android视图View绘制流程与源码分析(全)

MyBatis核心源码深度剖析工作机制和实现原理