Android 9.x多用户机制 2 #Profile User启动过程

Profile User启动的主要逻辑在UserController#startUser
客户端启动的逻辑为:

iActivityManager.startUserInBackground(userId);

主要调用逻辑代码如下:

UserController#startUser

    boolean startUser(
            final int userId,
            final boolean foreground,
            @Nullable IProgressListener unlockListener) {
        //1.检查权限
        if (mInjector.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 {
            final int oldUserId = getCurrentUserId();
            if (oldUserId == userId) {
                return true;
            }

            if (foreground) {
                mInjector.clearAllLockedTasks("startUser");
            }

            final UserInfo userInfo = getUserInfo(userId);
            if (userInfo == null) {
                Slog.w(TAG, "No user info for user #" + userId);
                return false;
            }
            //2.manage profile不允许前台启动
            if (foreground && userInfo.isManagedProfile()) {
                Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
                return false;
            }

            if (foreground && mUserSwitchUiEnabled) {
                mInjector.getWindowManager().startFreezingScreen(
                        R.anim.screen_user_exit, R.anim.screen_user_enter);
            }

            boolean needStart = false;
            boolean updateUmState = false;
            UserState uss;

            // If the user we are switching to is not currently started, then
            // we need to start it now.
            synchronized (mLock) {
                //3.创建该用户的UserState对象,用于后续启动期间,各个状态的保存和切换 
                //第一次执行的话,该对象为null,新创建的对象的状态处于初始状态0(BOOTING)
                uss = mStartedUsers.get(userId);
                if (uss == null) {
                    uss = new UserState(UserHandle.of(userId));
                    uss.mUnlockProgress.addListener(new UserProgressListener());
                    mStartedUsers.put(userId, uss);
                    updateStartedUserArrayLU();
                    needStart = true;
                    updateUmState = true;
                } else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) {
                    Slog.i(TAG, "User #" + userId
                            + " is shutting down - will start after full stop");
                    mHandler.post(() -> startUser(userId, foreground, unlockListener));
                    return true;
                }
                final Integer userIdInt = userId;
                mUserLru.remove(userIdInt);
                mUserLru.add(userIdInt);
            }
            if (unlockListener != null) {
                uss.mUnlockProgress.addListener(unlockListener);
            }
            if (updateUmState) {
                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
            }
            if (foreground) {
                // Make sure the old user is no longer considering the display to be on.
                mInjector.reportGlobalUsageEventLocked(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
                synchronized (mLock) {
                    mCurrentUserId = userId;
                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                }
                mInjector.updateUserConfiguration();
                updateCurrentProfileIds();
                mInjector.getWindowManager().setCurrentUser(userId, getCurrentProfileIds());
                mInjector.reportCurWakefulnessUsageEvent();
                // 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.
                if (mUserSwitchUiEnabled) {
                    mInjector.getWindowManager().setSwitchingUser(true);
                    mInjector.getWindowManager().lockNow(null);
                }
            } else {
                final Integer currentUserIdInt = mCurrentUserId;
                updateCurrentProfileIds();
                //4. 保存一个[userid,profileGroupId]数组,profileGroupId是用户创建阶段完成初始化赋值的
                mInjector.getWindowManager().setCurrentProfileIds(getCurrentProfileIds());
                synchronized (mLock) {
                    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);
                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
                synchronized (mLock) {
                    updateStartedUserArrayLU();
                }
                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);
                mInjector.getUserManagerInternal().setUserState(userId, uss.state);
                synchronized (mLock) {
                    updateStartedUserArrayLU();
                }
                needStart = true;
            }
           //5. 发送SYSTEM_USER_START_MSG消息,回调系统指所有systemServer的onStartUser方法,通知user启动
            if (uss.state == UserState.STATE_BOOTING) {
                // Give user manager a chance to propagate user restrictions
                // to other services and prepare app storage
                mInjector.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) {
                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_MS);
            }

            if (needStart) {
                //6. Send ACTION_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);
                mInjector.broadcastIntent(intent,
                        null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                        null, false, false, MY_PID, SYSTEM_UID, userId);
            }

            if (foreground) {
                moveUserToForeground(uss, oldUserId, userId);
            } else {
                //7. 执行Boot操作,会执行执行user启动的各个状态,并报个每个阶段的进度
                finishUserBoot(uss);
            }

            if (needStart) {
                //8.发送ACTION_USER_STARTING广播
                Intent intent = new Intent(Intent.ACTION_USER_STARTING);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);//静态注册的广播(AndroidMenifest.xml中注册的)不能接受该广播
                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                mInjector.broadcastIntent(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;
    }

启动的流程总结如下

startUser
  1. 检查启动该用户的是否具有INTERACT_ACROSS_USERS_FULL权限,如果没有,直接抛出异常,应用崩溃
  2. 检查改profile user是否是后台启动,如果是前台启动,则直接返回false;这也是profile user和普通user的区别,不同user可用通过
    switchUser方法,切换到前台用户
  3. 创建改用户对象的UserState,第一次启动时,该用户的状态为0(STATE_BOOTING)
  4. 保存主用户和该用户对应的profileGroupid的对应关系,维护一个{userid,profileGroupId}的数据结构
  5. 发送SYSTEM_USER_START_MSG消息,回调系统指所有systemServer的onStartUser方法,通知他们,该user启动了
  6. Send ACTION_USER_STARTED broadcast
    该广播特性:只允许动态广播监听;接受者具有FOREGROUND优先级
  7. 执行finishUserBoot操作,结束Boot状态,详细过程见下面的finishUserBoot章节
  8. 发送ACTION_USER_STARTING广播

下面看下,以上流程的中,比较重要的阶段的代码逻辑

finishUserBoot

后台用户才会执行该操作,我们创建的profile User是一个ManagedProfile,并且必须后台启动;
改方法的主要代理逻辑是执行user启动的各个状态,并报个每个阶段的进度


Profile User启动过程_finishUserBoot_
  1. 将该用户的状态从STATE_BOOTING--->STATE_RUNNING_LOCKED;状态设置成功的情况系,执行以下操作
    发送消息REPORT_LOCKED_BOOT_COMPLETE_MSG,告诉其他注册了IUserSwitchObserver的监听模块,该用户完成了BootComplete
    发送广播ACTION_LOCKED_BOOT_COMPLETED

  2. 执行maybeUnlockUser操作

    maybeUnlockUser

    首先,执行解锁用户存储操作
    主要代码逻辑是通过Ext4Crypt.cpp的e4crypt_unlock_user_key方法,设置profile user的存储为unlock状态

    TODO: rename to 'install' for consistency, and take flags to know which keys to install
    bool e4crypt_unlock_user_key(userid_t user_id, int serial, const std::string& token_hex,
                                 const std::string& secret_hex) {
        LOG(DEBUG) << "e4crypt_unlock_user_key " << user_id << " serial=" << serial
                   << " token_present=" << (token_hex != "!");
        if (e4crypt_is_native()) {
            if (s_ce_key_raw_refs.count(user_id) != 0) {
                LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id;
                return true;
            }
            std::string token, secret;
            if (!parse_hex(token_hex, &token)) return false;
            if (!parse_hex(secret_hex, &secret)) return false;
            android::vold::KeyAuthentication auth(token, secret);
            if (!read_and_install_user_ce_key(user_id, auth)) {
                LOG(ERROR) << "Couldn't read key for " << user_id;
                return false;
            }
        } else {
            // When in emulation mode, we just use chmod. However, we also
            // unlock directories when not in emulation mode, to bring devices
            // back into a known-good state.
            if (!emulated_unlock(android::vold::BuildDataSystemCePath(user_id), 0771) ||
                !emulated_unlock(android::vold::BuildDataMiscCePath(user_id), 01771) ||
                !emulated_unlock(android::vold::BuildDataMediaCePath("", user_id), 0770) ||
                !emulated_unlock(android::vold::BuildDataUserCePath("", user_id), 0771)) {
                LOG(ERROR) << "Failed to unlock user " << user_id;
                return false;
            }
        }
        return true;
    }
    

其次,执行finishUserUnlocking操作
改操作的主要路逻辑如下:
1. 开始进度report,报告unlock进度5%;
2. 回调UserManager的onBeforeUnlockUser方法,
3. 将profile user的状态为从STATE_RUNNING_LOCKED--->STATE_RUNNING_UNLOCKING
4. 将profile user的状态更显到UMS的mUserStates中去
5. report profile user unlock进度20%
6. 处理SYSTEM_USER_UNLOCK_MSG消息
调用系统中所有systemServer的unlockUser方法 更改profile user的状态STATE_RUNNING_UNLOCKING-->STATE_RUNNING_UNLOCKED 将profile user的状态更显到UMS的mUserStates中去 报告unlock进度100% 发送ACTION_USER_UNLOCKED广播 发送ACTION_MANAGED_PROFILE_UNLOCKED广播 发送ACTION_USER_INITIALIZE广播 发送ACTION_BOOT_COMPLETED广播

startUser阶段,各个系统广播发送顺序

  1. Intent#ACTION_USER_STARTED} sent to registered receivers of the new user
  2. Intent#ACTION_USER_BACKGROUND} sent to registered receivers of the outgoing user and all profiles of this user. Sent only if {@code foreground} parameter is true
  3. Intent#ACTION_USER_FOREGROUND} sent to registered receivers of the new user and all profiles of this user. Sent only if {@code foreground} parameter is true
    以上两个广播,只在该方法进行了发送。
    UserController.java
    void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
        long ident = Binder.clearCallingIdentity();
        try {
            Intent intent;
            if (oldUserId >= 0) {
                // Send USER_BACKGROUND broadcast to all profiles of the outgoing user
                List profiles = mInjector.getUserManager().getProfiles(oldUserId, false);
                int count = profiles.size();
                for (int i = 0; i < count; i++) {
                    int profileUserId = profiles.get(i).id;
                    intent = new Intent(Intent.ACTION_USER_BACKGROUND);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                            | Intent.FLAG_RECEIVER_FOREGROUND);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
                    mInjector.broadcastIntent(intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
                }
            }
            if (newUserId >= 0) {
                // Send USER_FOREGROUND broadcast to all profiles of the incoming user
                List profiles = mInjector.getUserManager().getProfiles(newUserId, false);
                int count = profiles.size();
                for (int i = 0; i < count; i++) {
                    int profileUserId = profiles.get(i).id;
                    intent = new Intent(Intent.ACTION_USER_FOREGROUND);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                            | Intent.FLAG_RECEIVER_FOREGROUND);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId);
                    mInjector.broadcastIntent(intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, SYSTEM_UID, profileUserId);
                }
                intent = new Intent(Intent.ACTION_USER_SWITCHED);
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                        | Intent.FLAG_RECEIVER_FOREGROUND);
                intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
                mInjector.broadcastIntent(intent,
                        null, null, 0, null, null,
                        new String[] {android.Manifest.permission.MANAGE_USERS},
                        AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID,
                        UserHandle.USER_ALL);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

该方法有两个调用场景
第一个:AMS#systemReady, mUserController.sendUserSwitchBroadcasts(-1, currentUserId);,因为oldUserId为-1,因此只会发送ACTION_USER_FOREGROUND广播
第二个:在startUser的时候,这个场景,只有foreground为true的时候才会发送。两个广播都会发送,因为一个user切换到前台,必然伴随另一个user切换到后台;两个广播携带的userid不一样(不是废话吗)

if (foreground) {
    moveUserToForeground(uss, oldUserId, userId);-->sendUserSwitchBroadcasts
} else {
    finishUserBoot(uss);
}
  1. Intent#ACTION_USER_SWITCHED} sent to registered receivers of the new user.Sent only if {@code foreground} parameter is true
    也是在sendUserSwitchBroadcasts方法中,场景同上面两个广播
    //Intent#ACTION_USER_STARTING} 注释找那个标注,这个广播应该在这个位置,实际代码中实在startUser的最后阶段发送的

  2. Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new user

  3. Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user

  4. Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new user. Sent only when the user is booting after a system update.

  5. Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of thenew user. Sent only the first time a user is starting.

  6. Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the newuser. Indicates that the user has finished booting.

  7. Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers of the new fg user

扩展知识

有序广播
有序广播,即从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接收器进行处理,依次类推,直到最后。如果多个应用程序设置的优先级别相同,则谁先注册的广播,谁就可以优先接收到广播。
通过Context.sendorderBroadCast()方法来发送

sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras)

其中的参数resultReceiver,可以自己重写一个类,作为一个最终的receive 最后都能够接收到广播,最终的receiver 不需要再清单文件里面配置,initialData可以作为传输的数据
广播可以被终止,数据传输过程中可以被修改。

你可能感兴趣的:(Android 9.x多用户机制 2 #Profile User启动过程)