Profile User啟動的主要邏輯在UserController#startUser
客戶端啟動的邏輯為:
iActivityManager.startUserInBackground(userId);
主要調(diào)用邏輯代碼如下:
UserController#startUser
boolean startUser(
final int userId,
final boolean foreground,
@Nullable IProgressListener unlockListener) {
//1.檢查權(quán)限
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();
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;
}
//2.manage profile不允許前臺啟動
if (foreground && userInfo.isManagedProfile()) {
Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
if (foreground && mUserSwitchUiEnabled) {
mInjector.getWindowManager().startFreezingScreen(
R.anim.screen_user_exit, R.anim.screen_user_enter);
}
boolean needStart = false;
boolean updateUmState = false;
UserState uss;
// If the user we are switching to is not currently started, then
// we need to start it now.
synchronized (mLock) {
//3.創(chuàng)建該用戶的UserState對象嗤攻,用于后續(xù)啟動期間,各個狀態(tài)的保存和切換
//第一次執(zhí)行的話,該對象為null,新創(chuàng)建的對象的狀態(tài)處于初始狀態(tài)0(BOOTING)
uss = mStartedUsers.get(userId);
if (uss == null) {
uss = new UserState(UserHandle.of(userId));
uss.mUnlockProgress.addListener(new UserProgressListener());
mStartedUsers.put(userId, uss);
updateStartedUserArrayLU();
needStart = true;
updateUmState = true;
} else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) {
Slog.i(TAG, "User #" + userId
+ " is shutting down - will start after full stop");
mHandler.post(() -> startUser(userId, foreground, unlockListener));
return true;
}
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
}
if (unlockListener != null) {
uss.mUnlockProgress.addListener(unlockListener);
}
if (updateUmState) {
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
}
if (foreground) {
// Make sure the old user is no longer considering the display to be on.
mInjector.reportGlobalUsageEventLocked(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
synchronized (mLock) {
mCurrentUserId = userId;
mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
}
mInjector.updateUserConfiguration();
updateCurrentProfileIds();
mInjector.getWindowManager().setCurrentUser(userId, getCurrentProfileIds());
mInjector.reportCurWakefulnessUsageEvent();
// 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.
if (mUserSwitchUiEnabled) {
mInjector.getWindowManager().setSwitchingUser(true);
mInjector.getWindowManager().lockNow(null);
}
} else {
final Integer currentUserIdInt = mCurrentUserId;
updateCurrentProfileIds();
//4. 保存一個[userid,profileGroupId]數(shù)組,profileGroupId是用戶創(chuàng)建階段完成初始化賦值的
mInjector.getWindowManager().setCurrentProfileIds(getCurrentProfileIds());
synchronized (mLock) {
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);
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
synchronized (mLock) {
updateStartedUserArrayLU();
}
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);
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
synchronized (mLock) {
updateStartedUserArrayLU();
}
needStart = true;
}
//5. 發(fā)送SYSTEM_USER_START_MSG消息侦啸,回調(diào)系統(tǒng)指所有systemServer的onStartUser方法,通知user啟動
if (uss.state == UserState.STATE_BOOTING) {
// Give user manager a chance to propagate user restrictions
// to other services and prepare app storage
mInjector.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));
}
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_MS);
}
if (needStart) {
//6. Send ACTION_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);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, userId);
}
if (foreground) {
moveUserToForeground(uss, oldUserId, userId);
} else {
//7. 執(zhí)行Boot操作丧枪,會執(zhí)行執(zhí)行user啟動的各個狀態(tài)光涂,并報個每個階段的進度
finishUserBoot(uss);
}
if (needStart) {
//8.發(fā)送ACTION_USER_STARTING廣播
Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);//靜態(tài)注冊的廣播(AndroidMenifest.xml中注冊的)不能接受該廣播
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(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;
}
啟動的流程總結(jié)如下
- 檢查啟動該用戶的是否具有INTERACT_ACROSS_USERS_FULL權(quán)限,如果沒有拧烦,直接拋出異常忘闻,應(yīng)用崩潰
- 檢查改profile user是否是后臺啟動,如果是前臺啟動恋博,則直接返回false齐佳;這也是profile user和普通user的區(qū)別,不同user可用通過
switchUser方法债沮,切換到前臺用戶 - 創(chuàng)建改用戶對象的UserState炼吴,第一次啟動時,該用戶的狀態(tài)為0(STATE_BOOTING)
- 保存主用戶和該用戶對應(yīng)的profileGroupid的對應(yīng)關(guān)系疫衩,維護一個{userid,profileGroupId}的數(shù)據(jù)結(jié)構(gòu)
- 發(fā)送SYSTEM_USER_START_MSG消息硅蹦,回調(diào)系統(tǒng)指所有systemServer的onStartUser方法,通知他們,該user啟動了
- Send ACTION_USER_STARTED broadcast
該廣播特性:只允許動態(tài)廣播監(jiān)聽童芹;接受者具有FOREGROUND優(yōu)先級 - 執(zhí)行finishUserBoot操作命爬,結(jié)束Boot狀態(tài),詳細過程見下面的finishUserBoot章節(jié)
- 發(fā)送ACTION_USER_STARTING廣播
下面看下辐脖,以上流程的中饲宛,比較重要的階段的代碼邏輯
finishUserBoot
后臺用戶才會執(zhí)行該操作,我們創(chuàng)建的profile User是一個ManagedProfile嗜价,并且必須后臺啟動艇抠;
改方法的主要代理邏輯是執(zhí)行user啟動的各個狀態(tài),并報個每個階段的進度
將該用戶的狀態(tài)從STATE_BOOTING--->STATE_RUNNING_LOCKED久锥;狀態(tài)設(shè)置成功的情況系家淤,執(zhí)行以下操作
發(fā)送消息REPORT_LOCKED_BOOT_COMPLETE_MSG,告訴其他注冊了IUserSwitchObserver的監(jiān)聽模塊瑟由,該用戶完成了BootComplete
發(fā)送廣播ACTION_LOCKED_BOOT_COMPLETED-
執(zhí)行maybeUnlockUser操作
首先絮重,執(zhí)行解鎖用戶存儲操作
主要代碼邏輯是通過Ext4Crypt.cpp的e4crypt_unlock_user_key方法,設(shè)置profile user的存儲為unlock狀態(tài)TODO: rename to 'install' for consistency, and take flags to know which keys to install bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex, const std::string& secret_hex) { LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial << " token_present=" << (token_hex != "!"); if (e4crypt_is_native()) { if (s_ce_key_raw_refs.count(user_id) != 0) { LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id; return true; } std::string token, secret; if (!parse_hex(token_hex, &token)) return false; if (!parse_hex(secret_hex, &secret)) return false; android::vold::KeyAuthentication auth(token, secret); if (!read_and_install_user_ce_key(user_id, auth)) { LOG(ERROR) << "Couldn't read key for " << user_id; return false; } } else { // When in emulation mode, we just use chmod. However, we also // unlock directories when not in emulation mode, to bring devices // back into a known-good state. if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) || !emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) || !emulated_unlock(android::vold::BuildDataMediaCePath("", user_id), 0770) || !emulated_unlock(android::vold::BuildDataUserCePath("", user_id), 0771)) { LOG(ERROR) << "Failed to unlock user " << user_id; return false; } } return true; }
其次歹苦,執(zhí)行finishUserUnlocking操作
改操作的主要路邏輯如下:
1. 開始進度report,報告unlock進度5%;
2. 回調(diào)UserManager的onBeforeUnlockUser方法青伤,
3. 將profile user的狀態(tài)為從STATE_RUNNING_LOCKED--->STATE_RUNNING_UNLOCKING
4. 將profile user的狀態(tài)更顯到UMS的mUserStates中去
5. report profile user unlock進度20%
6. 處理SYSTEM_USER_UNLOCK_MSG消息
調(diào)用系統(tǒng)中所有systemServer的unlockUser方法 更改profile user的狀態(tài)STATE_RUNNING_UNLOCKING-->STATE_RUNNING_UNLOCKED 將profile user的狀態(tài)更顯到UMS的mUserStates中去 報告unlock進度100% 發(fā)送ACTION_USER_UNLOCKED廣播 發(fā)送ACTION_MANAGED_PROFILE_UNLOCKED廣播 發(fā)送ACTION_USER_INITIALIZE廣播 發(fā)送ACTION_BOOT_COMPLETED廣播
startUser階段,各個系統(tǒng)廣播發(fā)送順序
- Intent#ACTION_USER_STARTED} sent to registered receivers of the new user
- Intent#ACTION_USER_BACKGROUND} sent to registered receivers of the outgoing user and all profiles of this user. Sent only if {@code foreground} parameter is true
- Intent#ACTION_USER_FOREGROUND} sent to registered receivers of the new user and all profiles of this user. Sent only if {@code foreground} parameter is true
以上兩個廣播殴瘦,只在該方法進行了發(fā)送狠角。
UserController.java
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
long ident = Binder.clearCallingIdentity();
try {
Intent intent;
if (oldUserId >= 0) {
// Send USER_BACKGROUND broadcast to all profiles of the outgoing user
List<UserInfo> profiles = mInjector.getUserManager().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);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, profileUserId);
}
}
if (newUserId >= 0) {
// Send USER_FOREGROUND broadcast to all profiles of the incoming user
List<UserInfo> profiles = mInjector.getUserManager().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);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, profileUserId);
}
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);
mInjector.broadcastIntent(intent,
null, null, 0, null, null,
new String[] {android.Manifest.permission.MANAGE_USERS},
AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
UserHandle.USER_ALL);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
該方法有兩個調(diào)用場景
第一個:AMS#systemReady, mUserController.sendUserSwitchBroadcasts(-1, currentUserId);蚪腋,因為oldUserId為-1丰歌,因此只會發(fā)送ACTION_USER_FOREGROUND廣播
第二個:在startUser的時候,這個場景,只有foreground為true的時候才會發(fā)送屉凯。兩個廣播都會發(fā)送立帖,因為一個user切換到前臺,必然伴隨另一個user切換到后臺悠砚;兩個廣播攜帶的userid不一樣(不是廢話嗎)
if (foreground) {
moveUserToForeground(uss, oldUserId, userId);-->sendUserSwitchBroadcasts
} else {
finishUserBoot(uss);
}
Intent#ACTION_USER_SWITCHED} sent to registered receivers of the new user.Sent only if {@code foreground} parameter is true
也是在sendUserSwitchBroadcasts方法中晓勇,場景同上面兩個廣播
//Intent#ACTION_USER_STARTING} 注釋找那個標注,這個廣播應(yīng)該在這個位置哩簿,實際代碼中實在startUser的最后階段發(fā)送的Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new user
Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user
Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new user. Sent only when the user is booting after a system update.
Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of thenew user. Sent only the first time a user is starting.
Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the newuser. Indicates that the user has finished booting.
Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers of the new fg user
擴展知識
有序廣播
有序廣播宵蕉,即從優(yōu)先級別最高的廣播接收器開始接收,接收完了如果沒有丟棄节榜,就下傳給下一個次高優(yōu)先級別的廣播接收器進行處理羡玛,依次類推,直到最后宗苍。如果多個應(yīng)用程序設(shè)置的優(yōu)先級別相同稼稿,則誰先注冊的廣播薄榛,誰就可以優(yōu)先接收到廣播。
通過Context.sendorderBroadCast()方法來發(fā)送
sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras)
其中的參數(shù)resultReceiver让歼,可以自己重寫一個類敞恋,作為一個最終的receive 最后都能夠接收到廣播,最終的receiver 不需要再清單文件里面配置谋右,initialData可以作為傳輸?shù)臄?shù)據(jù)
廣播可以被終止硬猫,數(shù)據(jù)傳輸過程中可以被修改。