最近处理了一个多用户切换过程黑屏一小会的问题,记录下切换用户的过程. 这里先分析6.0系统再分析7.0系统,7.0系统添加了directBoot特性略有不同
private boolean startUser(final int userId, final boolean foreground) {
// 1 检查权限INTERACT_ACROSS_USERS_FULL
if (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);
}
if (DEBUG_MU) Slog.i(TAG_MU, "starting userid:" + userId + " fore:" + foreground);
final long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
final int oldUserId = mCurrentUserId;
if (oldUserId == userId) {
return true;
}
//2 更新lock task mode
mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
"startUser", false);
//3 由于启动用户之前要创建用户,初始化一些用户的分区,数据,所以这里如果用户不存在说明还没有创建
final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
if (userInfo == null) {
Slog.w(TAG, "No user info for user #" + userId);
return false;
}
//4 对于前台启动的话设计到页面的切换,如果是个人资料用户,不算full user 不能前台启动
if (foreground && userInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
// 5 冻结屏幕,由于启动过程中涉及界面切换,有可能在切换过程中没有可以渲染的页面,用户就会看到黑屏,
// 冻结屏幕的作用就是截图显示,当屏幕冻结完成关闭截图surface,这样就不会出现黑屏
if (foreground) {
mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
R.anim.screen_user_enter);
}
boolean needStart = false;
//6 放到mStartedUsers结合中表示user已经启动,这里创建的UserState结构也是用于用户
// 切换过程中状态的设置
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
updateStartedUserArrayLocked();
needStart = true;
}
final Integer userIdInt = Integer.valueOf(userId);
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
if (foreground) {
mCurrentUserId = userId;
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
updateCurrentProfileIdsLocked();
//7 这里WMS会将其他user的页面设置成不可见,主要是通知SurfaceFlinger隐藏surface
mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
// 8 锁屏
mWindowManager.lockNow(null);
} else {
//对于后台启动则不设计界面的切换,
final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
updateCurrentProfileIdsLocked();
mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
mUserLru.remove(currentUserIdInt);
mUserLru.add(currentUserIdInt);
}
final UserState uss = mStartedUsers.get(userId);
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
if (uss.mState == UserState.STATE_STOPPING) {
// If we are stopping, we haven't sent ACTION_SHUTDOWN,
// so we can just fairly silently bring the user back from
// the almost-dead.
uss.mState = UserState.STATE_RUNNING;
updateStartedUserArrayLocked();
needStart = true;
} else if (uss.mState == UserState.STATE_SHUTDOWN) {
// This means ACTION_SHUTDOWN has been sent, so we will
// need to treat this as a new boot of the user.
uss.mState = UserState.STATE_BOOTING;
updateStartedUserArrayLocked();
needStart = true;
}
//10 通知系统服务们用户启动了,注意mHandler和system_service中处理广播的线程为同一个线程
if (uss.mState == UserState.STATE_BOOTING) {
// Booting up a new user, need to tell system services about it.
// Note that this is on the same handler as scheduling of broadcasts,
// which is important because it needs to go first.
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
}
// 11 这里发送了两个消息,REPORT_USER_SWITCH_MSG用于报告用户切换,这个消息的处理会通知其他
//关心切换用户的监听者 只有所有监听者处理完成消息后才会向下执行,向下执行会导致WMS的frozen状态
//结束, USER_SWITCH_TIMEOUT_MSG则是超时处理,framework中很多由于客户端不可控的处理都是采用
//超时处理进行善后
if (foreground) {
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
oldUserId));
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
uss.switching = true;
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
}
//12 首次启动发送ACTION_USER_STARTED广播
if (needStart){
// Send USER_STARTED broadcast
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, userId);
}
if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
if (userId != UserHandle.USER_OWNER) {
Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
//13 延迟初始化操作
onUserInitialized(uss, foreground, oldUserId, userId);
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
null, true, false, MY_PID, Process.SYSTEM_UID, userId);
uss.initializing = true;
} else {
//14 直接执行初始化
getUserManagerLocked().makeInitialized(userInfo.id);
}
}
if (foreground) {
if (!uss.initializing) {
//15初始化完成的直接启动界面
moveUserToForeground(uss, oldUserId, userId);
}
} else {
//后台启动则通知StackSupervisor
mStackSupervisor.startBackgroundUserLocked(userId, uss);
}
//16 ACTION_USER_STARTING广播,妈的有病先发ACTION_USER_STARTED后发ACTION_USER_STARTING
if (needStart) {
Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
broadcastIntentLocked(null, null, intent,
null, new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) throws RemoteException {
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return true;
}
整体流程如注释所写,值得注意的就两个状态的切换
1 initializing ,switching 这二者用于处管理界面frozen状态
2 mState 有四个状态,其中启动过程涉及两个状态STATE_BOOTING,STATE_RUNNING
先来看initializing ,switching状态的处理, initializing在发送ACTION_USER_INITIALIZE广播时候设置为true,处理该广播的逻辑如下
void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
synchronized (this) {
if (foreground) {
moveUserToForeground(uss, oldUserId, newUserId);
}
}
completeSwitchAndInitialize(uss, newUserId, true, false);
}
首先对于前台启动直接切换页面,然后执行completeSwitchAndInitialize 函数,注意在初始化过程中,只是设置参数clearInitializing为真,在进入completeSwitchAndInitialize函数中设置uss.initializing = false.
void completeSwitchAndInitialize(UserState uss, int newUserId,
boolean clearInitializing, boolean clearSwitching) {
boolean unfrozen = false;
synchronized (this) {
//1 设置uss.initializing = false;
if (clearInitializing) {
uss.initializing = false;
getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
}
// 2 设置uss.switching = false;
if (clearSwitching) {
uss.switching = false;
}
//3 切换和初始化都完成才结束frozen状态,尽量保证不出现黑屏
if (!uss.switching && !uss.initializing ) {
mWindowManager.stopFreezingScreen();
unfrozen = true;
}
}
//4报告切换完成
if (unfrozen) {
mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
newUserId, 0));
}
//5 停止其他访客账号
stopGuestUserIfBackground();
}
函数completeSwitchAndInitialize第三步骤可以看出既要完成switch还要完成initializing才会结束frozen状态,frozen状态有个好处,就是会显示截图,不至于出现黑屏.
对于uss.switching的设置则在REPORT_USER_SWITCH_MSG消息的处理中,还记得吗前台启动要发送REPORT_USER_SWITCH_MSG消息.
dispatchUserSwitch函数用于处理REPORT_USER_SWITCH_MSG消息
void dispatchUserSwitch(final UserState uss, final int oldUserId,
final int newUserId) {
final int N = mUserSwitchObservers.beginBroadcast();
if (N > 0) {
final IRemoteCallback callback = new IRemoteCallback.Stub() {
int mCount = 0;
@Override
public void sendResult(Bundle data) throws RemoteException {
synchronized (ActivityManagerService.this) {
if (mCurUserSwitchCallback == this) {
mCount++;
if (mCount == N) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
}
}
};
synchronized (this) {
uss.switching = true;
mCurUserSwitchCallback = callback;
}
for (int i=0; i<N; i++) {
try {
mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
newUserId, callback);
} catch (RemoteException e) {
}
}
} else {
synchronized (this) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
mUserSwitchObservers.finishBroadcast();
}
主要就是通知mUserSwitchObservers所管理的关心用户切换事件的事件订阅者处理事件,当事件处理完成会回调callback,当所有的订阅者都处理完成事件后则发送sendContinueUserSwitchLocked(uss, oldUserId, newUserId)消息完成后续处理,而sendContinueUserSwitchLocked(uss, oldUserId, newUserId)就是要进行uss.switching状态的切换, 注意dispatchUserSwitch函数中还会设置uss.switching = true; 这里显示已经晚了,这是一个bug
void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
mCurUserSwitchCallback = null;
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
oldUserId, newUserId, uss));
}
sendContinueUserSwitchLocked 函数移除USER_SWITCH_TIMEOUT_MSG消息,说明用户切换没有超时,这里可见超时还是针对不可控的客户端来做的,并且发送了一个CONTINUE_USER_SWITCH_MSG消息.
CONTINUE_USER_SWITCH_MSG消息的处理在continueUserSwitch函数中完成
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
completeSwitchAndInitialize(uss, newUserId, false, true);
}
这里还是执行了completeSwitchAndInitialize函数只不过与初始化过程不同的是设置clearSwitching为真,这样completeSwitchAndInitialize函数就会设置uss.switching为false,从而就可以结束frozen过程了.
我们在看看超时的处理,
void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (this) {
Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
这里直接执行sendContinueUserSwitchLocked函数,发送CONTINUE_USER_SWITCH_MSG,不在等待所有客户端处理完成了.看到这里我们也知道sendContinueUserSwitchLocked函数为什么设置mCurUserSwitchCallback=null了.
对于界面的切换我们还要关注一个点,moveUserToForeground
void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
if (homeInFront) {
startHomeActivityLocked(newUserId, "moveUserToFroreground");
} else {
mStackSupervisor.resumeTopActivitiesLocked();
}
EventLogTags.writeAmSwitchUser(newUserId);
getUserManagerLocked().onUserForeground(newUserId);
sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
}
moveUserToForeground函数有两个地方调用, 第一点是在用户初始化的函数moveUserToForeground中,如果是前台启动则会调用moveUserToForeground函数, 另外一个地方是startUser过程中,如果用户已经初始化完成,并且是前台启动直接moveUserToForeground进行界面切换.
moveUserToForeground函数中getUserManagerLocked().onUserForeground(newUserId);调用只是用于持久化user数据,而比较重要的函数是sendUserSwitchBroadcastsLocked用于告诉其他应用,user界面启动完成可以做界面操作了.
void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
long ident = Binder.clearCallingIdentity();
try {
Intent intent;
//1 通知旧用户以及他的个人资料用户进入后台
if (oldUserId >= 0) {
// Send USER_BACKGROUND broadcast to all profiles of the outgoing user
List<UserInfo> profiles = mUserManager.getProfiles(oldUserId, false);
int count = profiles.size();
for (int i = 0; i < count; i++) {
int profileUserId = profiles.get(i).id;
intent = new Intent(Intent.ACTION_USER_BACKGROUND);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
}
}
//2 通知新用户以及个人资料进入前台
if (newUserId >= 0) {
// Send USER_FOREGROUND broadcast to all profiles of the incoming user
List<UserInfo> profiles = mUserManager.getProfiles(newUserId, false);
int count = profiles.size();
for (int i = 0; i < count; i++) {
int profileUserId = profiles.get(i).id;
intent = new Intent(Intent.ACTION_USER_FOREGROUND);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
}
//3 通知用户切换完成
intent = new Intent(Intent.ACTION_USER_SWITCHED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
由此可见启动用户还是比较简单的,难点在于用户的创建和数据空间的准备以及分裂. 下面我们再来看看7.0中有何不同
boolean startUser(final int userId, final boolean foreground) {
// 1 检查权限
if (mService.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);
}
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mService) {
final int oldUserId = mCurrentUserId;
if (oldUserId == userId) {
return true;
}
// 2 Lock mode处理
mService.mStackSupervisor.setLockTaskModeLocked(null,
ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false);
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;
}
//3 前台启动冻结屏幕
if (foreground) {
mService.mWindowManager.startFreezingScreen(
R.anim.screen_user_exit, R.anim.screen_user_enter);
}
boolean needStart = false;
// If the user we are switching to is not currently started, then
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
UserState userState = new UserState(UserHandle.of(userId));
mStartedUsers.put(userId, userState);
getUserManagerInternal().setUserState(userId, userState.state);
updateStartedUserArrayLocked();
needStart = true;
}
final UserState uss = mStartedUsers.get(userId);
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
// 4 前台启动 更新WMS关闭老用户界面,锁屏
if (foreground) {
mCurrentUserId = userId;
mService.updateUserConfigurationLocked();
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
updateCurrentProfileIdsLocked();
mService.mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
// Once the internal notion of the active user has switched, we lock the device
// with the option to show the user switcher on the keyguard.
mService.mWindowManager.lockNow(null);
} else {
final Integer currentUserIdInt = mCurrentUserId;
updateCurrentProfileIdsLocked();
mService.mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
mUserLru.remove(currentUserIdInt);
mUserLru.add(currentUserIdInt);
}
// Make sure user is in the started state. If it is currently
// stopping, we need to knock that off.
if (uss.state == UserState.STATE_STOPPING) {
// If we are stopping, we haven't sent ACTION_SHUTDOWN,
// so we can just fairly silently bring the user back from
// the almost-dead.
uss.setState(uss.lastState);
getUserManagerInternal().setUserState(userId, uss.state);
updateStartedUserArrayLocked();
needStart = true;
} else if (uss.state == UserState.STATE_SHUTDOWN) {
// This means ACTION_SHUTDOWN has been sent, so we will
// need to treat this as a new boot of the user.
uss.setState(UserState.STATE_BOOTING);
getUserManagerInternal().setUserState(userId, uss.state);
updateStartedUserArrayLocked();
needStart = true;
}
if (uss.state == UserState.STATE_BOOTING) {
// Give user manager a chance to propagate user restrictions
// to other services and prepare app storage
getUserManager().onBeforeStartUser(userId);
// Booting up a new user, need to tell system services about it.
// Note that this is on the same handler as scheduling of broadcasts,
// which is important because it needs to go first.
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
}
// 5 前台启动设置超时和REPORT_USER_SWITCH_MSG消息报告切换用户给客户端
if (foreground) {
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
oldUserId));
mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
}
//6 ACTION_USER_STARTED广播
if (needStart) {
// Send USER_STARTED broadcast
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mService.broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, userId);
}
//7 直接启动界面
if (foreground) {
moveUserToForegroundLocked(uss, oldUserId, userId);
} else {
//8 后台启动直接完成启动
mService.mUserController.finishUserBoot(uss);
}
//9 ACTION_USER_STARTING广播
if (needStart) {
Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mService.broadcastIntentLocked(null, null, intent,
null, new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) throws RemoteException {
}
}, 0, null, null,
new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return true;
}
这里与6.0不同的地方是直接启动界面,没有用户初始化的过程,那么我们再看看REPORT_USER_SWITCH_MSG消息的处理.
还是在dispatchUserSwitch函数中
void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
final int observerCount = mUserSwitchObservers.beginBroadcast();
if (observerCount > 0) {
final IRemoteCallback callback = new IRemoteCallback.Stub() {
int mCount = 0;
@Override
public void sendResult(Bundle data) throws RemoteException {
synchronized (mService) {
if (mCurUserSwitchCallback == this) {
mCount++;
if (mCount == observerCount) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
}
}
};
synchronized (mService) {
uss.switching = true;
mCurUserSwitchCallback = callback;
}
for (int i = 0; i < observerCount; i++) {
try {
mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
newUserId, callback);
} catch (RemoteException e) {
}
}
} else {
synchronized (mService) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
mUserSwitchObservers.finishBroadcast();
}
和6.0中是一致的,sendContinueUserSwitchLocked函数也是一致的
void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
mCurUserSwitchCallback = null;
mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG,
oldUserId, newUserId, uss));
}
continueUserSwitch函数则大不相同
void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
synchronized (mService) {
mService.mWindowManager.stopFreezingScreen();
}
uss.switching = false;
mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
newUserId, 0));
stopGuestOrEphemeralUserIfBackground();
stopBackgroundUsersIfEnforced(oldUserId);
}
不再判断初始化流程,直接解冻屏幕,可以看出整个流程提前切换了界面和提前了解冻屏幕.
另外超时的处理也是一样的
finishUserBoot函数
private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
final int userId = uss.mHandle.getIdentifier();
Slog.d(TAG, "Finishing user boot " + userId);
synchronized (mService) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(userId) != uss) return;
// We always walk through all the user lifecycle states to send
// consistent developer events. We step into RUNNING_LOCKED here,
// but we might immediately step into RUNNING below if the user
// storage is already unlocked.
if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
getUserManagerInternal().setUserState(userId, uss.state);
int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
MetricsLogger.histogram(mService.mContext, "framework_locked_boot_completed",
uptimeSeconds);
Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null,
new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
// We need to delay unlocking managed profiles until the parent user
// is also unlocked.
if (getUserManager().isManagedProfile(userId)) {
final UserInfo parent = getUserManager().getProfileParent(userId);
if (parent != null
&& isUserRunningLocked(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) {//父用户解锁则子用户解锁
Slog.d(TAG, "User " + userId + " (parent " + parent.id
+ "): attempting unlock because parent is unlocked");
maybeUnlockUser(userId);
} else {
String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
Slog.d(TAG, "User " + userId + " (parent " + parentId
+ "): delaying unlock because parent is locked");
}
} else {
//不是个人资料用户解锁
maybeUnlockUser(userId);
}
}
}
这里可以看到用户启动多了好几种状态,都是为FPE(基于文件的加密)准备的:
public final static int STATE_BOOTING = 0;
// User is in the locked state.
public final static int STATE_RUNNING_LOCKED = 1;
// User is in the unlocking state.
public final static int STATE_RUNNING_UNLOCKING = 2;
// User is in the running state.
public final static int STATE_RUNNING_UNLOCKED = 3;
// User is in the initial process of being stopped.
public final static int STATE_STOPPING = 4;
// User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
public final static int STATE_SHUTDOWN = 5;
首先设置用户状态为STATE_RUNNING_LOCKED,锁定状态,然后发送启动完成广播ACTION_LOCKED_BOOT_COMPLETED
boolean maybeUnlockUser(final int userId) {
// Try unlocking storage using empty token
return unlockUserCleared(userId, null, null, null);
}
boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
IProgressListener listener) {
synchronized (mService) { //1 解锁文件
// TODO Move this block outside of synchronized if it causes lock contention
if (!StorageManager.isUserKeyUnlocked(userId)) {
final UserInfo userInfo = getUserInfo(userId);
final IMountService mountService = getMountService();
try {
// We always want to unlock user storage, even user is not started yet
mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret);
} catch (RemoteException | RuntimeException e) {
Slog.w(TAG, "Failed to unlock: " + e.getMessage());
}
}
// Bail if user isn't actually running, otherwise register the given
// listener to watch for unlock progress
final UserState uss = mStartedUsers.get(userId);
if (uss == null) { //2通知解锁
notifyFinished(userId, listener);
return false;
} else {
uss.mUnlockProgress.addListener(listener);
}
finishUserUnlocking(uss); //3解锁
// We just unlocked a user, so let's now attempt to unlock any
// managed profiles under that user.
for (int i = 0; i < mStartedUsers.size(); i++) { //解锁子用户
final int testUserId = mStartedUsers.keyAt(i);
final UserInfo parent = getUserManager().getProfileParent(testUserId);
if (parent != null && parent.id == userId && testUserId != userId) {
Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
+ "): attempting unlock because parent was just unlocked");
maybeUnlockUser(testUserId);
}
}
}
return true;
}
finishUserUnlocking为实际解锁的函数,只是到unLocking状态,还模拟了一个进度……. 最后发送SYSTEM_USER_UNLOCK_MSG消息处理解锁
private void finishUserUnlocking(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
synchronized (mService) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
// Only keep marching forward if user is actually unlocked
if (!StorageManager.isUserKeyUnlocked(userId)) return;
if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
getUserManagerInternal().setUserState(userId, uss.state);
uss.mUnlockProgress.start();
// Prepare app storage before we go any further
uss.mUnlockProgress.setProgress(5,
mService.mContext.getString(R.string.android_start_title));
mUserManager.onBeforeUnlockUser(userId);
uss.mUnlockProgress.setProgress(20);
// Dispatch unlocked to system services; when fully dispatched,
// that calls through to the next "unlocked" phase
mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
.sendToTarget();
}
}
}
case SYSTEM_USER_UNLOCK_MSG: {
final int userId = msg.arg1;
mSystemServiceManager.unlockUser(userId); //1 通知system_server
synchronized (ActivityManagerService.this) {
mRecentTasks.loadUserRecentsLocked(userId); //2加载多任务
}
if (userId == UserHandle.USER_SYSTEM) {
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); //3启动没有设置directboot的常驻进程,这里磁盘已经解密,可以启动了
}
installEncryptionUnawareProviders(userId);//安装非directBoot的provider
mUserController.finishUserUnlocked((UserState) msg.obj); //4 启动完成
break;
}
void finishUserUnlocked(final UserState uss) {
final int userId = uss.mHandle.getIdentifier();
synchronized (mService) {
// Bail if we ended up with a stale user
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
// Only keep marching forward if user is actually unlocked
if (!StorageManager.isUserKeyUnlocked(userId)) return;
if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) { //1更新解锁状态
getUserManagerInternal().setUserState(userId, uss.state);
uss.mUnlockProgress.finish();
// Dispatch unlocked to external apps
//2 解锁广播
final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
unlockedIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null,
null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
userId);
if (getUserInfo(userId).isManagedProfile()) { //2发送子用户ACTION_MANAGED_PROFILE_UNLOCKED解锁广播
UserInfo parent = getUserManager().getProfileParent(userId);
if (parent != null) {
final Intent profileUnlockedIntent = new Intent(
Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
profileUnlockedIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, profileUnlockedIntent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID,
parent.id);
}
}
// Send PRE_BOOT broadcasts if user fingerprint changed; we
// purposefully block sending BOOT_COMPLETED until after all
// PRE_BOOT receivers are finished to avoid ANR'ing apps
final UserInfo info = getUserInfo(userId);
if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
//ota升级先发送Intent.ACTION_PRE_BOOT_COMPLETED广播,注意这个广播只在ota后发送
new PreBootBroadcaster(mService, userId, null) {
@Override
public void onFinished() {
finishUserUnlockedCompleted(uss); //3开机广播
}
}.sendNext();
} else {
finishUserUnlockedCompleted(uss);//3开机广播
}
}
}
}
private void finishUserUnlockedCompleted(UserState uss) {
final int userId = uss.mHandle.getIdentifier();
synchronized (mService) {
// Bail if we ended up with a stale user//1 检查状态,当前用户凭证已经失效直接返回
if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
final UserInfo userInfo = getUserInfo(userId);
if (userInfo == null) {
return;
}
// Only keep marching forward if user is actually unlocked
if (!StorageManager.isUserKeyUnlocked(userId)) return; //2 检查解密状态
// Remember that we logged in
mUserManager.onUserLoggedIn(userId);
if (!userInfo.isInitialized()) { //3 非system用户初始化操作
if (userId != UserHandle.USER_SYSTEM) {
Slog.d(TAG, "Initializing user #" + userId);
Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
// Note: performReceive is called with mService lock held
getUserManager().makeInitialized(userInfo.id);
}
}, 0, null, null, null, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, userId);
}
}
Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
//4 开机广播 这里可以看到FBE影响开机广播
MetricsLogger.histogram(mService.mContext, "framework_boot_completed", uptimeSeconds);
final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null,
new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
}
public void makeInitialized(int userId) {
checkManageUsersPermission("makeInitialized");
boolean scheduleWriteUser = false;
UserData userData;
synchronized (mUsersLock) {
userData = mUsers.get(userId);
if (userData == null || userData.info.partial) {
Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
return;
}
if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
userData.info.flags |= UserInfo.FLAG_INITIALIZED;
scheduleWriteUser = true;
}
}
if (scheduleWriteUser) {
scheduleWriteUser(userData);
}
}
makeInitialized韩式只是用于持久化和设置 UserInfo.FLAG_INITIALIZED标志。
对于原始user SYSTEM_USER ,则是在WMS初始化完成之后,在bootAnimationComplete函数回调完成的
@Override
public void bootAnimationComplete() {
final boolean callFinishBooting;
synchronized (this) {
callFinishBooting = mCallFinishBooting;
mBootAnimationComplete = true;
}
if (callFinishBooting) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
finishBooting();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
再次总结下整个流程,主要分两路
1 REPORT_USER_SWITCH_MSG 用于switch流程,调用客户端的注册在mUserSwitchObservers中的事件订阅者,在MainHandler中执行
2 REPORT_USER_SWITCH_COMPLETE_MSG
广播,有可能不在MainHandler中执行,因为包含从finshBoradcast中执行的情况,但是会保证广播有序执行
1 Intent.ACTION_USER_STARTED广播
2 Intent.ACTION_USER_INITIALIZE 用于初始化
3 Intent.ACTION_USER_STARTING
4 Intent.ACTION_USER_BACKGROUND
5 Intent.ACTION_USER_FOREGROUND
6 Intent.ACTION_USER_SWITCHED