StartActivity之根Activity的启动过程
前言
之前在另一篇文章中简述了应用进程的创建过程,略去了Activity的创建,本篇以从Launcher界面点击应用图标启动一个app的过程来讲述根Activity的启动过程。根Activity指一个应用启动的第一个Activity,启动根Activity的时候也需要启动应用进程。大致流程如下:
- Launcher收到用户点击事件,向Ams发起startActivity的ipc请求
- AMS收到请求,记录下要启动的Activity的信息,并且通知Launcher进行pause
- Launcher执行pause的生命周期,并返回给AMS
- AMS检测到新app进程未启动,遂向zygote请求创建进程
- 新的应用创建完成后,执行attach通知AMS,AMS调用ApplicationThread的bindApplication反馈
- AMS使用2步记录的Activity信息继续创建组件
步骤
Launcher点击启动
老规矩先看调用栈
1375-1375/com.android.launcher3 W: at android.app.Instrumentation.execStartActivity(Instrumentation.java:1518)
1375-1375/com.android.launcher3 W: at android.app.Activity.startActivityForResult(Activity.java:4255)
1375-1375/com.android.launcher3 W: at com.android.launcher3.Launcher.startActivityForResult(Launcher.java:1993)
1375-1375/com.android.launcher3 W: at android.app.Activity.startActivity(Activity.java:4548)
1375-1375/com.android.launcher3 W: at com.android.launcher3.Launcher.startActivitySafely(Launcher.java:2841)
1375-1375/com.android.launcher3 W: at com.android.launcher3.Launcher.startAppShortcutOrInfoActivity(Launcher.java:2594)
1375-1375/com.android.launcher3 W: at com.android.launcher3.Launcher.onClick(Launcher.java:2415)
1375-1375/com.android.launcher3 W: at android.view.View.performClick(View.java:5637)
1375-1375/com.android.launcher3 W: at android.view.View$PerformClick.run(View.java:22445)
1375-1375/com.android.launcher3 W: at android.os.Handler.handleCallback(Handler.java:755)
1375-1375/com.android.launcher3 W: at android.os.Handler.dispatchMessage(Handler.java:95)
1375-1375/com.android.launcher3 W: at android.os.Looper.loop(Looper.java:154)
1375-1375/com.android.launcher3 W: at android.app.ActivityThread.main(ActivityThread.java:6141)
1375-1375/com.android.launcher3 W: at java.lang.reflect.Method.invoke(Native Method)
1375-1375/com.android.launcher3 W: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
1375-1375/com.android.launcher3 W: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
显而易见,调用栈是从Launcher的主循环开始的,可以看出点击事件也是push到主线程的handler中执行的,事件的派发之后用单独的文章讨论。从startActivitySafely开始启动一个app的流程。
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
...
// Prepare intent 1
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
if (Utilities.ATLEAST_MARSHMALLOW && item != null
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& ((ShortcutInfo) item).promisedIntent == null) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(UserHandleCompat.myUserHandle())) {
// Could be launching some bookkeeping activity 2
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
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;
}
在注释 1 处将启动的Flag设置为Intent.FLAG_ACTIVITY_NEW_TASK① ,这样根Activity
会在新的任务栈中启动。在注释 2 处会调用 startActivity方法,这个 startActivity 方法在Activity.java 中实现,如下所示
@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);
}
}
继续调用startActivityForResult,看调用栈又跳回了Launcher.java这是因为over write了该方法,但是继续执行父类方法
@Override
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
super.startActivityForResult(intent, requestCode, options);
}
Activity.java
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());
}
看到了熟悉的Instrumentation,我们在之前的文章中专门分析过Instrumentation,用它来直接启动各种组件,它在Activity实体创建的时候由ActivityThread在attach方法中给Activity实体赋值的,一个app只有一个Instrumentation实例。
它通过ActivityManagerNative向Ams发起ipc的请求(以7.1代码为示例)
mMainThread指的是ActivityThread的引用,里面有个内部内ApplicationThread,这个是个Binder对象,用来传递给Ams然后Ams远程回调用的。因为Binder实现了IBinder接口,所以也能传递给IBinder参数的方法。mToken是个IBinder对象,指向的是Ams中的ActivityRecord,它是每个启动的Activity在Ams中的记录实体。之后专门单独来说说这个mToken,非常重要。
Instrumentation.java
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
...
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
Exception jin = new Exception("jin3");
jin.printStackTrace();
int result = ActivityManagerNative.getDefault()
.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;
}
总的来说,最后Instrumentation将Launcher的ApplicationThread和ActivityRecord,以及要启动的Activity信息传给了Ams。
AMS收到请求
惯例先总体看一下调用栈。看到了好多ActivityStack相关的东西,最后停在了startPausingLocked这是为什么?
587-646/system_process W: at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:1151)
587-646/system_process W: at com.android.server.am.ActivityStackSupervisor.pauseBackStacks(ActivityStackSupervisor.java:982)
587-646/system_process W: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2413)
587-646/system_process W: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2215)
587-646/system_process W: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:1860)
587-646/system_process W: at com.android.server.am.ActivityStarter.startActivityUnchecked(ActivityStarter.java:1251)
587-646/system_process W: at com.android.server.am.ActivityStarter.startActivityLocked(ActivityStarter.java:516)
587-646/system_process W: at com.android.server.am.ActivityStarter.startActivityMayWait(ActivityStarter.java:860)
587-646/system_process W: at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4799)
587-646/system_process W: at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4767)
587-646/system_process W: at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:165)
587-646/system_process W: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3169)
587-646/system_process W: at android.os.Binder.execTransact(Binder.java:565)
原来startPausingLocked最后会调用到ActivityThread中的ApplicationThread内部类的schedulePauseActivity方法,这儿又是一次跨进程调用,调用到startActivity自身的进程里面,也就是Launcher,所以前面传递的mMainThread.getApplicationThread()应该派上了用场,待会儿再看,现在一步一步分析。
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
int seq = getLifecycleSeq();
if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
+ " operation received seq: " + seq);
sendMessage(
finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
token,
(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
configChanges,
seq);
}
从AMS收到请求开始。
@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());
}
比较重要的三个参数刚才已经说过,一个是caller,就是Launcher的ApplicationThread,一个是resultTo,保存了Launcher组件对应的ActivityRecord,还有就是Intent保存了待启动的组件信息。
ActivityStarter.java
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, IActivityManager.WaitResult outResult, Configuration config,
Bundle bOptions, boolean ignoreTargetSecurity, int userId,
IActivityContainer iContainer, TaskRecord inTask) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
...
try {
synchronized (mService) {
ActivityRecord[] outActivity = new ActivityRecord[1];
...
ActivityOptions options = ActivityOptions.fromBundle(
i == intents.length - 1 ? bOptions : null);
int res = startActivityLocked(caller, intent, null /*ephemeralIntent*/,
resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, 0,
options, false, componentSpecified, outActivity, null, null);
if (res < 0) {
return res;
}
resultTo = outActivity[0] != null ? outActivity[0].appToken : null;
}
}
} finally {
Binder.restoreCallingIdentity(origId);
}
return START_SUCCESS;
}
ActivityStarter是7.0引入的类,它是加载ACtivity的控制类;收集所有的逻辑来确定如何将intent和flag转化为Activity,并将task、Activity、和Stack相关联。
final 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, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
...
}
}
...
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
...
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
options, sourceRecord);
...
try {
mService.mWindowManager.deferSurfaceLayout();
err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true, options, inTask);
} finally {
mService.mWindowManager.continueSurfaceLayout();
}
postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
return err;
}
这里最重要的是创建了ActivityRecord对象r来描述要创建的Activity,前面说过这是一个Activity在AMS中的描述,现在感觉离终点越来越近了。不过整个调用栈对于各种逻辑的判断实在太过庞大,在这儿就不一一叙述了。总体就是把新的ActivityRecord添加到适合的任务栈中(包括新建),并且放在栈顶,然后pause掉原来Luancher的组件。然后resume栈顶的ActivityRecord,进入到真正的startActivity流程中。
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);
...
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
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);
}
如上代码,先判断要启动的组件所在进程是否已经启动,如果没有就会先startProcess,startProcess的流程在另一篇文章中已经讲述,可见startProcess之前还有那么多事情要完成;如果进程已经启动则进行realStartActivityLocked。调用栈如下所示
637-1011/system_process W: at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1336)
637-1011/system_process W: at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1431)
637-1011/system_process W: at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2741)
637-1011/system_process W: at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2213)
637-1011/system_process W: at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:1860)
637-1011/system_process W: at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1393)
637-1011/system_process W: at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1237)
637-1011/system_process W: at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7395)
realStartActivity最终会去调用新进程中的ActivityThread中的方法去完成组件的创建。
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, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo,r.task.taskId);
} catch (RemoteException e) {
}
...
}
下面进入第三部分,目标组件Activity实体的创建过程,其过程发生在目标进程内部。
目标进程启动组件
其实在创建目标进程的时候就已经创建了目标进程的ActivityThread,然后调用attachApplication通知ams,ams调用bindApplication反馈,然后进入了它的主消息循环,但是这时还没创建任何组件。直到AMS调用scheduleLaunchActivity通知到ActivityThread,这才开始Activity组件真正的创建。
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,int taskId_param) {
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;
r.taskId = taskId_param;
updatePendingConfiguration(curConfig);
sendMessage(H.LAUNCH_ACTIVITY, r);
}
scheduleLaunchActivity 方法将启动 Activity 的参数封装成 ActivityClientRecord,
sendMessage 方法向 H 类发送类型为LAUNCH_ACTIVITY的消息,并将ActivityClientRecord传递过去。之所以要发送消息,是想把真正的业务切换到主线程去执行,因为scheduleLaunchActivity是AMS远程调用的,它执行在目标进程的binder线程池中,不在主线程。
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;
继续看handleLaunchActivity
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
...
// Initialize before creating the activity
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);
...
注意这里调用performLaunchActivity,但是返回的参数类型是Activity,多半Activity的实例是在里面被创建好并返回了。看后面如果activity不为空,还会执行resume的操作。
重头戏来了,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
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
//创建Activity实例
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
} catch (Exception e) {
...
}
try {
//创建application
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
...
if (activity != null) {
//创建context
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
//初始化activity 给很多成员变量赋值
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);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
//调用onCreate
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
r.paused = true;
mActivities.put(r.token, r);
}
...
return activity;
}
是不是看到了好多熟悉的名字,context、onCreate、instrument、application等等。至此,Activity的创建过程就结束了,当然一个Activity要让我们能够看见其绚丽的外表,还有很多工作要做,比如setContentLayout、window、viewroot等等,这些内容也非常庞大,放在专门的章节去细述,本文的重点在于梳理流程。
总结
通过对于整个根Activity启动流程的梳理,我们大概了解了启动根Activity需要哪些环节,知道了Activity实体在哪里创建的,让脑海中有了一个脉络。同时流程也很清晰地说明了先对当前Activity做了pause然后再去启动新的组件。AMS先创建(或寻找)新Activity的任务栈,创建ActivityRecord,再根据需要判断是否需要创建进程,再通知新进程自身去完成Activity实体的创建以及初始生命周期的调用。
浙公网安备 33010602011771号