DevicePolicyManagerService之DeviceOwner和ProfileOwner
目录
1.ProfileOwner
2.DeviceOwner
3.DO或PO授权后获取设备信息:
3.1.获取设备IMEI(Android10及以上版本)
3.2.获取IMSI,ICCID及电话号码
1.ProfileOwner
ProfileOwner是Android5.0系统推出.ProfileOwner包含了所有DeviceAdmin用户的管理能力.系统只能设置一个Profile Owner程序,并且设置为ProfileOwner后应用无法卸载.
设置ProfileOwner
具有MANAGE_PROFILE_AND_DEVICE_OWNERS权限和shell uid的应用程序才能调用此方法
public boolean setProfileOwner(ComponentName, String, int) {}
应用反射调用:
public void setProfileOwner(){
try {
MethodsetDeviceOwner =mDevicePolicyManager.getClass().getDeclaredMethod("setActiveProfileOwner", ComponentName.class,String.class);
setDeviceOwner.setAccessible(true);
setDeviceOwner.invoke(mDevicePolicyManager,admin,"ansen");
} catch (IllegalAccessExceptione) {
e.printStackTrace();
} catch (InvocationTargetExceptione) {
e.printStackTrace();
} catch (NoSuchMethodExceptione) {
e.printStackTrace();
}
}
// APP需要系统签名和如下权限
<uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
DPMS接口:
public boolean setProfileOwner(ComponentNamewho, StringownerName, intuserHandle) {
if (!mHasFeature) {
return false;
}
if (who == null
|| !isPackageInstalledForUser(who.getPackageName(),userHandle)) {
throw new IllegalArgumentException("Component " +who
+ " not installed for userId:" +userHandle);
}
final booleanhasIncompatibleAccountsOrNonAdb =
hasIncompatibleAccountsOrNonAdbNoLock(userHandle,who);
synchronized (getLockObject()) {
enforceCanSetProfileOwnerLocked(who,userHandle,hasIncompatibleAccountsOrNonAdb);
final ActiveAdminadmin = getActiveAdminUncheckedLocked(who,userHandle);
if (admin == null || getUserData(userHandle).mRemovingAdmins.contains(who)) {
throw new IllegalArgumentException("Not active admin: " +who);
}
if (isAdb()) {
// Log profile owner provisioning was started using adb.
MetricsLogger.action(mContext,PROVISIONING_ENTRY_POINT_ADB,LOG_TAG_PROFILE_OWNER);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PROVISIONING_ENTRY_POINT_ADB)
.setAdmin(who)
.setStrings(LOG_TAG_PROFILE_OWNER)
.write();
}
// Shutting down backup manager service permanently.
toggleBackupServiceActive(userHandle, /* makeActive= */ false);
mOwners.setProfileOwner(who,ownerName,userHandle);
mOwners.writeProfileOwner(userHandle);
Slog.i(LOG_TAG, "Profile owner set: " +who + " on user " +userHandle);
final longid =mInjector.binderClearCallingIdentity();
try {
if (mUserManager.isManagedProfile(userHandle)) {
maybeSetDefaultRestrictionsForAdminLocked(userHandle,admin,
UserRestrictionsUtils.getDefaultEnabledForManagedProfiles());
ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle,admin,
true /* newOwner */);
}
sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED,
userHandle);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
mDeviceAdminServiceController.startServiceForOwner(
who.getPackageName(),userHandle, "set-profile-owner");
return true;
}
}
ProfileOwner支持的管控能力:
是否为ProfileOwner
mDevicePolicyManager.isProfileOwnerApp(mComponentName.getPackageName());
隐藏应用
可停用制定应用并且不再界面显示,除非调用相应API恢复可用,否则该应用永远无法运行.可以用来开发应用黑白名单功能
mDevicePolicyManager.setApplicationHidden(admin, "packageName", true);
// 应用是否隐藏
mDevicePolicyManager.isApplicationHidden(admin, "packageName");
禁止卸载应用
被设置为禁止卸载的应用将成为受保护应用,无法被用户卸载,除非取消保护
mDevicePolicyManager.setUninstallBlocked(admin, "packageName", true);
mDevicePolicyManager.isUninstallBlocked(admin, "packageName");
DPMS实现
public void setUninstallBlocked(ComponentNamewho, StringcallerPackage, StringpackageName,
booleanuninstallBlocked) {
final intuserId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
// Ensure the caller is a DO/PO or a block uninstall delegate
enforceCanManageScope(who,callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
DELEGATION_BLOCK_UNINSTALL); // 调用者权限检查
longid =mInjector.binderClearCallingIdentity(); //清空远程调用端的uid和pid,用当前本地进程的uid和pid替代
try {
mIPackageManager.setBlockUninstallForUser(packageName,uninstallBlocked,userId); // 通过binder调用PMS来设置
} catch (RemoteExceptionre) {
// Shouldn't happen.
Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser",re);
} finally {
mInjector.binderRestoreCallingIdentity(id);// 恢复远程调用端的uid和pid信息
}
}
final booleanisDelegate = (who == null);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_UNINSTALL_BLOCKED)
.setAdmin(callerPackage)
.setBoolean(isDelegate)
.setStrings(packageName)
.write();
}
首先对调用者权限检查,只有device owner,profile owner或指定DELEGATION_BLOCK_UNINSTALL作用域的委托调用,然后使用SystemServer的权限来调用PMS的setBlockUninstallForUser()方法来设置调用者用户的应用是否可卸载.
修改系统设置
mDevicePolicyManager.setSecureSetting(admin, "setting", "value");
public void setSecureSetting(ComponentNamewho, Stringsetting, Stringvalue) {
Preconditions.checkNotNull(who, "ComponentName is null");
intcallingUserId =mInjector.userHandleGetCallingUserId();
// ... ...
// 对调用者的权限判断
longid =mInjector.binderClearCallingIdentity(); //清空远程调用端的uid和pid,用当前本地进程的uid和pid替代
try {
if (Settings.Secure.DEFAULT_INPUT_METHOD.equals(setting)) {
final StringcurrentValue =mInjector.settingsSecureGetStringForUser(
Settings.Secure.DEFAULT_INPUT_METHOD,callingUserId);
if (!TextUtils.equals(currentValue,value)) {
// Tell the content observer that the next change will be due to the owner
// changing the value. There is a small race condition here that we cannot
// avoid: Change notifications are sent asynchronously, so it is possible
// that there are prior notifications queued up before the one we are about
// to trigger. This is a corner case that will have no impact in practice.
mSetupContentObserver.addPendingChangeByOwnerLocked(callingUserId);
}
getUserData(callingUserId).mCurrentInputMethodSet = true;
saveSettingsLocked(callingUserId);
}
mInjector.settingsSecurePutStringForUser(setting,value,callingUserId); //调用Settings.Secure.putStringForUser()执行逻辑
} finally {
mInjector.binderRestoreCallingIdentity(id); // 恢复远程调用端的uid和pid信息
}
// ... ...
}
首先也是对调用者的权限进行一系列判断,随后以SystemServer的权限来调用Settings.Secure.putStringForUser()方法传入需要设置的值和调用user.
设置静音
mDevicePolicyManager.setMasterVolumeMuted(admin, true);
mDevicePolicyManager.isMasterVolumeMuted(admin); //是否静音
public void setMasterVolumeMuted(ComponentNamewho, booleanon) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
setUserRestriction(who, UserManager.DISALLOW_UNMUTE_DEVICE,on);
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_MASTER_VOLUME_MUTED)
.setAdmin(who)
.setBoolean(on)
.write();
}
}
首先也是权限判断,随后调用 用户限制管理的方法setUserRestriction传入SET_MASTER_VOLUME_MUTED设置静音的指令完成.
用户限制管理
mDevicePolicyManager.addUserRestriction(admin,key); // 添加用户限制
mDevicePolicyManager.clearUserRestriction(admin,key); // 清除用户限制
mDevicePolicyManager.getUserRestrictions(admin); // 获取用户限制
DPM中的addUserRestriction会调用到DPMS的setUserRestriction方法,具体如下
public void setUserRestriction(ComponentNamewho, Stringkey, booleanenabledFromThisOwner) {
Preconditions.checkNotNull(who, "ComponentName is null");
if (!UserRestrictionsUtils.isValidRestriction(key)) {
return;
}
final intuserHandle =mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
final ActiveAdminactiveAdmin =
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); // 调用者权限检查
final booleanisDeviceOwner = isDeviceOwner(who,userHandle);
if (isDeviceOwner) {
if (!UserRestrictionsUtils.canDeviceOwnerChange(key)) { //判断当前用户是否限制了DeviceOwner设置
throw new SecurityException("Device owner cannot set user restriction " +key);
}
} else { // profile owner
if (!UserRestrictionsUtils.canProfileOwnerChange(key,userHandle)) { //判断当前用户是否限制了ProfileOwner设置
throw new SecurityException("Profile owner cannot set user restriction " +key);
}
}
// 把当前的限制策略保存到activeAdmin的一个bundle对象中
final Bundlerestrictions =activeAdmin.ensureUserRestrictions();
if (enabledFromThisOwner) {
restrictions.putBoolean(key, true);
} else {
restrictions.remove(key);
}
saveUserRestrictionsLocked(userHandle); //保存并应用该限制
}
final inteventId =enabledFromThisOwner
? DevicePolicyEnums.ADD_USER_RESTRICTION
: DevicePolicyEnums.REMOVE_USER_RESTRICTION;
DevicePolicyEventLogger
.createEvent(eventId)
.setAdmin(who)
.setStrings(key)
.write();
if (SecurityLog.isLoggingEnabled()) {
final inteventTag =enabledFromThisOwner
? SecurityLog.TAG_USER_RESTRICTION_ADDED
: SecurityLog.TAG_USER_RESTRICTION_REMOVED;
SecurityLog.writeEvent(eventTag,who.getPackageName(),userHandle,key);
}
}
private void saveUserRestrictionsLocked(intuserId) {
saveSettingsLocked(userId); // 获取当前最新的DevicePolicyData,然后保存到xml文件中
pushUserRestrictions(userId); // 调用UserManagerService,传入之前保存在Bundle中的限制策略key
sendChangedNotification(userId); // 发送策略状态改变的广播
}
在setUserRestriction方法中对调用者权限检查,然后判断当前user是否有不能修改的限制,接着把当前的限制策略key保存到activeAdmin的一个bundle对象中.
最后
设置用户图标
mDevicePolicyManager.setUserIcon(admin,icon);
修改权限申请的策略
mDevicePolicyManager.setPermissionPolicy(admin, DevicePolicyManager.PERMISSION_POLICY_PROMPT);
// 修改指定权限的策略
mDevicePolicyManager.setPermissionGrantState(admin, "packageName", "permission", DevicePolicyManager.PERMISSION_POLICY_PROMPT);
有如下三种策略,这些策略都不影响已经允许过拒绝的权限
PERMISSION_POLICY_PROMPT
每次都提醒是否允许
PERMISSION_POLICY_AUTO_GRANT
自动允许
PERMISSION_POLICY_AUTO_DENY
自动拒绝
设置应用限制
mDevicePolicyManager.setApplicationRestrictions(admin, "packageName", null);
mDevicePolicyManager.getApplicationRestrictions(admin,packageName); // 获取应用程序受限信息
主要是调用UserManager来实现应用限制.
public void setApplicationRestrictions(ComponentNamewho, StringcallerPackage,
StringpackageName, Bundlesettings) {
enforceCanManageScope(who,callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER,
DELEGATION_APP_RESTRICTIONS); // 调用者权限检查
final UserHandleuserHandle =mInjector.binderGetCallingUserHandle();
final longid =mInjector.binderClearCallingIdentity(); // 清空远程调用端的uid和pid
try {
mUserManager.setApplicationRestrictions(packageName,settings,userHandle); //调用UserManager方法实现
// ...
} finally {
mInjector.binderRestoreCallingIdentity(id);// 恢复远程调用端的uid和pid
}
}
启用或禁用备份服务
DeviceOwner调用此API来控制设备上所有用户的备份服务。ProfileOwner可以使用此API启用或禁用Profile的备份服务
mDevicePolicyManager.setBackupServiceEnabled(admin,enabled);
mDevicePolicyManager.isBackupServiceEnabled(admin); // 备份服务是否开启
这主要是调用IBackupManager的实现类Trampoline类创建当前用户的BackupManagerService
public void setBackupServiceEnabled(ComponentNameadmin, booleanenabled) {
if (!mHasFeature) {
return;
}
Preconditions.checkNotNull(admin); // 不为空检查
enforceProfileOrDeviceOwner(admin); // 检查调用者是否为ProfileOwner
intuserId =mInjector.userHandleGetCallingUserId();
toggleBackupServiceActive(userId,enabled); // 通过userid来控制当前用户备份服务启用和禁止
}
private void toggleBackupServiceActive(intuserId, booleanmakeActive) {
longident =mInjector.binderClearCallingIdentity();
try {
if (mInjector.getIBackupManager() != null) {
mInjector.getIBackupManager()
.setBackupServiceActive(userId,makeActive);// 如果makeActive为true,则创建一个BackupManagerService,创建用户的激活文件
}
} catch (RemoteExceptione) {
throw new IllegalStateException("Failed deactivating backup service.",e);
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
}
设置状态栏的禁用或启用
mDevicePolicyManager.setStatusBarDisabled(admin,disabled);
public boolean setStatusBarDisabled(ComponentNamewho, booleandisabled) {
intuserId = UserHandle.getCallingUserId();
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); //检查调用者权限
if (!isUserAffiliatedWithDeviceLocked(userId)) {
throw new SecurityException("Admin " +who +
" is neither the device owner or affiliated user's profile owner.");
}
if (isManagedProfile(userId)) {
throw new SecurityException("Managed profile cannot disable status bar");
}
DevicePolicyDatapolicy = getUserData(userId); // 获取当前用户的设备策略数据对象
if (policy.mStatusBarDisabled !=disabled) {
booleanisLockTaskMode = false;
try {
isLockTaskMode =mInjector.getIActivityTaskManager().getLockTaskModeState()
!=LOCK_TASK_MODE_NONE;
} catch (RemoteExceptione) {
Slog.e(LOG_TAG, "Failed to get LockTask mode");
}
if (!isLockTaskMode) {
if (!setStatusBarDisabledInternal(disabled,userId)) {
return false;
}
}
policy.mStatusBarDisabled =disabled; // 禁用状态栏的值在policy中设置
saveSettingsLocked(userId); // 保存当前策略xml中,并发送更改策略的广播
}
}
// ...
return true;
}
设置输入法权限
默认情况下,用户可以使用任何输入法.当添加了零个或多个包时,用户无法启用不在列表中的输入法
mDevicePolicyManager.setPermittedInputMethods(admin, new ArrayList<String>(){});
mDevicePolicyManager.getPermittedInputMethods(admin); // 获取受信任的输入法包列表
设置是否禁止截图
mDevicePolicyManager.setScreenCaptureDisabled(admin, true);
mDevicePolicyManager.getScreenCaptureDisabled(admin); // 是否禁止截图
禁止蓝牙访问联系人
mDevicePolicyManager.setBluetoothContactSharingDisabled(admin, true);
mDevicePolicyManager.getBluetoothContactSharingDisabled(admin); // 获取蓝牙访问联系人状态
通过包名添加删除应用程序小部件
mDevicePolicyManager.addCrossProfileWidgetProvider(admin,packageName); // 添加小部件
mDevicePolicyManager.removeCrossProfileWidgetProvider(admin,packageName); // 删除小部件
mDevicePolicyManager.getCrossProfileWidgetProviders(admin); // 获取所有可用小部件
管理应用程序消息通知
默认允许所有应用的通知消息,当添加了零个或多个包时,不在列表中且不是当前用户上的应用通知将不接收
mDevicePolicyManager.setPermittedCrossProfileNotificationListeners(admin,packageList);
mDevicePolicyManager.getPermittedCrossProfileNotificationListeners(admin); // 获取可显示消息通知的包列表
运行时权限控制
mDevicePolicyManager.getPermissionGrantState(admin,packageName,permission); // 获取应用程序的运行时权限状态
mDevicePolicyManager.setPermissionPolicy(admin,policy); // 允许应用程序自动授予或拒绝运行时权限请求
mDevicePolicyManager.getPermissionPolicy(admin); // 返回设备或配置文件所有者设置的当前运行时权限策略
设置特定的服务组件作为内容提供者
用于向用户的本地或远程管理员发出权限请求
mDevicePolicyManager.setRestrictionsProvider(admin,provider);
禁用特定类型的帐户
mDevicePolicyManager.setAccountManagementDisabled(admin, "accountType", true);
mDevicePolicyManager.getAccountTypesWithManagementDisabled();// 获取禁用的账户列表
重新启用用户初始化时默认禁用的系统应用程序
mDevicePolicyManager.enableSystemApp(admin,packageName);
设置辅助权限
默认情况下,用户可以使用任何可访问性服务.当添加了零个或多个包时,用户无法启用列表中非系统部分的可访问性服务
mDevicePolicyManager.setPermittedAccessibilityServices(admin, new ArrayList<String>(){});
mDevicePolicyManager.getPermittedAccessibilityServices(admin);
设置组织名
mDevicePolicyManager.setOrganizationName(admin,title); //设置组织名
mDevicePolicyManager.getOrganizationName(admin);// 获取组织名
禁止或者开启搜索联系人功能
mDevicePolicyManager.setCrossProfileContactsSearchDisabled(admin,disabled);
mDevicePolicyManager.getCrossProfileContactsSearchDisabled(admin); // 获取搜索联系人状态
禁止或者开启来电显示功能
mDevicePolicyManager.setCrossProfileCallerIdDisabled(admin,disabled);
mDevicePolicyManager.getCrossProfileCallerIdDisabled(admin); // 获取禁止来电显示状态
设置应用程序挂起
挂起的程序将无法启动任何活动
mDevicePolicyManager.setPackagesSuspended(admin,packageNames,suspended);
mDevicePolicyManager.isPackageSuspended(admin,packageName); // 是否为挂起应用
指定特定应用程序始终打开的VPN连接
此连接在重新启动后自动授予并持久化
mDevicePolicyManager.setAlwaysOnVpnPackage(admin,vpnPackage,lockdownEnabled);
获取打开VPN连接的应用
mDevicePolicyManager.getAlwaysOnVpnPackage(admin);
授予对另一个应用程序的特权API的访问权
mDevicePolicyManager.setDelegatedScopes(admin,delegatePackage,scopes);
mDevicePolicyManager.getDelegatedScopes(admin,delegatedPackage); // 获取特权应用的所有权限
安装证书和相应的私钥
mDevicePolicyManager.installKeyPair(admin,privKey,cert,alias);
mDevicePolicyManager.removeKeyPair(admin,alias); // 删除密匙
CA证书管理
mDevicePolicyManager.uninstallAllUserCaCerts(admin); // 卸载所有自定义的可信CA证书,除系统CA证书外,通过设备策略以外的方式安装的证书也将被删除
mDevicePolicyManager.uninstallCaCert(admin,certBuffer); // 从可信用户CAs卸载给定的证书
mDevicePolicyManager.installCaCert(admin,certBuffer); // 将给定证书安装为用户可信CA
mDevicePolicyManager.hasCaCertInstalled(admin,certBuffer); // 此证书是否安装为可信CA
mDevicePolicyManager.getInstalledCaCerts(admin); // 返回当前受信任的所有CA证书,不包括系统CA证书.如果用户通过除设备策略之外的其他方式安装了任何证书,这些证书也将包括在内
锁屏管理
mDevicePolicyManager.setRequiredStrongAuthTimeout(admin,timeoutMs); // 超时后用户必须使用身份验证才能进入系统,比如指纹、密码等
mDevicePolicyManager.setResetPasswordToken(admin,token); // 重置设备锁屏密码
mDevicePolicyManager.clearResetPasswordToken(admin); // 清除重置设备密码Token
mDevicePolicyManager.resetPasswordWithToken(admin,password,token,flags); // 重置设备锁屏密码,在Token激活的状态下有效
2.DeviceOwner
Android 5.0 引入了部署DeviceOwner应用的功能.DeviceOwner(设备所有者)是一种专业化类型的设备管理员.DeviceOwner包含了ProfileOwner的所有管理能力,并且在这些基础上额外添加了一些管理权限,如重启设备、禁用状态栏、创建和移除二级用户以及配置全局设置的能力等.一台设备在同一时间只能有一名活动的DeviceOwner.并且系统同时只能有一个DeviceOwner应用或者ProfileOwner应用
2.1.设置DeviceOwner
adb shell dpm set-device-owner --name Test com.example.myapplication/.AdminReciver
adb shell dpm remove-active-admin com.example.myapplication/.AdminReciver
可以通过如上adb命令设置DeviceOwner,同时也可以使用如下接口设置,该接口为hide api,需要系统应用才可调用.
APP反射调用:
public void setDeviceOwner(){
try {
MethodsetDeviceOwner =mDevicePolicyManager.getClass().getDeclaredMethod("setDeviceOwner", ComponentName.class);
setDeviceOwner.setAccessible(true);
setDeviceOwner.invoke(mDevicePolicyManager,admin);
} catch (IllegalAccessExceptione) {
e.printStackTrace();
} catch (InvocationTargetExceptione) {
e.printStackTrace();
} catch (NoSuchMethodExceptione) {
e.printStackTrace();
}
}
// APP需要系统签名和如下权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
应用层接口:
mDevicePolicyManager.setDeviceOwner(ComponentNamewho, StringownerName, intuserId); // 设置DeviceOwner
mDevicePolicyManager.isDeviceOwnerApp(mComponentName.getPackageName()); // 是否为DeviceOwner
2.2.DeviceOwner的主要能力:
用户管理
mDevicePolicyManager.createAndManageUser(admin,name,profileOwner,adminExtras,flags); // 创建用户
mDevicePolicyManager.switchUser(admin,userHandle); // 切换用户
mDevicePolicyManager.removeUser(admin,userHandle); // 删除用户
由DeviceOwner调用,创建指定名称的用户并将传入的组件包作为profile owner.
这个方法主要做了两件事,首先是创建用户,然后设置ProfileOwner,设置ProfileOwner前提是需要先设置device admin.
public UserHandle createAndManageUser(ComponentNameadmin, Stringname,
ComponentNameprofileOwner, PersistableBundleadminExtras, intflags) {
//参数不为空判断
Preconditions.checkNotNull(admin, "admin is null");
Preconditions.checkNotNull(profileOwner, "profileOwner is null");
if (!admin.getPackageName().equals(profileOwner.getPackageName())) {
throw new IllegalArgumentException("profileOwner " +profileOwner + " and admin "
+admin + " are not in the same package");
}
// 只允许系统用户使用本方法
if (!mInjector.binderGetCallingUserHandle().isSystem()) {
throw new SecurityException("createAndManageUser was called from non-system user");
}
final booleanephemeral = (flags & DevicePolicyManager.MAKE_USER_EPHEMERAL) != 0;
final booleandemo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0
&& UserManager.isDeviceInDemoMode(mContext);
final booleanleaveAllSystemAppsEnabled = (flags &LEAVE_ALL_SYSTEM_APPS_ENABLED) != 0;
final inttargetSdkVersion;
// 创建用户
UserHandleuser = null;
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);// 权限检查,只允许DeviceOwner调用
final intcallingUid =mInjector.binderGetCallingUid();
final longid =mInjector.binderClearCallingIdentity(); //清除调用者的PID UID并保存到id变量中
try {
targetSdkVersion =mInjector.getPackageManagerInternal().getUidTargetSdkVersion(
callingUid);
// 对设备的存储大小和创建用户数限制进行检查
DeviceStorageMonitorInternaldeviceStorageMonitorInternal =
LocalServices.getService(DeviceStorageMonitorInternal.class);
if (deviceStorageMonitorInternal.isMemoryLow()) {
if (targetSdkVersion >= Build.VERSION_CODES.P) {
throw new ServiceSpecificException(
UserManager.USER_OPERATION_ERROR_LOW_STORAGE, "low device storage");
} else {
return null;
}
}
if (!mUserManager.canAddMoreUsers()) {
if (targetSdkVersion >= Build.VERSION_CODES.P) {
throw new ServiceSpecificException(
UserManager.USER_OPERATION_ERROR_MAX_USERS, "user limit reached");
} else {
return null;
}
}
intuserInfoFlags = 0;
if (ephemeral) {
userInfoFlags |= UserInfo.FLAG_EPHEMERAL;
}
if (demo) {
userInfoFlags |= UserInfo.FLAG_DEMO;
}
String[]disallowedPackages = null;
if (!leaveAllSystemAppsEnabled) {
disallowedPackages =mOverlayPackagesProvider.getNonRequiredApps(admin,
UserHandle.myUserId(),ACTION_PROVISION_MANAGED_USER).toArray(
new String[0]);
}
//调用UserManagerService的方法创建用户,和调用UserManager.createuser()相同,
//但绕过了UserManager#DISALLOW_ADD_USER和UserManager#DISALLOW_ADD_MANAGED_PROFILE的检查
UserInfouserInfo =mUserManagerInternal.createUserEvenWhenDisallowed(name,
userInfoFlags,disallowedPackages);
if (userInfo != null) {
user =userInfo.getUserHandle();
}
} finally {
mInjector.binderRestoreCallingIdentity(id); //从id变量中恢复调用者的PID UID
}
}
// ...
final intuserHandle =user.getIdentifier();
// 发送用户创建的广播
final Intentintent = new Intent(DevicePolicyManager.ACTION_MANAGED_USER_CREATED)
.putExtra(Intent.EXTRA_USER_HANDLE,userHandle)
.putExtra(
DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED,
leaveAllSystemAppsEnabled)
.setPackage(getManagedProvisioningPackage(mContext))
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
final longid =mInjector.binderClearCallingIdentity();
try {
final StringadminPkg =admin.getPackageName();
try {
// Install the profile owner if not present.
if (!mIPackageManager.isPackageAvailable(adminPkg,userHandle)) {
mIPackageManager.installExistingPackageAsUser(adminPkg,userHandle,
PackageManager.INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,
PackageManager.INSTALL_REASON_POLICY, null);
}
} catch (RemoteExceptione) {
// Does not happen, same process
}
// 激活admin
setActiveAdmin(profileOwner, true,userHandle);
final StringownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
// 设置ProfileOwner
setProfileOwner(profileOwner,ownerName,userHandle);
synchronized (getLockObject()) {
DevicePolicyDatapolicyData = getUserData(userHandle);
policyData.mInitBundle =adminExtras;
policyData.mAdminBroadcastPending = true;
saveSettingsLocked(userHandle); // 保存该用户配置的策略到xml并发送状态改变广播
}
// 保存新建用户的userId(该id可用来移除和切换用户)
if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 1,userHandle);
}
returnuser;
} catch (Throwablere) {
mUserManager.removeUser(userHandle);
if (targetSdkVersion >= Build.VERSION_CODES.P) {
throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN,
re.getMessage());
} else {
return null;
}
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
}
重启设备
调用PowerManager的reboot方法来来重启设备,该方法只有DeviceOwner可以调用
mDevicePolicyManager.reboot(admin);
获取wifi Mac地址
调用WifiManager的getFactoryMacAddresses方法获取mac地址,该方法只有DeviceOwner可以调用
mDevicePolicyManager.getWifiMacAddress(admin);
将锁屏模式设置为None,当用户设置了密码时无效
mDevicePolicyManager.setKeyguardDisabled(admin,disabled);
系统更新策略
mDevicePolicyManager.setSystemUpdatePolicy(admin,policy); // 设置系统更新策略
mDevicePolicyManager.getSystemUpdatePolicy(); // 获取系统更新策略
设置系统设置中Global相关的属性
mDevicePolicyManager.setGlobalSetting(admin,setting,value);
锁屏管理
mDevicePolicyManager.setDeviceOwnerLockScreenInfo(admin,info); // 设置锁屏界面显示的提示消息
mDevicePolicyManager.getDeviceOwnerLockScreenInfo();// 获取锁屏界面显示消息
设置一个独立于网络的全局HTTP代理
mDevicePolicyManager.setRecommendedGlobalProxy(admin,proxyInfo);
固定屏幕的指定应用
需要device owner调用,然后调用Activity的startLockTask()方法
mDevicePolicyManager.setLockTaskPackages(mComponentName, new String[]{"packages"});
mDevicePolicyManager.getLockTaskPackages(admin); // 获取允许在锁定界面显示的包列表
mDevicePolicyManager.isLockTaskPermitted(packageName); // 查询一个应用是否能够在锁定界面显示
3.DO或PO授权后获取设备信息:
3.1.获取设备IMEI(Android10及以上版本)
(1).应用必须动态获取android.permission.READ_PHONE_STATE 权限
(2).应用必须具有DeviceOwner或者ProfileOwner权限。或者由具有这两个权限的应用通过setDelegatedScopes(ComponentName admin,String delegatePackage,List<String> scopes)方法进行授权。scopes需要包含DevicePolicyManager.DELEGATION_CERT_INSTALL
(3).调用TelephonyManager.getImei(int slotIndex)
例:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
DevicePolicyManagerdpm = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
ArrayList<String> strings = new ArrayList<String>(Arrays.asList("delegation-cert-install"));
dpm.setDelegatedScopes(new ComponentName("com.example.deviceadmin","com.example.deviceadmin.DeviceAdminSampleReceiver"),"com.xx.xxx",strings);
}else{
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 1);
}
3.2.获取IMSI,ICCID及电话号码
(1).应用必须动态获取android.permission.READ_PHONE_STATE 权限,且具有android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE权限(该权限需系统应用或者deviceAdmin和ProflieOwner才能使用)
(2).反射调用SubscriptionManager.getActiveSubscriptionInfoList,返回值为List<SubscriptionInfo>内容示例如下:
[{id=1 iccId=89860042191833126825 simSlotIndex=1 carrierId=1435 displayName=移动 carrierName=中国移动 nameSource=0 iconTint=-16746133 number= dataRoaming=0 iconBitmap=android.graphics.Bitmap@7f33c3b mcc=460 mnc=07 countryIso=cn isEmbedded=false nativeAccessRules=null cardString=89860042191833126825 cardId=0 isOpportunistic=false groupUUID=null isGroupDisabled=false profileClass=-1 ehplmns=[46000, 46007, 46002, 46008] hplmns=[46000, 46000, 46000] subscriptionType=0 groupOwner=null carrierConfigAccessRules=null areUiccApplicationsEnabled=true}]
(3).通过SubscriptionInfo.getIccId(),SubscriptionInfo.getNumber()方法获取Iccid和电话号码。
(4).通过SubscriptionInfo.getSubscriptionId() 获取SubscriberId,然后反射调用TelephonyManager.getSubscriberId(int SubscriberId)获取IMSI
DevicePolicyManagerService之DeviceOwner和ProfileOwner相关推荐
- DevicePolicyManagerService之DeviceAdmin
目录 1.DevicePolicyManagerService的初始化 2.DeviceAdmin DevicePolicyManagerService是Android提供的一个可管理和操作设备的系统 ...
- Android之解决Gigaset手机不能设置DeviceOwner权限提示already provisioned问题
客户那里有Gigaset手机,安装我们的产品需要注入DeviceOwner,但是刚恢复默认出厂的Gigaset手机很奇葩,注入权限的提示下面错误,导致不能使用我们的产品 设置DeviceOwner权限 ...
- Android DeviceOwner
1:DeviceAdminReceiver 首先注册deviceAdminReceiver广播接收者. public class MyDeviceAdminReceiver extends Devic ...
- Android如何设置为设备拥有者device-owner?
首先条件为android5.0及以上,执行命令adb shell dpm set-device-owner com.test/com.test.receiver.TestDeviceAdminRece ...
- 给Android应用设置DeviceOwner权限遇到的问题及解决方案
原文作者:岛哥的质量效能笔记 原文链接:https://juejin.cn/post/6995906975477432357 背景 Android手机品牌和型号众多,特别是国产手机系统时常添加各种中国 ...
- android手机deviceowner,删除 androidDeviceOwnerWiFiConfiguration
删除 androidDeviceOwnerWiFiConfigurationDelete androidDeviceOwnerWiFiConfiguration 2021/3/24 本文内容 命名空间 ...
- Vivo x9s设置deviceOwner后,无法使用应用分身
1:排除掉应用分身app被禁用的问题 adb shell pm list package -d(查询被disable掉的package) 2:查看vivo应用分身对应的包名等信息 adb shell ...
- 微信小程序入门级实战开发指南
微信小程序入门级实战开发指南 概述 微信小程序,简称小程序,英文名Mini Program,是一种"不需要下载安装"即可使用的应用(实际上是需要下载安装的,只是整个过程被简化到可以 ...
- android权限级别探索(四),Work Profile/Profile Owner的开启与功能
一.什么是Work Profile 因为Work Profile在体验上与Device Owner和Device admin有很大的差别,所以在讲怎么开启profileOwner之前先讲一下什么是 ...
- Octavia 项目加速 OpenStack LBaaS 落地大规模应用场景
目录 文章目录 目录 OpenStack LBaaS Octavia 软件架构 网络架构 操作对象基本概念 功能实现基本概念 Ocatvia Daemon 列表 部署 Ocatvia 手动方式集成 O ...
最新文章
- 硅谷产品实战-总结:14、如何用数据做出产品决定?
- Web 2.0技术对SEO的影响
- Java程序员必备!Redis面试复习大纲在手面试不慌
- 你可以去学python_你是怎么学好Python的?
- 你不知道的Node.js性能优化,读了之后水平直线上升
- 《进化——我们在互联网上奋斗的故事》一一1.1 靠谱工程师向管理者的转变...
- Linux中打包和解压到的方法
- 使用Kubernetes和Docker将Spring Boot与MongoDB作为容器部署
- 带UpdatePanel页面返回js问题
- 一阶电路暂态响应的结果分析。_【2020考研】南京邮电大学813《电路分析》考试大纲...
- [转]Error: SQL BPA command line has encountered a problem and needs to close
- 《浪潮之巅》吴军:特斯拉自动驾驶堪比中甲水平,全球5G看好华为
- 第9章 SportsStorePeta 完成购物车
- java request含嵌套_使用 RxJava 进行嵌套串行网络请求的一种方法
- ucGUI/emWin 自定义中文字库(汉字字库)
- 100以内奇数的平方和
- 从HttpClient3迁移到HttpClient4
- GAMS系列分享20—GAMS电力系统—目标函数增量线性化
- b2b平台和b2b网站一样吗?B2B是什么意思?
- CodeFun-UI 设计稿智能生成前端源代码
热门文章
- notempty注解属于哪个依赖_@NotEmpty、@NotNull、@NotBlank注解解析
- 木瓜移动每日快讯0511:谷歌Chrome引入新隐私功能fenced frame
- 【华为云·云筑2020】DevCloud考卷答案
- 邮箱大佬告诉你电子邮箱格式如何正确书写
- ansiblea基本使用
- 电源管理IC的分类及智能变化
- 【RDMA】qp数量和RDMA性能(节选)|连接数
- Unipus-writing exercise Expository_Text_09
- 招商银行软件开发笔试知识汇总
- matlab的persistent,MATLAB局部静态变量类型persistent