当前位置:首页 > 手机资讯 > 正文

Android 手机应用关闭手机「Android 手机应用」

Android 手机应用关闭手机「Android 手机应用」

当前市面上实现手机分身的方式主要有三类:

  1. 修改Framework -> 使用进行实现

    该方式适用于手机厂商,修改底层代码,通过创建多用户的方法来实现手机分身功能。

    通过getFileDir()的api发现,在本体得到的是 ,克隆得到的是

  2. 修改apk

    通过反编译apk,修改apk的包名、签名等将apk伪装成另一个app,市面上常见的第三方多开app大部分都是使用该技术。其特点是每次制作一个分身都需要时间进行一个拷贝、并且在应用列表中可以看到

    参考资料:

    https://blog.csdn.net/weixin_43970718/article/details/119116441

  3. 虚拟操作系统

    虚拟一个操作系统,克隆体app在这个虚拟系统中运行,在应用列表不可见,代表产品:360分身

    检测方案:
    这个据说是唯一一种绕过getFileDir()的分身方式,确实这种方式让我耗费了很长时间,下面以360的分身举例,详细说下分析过程

    1. 首先通过getFileDir()尝试,本体和克隆体输出一致。失败!!
    2. 通过在本体和克隆体登录不同账号获取SP中存储的账号信息,确定获取的信息不同,证明存储位置不一致
    3. 通过文件管理器查看最近修改的文件,发现系统根目录下有一个docker的文件夹,里面包含了跟根目录类似的结构,在其里面的Android/data下就会发现我们自己的包名,分身的本地数据就存放在这里。
    4. 找到分身的本地存储后,本想向其中存储数据用来标记是否为分身,但本体运行时报了一个无权限写入的异常,因此改为了判断当前是否有对该目录的写入权限

2.1、多用户简介

从Android 4.0开始,Google就开始在Android上布局多用户,因此而诞生。

2.2、基础概念

多用户的一些基础概念:

  1. Uid(用户id):在Linux上,一个用户Uid标识着一个给定的用户。Android上也沿用了Linux用户概念,Root用户Uid为0,System Uid为1000,并且,每个应用程序在安装时也被赋予了单独的Uid,这个Uid将伴随着应用从安装到卸载。
  2. Gid(用户组id):Linux上规定每个应用都应该有一个用户组,对于Android应用程序来说,每个应用的所属用户组与Uid相同。
  3. Gids:应用在安装后所获得权限的Id。在Android上,每个权限都可能对应一个或多个group,每个group有个gid name,gids就是通过每个gid name计算得出的id,一个UID可以关联GIDS,表明该UID拥有多种权限。

2.3、多户用特性

  1. 独立的

    Android在创建每个用户时,都会分配一个整型的userId。对于主用户(正常下的默认用户)来说,userId为0,之后创建的userId将从10开始计算,每增加一个userId加1。

     

    创建一个名为“ulangch”的用户:

     

    启动和切换到该用户:

     
  2. 独立的文件存储

    为了多用户下的数据安全性,在每个新用户创建之初,不管是外部存储(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。

  3. 独立的权限控制

    1. 不同的用户具有权限不同,如:访客用户的默认权限限制就有:

       

      (注:使用 “adb shell dumpsys user” 可以查看所有的用户信息,如userId、name、restrictions等)

      这些权限可以在创建用户时规定,也可以后期由系统动态设置。

    2. 不同用户下App的应用权限是独立的

      前面说到,uid与userId存在一种计算关系(uid = userId * 1000000 + appId),而在系统中对于权限控制也是根据uid和对应的userId来判定的,因此不同用户下相同应用可以具有不同的权限。

  4. App安装的唯一性

    App的文件存储和数据目录在不同用户下都是独立的,但是对于App的安装,多个用户下同一个App却保持着同一个安装目录,即:

    1. 普通三方app:

    2. 普通系统应用:

    3. 特权系统应用:

       

    拓展:权限在声明时安全等级(protectionLevel)分为3类:

     
      
    1. normal:普通权限,在AndroidManifest.xml中声明就可以获取权限,如 INTERNET 权限
    2. dangerous:敏感权限,需要动态申请告知用户才能获取
    3. singature|privileged:具有系统签名的系统应用才可以获取的权限,对应上方的

    因此,多用户下的应用其实只安装一次,不同用户下同一个应用的版本和签名都应该相同,不同用户下相同App能够独立运行是因为系统为他们创造了不同的运行环境和权限。

  5. 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/)

3.1、概述

Android 多用户模型,通过UserManagerService对多用户进行创建、删除、查询等管理操作。

  • Binder服务端:UserManagerService继承于IUserManager.Stub,作为 binder 服务端。
  • Binder客户端:UserManager的成员变量mService继承于IUserManager.Stub.Proxy,该变量作为binder客户端。UserManager的大部分核心工作都是交由其成员变量mService,再通过binder调用到UserManagerService所相应的方法。
3.1.1、概念

userId,uid,appid,ShareAppGid概念关系

  • userId:是指用户Id;
  • appId: 是指跟用户空间无关的应用程序id;取值范围 0<= appId <100000
  • uid:是指跟用户空间紧密相关的应用程序id;
  • SharedAppGid:是指可共享的应用id;

转换关系:

 

另外,PER_USER_RANGE = 100000, 意味着每个user空间最大可以有100000个appid。这些区间分布如下:

  • system appid: [1000, 9999]
  • application appid:[10000, 19999]
  • Shared AppGid: [50000, 59999]
  • isolated appid: [99000, 99999]
3.1.2、UserHandle

常见方法:

方法含义isSameUser比较两个uid的userId是否相同isSameApp比较两个uid的appId是否相同isAppappId是否属于区间[10000,19999]isIsolatedappId是否属于区间[99000,99999]getIdentifier获取UserHandle所对应的userId

常见成员变量:(UserHandle的成员变量mHandle便是userId)

userId赋值含义USER_OWNER0拥有者USER_ALL-1所有用户USER_CURRENT-2当前活动用户USER_CURRENT_OR_SELF-3当前用户或者调用者所在用户USER_NULL-1000未定义用户

类成员变量:

 

关于UID默认情况下,客户端可使用rocess.myUserHandle(); 服务端可使用UserHandle.getCallingUserId();

3.1.3、UserInfo

UserInfo代表的是一个用户的信息,涉及到的flags及其含义,如下:

flags含义FLAG_PRIMARY主用户,只有一个user具有该标识FLAG_ADMIN具有管理特权的用户,例如创建或删除其他用户FLAG_GUEST访客用户,可能是临时的FLAG_RESTRICTED限制性用户,较普通用户具有更多限制,例如禁止安装app或者管理wifi等FLAG_INITIALIZED表明用户已初始化FLAG_MANAGED_PROFILE表明该用户是另一个用户的轮廓FLAG_DISABLED表明该用户处于不可用状态
3.1.4、UserState
 

用户生命周期线:

 

3.2、UserManager的使用

 
 

4.1、进入设置中的应用界面逻辑代码

,通过进入应用界面的布局文件

 
 

在这里插入图片描述

在这里插入图片描述

4.2、进入手机分身的fragment类

 

user()方法,是父类DashboardFragment的方法

 

进入布局文件

 

在这里插入图片描述

进入
 
进入分身的布局

点击开启分身的时候创建一个Toast来提醒
在这里插入图片描述

关闭分身弹出dialog,判断是否进行关闭

在这里插入图片描述

 

4.3、计算应用界面中应用的数量

在这里插入图片描述

通过该界面的布局文件中的

进入类中,该类计算当前应用的数量,并且显示当前使用的应用数量

通过分析,可知,该方法中的加载所有app的数量,该方法实例化类,并重写方法

 
进入超父类中

方法进行计算总数量,该计算方法,通过遍历用户和应用双重遍历进行计算,所以算出来的数量double,所以在中,只获取第一个用户,在进行遍历应用

 

4.4、进入所有应用

在这里插入图片描述

该界面的方法类来显示应用图标和名字

该类有两个内部类适配器

-> SettingsSpinnerAdapter的适配器

在这里插入图片描述

-> RecyclerView的适配器

在这里插入图片描述

在该方法中创建头部SpinnerHeader,关闭头部的时候只显示一个的应用

 

4.5、开启手机分身后所有应用的显示

在这里插入图片描述

个人区域存放所有应用

工作区域显示的应用

实现的逻辑类
 

4.6、在Launcher进行设置

开启应用分身时第一次会创建clone用户,在创建clone用户时会触发该用户的下的app的onPackagesUpdated更新操作,而在无抽屉模式下onPackagesUpdated更新会触发VerifyIdleAppTask任务来更新该用户的图标显示

在VerifyIdleAppTask任务中对onPackagesUpdated进行判断,如果为clone用户下的应用更新只更新允许应用分身的package包名其他的应用则进行过滤不显示更新。

有话要说...

最新文章