美文网首页Android进阶学习
重温ActivityManagerService--应用启动流程

重温ActivityManagerService--应用启动流程

作者: Jack_Ou | 来源:发表于2021-10-15 00:25 被阅读0次

    前言

    前一篇文章《重温ActivityManagerService》重温了AMS,记录了AMS启动过程,与AMS交互的几个重要的类和数据结构。

    分析的笔记见:AMS源码分析笔记

    此文章主要记录一个应用是如何启动起来的。其中分析启动过程我将以两种不同的启动方式来分析:

    • 根Activity的启动流程(进程没有启动的状态)
    • 子Activity的启动过程(进程已经启动)

    1 图解Acitivity启动过程

    凡事由浅入深,一口气带出全过程必然一脸蒙蔽。因此我先放出一张简易版的子Activity的启动过程图。小伙伴们肯定可以看懂一个界面是如何启动起来的。但是该图只能说明大致流程,没有考虑进程还没有启动的情况。

    启动子Activity流程图.png

    然后看看稍微详细一些的子Activity启动流程图,可以更加详细得明白APP和AMS是如何调度的。

    子Activity组件启动过程.png

    最后看看详细的根Activity的启动流程图,可以全面看清楚一个应用从无到启动完成的过程。后面章节也会详细叙述每个步骤做了什么。

    根Activity组件启动过程.png

    注意:根Activity的23步到24步还做了很多事件,例如AMS通过Socket请求Zygote fork一个子进程等操作没有画入到该流程图中,因为该过程在《Android系统启动流程分析》中有分析到,此处只列出了调用AMS的startProcessLocked()就启动了一个进程,然后调用了ActivityThread的main()方法。

    小结:

    Launcher组件启动MainActivity组件的过程:

    • (1)Launcher组件向AMS发送一个启动MAinActivity组件的进程间通信请求
    • (2)AMS首先将要启动的MAinActivity组件信息保存下来,然后再向Launcher组件发送一个进入中止状态的进程间通信请求。
    • (3)Launcher组件进入到中止状态之后,就会向AMS发送一个已进入中止状态的进程间通信请求,以便AMS可以继续执行启动MAinActivity组件的操作。
    • (4)AMS发现用来运行MAinActivity组件的应用程序进程不存在,因此,他就会先启动一个新的应用程序进程。
    • (5)新的应用程序进程启动完成之后,就会向AMS发送一个启动完成的进程间通信请求,以便AMS可以继续执行启动MAinActivity组件的操作。
    • (6)AMS将第2步保存下来的MAinActivity组件的信息发送给第4步创建的应用程序进程,以便它可以将MAinActivity组件启动起来。

    Ok, let's go! 为了叙述的完整性,我们还是从启动根Activity开始分析,因此启动子Activity绝大多数步骤是沿用启动根Activity的流程。

    2.启动根Activity

    启动根Activity我们以在Launcher应用中点击Icon开始分析。

    2.1 在Launcher进程中完成的操作
    Launcher_startActivity.png

    在Launcher进程中完成了以下五个步骤的调用,具体实现的功能如下:

    • 1.用户调用launcher的startActivitySafely,设置Activity组件启动标志位Intent.FLAG_ACTIVITY_NEW_TASK为1,然后调用父类的startActivity。
    • 2.调用startActivityForResult(intent,int),第二个参数为-1,表示不需要知道即将启动的Activity组件的执行结果。
    • 3.传递ApplicationThread给AMS,以便AMS告知Launcher可以进入pause状态,mToken对象指向AMS中的ActivityRecord,每一个已经启动的activity都会在AMS中记录一个ActivityRecord,用来记录activity组件运行状态。
    • 4.在execStartActivity中通过AMS的代理对象调用AMS的startActivity。
    • 5.AMS代理透传信息。
    2.2 在ActivityManagerService中完成的操作
    AMS_pause.png

    从6至12步骤是在AMS中完成的操作,具体实现的功能如下:

    • 6.AMS内部有一个activityStack,用来描述一个activity组件堆栈,在该步骤中进一步调用mActivityStack的startActivityMayWait进一步响应进程间通信请求。
    • 7.在PMS中解析Intent的内容,以获得要启动activity组件的信息。然后调用startActivityLocked继续启动activity
    • 8.每一个应用程序都会使用ProcessRecord对象来描述并且保存在AMS内部。通过传进来的ApplicationThread在AMS中查询到Launcher的ProcessRecord。从mHistory堆栈中获得launcher组件的ActivityRecord。创建一个Mactivity的ActivityRecord。调用startActivityUncheckedLocked启动目标组件
    • 9.判断新启动的activity是否要在新任务中启动,在AMS中查询该任务是否已经存在。为MainActivity创建新的任务,并且将该任务加入到AMS的task堆栈中。将目标ActivityRecord保存在mHistory中,并且把MAinActivity放在栈顶,调用resumeTopActivityLocked。
    • 10.从栈顶取出activity,判断当前activity是不是被激活的activity,如果是,并且状态是Resumed直接退出,说明已经启动了。判断当前activity是否是上一次被中止的activity组件。由于当前activity是launcher,调用startPausingLocked来通知他进入pause状态。
    • 11.向launcher发送一个中止通知,并且在AMS中发送一个中止超时消息,如果Launcher没有在超时时间内返回,那么就认为Launcher没有响应了。
    • 12.透传参数给ApplicationThread。
    2.3 在Launcher进程中完成的操作
    launcher_pause.png

    从13至17步骤是在Launcher中完成的操作,具体内容如下:

    • 13.调用ActivityThread的queueOrSendMessage,这个步骤已经在launcher进程中。准备将通知暂停的消息抛到主线程。

    • 14.封装一个message发送到mH主线程。

    • 15.处理activityThread发来的PAUSE_ACTIVITY

    • 16.(1)从launcher进程中的mActivities中取出ActivityClientRecord。

        (2)调用performUserLeavingActivity向launcher组件发送一个用户离开事件通知,即调用成员函数onUserLeaveHint
        (3)调用performPauseActivity向Launcher发送中止事件通知,调用成员函数onPause
        (4)调用QueuedWork类的静态方法waitToFinish()等待完成前面的一些数据写入操作。为了回到Resumed状态时,能够恢复当前的状态信息。
        (5)调用handlePauseActivity向AMS发送中止Launcher组件的进程间通信请求。
      
    • 17.从AMS代理调用activityPaused。

    2.4 在ActivityManagerService中完成的操作
    AMS_startproc.png

    从18至23步骤是在AMS中完成的操作,具体实现的功能如下:

    • 18.收到launcher已经暂停的通知之后,调用activitystack的activityPaused.
    • 19.从mHistory取出launcher的ActivityRecord,从mHandler中移除暂停超时通知。调用completePauseLocked。
    • 20.把当前进入mPausingAcitivity取出,如果是空的,表示当前正在进入中止的Activity已经进入了Paused状态。检查当前系统是不是正在进入睡眠或者关闭状态。
    • 21.取出栈顶的ActivityRecord,MainActivity的app是空的,所以调用startSpecificActivityLocked将MainActivity的进程启动起来。
    • 22.通过activityRecord中的UID和进程名字查找是否存在MAinActivity所在的进程,如果存在则直接通知Activity启动,否则AMS的startProcessLocked来启动MAinActivity应用进程。如果进程已经起来了,那就调用realStartActivityLocked
    • 23.(1)通过processName和uid判断ProcessRecord是否存在,如果不存在,调用startProcessLocked启动新进程。
      (2)创建新进程用户Id和用户组Id
      (3)Process.start方法启动一个新的应用进程
      (4)将新创建的ProcessRecord保存在AMS的mPidsSelfLocked中,并且发送一个启动计时Message,如果超时AMS认为进程启动失败,否则AMS就会通知应用启动Maintivity。
    2.5 在Launcher进程中完成的操作
    launcher_attach.png

    24步之前,AMS会调到Zygote, Zygote会fork一个进程出来,然后调用Launcher的ActivityThread.main().

    从24至25步骤是在Launcher中完成的操作,具体内容如下:

    • 24.此步骤已经进入了新进程Main方法,在Main方法中新建MainLooper,然后new一个ActivityThread,并且调用attach方法,最后Looper循环起来。在ActivityThread中新建一个ApplicationThread,通过AMS代理调用attachApplication。
    • 25.新建进程状态透传给AMS。此处将IApplicationThread传递给AMS,AMS之后就可以通过Binder 客户端和新起来的进程通信了。
    2.6 在ActivityManagerService中完成的操作
    AMS_launch_activity.png

    从27至30步骤是在AMS中完成的操作,具体实现的功能如下:

    • 27.(1)通过PID在AMS中找到新建的ProcessRecors并且初始化他们。
      (2)移除应用启动超时消息
      (3)获取栈顶activityRecord,并且判断栈顶的activityRecord和要启动的是不是一致的。如果是一致的,调用activityStack的realStartAcitivityLocked
    • 28.将ActivityRecord的app值赋成新建的APP,然后将activity组件存入app所描述的进程中。然后在app描述的线程中调用scheduleLauncherActivity来通知新创建的进程启动activityRecord所描述的组件,即MainActivity
    • 29.透传activityRecord信息
    • 30.此步已经回到了新启动的应用进程。新建一个ActivityClientRecord,将AMS传来的参数对该ActivityClientRecord初始化,并且调用queueOrSendMessage
    2.7 在Launcher进程中完成的操作
    launcher_handle_create.png

    从31至35步骤是在Launcher中完成的操作,具体内容如下:

    • 31.封装一个message向主线程handle一个消息。
    • 32.通过ActivityClientRecord的applicationInfo查询新启动应用程序的包信息。然后调用handleLaunchActivity来启动一个新的activity
    • 33.调用performLaunchActivity将MainActivity启动起来,并且调用HandleResumeActivity表示当前activity已经处于已激活状态。
    • 34.(1)获取componentName,并且用ActivityClientRecord.packageInfo的类加载器加载MainActivity类。
      (2)ActivityClientRecord.packageInfo的makeApplication创建一个Application对象。
      (3)如果上面加载的MainActivity不是空的。新建一个contextImpl并且用ActivityClientRecord来初始化他。
      (4)调用activity.attach来初始化activity
      (5)调用mInstrumentation.callActivityOnCreate
      (6)将activityClientRecord的token作为关键字,并且将他保存在Activity的mActivity中。token是一个Binder代理,指向AMS中对应activity的ActivityRecrod
    • 35.onCreate被调用,加载用户界面,已经对用户界面上的控件进行初始化。
    2.8 小结

    MainActivity组件作为应用程序Activity的根activity,他启动起来就意味着应用程序启动起来了。因此我们可以将一个根Activity的启动过程看做一个Android应用程序的启动过程。

    3.启动子Activity

    启动子Activity和启动根Activity步骤相似度非常高,只是在startActivityUncheckedLocked中判断是否能通过AcitivityRecord获得到IApplicationThread,如果获取不到就说明进程没有启动,就去先启进程;如果不为空,就直接启动子Activity。

    3.1 在Launcher进程中完成的操作
    launcher_sub_startactivity.png

    从1至5步骤是在Launcher中完成的操作,具体内容如下:

    • 1.设置intent,调用startActivity
    • 2.3.4.5.沿用根activity启动的流程,并且目前是在原应用进程中执行。
    3.2 在ActivityManagerService中完成的操作
    AMS_sub_pause.png

    从6至12步骤是在AMS中完成的操作,具体实现的功能如下:

    • 6.7.8.沿用根activity流程。从这三步开始在AMS进程中执行。
    • 9.判断是否需要创建一个新的任务来启动子activity组件。将新建的activityRecord加入到mHistory中。调用resumeTopActivityLocked
    • 10.检查要启动的activity是否已经是当前激活的activity,判断要启动的activity的是否是上次中止的activity。
    • 11.发送暂停通知,并且开始计时
    • 12.透传暂停通知
    3.3 在Launcher进程中完成的操作
    launcher_sub_pause.png

    从13至17步骤是在Launcher中完成的操作,具体内容如下:

    • 13.调用queueOrSendMessage
    • 14.封装message并且发送到主线程
    • 15.处理暂停事件
    • 16.(1)获得前一个组件ActivityClientRecord
      (2)向前一个组件发送离开通知,调用onUserLeaveHint
      (3)调用前一个组件的中止通知onPause
      (4)等待前一个组件将数据写入磁盘
    • 17.将前一个组件已经暂停的通知告知AMS
    3.4 在ActivityManagerService中完成的操作
    AMS_sub_launch_activity.png

    从18至25步骤是在AMS中完成的操作,具体实现的功能如下:

    • 18.透传已暂停通知给AMS
    • 19.暂停计时,设置上一个activity为pause状态
    • 20.设置中止中的activity为上一个activity,说明暂停状态已经结束
    • 21.取出栈顶的ActivityRecord,SubActivity的app是空的,所以调用startSpecificActivityLocked将SubActivity的进程启动起来。
    • 22.查看processRecord是否是空,如果不是空,则调用realStartActivityLocked真正启动一个activity
    • 23.将ActivityRecord的app值赋成新建的APP,然后将activity组件存入app所描述的进程中。然后在app描述的线程中调用scheduleLauncherActivity来通知新创建的进程启动activityRecord所描述的组件,即SubActivity
    • 24.透传activityRecord信息
    • 25.用传来的activityRecord初始化activityClientRecord
    3.5 在Launcher进程中完成的操作
    launcher_sub_handle_create.png

    从26至30步骤是在Launcher中完成的操作,具体实现的功能如下:

    • 26.封装一个message,向主线程发送一个message
    • 27.获取APK资源来处理启动activity事件
    • 28.调用performLaunchActivity将MainActivity启动起来,并且调用HandleResumeActivity表示当前activity已经处于已激活状态。
    • 29.(1)获取componentName,并且用ActivityClientRecord.packageInfo的类加载器加载MainActivity类。
      (2)ActivityClientRecord.packageInfo的makeApplication创建一个Application对象。
      (3)如果上面加载的MainActivity不是空的。新建一个contextImpl并且用ActivityClientRecord来初始化他。
      (4)调用activity.attach来初始化activity
      (5)调用mInstrumentation.callActivityOnCreate
      (6)将activityClientRecord的token作为关键字,并且将他保存在Activity的mActivity中。token是一个Binder代理,指向AMS中对应activity的ActivityRecrod
    • 30.onCreate被调用,加载用户界面,已经对用户界面上的控件进行初始化。
    3.6 说明

    如果子activity设置了android:process属性为另一个进程,启动过程跟MainActivity启动一样,只是不用再新建一个task了,因为子activity的android:taskAffinity和MAinActivity是一样的,MainActivity已经新创建了一个task,可以在同一个task中进程。

    相关文章

      网友评论

        本文标题:重温ActivityManagerService--应用启动流程

        本文链接:https://www.haomeiwen.com/subject/oqppoltx.html