前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 7.0 中 Launcher 启动 Activity 过程

Android 7.0 中 Launcher 启动 Activity 过程

原创
作者头像
汪毅雄
修改2017-10-16 17:20:29
3.4K0
修改2017-10-16 17:20:29
举报

话不多说,先看看整体跳转启动架构:

[1503455343021_7118_1503455343129.jpg]
[1503455343021_7118_1503455343129.jpg]

从图中,我们可以看到从Lanucher启动Activity会至少涉及3个进程,其中ActivityManagerService则是其中的纽带。

由于Activity的启动流程步骤经过了多层的封装,步骤较多。所以我先简单说明一下Framework层主要类的主要功能,然后在跳转步骤中重点说主要的。

主要类说明:

User进程

ApplicationThread:是一个Binder对象,里面有各种于AMS通信的接口,主要负责与AMS的通信。

ActivityThread:里面有进程主线程的入口,类似于main的功能,也建立main looper。同时负责与AMS的四大组建、生命周期的各种调度。

Instrumentation:可以理解为一个包装好的统一管理类,里面有callActivityOnCreate、callApplicationOnCreate、newActivity、callActivityOnNewIntent 等基本上在application和activity的所有生命周期调用中的方法。

AMS进程

ActivityManagerService:Activity管理机制的服务器端,属于一个系统服务。用于管理activity的各种行为,控制activity的生命周期,派发消息事件,低内存管理等等。实现了IBinder接口,可以用于进程间通信。

ActivityStack:为了让这许多 Activity协同工作而不至于产生混乱,Android平台设计了一种堆栈机制用于管理Activity,其遵循先进后出的原则,系统总是显示位于栈顶的Activity。

ActivityStackSupervisor:顾名思义,ActivityStack的管理者,宏观上把一群sleep、visible、stop的Activity汇集起来。也负责Activity生命周期的一些方法调度。

数据结构

ActivityRecord:Activity的一些信息,比如说宿主进程、component信息等。

ProcessRecord:有进程的一些信息,可能会包含这很多ActivityRecord(还有Service等其他组件)。

TaskRecord:task信息,不过有一点注意的是taskRecord对应的ActivityRecord会处于连续的位置。

接下来直接看代码吧

1、Activity.startActivity

2、Activity.startActivityForResult

[1503455417338_287_1503455417460.jpg]
[1503455417338_287_1503455417460.jpg]

3、Instrumentation.execStartActivity

[1503455427065_921_1503455427180.jpg]
[1503455427065_921_1503455427180.jpg]

上面步骤中,经过几步的方法包装后,startActivity会交给Instrumentation.execStartActivity方法。这个方法中,会把当前Activity的Binder对象ApplicationThread、包名、intent数据等一些信息通过ipc交给AMS处理。

4、ActivityManagerService.startActivity

5、ActivityManagerService.startActivityAsUser

6、ActivityStarter.startActivityMayWait

[1503455542153_9406_1503455542428.jpg]
[1503455542153_9406_1503455542428.jpg]

获取pid和uid以便权限检查

7、ActivityStarter..startActivityLocked

[1503455554962_3437_1503455555124.jpg]
[1503455554962_3437_1503455555124.jpg]

根据caller的ibinder获取ProcessRecord,不为空则重新赋值pid和uid

[1503455647275_7340_1503455647378.jpg]
[1503455647275_7340_1503455647378.jpg]
[1503455658536_2803_1503455658668.jpg]
[1503455658536_2803_1503455658668.jpg]

确定sourceRecord和resultRecord,sourceRecord代表请求启动当前activity;后者表示需要返回结果的ActivityRecord。一般,如果sourceRecord的activity使用startActivityForResult启动当前activity并且requestCode>=0时,则resultRecord=sourceRecord。

但是当intent设为FLAG_ACTIVITY_FORWARD_RESULT的时候,这个情况很特殊。比如说A打开B,B会把result给A,但是如果B打开C的时候设置了FLAG_ACTIVITY_FORWARD_RESULT,那C也会把result给A,这时候会冲突,就会把这个result直接干掉。

8.ActivityStackSupervisor.jcheckStartAnyActivityPermission

[1503455688765_5037_1503455688870.jpg]
[1503455688765_5037_1503455688870.jpg]
[1503455694648_7312_1503455694726.jpg]
[1503455694648_7312_1503455694726.jpg]
[1503455701114_6597_1503455701312.jpg]
[1503455701114_6597_1503455701312.jpg]

这几步

(1)首先是检测是否有root权限

(2)然后如果export=false,且callingUid不等于启动的uid(不在一个进程),则不予权限。

(3)activity的permission与application相同,则授权。

(4)activity的permission为空授权;

(5)请求启动的activity设定了permission,那么检查caller的activity中是否声明了使用这个permission,如果声明了授权。

回到7的startActivityLocked继续往下走

[1503455718254_6036_1503455718346.jpg]
[1503455718254_6036_1503455718346.jpg]

computeLaunchingTaskFlags

[1503455751983_4509_1503455752127.jpg]
[1503455751983_4509_1503455752127.jpg]
[1503455758393_1055_1503455758511.jpg]
[1503455758393_1055_1503455758511.jpg]

判断task是否为空,把flag设为New Task,不为空则判断标志位是否为New Task。

再通过Launchmodel设定的singleInstance和newtask真正确定launchflag。

[1503455775763_7972_1503455775909.jpg]
[1503455775763_7972_1503455775909.jpg]

在singleTop的时候,如果在top,直接通知其执行onNewIntent方法,对应应用层的onNewIntent

[1503455789042_9279_1503455789115.jpg]
[1503455789042_9279_1503455789115.jpg]

在前两步中确定的launchFlag为New task,mAddingToTask不为true等其他条件满足时,创建或复用task。

Task的复用值得一说:

如果一个activity启动时创建的了一个新的task,那么这个activity就是该task的root activity。而其中的几个属性affinity、intent是均指root activity的。

关于task的复用条件刚才已经提到了,为什么能去复用呢,因为我们知道以NewTask和NewInstance这两个launchmode的Activity只可能会是task的root Activity,既然是root,那么其affinity肯定是和task保持一致,这样就可以通过affinity来寻找。

而查找的过程是通过AMS中的mHistory来处理的

(1)查找mHistory中是否有与要启动的activity相同affinity的task,这点上面已经明述。

(2)如果activity的android:taskAffinity属性为空,此时AMS就会去mHistory中通过比较task.intent.getComponent()和启动activity的Comeponent比较,去查找是否存在task的root activity和启动的activity相同。

(3)如果task.Intent为空且这种情况发生在TaskReparenting之后,所谓TaskReparenting是用于设定Activity能够从启动它的任务中转移到另一个与启动它的任务有亲缘关系的任务中。如果设置了true,则能够转移,如果设置了false,则这个Activity必须要保留在启动它的那个任务中。TaskReparenting之后,AMS为TaskReparenting前的activity创建一个新的task,并将启动这个activity的Intent赋值给task.affinityIntent,并且此时的task.Intent==null。此时就需要比较task.affinityIntent.getComponent()和启动activity的Comeponent比较,看是否和启动的activity相同。

[1503455819412_9057_1503455819526.jpg]
[1503455819412_9057_1503455819526.jpg]

假如activity没获得焦点,无法进行resume操作。或者满足条件后开始resume。

9、ActivityStackSupervisor.resumeFocusedStackTopActivityLocked

10、ActivityStack.resumeTopActivityUncheckedLocked

[1503455873001_2654_1503455873120.jpg]
[1503455873001_2654_1503455873120.jpg]

在resumeTopActivityInnerLocked中先执行onpause,再考虑onresume。

[1503455886958_4264_1503455887042.jpg]
[1503455886958_4264_1503455887042.jpg]

先获取来源activity prev的Binder对象,通过ipc告诉prev该pause了。

11、ActivityThread.schedulePauseActivity

[1503455906461_2371_1503455906595.jpg]
[1503455906461_2371_1503455906595.jpg]
[1503455911687_2293_1503455911757.jpg]
[1503455911687_2293_1503455911757.jpg]
[1503455916856_407_1503455916930.jpg]
[1503455916856_407_1503455916930.jpg]

以上动作在Activity的进程中最终完成pause的操作。

[1503455931987_8828_1503455932067.jpg]
[1503455931987_8828_1503455932067.jpg]

在完成pause之后,通过ipc告诉AMS

12、AMS.activityPaused

13、ActivityStack.activityPausedLocked

14、ActivityStack.completePausedLocked

[1503455944756_9217_1503455944822.jpg]
[1503455944756_9217_1503455944822.jpg]

经过多层包装后定位到该方法。

15、ActivityStackSupervisor.startSpecificActivityLocked

[1503455956289_5404_1503455956389.jpg]
[1503455956289_5404_1503455956389.jpg]

如果process不在,就准备开启新的process,否则就直接准备launchActivity了,process在的情况其实是不在情况的一种子情况。

[1503455981029_9576_1503455981127.jpg]
[1503455981029_9576_1503455981127.jpg]
[1503455986923_3956_1503455986988.jpg]
[1503455986923_3956_1503455986988.jpg]

启动新的process有几个条件

(1)Process不存在

(2)该Process死亡,实际的caller也认为它真的死亡了,或者认为它有crash风险的时候会重新创建一个新的

(3)Pid没有被使用(也就是说避免重复启process)

[1503456002442_7104_1503456002530.jpg]
[1503456002442_7104_1503456002530.jpg]

而在启动的时候,会发出一个PROC_START_TIMEOUT的消息,这个消息意味这进程必须在这个消息触发之前处理,否则就认为它超时,也将无法和Activity组件关联起来。

16、ActivityThread.main

[1503456030072_1980_1503456030173.jpg]
[1503456030072_1980_1503456030173.jpg]

创建主线程和MainLooper,其在进程一启动的时候就诞生了。而ActivityThread在attach的时候会告诉系统这是非系统进程。Attach过程,会通过binder告诉AMS执行attachApplication,这才真正把binder对象(进程的代表)和pid进行绑定。

[1503456037311_3692_1503456037411.jpg]
[1503456037311_3692_1503456037411.jpg]

而在attachApplicationLocked中,在启动process之前,我们已经获得了一个和pid关联的processRecord这么一个对象,如果进程在上一步中提到的消息处理时间内中完成了,这一步就会进一步完善processRecord,也就是把进程创建完成后的那个ApplicationThread这个binder对象赋给processRecord,这样AMS就可以于创建的进程通信了。

[1503456054468_3614_1503456054586.jpg]
[1503456054468_3614_1503456054586.jpg]
[1503456062971_1875_1503456063052.jpg]
[1503456062971_1875_1503456063052.jpg]
[1503456069661_7548_1503456069743.jpg]
[1503456069661_7548_1503456069743.jpg]

上一步执行完后,AMS会告诉进程,可以启动Application了。先会会Application创建一个ApplicationContext,并初始化最开始的启动Activity的Instrumentation,之后Instrumentation会执行我们在Application常见的oncreate方法。

[1503456098686_1249_1503456098773.jpg]
[1503456098686_1249_1503456098773.jpg]
[1503456103706_8694_1503456103801.jpg]
[1503456103706_8694_1503456103801.jpg]

启动完了process,刚才还有个Activity等着我们去启动呢,就是这一步中在干的事。这一步android的四大组建都会在这里等着初始化。在这个方法中,先获取stack中top running Activity。什么情况下我们该启动它呢?显然:

如果发现这个Activity的包名、uid等于process的包名、uid。

这个Activity没有附着在任何process上。

这时候就可以在这个process中启动它。

17、AMS.scheduleLaunchActivity

[1503456122331_6709_1503456122443.jpg]
[1503456122331_6709_1503456122443.jpg]
[1503456127988_3372_1503456128089.jpg]
[1503456127988_3372_1503456128089.jpg]

17、ActivityThread.scheduleLaunchActivity

[1503456150223_9557_1503456150346.jpg]
[1503456150223_9557_1503456150346.jpg]
[1503456157219_8385_1503456157325.jpg]
[1503456157219_8385_1503456157325.jpg]
[1503456162800_9038_1503456162887.jpg]
[1503456162800_9038_1503456162887.jpg]
[1503456168143_2753_1503456168226.jpg]
[1503456168143_2753_1503456168226.jpg]

如果Activity为空,则创建一个新的Activity,并执行attach操作,这个操作就类似于构造方法给成员变量赋值,以便后续的操作。之后依次为Activity执行oncreate、onstart等操作。而在onresume操作中,ActivityThread又会通过Binder告诉AMS它已经进入onResume状态,至此整个activity的启动过程就结束了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 主要类说明:
    • User进程
      • AMS进程
        • 数据结构
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档