上一章讲解了,第三方app要切换用户ActivityManagerService的SwtichUser方法最终走到切换用户的最关键方法: UserController里面的startUser方法。前面叫做切换用户,而当前这一步这叫做启动新用户。其实切换到新用户就是启动新用户的过程。
本章将详细讲解startUser方法。
boolean startUser(
final int userId,
final boolean foreground,
@Nullable IProgressListener unlockListener) {
if (mInjector.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + INTERACT_ACROSS_USERS_FULL;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
//首先是加个打印,一共查询
Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
final long ident = Binder.clearCallingIdentity();
//核心功能第一步,再次查询,目标用户是否满足被切换的条件,逻辑代码和SwtichUser有重合的地方。
try {
final int oldUserId = getCurrentUserId();
//如果目标用户就是当前用户则不启动目标用户
if (oldUserId == userId) {
return true;
}
if (foreground) {
mInjector.clearAllLockedTasks("startUser");
}
//如果目标用户不存在则不启动目标用户
final UserInfo userInfo = getUserInfo(userId);
if (userInfo == null) {
Slog.w(TAG, "No user info for user #" + userId);
return false;
}
//如果目标用户不支持切换则不启动目标用户
if (foreground && userInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
//核心代码第二步,如果采用有提示的切换方式则冻屏。这里很多人不理解为什么要冻屏。这是为了保证dialog的显示时间和切换用户的时间保持一致。
//切换用户的时间是不确定的,受CPU等因素影响,每次切换用户时间都不太一样。我们既不希望用户还没切换的时候,提示的dialog就消失了,也不希望用户已经切换过去,dialog还在继续显示。
//那么最好的方案就是在dialog显示的时候把屏幕冻住,而后在用户切完结束的时候在把屏幕激活。
//所以,实际的di