配置多用户:
/frameworks/base/core/res/res/values/config.xml
修改其中的config_multiuserMaximumUsers的值为4 (看要支持几个用户)
修改之后,设置中能看到用户这个菜单,而不是本来就有的账户。
管理访客和用户的设置
此信息中的部分内容仅适用于运行 Android5.0 或更高版本的设备。如果您的设备运行 4.4 或更低版本的系统,则“菜单”图标类似 这个图标。如果您的设备运行 4.3 或更低版本的系统,则“设置”图标类似 这个图标。
如果您与家人或朋友共用您的手机或平板电脑,可以为他们设置独立的用户空间。在手机上,您可以让其他人以访客身份使用您的手机,这样一来,他们就无法访问设备上的所有信息。您可以更改访客和用户的设置,还可以查看每位用户或访客使用了多少存储空间。
请注意,只有机主可以管理设备上的其他用户。更改设备机主的唯一方法是将设备恢复出厂设置,这样会清除设备上的所有数据。
关于用户
您在手机上最多可以创建 4 位用户,而在平板电脑上最多可以创建 8 位用户。如果您使用的是手机,则手机需要运行 Android5.0 或更高版本,才能创建用户。如果您是平板电脑的机主,那么您还可以创建受限个人资料,以限制其他用户使用某些功能或查看相应内容。了解如何添加、更改或删除用户。
用户可以如何使用设备
在您将用户添加到设备而且他们完成设置流程后,新用户可以通过多种常用方式来使用设备:
· 设置他们自己的 Google 帐户和其他类型的帐户。
· 自定义锁定屏幕、主屏幕和其他设置。
· 添加、更新和删除应用。
设备机主和其他用户几乎可以执行相同的操作。但只有机主可以完全移除其他用户的空间。
· 设备机主可以选择是否允许用户拨打电话和发送短信。请注意,允许用户拨打电话和发送短信的同时也将允许其查看设备的通话记录和短信记录。
· 设备机主可以选择是否允许通过锁定屏幕创建新用户。
· 任何用户都可以代表其他用户接受更新后的应用权限。
· 与计算机一样,您只应与自己信任的人共用设备。
用户可以在设备上更改的设置
当设备上有多个用户时,各项设置的效果会有所不同:
· 根据您所使用的 Android 版本,设置 > 提示音和通知或声音(在“设备”下)下的设置仅会对单个用户的空间产生影响。
· 任何用户都可以更改设置 > 更多 > 飞行模式下的设置,且这些设置会对包括机主在内的所有用户产生影响。
· 如果您的设备运行的是 Android4.4,那么只有机主可以查看设置 > 更多 > VPN 下的设置,且这些设置会对所有用户产生影响。
关于访客
此信息仅适用于运行 Android5.0 或更高版本的设备。
您可以让其他人以访客的身份使用您的设备,这样一来,他们就无法访问设备上的所有信息。访客个人资料指的是访客在使用设备后可以删除的临时空间。了解如何使用或删除访客。
访客可以如何使用设备
请注意,在访客信息被删除前,它会一直保留在设备上。在您切换到访客模式后,访客可以通过多种常用方式来使用手机:
· 登录到其自己的 Google 帐户和其他类型的帐户。
· 自定义锁定屏幕、主屏幕和其他设置。
· 添加、更新和删除应用。
访客可以在设备上更改的设置
手机机主和访客几乎可以执行相同的操作。但只有机主可以完全移除其他用户的空间或卸载其他用户安装的应用:
· 设备机主可以选择是否允许访客拨打电话。请注意,允许访客拨打电话的同时也将允许其查看设备的通话记录。
· 设备机主可以选择是否允许通过锁定屏幕创建或移除访客。
· 任何用户都可以代表其他用户接受更新的应用权限。
· 与其他设备一样,您只应与自己信任的人共用手机。
访客和用户的设置
此信息中的部分内容仅适用于运行 Android5.0 或更高版本的设备。
通过锁定屏幕添加和切换用户
您可以对设备进行设置,以允许通过锁定屏幕创建或访问访客或用户。如果您想允许他人为自己创建空间,但又不想让这个人访问您的帐户,或者如果您限制对设备的所有访问,这项设置会十分有用。
启用或停用“允许在设备锁定时添加用户”功能
1. 打开设备的“设置”菜单 。
2. 触摸“设备”下的用户。
3. 触摸“菜单”图标 。
4. 选中或取消选中“允许在设备锁定时添加用户”。
查看访客和用户的存储空间使用情况
您可以查看每位访客或用户在您的设备上使用了多少存储空间。
查看存储空间使用情况
1. 打开设备的“设置”菜单 。
2. 触摸“设备”下的存储空间。
3. 屏幕上会显示当前用户或访客使用了多少存储空间。
4. 您可以在“其他用户”下查看其他用户或访客总共使用了多少存储空间。您将无法查看其他用户将这些存储空间用在了何处(即应用或文件)。
查看访客和用户的流量消耗情况
您可以查看每位访客或用户在您的设备上使用了多少流量。
查看流量消耗情况
1. 打开设备的“设置”菜单 。
2. 触摸“无线和网络”下的流量消耗。
3. 图表上会显示当前用户或访客已使用了多少流量。
4. 您可以在图表下查看其他用户或访客总共已使用了多少流量。您将无法查看其他用户将流量用在了何处(即应用使用情况)。
5. 触摸某位用户即可查看有关其流量消耗情况的详细信息,包括日期范围、前台数据和后台数据。
本文将跟随洒家的理解和同学们的指正进一步修改。所以如果您需要转载,请保留出处,以防以后我改对了,您那边还是错的。
在Android4.2中的一个比较显著的改变就是加入了多用户的支持。因多用户手机专利早已被Symbian雇员注册,故 android官方的多用户切换目前仅支持平板设备。
多用户模式的启用
系统判断当前设备是否支持多用户模式的依据是配置文件config.xml中的config_multiuserMaximumUsers配置项。其取值为整型,决定着当前设备支持的最大用户上限。默认值为1,即不支持多用户。如需启用多用户,则设置此值为大于1的值。在Nexus 7中,此值为 8。
具体代码的判断位置在UserManager.java:
public static int getMaxSupportedUsers() { // Don't allow multiple users on certain builds if (android.os.Build.ID.startsWith("JVP")) return 1; return SystemProperties.getInt("fw.max_users", Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers)); } |
多用户相关操作流程
对用户的操作目前未对普通应用开放,其相关API都有hide注解,并需要system权限。此外,用户的添加和移除还要需android.Manifest.permission.MANAGE_USERS权限。
用户添加流程
用户添加是通过调用UserManager的publicUserInfo createUser(String name, int flags)方法进行的。其具体实现在UserManagerService的同名方法中。
在调用时,系统进行如下操作:
1. 检查调用者是否具有所需权限。
2. 对安装和软件包流程加锁,保证线程安全
3. 检查多用户环境是否到达用户数量限制。如果没有,创建用户实例
4. 为新用户创建相关目录
5. 序列化用户列表
6. 发送用户建立广播,MountService在收到此广播后,调用createEmulatedVolumeForUserLocked方法为用户建立相应的数据目录
用户的保存
用户创建后,会首先在/data/system/users/userlist.xml文件中保存新增加用户的id,创建/data/system/users/用户id 目录,并将用户信息保存至其下的 用户id.xml 文件中。其内容包括一些基本的用户信息。
用户切换流程
用户切换是通过调用ActivityManager的publicboolean switchUser(int userId)方法进行。一般通过ActivityManagerNative.getDefault().switchUser(int userId)进行调用。
在调用时,系统进行以下操作
1. 检查调用者是否具有所需权限。
2. 获取切换目标用户信息,并设定当前用户为目标用户
3. WindowsManagerService设置当前用户,锁定屏幕
4. 切换目标用户状态至启动
5. 广播REPORT_USER_SWITCH_MSG和USER_SWITCH_TIMEOUT_MSG消息,设定用户切换和切换超时时间(2秒),此超时时间用于限定REPORT_USER_SWITCH_MSG广播全程时间。
6. 切换Activity堆栈至当前用户
7. 广播ACTION_USER_SWITCHED消息,各接收组件进行相应操作。大部分具体操作,比如存储目录切换、安全设置切换等,都在此广播后进行。
用户移除流程
用户移除是通过调用UserManager的 publicboolean removeUser(int userHandle) 方法进行的。其具体实现同样是在UserManagerService的同名方法中。
在调用时,系统进行如下操作:
1. 检查调用者是否具有所需权限。
2. 对软件包变化加锁
3. 将用户id加入待移除用户列表,将用户状态设为partial,这样,在下次系统启动时,会清除此用户。
4. 停止用户,杀掉用户相关进程。
5. 发送用户移除的广播。广播成功后,删除用户描述文件和数据文件。
6. 序列化用户列表
此外UserManager还提供了 publicvoid wipeUser(int userHandle) 方法,用于删除单个用户的所有数据,但保留用户账号。此方法目前对应的底层实现尚未完成。
多用户模式的API接口UserManager->UserManagerService
大致结构
与其它系统服务的实现类似,用户管理也采用了经由Binder调用的远程服务机制。UserManager为暴露给用户的接口,UserManagerService为接口的底层实现。其类图如下所示:
android.os.UserManager
UserManager是暴露出来的应用程序接口。对于普通应用程序,提供用户数查询,用户状态判断和用户序列号查询等基本功能。 普通应用没有用户操作权限。
对于系统应用,UserManager提供了创建/删除/擦除用户、用户信息获取、用户句柄获取等用户操作的接口。均由远程调用UserManagerService服务的对应方法实现。
isUserAGoat()
UserManager中提供了一个名为isUserAGoat()的方法。源码中此方法直接返回了false。此方法的加入纯粹是为了给枯燥的编程生活带来一丝乐趣,以便写出:
while(!isUserAGoat()){ } |
这样的语句。
com.android.server.pm.UserManagerService
与其它大部分Service一样,UserManagerService的实现采用了 单例模式。在服务中,由组成为UserInfo类的散列表mUsers维护所有的用户状态。
mUsers在系统启动时由/data/system/users/userlist.xml读取生成,并在运行期间动态改变。所有用户的添加、删除操作,都最终序列化回此文件中。
com.android.server.am.ActivityManagerService
ActivityManagerService目前加入了多用户支持。负责维护设备中存在的所有用户状态。服务以下述变量来记录当前处于“启动”状态的用户。
final SparseArray mStartedUsers = new SparseArray(); final ArrayList mUserLru = new ArrayList(); int[] mStartedUserArray = new int[] { 0 }; |
用户的启动状态对象为com.android.server.am.UserStartedState。其中指定的用户状态有四种:
· public final static intSTATE_BOOTING = 0; //用户启动
· public final static intSTATE_RUNNING = 1; //运行中
· public final static intSTATE_STOPPING = 2; //停止中
· public final static intSTATE_SHUTDOWN = 3; //用户关闭状态
完整的用户生命周期为:
BOOTING->RUNNING->STOPPING->SHUTDOWN
用户必须处于RUNNING状态时,才能作为切换的目标用户。所以在用户切换流程中,首先要判断当前用户的状态,并启动STOPPING/SHUTDOWN状态的用户。
多用户模式的牵涉面
锁屏界面
用户最先体验到多用户的入口位置即为锁屏界面。锁屏界面中加入了用户切换组件:KeyguardMultiUserSelectorView类。
该类在设备允许多用户存在的情况下,显示当前所有用户的列表。并在用户进行选择后,调用ActivityManagerNative.getDefault().switchUser(int userId)方法进行用户切换。
外部存储
对于每个用户,Android都为其分配了单独的存储空间。标准的支持多用户的外部存储空间是由init.rc定义的环境变量所指定:
# See storage config details at http://source.android.com/tech/storage/ mkdir /mnt/shell/emulated 0700 shell shell mkdir /storage/emulated 0555 root root export EXTERNAL_STORAGE /storage/emulated/legacy export EMULATED_STORAGE_SOURCE /mnt/shell/emulated export EMULATED_STORAGE_TARGET /storage/emulated # Support legacy paths symlink /storage/emulated/legacy /sdcard symlink /storage/emulated/legacy /mnt/sdcard symlink /storage/emulated/legacy /storage/sdcard0 symlink /mnt/shell/emulated/0 /storage/emulated/legacy |
在Dalvik虚拟机初始化的过程中,会以dalvik_system_Zygote.cpp中的mountEmulatedStorage函数,使用带有 MS_BIND参数的mount命令,将用户对应的外部存储卡目录mount到上述定义的TARGET目录下。其判断应用userid的方式为:以当前应用的uid/100000,获得对应的userid,这段逻辑位于system/core/libcutils/multiuser.c中。
而Environment类中相应的获取外部存储目录的方法,也是由上述环境变量所获得。对于每个用户,其标准外部存储路径为:
EMULATED_STORAGE_TARGET/userid/
比如:
/storage/emulated/0 为主用户的外部存储路径。
包管理(PackageManagerService)
在多用户环境下,所有用户安装的应用仍然同以前一样,放置于/data/app目录下。但原先/data/data的数据存储位置目前仅对主用户有效,其余用户的数据存储目录则位于/data/user/用户id/目录下。此目录的创建是在创建用户时由前述的MountService完成的。
对于每个用户,系统都会以PackageuserState类来维护其安装的软件状态。此列表以散列表的形式存在,由PackageSettingBase类维护。所有的包——用户关系和状态最终仍然序列化至/data/system/package.xml中,并保留/data/system/package-backup.xml作为备份。
可能的发展
Guest用户的实现
目前代码中已经存在诸如isGuestEnabled() 之类的方法。但没有对开发公开,可以预计今后会加入Guest用户,实现“随手玩玩”模式。