文章仅记录自己的一点分析过程,供日后参考。
1.dismissKeyguard()
先看下这个函数功能:
void dismissKeyguard() {
if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
if (mDismissKeyguardOnNextActivity) {
mDismissKeyguardOnNextActivity = false;
mWindowManager.dismissKeyguard();
}
}
函数很简单,判断mDismissKeyguardOnNextActivity为true,然后调用mWindowManager.dismissKeyguard()-->PhoneWindowManager.dismissKeyguardLw().
public void dismissKeyguardLw() {
if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
mHandler.post(new Runnable() {
public void run() {
if (mKeyguardDelegate.isDismissable()) {
// Can we just finish the keyguard straight away?
mKeyguardDelegate.keyguardDone(false, true);
} else {
// ask the keyguard to prompt the user to authenticate if necessary
mKeyguardDelegate.dismiss();
}
}
});
}
}
上面的代码逻辑是如果keyguard当前是显示状态,那么就进行解锁,否则直接返回。解锁时再判断当前keyguard是否设置了密码保护,如果设置了那么走mKeyguardDelegate.dismiss(),如果没设置,那就调用mKeyguardDelegate.keyguardDone(false, true)直接解锁keyguard。
dismissKeyguard()函数就是提供了一个给AMS侧使用的解锁keyguard接口。但是能不能调用真正解锁还得过mDismissKeyguardOnNextActivity变量这一关呀,这个变量在dismissKeyguardOnNextActivity()-->setDismissKeyguard(true)中赋值为true。dismissKeyguardOnNextActivity()是提供给launcher应用使用的。然而在AMS中的很多地方又调用setDismissKeyguard(false),一般情况是在startActivityLocked()一个activity,当出现权限等异常情况时调用。
2.resumeHomeActivity(ActivityRecord prev)
boolean resumeHomeActivity(ActivityRecord prev) {
moveHomeToTop();
if (prev != null) {
prev.task.mOnTopOfHome = false;
}
ActivityRecord r = mHomeStack.topRunningActivityLocked(null);
if (r != null && r.isHomeActivity()) {
mService.setFocusedActivityLocked(r);
return resumeTopActivitiesLocked(mHomeStack, prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser);
}
函数首先调用moveHomeToTop()来将HomeStack移到前台,然后再把launcher所在的Task移到顶端,这样下面调用resumeTopActivitiesLocked()时便能找到正确的ActivityStack和Task来启动。有个小细节需要注意的是:如果prev不为null,表示是从pre直接起launcher的,此时将prev.task.mOnTopOfHome设为FALSE。
3.TaskRecord.mOnTopOfHome
为什么要设为FALSE?要搞清这个问题需要完全理解mOnTopOfHome这个变量的设计思想。源码对mOnTopOfHome的解释如下:
/** Launch the home activity when leaving this task. */
只要是TaskRecord设置了mOnTopOfHome为true,待leaving这个Task时便回到桌面,这个解释是绝对正确的吗?还有什么叫leaving this task?这个得好好研究下。要研究清楚mOnTopOfHome,必然要研究使用mOnTopOfHome的各种场景,从场景中还原出最准确的理解。mOnTopOfHome作为判断条件的地方只有7处,分别在removeTask()、moveTaskToBackLocked()、removeActivityFromHistoryLocked()、adjustFocusedActivityLocked()、resumeTopActivityLocked()、isActivityOverHome()六个函数中。下面来一个个研究这几个函数(还好不多)。
㈠、isActivityOverHome()
/**
* Determine if home should be visible below the passed record.
* @param record activity we are querying for.
* @return true if home is visible below the passed activity, false otherwise.
*/
boolean isActivityOverHome(ActivityRecord record) {
// Start at record and go down, look for either home or a visible fullscreen activity.
final TaskRecord recordTask = record.task;
for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
final int startNdx =
task == recordTask ? activities.indexOf(record) : activities.size() - 1;
for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.isHomeActivity()) {
return true;
}
if (!r.finishing && r.fullscreen) {
// Passed activity is over a fullscreen activity.
return false;
}
}
if (task.mOnTopOfHome) {
// Got to the bottom of a task on top of home without finding a visible fullscreen
// activity. Home is visible.
return true;
}
}
// Got to the bottom of this stack and still don't know. If this is over the home stack
// then record is over home. May not work if we ever get more than two layers.
return mStackSupervisor.isFrontStack(this);
}
这个函数非常好理解,解释已经说得很清楚了,就是判断launcher是否会显示在参数给出的Activity之下。首先明白Activity是处在一个ActivityTask中的,所以逻辑就变成了判断launcher是否会显示在参数给出的Activity所在的ActivityTask中的所有Activity之下。这个说法还不太精确,准备的说是所处ActivityTask的参数Activity及以下的所有Activity。如果在这些Activity中找到一个全屏的,并且没有被finish的Activity,那么表示launcher就不会显示在参数Activity之下。如果在 这个Task中没有找到符合那两个条件的Activity,那么就看task.mOnTopOfHome是否为true, 如果为true,那么就返回true;如果整个Stack中都还没确认是否显示launcher,那么就依据mStackSupervisor.isFrontStack(this)来判断,其实这是由bug的,做多窗口时这个地方肯定要做修改,注释也说明了多于2个stack就会有问题。
从这个函数中已经隐约知道这个mOnTopOfHome变量的作用了,在Android4.4之前,只有一个Stack,所有的Task都放在mTaskHistoty中,现在有两个(多窗口有多个)ActivityStack,Task的管理变得相对来说复杂一些了,还好Google把其中一个ActivityStack定制为HomeStack,一般情况可认为就代表着launcher。那么问题来了?不是挖掘机哪家强的问题,是如何统一管理HomeStack跟另一个activityStack中的Task,Google借助了mOnTopOfHome这个属性,虽然有两个mTaskHistory,但你可以根据ActivityTask.mOnTopOfHome的值把这两个mTaskHistory合成一个mTaskHistory。反过来说就是Android 4.4 把Android 4.4之前的一个ActivityStack中的所有Task拆分到两个ActivityStack中,拆分规则就是把launcher和后台Activity拆分到一个ActivityStack(HomeStack)中,其他的所有Task放在另一个ActivityStack中,但是所有的Task还是要维持像4.4之前只有一个mTaskHistory那样后进后出的逻辑,比如从launcher启动微信,微信又启动相机,那么在非HomeStack中相机Task在栈顶,launcher最低,然而launcher Task又不在这个非HomeStack中管理,这个时候就需要mOnTopOfHome来标注一下微信所在Task之下就应该是launcher所在的Task。这样就达到了所有Task的统一管理。
所以mOnTopOfHome应该这么理解:mOnTopOfHome=true表示在整个Task栈管理中,当前这个Task紧着的下一个Task就是launcher所在的Task。嗯,这么理解,上面的isActivityOverHome()就变得更加容易理解了。相信后面那5个函数理解起来也非常容易理解了,都不用看了。哈哈,太开心了有没有。
㈡、ActivityStack.removeTask()
boolean removeTask(TaskRecord task) {
final int taskNdx = mTaskHistory.indexOf(task);
final int topTaskNdx = mTaskHistory.size() - 1;
if (task.mOnTopOfHome && taskNdx < topTaskNdx) {
mTaskHistory.get(taskNdx + 1).mOnTopOfHome = true;
}
mTaskHistory.remove(task);
return mTaskHistory.isEmpty();
}
在整个Task管理中,如果移除的Task的mOnTopOfHome值为true,并且该Task不位于栈顶,那么肯定要把该Task的上一个Task.mOnTopOfHome设为true,不然逻辑就不对了。如果移除的Task位于栈顶或是mOnTopOfHome值不为true,那就直接remove掉即可。㈢、ActivityStack.moveTaskToBackLocked()
/**
* Worker method for rearranging history stack. Implements the function of moving all
* activities for a specific task (gathering them if disjoint) into a single group at the
* bottom of the stack.
*
* If a watcher is installed, the action is preflighted and the watcher has an opportunity
* to premeptively cancel the move.
*
* @param taskId The taskId to collect and move to the bottom.
* @return Returns true if the move completed, false if not.
*/
final boolean moveTaskToBackLocked(int taskId, ActivityRecord reason) {
Slog.i(TAG, "moveTaskToBack: " + taskId);
// If we have a watcher, preflight the move before committing to it. First check
// for *other* available tasks, but if none are available, then try again allowing the
// current task to be selected.
if (mStackSupervisor.isFrontStack(this) && mService.mController != null) { //①一般mController 为null,所以这个逻辑不执行。
ActivityRecord next = topRunningActivityLocked(null, taskId);
if (next == null) {
next = topRunningActivityLocked(null, 0);
}
if (next != null) {
// ask watcher if this is allowed
boolean moveOK = true;
try {
moveOK = mService.mController.activityResuming(next.packageName);
} catch (RemoteException e) {
mService.mController = null;
Watchdog.getInstance().setActivityController(null);
}
if (!moveOK) {
return false;
}
}
}
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare to back transition: task=" + taskId);
final TaskRecord tr = taskForIdLocked(taskId);
if (tr == null) {
return false;
}
mTaskHistory.remove(tr); //②将指定的Task移到mTaskHistory的最低端。
mTaskHistory.add(0, tr);
// There is an assumption that moving a task to the back moves it behind the home activity.
// We make sure here that some activity in the stack will launch home.
ActivityRecord lastActivity = null;
int numTasks = mTaskHistory.size();
for (int taskNdx = numTasks - 1; taskNdx >= 1; --taskNdx) { //③Task移到最低端还不够,还需一个Task.mOnTopOfHome设为true;
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.mOnTopOfHome) {
break;
}
if (taskNdx == 1) {
// Set the last task before tr to go to home.
task.mOnTopOfHome = true;
}
}
if (reason != null &&
(reason.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
ActivityRecord r = topRunningActivityLocked(null);
if (r != null) {
mNoAnimActivities.add(r);
}
} else {
mWindowManager.prepareAppTr