前言
前一篇我们介绍了activity启动流程中的一部分,主要涉及到Intent 的检查,以及SingleTask与SingleTask 页面的复用,TaskRecord的选择与创建等。 如果我们启动的页面是SingleInstance 或者是SingleTask的页面且这个页面之气启动过了,那么启动流程到前面一片文章基本就结束了,假如是第一个启动一个页面,那么会接着往下走来到ActivityStack的startActivityLocked
一 启动页面
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
//要启动的页面被放置的Task
TaskRecord rTask = r.task;
final int taskId = rTask.taskId;
// mLaunchTaskBehind 表示的是后台启动,一般是系统行为,
//taskForIdLocked 确认rTask是否在爱当前ActivityRecord里面
if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
//添加到栈的顶部
insertTaskAtTop(rTask);
mWindowManager.moveTaskToTop(taskId);
}
TaskRecord task = null;
//newTask 表示rTask 是不是一个新创建的Task
if (!newTask) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
// get started when the user navigates back to it.
boolean startIt = true;
//判断所要打开页面之上是不是存在全屏的页面。
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
// All activities in task are finishing.
//某一个Task里面所有的页面都销毁了
continue;
}
if (task == r.task) {
//
if (!startIt) {
//将想要打开的页面加入到所在的task的里面。
//r虽然被添加到了栈的顶部,但还没有显示
task.addActivityToTop(r);
//内部仅仅是设置一个标示位
r.putInHistory();
//绑定
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
ActivityOptions.abort(options);
return;
}
break;
} else if (task.numFullscreen > 0) {
//task.numFullscreen > 0 表示全屏页面的数量
startIt = false;
}
}
}
// If we are not placing the new activity frontmost, we do not want
// to deliver the onUserLeaving callback to the actual frontmost
// activity
//task不是当前显示页面所在的task.
//例如App处于后台的时候开启了一个新的页面
if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
mStackSupervisor.mUserLeaving = false;
if (DEBUG_USER_LEAVING) Slog.v(TAG,
"startActivity() behind front, mUserLeaving=false");
}
task = r.task;
// Slot the activity into the history stack and proceed
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
//当前页面添加到所在的栈顶部。
task.addActivityToTop(r);
task.setFrontOfTask();
// 标记ActivityRecord已经放置到宿主栈中
r.putInHistory();
if (!isHomeStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
// not currently running.
// 进入该分支,表示宿主栈中已经有Activity
// 此处省略与Activity启动动画相关的代码
// 将待启动的Activity绑定到窗口上
mWindowManager.addAppToken(task.mActivities.indexOf(r),
r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
// 此处省略与Activity启动动画相关的代码
} else {
// If this is the first activity, don't do any fancy animations,
// because there is nothing for it to animate on top of.
// 进入该分支,表示当前的宿主栈中还没有任何Activity,则不需要设置任何Activity启动相关的动画
// 只是将待启动的Activity绑定到窗口上
//动画是跟RecordTask绑定在一起的?app若是有多个RecordTask,当前正在显示的页面在别的RecordTask呢
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind);
ActivityOptions.abort(options);
options = null;
}
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
}
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
}
}
这里主要是为开启的Activity 在WindowManagerService 里面申请一个AppToke,关于创建AppToken 的过程有机会以后再说。之后就调用mStackSupervisor.resumeTopActivitiesLocked()方法。
boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
Bundle targetOptions) {
if (targetStack == null) {
targetStack = getFocusedStack();
}
// Do targetStack first.
boolean result = false;
//targetStack是不是在最上面
if (isFrontStack(targetStack)) {
result = targetStack.resumeTopActivityLocked(target, targetOptions);
}
// 对所有显示设备上的ActivityStack都进行相同的操作
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (stack == targetStack) {
// Already started above.
continue;
}
if (isFrontStack(stack)) {
// 转由其他显示设备的ActivityStack完成待启动Activity的显示
stack.resumeTopActivityLocked(null);
}
}
}
return result;
}
该函数的逻辑可以一句话说明白,就是将所有ActivityStack栈顶的ActivityRecord迁移到显示状态,都是通过调用AS.resumeTopActivityLocked()来完成实际的操作,细细品味,调用参数的传入略有区别: 宿主ActivityStack,传入的参数是待启动的ActivityRecord;其他ActivityStack,传入的参数的是null。简而言之就是刷新各个显示设备的显示页面。
下面进入ActivityStack的resumeTopActivityLocked
final boolean resumeTopActivityLocked(ActivityRecord prev) {
return resumeTopActivityLocked(prev, null);
}
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
} finally {
inResumeTopActivity = false;
}
return result;
}
这里通过一个标志位避免递归调用。
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
// 如果系统还未启动完毕,那AMS还不能正常工作,所以也不能显示Activity
if (!mService.mBooting && !mService.mBooted) {
// Not ready yet!
return false;
}
ActivityRecord parent = mActivityContainer.mParentActivity;
if ((parent != null && parent.state != ActivityState.RESUMED) ||
!mActivityContainer.isAttachedLocked()) {
// Do not resume this stack if its parent is not resumed.
// TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st.
return false;
}
// 当前AMS中可能存在一些正处于Intializing状态的ActivityRecord,
// 如果这些ActivityRecord不是位于栈顶,而且正在执行窗口启动动画,
// 那么,就需要取消这些Activity的启动动画。
cancelInitializingActivities();
// 这里比较有意思,
//
ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = false;
final TaskRecord prevTask = prev != null ? prev.task : null;
if (next == null) {
/// 进入该条件分支表示AMS中没有Activity
ActivityOptions.abort(options);
// Only resume home if on home display
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
//如果next为空,就启动Launcher。换句话说,无论何时Android系统都会有正在运行的Activity,默认就是Launcher
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
}
next.delayedResume = false;
// 当前正在显示的Activity正好就是下一个待显示的Activity,
// 那么,就中断对待显示ActivityRecord的调度
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
mStackSupervisor.allResumedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Top activity resumed " + next);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
// Make sure to notify Keyguard as well if it is waiting for an activity to be drawn.
mStackSupervisor.notifyActivityDrawnForKeyguard();
return false;
}
final TaskRecord nextTask = next.task;
if (prevTask != null && prevTask.stack == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
if (prevTask == nextTask) {
prevTask.setFrontOfTask();
} else if (prevTask != topTask()) {
// This task is going away but it was supposed to return to the home stack.
// Now the task above it has to return to the home task instead.
final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
} else {
if (DEBUG_STATES && isOnHomeDisplay()) Slog.d(TAG,
"resumeTopActivityLocked: Launching home next");
// Only resume home if on home display
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
}
}
// 系统进入休眠状态,当前AMS的栈顶Activity已经处于Paused状态
// 那么,中断对待显示Activity的调度
if (mService.isSleepingOrShuttingDown()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
// should be nothing left to do at this point.
mWindowManager.executeAppTransition();
mNoAnimActivities.clear();
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Going to sleep and all paused");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// Make sure that the user who owns this activity is started. If not,
// we will just leave it as is because someone should be bringing
// another user's activities to the top of the stack.
// 如果找不到启动Activity的User,则返回
if (mService.mStartedUsers.get(next.userId) == null) {
Slog.w(TAG, "Skipping resume of top activity " + next
+ ": user " + next.userId + " is stopped");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
mStackSupervisor.mWaitingVisibleActivities.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
// If we are currently pausing an activity, then don't do anything
// until that is done.
if (!mStackSupervisor.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return false;
}
// We need to start pausing the current activity so the top one
// can be resumed...
boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
if (mResumedActivity != null) {
//暂停当前显示的activity,调用Activity的onPause, 这里对应了一个生命周期
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
}
if (pausing) {
// 当前有正在Pausing的Activity
if (next.app != null && next.app.thread != null) {
//如果app已经启动过
//调度Activity所在进程的优先级,保证其不被kill
mService.updateLruProcessLocked(next.app, true, null);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
if (mService.isSleeping() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG, "no-history finish of " + mLastNoHistoryActivity +
" on new resume");
requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
null, "no-history", false);
mLastNoHistoryActivity = null;
}
// Launching this app's activity, make sure the app is no longer
// considered stopped.
try {
// 通过PackageManager修改待启动Package的状态
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false, next.userId); /* TODO: Verify if correct userid */
} catch (RemoteException e1) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ next.packageName + ": " + e);
}
// We are starting up the next activity, so tell the window manager
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
// ... // 省略与Activity切换动画相关的代码
ActivityStack lastStack = mStackSupervisor.getLastStack();
if (next.app != null && next.app.thread != null) {
// 待启动Activity的宿主进程已经存在了
// This activity is now becoming visible.
//设置可见性。
mWindowManager.setAppVisibility(next.appToken, true);
// schedule launch ticks to collect information about slow apps.
next.startLaunchTickingLocked();
ActivityRecord lastResumedActivity =
lastStack == null ? null :lastStack.mResumedActivity;
ActivityState lastState = next.state;
mService.updateCpuStats();
if (DEBUG_STATES) Slog.v(TAG, "Moving to RESUMED: " + next + " (in existing)");
// **这里,将待显示的Activity已经处于Resumed状态**
next.state = ActivityState.RESUMED;
//这个就是当前可见的页面,但是好像实际上页面的声明周期根本没有走呢。
mResumedActivity = next;
next.task.touchActiveTime();
mService.addRecentTaskLocked(next.task);
//后面分析
mService.updateLruProcessLocked(next.app, true, null);
updateLRUListLocked(next);
//后面分析
mService.updateOomAdjLocked();
//........ 省略
} else {
//........ 省略
//Home 页面点击图片启动App的时候调用,会创建对应的进程
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
前面检查了一下系统的状态,首先确保系统已经启动完成,同时确保手机没有进入休眠状态, 因为此时即使把这个Activity启动起来,用户也看不见,还不如先把它保存起来,等到下次可见的时候再启动。
这里resumeTopActivityInnerLocked 方法有两个比较关键的变量一个是pre,一个是next。前面说了一个系统可能有多个显示屏,当在某一个显示屏启动一个页面的时候实际每一显示屏当前显示的ActivityStack 都会刷新显示。对于要显示新页面的ActivityStack的resumeTopActivityLocked的pre不是null,而是要显示的页面,next 也是要显示的页面,对于其他的ActivityStack的resumeTopActivityLocked的pre是null,而next 是当前正在显示的页面。
经过一些检查之后就会执行startPausingLocked将当前正在显示的页面进入pause状态,然后检查对应的进程是否已经创建如果还没有创建进程那么调用startSpecificActivityLocked 创建进程。如果对应的进程已经存在就会通过updateLruProcessLocked,updateOomAdjLocked调整进程内存回收的优先次序(这个我们放大后面介绍),最后通过scheduleResumeTopActivities启动对应的页面。
二、创建进程
前面说了在启动页面的时候如果对应的进程还没有创建这里会先创建进程
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.task.stack.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);
}
//app进程加载完成之后加载的页面,或者说是除去首页之后的页面走的就是这里
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);
}
在AMS中有多个重载的startProcessLocked()函数,我们先来看其中一个,根据processName来启动进程,这时候可能processName对应的进程还没创建。
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
if (!isolated) {
// 进程有isolated的概念,意味着这是一个隔离的进程。对于隔离的进程而言,每次启动都是独立的,不能复用已有的进程信息。
// 如果要启动一个非隔离的进程,那么就需要区分进程是在前台启动还是后台启动,这是用户体验相关的设计。
//这里是false ,可以参考Service,其有提供隔离的功能
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
} else {
// If this is an isolated process, it can't re-use an existing process.
app = null;
}
if (app != null && app.pid > 0) {
//knownToBeDead 这里是true
if (!knownToBeDead || app.thread == null) {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: done, added package to proc");
return app;
}
// An application record is attached to a previous process,
// clean it up now.
// 进程已经挂掉
Process.killProcessGroup(app.info.uid, app.pid);
handleAppDiedLocked(app, true, true);
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (!isolated) {
// 启动参数中,带有FLAG_FROM_BACKGROUND标志,表示进程需要后台启动
if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
if (mBadProcesses.get(info.processName, info.uid) != null) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + info.processName);
return null;
}
} else {
// When the user is explicitly starting a process, then clear its
// crash count so that we won't make it bad until they see at
// least one crash dialog again, and make the process good again
// if it had been bad.
// // 前台启动,则需要将宿主进程从坏的进程中剔除
mProcessCrashTimes.remove(info.processName, info.uid);
if (mBadProcesses.get(info.processName, info.uid) != null) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mBadProcesses.remove(info.processName, info.uid);
if (app != null) {
app.bad = false;
}
}
}
}
if (app == null) {
checkTime(startTime, "startProcess: creating new process record");
// 创建一个新的ProcessRecord
//processName 是怎么来的呢?
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
app.crashHandler = crashHandler;
if (app == null) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null;
}
mProcessNames.put(processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
checkTime(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
app.addPackage(info.packageName, info.versionCode, mProcessStats);
checkTime(startTime, "startProcess: added package to existing proc");
}
// If the system is not ready yet, then hold off on starting this
// process until it is.
// 如果系统还未启动,则需要将待启动进程先保持住,等系统启动后,再来启动这些进程
if (!mProcessesReady
&& !isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
checkTime(startTime, "startProcess: returning with proc on hold");
return app;
}
checkTime(startTime, "startProcess: stepping in to startProcess");
调用另外一个startProcessLocked()函数
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
checkTime(startTime, "startProcess: done starting proc!");
return (app.pid != 0) ? app : null;
}
这里主要就是创建一个对应的ProcessRecord,然后调用startProcessLocked
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,
null /* entryPoint */, null /* entryPointArgs */);
}
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
xxx
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
xxx
}
之后Process.start 内部会通过Zygote 来fork 出对应的进程然后调用ActivityThread.main 方法,关于这一块有想了解细节的同学可以自己查阅相关资料。关于ActivityThread.main 方法放在下一篇介绍。