当前市面上实现手机分身的方式主要有三类:
修改Framework -> 使用进行实现
该方式适用于手机厂商,修改底层代码,通过创建多用户的方法来实现手机分身功能。
通过getFileDir()的api发现,在本体得到的是 ,克隆得到的是
修改apk
通过反编译apk,修改apk的包名、签名等将apk伪装成另一个app,市面上常见的第三方多开app大部分都是使用该技术。其特点是每次制作一个分身都需要时间进行一个拷贝、并且在应用列表中可以看到
参考资料:
https://blog.csdn.net/weixin_43970718/article/details/119116441
虚拟操作系统
虚拟一个操作系统,克隆体app在这个虚拟系统中运行,在应用列表不可见,代表产品:360分身
检测方案:
这个据说是唯一一种绕过getFileDir()的分身方式,确实这种方式让我耗费了很长时间,下面以360的分身举例,详细说下分析过程
从Android 4.0开始,Google就开始在Android上布局多用户,因此而诞生。
多用户的一些基础概念:
独立的
Android在创建每个用户时,都会分配一个整型的userId。对于主用户(正常下的默认用户)来说,userId为0,之后创建的userId将从10开始计算,每增加一个userId加1。
创建一个名为“ulangch”的用户:
启动和切换到该用户:
独立的文件存储
为了多用户下的数据安全性,在每个新用户创建之初,不管是外部存储(External Storage)还是app data目录,Android都为其准备了独立的文件存储。
多用户下的/storage分区:
新用户创建时,Android在 “/storage/emulated” 目录下为每个用户都创建了名为用户id的目录,当我们在代码中使用 “Environment.getExternalStorageDirectory().absolutePath” 获取外部存储路径时,返回的就是当前用户下的对应目录(如:userId = 11, 则返回为 “/storage/emulated/10”)。
另外,可以看出,我们平常说到的 “/sdcard” 目录其实最终也是软链到了 “/storage/emulated/0”
多用户下的/data分区
与External Storage相同,新用户创建时,Android也会在 “data/user” 目录下创建了名为userId的目录,用于存储该用户中所有App的隐私数据,如果在代码中使用 “Context.getFilesDir()” 来获取应用的data目录,不同User下也会有不同。
另外,也可以看出,平常说到的 “/data/data” 目录其实也是软链到了 “/data/user/0”。
注:在Android中,应用的uid是和当前的用户有关的,同一个应用具有相同的appId,其uid的计算方式为: ,在主用户中,uid = appId。
独立的权限控制
不同的用户具有权限不同,如:访客用户的默认权限限制就有:
(注:使用 “adb shell dumpsys user” 可以查看所有的用户信息,如userId、name、restrictions等)
这些权限可以在创建用户时规定,也可以后期由系统动态设置。
不同用户下App的应用权限是独立的
前面说到,uid与userId存在一种计算关系(uid = userId * 1000000 + appId),而在系统中对于权限控制也是根据uid和对应的userId来判定的,因此不同用户下相同应用可以具有不同的权限。
App安装的唯一性
App的文件存储和数据目录在不同用户下都是独立的,但是对于App的安装,多个用户下同一个App却保持着同一个安装目录,即:
普通三方app:
普通系统应用:
特权系统应用:
拓展:权限在声明时安全等级(protectionLevel)分为3类:
因此,多用户下的应用其实只安装一次,不同用户下同一个应用的版本和签名都应该相同,不同用户下相同App能够独立运行是因为系统为他们创造了不同的运行环境和权限。
kernel及系统进程的不变性
在不同用户下,虽然能够看到不同的桌面,不同的运行环境,一切都感觉是新的,但是我们系统本身并没有发生改变,kernel进程、system_server进程以及所有daemon进程依然是同一个,并不会重启。
而如果我们在不同用户中开启相同的app,我们可以看到可以有多个app进程,而他们的父进程都是同一个,即 zygote:
参考资料:https://blog.csdn.net/misiyuan/article/details/77432020?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ETopNSimilar%7Edefault-1-77432020-blog-94654401.topnsimilarv1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ETopNSimilar%7Edefault-1-77432020-blog-94654401.topnsimilarv1&utm_relevant_index=2
多用户模型:
链接:[多用户管理UserManager - Gityuan博客 | 袁辉辉的技术博客](http://gityuan.com/2016/11/20/user_manager/)
Android 多用户模型,通过UserManagerService对多用户进行创建、删除、查询等管理操作。
userId,uid,appid,ShareAppGid概念关系
转换关系:
另外,PER_USER_RANGE = 100000, 意味着每个user空间最大可以有100000个appid。这些区间分布如下:
常见方法:
常见成员变量:(UserHandle的成员变量mHandle便是userId)
类成员变量:
关于UID默认情况下,客户端可使用rocess.myUserHandle(); 服务端可使用UserHandle.getCallingUserId();
UserInfo代表的是一个用户的信息,涉及到的flags及其含义,如下:
用户生命周期线:
,通过进入应用界面的布局文件
user()方法,是父类DashboardFragment的方法
进入布局文件
点击开启分身的时候创建一个Toast来提醒
关闭分身弹出dialog,判断是否进行关闭
通过该界面的布局文件中的
通过分析,可知,该方法中的加载所有app的数量,该方法实例化类,并重写方法
方法进行计算总数量,该计算方法,通过遍历用户和应用双重遍历进行计算,所以算出来的数量double,所以在中,只获取第一个用户,在进行遍历应用
该界面的方法类来显示应用图标和名字
该类有两个内部类适配器
-> SettingsSpinnerAdapter的适配器
-> RecyclerView的适配器
在该方法中创建头部SpinnerHeader,关闭头部的时候只显示一个的应用
工作区域显示的应用
开启应用分身时第一次会创建clone用户,在创建clone用户时会触发该用户的下的app的onPackagesUpdated更新操作,而在无抽屉模式下onPackagesUpdated更新会触发VerifyIdleAppTask任务来更新该用户的图标显示
在VerifyIdleAppTask任务中对onPackagesUpdated进行判断,如果为clone用户下的应用更新只更新允许应用分身的package包名其他的应用则进行过滤不显示更新。
本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:xinmeigg88@163.com
本文链接:http://zleialh.tongchengxian.cn/news/2396.html
有话要说...