多用戶創(chuàng)建
UserManager#createProfile源碼流程
@SystemApi
@RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
Manifest.permission.CREATE_USERS})
@UserHandleAware
public @Nullable UserHandle createProfile(@NonNull String name, @NonNull String userType,
@NonNull Set<String> disallowedPackages) throws UserOperationException {
try {
return mService.createProfileForUserWithThrow(name, userType, 0,
mUserId, disallowedPackages.toArray(
new String[disallowedPackages.size()])).getUserHandle();
} catch (ServiceSpecificException e) {
return returnNullOrThrowUserOperationException(e,
mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
UserManagerService#createProfileForUserWithThrow
1.為新用戶創(chuàng)建一個新的userId (新用戶的userId從10開始遞增)
private @NonNull UserInfo createUserInternalUncheckedNoTracing(
@Nullable String name, @NonNull String userType, @UserInfoFlag int flags,
@UserIdInt int parentId, boolean preCreate, @Nullable String[] disallowedPackages,
@NonNull TimingsTraceAndSlog t, @Nullable Object token)
throws UserManager.CheckedUserOperationException {
...
userId = getNextAvailableId();
}
2.存儲新用戶信息。構(gòu)造包含新用戶信息的UserData,并固化到 /data/system/users/${userId}.xml文件中
private void writeUserLP(UserData userData) {
if (DBG) {
debug("writeUserLP " + userData);
}
try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) {
FileOutputStream fos = null;
try {
fos = userFile.startWrite();
writeUserLP(userData, fos);
userFile.finishWrite(fos);
} catch (Exception ioe) {
Slog.e(LOG_TAG, "Error writing user info " + userData.info.id, ioe);
userFile.failWrite(fos);
}
}
}
3:將新創(chuàng)建新userId固化到 "/data/system/users/userlist.xml"文件中
private void writeUserListLP() {
if (DBG) {
debug("writeUserList");
}
try (ResilientAtomicFile file = getUserListFile()) {
FileOutputStream fos = null;
try {
fos = file.startWrite();
final TypedXmlSerializer serializer = Xml.resolveSerializer(fos);
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
true);
serializer.startTag(null, TAG_USERS);
serializer.attributeInt(null, ATTR_NEXT_SERIAL_NO, mNextSerialNumber);
serializer.attributeInt(null, ATTR_USER_VERSION, mUserVersion);
serializer.attributeInt(null, ATTR_USER_TYPE_VERSION, mUserTypeVersion);
...
}
3、準(zhǔn)備文件系統(tǒng)
通過vold(Android存儲守護進程)為新用戶進行文件系統(tǒng)加密;
創(chuàng)建/data/misc/users/{userId}、/data/user_ce/${userId}等等。
t.traceBegin("createUserStorageKeys");
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.createUserStorageKeys(userId, userInfo.isEphemeral());
t.traceEnd();
// Only prepare DE storage here. CE storage will be prepared later, when the user is
// unlocked. We do this to ensure that CE storage isn't prepared before the CE key is
// saved to disk. This also matches what is done for user 0.
t.traceBegin("prepareUserData");
mUserDataPreparer.prepareUserData(userInfo, StorageManager.FLAG_STORAGE_DE);
t.traceEnd();
4、生成一個唯一的合成密碼,通常通過復(fù)雜的密碼生成算法創(chuàng)建,用于加密和解密用戶數(shù)據(jù)。
LockSettingsService
SyntheticPassword initializeSyntheticPassword(int userId) {
synchronized (mSpManager) {
Slogf.i(TAG, "Initializing synthetic password for user %d", userId);
Preconditions.checkState(getCurrentLskfBasedProtectorId(userId) ==
SyntheticPasswordManager.NULL_PROTECTOR_ID,
"Cannot reinitialize SP");
final SyntheticPassword sp = mSpManager.newSyntheticPassword(userId);
final long protectorId = mSpManager.createLskfBasedProtector(getGateKeeperService(),
LockscreenCredential.createNone(), sp, userId);
setCurrentLskfBasedProtectorId(protectorId, userId);
setCeStorageProtection(userId, sp);
if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
}
onSyntheticPasswordCreated(userId, sp);
Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
return sp;
}
}
void createNewUser(int userId, @Nullable Set<String> userTypeInstallablePackages,
String[] disallowedPackages) {
try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) {
mSettings.createNewUserLI(this, mInstaller, userId,
userTypeInstallablePackages, disallowedPackages);
}
synchronized (mLock) {
scheduleWritePackageRestrictions(userId);
scheduleWritePackageListLocked(userId);
mAppsFilter.onUserCreated(snapshotComputer(), userId);
}
}
6、通知PMS為新用戶和應(yīng)用賦予默認的權(quán)限
PackageManagerService
void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) {
if (DEBUG_PERMISSIONS) {
Slog.d(TAG, "onNewUserCreated(id=" + userId
+ ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
}
if (!convertedFromPreCreated || !readPermissionStateForUser(userId)) {
mPermissionManager.onUserCreated(userId);
mLegacyPermissionManager.grantDefaultPermissions(userId);
mPermissionManager.setDefaultPermissionGrantFingerprint(Build.FINGERPRINT, userId);
mDomainVerificationManager.clearUser(userId);
}
}
7、發(fā)送 "ACTION_USER_ADDED"廣播,通知新用戶創(chuàng)建完成
UserManagerService
private void dispatchUserAdded(@NonNull UserInfo userInfo, @Nullable Object token) {
//...then external ones
Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
addedIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
// In HSUM, MainUser might be created before PHASE_ACTIVITY_MANAGER_READY has been sent.
addedIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
// Also, add the UserHandle for mainline modules which can't use the @hide
// EXTRA_USER_HANDLE.
addedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userInfo.id));
mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
android.Manifest.permission.MANAGE_USERS);
MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED
: (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1);
通過以上工作流程可以看到,多用戶其實是系統(tǒng)為應(yīng)用的data目錄分配了一份不同且獨立的存儲空間,不同用戶下的存儲空間互不影響且沒有權(quán)限訪問。同時,系統(tǒng)中的AMS、PMS、WMS等各大服務(wù)都會針對userId/UserHandle進行多用戶適配,并在用戶啟動、切換、停止、刪除等生命周期時做出相應(yīng)策略的改變。通過以上,Android創(chuàng)造出來一個虛擬的多用戶運行環(huán)境。
多用戶啟切換
多用戶切換最終調(diào)用到UserControl#startUserInternal,多用戶切換時userStartMode = USER_START_MODE_FOREGROUND,后臺啟動時userStartMode =
USER_START_MODE_BACKGROUND_VISIBLE, 這里主要分析startUserInternal方法
1.如果是啟動前臺用戶,則通知AMS清除所有鎖定任務(wù),并請求結(jié)束LockTask模式
if (foreground) {
t.traceBegin("clearAllLockedTasks");
mInjector.clearAllLockedTasks("startUser");
t.traceEnd();
}
2.獲取目標(biāo)用戶的相關(guān)信息 ,經(jīng)過一系列邏輯判斷,最后在開始時將目標(biāo)用戶分配給顯示器,返回分配是否成功
final UserInfo userInfo = getUserInfo(userId);
t.traceEnd();
if (userInfo == null) {
Slogf.w(TAG, "No user info for user #" + userId);
return false;
}
if (foreground && userInfo.isProfile()) {
Slogf.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
return false;
}
if ((foreground || onSecondaryDisplay) && userInfo.preCreated) {
Slogf.w(TAG, "Cannot start pre-created user #" + userId + " in foreground or on "
+ "secondary display");
return false;
}
t.traceBegin("assignUserToDisplayOnStart");
int result = mInjector.getUserManagerInternal().assignUserToDisplayOnStart(userId,
userInfo.profileGroupId, userStartMode, displayId);
t.traceEnd();
if (result == USER_ASSIGNMENT_RESULT_FAILURE) {
Slogf.e(TAG, "%s user(%d) / display (%d) assignment failed: %s",
userStartModeToString(userStartMode), userId, displayId,
userAssignmentResultToString(result));
return false;
}
3.為目標(biāo)用戶創(chuàng)建UserState,并放入mStartedUsers數(shù)據(jù)結(jié)構(gòu),調(diào)整用戶在mUserLru中的位置,將目標(biāo)用戶位于末尾,根據(jù)mUserLru可以知道當(dāng)前系統(tǒng)運行的用戶信息,接著會移除停止用戶允許的message
t.traceBegin("updateStartedUserArrayStarting");
synchronized (mLock) {
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) {
Slogf.i(TAG, "User #" + userId
+ " is shutting down - will start after full shutdown");
mPendingUserStarts.add(new PendingUserStart(userId, userStartMode,
unlockListener));
t.traceEnd(); // updateStartedUserArrayStarting
return true;
}
}
// No matter what, the fact that we're requested to start the user (even if it is
// already running) puts it towards the end of the mUserLru list.
addUserToUserLru(userId);
if (android.multiuser.Flags.scheduleStopOfBackgroundUser()) {
mHandler.removeEqualMessages(SCHEDULED_STOP_BACKGROUND_USER_MSG,
Integer.valueOf(userId));//這里
}
4.將目標(biāo)用戶的UserState設(shè)置為BOOTING狀態(tài),將啟動的userId設(shè)置為mCurrentUserId ,然后更新mCurrentUserId的配置,并將切換狀態(tài)置為true
if (updateUmState) {
t.traceBegin("setUserState");
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
t.traceEnd();
}
t.traceBegin("updateConfigurationAndProfileIds");
if (foreground) {
// Make sure the old user is no longer considering the display to be on.
mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
boolean userSwitchUiEnabled;
synchronized (mLock) {
mCurrentUserId = userId;
userSwitchUiEnabled = mUserSwitchUiEnabled;
}
mInjector.updateUserConfiguration();
// NOTE: updateProfileRelatedCaches() is called on both if and else parts, ideally
// it should be moved outside, but for now it's not as there are many calls to
// external components here afterwards
updateProfileRelatedCaches();
mInjector.getWindowManager().setCurrentUser(userId);
mInjector.reportCurWakefulnessUsageEvent();
if (userSwitchUiEnabled) {
mInjector.getWindowManager().setSwitchingUser(true);
}
}
5.準(zhǔn)備相關(guān)用戶的限制及存儲 ,發(fā)送用戶啟動消息
if (uss.state == UserState.STATE_BOOTING) {
t.traceBegin("updateStateBooting");
// 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(USER_START_MSG, userId, NO_ARG2));
t.traceEnd();
}
6.發(fā)送REPORT_USER_SWITCH_MSG消息、REPORT_USER_SWITCH_MSG消息和USER_SWITCH_TIMEOUT_MSG消息
if (foreground) {
mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));//onUserSwitching
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), getUserSwitchTimeoutMs());
}
REPORT_USER_SWITCH_MSG消息是告知系統(tǒng)正在切換用戶
REPORT_USER_SWITCH_MSG消息里邏輯很繞,就不詳細展開,最重要的是干了2件事:
1.調(diào)用showUserSwitchDialog顯示彈窗
2.并且會監(jiān)聽動態(tài)壁紙的顯示狀態(tài)變化。當(dāng)動態(tài)壁紙的渲染引擎(Engine)啟動并成功顯示時,系統(tǒng)會通過aidl通知UserControl用以dismissUserSwitchDialog
USER_SWITCH_TIMEOUT_MSG消息主要是發(fā)送一個5s的超時消息,超時了以后會取消彈窗并處理相關(guān)超時邏輯
7.移動新的user到前臺
if (foreground) {
t.traceBegin("moveUserToForeground");
moveUserToForeground(uss, userId);
t.traceEnd();
} else {
t.traceBegin("finishUserBoot");
finishUserBoot(uss);//這里
t.traceEnd();
}
private void moveUserToForeground(UserState uss, int newUserId) {
boolean homeInFront = mInjector.taskSupervisorSwitchUser(newUserId, uss);
if (homeInFront) {
mInjector.startHomeActivity(newUserId, "moveUserToForeground");
} else {
mInjector.taskSupervisorResumeFocusedStackTopActivity();
}
EventLogTags.writeAmSwitchUser(newUserId);
}
多用戶刪除
UserManager#removeUser源碼流程
直接看UserManagerService#removeUser實現(xiàn)
1、檢查調(diào)用者是否有刪除用戶的權(quán)限
public boolean removeUser(@UserIdInt int userId) {
Slog.i(LOG_TAG, "removeUser u" + userId);
checkCreateUsersPermission("Only the system can remove users");
final String restriction = getUserRemovalRestriction(userId);
if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(restriction, false)) {
Slog.w(LOG_TAG, "Cannot remove user. " + restriction + " is enabled.");
return false;
}
return removeUserWithProfilesUnchecked(userId);
}
2、保存要刪除的userId,防止重復(fù)刪除;
把partial變量修改為true, 開機后如果該變量還是true會刪除相關(guān)文件
將userData的flag增加UserInfo.FLAG_DISABLED,更新/data/system/users/${id}.xml文件
private boolean removeUserUnchecked(@UserIdInt int userId) {
final long ident = Binder.clearCallingIdentity();
try {
final UserData userData;
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
final int userRemovability = getUserRemovabilityLocked(userId, "removed");
if (userRemovability != UserManager.REMOVE_RESULT_USER_IS_REMOVABLE) {
return UserManager.isRemoveResultSuccessful(userRemovability);
}
userData = mUsers.get(userId);
Slog.i(LOG_TAG, "Removing user " + userId);
addRemovingUserIdLocked(userId);
}
// Set this to a partially created user, so that the user will be purged
// on next startup, in case the runtime stops now before stopping and
// removing the user completely.
userData.info.partial = true;
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
userData.info.flags |= UserInfo.FLAG_DISABLED;
writeUserLP(userData);
}
...
3、刪除該用戶的UidState狀態(tài)
發(fā)送刪除用戶的廣播
try {
mAppOpsService.removeUser(userId);
} catch (RemoteException e) {
Slog.w(LOG_TAG, "Unable to notify AppOpsService of removing user.", e);
}
if (userData.info.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
&& userData.info.isProfile()) {
sendProfileRemovedBroadcast(userData.info.profileGroupId, userData.info.id,
userData.info.userType);
}
4、停止正在運行的用戶
用戶停止后, 刪除用戶相關(guān)應(yīng)用信息
try {
res = ActivityManager.getService().stopUserWithCallback(userId,
new IStopUserCallback.Stub() {
@Override
public void userStopped(int userIdParam) {
finishRemoveUser(userIdParam);
int originUserId = UserManagerService.this.getCurrentUserId();
mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
userData.info, USER_JOURNEY_USER_REMOVE,
ERROR_CODE_UNSPECIFIED);
mUserJourneyLogger
.logDelayedUserJourneyFinishWithError(originUserId,
userData.info, USER_JOURNEY_USER_LIFECYCLE,
ERROR_CODE_UNSPECIFIED);
}
@Override
public void userStopAborted(int userIdParam) {
int originUserId = UserManagerService.this.getCurrentUserId();
mUserJourneyLogger.logUserJourneyFinishWithError(originUserId,
userData.info, USER_JOURNEY_USER_REMOVE,
ERROR_CODE_ABORTED);
mUserJourneyLogger
.logDelayedUserJourneyFinishWithError(originUserId,
userData.info, USER_JOURNEY_USER_LIFECYCLE,
ERROR_CODE_ABORTED);
}
});
} catch (RemoteException e) {
Slog.w(LOG_TAG, "Failed to stop user during removal.", e);
return false;
}
finishRemoveUser內(nèi)部會開線程執(zhí)行removeUserState方法
private void removeUserState(final @UserIdInt int userId) {
Slog.i(LOG_TAG, "Removing user state of user " + userId);
// Cleanup lock settings. This requires that the user's DE storage still be accessible, so
// this must happen before destroyUserStorageKeys().
mLockPatternUtils.removeUser(userId);
// Evict and destroy the user's CE and DE encryption keys. At this point, the user's CE and
// DE storage is made inaccessible, except to delete its contents.
try {
mContext.getSystemService(StorageManager.class).destroyUserStorageKeys(userId);
} catch (IllegalStateException e) {
// This may be simply because the user was partially created.
Slog.i(LOG_TAG, "Destroying storage keys for user " + userId
+ " failed, continuing anyway", e);
}
// Cleanup package manager settings
mPm.cleanUpUser(this, userId);
// Clean up all data before removing metadata
mUserDataPreparer.destroyUserData(userId,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
// Remove this user from the list
synchronized (mUsersLock) {
mUsers.remove(userId);
mIsUserManaged.delete(userId);
}
synchronized (mUserStates) {
mUserStates.delete(userId);
}
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.remove(userId);
mAppliedUserRestrictions.remove(userId);
mCachedEffectiveUserRestrictions.remove(userId);
// Remove restrictions affecting the user
if (mDevicePolicyUserRestrictions.remove(userId)) {
applyUserRestrictionsForAllUsersLR();
}
}
// Update the user list
synchronized (mPackagesLock) {
writeUserListLP();
}
// Remove user file(s)
getUserFile(userId).delete();