Android 5.0(lollipop)发布之后,看特性文档增加了不少有趣的东西。

最近花了一些时间,研究了下其中Managed Profile的概念,简称MP,记录下来作为一些经验,有需要的同学请参考。

简介

Managed Profile,简称被管理者账户。这个概念并不是什么新东西,因为早在4.2版本中,Android就引入了多用户机制来解决平板使用上的问题。而如今5.0新加入的这个被管理者账户功能,可以理解成为是为了解决用户本人对于应用进行分类的需求问题而做的细化吧。

存在于被管理者账户中的应用受制于主账户,也就是仍然处于机主本人的控制之下。但这些应用的存储空间,以及应用的userID和PID都不同于主账户的同名应用。

这些在被管理者账户中的应用可以由机主进行各方面的限制,比如说控制这些应用不能访问摄像头——所有涉及到拍照部分的功能都开启不了,再比如说控制某些特定应用的功能——比如说让chrome的历史记录功能禁止使用。而所有的这些应用都与主账户中的应用隔离,这就意味着原本可能会被无故唤起的某些应用放到这里之后,它也再也不会被另一些流氓应用给后台唤醒了。

前提条件

首先,你需要一台安装Android5.0及以上版本的手机,亲儿子系列最好,因为不知道第三方ROM是否会将“加密”功能给阉割了。

开启手机加密的方法为:

设置——安全——加密手机

一般来说,手机出厂设置是不默认加密的,需要用户自己启动才行。当然,也可以通过代码来启动该功能,具体如下:

private voidregisterPovisionManagerProfile() {  if (null== this) {  return;  }  Intentintent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);  intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,  this.getApplicationContext().getPackageName());  if(intent.resolveActivity(this.getPackageManager()) != null) {  startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);  this.finish();  } else {  Toast.makeText(this, "Device provisioning is not enabled.Stopping.",  Toast.LENGTH_SHORT).show();  }
}  @Override  public voidonActivityResult(int requestCode, int resultCode, Intent data) {  if(requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {  if(resultCode == Activity.RESULT_OK) {  Toast.makeText(getApplicationContext(), "Provisioning done.",Toast.LENGTH_SHORT).show();  }else {  Toast.makeText(getApplicationContext(), "Provisioningfailed.", Toast.LENGTH_SHORT).show();  }  return;  }  super.onActivityResult(requestCode, resultCode, data);  }  

之后根据引导窗口则可以完成加密手机并设置Managed Profile的流程。

具体模块设计相关

对手机加密完成,并生成Managed Profile账户之后,我考虑了以下几个问题。

1.      启动MP账户的流程

在google给出的官方样例中,启动一个ManagedProfile已经有了一套成熟的方案。

具体如下:

a)        判断当前应用是否已经注册为当前账户的账户所有者(profile owner)——可以理解是拥有某些高级权限,类似admin用户。

b)        如果不是,则参考加密的流程,发一个系统的intent启动加密流程。

c)        如果是,那么恭喜你,你已经处于一个MP中,并且拥有这个MP下的类管理者权限了。

参考google的官方样例BasicManagedProfile即可。

为了方便后续描述,当前应用我简称为AdminApp好了。

2.      如何添加现有应用至MP账户中。

一般来说,查询当前系统中安装的应用状态Android已经有了非常方便的方式,通过PackageManager可以查到系统中安装的各个包的信息总合,也可以指定特定的包名来查询对应信息。

但是,这个在MP账户中是做不到的。

比如常见的getInstalledPackages(intflag)方法,虽然平时调用时仅使用参数flags。但从源码来看,真实的被调用者其实是被隐藏的方法getInstalledPackages(int flags,int userId),暴露给我们的方法中,userId已经固定为当前的用户ID。

再看一下PackageManager服务进程就能知道,真正在查询安装包信息时,该方法需要将userID作为校验条件之一。通常一个Profile下对应的所有应用都有一个相同的userID,所以跨了Profile后就无法查询主账户下的应用信息了。

所以在默认的MP账户中操作getInstalledPackages(),如果指明返回非系统应用,则只会返回当前应用本身,其他的三方应用是无法找到的。同样,查找系统应用也只能查找到在MP账户中注册的系统应用,没有注册的同样也找不到。

因此,如果要添加相关应用至MP账户中,无法通过轮询当前被管理者账户下所有的应用名称来一一添加。目前可行的有两种方法,一种是用包名字串来激活,另一种是从主账户AP来获取包名激活。

其中,谷歌的官方demo BasicManagedProfile使用的第一种方法,这里先进行介绍这种方法。如何从主账户来获取留在后面介绍。

还是以Chrome应用为例。

Chrome的包名是:com.android.chrome

通过isApplicationEnabled方法可以判断当前这个应用并没有在MP账户中。具体的原理就是刚才所说的userID隔离后的查询的结果。

 /** * Checks if the application is availablein this profile. * * @param packageName The package name * @return True if the application isavailable in this profile. */
private boolean isApplicationEnabled(String packageName) {
…
}  

Android对已知包名的系统应用,提供了将其重新安装到被管理者账户中的方法供AdminApp来调用。即public void enableSystemApp (ComponentName admin, StringpackageName)。

具体的使用流程可以参考demo中的代码段:

/** * Enables or disables the specified app in this profile. * * @param packageName The package name of the target app. * @param enabled     Pass true toenable the app. */
private voidsetAppEnabled(String packageName, boolean enabled) {
}  

需要注明的一点是,这个方法只针对拥有INSTALL_PACKAGES权限的系统应用有效,如果你传入的第三方应用包名,那么肯定会抛出IllegalArgumentException:Only system apps canbe enabled this way异常。

即使通过反射直接调用PackageManager服务的installExistingPackageAsUser(packageName,userID)方法,也会因为权限的问题而失败。

所以,手动添加第三方应用到MP中目前我是没有找到更好的方法,只能在建立MP之后重新安装指定的第三方应用,此时,MP中会同样安装一份拷贝版本。

通过AdminApp调用enableSystemApp使能的系统应用会出现在被管理者账户中,作为Launch的图标显示出来。

:

同样,如果不希望该应用显示在MP中,可以用AdminApp调用publicboolean setApplicationHidden (ComponentName admin, String packageName, booleanhidden)来隐藏。

简而言之,通过上述的操作,可以将一个系统应用重新安装到被管理者账户中。之后,你可以对这个被管理者账户中的应用进行限制操作了。

Android之Lollipop DevicePolicyManager学习(上)相关推荐

  1. Android之Lollipop DevicePolicyManager学习(下)

    转载:http://blog.csdn.net/guiyu_1985/article/details/42968781 3.      如何在主账户与被管理者账户之间做数据通信. a)         ...

  2. Android第一行代码学习思考笔记(碎片、广播、持久化技术和Android数据库)

    Android第一行代码学习思考笔记(碎片.广播.持久化技术和Android数据库 第四章 手机平板要兼顾--探究碎片 4.1碎片是什么(Fragment) 4.2碎片的使用方式 4.2.1碎片的简单 ...

  3. android组件浮动在activity上_Jetpack Hilt 依赖注入框架上手指南

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:LvKang-insist 链接:https://juejin.im/post/5efdff9d6fb9a07e ...

  4. Android 开源项目及其学习

    Android 系统研究:http://blog.csdn.net/luoshengyang/article/details/8923485 Android 腾讯技术人员博客 http://hukai ...

  5. Android接口和框架学习

    Android接口和框架学习 缩写: HAL:HardwareAbstraction Layer,硬件抽象层 CTS:CompatibilityTest Suite,兼容性测试套件 Android让你 ...

  6. Android的启动模式(上)

    Android的启动模式(上) 1. 基本介绍 大家平时只要懂一点Android知识的话,都一定会知道,一个应用的组成,往往包含了许多的activity组件,每个activity都应该围绕用户的特定动 ...

  7. [Android]Android P(9) WIFI学习笔记 - HAL (1)

    目录 前文回顾 前言 入口 WifiNative 初始化 打开WIFI IWifiChip IWifiCond ISupplicant 前文回顾 WIFI学习笔记 - Framework (1) WI ...

  8. Android Qcom USB Driver学习(二)

    该系列文章总目录链接与各部分简介: Android Qcom USB Driver学习(零) BC v1.2充电规范 Battery Charging Specification USB port 如 ...

  9. 基于android系统的单词学习软件设计与开发【附项目源码+论文说明】分享

    基于android系统的单词学习软件设计与开发演示 摘要 随着手机使用的普及,人们获取与保存信息的方式已经发生了激动人心的转变.智能手机正在逐步融入我们的生活,并影响和改变着我们的生活.由于现在各种智 ...

最新文章

  1. android教程登陆,【教程】Android 记住密码和自动登录界面的实现
  2. vscode / ubuntu 下编译和调试 C/C++ 方法
  3. JavaWeb第一讲 Servlet的工作原理及生命周期
  4. 硬盘基本知识(磁头、磁道、扇区、柱面) 转
  5. 【转】详细解析Java中抽象类和接口的区别
  6. 前端学习(2579):组件库使用
  7. python中zip的使用_浅谈Python中的zip()与*zip()函数详解
  8. linux命令行 teamview,linux下安装team viewer的方法
  9. linux如何打开22端口?如何开启ssh远程链接
  10. 用Wireshark+小度WIFI抓手机app包
  11. 潮流计算程序————支路功率计算与输出程序
  12. vs2015遇到找不到kernel32.lib,无法解析的外部符号 __imp__printf的问题
  13. Adobe Premiere Pro CC 2018 剪裁音频文件攻略
  14. python是个啥-CPython是个什么鬼?
  15. [rtsp @ 0x55ba1dae9200] UDP timeout, retrying with TCP的解决办法
  16. ArangoDB数据类型
  17. Django作业管理系统(1)
  18. iPhone“点击支付”新功能上热搜:比支付宝还方便?
  19. [ue4] 着色器绑定(Shader Binding)
  20. 一键搞定Netty难关,看到NIO再也不犯糊涂了,积累总结

热门文章

  1. ASP.NET Core使用Middleware有条件地允许访问路由
  2. ASP.NET Core 中的规约模式(Specification Pattern )——增强泛型仓储模式
  3. 面向.NET开发人员的Dapr——发布和订阅
  4. .NET 搭建简单的通知服务
  5. ABP vNext分布式事件总线RabbitMQ注意事项
  6. 吐槽一下Abp的用户和租户管理模块
  7. 在ubuntu上实现基于webrtc的多人在线视频聊天服务
  8. 提高文档翻译效率神器:VS Code 插件之 Translator Helper
  9. WebAssembly生态将完善网络安全性
  10. [NewLife.XCode]百亿级性能