Android中的多用户与Windows的多用户类似,可以支持多个用户使用系统。通常,第一个在系统中注册的用户将默认成为系统管理员。
不同用户的设置各不相同,并且不同用户安装的应用及应用数据也不相同。但是系统中和硬件相关的设置则是共用的,例如网络设置等。
Android与Windows不同,用户切换后前面用户运行的后台进程还可以继续运行。这样,进行用户切换时无须中断一些后台进行的耗时操作(如下载)。
UserManagerService的主要功能是创建和删除用户,以及查询用户信息。
UserManagerService是在PackageManagerService的构造方法中创建的,如下:
[java] view plain copy sUserManager = new UserManagerService(context, this, mInstallLock, mPackages); UserManagerService的构造方法,如下:[java] view plain copy UserManagerService(Context context, PackageManagerService pm, Object installLock, Object packagesLock) { this(context, pm, installLock, packagesLock, Environment.getDataDirectory(), new File(Environment.getDataDirectory(), "user")); } 调用另一个构造方法,并多传递了两个参数:/data目录和/data/user文件。如下:[java] view plain copy 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; } } } 在构造方法中创建了几个目录:/data/system/users、data/system/users/0、/data/system/users/userlist.xml等。之后设置基本的限制条件,如下:[java] view plain copy private void initDefaultGuestRestrictions() { if (mGuestRestrictions.isEmpty()) { mGuestRestrictions.putBoolean(UserManager.DISALLOW_OUTGOING_CALLS, true);//"no_outgoing_calls" mGuestRestrictions.putBoolean(UserManager.DISALLOW_SMS, true);//"no_sms" } } 然后调用readUserListLocked()方法解析/data/system/users/userlist.xml文件,这个文件保存了系统中所有用户的id信息。文件内容如下:[java] view plain copy <?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> 得到id信息后还有读取保存了用户注册信息的xml文件,以用户id的数字表示,如0.xml。内容如下:[java] view plain copy <?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> 读取用户的xml文件内容后,将根据文件内容来创建和初始化一个UserInfo对象来保存信息,并把该对象加入到mUsers列表中。如果xml文件中某个用户的属性中有partial="true',则表示这个用户没有完全创建成功,需要从系统中移除掉。这样UserManagerService的初始化工作就完成了,主要的工作是分析userlist.xml文件,并创建了mUsers列表中的UserInfo对象。
UserManagerService服务中添加用户的接口是createUser(),如下:
[java] view plain copy public UserInfo createUser(String name, int flags) { checkManageUsersPermission("Only the system can create users"); return createUserInternal(name, flags, UserHandle.USER_NULL); } createUser()方法首先检查调用者的权限,只有system身份的进程才能调用这个方法。然后调用createUserInternal()方法继续执行,如下:[java] view plain copy 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; (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。
UserManagerService服务中删除用户的接口是removeUser()方法,如下:
[java] view plain copy 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()方法。如下:
[java] view plain copy 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()方法。代码如下:[java] view plain copy 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信息,最后将用户目录下的所有文件都删除。在多用户的环境中,所有用户安装的应用还是位于/data/app目录,但是这些应用的数据在每个用户的目录/data/user/<用户id>/下都有单独的一份。目录/data/data也还保存应用的数据,但这些数据只对id为0的用户有效。
上面讲到创建用户时会调用PackageManagerService的createNewUserLILPw()方法,如下:
[java] view plain copy /** Called by UserManagerService */ 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()方法是如何处理的,如下:
[java] view plain copy public int createUserConfig(int userId) { StringBuilder builder = new StringBuilder("mkuserconfig"); builder.append(' '); builder.append(userId); return mInstaller.execute(builder.toString()); } mInstaller是InstallerConnection的对象,这里调用InstallConnection对象的execute()方法,如下:[java] view plain copy public int execute(String cmd) { String res = transact(cmd); try { return Integer.parseInt(res); } catch (NumberFormatException ex) { return -1; } } 这里实现了与installd服务通信的过程,具体操作是由installd服务完成的。再看下mSettings的createNewUserLILPw()方法,我们知道mSettings中保存的是从文件中读取的所有应用的信息。如下:[java] view plain copy 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); } createNewUserLILPw()方法会遍历mPackages列表,这个列表保存的是系统中所有已安装的应用信息,然后针对每一个应用调用installer的createUserData()方法,调用Installer的方法最终会调用installd守护进程的命令,这里最终调用installd的“mkuserdata”命令来执行应用数据目录的创建工作。[java] view plain copy 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和组件的关联数据。
PackageManagerService中删除用户的方法是cleanUpUserLILPw()方法,如下:
[java] view plain copy /** 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); } cleanUpUserLILPw方法主要的工作就是调用mInstaller的removeUserDataDirs()方法来删除用户目录下所有应用的数据。同时调用mSettings的removeUserLPw()方法来删除PackageManagerService中和用户相关的数据,如下:[java] view plain copy 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); }UserManagerService主要管理用户的账号信息,运行中的用户管理由ActivityManagerService实行。
用户有四种运行状态,定义如下:
[java] view plain copy 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;//用户已经关闭 在AMS中,变量mCurrentUserId记录了当前的用户Id,mStartedUsers列表则保存了正在运行的用户,只有在mStartedUsers列表中的用户才会有上面这4中状态,不在列表中的是已经注册了但是没有运行的用户。对消息START_USER_SWITCH_MSG的处理是调用方法showUserSwitchDialog,这个方法将弹出一个对话框来确定是否要进行用户切换,一旦用户点击确定按钮后,调用startUserInForeground()方法
[java] view plain copy case START_USER_SWITCH_MSG: { showUserSwitchDialog(msg.arg1, (String) msg.obj); break; } [java] view plain copy 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()方法如下:
[java] view plain copy /** * 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; } 在startUserInForeground()方法中只是调用了startUser()方法,如下:[java] view plain copy 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,如下:
[java] view plain copy case REPORT_USER_SWITCH_MSG: { dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2); break; } [java] view plain copy 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消息,继续进行用户切换。如下:
[java] view plain copy case USER_SWITCH_TIMEOUT_MSG: { timeoutUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2); break; } [java] view plain copy void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) { synchronized (this) { Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId); sendContinueUserSwitchLocked(uss, oldUserId, newUserId); } } [java] view plain copy 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)); } [java] view plain copy case CONTINUE_USER_SWITCH_MSG: { continueUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2); break; } [java] view plain copy void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) { completeSwitchAndInitalize(uss, newUserId, false, true); } [java] view plain copy 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(); } CONTINUE_USER_SWITCH_MSG消息的处理方法是continueUserSwitch(),这个方法会调用completeSwitchAndInitalize()方法继续处理,处理的结果是对mUserSwitchObservers列表中所有观测对象调用他们的onUserSwitchComplete()方法。至此,startUser()方法的工作就完成了。但是还有一个问题,状态为STATE_BOOTING的用户什么时候切换到STATE_RUNNING状态?在activityIdleInternalLocked()方法中有一段代码如下:
[java] view plain copy for (int i = 0; i < startingUsers.size(); i++) { mService.finishUserSwitch(startingUsers.get(i)); } activityIdleInternalLocked()方法会在Activity进入Idle状态时调用,也就相当于用户已经切换完成了,会对每个startingUsers列表中的用户调用finishUserBoot()方法,如下:[java] view plain copy 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++; } } } finishUserSwitch()方法完成了两件工作。一是调用方法finishUserBoot()把状态还是STATE_BOOTING的用户切换到STATE_RUNNING状态,同时发送广播ACTION_BOOT_COMPLETED给该用户,表示用户启动结束。另一件工作是停止多余的用户。从mUserLru列表的第0项开始,对于处于状态STATE_RUNNING的用户,只要不是主用户或当前用户,一律停止,只保留处于STATE_RUNNING状态的用户。ActivityManagerService中停止用户运行的接口是stopUser(),这个方法在检查了调用进程的权限后,调用内部方法stopUserLocked()继续停止用户的工作,stopUserLocked()代码如下:
[java] view plain copy 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; } stopUserLocked()方法首先判断请求停止的用户是否是当前用户,是,返回。由此可见,当前正在运行的用户是不能停止的,必须先切换到其他的用户才能再停止该用户。接下来判断用户是否处于运行状态,没有运行就post一个消息,在消息的处理方法中调用参数中的回调方法结束处理。
如果用户已经运行,先切换用户的状态为STATE_STOPPING,然后广播一个用户正在停止的消息ACTION_USER_STOPPING,同时方法中也会接收这个广播,收到后切换用户的状态为STATE_SHUTDOWN,再发出一个ACTION_SHUTDOWN的广播,方法中同样也会接受这个广播,收到后再调用finishUserStop()方法继续处理,如下:
[java] view plain copy 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); } } } finishUserStop()方法的主要工作是从mStartedUsers和mUserLru中删除用户,然后发送广播Intent.ACTION_USER_STOPPED来通知某个用户停止了,接下来调用UserManagerService的回调方法通知UserManagerService来处理,最后调用removeUserLocked()方法从mStackSupervisor列表中删除用户的相关信息。新闻热点
疑难解答