Activity组件启动过程分析

本文参考

    1. Gityuan博文:startActivity启动过程分析

    2. 老罗博文:Activity组件的启动过程


整理文档 网盘地址:https://pan.baidu.com/s/1hrEn2O8



Activity

ActivityAndroid应用程序的四大组件之一,它负责管理Android应用程序的用户界面。一个应用程序一般会包含若干个Activity组件,每一个Activity组件负责一个用户界面的展现,它们可能运行在同一个进程中 ,也可能运行在不同的进程中。运行在不同进程中的Activity组件通过Binder进程间通信机制来协作完成应用程序的功能。

从应用程序的角度出发,我们可以将Activity组件划分为两种类型:一种是根Activity,另一种是子Activity。根Activity以快捷图标的形式显示在应用程序启动器中,它的启动过程就代表了一个Android应用程序的启动过程。子Activity由根Activity或者其他子Activity启动,它们有可能与启动它们的Activity运行在同一个进程中,也有可能运行在不同的进程中,这取决于它们的配置和启动参数。

Activity组件的启动方式分为显示和隐式两种。对于显示启动的Activity组件来说,我们必须事先知道用来实现它们的类的名称而对于隐式启动的Activity组件来说,我们只需要知道它们的组件名称即可,而不需要知道它们是由哪一个类来实现的。无论是显示启动的Activity组件,还是隐式启动的Activity组件,它们的启动过程都是类似的,唯一的区别在于系统是根据类名还是组件名称来找到它们。但是从软件工程的角度来看,隐式启动Activity组件可以减少Android应用程序组件间的依赖。


Activity组件的启动过程

指令:adb shell dumpsys activity activities

该指令可以查看栈中Activity列表,包含了task等信息。从下面的图一来看,当前只有一个任务栈#0,栈中有两个任务,任务#3是我们直观可见的Launcher,任务#4是长按任务键可见的最近任务列表。这种情况是默认的场景。


1、默认场景


2Launcher启动My Test应用


前言介绍:

My Test应用根ActivityMainActivity,拥有两个子ActivityMainActivitySubActivity1运行在同一个进程中,而SubActivity2处于不同的进程中。从Launcher点击启动My Test应用,默认启动MainActivity。结合图12来看,由于之前没有启动过,此次启动MainActivity会创建一个新的任务栈,即任务栈#1,栈中只运行了一个根Activity

Activity


Activity



从上面的图2来看,MainActivity位于任务栈#1中,运行在进程com.example.calf1234.mainprocess/u0a57中,与Launcher组件所处的进程不同。换而言之,启动Main Activity需要创建一个新的进程。本章节将根据events log来分析根Activity的启动过程。


3My Test启动events log

events log来看,大致可推出MainActivity的启动过程:

1、Launcher组件向AMS发送一个启动MainActivity组件的进程间通信请求。

2、AMSActivityManagerService)首先将要启动的MainActivity组件的信息保存下来,然后再向Launchr组件发送一个进入中止状态的进程间通信请求。

3、Launcher组件进入到中止状态之后,就会向AMS发送一个已进入中止状态的进程间通信请求,以便AMS可以继续执行启动MainActivity组件的操作。

4、AMS发现用来运行MainActivity组件的应用程序进程不存在,因此,它就会先启动一个新的应用程序进程。

5、新的应用程序进程启动完成之后,就会向AMS发送一个启动完成的进程间通信请求,以便AMS可以继续执行启动MainActivity组件的操作。

6、AMSstep 2保存下来的Main Activity组件的信息发送给step 4创建的应用程序进程,以便它可以将MainActivity组件启动起来。

 

4Activity组件启动流程图


1.Launcher通知AMS启动MainActivity


step5. intent设置了FLAG_ACTIVITY_NEW_TASK标志位。此标志位意味着一般从Launcher启动应用都会新建一个调用栈,除非之前有遗留的未被销毁的调用栈。


step6. 默认的requestcode值为-1,即不返回结果。 


Step8. 


Instrumentation.java文件中有三个execStartActivity方法,在Activity类中调用此方法2。重要参数:

contextThread:传递进来的为类型ApplicationTheadIBinder对象,实际上代表Launcher组件所运行的应用程序进程。

Token:传递进来的是一个IBinder代理对象,该对象指向了AMS中对应的ActivityRecord对象,即保存有Launcher组件信息。

targetActivity对象,这里指的是Launcher组件。

intent:携带即将要启动的组件的信息,这里指的是MainActivity组件。


1的差别在于param4,1中为Activity对象,2中则为String对象。



step9. 此步骤,Launcher进程开始通过AMS代理对象与AMS进行Binder进程间通信。换而言之,Launcher组件向AMS发送一个启动MainActivity组件的进程间通信请求。



2.保存MainActivity信息,后通知Launcher中止


step1. 将需奥传递的数据封装成Parcel对象,、通过Binder进程间通信机制与AMS进行交互,附带子命令:START_ACTIVITY_TRANSACTION


step2. 重点关注callerintentresultTo参数。


step56. 通过PMS获取最匹配intent的组件,此处代表的是即将要启动的MainActivity组件详细信息。

step7. AMS中新建与即将要启动的MainActivity组件相对应的ActivityRecord对象。


step8. 方法一开始进行一些初始化操作,主要还是为intent进一步设置标志位,同时根据标志位做一些特定地操作,比如新建任务栈。


之前设置了FLAG_ACTIVITY_NEW_TASK标志位,这里会新建一个task


这里对上了一部分的events log


step11. 在启动MainActivity组件的过程中发现Launcher组件并没有pausing


step12. 此时此刻Launchr组件发送一个进入中止状态的进程间通信请求,同时在events log中输出Launcher组件am_pause_activity信息。



3.Launcher中止OK,通知AMS继续启动


step2. 利用Handler沟通ApplicationThreadActivityThread


step6. 该方法内通过调用Instrumentation类的callActivityOnPause方法来中止Launcher组件,执行完该代码后,events log中会输出am_on_pause_called信息。


step8. 6804行代码很熟悉,会调用自己继承Activity类重写的方法onPause


step9. Launcher组件自己中止OK后,通知AMS继续启动MainActivity组件。



4.AMS继续启动MainActivity组件


step4. 继续启动MainActivity组件。


step7. MainActivity组件对应的ProcessRecordApplicationThread对象不存在。


step8. 基于step7,发现MainActivity组件所属的进程不存在,故先去创建进程。



5.AMSMainActivity组件创建新进程


step4. 通知zygote fork一个子进程,返回的ProcessStartResult结果带有pid进程号。


step15. BindApplication时,创建contextInstrumentationApplication类型对象。



6.进程创建OK,继续启动MainActivity组件


step1. 获取即将要启动的MainActivity组件。


此时hr值不为空,故调用realStartActivityLocked方法去启动MainActivity组件。


step3. 通知My Test应用程序进程去启动MainActivity组件。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值