Android DevicePolicyManager 使用
Android DevicePolicyManager 使用
DevicePolicyManager是个公司做的EMM很大一部分就是围绕这个类展开的。记得有个很强大的病毒就是利用了DevicePolicyManager 与激活设备绑定之后,用户无法卸载该用户,成千上万的设备被感染,个人信息被获取,清除数据等等邪恶的操作。
凡事都有正反两面,关键是看怎么使用了。接下来要记录一下关于这个非常厉害类的使用方法,设备管理器的激活,防止用户卸载,以及扩展使用。
个人觉得英文不好,略识几个单词,但是喜欢看官方文档。大家不妨先看一下官方API的描述,接下来我会详细介绍:http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html
首先需要配置一下 使用设备管理器的哪些功能
<?xml version="1.0" encoding="utf-8"?>
<device-admin
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<!-- 限制密码规则的限制 -->
<watch-login />
<!-- 监听登录 -->
<reset-password />
<!-- 重置密码 -->
<force-lock />
<!-- 强制锁屏 -->
<wipe-data />
<!-- 恢复出厂设置 清除数据 -->
</uses-policies>
</device-admin>
配置一下关于设备管理员的监听receiver
<receiver
android:name="com.xxx.emm.receiver.DeviceAdminSampleReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
这个工具的使用当然需要用户的同意,也就是激活。 看一下激活组件:
private ComponentName emmmDeviceAdmin emmmDeviceAdmin = new ComponentName(this,DeviceAdminSampleReceiver.class);
private DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
/**
* Helper to determine if we are an active admin
*/
private boolean isActiveAdmin() {
return devicePolicyManager.isAdminActive(emmmDeviceAdmin);
}
/**
* 启动系统激活设备管理器页面
*/
protected void launchDeviceAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, emmmDeviceAdmin);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, getString(R.string.add_admin_extra_app_text)); /// 这句话告诉用户激活这个组件的作用以及其他内容
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
}
接下来看一下监听类的实现,以及各个方法的作用:
/**
*
* Receiver The callback methods, like the base
* BroadcastReceiver.onReceive() method, happen on the main thread of the
* process. Thus long running operations must be done on another thread. Note
* that because a receiver is done once returning from its receive function,
* such long-running operations should probably be done in a Service.
*/
public class DeviceAdminSampleReceiver extends DeviceAdminReceiver {
private static final String TAG = "DeviceAdminSampleReceiver";
public static int ERR_TIME = 0;
public static int ERR_TIME_TOTAL = 0;
void showToast(Context context, String msg) {
String status = context.getString(R.string.admin_receiver_status, msg);
Toast.makeText(context, status, Toast.LENGTH_LONG).show();
}
@Override
public void onEnabled(Context context, Intent intent) {
// showToast(context,
// context.getString(R.string.admin_receiver_status_enabled));
showToast(context, "当前应用已与设备管理器绑定!");
}
@Override
public synchronized 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));
}
@Override
public void onPasswordFailed(Context context, Intent intent) {
ERR_TIME_TOTAL += 1;
if (ERR_TIME_TOTAL >= ERR_TIME) {
showToast(context, "密码输入错误" + ERR_TIME_TOTAL + "次,清除系统资料!");
System.out.println("密码错误已达:" + ERR_TIME_TOTAL);
} else {
showToast(context, "密码输入错误" + ERR_TIME_TOTAL + "次,连续错误" + ERR_TIME
+ "次将清除系统资料!");
}
// showToast(context,
// context.getString(R.string.admin_receiver_status_pw_failed));
}
@Override
public void onPasswordSucceeded(Context context, Intent intent) {
// showToast(context,
// context.getString(R.string.admin_receiver_status_pw_succeeded));
showToast(context, "密码输入成功!");
ERR_TIME_TOTAL = 0;
}
@Override
public void onPasswordExpiring(Context context, Intent intent) {
DevicePolicyManager dpm = (DevicePolicyManager) context
.getSystemService(Context.DEVICE_POLICY_SERVICE);
long expr = dpm.getPasswordExpiration(new ComponentName(context,
DeviceAdminSampleReceiver.class));
long delta = expr - System.currentTimeMillis();
boolean expired = delta < 0L;
String message = context
.getString(expired ? R.string.expiration_status_past: R.string.expiration_status_future);
showToast(context, message);
Log.v(TAG, message);
}
// 设置用户密码的使用规则
public void password_quality_setting(View v) {
// PASSWORD_QUALITY_ALPHABETIC
// 用户输入的密码必须要有字母(或者其他字符)。
// PASSWORD_QUALITY_ALPHANUMERIC
// 用户输入的密码必须要有字母和数字。
// PASSWORD_QUALITY_NUMERIC
// 用户输入的密码必须要有数字
// PASSWORD_QUALITY_SOMETHING
// 由设计人员决定的。
// PASSWORD_QUALITY_UNSPECIFIED
// 对密码没有要求。
Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
devicePolicyManager.setPasswordQuality(componentName, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); //// 数字型密码。
startActivity(intent);
}
}
接下来通过设备管理员可以实现一些关于相机,锁屏,清除数据,恢复出厂设置,等等功能的实现:
/**
* 锁设备
*
* @param pwd 密码
*
*/
public void lockDevice(String pwd) {
L.d(this.getClass(), "password : " + pwd);
if (pwd.equals("")) { // 無密碼直接關螢幕
mDPM.lockNow();
} else {
mDPM.setPasswordQuality(mDeviceAdminSample,
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); // 修改密碼前需先將密碼複雜程度設為"Unspecified"後,再將密碼設為""包住之空字串,才能設定成功。
mDPM.resetPassword(pwd,
DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);
mDPM.lockNow();
}
}
/**
* 清除设备数据.
*/
public void removeWipe() {
L.i(this.getClass(), "wraning remove wipe ");
mDPM.wipeData(0); // Wipe internal data, like a factory reset.
mDPM.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);
}
/**
* 移除设备密码. 设备解锁.
*/
public void unLockDevice() {
mDPM.setPasswordMinimumLength(mDeviceAdminSample, 0);
mDPM.setPasswordQuality(mDeviceAdminSample,
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); // 移除密碼前需先將密碼複雜程度設為"Unspecified"後,再將密碼設為""包住之空字串,才能設定成功。
mDPM.resetPassword("", DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY); // 移除密碼
}
/**
* 相机可用
*/
public void enableCamera() {
mDPM.setCameraDisabled(mDeviceAdminSample, false);
L.i(this.getClass(), "camera is enabled ...");
}
/**
* 设置5秒后锁屏
*/
public void btnlocktime(View v) {
mDPM.setMaximumTimeToLock(componentName, 5000);
}
总结:
DevicePolicyManager 的功能很多,如果实际开发中用到的就可以在配置文件中配置,不用则无需配置,激活选项过多容易引起用户的反感。在原生系统中测试,该组件被激活后,用户无法卸载,除非取消激活设备管理器,与此同时这就给了黑客了一些灵感, 可以在取消激活的方法中写一些代码,导致用户无法取消激活,也就会导致用户卸载不掉该应用。但是在某一些系统中激活后可以卸载,比如说MIUI