Android中的多用户与Windows的多用户类似,可以支持多个用户使用系统。通常,第一个在系统中注册的用户将默认成为系统管理员。
不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,例如网络设置等。
Android与Windows不同,用户切换后前面用户运行的后台进程还可以继续运行。这样,进行用户切换时无须中断一些后台进行的耗时操作(如下载)。
一、管理用户的系统服务--UserManagerService
UserManagerService的主要功能是创建和删除用户,以及查询用户信息。
1、初始化
UserManagerService是在PackageManagerService的构造方法中创建的,如下:
- sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);
UserManagerService的构造方法,如下:
- UserManagerService(Context context, PackageManagerService pm,
- Object installLock, Object packagesLock) {
- this(context, pm, installLock, packagesLock,
- Environment.getDataDirectory(),
- new File(Environment.getDataDirectory(), "user"));
- }
调用另一个构造方法,并多传递了两个参数:/data目录和/data/user文件。如下:
- private UserManagerService(Context context, PackageManagerService pm,
- Object installLock, Object packagesLock,
- File dataDir, File baseUserPath) {
- mContext = context;
- mPm = pm;
- mInstallLock = installLock;
- mPackagesLock = packagesLock;
- mHandler = new Handler();
- synchronized (mInstallLock) {
- synchronized (mPackagesLock) {
- mUsersDir = new File(dataDir, USER_INFO_DIR);
- mUsersDir.mkdirs();
-
- File userZeroDir = new File(mUsersDir, "0");
- userZeroDir.mkdirs();
- mBaseUserPath = baseUserPath;
- FileUtils.setPermissions(mUsersDir.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG
- |FileUtils.S_IROTH|FileUtils.S_IXOTH,
- -1, -1);
- mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
- initDefaultGuestRestrictions();
- readUserListLocked();
-
- ArrayList partials = new ArrayList();
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo ui = mUsers.valueAt(i);
- if ((ui.partial || ui.guestToRemove) && i != 0) {
- partials.add(ui);
- }
- }
- for (int i = 0; i < partials.size(); i++) {
- UserInfo ui = partials.get(i);
- Slog.w(LOG_TAG, "Removing partially created user #" + i
- + " (name=" + ui.name + ")");
- removeUserStateLocked(ui.id);
- }
- sInstance = this;
- }
- }
- }
在构造方法中创建了几个目录:/data/system/users、data/system/users/0、/data/system/users/userlist.xml等。之后设置基本的限制条件,如下:
- private void initDefaultGuestRestrictions() {
- if (mGuestRestrictions.isEmpty()) {
- mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);
- mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);
- }
- }
然后调用readUserListLocked()方法解析/data/system/users/userlist.xml文件,这个文件保存了系统中所有用户的id信息。文件内容如下:
- '1.0' encoding='utf-8' standalone='yes' ?>
- "11" version="5">
-
- "true" no_sms="true" />
-
- "0" />
- "10" />
-
得到id信息后还有读取保存了用户注册信息的xml文件,以用户id的数字表示,如0.xml。内容如下:
- '1.0' encoding='utf-8' standalone='yes' ?>
- "0" serialNumber="0" flags="19" created="0" lastLoggedIn="1436392413074">
- Owner
-
-
读取用户的xml文件内容后,将根据文件内容来创建和初始化一个UserInfo对象来保存信息,并把该对象加入到mUsers列表中。如果xml文件中某个用户的属性中有partial="true',则表示这个用户没有完全创建成功,需要从系统中移除掉。
这样UserManagerService的初始化工作就完成了,主要的工作是分析userlist.xml文件,并创建了mUsers列表中的UserInfo对象。
2、UserInfo的定义
在UserManagerService中,UserInfo对象代表用户,定义如下:
- public class UserInfo implements Parcelable {
-
-
- public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
-
-
-
-
-
- public static final int FLAG_PRIMARY = 0x00000001;
-
-
-
-
-
- public static final int FLAG_ADMIN = 0x00000002;
-
-
-
-
- public static final int FLAG_GUEST = 0x00000004;
-
-
-
-
-
- public static final int FLAG_RESTRICTED = 0x00000008;
-
-
-
-
- public static final int FLAG_INITIALIZED = 0x00000010;
-
-
-
-
-
- public static final int FLAG_MANAGED_PROFILE = 0x00000020;
-
-
-
-
- public static final int FLAG_DISABLED = 0x00000040;
-
- public static final int NO_PROFILE_GROUP_ID = -1;
-
- public int id;
- public int serialNumber;
- public String name;
- public String iconPath;
- public int flags;
- public long creationTime;
- public long lastLoggedInTime;
- public int profileGroupId;
-
-
- public boolean partial;
- public boolean guestToRemove;
注意:用户id用来标识用户,用户删除后它的id会分配给下一个新建的用户,保持id号的连续;而serialNumber则是一个在设备中不会重复的数字,用来唯一标识一个用户,如果应用中希望记录和某个用户相关的信息,最好使用serialNumber来表示用户,而不是用户id。
3、用户限制(Restriction)
Android5.1的UserManager中定义了很多和用户相关的限制,这样管理员在创建用户时就能通过这些限制来给予不同用户不同的权限,介绍如下:
- public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
- public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
- public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
- public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
- public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
- public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
- public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
- public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
- public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
- public static final String DISALLOW_REMOVE_USER = "no_remove_user";
- public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
- public static final String DISALLOW_CONFIG_VPN = "no_config_";
- public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
- public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
- public static final String DISALLOW_ADD_USER = "no_add_user";
- public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
- public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
- public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
- public static final String DISALLOW_APPS_CONTROL = "no_control_apps";
- public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
- public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
- public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
- public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
- public static final String DISALLOW_SMS = "no_sms";
- public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
- public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
- public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
4、添加用户
UserManagerService服务中添加用户的接口是createUser(),如下:
- public UserInfo createUser(String name, int flags) {
- checkManageUsersPermission("Only the system can create users");
-
- return createUserInternal(name, flags, UserHandle.USER_NULL);
- }
createUser()方法首先检查调用者的权限,只有system身份的进程才能调用这个方法。然后调用createUserInternal()方法继续执行,如下:
- private UserInfo createUserInternal(String name, int flags, int parentId) {
- if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
- UserManager.DISALLOW_ADD_USER, false)) {
- Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
- return null;
- }
- final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
- final long ident = Binder.clearCallingIdentity();
- UserInfo userInfo = null;
- try {
- synchronized (mInstallLock) {
- synchronized (mPackagesLock) {
- UserInfo parent = null;
- if (parentId != UserHandle.USER_NULL) {
- parent = getUserInfoLocked(parentId);
- if (parent == null) return null;
- }
-
- if (!isGuest && isUserLimitReachedLocked()) {
- return null;
- }
-
- if (isGuest && findCurrentGuestUserLocked() != null) {
- return null;
- }
-
- if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0
- && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
- >= MAX_MANAGED_PROFILES) {
- return null;
- }
- int userId = getNextAvailableIdLocked();
- userInfo = new UserInfo(userId, name, null, flags);
- File userPath = new File(mBaseUserPath, Integer.toString(userId));
- userInfo.serialNumber = mNextSerialNumber++;
- long now = System.currentTimeMillis();
- userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
- userInfo.partial = true;
- Environment.getUserSystemDirectory(userInfo.id).mkdirs();
- mUsers.put(userId, userInfo);
- writeUserListLocked();
- if (parent != null) {
- if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
- parent.profileGroupId = parent.id;
- writeUserLocked(parent);
- }
- userInfo.profileGroupId = parent.profileGroupId;
- }
- writeUserLocked(userInfo);
- mPm.createNewUserLILPw(userId, userPath);
- userInfo.partial = false;
- writeUserLocked(userInfo);
- updateUserIdsLocked();
- Bundle restrictions = new Bundle();
- mUserRestrictions.append(userId, restrictions);
- }
- }
- if (userInfo != null) {
- Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
- mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return userInfo;
-
(1)检查调用进程所属用户是否被限制添加用户。
(2)调用isUserLimitReachedLocked()方法来确定是否还能创建更多的用户。isUserLimitReachedLocked()方法将调用getMaxSupportedUsers()方法得到系统允许的最大用户数和当前用户数进行比较。
(3)调用getNextAvailableIdLocked()方法得到新的用户id。getNextAvailableIdLocked()方法会从10开始查找,如果某个用户Id还没有使用,则将它返回。
(4)根据用户id创建用户的数据目录。同时为用户创建UserInfo对象,并加入到mUsers列表中。
(5)向userlist.xml文件中加入用户的id信息。在/data/system/users/目录下创建以用户id数字表示的xml文件,保存UserInfo中的用户信息,文件中partial属性会被设为true。
(6)调用PackageManagerService的createNewuserLILPw()方法,在新建用户的目录下为所有应用创建数据目录。
(7)更新用户的信息文件,将xml文件中的partial属性移除,这样新用户就创建完成了。使用partial属性的目的是为了防止调用createNewUserLILPw()方法出错,不能成功创建用户。利用这个标志,系统重启时可以清除掉创建失败的用户。
(8)广播加入新用户的消息Intent.ACTION_USER_ADDED。
5、Guest用户
在Android5.0中,创建Guest用户需要通过UserManager的createGuest()方法来完成。如下:
- public UserInfo createGuest(Context context, String name) {
- UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
- if (guest != null) {
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
- try {
- Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
- guestRestrictions.putBoolean(DISALLOW_SMS, true);
- guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
- mService.setUserRestrictions(guestRestrictions, guest.id);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not update guest restrictions");
- }
- }
- return guest;
- }
createGuest()先调用createUser()方法创建一个Guest用户,然后再调用setUserRestrictions()方法进一步对Guest用户进行限制。因此,Guest用户和普通用户的区别就在于权限不同。
6、删除用户
UserManagerService服务中删除用户的接口是removeUser()方法,如下:
- public boolean removeUser(int userHandle) {
- checkManageUsersPermission("Only the system can remove users");
- if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
- UserManager.DISALLOW_REMOVE_USER, false)) {
- Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
- return false;
- }
-
- long ident = Binder.clearCallingIdentity();
- try {
- final UserInfo user;
- synchronized (mPackagesLock) {
- user = mUsers.get(userHandle);
- if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
- return false;
- }
-
-
- mRemovingUserIds.put(userHandle, true);
-
- try {
- mAppOpsService.removeUser(userHandle);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
- }
-
-
-
- user.partial = true;
-
-
- user.flags |= UserInfo.FLAG_DISABLED;
- writeUserLocked(user);
- }
-
- if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
- && user.isManagedProfile()) {
-
-
- sendProfileRemovedBroadcast(user.profileGroupId, user.id);
- }
-
- if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
- int res;
- try {
- res = ActivityManagerNative.getDefault().stopUser(userHandle,
- new IStopUserCallback.Stub() {
- @Override
- public void userStopped(int userId) {
- finishRemoveUser(userId);
- }
- @Override
- public void userStopAborted(int userId) {
- }
- });
- } catch (RemoteException e) {
- return false;
- }
- return res == ActivityManager.USER_OP_SUCCESS;
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
removeUser()方法并没有立即删除用户相关的文件,而是首先将用户信息中的partial属性改为true。这样的好处是,如果后面的过程被意外终止了,系统重启后还是会删除该用户所有目录和文件。
考虑到被删除的用户可能正在运行,因此,removeUser()方法要调用ActivityManagerService的stopUser()方法来改变该用户的运行状态,结束后,AMS将调用函数参数中的回调方法,最终调用到finishRemoveUser()方法。如下:
- void finishRemoveUser(final int userHandle) {
- if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
-
-
- long ident = Binder.clearCallingIdentity();
- try {
- Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
- mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS,
-
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DBG) {
- Slog.i(LOG_TAG,
- "USER_REMOVED broadcast sent, cleaning up user data "
- + userHandle);
- }
- new Thread() {
- public void run() {
- synchronized (mInstallLock) {
- synchronized (mPackagesLock) {
- removeUserStateLocked(userHandle);
- }
- }
- }
- }.start();
- }
- },
-
- null, Activity.RESULT_OK, null, null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
在finishRemoveUser()方法中发出了广播Intent.ACTION_USER_REMOVED,同时也创建了一个BroadcastReceiver对象来接收这个广播。注意,这时创建的广播接收器将最后才能收到广播通知。这是为了让系统中其他关心这条广播的地方先处理,最后才回到这里继续完成删除用户的工作。收到广播后,考虑到后面的工作还很耗时,因此,在onReceiver()方法中启动了一个线程来运行removeUserStateLocked()方法。代码如下:
- private void removeUserStateLocked(final int userHandle) {
-
- mPm.cleanUpUserLILPw(this, userHandle);
-
-
- mUsers.remove(userHandle);
-
- mRestrictionsPinStates.remove(userHandle);
-
- AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
- userFile.delete();
-
- writeUserListLocked();
- updateUserIdsLocked();
- removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));
- }
removeUserStateLocked()方法将删除所有用户相关的文件。首先是app的数据文件,然后是用户信息文件和userlist.xml中的用户Id信息,最后将用户目录下的所有文件都删除。
二、PackageManagerService和多用户
在多用户的环境中,所有用户安装的应用还是位于/data/app目录,但是这些应用的数据在每个用户的目录/data/user/<用户id>/下都有单独的一份。目录/data/data也还保存应用的数据,但这些数据只对id为0的用户有效。
1、创建用户的应用数据
上面讲到创建用户时会调用PackageManagerService的createNewUserLILPw()方法,如下:
-
- void createNewUserLILPw(int userHandle, File path) {
- if (mInstaller != null) {
- mInstaller.createUserConfig(userHandle);
- mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
- }
- }
createNewUserLILPw()方法只是调用了mInstaller的createUserConfig()和mSettings的createNewUserLILPw()方法。
我们先看下mInstaller的createUserConfig()方法是如何处理的,如下:
- public int createUserConfig(int userId) {
- StringBuilder builder = new StringBuilder("mkuserconfig");
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
mInstaller是InstallerConnection的对象,这里调用InstallConnection对象的execute()方法,如下:
- public int execute(String cmd) {
- String res = transact(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
这里实现了与installd服务通信的过程,具体操作是由installd服务完成的。再看下mSettings的createNewUserLILPw()方法,我们知道mSettings中保存的是从文件中读取的所有应用的信息。如下:
- void createNewUserLILPw(PackageManagerService service, Installer installer,
- int userHandle, File path) {
- path.mkdir();
- FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
- | FileUtils.S_IXOTH, -1, -1);
- for (PackageSetting ps : mPackages.values()) {
- if (ps.pkg == null || ps.pkg.applicationInfo == null) {
- continue;
- }
-
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
-
- installer.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle,
- ps.pkg.applicationInfo.seinfo);
- }
- readDefaultPreferredAppsLPw(service, userHandle);
- writePackageRestrictionsLPr(userHandle);
- }
createNewUserLILPw()方法会遍历mPackages列表,这个列表保存的是系统中所有已安装的应用信息,然后针对每一个应用调用installer的createUserData()方法,调用Installer的方法最终会调用installd守护进程的命令,这里最终调用installd的“mkuserdata”命令来执行应用数据目录的创建工作。
- public int createUserData(String name, int uid, int userId, String seinfo) {
- StringBuilder builder = new StringBuilder("mkuserdata");
- builder.append(' ');
- builder.append(name);
- builder.append(' ');
- builder.append(uid);
- builder.append(' ');
- builder.append(userId);
- builder.append(' ');
- builder.append(seinfo != null ? seinfo : "!");
-
- return mInstaller.execute(builder.toString());
- }
同时每个应用的设置对象PackageSetting中都有一个数组userState,表示应用已经被安装到哪些用户中,这里调用ps的setInstalled方法就是向数组userState中插入用户的信息。
调用readDefaultPreferredAppsLPw()方法是为了分析目录/etc/preferred-apps所有的xml文件,这个目录下的xml文件保存的是设备使用者指定的响应某个intent的最合适的组件。因为每个用户都可以指定它喜欢的最合适的组件,所以每个用户都需要在mPreferredActivities列表中加入它自己的PreferredIntentResolver对象,这个对象中保存的就是intent和组件的关联数据。
2、删除用户的应用数据
PackageManagerService中删除用户的方法是cleanUpUserLILPw()方法,如下:
-
- void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {
- mDirtyUsers.remove(userHandle);
- mSettings.removeUserLPw(userHandle);
- mPendingBroadcasts.remove(userHandle);
- if (mInstaller != null) {
-
-
-
- mInstaller.removeUserDataDirs(userHandle);
- }
- mUserNeedsBadging.delete(userHandle);
- removeUnusedPackagesLILPw(userManager, userHandle);
- }
cleanUpUserLILPw方法主要的工作就是调用mInstaller的removeUserDataDirs()方法来删除用户目录下所有应用的数据。同时调用mSettings的removeUserLPw()方法来删除PackageManagerService中和用户相关的数据,如下:
- void removeUserLPw(int userId) {
- Set> entries = mPackages.entrySet();
- for (Entry entry : entries) {
- entry.getValue().removeUser(userId);
- }"font-family: Arial, Helvetica, sans-serif;">
- mPreferredActivities.remove(userId);
- File file = getUserPackagesStateFile(userId);
- file.delete();
- file = getUserPackagesStateBackupFile(userId);
- file.delete();
- removeCrossProfileIntentFiltersLPw(userId);
- }
三、ActivityManagerService和多用户
UserManagerService主要管理用户的账号信息,运行中的用户管理由ActivityManagerService实行。
1、用户的状态
用户有四种运行状态,定义如下:
- public final class UserStartedState {
-
- public final static int STATE_BOOTING = 0;
-
- public final static int STATE_RUNNING = 1;
-
- public final static int STATE_STOPPING = 2;
-
- public final static int STATE_SHUTDOWN = 3;
在AMS中,变量mCurrentUserId记录了当前的用户Id,mStartedUsers列表则保存了正在运行的用户,只有在mStartedUsers列表中的用户才会有上面这4中状态,不在列表中的是已经注册了但是没有运行的用户。
2、切换当前用户
ActivityManagerService中提供了切换当前用户的接口switchUser(),如下:
- public boolean switchUser(final int userId) {
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
- String userName;
- synchronized (this) {
- UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
- if (userInfo == null) {
- Slog.w(TAG, "No user info for user #" + userId);
- return false;
- }
- if (userInfo.isManagedProfile()) {
- Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
- return false;
- }
- userName = userInfo.name;
- mTargetUserId = userId;
- }
- mHandler.removeMessages(START_USER_SWITCH_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));
- return true;
- }
switchUser()先调用getUserInfo()方法得到userId对应的用户信息,然后通过isManagedProfile()方法来判断这份UserInfo是否只是一个profile(Android中允许一个用户还拥有另一份profile)。如果确实是一个用户,则发出消息START_USER_SWITCH_MSG。
对消息START_USER_SWITCH_MSG的处理是调用方法showUserSwitchDialog,这个方法将弹出一个对话框来确定是否要进行用户切换,一旦用户点击确定按钮后,调用startUserInForeground()方法
- case START_USER_SWITCH_MSG: {
- showUserSwitchDialog(msg.arg1, (String) msg.obj);
- break;
- }
- private void showUserSwitchDialog(int userId, String userName) {
-
- Dialog d = new UserSwitchingDialog(this, mContext, userId, userName,
- true );
- d.show();
- }
startUserInForeground()方法如下:
-
-
-
- boolean startUserInForeground(final int userId, Dialog dlg) {
- boolean result = startUser(userId, true);
- dlg.dismiss();
- return result;
- }
在startUserInForeground()方法中只是调用了startUser()方法,如下:
- private boolean startUser(final int userId, final boolean foreground) {
- if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
- != PackageManager.PERMISSION_GRANTED) {
- 。。。。。。
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- final int oldUserId = mCurrentUserId;
- if (oldUserId == userId) {
- return true;
- }
-
- mStackSupervisor.setLockTaskModeLocked(null, false, "startUser");
-
- final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
- 。。。。。。
- if (foreground) {
- mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
- R.anim.screen_user_enter);
- }
-
- boolean needStart = false;
-
-
- if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserStartedState(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;
- updateCurrentProfileIdsLocked();
- mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
- mWindowManager.lockNow(null);
- } else {
- final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
- updateCurrentProfileIdsLocked();
- mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
- mUserLru.remove(currentUserIdInt);
- mUserLru.add(currentUserIdInt);
- }
-
- final UserStartedState uss = mStartedUsers.get(userId);
-
-
-
- if (uss.mState == UserStartedState.STATE_STOPPING) {
-
- uss.mState = UserStartedState.STATE_RUNNING;
- updateStartedUserArrayLocked();
- needStart = true;
- } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {
-
- uss.mState = UserStartedState.STATE_BOOTING;
- updateStartedUserArrayLocked();
- needStart = true;
- }
-
- if (uss.mState == UserStartedState.STATE_BOOTING) {
-
- 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);
- }
-
- if (needStart) {
-
- 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,
- 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) {
- onUserInitialized(uss, foreground, oldUserId, userId);
- }
- }, 0, null, null, null, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID,
- userId);
- uss.initializing = true;
- } else {
- getUserManagerLocked().makeInitialized(userInfo.id);
- }
- }
-
- if (foreground) {
- if (!uss.initializing) {
- moveUserToForeground(uss, oldUserId, userId);
- }
- } else {
- mStackSupervisor.startBackgroundUserLocked(userId, uss);
- }
-
- 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,
- INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return true;
- }
startUser()方法代码较长。方法中先确定用户的状态,如果用户还没有运行,那么mStartedUsers列表中将不会有用户的信息,因此,需要先创建表示用户状态的对象UserStartedState,然后加入到mStartedUsers列表中。同时还要调整用户在mUserLru列表中的位置到最后一项。系统中同时运行的用户数量最多为3个(目前的定义),mUserLru列表就是记录用户的登录顺序,在需要时会停止多余的用户运行。
对于已经在mStartedUsers列表中的用户,首先判定它的状态是否为STATE_RUNNING,如果不是,则需要完成状态转换,如果处于STATE_STOPPING状态,直接转换为STATE_RUNNING状态,如果处于STATE_SHUTDOWN状态,先转换为STATE_BOOTING状态。因此,switchUser()方法结束后用户有可能处于STATE_BOOTING状态,那么用户什么时候会再切换到STATE_RUNNING状态呢?稍候分析。
切换用户的工作还包括设置记录当前用户id的变量mCurrentUserId,调用WMS的setCurrentUser()方法来改变当前用户、锁定当前的屏幕等。
除了这些工作,startUser()方法最重要的工作是广播和用户相关的Intent。因为用户切换还牵扯到很多模块,例如壁纸管理、输入法、账号管理模块,他们都需要知道当前用户已经发生了变化,然后做出相应的调整。这里要注意广播的对象,有些是面向新用户的,有些是面向旧用户,有些面向所有用户。
(1)如果切换前用户不在STATE_RUNNING状态,向该用户发送广播ACTION_USER_STARTED。
(2)id不为0的用户如果还没有初始化,向该用户发送广播ACTION_USER_INITIALIZE。
(3)调用sendUserSwitchBroadcastsLocked()方法向旧用户发送广播ACTION_USER_BACKGROUND,向新用户发送广播ACTION_USER_FOREGROUND,向所有用户发送广播ACTION_USER_SWUTCHED。
(4)如果切换前用户不在STATE_RUNNING状态,向所有用户发送广播ACTION_USER_STARTING。
此外,startUser()方法中还会发两条消息:REPORT_USER_SWITCH_MSG和USER_SWITCH_TIMEOUT_MSG。其中REPORT_USER_SWITCH_MSG消息处理方法是dispatchUserSwitch,如下:
- case REPORT_USER_SWITCH_MSG: {
- dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
- void dispatchUserSwitch(final UserStartedState 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
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
- newUserId, callback);
- } catch (RemoteException e) {
- }
- }
- } else {
- synchronized (this) {
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
- }
- }
- mUserSwitchObservers.finishBroadcast();
- }
dispatchUserSwitch()方法的主要作用是调用mUserSwitchObservers列表中IUserSwitchObserver对象的onUserSwitching()接口。如果系统中有模块对用户切换感兴趣,可以调用AMS的registerUserSwitchObserver()接口来注册一个观测对象,这个对象将会保存到mUserSwitchObservers列表中。注册观测对象的模块在它的回调接口onUserSwitching()的处理中需要在调用传递的参数对象callback的sendResult方法来通知AMS。我们看下上面代码中的sendResult()方法,只有所有注册者都调用了sendResult()方法,mCount最后才会等于N,这时才会调用sendContinueUserSwitchLocked方法来发送CONTINUE_USER_SWITCH_MSG消息来继续切换用户。
我们看下USER_SWITCH_TIMEOUT_MSG消息的处理,发送USER_SWITCH_TIMEOUT_MSG消息是为了防止对CONTINUE_USER_SWITCH_MSG消息的处理时间过长,毕竟只有所有注册者处理完成才能继续。Android5.1不同于以往版本,这里会继续发送CONTINUE_USER_SWITCH_MSG消息,继续进行用户切换。如下:
- case USER_SWITCH_TIMEOUT_MSG: {
- timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
- void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
- synchronized (this) {
- Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
- }
- }
- void sendContinueUserSwitchLocked(UserStartedState uss, int oldUserId, int newUserId) {
- mCurUserSwitchCallback = null;
- mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
- mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
- oldUserId, newUserId, uss));
- }
- case CONTINUE_USER_SWITCH_MSG: {
- continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
- break;
- }
- void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
- completeSwitchAndInitalize(uss, newUserId, false, true);
- }
- void completeSwitchAndInitalize(UserStartedState uss, int newUserId,
- boolean clearInitializing, boolean clearSwitching) {
- boolean unfrozen = false;
- synchronized (this) {
- if (clearInitializing) {
- uss.initializing = false;
- getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
- }
- if (clearSwitching) {
- uss.switching = false;
- }
- if (!uss.switching && !uss.initializing) {
- mWindowManager.stopFreezingScreen();
- unfrozen = true;
- }
- }
- if (unfrozen) {
- final int N = mUserSwitchObservers.beginBroadcast();
- for (int i=0; i
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
- } catch (RemoteException e) {
- }
- }
- mUserSwitchObservers.finishBroadcast();
- }
- stopGuestUserIfBackground();
- }
CONTINUE_USER_SWITCH_MSG消息的处理方法是continueUserSwitch(),这个方法会调用completeSwitchAndInitalize()方法继续处理,处理的结果是对mUserSwitchObservers列表中所有观测对象调用他们的onUserSwitchComplete()方法。
至此,startUser()方法的工作就完成了。但是还有一个问题,状态为STATE_BOOTING的用户什么时候切换到STATE_RUNNING状态?在activityIdleInternalLocked()方法中有一段代码如下:
- for (int i = 0; i < startingUsers.size(); i++) {
- mService.finishUserSwitch(startingUsers.get(i));
- }
activityIdleInternalLocked()方法会在Activity进入Idle状态时调用,也就相当于用户已经切换完成了,会对每个startingUsers列表中的用户调用finishUserBoot()方法,如下:
- void finishUserSwitch(UserStartedState uss) {
- synchronized (this) {
- finishUserBoot(uss);
-
- startProfilesLocked();
-
- int num = mUserLru.size();
- int i = 0;
- while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
- Integer oldUserId = mUserLru.get(i);
- UserStartedState oldUss = mStartedUsers.get(oldUserId);
- if (oldUss == null) {
-
- mUserLru.remove(i);
- num--;
- continue;
- }
- if (oldUss.mState == UserStartedState.STATE_STOPPING
- || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
-
- num--;
- i++;
- continue;
- }
- if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
-
- i++;
- continue;
- }
-
- stopUserLocked(oldUserId, null);
- num--;
- i++;
- }
- }
- }
finishUserSwitch()方法完成了两件工作。一是调用方法finishUserBoot()把状态还是STATE_BOOTING的用户切换到STATE_RUNNING状态,同时发送广播ACTION_BOOT_COMPLETED给该用户,表示用户启动结束。另一件工作是停止多余的用户。从mUserLru列表的第0项开始,对于处于状态STATE_RUNNING的用户,只要不是主用户或当前用户,一律停止,只保留处于STATE_RUNNING状态的用户。
3、停止用户运行
ActivityManagerService中停止用户运行的接口是stopUser(),这个方法在检查了调用进程的权限后,调用内部方法stopUserLocked()继续停止用户的工作,stopUserLocked()代码如下:
- private int stopUserLocked(final int userId, final IStopUserCallback callback) {
- if (DEBUG_MU) Slog.i(TAG_MU, "stopUserLocked userId=" + userId);
- if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {
- return ActivityManager.USER_OP_IS_CURRENT;
- }
-
- final UserStartedState uss = mStartedUsers.get(userId);
- if (uss == null) {
-
-
- if (callback != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- callback.userStopped(userId);
- } catch (RemoteException e) {
- }
- }
- });
- }
- return ActivityManager.USER_OP_SUCCESS;
- }
-
- if (callback != null) {
- uss.mStopCallbacks.add(callback);
- }
-
- if (uss.mState != UserStartedState.STATE_STOPPING
- && uss.mState != UserStartedState.STATE_SHUTDOWN) {
- uss.mState = UserStartedState.STATE_STOPPING;
- updateStartedUserArrayLocked();
-
- long ident = Binder.clearCallingIdentity();
- try {
-
-
-
- final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
- stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
- stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
- final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
-
- final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- finishUserStop(uss);
- }
- };
-
- final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-
- synchronized (ActivityManagerService.this) {
- if (uss.mState != UserStartedState.STATE_STOPPING) {
-
- return;
- }
- uss.mState = UserStartedState.STATE_SHUTDOWN;
- }
- mBatteryStatsService.noteEvent(
- BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
- Integer.toString(userId), userId);
- mSystemServiceManager.stopUser(userId);
- broadcastIntentLocked(null, null, shutdownIntent,
- null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, userId);
- }
- };
-
- broadcastIntentLocked(null, null, stoppingIntent,
- null, stoppingReceiver, 0, null, null,
- INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
- true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- return ActivityManager.USER_OP_SUCCESS;
- }
stopUserLocked()方法首先判断请求停止的用户是否是当前用户,是,返回。由此可见,当前正在运行的用户是不能停止的,必须先切换到其他的用户才能再停止该用户。
接下来判断用户是否处于运行状态,没有运行就post一个消息,在消息的处理方法中调用参数中的回调方法结束处理。
如果用户已经运行,先切换用户的状态为STATE_STOPPING,然后广播一个用户正在停止的消息ACTION_USER_STOPPING,同时方法中也会接收这个广播,收到后切换用户的状态为STATE_SHUTDOWN,再发出一个ACTION_SHUTDOWN的广播,方法中同样也会接受这个广播,收到后再调用finishUserStop()方法继续处理,如下:
- void finishUserStop(UserStartedState uss) {
- final int userId = uss.mHandle.getIdentifier();
- boolean stopped;
- ArrayList callbacks;
- synchronized (this) {
- callbacks = new ArrayList(uss.mStopCallbacks);
- if (mStartedUsers.get(userId) != uss) {
- stopped = false;
- } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {
- stopped = false;
- } else {
- stopped = true;
-
- mStartedUsers.remove(userId);
- mUserLru.remove(Integer.valueOf(userId));
- updateStartedUserArrayLocked();
-
-
-
- forceStopUserLocked(userId, "finish user");
- }
-
-
- removeRecentTasksForUserLocked(userId);
- }
-
- for (int i=0; i
- try {
- if (stopped) callbacks.get(i).userStopped(userId);
- else callbacks.get(i).userStopAborted(userId);
- } catch (RemoteException e) {
- }
- }
-
- if (stopped) {
- mSystemServiceManager.cleanupUser(userId);
- synchronized (this) {
- mStackSupervisor.removeUserLocked(userId);
- }
- }
- }
finishUserStop()方法的主要工作是从mStartedUsers和mUserLru中删除用户,然后发送广播Intent.ACTION_USER_STOPPED来通知某个用户停止了,接下来调用UserManagerService的回调方法通知UserManagerService来处理,最后调用removeUserLocked()方法从mStackSupervisor列表中删除用户的相关信息。