Activity的启动过程在面试中被经常问到,可以看出这也是现在Android开发高级工程师必须掌握的一个知识点。下面我们开始介绍。
我这里把Activity的启动过程分为两种场景:
- 待启动的Activity所在的app没有启动【场景一】主要出现在,从桌面点击app的图标打开app(冷启动)时,Launcher启动app的首页Activity过程。另外就是从一个app的Activity去启动另一个未启动的app的Activity。
- 待启动的Activity所在的app已启动【场景二】,通常是我们最常见的,在一个app内部,从一个页面打开另一个页面。或是从一个app的Activity去启动另一个已启动的app的Activity。
两者的区别,主要是待启动的Activity所在的app进程有没有创建并启动。相比之下,【场景二】只是略过app进程的创建这一步。我们只需要重点了解【场景一】,就可以知道完整的Activity启动过程了。
接下来我们以【场景一】中的Launcher启动App首页Activity的过程作为分析的案例。
因为这其中涉及到的方法调用和步骤很多,为了便于理解,我们把整个过程大概分为三部分
- Launcher请求ActvityManagerService的过程【过程①】
- ActvityManagerService到ApplicationThread的过程【过程②】
- ActivityThread启动Activity的过程【过程③】
这种划分的方法,是依据这些方法执行时所在的进程来进行的。简单说,【过程①】是在Launcher的进程中执行,【过程②】是在AMS所在的SystemServer进程中执行,【过程③】是在Activity所在的app进程中执行。
下面按顺序一步步来看:
首先看看【过程①】的时序图
当我们点击桌面的app图标时,就会调用Launcher的startActivitySafely方法。我们这里只关注和Activity启动过程相关的代码。看代码
Launcher.startActivitySafely
//src/com/android/launcher3/Launcher.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
boolean success = super.startActivitySafely(v, intent, item);
.......
}
这个方法中主要是调用其父类,也就是BaseDraggingActivity的startActivitySafely方法。
BaseDraggingActivity.startActivitySafely
//src/com/android/launcher3/BaseDraggingActivity.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
...
//【注释①】
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
...
try {
boolean isShortcut = Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
//【注释②】
// Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
getUserEventDispatcher().logAppLaunch(v, intent);
return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
}
return false;
上面代码的【注释①】处,我们都很熟悉,是给启动Activity的Intent添加Intent.FLAG_ACTIVITY_NEW_TASK的FLAG,这样首页Activity会在新的任务栈中启动。
再看【注释②】处,这里的startActivity方法就是Activity基类的startActivity方法。因为BaseDraggingActivity继承自同目录下的BaseActivity,而BaseActivity继承自android.app.Activity。接下来,我们就应该去看看,Android开发都再熟悉不过的Activity.startActivity方法。
Activity.startActivity
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
startActivity方法内部调用了startActivityForResult,并且requestCode传了-1,也就是当Activity退出时不需要返回result。
Activity.startActivityForResult
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
// Is this activity embedded inside of another activity?
if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
...
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);
}
}
}
只关注重要的代码,mInstrumentation.execStartActivity。从源码的注释可以看到,官方对Instrumentation的定义,用于监控应用程序和系统的所有交互。
mInstrumentation.execStartActivity
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
...
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;
}
在上面这段代码中有两个地方值得注意,一个是whoThread,它的类型是IApplicationThread,这是一个aidl接口,所以看到它,你就应该能猜到,此处会有一个跨进程通信的过程。没错,ActivityManager.getService()
.startActivity方法的执行,就已经从当前进程,切换到了AMS所在的SystemServer进程。
这里顺带提一下ActivityManager.getService()
ActivityManager.getService()
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;
}
};
以上的代码是Android8.0的源码,8.0之前的源码逻辑有些不同,这里没有多加说明,请读者自行查阅。
从代码可以看出,这里是通过aidl的方式获取到ActivityManagerService的代理对象。要实现进程间通信,服务端也就是AMS只需要集成IActivityManager.Stub类并实现相应的方法就可以了。不熟悉aidl和binder原理的同学,可以看看这篇Binder和IPC机制。
我们接着看启动过程。至此,【过程①】完成,接下来是【过程②】,同样先看看时序图:
先来看看AMS的startActivity方法。AMS类中有两个startActivity方法
ActivityManagerService.startActivity
@Override
public int startActivity(IBinder whoThread, String callingPackage,
Intent intent, String resolvedType, Bundle bOptions) {
checkCaller();
int callingUser = UserHandle.getCallingUserId();
TaskRecord tr;
IApplicationThread appThread;
...
return mActivityStarter.startActivityMayWait(appThread, -1, callingPackage, intent,
resolvedType, null, null, null, null, 0, 0, null, null,
null, bOptions, false, callingUser, tr, "AppTaskImpl");
}
@Override
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());
}
@Override
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, "startActivityAsUser");
}
这里顺带提一句,两个startActivity方法中,都调用了UserHandle.getCallingUserId(),这个方法会获得调用者的UserId,AMS根据这个UserId来确定调用者的权限。
从源码可以看出,startActivity方法最终都会调用到mActivityStarter.startActivityMayWait。ActivityStarter是Android7.0新加入的类。它是加载Activity的控制类,会收集所有的逻辑来决定如何将相关的Intent和Flags转化为Activity,并将Activity和Task以及Stack相关联。
ActivityStarter.startActivityMayWait
接着往下看
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,
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, inTask,
reason);
...
...
}
这个方法非常的长!我们只关注重要的代码,这里需要注意下,startActivityLocked方法的倒数第二个参数,是TaskRecord类型,代表启动的Activity所在的任务栈的相关记录。
ActivityStarter.startActivityLocked
int startActivityLocked(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, TaskRecord inTask, String reason) {
...
mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
inTask);
...
}
ActivityStarter.startActivity
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, TaskRecord inTask) {
...
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = ActivityManager.START_PERMISSION_DENIED;
}
}
...
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, options, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
...
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
...
}
private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, outActivity);
...
}
上面代码的第一个startActivity方法中的逻辑很多,这里只列出了我们需要关心的代码。callerApp = mService.getRecordForAppLocked(caller); 这里的caller对象代表的是Launcher所在进程中的ApplicationThread对象,就是上面提到过的whoThread,ActivityManager.getService()
.startActivity方法中的第一个参数。callerApp是ProccessRecord类型,用来描述一个应用程序进程。同样的ActivityRecord用来描述一个Activity,用来记录一个Activity的所有信息。
接着,在第二个startActivity方法里,调用了startActivityUnchecked
ActivityStarter.startActivityUnchecked
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
...
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mWindowManager.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
}
...
}
这个方法主要处理与Activity栈管理相关的逻辑,根据intent和FLAG判断是否需要创建一个新的Activity任务栈,在这个方法里会根据Activity的启动标识位和Activity的启动模式来决定如何启动一个Activity以及是否调用deliverNewIntent方法来通知Activity有一个Intent试图重新启动它。
我们启动首页Activity时,intent添加了Intent.FLAG_ACTIVITY_NEW_TASK的Flag,所以会执行setTaskFromReuseOrCreateNewTask方法,其内部会创建一个新的TaskRecord,用来描述一个Activity任务栈。
到这一步,已经确定要启动的Activity所在的栈。这个方法最后会调用mSupervisor.resumeFocusedStackTopActivityLocked方法
ActivityStackSupervisor.resumeFocusedStackTopActivityLocked
boolean resumeFocusedStackTopActivityLocked(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!readyToResume()) {
return false;
}
if (targetStack != null && isFocusedStack(targetStack)) {
return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
//获取要启动的Activity所在栈的栈顶的Activity是不是处于停止状态
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
//如果栈顶的Activity为空,或者栈顶Activity当前不是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;
}
从上面的代码可以看出,我们启动app的首页Activity时,栈顶的Activity肯定为空,所以接下来就会调用targetStack.resumeTopActivityUncheckedLocked。targetStack是一个ActivityStack对象。
ActivityStack.resumeTopActivityUncheckedLocked
/**
* Ensure that the top activity in the stack is resumed.
*/
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
// We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
// any necessary pause logic occurs. In the case where the Activity will be shown regardless
// of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked}
// is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
checkReadyForSleep();
}
return result;
}
这个方法的逻辑很明显,我们需要接着往下看resumeTopActivityInnerLocked
ActivityStack.resumeTopActivityInnerLocked
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
mStackSupervisor.startSpecificActivityLocked(next, true, false);
...
}
这是一个有500多行代码的方法,我们现在先只关注启动过程的比较重要的调用mStackSupervisor.startSpecificActivityLocked
ActivityStackSupervisor.startSpecificActivityLocked
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
//获取待启动的Activity所在的app进程
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
if (app != null && app.thread != null) {
//此处判断app进程是否存在并且已经在运行
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);
}
...
}
此方法中将会获取待启动的Activity所在的app进程,如果进程已经创建并且已经在运行就会调用realStartActivityLocked方法,这个方法的第二个参数就是待启动的Activity所在的App进程的ProcessRecord。接着看:
ActivityStackSupervisor.realStartActivityLocked
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
...
}
这个方法也有200多行,我们还是先关注重点。代码中的app.thread指的是IApplicationThread,它的实现是ActivityThread的内部类ApplicationThread,ApplicationThread继承了IApplicationThread.Stub。标准的aidl方式。而且细心的同学会发现,这是Activity启动过程中第二次出现IApplicationThread,而它的每次出现都意味着,接下来的过程中会有进程切换或者说进程间通信。此处的app指的是待启动的Activity所在的app进程。这里的IApplicationThread是用来实现AMS所在的SystemServer进程与app进程进行Binder通信。至此,【过程②】完毕。接下来是过程【过程③】。
先来看看时序图
【过程③】ApplicationThread.scheduleLaunchActivity开始,这个方法是运行在待启动的Activity所在的app进程
ApplicationThread.scheduleLaunchActivity
//android\app\ActivityThread.java
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
updateProcessState(procState, false);
ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.referrer = referrer;
r.voiceInteractor = voiceInteractor;
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
r.startsNotResumed = notResumed;
r.isForward = isForward;
r.profilerInfo = profilerInfo;
r.overrideConfig = overrideConfig;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity方法将待启动的Actvity相关的参数保存在一个ActivityClientRecord对象里,然后向ApplicationThread内部的Handler子类对象mH发送LAUNCH_ACTIVITY的消息。这里的H对象是app进程的主线程中负责处理消息的Handler子类。因为ApplicationThread是个binder,它的代码执行都是在Binder线程池中,所以需要用H将代码逻辑切换到主线程。此时,Activity的启动过程就进入了H.handleMessage
H.handleMessage
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
...
}
这个handleMessage方法也有300行左右的代码,还是看重点:handleLaunchActivity
Activity.handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
mSomeActivitiesChanged = true;
if (r.profilerInfo != null) {
mProfiler.setProfiler(r.profilerInfo);
mProfiler.startProfiling();
}
// Make sure we are running with the most recent config.
handleConfigurationChanged(null, null);
if (localLOGV) Slog.v(
TAG, "Handling launch of " + r);
// Initialize before creating the activity
if (!ThreadedRenderer.sRendererDisabled) {
GraphicsEnvironment.earlyInitEGL();
}
WindowManagerGlobal.initialize();
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
if (!r.activity.mFinished && r.startsNotResumed) {
// The activity manager actually wants this one to start out paused, because it
// needs to be visible but isn't in the foreground. We accomplish this by going
// through the normal startup (because activities expect to go through onResume()
// the first time they run, before their window is displayed), and then pausing it.
// However, in this case we do -not- need to do the full pause cycle (of freezing
// and such) because the activity manager assumes it can just retain the current
// state it has.
performPauseActivityIfNeeded(r, reason);
// We need to keep around the original state, in case we need to be created again.
// But we only do this for pre-Honeycomb apps, which always save their state when
// pausing, so we can not have them save their state when restarting from a paused
// state. For HC and later, we want to (and can) let the state be saved as the
// normal part of stopping the activity.
if (r.isPreHoneycomb()) {
r.state = oldState;
}
}
} else {
// If there was an error, for any reason, tell the activity manager to stop us.
try {
ActivityManager.getService()
.finishActivity(r.token, Activity.RESULT_CANCELED, null,
Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
重点看看performLaunchActivity
ActivityThread.performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(
mInitialApplication.getPackageManager());
r.intent.setComponent(component);
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
...
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback);
...
mInstrumentation.callActivityOnCreate(activity, r.state);
...
}
performLaunchActivity方法中主要做了这么几件事
- 从ActivityClientRecord中获取待启动的Activity的组件信息
- 通过Instrumentation的newActivity方法使用类加载器创建Activity对象
- 通过LoadedApk的makeApplication方法来尝试创建Application对象
- 创建ContextImpl对象并通过Activity的attach方法完成一些重要数据的初始化。ContextImpl是通过Activity的attach方法与Activity建立关联的。除此之外,在attach方法中Activity还会完成Window对象(PhoneWindow)的创建并建立Activity与Window的关联,由此,WIndow接收到外部的输入事件后就可以将事件传递给Activity。
- 如果theme存在,为Activity设置Theme
- 调用mInstrumentation.callActivityOnCreate
Instrumentation.callActivityOnCreate
public void callActivityOnCreate(Activity activity, Bundle icicle,
PersistableBundle persistentState) {
prePerformCreate(activity);
activity.performCreate(icicle, persistentState);
postPerformCreate(activity);
}
Activity.performCreate
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
mActivityTransitionState.readState(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
}
至此,可以看到Activity对象的onCreate方法被回调。到这里,可以说Activity的启动过程算是完成了。
总结
我这里将整个过程分成三部分。是希望有助于读者理解,毕竟完整的讲述和记住整个过程的每一个方法调用,确实很难。我觉得按下面整个思路去理清整个启动过程,应该是相对容易理解和记住的。
【过程①】重点主要是,源Activity和AMS之间的跨进程通信过程,用到了IApplicationThread这个binder来实现进程切换。这部分逻辑都是在app进程中执行。
【过程②】重点主要是,根据Intent和Flag相关信息,处理待启动的Activity和Task还有Stack相关的一些逻辑。以及StstemServer进程和待启动的Activity所在的App进程之间的切换,同样是用到了IApplicationThread这个binder。这部分的代码逻辑都是在AMS所在的SystemServer进程中执行。
【过程③】重点主要是,mH的线程切换和performLaunchActivity方法所完成的那些动作。
本文参考
《Android进阶解密》
《Android开发艺术探索》