前言
Android支持多用户,所以多用户管理作为一个课题是研究Android frameworks逃不开的一个模块。从名字上来看UserManagerService看起来是管理用户的主要service,这个service位于
com.android.server.pm包下。Android并没有为用户管理新建一个package而是将其放在pm包下,我们都知道pm是对主要对一个个应用包做管理,也就是目标对象是一个个应用程序,那对用户的管理与对应用程序的管理同级存在是否别有一番意义呢?
首先回顾下Linux的基础知识点,Linux中是支持多用户体系的: 使用uid/gid来管理用户,uid代表用户Id,gid代表组id。而在不支持多用户Android早期,这种体系被应用到了应用管理上,这种感觉就是应用本身就Android的一个个独立用户。但是这种“用户”概念毕竟不是现实生活中真正使用手机的不同用户,所以在API 17,Android开始支持多用户后,引入了UserHandle的概念以此来区别真正操作手机的用户。除了这样微妙的联系外,PMS和UMS还有更加直接的联系,下文会介绍到。
静态结构
个人习惯先看一个模块的静态结构,所以这里先放上一张静态图:
从上面简便的结构图及类图中我们可以看到,对应UMS的Bp端服务UserManager位于base/core下的
android.os包中,而Bn端的UserManagerService服务却位于base/services/core下的
com.android.server.pm包中,从这样的位置我们不难看出Google的想法:面对上层用户管理(UserManager)理应是系统级的服务和系统息息相关,所以放在android.os包下,而在对应services中的用户管理和pm关系密切,所以放在com.android.server.pm包下。
除此之外,我们看到UMS和AMS有交互,这种交互主要是通过AMS中含有的UserController类来完成。PMS和UMS的交互则更加直接,PMS直接通过含有的UMS实例来完成对用户的管理亦或是对用户信息的获取。
启动
接下来我们动态的来看整个模块,首先是启动:
这张时序图描绘了启动时AMS,PMS和UMS关于用户管理的一些操作。虽然时序图的重点本身就是时间和顺序,但是这里还是要单独提下几个service的启动顺序。
首先是AMS的启动,AMS启动后一直在做自己的事情,前期并没有做关于用户管理的操作。然后就是PMS的启动,这里注意PMS的启动并不是像大多数的其他Service那样使用内部类LifeCycle来,他是直接调用了PackManagerService的main方法:
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
而main方法中:
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
// 这里直接构建了PackageManagerService的创造方法
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
而在PMS的构造函数中:
`public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//...
// 在这里直接构建了UserManagerService的实例
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
//...`
以上的代码对应时序图中的第6、7步,可以直观的看出在SystemServer启动UMS之前,UMS的实例已经被创建了。而在正式start UMS时,如下面代码所示:
public static class LifeCycle extends SystemService {
private UserManagerService mUms;
/** * @param context */
public LifeCycle(Context context) {
super(context);
}
@Override
public void onStart() {
// UMS实例已经被创建,所以这里直接publish了已存在的实例
mUms = UserManagerService.getInstance();
publishBinderService(Context.USER_SERVICE, mUms);
}
@Override
public void onBootPhase(int phase) {
// 在如下阶段的时候,UMS做的第一件事情是去clean up
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mUms.cleanupPartialUsers();
}
}
}
上面UMS真正工作前依赖了PHASE_ACTIVITY_MANAGER_READY的启动阶段,这个阶段由AMS释放,显然目前的阶段不符合,所以UMS被start了之后还未开始工作。
接着PackageManagerService 开始标记ready了对应12步,然后开始调用UMS中的方法整理用户信息。对应13步和15步。
接着AMS开始ready并且标记了PHASE_ACTIVITY_MANAGER_READY,UMS开始主动做clean up user的工作
。
最后当ActivityStackSupervisor触发finish boot时,AMS会调用UserController中的方法开始
start user。这里的start user其实就是记录start的user state保存在一个列表中,并且记
录了这个user的状态最终为启动状态。至此启动阶段的工作完成。
增删及切换用户
说到多用户管理,自然离不开启动、增加和删除用户。
1、启动用户
首先是启动用户
这里有个参数需要了解一下:forground,如其表面含义一样,这个参数其实代表是否是前台启动user还是后台启动,前台启动是什么意思?其实是比如像切换用户这种,可见的启动另一个用户。从上面的时序图我们
可以看出启动用户主要是以下几个工作:
1、如果是新用户启动的话,创建对应的UserState实例,并保存(对应图中2、3)
2、如果是前台启动用户,会调用WMS中的相关方法(对应4、5、6)
3、准备相应用户数据(对应7、8、9)
4、如果是前台启动就是发送相应广播,并且使用ActivityStackSupervisor将相应activity切到前台。(对应图中10-12步)
5、如果是后台启动则标记user state并且做些善后工作将finish user boot广播出去。
2、增加用户
我们从面向上层的UserManager开始出发:
创建用户的流程从图中可以看出主要分为以下步骤:
1、获取可用的user id,然后封装UserData信息,保存在UMS的列表中(对应图中5、6、7)
2、将用户数据写入本地持久化保存,注意这里partial字段标注了此时的用户因为还未创建完全所以是不完整的用户(对应图中8、9)
3、通过工具类准备用户目录和数据,在准备的过程中会做相应的校验,校验不通过会清空用户目录(对应图中10、11、12、13、14,在这个过程中会用到Installer(installd)来创建用户数据,省略在这几步中)
4、通过PMS来为新创建的用户安装系统app,准备系统app数据(对应图中15、16)
5、在数据准备完成之后,标记用户为完整用户并且更新本地用户数据,同时在pms中约束相关权限(对应图中12、18、19、20)
创建用户的最终产物是在UMS(内存)中创建了一份用户信息,同时磁盘上增加了此用户的用户目录数据及配套的系统app。
总的来说过程相对明朗,细节不再过多跟踪,下面来看下删除用户的流程。
3、删除用户
同样从UserManager出发:
从图中我们可以看出,删除用户的主要步骤为:
1、获取当前用户,check是否和要删除的一致,一致则不删除(对应图中4、5)
2、将要删除的用户数据记录到一个列表中,并置partial为true,同时更新磁盘上的用户数据(对应图中6、7)
3、通过AMS stop user并且改变对应user state,之后发送广播通知user_removed(对应图中8、9、10)
4、开始实际清除用户数据,首先删除了该用户下的app数据,然后利用工具类删除用户数据(对应图中11、12、13、14、15)
5、最后清除内存中的数据,同时删除磁盘上记录用户的xml文件
总的来说这个过程和创建用户对应,大致可以看作是逆过程,值得注意的是:在删除用户的时候同样先将用户的partial置为true,但是最后没有置回false是因为用户数据如果顺利被删除的话最后本身就已经不存在了,所以自然也没了将其置回false的过程。如果在删除的过程中手机重启了,带有标记位partial的数据,如之前所述第一时间会被继续清除掉。
总结
这里主要讲述了Android framework中对多用户的管理和支持,省略了storage 和 installd对于相关
存储和数据的操作。如对pms熟悉者读起来效果最佳。