Android4.2多用户模式的结构与实现

2024-03-31 07:48

本文主要是介绍Android4.2多用户模式的结构与实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://www.biaji.net/wp


本文将跟随洒家的理解和同学们的指正进一步修改。所以如果您需要转载,请保留出处,以防以后我改对了,您那边还是错的。

在Android 4.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 buildsif (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的public UserInfo 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的public boolean 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的 public boolean removeUser(int userHandle) 方法进行的。其具体实现同样 是在UserManagerService的同名方法中。

在调用时,系统进行如下操作:

  1. 检查调用者是否具有所需权限。
  2. 对软件包变化加锁
  3. 将用户id加入待移除用户列表,将用户状态设为partial,这样,在下次系统启动时,会清除此用户。
  4. 停止用户,杀掉用户相关进程。
  5. 发送用户移除的广播。广播成功后,删除用户描述文件和数据文件。
  6. 序列化用户列表

此外UserManager还提供了 public void 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目前加入了多用户支持。负责维护设备中存在的所有用户状态。服务以下述变量来记录当 前处于“启动”状态的用户。

/*** Which uses have been started, so are allowed to run code.*/final SparseArray mStartedUsers = new SparseArray();/*** LRU list of history of current users.  Most recently current is at the end.*/final ArrayList mUserLru = new ArrayList();/*** Constant array of the users that are currently started.*/int[] mStartedUserArray = new int[] { 0 };


用户的启动状态对象为com.android.server.am.UserStartedState。其中指定的用户状态有四种:

  • public final static int STATE_BOOTING = 0; //用户启动
  • public final static int STATE_RUNNING = 1; //运行中
  • public final static int STATE_STOPPING = 2; //停止中
  • public final static int STATE_SHUTDOWN = 3; //用户关闭状态

完整的用户生命周期为:
BOOTING->RUNNING->STOPPING->SHUTDOWN

用户必须处于RUNNING状态时,才能作为切换的目标用户。所以在用户切换流程中,首先要判断当前用户的状态, 并启动STOPPING/SHUTDOWN状态的用户。

多用户模式的牵涉面

锁屏界面

用户最先体验到多用户的入口位置即为锁屏界面。锁屏界面中加入了用户切换组件: KeyguardMultiUserSelectorView类。

该类在设备允许多用户存在的情况下,显示当前所有用户的列表。并在用户进行选择后,调用 ActivityManagerNative.getDefault().switchUser(int userId)方法进行用户切换。

外部存储

对于每个用户,Android都为其分配了单独的存储空间。标准的支持多用户的外部存储空间是由init.rc定义的环境 变量所指定:

# See storage config details at <a href="http://source.android.com/tech/storage/">http://source.android.com/tech/storage/</a>
mkdir /mnt/shell/emulated 0700 shell shell
mkdir /storage/emulated 0555 root rootexport 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用户, 实现“随手玩玩”模式。


这篇关于Android4.2多用户模式的结构与实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/863798

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、