Android成长之路之应用启动过程

引子:在Android代码中,我们通常调用startActivity就可以启动另外一个应用了,非常的简单。从最终用户来看,启动一个应用就是在桌面上点击一个应用图标。但是点击桌面的应用图标最终依然是调用startActivity来启动对应的应用,桌面应用图标的tag携带有intent,把这个intent传给startActivity就可以启动应用了。那么在Android里启动应用的过程就是执行startActivity的过程,其实我今天分享的也就是startActivity的执行过程。

过程分析
下图是在桌面上点击应用图标启动相应的应用的总体过程。
这里写图片描述
AMS是什么?ActivityManagerService简称AMS,AMS是Activity的管理服务,是Activity管理的服务端,它是Activity的调度中心,所有应用Activity请求启动和退出都必须通过AMS来管理,控制着Activity的生命周期。从上图可以看出,在Launcher上启动App1主要分为以下7个过程:
1. Launcher通知AMS,它要启动一个Activity。
2. AMS通知Launcher需进入Paused状态。
3. Launcher进入 Paused状态,然后通知AMS进入Paused状态就绪。
4. AMS fork出一个新进程,并启动主线程ActivityThread.
5. 新进程的主线程attach到AMS,通知AMS主线程初始化完成了。
6. AMS通知ActivityThread开始启动Activity
7. ActivityThread创建待启动的Activity实例,执行Activity的生命周期。

从上面的过程可以看到有三个进程在进行交互,Launcher和App1都是应用进程,AMS是系统进程,其实就是应用进程与系统进程间的通信,这就涉及到Android的进程间通信。我们都知道Android是通过实现Binder机制来完成进程间通信,如果一个对象是Binder对象,那么它就可以在进程间通信,那么如何可以得到一个Binder对象呢?很简单,继承自Binder类就可以了。很显然,应用进程与AMS所在进程之间肯定有Binder对象作为它们之间通信的桥梁。
这里写图片描述
从上图可以看到,App进程通过ActivityManagerProxy对象与AMS通信。ActivityManagerProxy是什么?它是ActivityManagerService在应用进程端的代理对象,因为ActivityManagerService自己就是一个Binder对象,通过调用它的代理对象就相当于调用它自己的方法,所以在应用端通过ActivityManagerNative.getDefault()就可以获得ActivityManagerService的代理对象,从而与AMS通信。那么AMS所在进程怎样与应用进程通信呢?ApplicationThreadProxy代理对象,它是应用的主线程在AMS里的代理对象。AMS通过调用这个代理对象的方法就等于调用了应用的主线程相对应的方法。AMS是如何得到这个代理对象的呢?在应用进程创建完成后,就会初始化主线程,在主线程里有一个内部对象ApplicationThread,它是一个Binder对象,初始化主线程时就会初始化这个内部的Binder对象,然后通过ActivityManagerProxy对象把这个内部的Binder对象传到AMS端。通过传过来的Binder对象就可以形成主线程的代理对象了。此时,进程进程与系统进程就可以相互通信了。
接下来,我们需要了解一下应用端的对象与服务端的对象之间的对象关系。
这里写图片描述
上图中,App代表一个应用进程,ActivityThread就是这个进程里的主线程。主线程中维护着一个ActivityClientRecord类型的列表,这个列表就是当前进程里的所有Activity.ActivityClientRecord代表着我们启动的Activity对象,它有一个成员变量就是Activity对象,它与Activity对象一一对应。在AMS端维护着相对应的两个列表,一个是所有应用进程的列表mProcessNames, 所有的应用进程都维护在这个列表里。还有一个是代表所有Activity的列表mHistory,它就是Activity的栈,ActivityRecord其实就是Activity在服务端对应的对象,它与应用端的对象ActivityClientRecord一一对应,这两个对象是如何对应起来的?mToken,它可以被理解为Activity的唯一标识。正由于应用端与服务端之间的这种对应关系,AMS维护Activity栈mHistory就相当于维护着应用进程里的Activity对象。
下图是AMS里的类图关系。
这里写图片描述
AMS主要是通过调用ActivityStack对象完成对Activity的栈管理工作。ActivityRecord对象有两个重要的成员:TaskRecord和ProcessRecord,分别表示Activity所属的task和所在的进程。ProcessRecord里有一个thread成员,它是进程里的主线程的代理对象,AMS就是通过这个thread成员与应用进程联系的。
从上面的分析,可以得出一个比较详细的启动过程图。
这里写图片描述
1. 首先得到应用图标携带的intent,调用Activity的startActivity方法,Launcher得到ActivityManagerProxy这个代理对象把intent传递给AMS,通知AMS启动一个Activity.
2. AMS通过PackageManager解析传递过来的intent对象,得到ActivityInfo和ApplicationInfo,通过解析到的信息创建ActivityRecord对象,接着创建ActivityRecord对象的重要属性TaskRecord。ActivityStack里有一个成员mResumedActivity,它表示当前正处于resumed状态的Activity。由于判断到mResumedActivity不为null,说明当前有一个正处于活动状态的Activity,于是通过这个mResumedActivity对象的thread成员通知该应用执行暂停。mResumedActivity代表的正是Launcher.
3. Launcher接到通知后,执行Activity对象的onPause方法,然后通过ActivityManagerProxy对象告诉AMS,当前活动的Activity已经处于暂停状态了。
4. AMS接到应用端的通知后,准备通知应用端启动Activity,却发现之前创建的ActivityRecord对象没有ProcessRecord属性,也就是说它还没有进程,于是创建ProcessRecord对象,同时调用系统内核创建一个新的进程。
5. 进程创建完成后,会找到ActivityThread类执行,初始化主线程,Handler,Looper,并将主线程里的Binder对象attach到AMS,通知AMS主线程初始化完成。
6. AMS将传过来的thread这个Binder对象赋值给ProcessRecord对象的属性,然后将ProcessRecord对象赋值给ActivityRecord对象的属性,这样等待启动的ActivityRecord对象的属性都齐全了,通知它 的主线程可以真正启动Activity了。
7. 主线程通过AMS传过来的token创建相对应的ActivityClientRecord对象,接着利用反射实例化Activity和Application,执行Activity的生命周期,这样新应用的Activity就启动起来了。

还是以点击桌面应用图标来启动一个应用为例,下图是代理里函数的执行过程。在下图中,左边是函数所在的类,中间是执行的函数,右边是所在的进程。
图1

图1

图2
图2

图3
图3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值