Update Activity 组件的启动过程.md

master
Omooo 5 years ago
parent c5012afd7b
commit 0d539ed26f
  1. 202
      blogs/Android/Framework/源代码情景分析/Activity 组件的启动过程.md

@ -160,3 +160,205 @@ ActivityStack 类的成员变量 mHistory 用来描述系统的 Activity 组件
现在,ActivityStack 类就得到了请求 AMS 执行启动 Activity 组件操作的源 Activity 组件,以及要启动的目标 Activity 组件的信息了,它们分别保存在 ActivityRecord 对象 sourceRecord 和 r 中。最后调用 startActivityUncheckedLocked 进一步执行启动目标 Activity 组件的操作。
```java
public class ActivityStack {
final int startActivityUncheckedLocked(ActivityRecord r, ...){
startActivityLocked(ActivityRecord r, ...);
}
private final void startActivityLocked(ActivityRecord r, ...){
mHistory.add(addPos, r);
resumeTopActivityLocked(null);
}
final boolean resumeTopActivityLocked(ActivityRecord prev){
// next 当前是 MainActivity
ActivityRecord next = topRunningActivityLocked(null);
// mResumedActivity 当前是 Launcher
if(mResumedActivity != null){
startPausingLocked();
return true;
}
}
}
```
系统当前正在激活的 Activity 组件是 Launcher 组件,即 ActivityStack 类的成员变量 mResumedActivity 指向了 Launcher 组件,因此,接下来就会调用 startPausingLocked 来通知它进入 Paused 状态,它可以将焦点让给即将要启动的 MainActivity 组件。
```java
public class ActivityStack {
private final void startPausingLocked() {
ActivityRecord prev = mResumedActivity;
if (prev.app != null && prev.app.thread != null) {
prev.app.thread.schedulePauseActivity(...);
}
}
}
```
ActivtyRecord 类有一个成员变量 app,它的类型为 ProcessRecord,用来描述一个 Activity 组件所运行在的应用程序进程;而 ProcessRecord 类又有一个 thread 成员变量,它的类型为 ApplicationThreadProxy,用来描述一个 Binder 代理对象,引用的是一个类型为 ApplicationThread 的 Binder 本地对象。
```java
class ApplicationThreadProxy implements IApplicationThread {
public final void schedulePauseActivity(IBinder token, ...){
Parcel data = Parcel.obtain();
data.writeStrongBinder(token);
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
}
}
```
通过 ApplicationThreadProxy 类内部的一个 Binder 代理对象 mRemote 向 Launcher 组件所在的应用程序进程发送一个类型为 SCHEDULE_PAUSE_ACTIVITY_TRANSACTION 的进程间通信请求。
这个进程间通信请求是异步的,因此,AMS 将它发送出去之后,就马上返回了。
以上都是在 AMS 中执行的,接下来就会在应用程序 Launcher 中去处理 AMS 的请求了。
```java
public final class ActivityThread {
private final class ApplicationThread extends ApplicationThreadNative {
public final void schedulePauseActivity(IBinder token, ...) {
queueOrSendMessage(H.PAUSE_ACTIVITY, ...);
}
}
}
```
ApplicationThread 类的成员函数 schedulePauseActivity 用来处理类型为 SCHEDULE_PAUSE_ACTIVITY_TRANSACTION 的进程间通信请求。
最后调用外部类 ActivityThread 的 queueOrSendMessage 来向 Launcher 的主进程的消息队列发送一个类型为 PAUSE_ACTIVITY 的消息。
应用程序 Laucher 为什么不直接在当前线程中执行中止 Launcher 组件的操作呢?一方面是因为当前线程需要尽快返回到 Binder 线程池中去处理其他进程间通信请求;另一方面是因为在中止 Launcher 组件的过程中,可能会涉及用户页面相关的操作,因此就需要将它放在主线程中执行。
```java
public final class ActivityThread {
private final class H extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case PAUSE_ACTIVITY:
handlePauseActivity(...);
}
}
}
}
public final class ActivityThread {
final HashMap<IBinder, ActivityClientRecord> mActivities
= new HashMap<>();
private final void handlePauseActivity(IBinder token, ...) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
performPauseActivity();
QueuedWork.waitToFinish();
ActivityManagerNative.getDefault().activityPaused(token, state);
}
}
}
```
在应用程序进程中启动的每一个 Activity 组件都使用一个 ActivityClientRecord 对象来描述,这些 ActivtyClientRecord 对象对应于 ActivityManagerService 中的 ActivityRecord 对象,并且保存在 ActivityThread 类的成员变量 mActivities 中。
调用成员函数 performPauseActivity 向 Launcher 组件发送一个中止事件通知,即调用它的成员函数 onPause。然后调用 QueuedWork 的 waitToFinish 等待完成前面的一些数据写入操作,例如将数据写入磁盘的操作。由于现在 Launcher 组件即将要进入 Paused 状态了,因此就要保证它前面的所有数据写入操作都处理完成;否则,等到它重新进入 Resumed 状态时,就无法恢复之前所保存的一些状态数据。
完成这些事之后,ActivityThread 类的成员函数 handlePauseActivity 就处理完 AMS 给它发送的中止 Launcher 组件的进程间通信请求了。
最后调用 ActivityManagerNative 类的静态成员函数 getDefault 来获得 AMS 的一个代理对象,然后再调用这个代理对象的成员函数 activityPaused 来通知 AMS Launcher 组件已经进入 Paused 状态了,因此,它就可以将 MainActivity 组件启动起来了。
```java
class ActivityManagerProxy implements IActivityManager {
public void activityPaused(IBinder token, ...) {
Parcel data = Parcel.obtain();
data.writeStrongBinder(token);
mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, ...);
}
}
```
将前面传进来的参数写入到 Parcel 对象 data 中,然后再通过 ActivityManagerProxy 类内部的一个 Binder 代理对象 mRemote 向 AMS 发送一个类型为 ACTIVITY_PAUSED_TRANSACTION 的进程间通信请求。
以上都是在应用程序 Launcher 中执行的,接下来是在 AMS 中处理 Launcher 组件发出的进程间通信请求。
```java
public final int class ActivityManagerService extends ActivityManagerNative {
public final void activityPaused(IBinder token, ...) {
mMainStack.activityPaused(token, ...);
}
}
```
ActivityManagerService 类的成员函数 activityPaused 用来处理类型为 ACTIVITY_PAUSED_TRANSACTION 的进程间通信请求。
```java
public class ActivityStack {
final void activityPaused(IBinder token, ...) {
ActivityRecord r = null;
r = (ActivityRecord)mHistory.get(index);
r.state = ActivityState.PAUSED;
completePauseLocked();
}
}
```
首先把 Launcher 组件对应的 ActivityRecord 对象的 state 设置为 PAUSED 状态,表示 Launcher 组件已经进入 Paused 状态了。然后调用 completePauseLocked 来执行启动 MainActivity 组件的操作。
```java
public class ActivityStack {
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
resumeTopActivityLocked(prev);
}
final boolean resumeTopActivityLocked(ActivityRecord prev) {
startSpecificActivityLocked(next, true, true);
}
private final void startSpecificActivityLocked(ActivityRecord r, ...) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName, ...);
if (app != null && app.thread != null) {
realStartActivityLocked(r, ...);
return;
}
mService.startProcessLocked(r.processName, r.info.application, true, 0, "activity", r.intent.getComponent(), false);
}
}
```
在 AMS 中,每一个 Activity 组件都有一个用户 ID 和一个进程名称;其中,用户 ID 是在安装该 Activity 组件时由 PKMS 分配的,而进程名称则是由该 Activity 组件的 android:process 属性来决定的。AMS 在启动一个 Activity 组件时,首先会以它的用户 ID 和进程名称来检查系统中是否存在一个对应的应用程序进程。如果存在,就会直接通知这个应用程序进程将该 Activity 组件启动起来;否则,就会先以这个用户 ID 和进程名称来创建一个应用程序进程,然后再通知这个应用程序进程将该 Activity 组件启动起来。
如果 ActivityRecord 对象 r 对应的 Activity 组件所需要的应用程序进程已经存在,就直接调用 realStartActivityLocked 来启动该 Activity 组件,否则,就先调用 startProcessLocked 为该 Activity 组件创建一个应用程序进程,然后再将它启动起来。
由于 MainActivity 组件是第一次被启动,所以 AMS 会先创建应用程序进程。
```java
// AMS
private final void startProcessLocked(...) {
int pid = Process.start("android.app.ActivityThread", ...);
}
```
调用 Process 类的 start 来启动一个新的应用程序进程,指定了该进程的入口函数为 ActivityThread 的 main 函数。
```java
public final class ActivityThread {
final ApplicationThread mAppThread = new ApplicationThread();
private final void attach(boolean system) {
IActivityManager mgr = ActivityManagerNative.getDefault();
mgr.attachApplication(mAppThread);
}
public static final void main(String[] args) {
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
Looper.loop();
}
}
```
新的应用程序进程在启动时,主要做了两件事情:
1. 在进程中创建一个 ActivityThread 对象,并且调用 attach 函数向 AMS 发送一个启动完成通知
2. 创建一个消息循环

Loading…
Cancel
Save