android 多使用者管理UserManager

samay發表於2017-09-22

一.概述

Android從4.2開始支援多使用者模式,不同的使用者執行在不同的使用者空間,相關的系統設定是各不相同而且不同使用者安裝的應用和應用資料也是不一樣的,但是系統中和硬體相關的設計則是共用的。

Android的多使用者實現主要通過UserManagerService(UMS)對多使用者進行建立、刪除等操作。

*Binder服務端:UMS繼承於IUserManager.Stub,作為Binder服務端;

*Binder伺服器:UserManager的成員變數mService繼承於IUserManager.Stub.Proxy,該變數作為binder客戶端。採用標準的binder通訊進行資訊傳遞

二.概念

2.1 userId,uid,appId

userId:使用者id; appId:跟使用者空間無關的應用程式id;取值範圍0<=appId<100000;uid:跟使用者空間緊密相關的應用程式id.

    uid = userId * 100000 + appId複製程式碼

2.2 UserHandler

常見方法:

方法 描述
isSameUser 比較兩個uid的userId是否相同
isSameApp 比較兩個uid的appId是否相同
isApp appId是否屬於區間[10000,19999]
isIsolated appId是否屬於區間[99000,99999]
getIdentifier 獲取UserHandler所對應的userId

常見成員變數:

userId 賦值 含義
USER_OWNER 0 擁有者
USER_ALL -1 所有使用者
USER_CURRENT -2 當前活動使用者
USER_CURRENT_OR_SELF -3 當前使用者或者呼叫者所在使用者
USER_NULL -1000 未定義使用者

2.3 UserInfo

UserInfo代表的是一個使用者的資訊,涉及到的flags及其含義,如下:

flags 含義
FLAG_PRIMARY 主使用者,只有一個user具有該標識
FLAG_ADMIN 具有管理特權的使用者,例如建立或刪除其他使用者
FLAG_GUEST 訪客使用者,可能是臨時的
FLAG_RESTRICTED 限制性使用者,較普通使用者具有更多限制,例如禁止安裝app或者管理wifi等
FLAG_INITIALIZED 表明使用者已初始化
FLAG_MANAGED_PROFILE 表明該使用者是另一個使用者的輪廓
FLAG_DISABLED 表明該使用者處於不可用狀態

2.4 UserState

        // User is first coming up.
        public final static int STATE_BOOTING = 0;
        // User is in the locked state.
        public final static int STATE_RUNNING_LOCKED = 1;
        // User is in the unlocking state.
        public final static int STATE_RUNNING_UNLOCKING = 2;
        // User is in the running state.
        public final static int STATE_RUNNING_UNLOCKED = 3;
        // User is in the initial process of being stopped.
        public final static int STATE_STOPPING = 4;
        // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN.
        public final static int STATE_SHUTDOWN = 5;複製程式碼

三.UMS的啟動

UMS在PMS中初始化

    public PackageManagerService(Context context, Installer installer,
                boolean factoryTest, boolean onlyCore) {
            ......
                 sUserManager = new UserManagerService(context, this, mPackages);
            .....
                }複製程式碼

UMS的初始化操作

    private UserManagerService(Context context, PackageManagerService pm,
                Object packagesLock, File dataDir) {
            mContext = context;
            mPm = pm;
            mPackagesLock = packagesLock;
            mHandler = new MainHandler();
            synchronized (mPackagesLock) {
                //建立目錄/data/system/users
                mUsersDir = new File(dataDir, USER_INFO_DIR);
                mUsersDir.mkdirs();
                //建立目錄/data/system/users/0
                File userZeroDir = new File(mUsersDir, String.valueOf(UserHandle.USER_SYSTEM));
                userZeroDir.mkdirs();
                FileUtils.setPermissions(mUsersDir.toString(),
                        FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IROTH | FileUtils.S_IXOTH,
                        -1, -1);
                //mYserListFile檔案路徑為/data/system/users/userlist.xml
                mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
                initDefaultGuestRestrictions();
                //解析userlist.xml檔案
                readUserListLP();
                sInstance = this;
            }
            mLocalService = new LocalService();
            LocalServices.addService(UserManagerInternal.class, mLocalService);
            mLockPatternUtils = new LockPatternUtils(mContext);
            //表示System正處於啟動階段
            mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
        }複製程式碼

四.建立一個使用者

建立一個多使用者主要是在UMS中createUserInternalUnchecked中執行

    private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
        //檢查一下手機是否處於低記憶體裝置
        if (ActivityManager.isLowRamDeviceStatic()) {
            return null;
        }
        //判斷需要建立的user是否是guest使用者
        final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
        //判斷需要建立的user是否是profile使用者
        final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
        //判斷需要建立的user是否是restricted使用者
        final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
        final boolean isDemo = (flags & UserInfo.FLAG_DEMO) != 0;
        final long ident = Binder.clearCallingIdentity();
        UserInfo userInfo;
        UserData userData;
        final int userId;
        try {
            synchronized (mPackagesLock) {
                UserData parent = null;
                if (parentId != UserHandle.USER_NULL) {
                    synchronized (mUsersLock) {
                        parent = getUserDataLU(parentId);
                    }
                    if (parent == null) return null;
                }
                if (isManagedProfile && !canAddMoreManagedProfiles(parentId, false)) {
                    Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
                    return null;
                }
                if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
                    // If we're not adding a guest/demo user or a managed profile and the limit has
                    // been reached, cannot add a user.
                    return null;
                }
                // If we're adding a guest and there already exists one, bail.
                if (isGuest && findCurrentGuestUser() != null) {
                    return null;
                }
                // In legacy mode, restricted profile's parent can only be the owner user
                if (isRestricted && !UserManager.isSplitSystemUser()
                        && (parentId != UserHandle.USER_SYSTEM)) {
                    Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
                    return null;
                }
                if (isRestricted && UserManager.isSplitSystemUser()) {
                    if (parent == null) {
                        Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
                                + "specified");
                        return null;
                    }
                    if (!parent.info.canHaveProfile()) {
                        Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
                                + "created for the specified parent user id " + parentId);
                        return null;
                    }
                }
                if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0
                        && (flags & UserInfo.FLAG_DEMO) == 0) {
                    Log.e(LOG_TAG,
                            "Ephemeral users are supported on split-system-user systems only.");
                    return null;
                }
                // In split system user mode, we assign the first human user the primary flag.
                // And if there is no device owner, we also assign the admin flag to primary user.
                if (UserManager.isSplitSystemUser()
                        && !isGuest && !isManagedProfile && getPrimaryUser() == null) {
                    flags |= UserInfo.FLAG_PRIMARY;
                    synchronized (mUsersLock) {
                        if (!mIsDeviceManaged) {
                            flags |= UserInfo.FLAG_ADMIN;
                        }
                    }
                }
                //得到新使用者的userId
                userId = getNextAvailableId();
                //建立data/system/users/{usdId}
                Environment.getUserSystemDirectory(userId).mkdirs();
                boolean ephemeralGuests = Resources.getSystem()
                        .getBoolean(com.android.internal.R.bool.config_guestUserEphemeral);

                synchronized (mUsersLock) {
                    // Add ephemeral flag to guests/users if required. Also inherit it from parent.
                    if ((isGuest && ephemeralGuests) || mForceEphemeralUsers
                            || (parent != null && parent.info.isEphemeral())) {
                        flags |= UserInfo.FLAG_EPHEMERAL;
                    }
                    //為該新使用者建立UserInfo
                    userInfo = new UserInfo(userId, name, null, flags);
                    //設定序列號
                    userInfo.serialNumber = mNextSerialNumber++;
                    //設定建立時間
                    long now = System.currentTimeMillis();
                    userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
                    //設定partial,表示正在建立
                    userInfo.partial = true;
                    userInfo.lastLoggedInFingerprint = Build.FINGERPRINT;
                    userData = new UserData();
                    userData.info = userInfo;
                    mUsers.put(userId, userData);
                }
                //將新建的使用者資訊寫入到/data/system/users/{userId}/{userId}.xml
                writeUserLP(userData);
                //將使用者資訊寫入到userlist.xml
                writeUserListLP();
                if (parent != null) {
                    if (isManagedProfile) {
                        if (parent.info.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
                            parent.info.profileGroupId = parent.info.id;
                            writeUserLP(parent);
                        }
                        userInfo.profileGroupId = parent.info.profileGroupId;
                    } else if (isRestricted) {
                        if (parent.info.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
                            parent.info.restrictedProfileParentId = parent.info.id;
                            writeUserLP(parent);
                        }
                        userInfo.restrictedProfileParentId = parent.info.restrictedProfileParentId;
                    }
                }
            }
            final StorageManager storage = mContext.getSystemService(StorageManager.class);
            storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
            //為新建的user準備儲存區域
            mPm.prepareUserData(userId, userInfo.serialNumber,
                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
            //給上步為新建user準備的儲存區域寫入資料
            mPm.createNewUser(userId);
            //設定partial,表示建立結束
            userInfo.partial = false;
            synchronized (mPackagesLock) {
                //更新/data/system/users/{userId}/{userId}.xml
                writeUserLP(userData);
            }
            //更新mUserIds資料組
            updateUserIds();
            Bundle restrictions = new Bundle();
            if (isGuest) {
                synchronized (mGuestRestrictions) {
                    restrictions.putAll(mGuestRestrictions);
                }
            }
            synchronized (mRestrictionsLock) {
                mBaseUserRestrictions.append(userId, restrictions);
            }
            //給新建立的使用者賦予預設許可權
            mPm.onNewUserCreated(userId);
            //傳送使用者建立完成的廣播
            Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
            addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
            mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
                    android.Manifest.permission.MANAGE_USERS);
            MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        return userInfo;
    }複製程式碼

五.切換使用者

使用者切換使用者通過呼叫AMS中switchUser方法實現

    public boolean switchUser(final int targetUserId) {
            enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId);
            UserInfo currentUserInfo;
            UserInfo targetUserInfo;
            synchronized (this) {
                //獲得當前使用者的UserInfo
                int currentUserId = mUserController.getCurrentUserIdLocked();
                currentUserInfo = mUserController.getUserInfo(currentUserId);
                //獲得目標使用者的UserInfo
                targetUserInfo = mUserController.getUserInfo(targetUserId);
                if (targetUserInfo == null) {
                    Slog.w(TAG, "No user info for user #" + targetUserId);
                    return false;
                }
                if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mContext)) {
                    Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId
                            + " when device is in demo mode");
                    return false;
                }
                if (!targetUserInfo.supportsSwitchTo()) {
                    Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
                    return false;
                }
                //如果使用者是Profile則不允許使用switchUser方法切換使用者
                if (targetUserInfo.isManagedProfile()) {
                    Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not a full user");
                    return false;
                }
                mUserController.setTargetUserIdLocked(targetUserId);
            }
            //傳送切換使用者的訊息
            Pair<UserInfo, UserInfo> userNames = new Pair<>(currentUserInfo, targetUserInfo);
            mUiHandler.removeMessages(START_USER_SWITCH_UI_MSG);
            mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_UI_MSG, userNames));
            return true;
        }複製程式碼

mUiHandler收到START_USER_SWITCH_UI_MSG訊息後的處理,顯示一個Dialog

     case START_USER_SWITCH_UI_MSG: {
                    mUserController.showUserSwitchDialog((Pair<UserInfo, UserInfo>) msg.obj);
                    break;
                }複製程式碼

這個Dialog顯示之後會呼叫startUser這個方法

     void startUser() {
            synchronized (this) {
                if (!mStartedUser) {
                    mService.mUserController.startUserInForeground(mUserId, this);
                    mStartedUser = true;
                    final View decorView = getWindow().getDecorView();
                    if (decorView != null) {
                        decorView.getViewTreeObserver().removeOnWindowShownListener(this);
                    }
                    mHandler.removeMessages(MSG_START_USER);
                }
            }
        }複製程式碼

上述方法本質上呼叫的是UserController中的startUser方法,而這個方法本質上是啟動多使用者的最關鍵的方法

    boolean startUser(final int userId, final boolean foreground) {
        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: switchUser() from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid()
                    + " requires " + INTERACT_ACROSS_USERS_FULL;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }

        Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);

        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mService) {
                //如果當前使用者已經是需要切換的使用者,退出當前流程
                final int oldUserId = mCurrentUserId;
                if (oldUserId == userId) {
                    return true;
                }

                mService.mStackSupervisor.setLockTaskModeLocked(null,
                        ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false);
                final UserInfo userInfo = getUserInfo(userId);
                //如果沒有需要啟動的使用者的資訊,則直接退出
                if (userInfo == null) {
                    Slog.w(TAG, "No user info for user #" + userId);
                    return false;
                }
                //如果是前臺啟動且是profile使用者,則直接退出
                if (foreground && userInfo.isManagedProfile()) {
                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
                    return false;
                }
                //如果是前臺啟動,則需要將螢幕凍結
                if (foreground) {
                    mService.mWindowManager.startFreezingScreen(
                            R.anim.screen_user_exit, R.anim.screen_user_enter);
                }

                boolean needStart = false;

                // If the user we are switching to is not currently started, then
                // we need to start it now.
                if (mStartedUsers.get(userId) == null) {
                    UserState userState = new UserState(UserHandle.of(userId));
                    mStartedUsers.put(userId, userState);
                    getUserManagerInternal().setUserState(userId, userState.state);
                    updateStartedUserArrayLocked();
                    needStart = true;
                }
                //調整使用者在mUserLru列表中的位置,當前使用者放在最後位置
                final UserState uss = mStartedUsers.get(userId);
                final Integer userIdInt = userId;
                mUserLru.remove(userIdInt);
                mUserLru.add(userIdInt);

                if (foreground) {
                    //如果是前臺切換,直接切換到需要啟動的使用者
                    mCurrentUserId = userId;
                    mService.updateUserConfigurationLocked();
                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                   //更新與該使用者相關的profile列表
                    updateCurrentProfileIdsLocked();
                    //在WMS中設定需要啟動的使用者為當前使用者
                    mService.mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
                    // Once the internal notion of the active user has switched, we lock the device
                    // with the option to show the user switcher on the keyguard.
                    mService.mWindowManager.lockNow(null);
                } else {
                    final Integer currentUserIdInt = mCurrentUserId;
                    //更新與該使用者相關的profile列表
                    updateCurrentProfileIdsLocked();
                    mService.mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
                    mUserLru.remove(currentUserIdInt);
                    mUserLru.add(currentUserIdInt);
                }

                // Make sure user is in the started state.  If it is currently
                // stopping, we need to knock that off.
                if (uss.state == UserState.STATE_STOPPING) {
                    // If we are stopping, we haven't sent ACTION_SHUTDOWN,
                    // so we can just fairly silently bring the user back from
                    // the almost-dead.
                    uss.setState(uss.lastState);
                    getUserManagerInternal().setUserState(userId, uss.state);
                    updateStartedUserArrayLocked();
                    needStart = true;
                } else if (uss.state == UserState.STATE_SHUTDOWN) {
                    // This means ACTION_SHUTDOWN has been sent, so we will
                    // need to treat this as a new boot of the user.
                    uss.setState(UserState.STATE_BOOTING);
                    getUserManagerInternal().setUserState(userId, uss.state);
                    updateStartedUserArrayLocked();
                    needStart = true;
                }

                if (uss.state == UserState.STATE_BOOTING) {
                    //如果使用者的狀態是正在啟動,則傳送一個SYSTEM_USER_START_MSG訊息
                    // Give user manager a chance to propagate user restrictions
                    // to other services and prepare app storage
                    getUserManager().onBeforeStartUser(userId);

                    // Booting up a new user, need to tell system services about it.
                    // Note that this is on the same handler as scheduling of broadcasts,
                    // which is important because it needs to go first.
                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
                }

                if (foreground) {
                    //傳送SYSTEM_USER_CURRENT_MSG的訊息
                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
                            oldUserId));
                    mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
                    mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
                    //傳送REPORT_USER_SWITCH_MSG和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) {
                    // Send USER_STARTED broadcast
                    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);
                    mService.broadcastIntentLocked(null, null, intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, SYSTEM_UID, userId);
                }

                if (foreground) {
                    //將user設定到前臺
                    moveUserToForegroundLocked(uss, oldUserId, userId);
                } else {
                    mService.mUserController.finishUserBoot(uss);
                }

                if (needStart) {
                    Intent intent = new Intent(Intent.ACTION_USER_STARTING);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                    mService.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,
                            new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                            null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        return true;
    }複製程式碼

分析如下幾個關鍵方法
moveUserToForegroundLocked:獲取newUserId使用者在切換之前的stack狀態,以便將原來在前臺的應用推到前臺

     void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
            boolean homeInFront = mService.mStackSupervisor.switchUserLocked(newUserId, uss);
            if (homeInFront) {
                //如果原來的stack是桌面,則啟動桌面
                mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
            } else {
                //如果是其他應用,則將該應用推到前臺
                mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
            }
            EventLogTags.writeAmSwitchUser(newUserId);
            sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
        }複製程式碼

訊息佇列處理:在上述方法中我們看到傳送很多handler訊息,如下簡單介紹一下這些訊息的作用

SYSTEM_USER_START_MSG:通知BatteryStatsService使用者切換的訊息以及讓SystemServiceManager通知各個SystemService呼叫startUser

        case SYSTEM_USER_START_MSG: {
                mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
                        Integer.toString(msg.arg1), msg.arg1);
                mSystemServiceManager.startUser(msg.arg1);
                break;
            }複製程式碼

SYSTEM_USER_CURRENT_MSG:通知BatteryStatsService使用者切換資訊以及讓SystemServiceManager通知各個SeysteService呼叫switchUser

    case SYSTEM_USER_CURRENT_MSG: {
                    mBatteryStatsService.noteEvent(
                            BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH,
                            Integer.toString(msg.arg2), msg.arg2);
                    mBatteryStatsService.noteEvent(
                            BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
                            Integer.toString(msg.arg1), msg.arg1);
                    mSystemServiceManager.switchUser(msg.arg1);
                    break;
                }複製程式碼

REPORT_USER_SWITCH_MSG:如果系統中有對切換使用者感興趣的模組,可以呼叫AMS的registerUserSwitchObserver方法來註冊觀察物件。當有使用者切換時AMS會通過呼叫
來通知這些模組,模組處理完成後呼叫引數中傳遞的callback來通知AMS。最後都調勇完成後會呼叫sendContinueUserSwitchLocked來繼續進行切換的工作。

     case REPORT_USER_SWITCH_MSG: {
         mUserController.dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
         break;
     }

         void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
             Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId);
             final int observerCount = mUserSwitchObservers.beginBroadcast();
             if (observerCount > 0) {
                 final ArraySet<String> curWaitingUserSwitchCallbacks = new ArraySet<>();
                 synchronized (mService) {
                     uss.switching = true;
                     mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks;
                 }
                 final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount);
                 for (int i = 0; i < observerCount; i++) {
                     try {
                         // Prepend with unique prefix to guarantee that keys are unique
                         final String name = "#" + i + " " + mUserSwitchObservers.getBroadcastCookie(i);
                         synchronized (mService) {
                             curWaitingUserSwitchCallbacks.add(name);
                         }
                         final IRemoteCallback callback = new IRemoteCallback.Stub() {
                             @Override
                             public void sendResult(Bundle data) throws RemoteException {
                                 synchronized (mService) {
                                     // Early return if this session is no longer valid
                                     if (curWaitingUserSwitchCallbacks
                                             != mCurWaitingUserSwitchCallbacks) {
                                         return;
                                     }
                                     curWaitingUserSwitchCallbacks.remove(name);
                                     // Continue switching if all callbacks have been notified
                                     if (waitingCallbacksCount.decrementAndGet() == 0) {
                                         sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
                                     }
                                 }
                             }
                         };
                         mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(newUserId, callback);
                     } catch (RemoteException e) {
                     }
                 }
             } else {
                 synchronized (mService) {
                     sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
                 }
             }
             mUserSwitchObservers.finishBroadcast();
         }複製程式碼

sendContinueUserSwitchLocked會發出CONTINUE_USER_SWITCH_MSG訊息

        void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
            mCurWaitingUserSwitchCallbacks = null;
            mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
            mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG,
                    oldUserId, newUserId, uss));
        }複製程式碼

CONTINUE_USER_SWITCH_MSG事實上是呼叫continueUserSwitch方法

        case CONTINUE_USER_SWITCH_MSG: {
            mUserController.continueUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
            break;
        }複製程式碼

continueUserSwitch將傳送REPORT_USER_SWITCH_COMPLETE_MSG資訊

    void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
            Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
            synchronized (mService) {
                mService.mWindowManager.stopFreezingScreen();
            }
            uss.switching = false;
            mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
                    newUserId, 0));
            stopGuestOrEphemeralUserIfBackground();
            stopBackgroundUsersIfEnforced(oldUserId);
        }複製程式碼

接收到該訊息後呼叫dispatchUserSwitchComplete方法

    case REPORT_USER_SWITCH_COMPLETE_MSG: {
                mUserController.dispatchUserSwitchComplete(msg.arg1);
            } break;複製程式碼

該方法將給註冊觀察onUserSwitchComplete方法回撥

     void dispatchUserSwitchComplete(int userId) {
            final int observerCount = mUserSwitchObservers.beginBroadcast();
            for (int i = 0; i < observerCount; i++) {
                try {
                    mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId);
                } catch (RemoteException e) {
                }
            }
            mUserSwitchObservers.finishBroadcast();
        }複製程式碼

USER_SWITCH_TIMEOUT_MSG:該訊息的目的是為了防止使用者切換時間太長,畢竟只有所有的觀察者都處理完了才能繼續進行切換使用者的操作。該訊息被handler處理後將呼叫timeoutUserSwitch。

    case USER_SWITCH_TIMEOUT_MSG: {
                mUserController.timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
                break;
            }複製程式碼

timeoutUserSwitch方法的本質是呼叫sendContinueUserSwitchLocked方法。該方法已描述。

void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
        synchronized (mService) {
            Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
                    + ". Observers that didn't send results: " + mCurWaitingUserSwitchCallbacks);
            sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
        }
    }複製程式碼

上述操作我們發現新建的User正處於Booting的階段,那麼如何將User進入下個階段呢?上述的方法有個finishUserBoot和moveUserToForegroundLocked方法。我們先看finishUserBoot

finishUserBoot將呼叫maybeUnlockUser。finishUserBoot將新建立的User從狀態STATE_BOOTING設定為STATE_RUNNING_LOCKED

    private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
        final int userId = uss.mHandle.getIdentifier();

        Slog.d(TAG, "Finishing user boot " + userId);
        synchronized (mService) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(userId) != uss) return;

            // We always walk through all the user lifecycle states to send
            // consistent developer events. We step into RUNNING_LOCKED here,
            // but we might immediately step into RUNNING below if the user
            // storage is already unlocked.
            if (uss.setState(STATE_BOOTING, STATE_RUNNING_LOCKED)) {
                getUserManagerInternal().setUserState(userId, uss.state);

                int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
                MetricsLogger.histogram(mService.mContext, "framework_locked_boot_completed",
                    uptimeSeconds);

                Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                        | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null,
                        new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                        AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
            }

            // We need to delay unlocking managed profiles until the parent user
            // is also unlocked.
            if (getUserManager().isManagedProfile(userId)) {
                final UserInfo parent = getUserManager().getProfileParent(userId);
                if (parent != null
                        && isUserRunningLocked(parent.id, ActivityManager.FLAG_AND_UNLOCKED)) {
                    Slog.d(TAG, "User " + userId + " (parent " + parent.id
                            + "): attempting unlock because parent is unlocked");
                    maybeUnlockUser(userId);
                } else {
                    String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
                    Slog.d(TAG, "User " + userId + " (parent " + parentId
                            + "): delaying unlock because parent is locked");
                }
            } else {
                maybeUnlockUser(userId);
            }
        }
    }複製程式碼

maybeUnlockUser呼叫unlockUserCleared方法

 boolean maybeUnlockUser(final int userId) {
        // Try unlocking storage using empty token
        return unlockUserCleared(userId, null, null, null);
    }複製程式碼

unlockUserCleared方法呼叫finishUserUnlocking方法

boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
            IProgressListener listener) {
        UserState uss;
        synchronized (mService) {
            // TODO Move this block outside of synchronized if it causes lock contention
            if (!StorageManager.isUserKeyUnlocked(userId)) {
                final UserInfo userInfo = getUserInfo(userId);
                final IMountService mountService = getMountService();
                try {
                    // We always want to unlock user storage, even user is not started yet
                    mountService.unlockUserKey(userId, userInfo.serialNumber, token, secret);
                } catch (RemoteException | RuntimeException e) {
                    Slog.w(TAG, "Failed to unlock: " + e.getMessage());
                }
            }
            // Bail if user isn't actually running, otherwise register the given
            // listener to watch for unlock progress
            uss = mStartedUsers.get(userId);
            if (uss == null) {
                notifyFinished(userId, listener);
                return false;
            } else {
                uss.mUnlockProgress.addListener(listener);
                uss.tokenProvided = (token != null);
            }
        }

        finishUserUnlocking(uss);

        final ArraySet<Integer> childProfilesToUnlock = new ArraySet<>();
        synchronized (mService) {

            // We just unlocked a user, so let's now attempt to unlock any
            // managed profiles under that user.
            for (int i = 0; i < mStartedUsers.size(); i++) {
                final int testUserId = mStartedUsers.keyAt(i);
                final UserInfo parent = getUserManager().getProfileParent(testUserId);
                if (parent != null && parent.id == userId && testUserId != userId) {
                    Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
                            + "): attempting unlock because parent was just unlocked");
                    childProfilesToUnlock.add(testUserId);
                }
            }
        }

        final int size = childProfilesToUnlock.size();
        for (int i = 0; i < size; i++) {
            maybeUnlockUser(childProfilesToUnlock.valueAt(i));
        }

        return true;
    }複製程式碼

finishUserUnlocking方法將新建立的User由STATE_RUNNING_LOCKED轉為STATE_RUNNING_UNLOCKING。同時傳送SYSTEM_USER_UNLOCK_MSG的訊息

private void finishUserUnlocking(final UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        boolean proceedWithUnlock = false;
        synchronized (mService) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;

            // Only keep marching forward if user is actually unlocked
            if (!StorageManager.isUserKeyUnlocked(userId)) return;

            if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
                getUserManagerInternal().setUserState(userId, uss.state);
                proceedWithUnlock = true;
            }
        }

        if (proceedWithUnlock) {
            uss.mUnlockProgress.start();

            // Prepare app storage before we go any further
            uss.mUnlockProgress.setProgress(5,
                    mService.mContext.getString(R.string.android_start_title));
            mUserManager.onBeforeUnlockUser(userId);
            uss.mUnlockProgress.setProgress(20);

            // Dispatch unlocked to system services; when fully dispatched,
            // that calls through to the next "unlocked" phase
            mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
                    .sendToTarget();
        }
    }複製程式碼

SYSTEM_USER_UNLOCK_MSG訊息實質上呼叫的是finishUserUnlocked方法

     case SYSTEM_USER_UNLOCK_MSG: {
         final int userId = msg.arg1;
         mSystemServiceManager.unlockUser(userId);
         synchronized (ActivityManagerService.this) {
             mRecentTasks.loadUserRecentsLocked(userId);
         }
         if (userId == UserHandle.USER_SYSTEM) {
             startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
         }
         installEncryptionUnawareProviders(userId);
         mUserController.finishUserUnlocked((UserState) msg.obj);
         break;
     }複製程式碼

finishUserUnlocked將新建立的User由狀態STATE_RUNNING_UNLOCKING設定為STATE_RUNNING_UNLOCKED。最後將呼叫finishUserUnlockedCompleted方法。

void finishUserUnlocked(final UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;

            // Only keep marching forward if user is actually unlocked
            if (!StorageManager.isUserKeyUnlocked(userId)) return;

            if (uss.setState(STATE_RUNNING_UNLOCKING, STATE_RUNNING_UNLOCKED)) {
                getUserManagerInternal().setUserState(userId, uss.state);
                uss.mUnlockProgress.finish();

                // Dispatch unlocked to external apps
                final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
                unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                unlockedIntent.addFlags(
                        Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
                mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null,
                        null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                        userId);
                ......
                // Send PRE_BOOT broadcasts if user fingerprint changed; we
                // purposefully block sending BOOT_COMPLETED until after all
                // PRE_BOOT receivers are finished to avoid ANR'ing apps
                final UserInfo info = getUserInfo(userId);
                if (!Objects.equals(info.lastLoggedInFingerprint, Build.FINGERPRINT)) {
                    // Suppress double notifications for managed profiles that
                    // were unlocked automatically as part of their parent user
                    // being unlocked.
                    final boolean quiet;
                    if (info.isManagedProfile()) {
                        quiet = !uss.tokenProvided
                                || !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
                    } else {
                        quiet = false;
                    }
                    new PreBootBroadcaster(mService, userId, null, quiet) {
                        @Override
                        public void onFinished() {
                            finishUserUnlockedCompleted(uss);
                        }
                    }.sendNext();
                } else {
                    finishUserUnlockedCompleted(uss);
                }
            }
        }
    }複製程式碼

在finishUserUnlockedCompleted中如果新建的User沒有被initialized。會呼叫getUserManager().makeInitialized方法完成新建User的initialized。同時發出ACTION_BOOT_COMPLETED。這樣就完成了新建User的啟動。

    private void finishUserUnlockedCompleted(UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) {
            // Bail if we ended up with a stale user
            if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
            final UserInfo userInfo = getUserInfo(userId);
            if (userInfo == null) {
                return;
            }

            // Only keep marching forward if user is actually unlocked
            if (!StorageManager.isUserKeyUnlocked(userId)) return;

            // Remember that we logged in
            mUserManager.onUserLoggedIn(userId);

            if (!userInfo.isInitialized()) {
                if (userId != UserHandle.USER_SYSTEM) {
                    Slog.d(TAG, "Initializing user #" + userId);
                    Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                    mService.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) {
                                    // Note: performReceive is called with mService lock held
                                    getUserManager().makeInitialized(userInfo.id);
                                }
                            }, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, true, false, MY_PID, SYSTEM_UID, userId);
                }
            }

            Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
            int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
            MetricsLogger.histogram(mService.mContext, "framework_boot_completed", uptimeSeconds);
            final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
            bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
            bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null,
                    new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
        }
    }複製程式碼

同時我們可以看到moveUserToForegroundLocked方法本質上啟動Activity,我們知道Activity的啟動流程一定會呼叫AMS中activityIdle方法,而activityIdle方法將呼叫mStackSupervisor.activityIdleInternalLocked方法。
而該方法中呼叫finishUserSwitch方法。

    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
            Configuration config) {
       ......
        if (!booting) {
            // Complete user switch
            if (startingUsers != null) {
                for (int i = 0; i < startingUsers.size(); i++) {
                    mService.mUserController.finishUserSwitch(startingUsers.get(i));
                }
            }
        }

        mService.trimApplications();
        //dump();
        //mWindowManager.dump();

        if (activityRemoved) {
            resumeFocusedStackTopActivityLocked();
        }

        return r;
    }複製程式碼

finishUserSwitch方法將呼叫finishUserBoot方法。流程如上文所述。

    void finishUserSwitch(UserState uss) {
        synchronized (mService) {
            finishUserBoot(uss);

            startProfilesLocked();
            stopRunningUsersLocked(MAX_RUNNING_USERS);
        }
    }複製程式碼

六.刪除使用者

刪除使用者的入口是UMS中的removeUser方法,該方法的實現如下:

public boolean removeUser(int userHandle) {
        //許可權檢測
        checkManageOrCreateUsersPermission("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 UserData userData;
            int currentUser = ActivityManager.getCurrentUser();
            if (currentUser == userHandle) {
                Log.w(LOG_TAG, "Current user cannot be removed");
                return false;
            }
            synchronized (mPackagesLock) {
                synchronized (mUsersLock) {
                    userData = mUsers.get(userHandle);
                     // 檢查被刪除的使用者是不是管理員使用者userHandle=0,檢查使用者列表中是否有該使用者,以及該使用者是否是正在被刪除的使用者
                    if (userHandle == 0 || userData == null || mRemovingUserIds.get(userHandle)) {
                        return false;
                    }

                    // We remember deleted user IDs to prevent them from being
                    // reused during the current boot; they can still be reused
                    // after a reboot.
                    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.
                userData.info.partial = true;
                // Mark it as disabled, so that it isn't returned any more when
                // profiles are queried.
                userData.info.flags |= UserInfo.FLAG_DISABLED;
                //更新使用者資訊並寫入到xml中
                writeUserLP(userData);
            }
            // 如果該user是一個user的一份profile,則發出一個ACTION_MANAGED_PROFILE_REMOVED廣播
            if (userData.info.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
                    && userData.info.isManagedProfile()) {
                // Send broadcast to notify system that the user removed was a
                // managed user.
                sendProfileRemovedBroadcast(userData.info.profileGroupId, userData.info.id);
            }

            if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
            int res;
            try {
                //呼叫AMS停止當前的使用者
                res = ActivityManagerNative.getDefault().stopUser(userHandle, /* force= */ true,
                //設定回撥函式,當stopUser執行完成之後呼叫finishRemoveUser方法
                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);
        }
    }複製程式碼

AMS中的stopUser方法,該方法將呼叫UserController中的stopUser方法

@Override
    public int stopUser(final int userId, boolean force, final IStopUserCallback callback) {
        return mUserController.stopUser(userId, force, callback);
    }複製程式碼

UserController中的stopUser方法將呼叫stopUsersLocked方法

    int stopUser(final int userId, final boolean force, final IStopUserCallback callback) {
        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: switchUser() from pid="
                    + Binder.getCallingPid()
                    + ", uid=" + Binder.getCallingUid()
                    + " requires " + INTERACT_ACROSS_USERS_FULL;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        if (userId < 0 || userId == UserHandle.USER_SYSTEM) {
            throw new IllegalArgumentException("Can't stop system user " + userId);
        }
        mService.enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
                userId);
        synchronized (mService) {
            return stopUsersLocked(userId, force, callback);
        }
    }複製程式碼

stopUsersLocked方法將呼叫stopUsersLocked

    private int stopUsersLocked(final int userId, boolean force, final IStopUserCallback callback) {
        if (userId == UserHandle.USER_SYSTEM) {
            return USER_OP_ERROR_IS_SYSTEM;
        }
        if (isCurrentUserLocked(userId)) {
            return USER_OP_IS_CURRENT;
        }
        int[] usersToStop = getUsersToStopLocked(userId);
        // If one of related users is system or current, no related users should be stopped
        for (int i = 0; i < usersToStop.length; i++) {
            int relatedUserId = usersToStop[i];
            if ((UserHandle.USER_SYSTEM == relatedUserId) || isCurrentUserLocked(relatedUserId)) {
                if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked cannot stop related user "
                        + relatedUserId);
                // We still need to stop the requested user if it's a force stop.
                if (force) {
                    Slog.i(TAG,
                            "Force stop user " + userId + ". Related users will not be stopped");
                    stopSingleUserLocked(userId, callback);
                    return USER_OP_SUCCESS;
                }
                return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
            }
        }
        if (DEBUG_MU) Slog.i(TAG, "stopUsersLocked usersToStop=" + Arrays.toString(usersToStop));
        for (int userIdToStop : usersToStop) {
            stopSingleUserLocked(userIdToStop, userIdToStop == userId ? callback : null);
        }
        return USER_OP_SUCCESS;
    }複製程式碼

stopUsersLocked將呼叫stopSingleUserLocked。該方法會將User的狀態設定為STATE_STOPPING。同時會呼叫了finishUserStopping

    private void stopSingleUserLocked(final int userId, final IStopUserCallback callback) {
        if (DEBUG_MU) Slog.i(TAG, "stopSingleUserLocked userId=" + userId);
        final UserState 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);
                        } catch (RemoteException e) {
                        }
                    }
                });
            }
            return;
        }

        if (callback != null) {
            uss.mStopCallbacks.add(callback);
        }

        if (uss.state != UserState.STATE_STOPPING
                && uss.state != UserState.STATE_SHUTDOWN) {
            //將狀態設定為正在停止
            uss.setState(UserState.STATE_STOPPING);
            getUserManagerInternal().setUserState(userId, uss.state);
            updateStartedUserArrayLocked();

            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);
                // 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) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                finishUserStopping(userId, uss);
                            }
                        });
                    }
                };
                // Clear broadcast queue for the user to avoid delivering stale broadcasts
                mService.clearBroadcastQueueForUserLocked(userId);
                // Kick things off.
                mService.broadcastIntentLocked(null, null, stoppingIntent,
                        null, stoppingReceiver, 0, null, null,
                        new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                        null, true, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }複製程式碼

finishUserStopping方法將呼叫finishUserStopped方法並呼叫 mService.mSystemServiceManager.stopUser(userId)方法通知SystemService呼叫stopUser。

    void finishUserStopping(final int userId, final UserState uss) {
        // On to the next.
        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) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        finishUserStopped(uss);
                    }
                });
            }
        };

        synchronized (mService) {
            if (uss.state != UserState.STATE_STOPPING) {
                // Whoops, we are being started back up.  Abort, abort!
                return;
            }
            uss.setState(UserState.STATE_SHUTDOWN);
        }
        getUserManagerInternal().setUserState(userId, uss.state);

        mService.mBatteryStatsService.noteEvent(
                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
                Integer.toString(userId), userId);
        mService.mSystemServiceManager.stopUser(userId);

        synchronized (mService) {
            mService.broadcastIntentLocked(null, null, shutdownIntent,
                    null, shutdownReceiver, 0, null, null, null,
                    AppOpsManager.OP_NONE,
                    null, true, false, MY_PID, SYSTEM_UID, userId);
        }
    }複製程式碼

finishUserStopped方法主要作用是將多使用者中的app停止。

void finishUserStopped(UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        boolean stopped;
        ArrayList<IStopUserCallback> callbacks;
        synchronized (mService) {
            callbacks = new ArrayList<>(uss.mStopCallbacks);
            if (mStartedUsers.get(userId) != uss) {
                stopped = false;
            } else if (uss.state != UserState.STATE_SHUTDOWN) {
                stopped = false;
            } else {
                stopped = true;
                // User can no longer run.
                mStartedUsers.remove(userId);
                getUserManagerInternal().removeUserState(userId);
                mUserLru.remove(Integer.valueOf(userId));
                updateStartedUserArrayLocked();

                mService.onUserStoppedLocked(userId);
                // Clean up all state and processes associated with the user.
                // Kill all the processes for the user.
                forceStopUserLocked(userId, "finish user");
            }
        }

        for (int i = 0; i < callbacks.size(); i++) {
            try {
                if (stopped) callbacks.get(i).userStopped(userId);
                else callbacks.get(i).userStopAborted(userId);
            } catch (RemoteException e) {
            }
        }

        if (stopped) {
            mService.mSystemServiceManager.cleanupUser(userId);
            synchronized (mService) {
                mService.mStackSupervisor.removeUserLocked(userId);
            }
            // Remove the user if it is ephemeral.
            if (getUserInfo(userId).isEphemeral()) {
                mUserManager.removeUser(userId);
            }
        }複製程式碼

如何AMS中StopUser完成了任務。該方法完成之後將執行finishRemoveUser方法.在該方法中執行removeUserState

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() {
                                @Override
                                public void run() {
                                    // Clean up any ActivityManager state
                                    LocalServices.getService(ActivityManagerInternal.class)
                                            .onUserRemoved(userHandle);
                                    removeUserState(userHandle);
                                }
                            }.start();
                        }
                    },

                    null, Activity.RESULT_OK, null, null);
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }複製程式碼

該方法的主要作用是刪除之前建立在/data/system/users/{userId}中配置的相關xml檔案同時呼叫PMS中的方法刪除相關app資料。

    private void removeUserState(final int userHandle) {
        try {
            mContext.getSystemService(StorageManager.class).destroyUserKey(userHandle);
        } catch (IllegalStateException e) {
            // This may be simply because the user was partially created.
            Slog.i(LOG_TAG,
                "Destroying key for user " + userHandle + " failed, continuing anyway", e);
        }

        // Cleanup gatekeeper secure user id
        try {
            final IGateKeeperService gk = GateKeeper.getService();
            if (gk != null) {
                gk.clearSecureUserId(userHandle);
            }
        } catch (Exception ex) {
            Slog.w(LOG_TAG, "unable to clear GK secure user id");
        }

        // Cleanup package manager settings
        mPm.cleanUpUser(this, userHandle);

        // Clean up all data before removing metadata
        mPm.destroyUserData(userHandle,
                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);

        // Remove this user from the list
        synchronized (mUsersLock) {
            mUsers.remove(userHandle);
            mIsUserManaged.delete(userHandle);
        }
        synchronized (mUserStates) {
            mUserStates.delete(userHandle);
        }
        synchronized (mRestrictionsLock) {
            mBaseUserRestrictions.remove(userHandle);
            mAppliedUserRestrictions.remove(userHandle);
            mCachedEffectiveUserRestrictions.remove(userHandle);
            mDevicePolicyLocalUserRestrictions.remove(userHandle);
        }
        // Update the user list
        synchronized (mPackagesLock) {
            writeUserListLP();
        }
        // Remove user file
        AtomicFile userFile = new AtomicFile(new File(mUsersDir, userHandle + XML_SUFFIX));
        userFile.delete();
        updateUserIds();
    }複製程式碼

參考資料:

1.www.heqiangfly.com/2017/03/06/…

2.gityuan.com/2016/11/20/…

相關文章