从源码的角度描述 Activity 的启动模式

Activity 显示调用

Android 系统内部已经做了很多的封装,这使得启动一个 Activity 变得异常简单。在显示调用的情况下,只需要通过如下代码即可完成:

1
2
Intent intent = new Intent(this, TestActivity.class);
startActivity(intent);

源码分析

我的源码是基于 Android 8.0 进行源码分析,那么我们就从 Activity 的 startActivity 方法开始分析,经过一系列的源码追踪会来到 startActivityForResult 方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}

在上面的代码中,我们只需要关注 mParent == null 这部分逻辑即可。mParent 代表的是 ActivityGroup,ActivityGroup 最开始被用来在一个界面中嵌入多个子 Activity,但是其在 API 13 中已经被废弃了,系统推荐代用 fragment 来代替 ActivityGroup,Fragment(android.app.Fragment 在 Android P 版本中被废弃,v4包下的 Fragment 可以使用)在使用时会更加的灵活。

在上面的代码中需要注意 mMainThread.getApplicatioinThread() 这个参数,他的类型是 ApplicationThread,ApplicationThread 是ActivityThread 的一个内部类,通过后面的分析可以发现,ApplicationThread 和 ActivityThread 在 Activity 的启动过程中发挥着很重要的作用。接着看一下 Instrumentation 的方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null;
if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
}
if (result != null) {
am.mHits++;
return result;
} else if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) {
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = ActivityManager.getService().startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}

从上面的代码可以看出,启动 Activity 真正的实现由 ActivityManager.getService() 的 startActivity 方法来完成。ActivityManagerService(下面简称为 AMS)继承了 IActivityManager.Stub,而 IActivityManager 是一个继承了 IInterfece 接口的接口,用于在在 Binder 中传输,因此可以看出 IActivityManager.Stub 实际上是一个 Binder,所以 AMS 也是一个 Binder,它是 IActivityManager.Stub 的具体实现。可以发现,ActivityManager 中,AMS 采用单例模式对外提供 Binder 对象,Singleton 是一个单例的封装类,第一次调用它的 get 方法时它会通过 create 方法来初始化 Binder 对象(也就是 AMS),在后续的调用中则直接返回之前创建的对象,这个过程的源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};

从上面的分析可以知道,Activity 由 ActivityManager.getService() 来启动,而 ActivityManager.getService() 实际上是 AMS,因此 Activity 的启动过程就转移到了 AMS 中,那么继续分析这个过程,就需要查看 AMS 的 startActivity 方法即可。

在分析 AMS 的 startActivity 方法之前,我们先看一下 Instrumentation 的 execStartActivity 方法中的 checkStartActivityResult(result, intent),直观上看起来这个方法的作用像是在检查启动 Activity 的结果,它的具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static void checkStartActivityResult(int res, Object intent) {
if (!ActivityManager.isStartResultFatalError(res)) {
return;
}
switch (res) {
case ActivityManager.START_INTENT_NOT_RESOLVED:
case ActivityManager.START_CLASS_NOT_FOUND:
if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
throw new ActivityNotFoundException("Unable to find explicit activity class " + ((Intent)intent).getComponent().toShortString() + "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException("No Activity found to handle " + intent);
case ActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity " + intent);
case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException("FORWARD_RESULT_FLAG used while also requesting a result");
case ActivityManager.START_NOT_ACTIVITY:
throw new IllegalArgumentException("PendingIntent is not an activity");
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException("Starting under voice control not allowed for: " + intent);
case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
throw new IllegalStateException("Session calling startVoiceActivity does not match active session");
case ActivityManager.START_VOICE_HIDDEN_SESSION:
throw new IllegalStateException("Cannot start voice activity on a hidden session");
case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
throw new IllegalStateException("Session calling startAssistantActivity does not match active session");
case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
throw new IllegalStateException("Cannot start assistant activity on a hidden session");
case ActivityManager.START_CANCELED:
throw new AndroidRuntimeException("Activity could not be started for " + intent);
default:
throw new AndroidRuntimeException("Unknown error code " + res + " when starting " + intent);
}
}

从上面的代码可以看出,checkStartActivityResult 的作用就是检查启动 Activity 的结果。当无法正确地启动一个 Activity 时,这个方法会抛出异常信息,其中最熟悉不过的就是 “Unable to find explicit activity class; have you declared this activity in your AndroidManifest.xml?” 这个异常了,当待启动的 Activity 没有在 AndroidManifest 中注册时,就会抛出这个异常。

接着我们开始分析 AMS 的 startActivity 方法,代码如下:

1
2
3
4
5
6
7
8
9
10
11
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, UserHandle.getCallingUserId());
}
public final int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, null, null, bOptions, false, userId, null, null, "startActivityAsUser");
}

可以看出,Activity 的启动过程有转移到了 ActivityStarter 的 startActivityMayWait 方法中了,在 startActivityMayWait 中又调用了startActivityLocked 方法:

1
2
3
4
5
6
7
8
9
final int startActivityMayWait(IApplicationThread caller, int callingUid, String callingPackage, Intent intent, String resolvedType, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult,Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,IActivityContainer iContainer, TaskRecord inTask, String reason) {
...
int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,aInfo, rInfo, voiceSession, voiceInteractor,resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,options, ignoreTargetSecurity, componentSpecified, outRecord, container,inTask, reason);
...
}

在 startActivityLocked 中又调用了 startActivity 方法:

1
2
3
4
5
6
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container, TaskRecord inTask) {
...
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,options, inTask, outActivity);
}

在 startActivity 中又调用了一个重载的方法,这一操作看似不起眼,但是需要注意的是 「true」这个参数,它的方法签名为「doResume」,这个参数后边会用到。

继续向下,重载的 startActivity 方法调用了 startActivityUnchecked 方法。至此,我们可以准确无误的追踪到 Activity 的启动过程,如何证明?以上方法上面都有注释,会一步一步引导你进入正确的方法中,比如最后 startActivityUnchecked 的方法上的注释是:「标记:这个方法应该只能从 startActivity 调用」。

下面我简化一下 startActivityUnchecked 的具体实现:

1
2
3
4
5
6
7
8
9
10
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask, ActivityRecord[] outActivity) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor);
...
if (mDoResume) {
mSupervisor.resumeFocusedStackTopActivityLocked();
}
...
}

接下来要调用的就是 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法,那么启动过程就跳转到了 ActivityStackSupervisor。

但是有个问题,resumeFocusedStackTopActivityLocked 方法在一个判断语句里面,通过对 ActivityStarter 类的追踪可以很容易的发现,这个 mDoResume 的初始值是 false,而这个字段到底是什么意思呢,字段上面也没有相关的注释。后经全局查找,最终找到了这个 mDoResume 字段状态变更之处。这便是方法内部一开始调用的 setInitialState 方法。

setInitialState 方法内部基本都是赋值,我就不上代码了,其中一句是 mDoResume = doResume; 这个 doResume 便是上边我让大家注意的 startActivity 的 doResume 的参数,在调用重载方法时,直接传入了一个 true。因此在设置完初始化状态以后,resumeFocusedStackTopActivityLocked 方法可以被调用。

同时,源码当中也给出了 mDoResume 字段的解释:「如果此时调用者要求恢复状态为 false,我们在记录中标记这一点,为的是我们能调过试图寻找正在顶部执行的 Activity 这一功能」

那么继续追踪 ActivityStackSupervisor 的 resumeFocusedStackTopActivityLocked 方法。resumeFocusedStackTopActivityLocked 内部调用 resumeFocusedStackTopActivityLocked 方法,然后调用 ActivityStack 的 resumeTopActivityUncheckedLocked,至此启动过程来到了 ActivityStack 类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} else if (r.state == RESUMED) {
// Kick off any lingering app transitions form the MoveTaskToFront operation.
mFocusedStack.executeAppTransition(targetOptions);
}
return false;
}

resumeTopActivityUncheckedLocked 内部调用 resumeTopActivityInnerLocked 方法,resumeTopActivityInnerLocked 内部调用了 ActivityStackSupervisor 的 startSpecificActivityLocked 方法,startSpecificActivityLocked 方法源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode, mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true);
}

从上面代码可以看出,startSpecificActivityLocked 方法调用了 realStartActivityLocked 方法,为了更清晰地说明 Activity 的启动过程在各种累之间的传递,这里用流程图加以说明。

Android 的启动模式 AMS 的传递

在 ActivityStackSupervisor 的 realStartActivityLocked 方法中有如下一段代码:

1
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, mergedConfiguration.getGlobalConfiguration(), mergedConfiguration.getOverrideConfiguration(), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

那么剩下的内容就和书上的内容完全一致,我再重复写一遍也没有意义,对于读者也是浪费时间的一种行为。剩下的内容在 「Android 开发艺术探索」中 P326 ~ P336中。

最后,祝各位读者阅读愉快。

坚持原创技术分享,您的支持将鼓励我继续创作!