Android--多用户模式
来源:互联网 发布:垦丁音乐节 知乎 编辑:程序博客网 时间:2024/05/07 01:14
Android中的多用户与Windows的多用户类似,可以支持多个用户使用系统。通常,第一个在系统中注册的用户将默认成为系统管理员。
不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,例如网络设置等。
Android与Windows不同,用户切换后前面用户运行的后台进程还可以继续运行。这样,进行用户切换时无须中断一些后台进行的耗时操作(如下载)。
一、管理用户的系统服务--UserManagerService
UserManagerService的主要功能是创建和删除用户,以及查询用户信息。
1、初始化
UserManagerService是在PackageManagerService的构造方法中创建的,如下:
- sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);
- UserManagerService(Context context, PackageManagerService pm,
- Object installLock, Object packagesLock) {
- this(context, pm, installLock, packagesLock,
- Environment.getDataDirectory(),
- new File(Environment.getDataDirectory(), "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);// /data/system/users
- mUsersDir.mkdirs();
- // Make zeroth user directory, for services to migrate their files to that location
- File userZeroDir = new File(mUsersDir, "0");//第一个用户的目录/data/system/users/0
- userZeroDir.mkdirs();
- mBaseUserPath = baseUserPath;// /data/user
- 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);// /data/system/users/userlist.xml
- initDefaultGuestRestrictions();
- readUserListLocked();//分析用户的信息文件
- // Prune out any partially created/partially removed users.
- ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
- for (int i = 0; i < mUsers.size(); i++) {
- UserInfo ui = mUsers.valueAt(i);
- if ((ui.partial || ui.guestToRemove) && i != 0) {
- partials.add(ui);//寻找userlist.xml文件中属性partial为true的用户
- }
- }
- 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);//属性为partial表示创建没完成的用户,从系统中移除
- }
- sInstance = this;
- }
- }
- }
- private void initDefaultGuestRestrictions() {
- if (mGuestRestrictions.isEmpty()) {
- mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);//"no_outgoing_calls"
- mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);//"no_sms"
- }
- }
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <users nextSerialNumber="11" version="5">
- <guestRestrictions>
- <restrictions no_outgoing_calls="true" no_sms="true" />
- </guestRestrictions>
- <user id="0" />
- <user id="10" />
- </users>
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <user id="0" serialNumber="0" flags="19" created="0" lastLoggedIn="1436392413074">
- <name>Owner</name>
- <restrictions />
- </user>
这样UserManagerService的初始化工作就完成了,主要的工作是分析userlist.xml文件,并创建了mUsers列表中的UserInfo对象。
2、UserInfo的定义
在UserManagerService中,UserInfo对象代表用户,定义如下:- public class UserInfo implements Parcelable {
- /** 8 bits for user type 用户类型 */
- public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
- /**
- * Primary user. Only one user can have this flag set. Meaning of this
- * flag TBD.主用户的标志,通常是第一个Id为0的用户
- */
- public static final int FLAG_PRIMARY = 0x00000001;
- /**
- * User with administrative privileges. Such a user can create and
- * delete users.admin用户标志,有此标志才能创建和删除用户
- */
- public static final int FLAG_ADMIN = 0x00000002;
- /**
- * Indicates a guest user that may be transient.guest用户标志
- */
- public static final int FLAG_GUEST = 0x00000004;
- /**
- * Indicates the user has restrictions in privileges, 标识权限受限的用户,具体受限功能未定。
- * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.
- */
- public static final int FLAG_RESTRICTED = 0x00000008;
- /**
- * Indicates that this user has gone through its first-time initialization.标识该用户是否已经初始化
- */
- public static final int FLAG_INITIALIZED = 0x00000010;
- /**
- * Indicates that this user is a profile of another user, for example holding a users
- * corporate data.标识该UserInfo是用户的信息,还是一份profile
- */
- public static final int FLAG_MANAGED_PROFILE = 0x00000020;
- /**
- * Indicates that this user is disabled.标识该用户是否已经被“禁止”
- */
- public static final int FLAG_DISABLED = 0x00000040;
- public static final int NO_PROFILE_GROUP_ID = -1;//profile group id 的无效值定义
- public int id;//用户id
- public int serialNumber;//用户的序列号,不会重复
- public String name;//用户的名称
- public String iconPath;//用户的头像路径
- public int flags;//用户的标志
- public long creationTime;//创建用户的时间
- public long lastLoggedInTime;//上次登录的时间
- public int profileGroupId;//用户的profile group id
- /** User is only partially created. */
- public boolean partial;//此标志为true,表示用户没有创建完成
- public boolean guestToRemove;
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";//限制配置WiFi
- public static final String DISALLOW_INSTALL_APPS = "no_install_apps";//限制安装app
- public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";//限制卸载app
- 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";//限制通过usb传输文件
- 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_vpn";//限制配置VPN
- public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";//限制配置Tether
- 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";//对该用户安装的app要进行校验
- 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";//限制对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";//限制对profile进行复制、粘贴
- 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);
- }
- 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;
- }
- // 如果添加的不是Guest用户,而且达到上限数,返回
- if (!isGuest && isUserLimitReachedLocked()) {
- return null;
- }
- // 如果添加的是Guest用户,但是已经有Guest用户存在,返回
- if (isGuest && findCurrentGuestUserLocked() != null) {
- return null;
- }
- //
- if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0
- && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)
- >= MAX_MANAGED_PROFILES) {//目前MAX_MANAGED_PROFILES最大是1
- return null;//如果创建的是一个用户的profile,检查该用户是否已经有profile
- }
- int userId = getNextAvailableIdLocked();//得到新用户ID
- 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;//将partial属性设为true
- Environment.getUserSystemDirectory(userInfo.id).mkdirs();
- mUsers.put(userId, userInfo);//把新用户信息添加到mUsers
- writeUserListLocked();//把用户信息写到文件userlist.xml中
- if (parent != null) {
- if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
- parent.profileGroupId = parent.id;
- writeUserLocked(parent);
- }
- userInfo.profileGroupId = parent.profileGroupId;
- }
- writeUserLocked(userInfo);//创建用户的信息文件10.xml
- mPm.createNewUserLILPw(userId, userPath);
- userInfo.partial = false;//创建成功,将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;
(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);//创建Guest用户
- if (guest != null) {
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
- try {//对Guest用户进行权限限制
- 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;
- }
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;
- }
- // 将userHandle放入mRemovingUserIds列表,防止重复删除一个用户
- mRemovingUserIds.put(userHandle, true);
- try {
- mAppOpsService.removeUser(userHandle);
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);
- }
- // 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.
- user.partial = true;
- // Mark it as disabled, so that it isn't returned any more when
- // profiles are queried.
- user.flags |= UserInfo.FLAG_DISABLED;
- writeUserLocked(user);//更新用户信息文件
- }
- if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
- && user.isManagedProfile()) {
- // Send broadcast to notify system that the user removed was a
- // managed user.
- 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);
- // Let other services shutdown any activity and clean up their state before completely
- // wiping the user's system directory and removing from the user list
- 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) {
- // Cleanup package manager settings调用PackageManagerService的cleanUpUserLILPw方法删除所有用户目录下app的数据
- mPm.cleanUpUserLILPw(this, userHandle);
- // Remove this user from the list在mUsers列表中删除用户的UserInfo对象
- mUsers.remove(userHandle);
- mRestrictionsPinStates.remove(userHandle);//从mRestrictionsPinStates列表中移除用户
- // Remove user file删除用户的信息文件
- AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
- userFile.delete();
- // Update the user list
- writeUserListLocked();//更新文件userlists.xml,移除用户信息
- updateUserIdsLocked();
- removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));//删除用户目录下的所有文件
- }
removeUserStateLocked()方法将删除所有用户相关的文件。首先是app的数据文件,然后是用户信息文件和userlist.xml中的用户Id信息,最后将用户目录下的所有文件都删除。
二、PackageManagerService和多用户
在多用户的环境中,所有用户安装的应用还是位于/data/app目录,但是这些应用的数据在每个用户的目录/data/user/<用户id>/下都有单独的一份。目录/data/data也还保存应用的数据,但这些数据只对id为0的用户有效。
1、创建用户的应用数据
上面讲到创建用户时会调用PackageManagerService的createNewUserLILPw()方法,如下:
- /** Called by UserManagerService */
- void createNewUserLILPw(int userHandle, File path) {
- if (mInstaller != null) {
- mInstaller.createUserConfig(userHandle);
- mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
- }
- }
我们先看下mInstaller的createUserConfig()方法是如何处理的,如下:
- public int createUserConfig(int userId) {
- StringBuilder builder = new StringBuilder("mkuserconfig");
- builder.append(' ');
- builder.append(userId);
- return mInstaller.execute(builder.toString());
- }
- public int execute(String cmd) {
- String res = transact(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
- void createNewUserLILPw(PackageManagerService service, Installer installer,
- int userHandle, File path) {
- path.mkdir();//创建用户保存应用数据的目录/data/user
- 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;
- }//对每一个应用在用户的目录下创建数据目录
- // Only system apps are initially installed.
- ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);
- // Need to create a data directory for all apps under this user.
- installer.createUserData(ps.name,
- UserHandle.getUid(userHandle, ps.appId), userHandle,
- ps.pkg.applicationInfo.seinfo);
- }
- readDefaultPreferredAppsLPw(service, userHandle);
- writePackageRestrictionsLPr(userHandle);
- }
- 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());
- }
调用readDefaultPreferredAppsLPw()方法是为了分析目录/etc/preferred-apps所有的xml文件,这个目录下的xml文件保存的是设备使用者指定的响应某个intent的最合适的组件。因为每个用户都可以指定它喜欢的最合适的组件,所以每个用户都需要在mPreferredActivities列表中加入它自己的PreferredIntentResolver对象,这个对象中保存的就是intent和组件的关联数据。
2、删除用户的应用数据
PackageManagerService中删除用户的方法是cleanUpUserLILPw()方法,如下:
- /** Called by UserManagerService */
- void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {
- mDirtyUsers.remove(userHandle);
- mSettings.removeUserLPw(userHandle);
- mPendingBroadcasts.remove(userHandle);
- if (mInstaller != null) {
- // Technically, we shouldn't be doing this with the package lock
- // held. However, this is very rare, and there is already so much
- // other disk I/O going on, that we'll let it slide for now.
- mInstaller.removeUserDataDirs(userHandle);//删除用户目录下所有应用的数据
- }
- mUserNeedsBadging.delete(userHandle);
- removeUnusedPackagesLILPw(userManager, userHandle);
- }
- void removeUserLPw(int userId) {
- Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();
- for (Entry<String, PackageSetting> entry : entries) {
- entry.getValue().removeUser(userId);
- }<span style="font-family: Arial, Helvetica, sans-serif;">//删除每个应用信息中该用户的信息</span>
- mPreferredActivities.remove(userId);//删除mPreferredActivities列表中该用户的数据
- File file = getUserPackagesStateFile(userId);
- file.delete();//删除该用户目录下的package-restrictions.xml文件
- file = getUserPackagesStateBackupFile(userId);
- file.delete();
- removeCrossProfileIntentFiltersLPw(userId);
- }
三、ActivityManagerService和多用户
UserManagerService主要管理用户的账号信息,运行中的用户管理由ActivityManagerService实行。
1、用户的状态
用户有四种运行状态,定义如下:
- public final class UserStartedState {
- // User is first coming up.
- public final static int STATE_BOOTING = 0;//用户正在启动
- // User is in the normal running state.
- public final static int STATE_RUNNING = 1;//用户正在运行
- // User is in the initial process of being stopped.
- public final static int STATE_STOPPING = 2;//用户正在停止
- // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
- public final static int STATE_SHUTDOWN = 3;//用户已经关闭
2、切换当前用户
ActivityManagerService中提供了切换当前用户的接口switchUser(),如下:- public boolean switchUser(final int userId) {
- enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
- String userName;
- synchronized (this) {
- UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);//获取userId对应的UserInfo
- if (userInfo == null) {
- Slog.w(TAG, "No user info for user #" + userId);
- return false;
- }
- if (userInfo.isManagedProfile()) {//如果这个UserInfo只是User的另一份profile,退出
- 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;
- }
对消息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) {
- // The dialog will show and then initiate the user switch by calling startUserInForeground
- Dialog d = new UserSwitchingDialog(this, mContext, userId, userName,
- true /* above system */);
- d.show();
- }
startUserInForeground()方法如下:
- /**
- * Start user, if its not already running, and bring it to foreground.
- */
- boolean startUserInForeground(final int userId, Dialog dlg) {
- boolean result = startUser(userId, /* foreground */ true);
- dlg.dismiss();
- return result;
- }
- 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);
- 。。。。。。//一些错误处理,返回false
- 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);//调整用户在mUserLru列表中的位置,当前用户位于最末的位置
- if (foreground) {//前台切换
- mCurrentUserId = userId;//切换当前用户
- mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
- updateCurrentProfileIdsLocked();
- mWindowManager.setCurrentUser(userId, mCurrentProfileIds);//在WMS这设置当前用户
- 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);
- // Make sure user is in the started state. If it is currently
- // stopping, we need to knock that off.
- 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) {
- //如果用户的状态为正在启动,发送消息SYSTEM_USER_START_MSG
- 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) {
- // 如果切换前用户不在STATE_RUNNING状态,向该用户发送广播ACTION_USER_STARTED
- 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) {//如果用户还没初始化,向该用户发送广播ACTION_USER_INITIALIZE
- 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 {//否则直接调用UserManagerService的makeInitialized方法
- getUserManagerLocked().makeInitialized(userInfo.id);
- }
- }
- if (foreground) {
- if (!uss.initializing) {//如果用户已经初始化了,将它设为前台用户
- moveUserToForeground(uss, oldUserId, userId);
- }
- } else {//否则先将用户加入到mStartingBackgroundUser中
- mStackSupervisor.startBackgroundUserLocked(userId, uss);
- }
- if (needStart) {//如果用户不在STATE_RUNNING状态,向所有用户发送广播ACTION_USER_STARTING
- 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++;//如果收到一条返回结果的调用,mCount++
- if (mCount == N) {//如果所有结果都返回了,发送继续处理的消息
- sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
- }
- }
- }
- }
- };
- synchronized (this) {
- uss.switching = true;
- mCurUserSwitchCallback = callback;
- }
- for (int i=0; i<N; i++) {
- try {//调用观测对象的onUserSwitching方法
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
- newUserId, callback);
- } catch (RemoteException e) {
- }
- }
- } else {//如果没有观测对象,直接调用sendContinueUserSwitchLocked
- 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<N; i++) {
- try {
- mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
- } catch (RemoteException e) {
- }
- }
- mUserSwitchObservers.finishBroadcast();
- }
- stopGuestUserIfBackground();
- }
至此,startUser()方法的工作就完成了。但是还有一个问题,状态为STATE_BOOTING的用户什么时候切换到STATE_RUNNING状态?在activityIdleInternalLocked()方法中有一段代码如下:
- for (int i = 0; i < startingUsers.size(); i++) {
- mService.finishUserSwitch(startingUsers.get(i));
- }
- 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) {//正常情况下不会出现为null
- // Shouldn't happen, but be sane if it does.
- mUserLru.remove(i);
- num--;
- continue;
- }
- if (oldUss.mState == UserStartedState.STATE_STOPPING
- || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {
- // This user is already stopping, doesn't count.如果用户已经停止了,继续
- num--;
- i++;
- continue;
- }
- if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
- // Owner and current can't be stopped, but count as running.
- i++;//如果是主用户或当前用户,继续
- continue;
- }
- // This is a user to be stopped.停止用户
- stopUserLocked(oldUserId, null);
- num--;
- i++;
- }
- }
- }
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) {
- // User is not started, nothing to do... but we do need to
- // callback if requested.
- if (callback != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- try {
- callback.userStopped(userId);//回调方法userStopped
- } catch (RemoteException e) {
- }
- }
- });
- }
- return ActivityManager.USER_OP_SUCCESS;//0
- }
- if (callback != null) {
- uss.mStopCallbacks.add(callback);
- }
- if (uss.mState != UserStartedState.STATE_STOPPING
- && uss.mState != UserStartedState.STATE_SHUTDOWN) {
- uss.mState = UserStartedState.STATE_STOPPING;//将用户的状态切换为正在停止
- updateStartedUserArrayLocked();//更新mStartedUserArray数组,存放UserStartedState对象
- long ident = Binder.clearCallingIdentity();
- try {
- // We are going to broadcast ACTION_USER_STOPPING and then
- // once that is done send a final ACTION_SHUTDOWN and then
- // stop the user.
- 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);
- // This is the result receiver for the final shutdown broadcast.
- 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);//收到ACTION_SHUTDOWN广播,继续执行
- }
- };
- // This is the result receiver for the initial stopping broadcast.
- final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
- @Override
- public void performReceive(Intent intent, int resultCode, String data,
- Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
- // On to the next.
- synchronized (ActivityManagerService.this) {
- if (uss.mState != UserStartedState.STATE_STOPPING) {
- // Whoops, we are being started back up. Abort, abort!
- return;
- }
- uss.mState = UserStartedState.STATE_SHUTDOWN;//收到ACTION_USER_STOPPING广播后,改变用户状态
- }
- 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);//再发送广播shutdownIntent(Intent.ACTION_SHUTDOWN)
- }
- };
- // Kick things off.
- 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);//发送广播stoppingIntent(Intent.ACTION_USER_STOPPING)
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- return ActivityManager.USER_OP_SUCCESS;
- }
接下来判断用户是否处于运行状态,没有运行就post一个消息,在消息的处理方法中调用参数中的回调方法结束处理。
如果用户已经运行,先切换用户的状态为STATE_STOPPING,然后广播一个用户正在停止的消息ACTION_USER_STOPPING,同时方法中也会接收这个广播,收到后切换用户的状态为STATE_SHUTDOWN,再发出一个ACTION_SHUTDOWN的广播,方法中同样也会接受这个广播,收到后再调用finishUserStop()方法继续处理,如下:
- void finishUserStop(UserStartedState uss) {
- final int userId = uss.mHandle.getIdentifier();
- boolean stopped;
- ArrayList<IStopUserCallback> callbacks;
- synchronized (this) {
- callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);
- if (mStartedUsers.get(userId) != uss) {
- stopped = false;
- } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {
- stopped = false;
- } else {
- stopped = true;
- // User can no longer run.从AMS的用户管理的数据结构中删除用户
- mStartedUsers.remove(userId);
- mUserLru.remove(Integer.valueOf(userId));
- updateStartedUserArrayLocked();
- // Clean up all state and processes associated with the user.
- // Kill all the processes for the user.
- forceStopUserLocked(userId, "finish user");//发送广播Intent.ACTION_USER_STOPPED
- }
- // Explicitly remove the old information in mRecentTasks.
- removeRecentTasksForUserLocked(userId);//清除用户相关的Recent Task列表
- }
- for (int i=0; i<callbacks.size(); i++) {
- try {//调用UserManagerService的回调方法
- if (stopped) callbacks.get(i).userStopped(userId);
- else callbacks.get(i).userStopAborted(userId);
- } catch (RemoteException e) {
- }
- }
- if (stopped) {
- mSystemServiceManager.cleanupUser(userId);//从mStackSupervisor删除用户
- synchronized (this) {
- mStackSupervisor.removeUserLocked(userId);
- }
- }
- }
- Android--多用户模式
- Android多用户模式的特性
- Android 多用户模式原理和实现介绍
- Android 7.0 判断是否支持多用户模式
- android多用户
- android多用户
- FireFox多用户模式
- xp-多用户模式设置
- 开启firefox多用户模式
- Android5.1--多用户模式
- hive多用户模式
- Android多用户API
- android 5.0多用户支持
- android 4.2 多用户
- Mac 多用户远程访问模式
- 修改数据库为多用户模式
- Hive多用户模式环境搭建
- 单用户模式 及 多用户模式转换
- linux 同步系统时间
- Android bdk-build error:libxxx.so/.a use VFP register arguments, output does not解决办法
- 什么是Dubbo
- 线程安全函数与可重入函数
- Win10不需要Cygwin搭建大数据测试环境(4)---Hive
- Android--多用户模式
- USB 设备类代码表
- androidstudio检测代码内的中文字符(解决安卓国际化修改字符问题)
- TCP三次握手/四次挥手详解
- 主流的网络游戏同步方式一览
- PHP输出斐波那契数列
- 数据库索引,联合索引
- 高内聚低耦合你知道多少?
- css使用字体文件