多用户创建
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.为新用户创建一个新的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.存储新用户信息。构造包含新用户信息的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:将新创建新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、准备文件系统
通过vold(Android存储守护进程)为新用户进行文件系统加密;
创建/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、生成一个唯一的合成密码,通常通过复杂的密码生成算法创建,用于加密和解密用户数据。
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为新用户和应用赋予默认的权限
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、发送 "ACTION_USER_ADDED"广播,通知新用户创建完成
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);
通过以上工作流程可以看到,多用户其实是系统为应用的data目录分配了一份不同且独立的存储空间,不同用户下的存储空间互不影响且没有权限访问。同时,系统中的AMS、PMS、WMS等各大服务都会针对userId/UserHandle进行多用户适配,并在用户启动、切换、停止、删除等生命周期时做出相应策略的改变。通过以上,Android创造出来一个虚拟的多用户运行环境。
多用户启切换
多用户切换最终调用到UserControl#startUserInternal,多用户切换时userStartMode = USER_START_MODE_FOREGROUND,后台启动时userStartMode =
USER_START_MODE_BACKGROUND_VISIBLE, 这里主要分析startUserInternal方法
1.如果是启动前台用户,则通知AMS清除所有锁定任务,并请求结束LockTask模式
if (foreground) {
t.traceBegin("clearAllLockedTasks");
mInjector.clearAllLockedTasks("startUser");
t.traceEnd();
}
2.获取目标用户的相关信息 ,经过一系列逻辑判断,最后在开始时将目标用户分配给显示器,返回分配是否成功
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.为目标用户创建UserState,并放入mStartedUsers数据结构,调整用户在mUserLru中的位置,将目标用户位于末尾,根据mUserLru可以知道当前系统运行的用户信息,接着会移除停止用户允许的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.将目标用户的UserState设置为BOOTING状态,将启动的userId设置为mCurrentUserId ,然后更新mCurrentUserId的配置,并将切换状态置为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.准备相关用户的限制及存储 ,发送用户启动消息
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.发送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消息是告知系统正在切换用户
REPORT_USER_SWITCH_MSG消息里逻辑很绕,就不详细展开,最重要的是干了2件事:
1.调用showUserSwitchDialog显示弹窗
2.并且会监听动态壁纸的显示状态变化。当动态壁纸的渲染引擎(Engine)启动并成功显示时,系统会通过aidl通知UserControl用以dismissUserSwitchDialog
USER_SWITCH_TIMEOUT_MSG消息主要是发送一个5s的超时消息,超时了以后会取消弹窗并处理相关超时逻辑
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实现
1、检查调用者是否有删除用户的权限
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,防止重复删除;
把partial变量修改为true, 开机后如果该变量还是true会删除相关文件
将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状态
发送删除用户的广播
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、停止正在运行的用户
用户停止后, 删除用户相关应用信息
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内部会开线程执行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();