Android--多用户模式

来源:互联网 发布:垦丁音乐节 知乎 编辑:程序博客网 时间:2024/05/07 01:14

Android中的多用户与Windows的多用户类似,可以支持多个用户使用系统。通常,第一个在系统中注册的用户将默认成为系统管理员。

不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,例如网络设置等。

Android与Windows不同,用户切换后前面用户运行的后台进程还可以继续运行。这样,进行用户切换时无须中断一些后台进行的耗时操作(如下载)。

一、管理用户的系统服务--UserManagerService

UserManagerService的主要功能是创建和删除用户,以及查询用户信息。

1、初始化

UserManagerService是在PackageManagerService的构造方法中创建的,如下:

[java] view plain copy
  1. sUserManager = new UserManagerService(context, this, mInstallLock, mPackages);  
UserManagerService的构造方法,如下:
[java] view plain copy
  1. UserManagerService(Context context, PackageManagerService pm,  
  2.         Object installLock, Object packagesLock) {  
  3.     this(context, pm, installLock, packagesLock,  
  4.             Environment.getDataDirectory(),  
  5.             new File(Environment.getDataDirectory(), "user"));  
  6. }  
调用另一个构造方法,并多传递了两个参数:/data目录和/data/user文件。如下:
[java] view plain copy
  1. private UserManagerService(Context context, PackageManagerService pm,  
  2.         Object installLock, Object packagesLock,  
  3.         File dataDir, File baseUserPath) {  
  4.     mContext = context;  
  5.     mPm = pm;  
  6.     mInstallLock = installLock;  
  7.     mPackagesLock = packagesLock;  
  8.     mHandler = new Handler();  
  9.     synchronized (mInstallLock) {  
  10.         synchronized (mPackagesLock) {  
  11.             mUsersDir = new File(dataDir, USER_INFO_DIR);// /data/system/users  
  12.             mUsersDir.mkdirs();  
  13.             // Make zeroth user directory, for services to migrate their files to that location  
  14.             File userZeroDir = new File(mUsersDir, "0");//第一个用户的目录/data/system/users/0  
  15.             userZeroDir.mkdirs();  
  16.             mBaseUserPath = baseUserPath;// /data/user  
  17.             FileUtils.setPermissions(mUsersDir.toString(),  
  18.                     FileUtils.S_IRWXU|FileUtils.S_IRWXG  
  19.                     |FileUtils.S_IROTH|FileUtils.S_IXOTH,  
  20.                     -1, -1);  
  21.             mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);// /data/system/users/userlist.xml  
  22.             initDefaultGuestRestrictions();  
  23.             readUserListLocked();//分析用户的信息文件  
  24.             // Prune out any partially created/partially removed users.  
  25.             ArrayList<UserInfo> partials = new ArrayList<UserInfo>();  
  26.             for (int i = 0; i < mUsers.size(); i++) {  
  27.                 UserInfo ui = mUsers.valueAt(i);  
  28.                 if ((ui.partial || ui.guestToRemove) && i != 0) {  
  29.                     partials.add(ui);//寻找userlist.xml文件中属性partial为true的用户  
  30.                 }  
  31.             }  
  32.             for (int i = 0; i < partials.size(); i++) {  
  33.                 UserInfo ui = partials.get(i);  
  34.                 Slog.w(LOG_TAG, "Removing partially created user #" + i  
  35.                         + " (name=" + ui.name + ")");  
  36.                 removeUserStateLocked(ui.id);//属性为partial表示创建没完成的用户,从系统中移除  
  37.             }  
  38.             sInstance = this;  
  39.         }  
  40.     }  
  41. }  
在构造方法中创建了几个目录:/data/system/users、data/system/users/0、/data/system/users/userlist.xml等。之后设置基本的限制条件,如下:
[java] view plain copy
  1. private void initDefaultGuestRestrictions() {  
  2.     if (mGuestRestrictions.isEmpty()) {  
  3.         mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);//"no_outgoing_calls"  
  4.         mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);//"no_sms"  
  5.     }  
  6. }  
然后调用readUserListLocked()方法解析/data/system/users/userlist.xml文件,这个文件保存了系统中所有用户的id信息。文件内容如下:
[java] view plain copy
  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?>  
  2. <users nextSerialNumber="11" version="5">  
  3.     <guestRestrictions>  
  4.         <restrictions no_outgoing_calls="true" no_sms="true" />  
  5.     </guestRestrictions>  
  6.     <user id="0" />  
  7.     <user id="10" />  
  8. </users>  
得到id信息后还有读取保存了用户注册信息的xml文件,以用户id的数字表示,如0.xml。内容如下:
[java] view plain copy
  1. <?xml version='1.0' encoding='utf-8' standalone='yes' ?>  
  2. <user id="0" serialNumber="0" flags="19" created="0" lastLoggedIn="1436392413074">  
  3.     <name>Owner</name>  
  4.     <restrictions />  
  5. </user>  
读取用户的xml文件内容后,将根据文件内容来创建和初始化一个UserInfo对象来保存信息,并把该对象加入到mUsers列表中。如果xml文件中某个用户的属性中有partial="true',则表示这个用户没有完全创建成功,需要从系统中移除掉。

这样UserManagerService的初始化工作就完成了,主要的工作是分析userlist.xml文件,并创建了mUsers列表中的UserInfo对象。

2、UserInfo的定义

在UserManagerService中,UserInfo对象代表用户,定义如下:
[java] view plain copy
  1. public class UserInfo implements Parcelable {  
  2.   
  3.     /** 8 bits for user type 用户类型 */  
  4.     public static final int FLAG_MASK_USER_TYPE = 0x000000FF;  
  5.   
  6.     /** 
  7.      * Primary user. Only one user can have this flag set. Meaning of this 
  8.      * flag TBD.主用户的标志,通常是第一个Id为0的用户 
  9.      */  
  10.     public static final int FLAG_PRIMARY = 0x00000001;  
  11.   
  12.     /** 
  13.      * User with administrative privileges. Such a user can create and 
  14.      * delete users.admin用户标志,有此标志才能创建和删除用户 
  15.      */  
  16.     public static final int FLAG_ADMIN   = 0x00000002;  
  17.   
  18.     /** 
  19.      * Indicates a guest user that may be transient.guest用户标志 
  20.      */  
  21.     public static final int FLAG_GUEST   = 0x00000004;  
  22.   
  23.     /** 
  24.      * Indicates the user has restrictions in privileges, 标识权限受限的用户,具体受限功能未定。 
  25.      * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts. 
  26.      */  
  27.     public static final int FLAG_RESTRICTED = 0x00000008;  
  28.   
  29.     /** 
  30.      * Indicates that this user has gone through its first-time initialization.标识该用户是否已经初始化 
  31.      */  
  32.     public static final int FLAG_INITIALIZED = 0x00000010;  
  33.   
  34.     /** 
  35.      * Indicates that this user is a profile of another user, for example holding a users 
  36.      * corporate data.标识该UserInfo是用户的信息,还是一份profile 
  37.      */  
  38.     public static final int FLAG_MANAGED_PROFILE = 0x00000020;  
  39.   
  40.     /** 
  41.      * Indicates that this user is disabled.标识该用户是否已经被“禁止” 
  42.      */  
  43.     public static final int FLAG_DISABLED = 0x00000040;  
  44.   
  45.     public static final int NO_PROFILE_GROUP_ID = -1;//profile group id 的无效值定义  
  46.   
  47.     public int id;//用户id  
  48.     public int serialNumber;//用户的序列号,不会重复  
  49.     public String name;//用户的名称  
  50.     public String iconPath;//用户的头像路径  
  51.     public int flags;//用户的标志  
  52.     public long creationTime;//创建用户的时间  
  53.     public long lastLoggedInTime;//上次登录的时间  
  54.     public int profileGroupId;//用户的profile group id  
  55.   
  56.     /** User is only partially created. */  
  57.     public boolean partial;//此标志为true,表示用户没有创建完成  
  58.     public boolean guestToRemove;  
注意:用户id用来标识用户,用户删除后它的id会分配给下一个新建的用户,保持id号的连续;而serialNumber则是一个在设备中不会重复的数字,用来唯一标识一个用户,如果应用中希望记录和某个用户相关的信息,最好使用serialNumber来表示用户,而不是用户id。

3、用户限制(Restriction)

Android5.1的UserManager中定义了很多和用户相关的限制,这样管理员在创建用户时就能通过这些限制来给予不同用户不同的权限,介绍如下:
[java] view plain copy
  1. public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";//限制修改用户账号  
  2. public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";//限制配置WiFi  
  3. public static final String DISALLOW_INSTALL_APPS = "no_install_apps";//限制安装app  
  4. public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";//限制卸载app  
  5. public static final String DISALLOW_SHARE_LOCATION = "no_share_location";//限制共享地理位置  
  6. public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";//限制安装本地应用  
  7. public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";//限制配置蓝牙  
  8. public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";//限制通过usb传输文件  
  9. public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";//限制配置设备的安全设置  
  10. public static final String DISALLOW_REMOVE_USER = "no_remove_user";//限制删除用户  
  11. public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";//限制使用调试功能  
  12. public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";//限制配置VPN  
  13. public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";//限制配置Tether  
  14. public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";//限制进行出厂设置  
  15. public static final String DISALLOW_ADD_USER = "no_add_user";//限制创建用户  
  16. public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";//对该用户安装的app要进行校验  
  17. public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";//限制用户配置小区广播  
  18. public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";//限制配置移动网络  
  19. public static final String DISALLOW_APPS_CONTROL = "no_control_apps";//限制进行清除应用数据和缓存的操作  
  20. public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";//限制挂载  
  21. public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";//限制对microphone进行静音  
  22. public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";//限制调节音量  
  23. public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";//限制拨打电话  
  24. public static final String DISALLOW_SMS = "no_sms";//限制发送短信  
  25. public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";//限制用户的应用进行弹窗功能  
  26. public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";//限制对profile进行复制、粘贴  
  27. public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";//限制  

4、添加用户

UserManagerService服务中添加用户的接口是createUser(),如下:

[java] view plain copy
  1. public UserInfo createUser(String name, int flags) {  
  2.     checkManageUsersPermission("Only the system can create users");  
  3.   
  4.     return createUserInternal(name, flags, UserHandle.USER_NULL);  
  5. }  
createUser()方法首先检查调用者的权限,只有system身份的进程才能调用这个方法。然后调用createUserInternal()方法继续执行,如下:
[java] view plain copy
  1.     private UserInfo createUserInternal(String name, int flags, int parentId) {  
  2.         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(  
  3.                 UserManager.DISALLOW_ADD_USER, false)) {//获取是否有添加用户的权限  
  4.             Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");  
  5.             return null;  
  6.         }  
  7.         final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;  
  8.         final long ident = Binder.clearCallingIdentity();  
  9.         UserInfo userInfo = null;  
  10.         try {  
  11.             synchronized (mInstallLock) {  
  12.                 synchronized (mPackagesLock) {  
  13.                     UserInfo parent = null;  
  14.                     if (parentId != UserHandle.USER_NULL) {  
  15.                         parent = getUserInfoLocked(parentId);  
  16.                         if (parent == nullreturn null;  
  17.                     }  
  18.                     // 如果添加的不是Guest用户,而且达到上限数,返回  
  19.                     if (!isGuest && isUserLimitReachedLocked()) {  
  20.                         return null;  
  21.                     }  
  22.                     // 如果添加的是Guest用户,但是已经有Guest用户存在,返回  
  23.                     if (isGuest && findCurrentGuestUserLocked() != null) {  
  24.                         return null;  
  25.                     }  
  26.                     //  
  27.                     if ((flags & UserInfo.FLAG_MANAGED_PROFILE) != 0  
  28.                             && numberOfUsersOfTypeLocked(UserInfo.FLAG_MANAGED_PROFILE, true)  
  29.                                 >= MAX_MANAGED_PROFILES) {//目前MAX_MANAGED_PROFILES最大是1  
  30.                         return null;//如果创建的是一个用户的profile,检查该用户是否已经有profile  
  31.                     }  
  32.                     int userId = getNextAvailableIdLocked();//得到新用户ID  
  33.                     userInfo = new UserInfo(userId, name, null, flags);  
  34.                     File userPath = new File(mBaseUserPath, Integer.toString(userId));  
  35.                     userInfo.serialNumber = mNextSerialNumber++;  
  36.                     long now = System.currentTimeMillis();  
  37.                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;  
  38.                     userInfo.partial = true;//将partial属性设为true  
  39.                     Environment.getUserSystemDirectory(userInfo.id).mkdirs();  
  40.                     mUsers.put(userId, userInfo);//把新用户信息添加到mUsers  
  41.                     writeUserListLocked();//把用户信息写到文件userlist.xml中  
  42.                     if (parent != null) {  
  43.                         if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {  
  44.                             parent.profileGroupId = parent.id;  
  45.                             writeUserLocked(parent);  
  46.                         }  
  47.                         userInfo.profileGroupId = parent.profileGroupId;  
  48.                     }  
  49.                     writeUserLocked(userInfo);//创建用户的信息文件10.xml  
  50.                     mPm.createNewUserLILPw(userId, userPath);  
  51.                     userInfo.partial = false;//创建成功,将partial设为false  
  52.                     writeUserLocked(userInfo);//更新用户的信息文件  
  53.                     updateUserIdsLocked();  
  54.                     Bundle restrictions = new Bundle();  
  55.                     mUserRestrictions.append(userId, restrictions);  
  56.                 }  
  57.             }  
  58.             if (userInfo != null) {//广播用户创建成功的消息  
  59.                 Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);  
  60.                 addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);  
  61.                 mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,  
  62.                         android.Manifest.permission.MANAGE_USERS);  
  63.             }  
  64.         } finally {  
  65.             Binder.restoreCallingIdentity(ident);  
  66.         }  
  67.         return userInfo;  
  68.       
(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()方法来完成。如下:
[java] view plain copy
  1. public UserInfo createGuest(Context context, String name) {  
  2.     UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);//创建Guest用户  
  3.     if (guest != null) {  
  4.         Settings.Secure.putStringForUser(context.getContentResolver(),  
  5.                 Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);  
  6.         try {//对Guest用户进行权限限制  
  7.             Bundle guestRestrictions = mService.getDefaultGuestRestrictions();  
  8.             guestRestrictions.putBoolean(DISALLOW_SMS, true);  
  9.             guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);  
  10.             mService.setUserRestrictions(guestRestrictions, guest.id);  
  11.         } catch (RemoteException re) {  
  12.             Log.w(TAG, "Could not update guest restrictions");  
  13.         }  
  14.     }  
  15.     return guest;  
  16. }  
createGuest()先调用createUser()方法创建一个Guest用户,然后再调用setUserRestrictions()方法进一步对Guest用户进行限制。因此,Guest用户和普通用户的区别就在于权限不同。

6、删除用户

UserManagerService服务中删除用户的接口是removeUser()方法,如下:

[java] view plain copy
  1. public boolean removeUser(int userHandle) {  
  2.     checkManageUsersPermission("Only the system can remove users");  
  3.     if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(  
  4.             UserManager.DISALLOW_REMOVE_USER, false)) {  
  5.         Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");  
  6.         return false;  
  7.     }//检查调用进程的权限以及进程所属的用户是否被“限制”  
  8.   
  9.     long ident = Binder.clearCallingIdentity();  
  10.     try {  
  11.         final UserInfo user;  
  12.         synchronized (mPackagesLock) {  
  13.             user = mUsers.get(userHandle);  
  14.             if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {  
  15.                 return false;  
  16.             }  
  17.   
  18.             // 将userHandle放入mRemovingUserIds列表,防止重复删除一个用户  
  19.             mRemovingUserIds.put(userHandle, true);  
  20.   
  21.             try {  
  22.                 mAppOpsService.removeUser(userHandle);  
  23.             } catch (RemoteException e) {  
  24.                 Log.w(LOG_TAG, "Unable to notify AppOpsService of removing user", e);  
  25.             }  
  26.             // Set this to a partially created user, so that the user will be purged  
  27.             // on next startup, in case the runtime stops now before stopping and  
  28.             // removing the user completely.  
  29.             user.partial = true;  
  30.             // Mark it as disabled, so that it isn't returned any more when  
  31.             // profiles are queried.  
  32.             user.flags |= UserInfo.FLAG_DISABLED;  
  33.             writeUserLocked(user);//更新用户信息文件  
  34.         }  
  35.   
  36.         if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID  
  37.                 && user.isManagedProfile()) {  
  38.             // Send broadcast to notify system that the user removed was a  
  39.             // managed user.  
  40.             sendProfileRemovedBroadcast(user.profileGroupId, user.id);  
  41.         }  
  42.   
  43.         if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);  
  44.         int res;  
  45.         try {//停止正在运行的用户  
  46.             res = ActivityManagerNative.getDefault().stopUser(userHandle,  
  47.                     new IStopUserCallback.Stub() {//回调函数  
  48.                         @Override  
  49.                         public void userStopped(int userId) {  
  50.                             finishRemoveUser(userId);  
  51.                         }  
  52.                         @Override  
  53.                         public void userStopAborted(int userId) {  
  54.                         }  
  55.                     });  
  56.         } catch (RemoteException e) {  
  57.             return false;  
  58.         }  
  59.         return res == ActivityManager.USER_OP_SUCCESS;  
  60.     } finally {  
  61.         Binder.restoreCallingIdentity(ident);  
  62.     }  
  63. }  

removeUser()方法并没有立即删除用户相关的文件,而是首先将用户信息中的partial属性改为true。这样的好处是,如果后面的过程被意外终止了,系统重启后还是会删除该用户所有目录和文件。

考虑到被删除的用户可能正在运行,因此,removeUser()方法要调用ActivityManagerService的stopUser()方法来改变该用户的运行状态,结束后,AMS将调用函数参数中的回调方法,最终调用到finishRemoveUser()方法。如下:

[java] view plain copy
  1. void finishRemoveUser(final int userHandle) {  
  2.     if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);  
  3.     // Let other services shutdown any activity and clean up their state before completely  
  4.     // wiping the user's system directory and removing from the user list  
  5.     long ident = Binder.clearCallingIdentity();  
  6.     try {  
  7.         Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);  
  8.         addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);  
  9.         mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,  
  10.                 android.Manifest.permission.MANAGE_USERS,  
  11.   
  12.                 new BroadcastReceiver() {  
  13.                     @Override  
  14.                     public void onReceive(Context context, Intent intent) {  
  15.                         if (DBG) {  
  16.                             Slog.i(LOG_TAG,  
  17.                                     "USER_REMOVED broadcast sent, cleaning up user data "  
  18.                                     + userHandle);  
  19.                         }  
  20.                         new Thread() {  
  21.                             public void run() {  
  22.                                 synchronized (mInstallLock) {  
  23.                                     synchronized (mPackagesLock) {  
  24.                                         removeUserStateLocked(userHandle);  
  25.                                     }  
  26.                                 }  
  27.                             }  
  28.                         }.start();  
  29.                     }  
  30.                 },  
  31.   
  32.                 null, Activity.RESULT_OK, nullnull);  
  33.     } finally {  
  34.         Binder.restoreCallingIdentity(ident);  
  35.     }  
  36. }  

在finishRemoveUser()方法中发出了广播Intent.ACTION_USER_REMOVED,同时也创建了一个BroadcastReceiver对象来接收这个广播。注意,这时创建的广播接收器将最后才能收到广播通知。这是为了让系统中其他关心这条广播的地方先处理,最后才回到这里继续完成删除用户的工作。收到广播后,考虑到后面的工作还很耗时,因此,在onReceiver()方法中启动了一个线程来运行removeUserStateLocked()方法。代码如下:
[java] view plain copy
  1. private void removeUserStateLocked(final int userHandle) {  
  2.     // Cleanup package manager settings调用PackageManagerService的cleanUpUserLILPw方法删除所有用户目录下app的数据  
  3.     mPm.cleanUpUserLILPw(this, userHandle);  
  4.   
  5.     // Remove this user from the list在mUsers列表中删除用户的UserInfo对象  
  6.     mUsers.remove(userHandle);  
  7.   
  8.     mRestrictionsPinStates.remove(userHandle);//从mRestrictionsPinStates列表中移除用户  
  9.     // Remove user file删除用户的信息文件  
  10.     AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));  
  11.     userFile.delete();  
  12.     // Update the user list  
  13.     writeUserListLocked();//更新文件userlists.xml,移除用户信息  
  14.     updateUserIdsLocked();  
  15.     removeDirectoryRecursive(Environment.getUserSystemDirectory(userHandle));//删除用户目录下的所有文件  
  16. }  

removeUserStateLocked()方法将删除所有用户相关的文件。首先是app的数据文件,然后是用户信息文件和userlist.xml中的用户Id信息,最后将用户目录下的所有文件都删除。

二、PackageManagerService和多用户

在多用户的环境中,所有用户安装的应用还是位于/data/app目录,但是这些应用的数据在每个用户的目录/data/user/<用户id>/下都有单独的一份。目录/data/data也还保存应用的数据,但这些数据只对id为0的用户有效。

1、创建用户的应用数据

上面讲到创建用户时会调用PackageManagerService的createNewUserLILPw()方法,如下:

[java] view plain copy
  1. /** Called by UserManagerService */  
  2. void createNewUserLILPw(int userHandle, File path) {  
  3.     if (mInstaller != null) {  
  4.         mInstaller.createUserConfig(userHandle);  
  5.         mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);  
  6.     }  
  7. }  
createNewUserLILPw()方法只是调用了mInstaller的createUserConfig()和mSettings的createNewUserLILPw()方法。

我们先看下mInstaller的createUserConfig()方法是如何处理的,如下:

[java] view plain copy
  1. public int createUserConfig(int userId) {  
  2.     StringBuilder builder = new StringBuilder("mkuserconfig");  
  3.     builder.append(' ');  
  4.     builder.append(userId);  
  5.     return mInstaller.execute(builder.toString());  
  6. }  
mInstaller是InstallerConnection的对象,这里调用InstallConnection对象的execute()方法,如下:
[java] view plain copy
  1. public int execute(String cmd) {  
  2.     String res = transact(cmd);  
  3.     try {  
  4.         return Integer.parseInt(res);  
  5.     } catch (NumberFormatException ex) {  
  6.         return -1;  
  7.     }  
  8. }  
这里实现了与installd服务通信的过程,具体操作是由installd服务完成的。再看下mSettings的createNewUserLILPw()方法,我们知道mSettings中保存的是从文件中读取的所有应用的信息。如下:
[java] view plain copy
  1. void createNewUserLILPw(PackageManagerService service, Installer installer,  
  2.         int userHandle, File path) {  
  3.     path.mkdir();//创建用户保存应用数据的目录/data/user  
  4.     FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG  
  5.             | FileUtils.S_IXOTH, -1, -1);  
  6.     for (PackageSetting ps : mPackages.values()) {  
  7.         if (ps.pkg == null || ps.pkg.applicationInfo == null) {  
  8.             continue;  
  9.         }//对每一个应用在用户的目录下创建数据目录  
  10.         // Only system apps are initially installed.  
  11.         ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle);  
  12.         // Need to create a data directory for all apps under this user.  
  13.         installer.createUserData(ps.name,  
  14.                 UserHandle.getUid(userHandle, ps.appId), userHandle,  
  15.                 ps.pkg.applicationInfo.seinfo);  
  16.     }  
  17.     readDefaultPreferredAppsLPw(service, userHandle);  
  18.     writePackageRestrictionsLPr(userHandle);  
  19. }  
createNewUserLILPw()方法会遍历mPackages列表,这个列表保存的是系统中所有已安装的应用信息,然后针对每一个应用调用installer的createUserData()方法,调用Installer的方法最终会调用installd守护进程的命令,这里最终调用installd的“mkuserdata”命令来执行应用数据目录的创建工作。
[java] view plain copy
  1. public int createUserData(String name, int uid, int userId, String seinfo) {  
  2.     StringBuilder builder = new StringBuilder("mkuserdata");  
  3.     builder.append(' ');  
  4.     builder.append(name);  
  5.     builder.append(' ');  
  6.     builder.append(uid);  
  7.     builder.append(' ');  
  8.     builder.append(userId);  
  9.     builder.append(' ');  
  10.     builder.append(seinfo != null ? seinfo : "!");  
  11.      
  12.     return mInstaller.execute(builder.toString());  
  13. }  
同时每个应用的设置对象PackageSetting中都有一个数组userState,表示应用已经被安装到哪些用户中,这里调用ps的setInstalled方法就是向数组userState中插入用户的信息。

调用readDefaultPreferredAppsLPw()方法是为了分析目录/etc/preferred-apps所有的xml文件,这个目录下的xml文件保存的是设备使用者指定的响应某个intent的最合适的组件。因为每个用户都可以指定它喜欢的最合适的组件,所以每个用户都需要在mPreferredActivities列表中加入它自己的PreferredIntentResolver对象,这个对象中保存的就是intent和组件的关联数据。

2、删除用户的应用数据

PackageManagerService中删除用户的方法是cleanUpUserLILPw()方法,如下:

[java] view plain copy
  1. /** Called by UserManagerService */  
  2. void cleanUpUserLILPw(UserManagerService userManager, int userHandle) {  
  3.     mDirtyUsers.remove(userHandle);  
  4.     mSettings.removeUserLPw(userHandle);  
  5.     mPendingBroadcasts.remove(userHandle);  
  6.     if (mInstaller != null) {  
  7.         // Technically, we shouldn't be doing this with the package lock  
  8.         // held.  However, this is very rare, and there is already so much  
  9.         // other disk I/O going on, that we'll let it slide for now.  
  10.         mInstaller.removeUserDataDirs(userHandle);//删除用户目录下所有应用的数据  
  11.     }  
  12.     mUserNeedsBadging.delete(userHandle);  
  13.     removeUnusedPackagesLILPw(userManager, userHandle);  
  14. }  
cleanUpUserLILPw方法主要的工作就是调用mInstaller的removeUserDataDirs()方法来删除用户目录下所有应用的数据。同时调用mSettings的removeUserLPw()方法来删除PackageManagerService中和用户相关的数据,如下:
[java] view plain copy
  1. void removeUserLPw(int userId) {  
  2.     Set<Entry<String, PackageSetting>> entries = mPackages.entrySet();  
  3.     for (Entry<String, PackageSetting> entry : entries) {  
  4.         entry.getValue().removeUser(userId);  
  5.     }<span style="font-family: Arial, Helvetica, sans-serif;">//删除每个应用信息中该用户的信息</span>  
  6.     mPreferredActivities.remove(userId);//删除mPreferredActivities列表中该用户的数据  
  7.     File file = getUserPackagesStateFile(userId);  
  8.     file.delete();//删除该用户目录下的package-restrictions.xml文件  
  9.     file = getUserPackagesStateBackupFile(userId);  
  10.     file.delete();  
  11.     removeCrossProfileIntentFiltersLPw(userId);  
  12. }  

三、ActivityManagerService和多用户

UserManagerService主要管理用户的账号信息,运行中的用户管理由ActivityManagerService实行。

1、用户的状态

用户有四种运行状态,定义如下:

[java] view plain copy
  1. public final class UserStartedState {  
  2.     // User is first coming up.  
  3.     public final static int STATE_BOOTING = 0;//用户正在启动  
  4.     // User is in the normal running state.  
  5.     public final static int STATE_RUNNING = 1;//用户正在运行  
  6.     // User is in the initial process of being stopped.  
  7.     public final static int STATE_STOPPING = 2;//用户正在停止  
  8.     // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.  
  9.     public final static int STATE_SHUTDOWN = 3;//用户已经关闭  
在AMS中,变量mCurrentUserId记录了当前的用户Id,mStartedUsers列表则保存了正在运行的用户,只有在mStartedUsers列表中的用户才会有上面这4中状态,不在列表中的是已经注册了但是没有运行的用户。

2、切换当前用户

ActivityManagerService中提供了切换当前用户的接口switchUser(),如下:
[java] view plain copy
  1. public boolean switchUser(final int userId) {  
  2.     enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);  
  3.     String userName;  
  4.     synchronized (this) {  
  5.         UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);//获取userId对应的UserInfo  
  6.         if (userInfo == null) {  
  7.             Slog.w(TAG, "No user info for user #" + userId);  
  8.             return false;  
  9.         }  
  10.         if (userInfo.isManagedProfile()) {//如果这个UserInfo只是User的另一份profile,退出  
  11.             Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");  
  12.             return false;  
  13.         }  
  14.         userName = userInfo.name;  
  15.         mTargetUserId = userId;  
  16.     }  
  17.     mHandler.removeMessages(START_USER_SWITCH_MSG);  
  18.     mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));//发送切换用户的消息  
  19.     return true;  
  20. }  
switchUser()先调用getUserInfo()方法得到userId对应的用户信息,然后通过isManagedProfile()方法来判断这份UserInfo是否只是一个profile(Android中允许一个用户还拥有另一份profile)。如果确实是一个用户,则发出消息START_USER_SWITCH_MSG。

对消息START_USER_SWITCH_MSG的处理是调用方法showUserSwitchDialog,这个方法将弹出一个对话框来确定是否要进行用户切换,一旦用户点击确定按钮后,调用startUserInForeground()方法

[java] view plain copy
  1. case START_USER_SWITCH_MSG: {  
  2.     showUserSwitchDialog(msg.arg1, (String) msg.obj);  
  3.     break;  
  4. }  
[java] view plain copy
  1. private void showUserSwitchDialog(int userId, String userName) {  
  2.     // The dialog will show and then initiate the user switch by calling startUserInForeground  
  3.     Dialog d = new UserSwitchingDialog(this, mContext, userId, userName,  
  4.             true /* above system */);  
  5.     d.show();  
  6. }  

startUserInForeground()方法如下:

[java] view plain copy
  1. /** 
  2.  * Start user, if its not already running, and bring it to foreground. 
  3.  */  
  4. boolean startUserInForeground(final int userId, Dialog dlg) {  
  5.     boolean result = startUser(userId, /* foreground */ true);  
  6.     dlg.dismiss();  
  7.     return result;  
  8. }  
在startUserInForeground()方法中只是调用了startUser()方法,如下:
[java] view plain copy
  1. private boolean startUser(final int userId, final boolean foreground) {  
  2.     if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)  
  3.             != PackageManager.PERMISSION_GRANTED) {  
  4.         。。。。。。//检查调用者权限  
  5.     }  
  6.     final long ident = Binder.clearCallingIdentity();  
  7.     try {  
  8.         synchronized (this) {  
  9.             final int oldUserId = mCurrentUserId;  
  10.             if (oldUserId == userId) {  
  11.                 return true;//当前用户已经是参数指定的用户,退出  
  12.             }  
  13.   
  14.             mStackSupervisor.setLockTaskModeLocked(nullfalse"startUser");  
  15.   
  16.             final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);  
  17.             。。。。。。//一些错误处理,返回false  
  18.             if (foreground) {  
  19.                 mWindowManager.startFreezingScreen(R.anim.screen_user_exit,  
  20.                         R.anim.screen_user_enter);  
  21.             }  
  22.   
  23.             boolean needStart = false;  
  24.   
  25.             // 如果用户还没有启动,需要先启动用户,切换用户状态为正在启动  
  26.             if (mStartedUsers.get(userId) == null) {  
  27.                 mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));  
  28.                 updateStartedUserArrayLocked();  
  29.                 needStart = true;  
  30.             }  
  31.   
  32.             final Integer userIdInt = Integer.valueOf(userId);  
  33.             mUserLru.remove(userIdInt);  
  34.             mUserLru.add(userIdInt);//调整用户在mUserLru列表中的位置,当前用户位于最末的位置  
  35.   
  36.             if (foreground) {//前台切换  
  37.                 mCurrentUserId = userId;//切换当前用户  
  38.                 mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up  
  39.                 updateCurrentProfileIdsLocked();  
  40.                 mWindowManager.setCurrentUser(userId, mCurrentProfileIds);//在WMS这设置当前用户  
  41.                 mWindowManager.lockNow(null);//锁上屏幕  
  42.             } else {  
  43.                 final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);  
  44.                 updateCurrentProfileIdsLocked();  
  45.                 mWindowManager.setCurrentProfileIds(mCurrentProfileIds);  
  46.                 mUserLru.remove(currentUserIdInt);  
  47.                 mUserLru.add(currentUserIdInt);  
  48.             }  
  49.   
  50.             final UserStartedState uss = mStartedUsers.get(userId);  
  51.   
  52.             // Make sure user is in the started state.  If it is currently  
  53.             // stopping, we need to knock that off.  
  54.             if (uss.mState == UserStartedState.STATE_STOPPING) {  
  55.                 // 如果用户的状态为正在停止,切换为正在运行  
  56.                 uss.mState = UserStartedState.STATE_RUNNING;  
  57.                 updateStartedUserArrayLocked();  
  58.                 needStart = true;  
  59.             } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) {  
  60.                 // 如果用户的状态为正在关闭,切换为正在启动  
  61.                 uss.mState = UserStartedState.STATE_BOOTING;  
  62.                 updateStartedUserArrayLocked();  
  63.                 needStart = true;  
  64.             }  
  65.   
  66.             if (uss.mState == UserStartedState.STATE_BOOTING) {  
  67.                 //如果用户的状态为正在启动,发送消息SYSTEM_USER_START_MSG  
  68.                 mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));  
  69.             }  
  70.   
  71.             if (foreground) {  
  72.                 mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,  
  73.                         oldUserId));  
  74.                 mHandler.removeMessages(REPORT_USER_SWITCH_MSG);  
  75.                 mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);  
  76.                 mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,  
  77.                         oldUserId, userId, uss));  
  78.                 mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,  
  79.                         oldUserId, userId, uss), USER_SWITCH_TIMEOUT);  
  80.             }  
  81.   
  82.             if (needStart) {  
  83.                 // 如果切换前用户不在STATE_RUNNING状态,向该用户发送广播ACTION_USER_STARTED  
  84.                 Intent intent = new Intent(Intent.ACTION_USER_STARTED);  
  85.                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY  
  86.                         | Intent.FLAG_RECEIVER_FOREGROUND);  
  87.                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);  
  88.                 broadcastIntentLocked(nullnull, intent,  
  89.                         nullnull0nullnullnull, AppOpsManager.OP_NONE,  
  90.                         falsefalse, MY_PID, Process.SYSTEM_UID, userId);  
  91.             }  
  92.   
  93.             if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {  
  94.                 if (userId != UserHandle.USER_OWNER) {//如果用户还没初始化,向该用户发送广播ACTION_USER_INITIALIZE  
  95.                     Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);  
  96.                     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);  
  97.                     broadcastIntentLocked(nullnull, intent, null,  
  98.                             new IIntentReceiver.Stub() {  
  99.                                 public void performReceive(Intent intent, int resultCode,  
  100.                                         String data, Bundle extras, boolean ordered,  
  101.                                         boolean sticky, int sendingUser) {  
  102.                                     onUserInitialized(uss, foreground, oldUserId, userId);  
  103.                                 }  
  104.                             }, 0nullnullnull, AppOpsManager.OP_NONE,  
  105.                             truefalse, MY_PID, Process.SYSTEM_UID,  
  106.                             userId);  
  107.                     uss.initializing = true;  
  108.                 } else {//否则直接调用UserManagerService的makeInitialized方法  
  109.                     getUserManagerLocked().makeInitialized(userInfo.id);  
  110.                 }  
  111.             }  
  112.   
  113.             if (foreground) {  
  114.                 if (!uss.initializing) {//如果用户已经初始化了,将它设为前台用户  
  115.                     moveUserToForeground(uss, oldUserId, userId);  
  116.                 }  
  117.             } else {//否则先将用户加入到mStartingBackgroundUser中  
  118.                 mStackSupervisor.startBackgroundUserLocked(userId, uss);  
  119.             }  
  120.   
  121.             if (needStart) {//如果用户不在STATE_RUNNING状态,向所有用户发送广播ACTION_USER_STARTING  
  122.                 Intent intent = new Intent(Intent.ACTION_USER_STARTING);  
  123.                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  124.                 intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);  
  125.                 broadcastIntentLocked(nullnull, intent,  
  126.                         nullnew IIntentReceiver.Stub() {  
  127.                             @Override  
  128.                             public void performReceive(Intent intent, int resultCode, String data,  
  129.                                     Bundle extras, boolean ordered, boolean sticky, int sendingUser)  
  130.                                     throws RemoteException {  
  131.                             }  
  132.                         }, 0nullnull,  
  133.                         INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,  
  134.                         truefalse, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);  
  135.             }  
  136.         }  
  137.     } finally {  
  138.         Binder.restoreCallingIdentity(ident);  
  139.     }  
  140.   
  141.     return true;  
  142. }  

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,如下:

[java] view plain copy
  1. case REPORT_USER_SWITCH_MSG: {  
  2.     dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);  
  3.     break;  
  4. }  
[java] view plain copy
  1. void dispatchUserSwitch(final UserStartedState uss, final int oldUserId,  
  2.         final int newUserId) {  
  3.     final int N = mUserSwitchObservers.beginBroadcast();  
  4.     if (N > 0) {  
  5.         final IRemoteCallback callback = new IRemoteCallback.Stub() {  
  6.             int mCount = 0;  
  7.             @Override  
  8.             public void sendResult(Bundle data) throws RemoteException {  
  9.                 synchronized (ActivityManagerService.this) {  
  10.                     if (mCurUserSwitchCallback == this) {  
  11.                         mCount++;//如果收到一条返回结果的调用,mCount++  
  12.                         if (mCount == N) {//如果所有结果都返回了,发送继续处理的消息  
  13.                             sendContinueUserSwitchLocked(uss, oldUserId, newUserId);  
  14.                         }  
  15.                     }  
  16.                 }  
  17.             }  
  18.         };  
  19.         synchronized (this) {  
  20.             uss.switching = true;  
  21.             mCurUserSwitchCallback = callback;  
  22.         }  
  23.         for (int i=0; i<N; i++) {  
  24.             try {//调用观测对象的onUserSwitching方法  
  25.                 mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(  
  26.                         newUserId, callback);  
  27.             } catch (RemoteException e) {  
  28.             }  
  29.         }  
  30.     } else {//如果没有观测对象,直接调用sendContinueUserSwitchLocked  
  31.         synchronized (this) {  
  32.             sendContinueUserSwitchLocked(uss, oldUserId, newUserId);  
  33.         }  
  34.     }  
  35.     mUserSwitchObservers.finishBroadcast();  
  36. }  

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消息,继续进行用户切换。如下:

[java] view plain copy
  1. case USER_SWITCH_TIMEOUT_MSG: {  
  2.     timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);  
  3.     break;  
  4. }  
[java] view plain copy
  1. void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {  
  2.     synchronized (this) {  
  3.         Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);  
  4.         sendContinueUserSwitchLocked(uss, oldUserId, newUserId);  
  5.     }  
  6. }  
[java] view plain copy
  1. void sendContinueUserSwitchLocked(UserStartedState uss, int oldUserId, int newUserId) {  
  2.     mCurUserSwitchCallback = null;  
  3.     mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);  
  4.     mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,  
  5.             oldUserId, newUserId, uss));  
  6. }  
[java] view plain copy
  1. case CONTINUE_USER_SWITCH_MSG: {  
  2.     continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);  
  3.     break;  
  4. }  
[java] view plain copy
  1. void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {  
  2.     completeSwitchAndInitalize(uss, newUserId, falsetrue);  
  3. }  
[java] view plain copy
  1. void completeSwitchAndInitalize(UserStartedState uss, int newUserId,  
  2.         boolean clearInitializing, boolean clearSwitching) {  
  3.     boolean unfrozen = false;  
  4.     synchronized (this) {  
  5.         if (clearInitializing) {  
  6.             uss.initializing = false;  
  7.             getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());  
  8.         }  
  9.         if (clearSwitching) {  
  10.             uss.switching = false;  
  11.         }  
  12.         if (!uss.switching && !uss.initializing) {  
  13.             mWindowManager.stopFreezingScreen();  
  14.             unfrozen = true;  
  15.         }  
  16.     }  
  17.     if (unfrozen) {  
  18.         final int N = mUserSwitchObservers.beginBroadcast();  
  19.         for (int i=0; i<N; i++) {  
  20.             try {  
  21.                 mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);  
  22.             } catch (RemoteException e) {  
  23.             }  
  24.         }  
  25.         mUserSwitchObservers.finishBroadcast();  
  26.     }  
  27.     stopGuestUserIfBackground();  
  28. }  
CONTINUE_USER_SWITCH_MSG消息的处理方法是continueUserSwitch(),这个方法会调用completeSwitchAndInitalize()方法继续处理,处理的结果是对mUserSwitchObservers列表中所有观测对象调用他们的onUserSwitchComplete()方法。

至此,startUser()方法的工作就完成了。但是还有一个问题,状态为STATE_BOOTING的用户什么时候切换到STATE_RUNNING状态?在activityIdleInternalLocked()方法中有一段代码如下:

[java] view plain copy
  1.    for (int i = 0; i < startingUsers.size(); i++) {  
  2.      mService.finishUserSwitch(startingUsers.get(i));  
  3.   }  
activityIdleInternalLocked()方法会在Activity进入Idle状态时调用,也就相当于用户已经切换完成了,会对每个startingUsers列表中的用户调用finishUserBoot()方法,如下:
[java] view plain copy
  1. void finishUserSwitch(UserStartedState uss) {  
  2.     synchronized (this) {  
  3.         finishUserBoot(uss);  
  4.   
  5.         startProfilesLocked();  
  6.   
  7.         int num = mUserLru.size();  
  8.         int i = 0;  
  9.         while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {  
  10.             Integer oldUserId = mUserLru.get(i);  
  11.             UserStartedState oldUss = mStartedUsers.get(oldUserId);  
  12.             if (oldUss == null) {//正常情况下不会出现为null  
  13.                 // Shouldn't happen, but be sane if it does.  
  14.                 mUserLru.remove(i);  
  15.                 num--;  
  16.                 continue;  
  17.             }  
  18.             if (oldUss.mState == UserStartedState.STATE_STOPPING  
  19.                     || oldUss.mState == UserStartedState.STATE_SHUTDOWN) {  
  20.                 // This user is already stopping, doesn't count.如果用户已经停止了,继续  
  21.                 num--;  
  22.                 i++;  
  23.                 continue;  
  24.             }  
  25.             if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {  
  26.                 // Owner and current can't be stopped, but count as running.  
  27.                 i++;//如果是主用户或当前用户,继续  
  28.                 continue;  
  29.             }  
  30.             // This is a user to be stopped.停止用户  
  31.             stopUserLocked(oldUserId, null);  
  32.             num--;  
  33.             i++;  
  34.         }  
  35.     }  
  36. }  
finishUserSwitch()方法完成了两件工作。一是调用方法finishUserBoot()把状态还是STATE_BOOTING的用户切换到STATE_RUNNING状态,同时发送广播ACTION_BOOT_COMPLETED给该用户,表示用户启动结束。另一件工作是停止多余的用户。从mUserLru列表的第0项开始,对于处于状态STATE_RUNNING的用户,只要不是主用户或当前用户,一律停止,只保留处于STATE_RUNNING状态的用户。

3、停止用户运行

ActivityManagerService中停止用户运行的接口是stopUser(),这个方法在检查了调用进程的权限后,调用内部方法stopUserLocked()继续停止用户的工作,stopUserLocked()代码如下:

[java] view plain copy
  1. private int stopUserLocked(final int userId, final IStopUserCallback callback) {  
  2.     if (DEBUG_MU) Slog.i(TAG_MU, "stopUserLocked userId=" + userId);  
  3.     if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {  
  4.         return ActivityManager.USER_OP_IS_CURRENT;  
  5.     }//如果要求停止的用户是当前用户,不能停止,返回  
  6.   
  7.     final UserStartedState uss = mStartedUsers.get(userId);  
  8.     if (uss == null) {  
  9.         // User is not started, nothing to do...  but we do need to  
  10.         // callback if requested.  
  11.         if (callback != null) {  
  12.             mHandler.post(new Runnable() {  
  13.                 @Override  
  14.                 public void run() {  
  15.                     try {  
  16.                         callback.userStopped(userId);//回调方法userStopped  
  17.                     } catch (RemoteException e) {  
  18.                     }  
  19.                 }  
  20.             });  
  21.         }  
  22.         return ActivityManager.USER_OP_SUCCESS;//0  
  23.     }  
  24.   
  25.     if (callback != null) {  
  26.         uss.mStopCallbacks.add(callback);  
  27.     }  
  28.   
  29.     if (uss.mState != UserStartedState.STATE_STOPPING  
  30.             && uss.mState != UserStartedState.STATE_SHUTDOWN) {  
  31.         uss.mState = UserStartedState.STATE_STOPPING;//将用户的状态切换为正在停止  
  32.         updateStartedUserArrayLocked();//更新mStartedUserArray数组,存放UserStartedState对象  
  33.   
  34.         long ident = Binder.clearCallingIdentity();  
  35.         try {  
  36.             // We are going to broadcast ACTION_USER_STOPPING and then  
  37.             // once that is done send a final ACTION_SHUTDOWN and then  
  38.             // stop the user.  
  39.             final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);  
  40.             stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);  
  41.             stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);  
  42.             stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);  
  43.             final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);  
  44.             // This is the result receiver for the final shutdown broadcast.  
  45.             final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {  
  46.                 @Override  
  47.                 public void performReceive(Intent intent, int resultCode, String data,  
  48.                         Bundle extras, boolean ordered, boolean sticky, int sendingUser) {  
  49.                     finishUserStop(uss);//收到ACTION_SHUTDOWN广播,继续执行  
  50.                 }  
  51.             };  
  52.             // This is the result receiver for the initial stopping broadcast.  
  53.             final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {  
  54.                 @Override  
  55.                 public void performReceive(Intent intent, int resultCode, String data,  
  56.                         Bundle extras, boolean ordered, boolean sticky, int sendingUser) {  
  57.                     // On to the next.  
  58.                     synchronized (ActivityManagerService.this) {  
  59.                         if (uss.mState != UserStartedState.STATE_STOPPING) {  
  60.                             // Whoops, we are being started back up.  Abort, abort!  
  61.                             return;  
  62.                         }  
  63.                         uss.mState = UserStartedState.STATE_SHUTDOWN;//收到ACTION_USER_STOPPING广播后,改变用户状态  
  64.                     }  
  65.                     mBatteryStatsService.noteEvent(  
  66.                             BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,  
  67.                             Integer.toString(userId), userId);  
  68.                     mSystemServiceManager.stopUser(userId);  
  69.                     broadcastIntentLocked(nullnull, shutdownIntent,  
  70.                             null, shutdownReceiver, 0nullnullnull, AppOpsManager.OP_NONE,  
  71.                             truefalse, MY_PID, Process.SYSTEM_UID, userId);//再发送广播shutdownIntent(Intent.ACTION_SHUTDOWN)  
  72.                 }  
  73.             };  
  74.             // Kick things off.  
  75.             broadcastIntentLocked(nullnull, stoppingIntent,  
  76.                     null, stoppingReceiver, 0nullnull,  
  77.                     INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,  
  78.                     truefalse, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);//发送广播stoppingIntent(Intent.ACTION_USER_STOPPING)  
  79.         } finally {  
  80.             Binder.restoreCallingIdentity(ident);  
  81.         }  
  82.     }  
  83.   
  84.     return ActivityManager.USER_OP_SUCCESS;  
  85. }  
stopUserLocked()方法首先判断请求停止的用户是否是当前用户,是,返回。由此可见,当前正在运行的用户是不能停止的,必须先切换到其他的用户才能再停止该用户。

接下来判断用户是否处于运行状态,没有运行就post一个消息,在消息的处理方法中调用参数中的回调方法结束处理。

如果用户已经运行,先切换用户的状态为STATE_STOPPING,然后广播一个用户正在停止的消息ACTION_USER_STOPPING,同时方法中也会接收这个广播,收到后切换用户的状态为STATE_SHUTDOWN,再发出一个ACTION_SHUTDOWN的广播,方法中同样也会接受这个广播,收到后再调用finishUserStop()方法继续处理,如下:

[java] view plain copy
  1. void finishUserStop(UserStartedState uss) {  
  2.     final int userId = uss.mHandle.getIdentifier();  
  3.     boolean stopped;  
  4.     ArrayList<IStopUserCallback> callbacks;  
  5.     synchronized (this) {  
  6.         callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);  
  7.         if (mStartedUsers.get(userId) != uss) {  
  8.             stopped = false;  
  9.         } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) {  
  10.             stopped = false;  
  11.         } else {  
  12.             stopped = true;  
  13.             // User can no longer run.从AMS的用户管理的数据结构中删除用户  
  14.             mStartedUsers.remove(userId);  
  15.             mUserLru.remove(Integer.valueOf(userId));  
  16.             updateStartedUserArrayLocked();  
  17.   
  18.             // Clean up all state and processes associated with the user.  
  19.             // Kill all the processes for the user.  
  20.             forceStopUserLocked(userId, "finish user");//发送广播Intent.ACTION_USER_STOPPED  
  21.         }  
  22.   
  23.         // Explicitly remove the old information in mRecentTasks.  
  24.         removeRecentTasksForUserLocked(userId);//清除用户相关的Recent Task列表  
  25.     }  
  26.   
  27.     for (int i=0; i<callbacks.size(); i++) {  
  28.         try {//调用UserManagerService的回调方法  
  29.             if (stopped) callbacks.get(i).userStopped(userId);  
  30.             else callbacks.get(i).userStopAborted(userId);  
  31.         } catch (RemoteException e) {  
  32.         }  
  33.     }  
  34.   
  35.     if (stopped) {  
  36.         mSystemServiceManager.cleanupUser(userId);//从mStackSupervisor删除用户  
  37.         synchronized (this) {  
  38.             mStackSupervisor.removeUserLocked(userId);  
  39.         }  
  40.     }  
  41. }  
finishUserStop()方法的主要工作是从mStartedUsers和mUserLru中删除用户,然后发送广播Intent.ACTION_USER_STOPPED来通知某个用户停止了,接下来调用UserManagerService的回调方法通知UserManagerService来处理,最后调用removeUserLocked()方法从mStackSupervisor列表中删除用户的相关信息。
0 0
原创粉丝点击