AMS->startUser过程分析

最近处理了一个多用户切换过程黑屏一小会的问题,记录下切换用户的过程. 这里先分析6.0系统再分析7.0系统,7.0系统添加了directBoot特性略有不同

private boolean startUser(final int userId, final boolean foreground) {
        // 1 检查权限INTERACT_ACROSS_USERS_FULL
        if (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 (DEBUG_MU) Slog.i(TAG_MU, "starting userid:" + userId + " fore:" + foreground);
        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (this) {
                final int oldUserId = mCurrentUserId;
                if (oldUserId == userId) {
                    return true;
                }
                //2 更新lock task mode 
                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
                        "startUser", false);
                //3 由于启动用户之前要创建用户,初始化一些用户的分区,数据,所以这里如果用户不存在说明还没有创建
                final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
                if (userInfo == null) {
                    Slog.w(TAG, "No user info for user #" + userId);
                    return false;
                }
                //4 对于前台启动的话设计到页面的切换,如果是个人资料用户,不算full user 不能前台启动
                if (foreground && userInfo.isManagedProfile()) {
                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
                    return false;
                }
                // 5 冻结屏幕,由于启动过程中涉及界面切换,有可能在切换过程中没有可以渲染的页面,用户就会看到黑屏,
                // 冻结屏幕的作用就是截图显示,当屏幕冻结完成关闭截图surface,这样就不会出现黑屏
                if (foreground) {
                    mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
                            R.anim.screen_user_enter);
                }

                boolean needStart = false;

                 //6 放到mStartedUsers结合中表示user已经启动,这里创建的UserState结构也是用于用户
                 // 切换过程中状态的设置
                // If the user we are switching to is not currently started, then
                // we need to start it now.
                if (mStartedUsers.get(userId) == null) {
                    mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
                    updateStartedUserArrayLocked();
                    needStart = true;
                }

                final Integer userIdInt = Integer.valueOf(userId);
                mUserLru.remove(userIdInt);
                mUserLru.add(userIdInt);
                if (foreground) {
                    mCurrentUserId = userId;
                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                    updateCurrentProfileIdsLocked();
                    //7 这里WMS会将其他user的页面设置成不可见,主要是通知SurfaceFlinger隐藏surface
                    mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
                    // 8 锁屏
                    mWindowManager.lockNow(null);

                } else {
                    //对于后台启动则不设计界面的切换,
                    final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
                    updateCurrentProfileIdsLocked();
                    mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
                    mUserLru.remove(currentUserIdInt);
                    mUserLru.add(currentUserIdInt);
                }

                final UserState uss = mStartedUsers.get(userId);

                // Make sure user is in the started state.  If it is currently
                // stopping, we need to knock that off.
                if (uss.mState == 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.mState = UserState.STATE_RUNNING;
                    updateStartedUserArrayLocked();
                    needStart = true;
                } else if (uss.mState == 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.mState = UserState.STATE_BOOTING;
                    updateStartedUserArrayLocked();
                    needStart = true;
                }

                //10 通知系统服务们用户启动了,注意mHandler和system_service中处理广播的线程为同一个线程
                if (uss.mState == UserState.STATE_BOOTING) {
                    // 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));
                }

                // 11 这里发送了两个消息,REPORT_USER_SWITCH_MSG用于报告用户切换,这个消息的处理会通知其他
                //关心切换用户的监听者 只有所有监听者处理完成消息后才会向下执行,向下执行会导致WMS的frozen状态
                //结束, USER_SWITCH_TIMEOUT_MSG则是超时处理,framework中很多由于客户端不可控的处理都是采用
                //超时处理进行善后
                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));
                    uss.switching = true;
                    mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
                            oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
                }
                //12 首次启动发送ACTION_USER_STARTED广播
                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);
                    broadcastIntentLocked(null, null, intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, Process.SYSTEM_UID, userId);
                }

                if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
                    if (userId != UserHandle.USER_OWNER) {
                        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                        broadcastIntentLocked(null, null, intent, null,
                                new IIntentReceiver.Stub() {
                                    public void performReceive(Intent intent, int resultCode,
                                            String data, Bundle extras, boolean ordered,
                                            boolean sticky, int sendingUser) {
                                            //13 延迟初始化操作
                                        onUserInitialized(uss, foreground, oldUserId, userId);
                                    }
                                }, 0, null, null, null, AppOpsManager.OP_NONE,
                                null, true, false, MY_PID, Process.SYSTEM_UID, userId);
                        uss.initializing = true; 
                    } else {
                        //14 直接执行初始化
                        getUserManagerLocked().makeInitialized(userInfo.id);
                    }
                }

                if (foreground) {
                    if (!uss.initializing) {
                        //15初始化完成的直接启动界面
                        moveUserToForeground(uss, oldUserId, userId);  
                    }
                } else {
                    //后台启动则通知StackSupervisor
                    mStackSupervisor.startBackgroundUserLocked(userId, uss);
                }

               //16 ACTION_USER_STARTING广播,妈的有病先发ACTION_USER_STARTED后发ACTION_USER_STARTING
               if (needStart) {
                    Intent intent = new Intent(Intent.ACTION_USER_STARTING);
                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                    broadcastIntentLocked(null, null, intent,
                            null, new IIntentReceiver.Stub() {
                                @Override
                                public void performReceive(Intent intent, int resultCode,
                                        String data, Bundle extras, boolean ordered, boolean sticky,
                                        int sendingUser) throws RemoteException {
                                }
                            }, 0, null, null,
                            new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
                            null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
                }  
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }

        return true;
    }

整体流程如注释所写,值得注意的就两个状态的切换
1 initializing ,switching 这二者用于处管理界面frozen状态
2 mState 有四个状态,其中启动过程涉及两个状态STATE_BOOTING,STATE_RUNNING

先来看initializing ,switching状态的处理, initializing在发送ACTION_USER_INITIALIZE广播时候设置为true,处理该广播的逻辑如下

 void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
        synchronized (this) {
            if (foreground) {
                moveUserToForeground(uss, oldUserId, newUserId);
            }
        }

        completeSwitchAndInitialize(uss, newUserId, true, false);
    }

首先对于前台启动直接切换页面,然后执行completeSwitchAndInitialize 函数,注意在初始化过程中,只是设置参数clearInitializing为真,在进入completeSwitchAndInitialize函数中设置uss.initializing = false.

 void completeSwitchAndInitialize(UserState uss, int newUserId,
            boolean clearInitializing, boolean clearSwitching) {
        boolean unfrozen = false;
        synchronized (this) {
        //1 设置uss.initializing = false;
            if (clearInitializing) {
                uss.initializing = false;
                getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
            }
            // 2 设置uss.switching = false;
            if (clearSwitching) {
                uss.switching = false;
            }
            //3 切换和初始化都完成才结束frozen状态,尽量保证不出现黑屏
            if (!uss.switching && !uss.initializing ) {
                mWindowManager.stopFreezingScreen();
                unfrozen = true;
            }
        }
        //4报告切换完成
        if (unfrozen) {
            mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
                    newUserId, 0));
        }
        //5 停止其他访客账号
        stopGuestUserIfBackground();
    }

函数completeSwitchAndInitialize第三步骤可以看出既要完成switch还要完成initializing才会结束frozen状态,frozen状态有个好处,就是会显示截图,不至于出现黑屏.

对于uss.switching的设置则在REPORT_USER_SWITCH_MSG消息的处理中,还记得吗前台启动要发送REPORT_USER_SWITCH_MSG消息.
dispatchUserSwitch函数用于处理REPORT_USER_SWITCH_MSG消息

    void dispatchUserSwitch(final UserState uss, final int oldUserId,
            final int newUserId) {
        final int N = mUserSwitchObservers.beginBroadcast();
        if (N > 0) {
            final IRemoteCallback callback = new IRemoteCallback.Stub() {
                int mCount = 0;
                @Override
                public void sendResult(Bundle data) throws RemoteException {
                    synchronized (ActivityManagerService.this) {
                        if (mCurUserSwitchCallback == this) {
                            mCount++;
                            if (mCount == N) {
                                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
                            }
                        }
                    }
                }
            };
            synchronized (this) {
                uss.switching = true;
                mCurUserSwitchCallback = callback;
            }
            for (int i=0; i<N; i++) {
                try {
                    mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
                            newUserId, callback);
                } catch (RemoteException e) {
                }
            }
        } else {
            synchronized (this) {
                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
            }
        }
        mUserSwitchObservers.finishBroadcast();
    }

主要就是通知mUserSwitchObservers所管理的关心用户切换事件的事件订阅者处理事件,当事件处理完成会回调callback,当所有的订阅者都处理完成事件后则发送sendContinueUserSwitchLocked(uss, oldUserId, newUserId)消息完成后续处理,而sendContinueUserSwitchLocked(uss, oldUserId, newUserId)就是要进行uss.switching状态的切换, 注意dispatchUserSwitch函数中还会设置uss.switching = true; 这里显示已经晚了,这是一个bug

 void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
        mCurUserSwitchCallback = null;
        mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
        mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
                oldUserId, newUserId, uss));
    }

sendContinueUserSwitchLocked 函数移除USER_SWITCH_TIMEOUT_MSG消息,说明用户切换没有超时,这里可见超时还是针对不可控的客户端来做的,并且发送了一个CONTINUE_USER_SWITCH_MSG消息.

CONTINUE_USER_SWITCH_MSG消息的处理在continueUserSwitch函数中完成

void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
        completeSwitchAndInitialize(uss, newUserId, false, true);
    }

这里还是执行了completeSwitchAndInitialize函数只不过与初始化过程不同的是设置clearSwitching为真,这样completeSwitchAndInitialize函数就会设置uss.switching为false,从而就可以结束frozen过程了.

我们在看看超时的处理,

  void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
        synchronized (this) {
            Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
            sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
        }
    }

这里直接执行sendContinueUserSwitchLocked函数,发送CONTINUE_USER_SWITCH_MSG,不在等待所有客户端处理完成了.看到这里我们也知道sendContinueUserSwitchLocked函数为什么设置mCurUserSwitchCallback=null了.

对于界面的切换我们还要关注一个点,moveUserToForeground

  void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
        boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
        if (homeInFront) {
            startHomeActivityLocked(newUserId, "moveUserToFroreground");
        } else {
            mStackSupervisor.resumeTopActivitiesLocked();
        }
        EventLogTags.writeAmSwitchUser(newUserId);
        getUserManagerLocked().onUserForeground(newUserId);
        sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
    }

moveUserToForeground函数有两个地方调用, 第一点是在用户初始化的函数moveUserToForeground中,如果是前台启动则会调用moveUserToForeground函数, 另外一个地方是startUser过程中,如果用户已经初始化完成,并且是前台启动直接moveUserToForeground进行界面切换.
moveUserToForeground函数中getUserManagerLocked().onUserForeground(newUserId);调用只是用于持久化user数据,而比较重要的函数是sendUserSwitchBroadcastsLocked用于告诉其他应用,user界面启动完成可以做界面操作了.

void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
        long ident = Binder.clearCallingIdentity();
        try {
            Intent intent;
            //1 通知旧用户以及他的个人资料用户进入后台
            if (oldUserId >= 0) {
                // Send USER_BACKGROUND broadcast to all profiles of the outgoing user
                List<UserInfo> profiles = mUserManager.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);
                    broadcastIntentLocked(null, null, intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
                }
            }
            //2 通知新用户以及个人资料进入前台
            if (newUserId >= 0) {
                // Send USER_FOREGROUND broadcast to all profiles of the incoming user
                List<UserInfo> profiles = mUserManager.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);
                    broadcastIntentLocked(null, null, intent,
                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                            null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId);
                }
                //3 通知用户切换完成
                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);
                broadcastIntentLocked(null, null, intent,
                        null, null, 0, null, null,
                        new String[] {android.Manifest.permission.MANAGE_USERS},
                        AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID,
                        UserHandle.USER_ALL);
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }

由此可见启动用户还是比较简单的,难点在于用户的创建和数据空间的准备以及分裂. 下面我们再来看看7.0中有何不同

boolean startUser(final int userId, final boolean foreground) {
        // 1 检查权限
        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);
        }

        final long ident = Binder.clearCallingIdentity();
        try {
            synchronized (mService) {
                final int oldUserId = mCurrentUserId;
                if (oldUserId == userId) {
                    return true;
                }
                // 2 Lock mode处理
                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;
                }
                if (foreground && userInfo.isManagedProfile()) {
                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
                    return false;
                }
                //3 前台启动冻结屏幕
                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;
                }

                final UserState uss = mStartedUsers.get(userId);
                final Integer userIdInt = userId;

                mUserLru.remove(userIdInt);
                mUserLru.add(userIdInt);
                // 4 前台启动 更新WMS关闭老用户界面,锁屏
                if (foreground) {
                    mCurrentUserId = userId;
                    mService.updateUserConfigurationLocked();
                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                    updateCurrentProfileIdsLocked();

                    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;
                    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) {
                    // 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));
                }
                // 5 前台启动设置超时和REPORT_USER_SWITCH_MSG消息报告切换用户给客户端
                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);
                }
                 //6 ACTION_USER_STARTED广播
                 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);
                }
                //7 直接启动界面
                if (foreground) {
                    moveUserToForegroundLocked(uss, oldUserId, userId);
                } else {
                    //8 后台启动直接完成启动
                    mService.mUserController.finishUserBoot(uss);
                }

               //9 ACTION_USER_STARTING广播
                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;
    }

这里与6.0不同的地方是直接启动界面,没有用户初始化的过程,那么我们再看看REPORT_USER_SWITCH_MSG消息的处理.
还是在dispatchUserSwitch函数中

 void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
        final int observerCount = mUserSwitchObservers.beginBroadcast();
        if (observerCount > 0) {
            final IRemoteCallback callback = new IRemoteCallback.Stub() {
                int mCount = 0;
                @Override
                public void sendResult(Bundle data) throws RemoteException {
                    synchronized (mService) {
                        if (mCurUserSwitchCallback == this) {
                            mCount++;
                            if (mCount == observerCount) {
                                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
                            }
                        }
                    }
                }
            };
            synchronized (mService) {
                uss.switching = true;
                mCurUserSwitchCallback = callback;
            }
            for (int i = 0; i < observerCount; i++) {
                try {
                    mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
                            newUserId, callback);
                } catch (RemoteException e) {
                }
            }
        } else {
            synchronized (mService) {
                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
            }
        }
        mUserSwitchObservers.finishBroadcast();
    }

和6.0中是一致的,sendContinueUserSwitchLocked函数也是一致的

  void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
        mCurUserSwitchCallback = null;
        mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
        mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG,
                oldUserId, newUserId, uss));
    }

continueUserSwitch函数则大不相同

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);
    }

不再判断初始化流程,直接解冻屏幕,可以看出整个流程提前切换了界面和提前了解冻屏幕.
另外超时的处理也是一样的

finishUserBoot函数

 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);
            }
        }
    }

这里可以看到用户启动多了好几种状态,都是为FPE(基于文件的加密)准备的:
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;

首先设置用户状态为STATE_RUNNING_LOCKED,锁定状态,然后发送启动完成广播ACTION_LOCKED_BOOT_COMPLETED

  boolean maybeUnlockUser(final int userId) {
        // Try unlocking storage using empty token
        return unlockUserCleared(userId, null, null, null);
    }
    boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
            IProgressListener listener) {
        synchronized (mService) { //1 解锁文件
            // 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
            final UserState uss = mStartedUsers.get(userId);
            if (uss == null) { //2通知解锁
                notifyFinished(userId, listener);
                return false;
            } else { 
                uss.mUnlockProgress.addListener(listener);
            }

            finishUserUnlocking(uss); //3解锁

            // 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");
                    maybeUnlockUser(testUserId);
                }
            }
        }

        return true;
    }

finishUserUnlocking为实际解锁的函数,只是到unLocking状态,还模拟了一个进度……. 最后发送SYSTEM_USER_UNLOCK_MSG消息处理解锁

 private void finishUserUnlocking(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_LOCKED, STATE_RUNNING_UNLOCKING)) {
                getUserManagerInternal().setUserState(userId, uss.state);
                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();
            }
        }
    }
 case SYSTEM_USER_UNLOCK_MSG: {
                final int userId = msg.arg1;
                mSystemServiceManager.unlockUser(userId); //1 通知system_server
                synchronized (ActivityManagerService.this) {
                    mRecentTasks.loadUserRecentsLocked(userId); //2加载多任务
                }
                if (userId == UserHandle.USER_SYSTEM) {
                    startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); //3启动没有设置directboot的常驻进程,这里磁盘已经解密,可以启动了
                }
                installEncryptionUnawareProviders(userId);//安装非directBoot的provider
                mUserController.finishUserUnlocked((UserState) msg.obj); //4 启动完成
                break;
            }
 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)) { //1更新解锁状态
                getUserManagerInternal().setUserState(userId, uss.state);
                uss.mUnlockProgress.finish();

                // Dispatch unlocked to external apps
                //2 解锁广播
                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);

                if (getUserInfo(userId).isManagedProfile()) { //2发送子用户ACTION_MANAGED_PROFILE_UNLOCKED解锁广播
                    UserInfo parent = getUserManager().getProfileParent(userId);
                    if (parent != null) {
                        final Intent profileUnlockedIntent = new Intent(
                                Intent.ACTION_MANAGED_PROFILE_UNLOCKED);
                        profileUnlockedIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(userId));
                        profileUnlockedIntent.addFlags(
                                Intent.FLAG_RECEIVER_REGISTERED_ONLY
                                | Intent.FLAG_RECEIVER_FOREGROUND);
                        mService.broadcastIntentLocked(null, null, profileUnlockedIntent,
                                null, null, 0, null, null, null, AppOpsManager.OP_NONE,
                                null, false, false, MY_PID, SYSTEM_UID,
                                parent.id);
                    }
                }

                // 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)) { 
                    //ota升级先发送Intent.ACTION_PRE_BOOT_COMPLETED广播,注意这个广播只在ota后发送
                    new PreBootBroadcaster(mService, userId, null) {
                        @Override
                        public void onFinished() {
                            finishUserUnlockedCompleted(uss); //3开机广播
                        }
                    }.sendNext();
                } else {
                    finishUserUnlockedCompleted(uss);//3开机广播
                }
            }
        }
    }
  private void finishUserUnlockedCompleted(UserState uss) {
        final int userId = uss.mHandle.getIdentifier();
        synchronized (mService) { 
            // Bail if we ended up with a stale user//1 检查状态,当前用户凭证已经失效直接返回
            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; //2 检查解密状态

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


            if (!userInfo.isInitialized()) { //3 非system用户初始化操作
                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); 
            //4 开机广播 这里可以看到FBE影响开机广播
            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);
        }
public void makeInitialized(int userId) {
        checkManageUsersPermission("makeInitialized");
        boolean scheduleWriteUser = false;
        UserData userData;
        synchronized (mUsersLock) {
            userData = mUsers.get(userId);
            if (userData == null || userData.info.partial) {
                Slog.w(LOG_TAG, "makeInitialized: unknown user #" + userId);
                return;
            }
            if ((userData.info.flags & UserInfo.FLAG_INITIALIZED) == 0) {
                userData.info.flags |= UserInfo.FLAG_INITIALIZED;
                scheduleWriteUser = true;
            }
        }
        if (scheduleWriteUser) {
            scheduleWriteUser(userData);
        }
    }

makeInitialized韩式只是用于持久化和设置 UserInfo.FLAG_INITIALIZED标志。

对于原始user SYSTEM_USER ,则是在WMS初始化完成之后,在bootAnimationComplete函数回调完成的

@Override
    public void bootAnimationComplete() {
        final boolean callFinishBooting;
        synchronized (this) {
            callFinishBooting = mCallFinishBooting;
            mBootAnimationComplete = true;
        }
        if (callFinishBooting) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
            finishBooting();
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        }
    }

再次总结下整个流程,主要分两路
1 REPORT_USER_SWITCH_MSG 用于switch流程,调用客户端的注册在mUserSwitchObservers中的事件订阅者,在MainHandler中执行
2 REPORT_USER_SWITCH_COMPLETE_MSG

广播,有可能不在MainHandler中执行,因为包含从finshBoradcast中执行的情况,但是会保证广播有序执行
1 Intent.ACTION_USER_STARTED广播
2 Intent.ACTION_USER_INITIALIZE 用于初始化
3 Intent.ACTION_USER_STARTING
4 Intent.ACTION_USER_BACKGROUND
5 Intent.ACTION_USER_FOREGROUND
6 Intent.ACTION_USER_SWITCHED

猜你喜欢

转载自blog.csdn.net/woai110120130/article/details/79943022