一、 问题描述
ActivityManager.getService().registerUserSwitchObserver
这个API的回调是一个阻塞式接口,也就是说框架那边遍历注册的observer,依次回调,每个observer执行完后框架才会回调下一个,直到全部执行结束,才会以安全的状态切换多用户。
当任意一处回调出现了耗时严重、卡顿、ANR问题甚至超时,都会严重影响系统切换多用户的过程。
二、 流程分析
2.1 基本概念
多用户相关逻辑,由AMS委派给UserController
类控制:
// 注册的IUserSwitchObserver接口保存在其中
private final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
= new RemoteCallbackList<>();
UserController(Injector injector) {
mInjector = injector;
// 回调所使用的Handler在构造方法中赋值
mHandler = mInjector.getHandler(this);
mUiHandler = mInjector.getUiHandler(this);
// User 0 is the first and only user that runs at boot.
final UserState uss = new UserState(UserHandle.SYSTEM);
// ...
}
/**
* 这四个dispatch方法分别对应UserSwitchObserver的四个回调方法
*/
public boolean handleMessage(Message msg) {
switch (msg.what) {
case REPORT_USER_SWITCH_MSG:
dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
break;
case FOREGROUND_PROFILE_CHANGED_MSG:
dispatchForegroundProfileChanged(msg.arg1);
break;
case REPORT_USER_SWITCH_COMPLETE_MSG:
dispatchUserSwitchComplete(msg.arg1);
break;
case REPORT_LOCKED_BOOT_COMPLETE_MSG:
dispatchLockedBootComplete(msg.arg1);
break;
// ...
}
}
RemoteCallbackList
由名字可知是跟binder相关:
// 保存的应用层注册的binder回调
public class RemoteCallbackList<E extends IInterface> {
/*package*/ ArrayMap<IBinder, Callback> mCallbacks
= new ArrayMap<IBinder, Callback>();
}
Injector
是UserController
的内部类:
static class Injector {
private final ActivityManagerService mService;
private UserManagerService mUserManager;
private UserManagerInternal mUserManagerInternal;
Injector(ActivityManagerService service) {
mService = service;
}
protected Handler getHandler(Handler.Callback callback) {
return new Handler(mService.mHandlerThread.getLooper(), callback);
}
protected Handler getUiHandler(Handler.Callback callback) {
return new Handler(mService.mUiHandler.getLooper(), callback);
}
}
mService.mHandlerThread
是AMS中用于执行业务的子线程:
public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
mInjector = new Injector();
mHandlerThread = new ServiceThread(TAG,
THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
mUiHandler = mInjector.getUiHandler(this);
// ...
}
下面分析多用户切换整个过程,以首次创建子用户为例。
2.2 创建用户
选择新建子用户时,执行UserManager#createUser
,在UserManagerService
中经过权限校验,最后调用到了createUserInternalUnchecked
方法:
private UserInfo createUserInternalUnchecked(...) {
// ...
// 分配UserId,从10开始
userId = getNextAvailableId();
// 以UserId为文件夹名创建子用户的系统数据根目录
Environment.getUserSystemDirectory(userId).mkdirs();
// ...
// 写入用户配置文件数据
writeUserLP(userData);
writeUserListLP();
// ...
// 创建用户密钥
final StorageManager storage = mContext.getSystemService(StorageManager