一、设备管理概述
Device admin 过时了。从Android 2.2开始,当device admin调用某些admin政策时会报过时。建议从现在准备好接受改变。更多集成的建议,请参考Device admin deprecation
Android 通过Android 设备管理API(Android Device Administration API)提供对企业应用的支持。Android设备管理API提供了系统层的设备管理特性。IT专业人员需要控制员工的设备时可以通过该APIs创建安全的应用。例如内置的Android邮件应用通过该APIs来提高交换的支持。通过该邮件应用,管理员可以强制指定通过该设备的密码政策(字母数字密码或数字的PINs密码)。管理员也可以远程清除丢失或被盗的手机信息(即恢复出厂设置)。用户也可以同步他们的邮件和日历数据。
本文适用于打算在Android设备上开发企业应用的开发者,本文讨论了设备管理API的各种特性,为员工的Android设备提供了高安全性。
1、Device administartion API概述
下面是可能使用Device Administration API的应用类型:
--邮件客户端
--远程清除数据的安全软件
--管理服务或应用的管理软件
2、工作原理?
使用设备管理API来写安装在用户手机上的设备管理应用。设备管理应用强制执行这些策略。下面是工作原理:
--系统管理员通过设备管理应用可以实施远程的安全策略。这些策略可以硬编码到该应用,也可以动态地从第三方服务器拉取。
--应用安装在用户的设备上。安卓目前没有自动条款的解决方案。系统管理员可以通过下面的方式向用户分发应用。
----Google Play
----第三方应用商店
----通过其它途径,例如邮件或者网站
--系统提示用户激活应用。如何、何时询问看应用如何实现。
--用户一旦激活该应用,将会受控于所激活的策略。遵从这些策略将会得到权限,例如访问敏感的系统数据。
在企业级的设置中,通常情况下,员工的设备必须严格依附于一系列使用手机的策略。下面列出了设备管理API所支持的策略。
需要注意的是设备管理的API目前只支持锁屏的密码。
如果用户没有激活应用,它仍然保留在设备上,但是处于未激活状态。用户不会遵从这些策略,也不会得到任何特权--例如,可能不能同步数据
如果用户没有遵从策略(例如,如果用户设置的密码违背了知道方针),如何处理由应用决定。然而,通常这将导致无法同步数据。
如果设备尝试使用本设备不支持的设备管理API,连接将被拒绝。设备管理API目前不支持部分允许。换句话说,如果一个设备(例如老旧的设备)不能支持所声明的所有策略,那么所有的策略都不会支持。
如果设备上有多个设备管理应用,最严格的策略将会被执行。
如果要卸载一个设备管理应用,用户首先需要取消注册应用的管理员权限。
3、策略
在企业应用的设置中,用户的设备必须依附于一系列管理用户设备的策略。设备管理API支持下面列出的策略。
策略
描述
启用密码 设备弹出PIN或密码询问
密码的最小长度 设置密码的长度。例如,设置PIN或者密码最小长度为6
字母数字密码 密码为数字和字母的组合。可能包含符号
复杂密码 从Android3.0开始,可以设置复杂密码。至少含一个字母,一个数字和一个特殊字符
密码中最小的字母长度
从Android3.0开始,可以要求所有的设备管理员或某一个成员设置的密码中包含的字母的数量
密码中小写字母的数量
设置密码中需要有多少个小写字母
密码中最小的非字母数量
设置密码中需要包含多少个非字母字符
最小的数字数量 密码中需要有多少个数字
最小的特殊字符数量 密码中至少需要多少个特殊字符
最小的大写字母数量 密码中至少需要包含多少个大写字母
密码过期时间 设置密码过期时间,单位为毫秒
密码输入失败次数 设置密码错误的次数。通过该API管理员可以远程让设备恢复出厂设置,防止手机丢失或被盗时数据泄露
设置锁屏时间 当用户于手机不进行交互后多久进行锁屏,如果超过时间,用户需要重新输入PIN或者密码才能重新访问手机和数据
存储加密 设置特定的存储区域的数据加密
禁用照相机 设置禁用照相机
其它特性
除了上表列出的特性,通过设备管理API还可以做以下的事情:
--提示用户设置一个新的密码
--立即锁屏
--清除手机数据(即恢复出厂设置)
示例
本文中的示例取自Device Admimistration API Sample,可以通过SDK Manager进行下载,下载后的位置在
<sdk_root>/ApiDemos/app/src/main/java/com/example/android/apis/app/DeviceAdminSample.java
该例子演示了设备管理的特性。为用户提供了一个接口让用户可以激活设备管理app。
一旦应用被激活,可以进行以下操作:
--设置密码质量
--设定密码需求,例如最小长度,需要包含的最小数字或字母数量等等
--设置密码。如果密码与所设置的策略部符,系统返回错误
--设置密码输入失败次数
--设置密码过期时间
--设置历史密码长度(存储使用过的密码的长度)。禁止用户重用最近n次内使用过的密码
--设置存储加密
--设置最大的停止交互时间
--立即锁屏
--清除数据
--禁用摄像机
应用截图
二、开发一个设备管理应用
系统管理员可以使用设备管理API来写应用,强制远程/本地的设备安全策略强制指向。以下是创建步骤
1、创建MainFest
使用设备管理API,应用的mainfest必须包含下面的设置:
--一个DeviceAdminReceiver的子类并包含下面选项
----权限BIND_DEVICE_ADMIN
----mainfest中配置intent的filter来响应intent ACTION_DEVICE_ADMIN_ENABLED
--在metadata中声明安全策略
以下摘录自示例
<activity android:name=".app.DeviceAdminSample"
android:label="@string/activity_sample_device_admin">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver"
android:label="@string/sample_device_admin"
android:description="@string/sample_device_admin_description"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
需要注意的是:
--以下引自字符的标签位于 ApiDemos/res/values/strings.xml.更多信息请查看Application Resources
----android:label="@string/activity_sample_device_admin",用户看到的activity的标签
----android:label="@string/sample_device_admin",用户看到的权限
----android:description="@string/sample_device_admin_description",用户看到的权限描述。描述往往比标签的信息更多
--android:permission="android.permission.BIND_DEVICE_ADMIN",为了保证只有系统可以与该广播接收者进行交互(没有任何应用可以被授予该权限),DeviceAdminReceiver的子类必须包含该权限。可以防止其它应用滥用你的设备管理应用。
--android.app.action.DEVICE_ADMIN_ENABLED是DeviceAdminReceiver的子类必须处理的action,用来管理手机。当用户激活该应用时触发。你的代码中通常在onEnabled()方法中进行处理。除此之外,还必须与权限BIND_DEVICE_ADIN一起使用来防止其它应用来滥用它。
--当用户激活了该应用,就授予了广播接收者对系统响应的事件进行响应的权限。当响应的事件出现,应用可以使用相应的策略。例如,用户设置了一个与策略不符的密码,应用可以提示用户输入另一个符合策略的密码。
--应用发布后避免修改广播接收者的名字。如果名字被改变,当应用升级后,设备管理将失效。
--android:resource="@xml/device_admin_sample"声明了在metadata中声明的安全策略。metadata提供了设备管理的额外信息,由类DeviceAdminInfo进行解析。以下是device_admin_sample.xml的内容
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
</uses-policies>
</device-admin>
你的应用中只需要添加所需要的策略就可以,不需要把所有的策略都添加上。
2、实现代码
设备管理API包含以下的类
DeviceAdminReceiver
实现一个设备的管理组件的基类。该类可以方便地与系统发送的动作进行交互。应用中必须包含一个DeviceAdminReceiver的子类。
DevicePolicyManager
一个管理在设备上强制执行的策略的类。大多数客户端必须发布用户现在允许的DeviceAdminReceier。DevicePolicyManager用于管理一个或者多个DeviceAdminReceiver实例。
DeviceAdminInfo
用于声明设备管理组件的metadata。
这些类为设备管理应用提供了完整的功能性基础。以下是如何通过DeviceAdminReceiver和DevicePolicyManager的API来写设备管理应用。
子类DeviceAdminReceiver
设备管理应用必须包含DeviceAdminReceiver的子类。DeviceAdminReceiver包含了一系列特殊事件触发时的回掉。
以下在当相应事件被触发时在回调中弹出一个吐司
public class DeviceAdminSample extends DeviceAdminReceiver {
void showToast(Context context, String msg) {
String status = context.getString(R.string.admin_receiver_status, msg);
Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
}
@Override
public void onEnabled(Context context, Intent intent) {
showToast(context, context.getString(R.string.admin_receiver_status_enabled));
}
@Override
public CharSequence onDisableRequested(Context context, Intent intent) {
return context.getString(R.string.admin_receiver_status_disable_warning);
}
@Override
public void onDisabled(Context context, Intent intent) {
showToast(context, context.getString(R.string.admin_receiver_status_disabled));
}
@Override
public void onPasswordChanged(Context context, Intent intent) {
showToast(context, context.getString(R.string.admin_receiver_status_pw_changed));
}
...
}
激活应用
用户必须显式激活该应用,这样策略才可以被强制执行。如果用户不激活设备上的应用,该应用虽然在设备上,但是却不能获得任何额外的方便。
当触发动作ACTION_ADD_DEVICE_ADMIN的意图时,激活应用的界面被触发。当用户点击“激活应用”时被激活。
下图是激活应用的界面:
下面是用户点击“激活应用”后执行的代码。onPrferenceChange()是一个回调函数,当Preference的值被改变时触发该回调。
如果用户激活该应用,会弹出如上图所示的界面,否则禁用设备管理应用。
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (super.onPreferenceChange(preference, newValue)) {
return true;
}
boolean value = (Boolean) newValue;
if (preference == mEnableCheckbox) {
if (value != mAdminActive) {
if (value) {
// Launch the activity to have the user enable our admin.
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
mActivity.getString(R.string.add_admin_extra_app_text));
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
// return false - don't update checkbox until we're really active
return false;
} else {
mDPM.removeActiveAdmin(mDeviceAdminSample);
enableDeviceCapabilitiesArea(false);
mAdminActive = false;
}
}
} else if (preference == mDisableCameraCheckbox) {
mDPM.setCameraDisabled(mDeviceAdminSample, value);
...
}
return true;
}
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);表明了mDeviceAdminSample(一个DeviceAdminReceiver的组件)是一个目标策略。包含了用户与上图所示的提示进行交互的步骤,允许或拒绝。
当应用需要执行与激活应用相关的操作时,需要检测应用被激活,使用的是DevicePolicyManager中的方法isAdminActive();需要注意的是该方法需要将DeviceAdminReceiver作为参数。
DevicePolicyManager mDPM;
...
private boolean isActiveAdmin() {
return mDPM.isAdminActive(mDeviceAdminSample);
}
管理策略
DevicePolicyManager用户管理强制执行的策略,可以管理一个或多个DeviceAdminReceiver的实例
获取方式如下:
evicePolicyManager mDPM =
(DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
设置密码策略
只对锁屏的密码有效。
显示设置密码的界面:
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent);
密码指令可以为下面任何一个:
PASSWORD_QUALITY_ALPHABETIC:密码必须包含最少一个字母或特殊字符
PASSWORD_QUALITY_ALPHANUMERIC:密码必须包含最少一个数字和一个字母(或特殊字符)
PASSWORD_QUALITY_NUMERIC:密码必须包含一个数字
PASSWORD_QUALITY_COMPLEX:密码必须包含一个字母、一个数字和一个特殊字符
PASSWORD_SOMETHING:需要一个密码但不在乎密码里有什么内容
PASSWORD_QUALITY_UNSPECIFIED:对密码没有要求
以下是设置密码策略的代码:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
mDPM.setPasswordQuality(mDeviceAdminSample, DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
设置密码内容:
从Android 3.0开始,DevicePolicyManager包含了可以调整密码内容的方法。例如,你可以设置一个策略声明密码必须包含至少n个字母。以下是调整内容的方法
setPasswordMinimumLetters()
setPasswordMinimumLowerCase()
setPasswordMinimumUpperCase()
setPasswordMinimumNonLetter()
setPasswordMinimumNumeric()
setPasswordMinimumSymbols()
下面是设置密码必须包含两个大写字母的方法代码片段:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
int pwMinUppercase = 2;
...
mDPM.setPasswordMinimumUpperCase(mDeviceAdminSample, pwMinUppercase);
设置密码最小长度为pwLenght:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
int pwLength;
...
mDPM.setPasswordMinimumLength(mDeviceAdminSample, pwLength);
设置最大的密码输入错误次数为maxFailedPw:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
int maxFailedPw;
...
mDPM.setMaximumFailedPasswordsForWipe(mDeviceAdminSample, maxFailedPw);
设置密码过期时间pwExpiration,单位为毫秒
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
long pwExpiration;
...
mDPM.setPasswordExpirationTimeout(mDeviceAdminSample, pwExpiration);
禁止重用旧密码:
Android 3.0开始,可以通过方法setPasswordHistoryLength()来限制用户使用旧密码。该方法需要传入需要保存的密码个数作为参数。当该策略被激活,用户可以输入一个符合最近n个密码的新密码。这个策略可以防止用户重复地使用同一个密码。通常这个策略与方法setPsswordExpirationTimeout()联合使用,当特定时间过去后强制用户更新密码。
禁止重用最近5次的任何密码:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
int pwHistoryLength = 5;
...
mDPM.setPasswordHistoryLength(mDeviceAdminSample, pwHistoryLength);
设置锁屏时间:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
long timeMs = 1000L*Long.parseLong(mTimeout.getText().toString());
mDPM.setMaximumTimeToLock(mDeviceAdminSample, timeMs);
立即锁屏:
DevicePolicyManager mDPM;
mDPM.lockNow();
清除数据:
通过DevicePolicyManager的方法wipeData()恢复手机出厂设置。当手机丢失或被盗后很有用。通常清除手机数据是为了满足特定的需求。例如,seetMaximumFailedPasswordsForWipe()来声明当密码重试多少次后清空数据。
清除数据的代码:
DevicePolicyManager mDPM;
mDPM.wipeData(0);
wipeData()的参数为附加选项的位掩码,目前必须是0.
禁用摄像机:
从Andorid 4.0开始,可以禁用摄像机。需要注意的是这不是一个永久性的禁用。相机可以根据context、时间等等进行启用/禁用。
private CheckBoxPreference mDisableCameraCheckbox;
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
mDPM.setCameraDisabled(mDeviceAdminSample, mDisableCameraCheckbox.isChecked());
存储加密:
从Android 3.0开始,你可以使用setStorageEncryption()方法来设置加密存储区域的策略。
例如:
DevicePolicyManager mDPM;
ComponentName mDeviceAdminSample;
...
mDPM.setStorageEncryption(mDeviceAdminSample, true);
通过设备管理API 的例子查看完整的代码。
更多的代码示例:
Android AppRestrictionsEnforcer和 Android DeviceOwner 提供了更多关于设备管理API的代码