美文网首页Android OS
Android 9.x多用户机制 2 #Profile User

Android 9.x多用户机制 2 #Profile User

作者: 古风子 | 来源:发表于2019-03-11 21:00 被阅读0次

    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<UserInfo> 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<UserInfo> 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

        本文链接:https://www.haomeiwen.com/subject/gweipqtx.html