当前位置: 首页 > 工具软件 > OWNER > 使用案例 >

Profile Owner使用总结

袁雅逸
2023-12-01

一、Profile Owner

ProfileOwner 是配置文件所有者,从Android5.0开始推出。

在系统中只能设置一个Profile Owner程序,程序在设置为ProfileOwner后不能取消,也不能卸载,所以想要需要,只有恢复出厂设置。

二、成为Profile Owner

2.1 系统权限

要使程序成为ProfileOwner,需要程序拥有系统权限:
1.AndroidManifest文件中manifest标签添加:

android:sharedUserId="android.uid.system"

2.在app的build.gradle中使用系统签名

2.2 成为DeviceAdmin

想要成为ProfileOwner,有些方式首先需要先成为DeviceAdmin。
1.创建DeviceReceiver继承DeviceAdminReceiver:

public class AdminReceiver extends DeviceAdminReceiver {
    private static final String TAG = "AdminReceiver";
    
    @Override
    public void onEnabled(Context context, Intent intent) {
        super.onEnabled(context, intent);
        Logg.i(TAG, "Device Owner Enabled");
    }
    
    @Override
    public CharSequence onDisableRequested(Context context, Intent intent) {
        return "Warning: Device Admin is going to be disabled.";
    }
    
    @Override
    public void onDisabled(Context context, Intent intent) {
    }
    
    @Override
    public void onLockTaskModeEntering(Context context, Intent intent,
                                   String pkg) {
        Logg.i(TAG, "onLockTaskModeEntering");
    }
    
    @Override
    public void onLockTaskModeExiting(Context context, Intent intent) {
        Logg.i(TAG, "onLockTaskModeExiting");
    }
}

2.AndroidManifest注册:

<receiver
    android:name=".receiver.AdminReceiver"
    android:label="@string/app_name"
    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>

3.res/xml目录下添加文件admin.xml:

<?xml version="1.0" encoding="utf-8"?>
<device-admin
    xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
        <force-lock />
        <!--限制密码类型-->
        <limit-password />
        <!-- 监控屏幕解锁尝试次数 -->
        <watch-login />
        <!-- 重置密码-->
        <reset-password />
        <!--恢复出厂设置-->
        <wipe-data />
        <!-- 设置锁定屏幕密码的有效期 -->
        <expire-password />
        <!-- 设置存储设备加密 -->
        <encrypted-storage />
        <!-- 停用相机 -->
        <disable-camera />
    </uses-policies>
</device-admin>

4.激活deviceAdmin:

mComName = new ComponentName(context, AdminReceiver.class);
    
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mComName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "激活此设备管理员后可免root停用应用");
startActivityForResult(intent, 1);
    
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            Log.i(TAG, "[ProfileOwner][Admin]User accepted");
        } else {
            Log.i(TAG, "[ProfileOwner][Admin]User rejected");
        }
    }
}

使用上面的代码可以成为DeviceAdmin,会弹出窗口提示用户是否设置DeviceAdmin,用户同意后该程序会成为DeviceAdmin。

设置完成后,可以使用isAdminActive方法判断是否激活成功。
使用例子:

DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.isAdminActive(mComName);

2.3 成为Profile Owner

成为profile owner有三种方式。

2.3.1 adb命令

使用adb命令设置Profile Owner:

adb shell;
dpm set-profile-owner com.our.xxx/com.our.xxx.receiver.AdminReceiver;

设置您在代码中设定的Receiver,这种方式是将当前用户拥有AdminReceiver的程序设置为Profile Owner。
该方式不需要先成为DeviceAdmin,可以直接设置成为ProfileOwner,并且设备没有任何的弹窗提示用户点击同意按钮。

2.3.2 反射DevicePolicyManager方法

可以使用反射,反射出DevicePolicyManager中的设置Profile Owner的方法进行设置。
有两个方法都可以进行设置(该方法不适用于android10及以上版本):

1.setProfileOwner
使用例子:

mComName = new ComponentName(context, AdminReceiver.class);
    
Class c = Class.forName("android.app.admin.DevicePolicyManager");
Method method = c.getMethod("setProfileOwner", ComponentName.class, String.class, int.class);
method.invoke(mDevicePolicyManager, mComName, "ProfileOwner", 0);

setProfileOwner三个参数,第一个参数为ComponentName,第二个参数为 ownerName,第三个参数为用户id。ownerName为您要设置的名称,可随意;用户id为您要设置哪个用户中的程序成为ProfileOwner(系统首次启动时,默认会拥有用户id为0的用户空间)。
该方法需要先将该程序设置为DeviceAdmin,设置DeviceAdmin成功后,再调用该方法才可以设置成功,适用与android10以下版本

2.setActiveProfileOwner
使用例子:

mComName = new ComponentName(context, AdminReceiver.class);
    
Class c = Class.forName("android.app.admin.DevicePolicyManager");
Method method = c.getMethod("setActiveProfileOwner", ComponentName.class, String.class);
method.invoke(mDevicePolicyManager, mComName, "ProfileOwner");

setActiveProfileOwner两个参数,第一个参数为ComponentName,第二个参数为 ownerName。ownerName为您要设置的名称,可随意。
这里为什么不设置用户id呢?是因为用户id在这个方法中会自动获取当前用户id设置,不需要指定用户id。
该方法不能先将该程序设置为DeviceAdmin,会直接设置成为ProfileOwner(若程序已经是DeviceAdmin,使用该方法会失败),并且设备没有任何的弹窗提示用户点击同意按钮,适用与android10以下版本

2.3.3开启申请ProfileOwner界面

该方式需要先成为DeviceAdmin,然后执行下面的步骤成为ProfileOwner。该方式会新建一个用户空间,新建的这个用户空间中的指定程序会成为ProfileOwner。

1.打开申请Profile Owner的界面:

Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
    intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, getPackageName());
} else {
    final ComponentName component = new ComponentName(this, AdminReceiver.class.getName());
    intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, component);
}
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(intent, 1);
} else {
    Log.e("ProfileTest", "Device provisioning is not enabled. Stopping.");
}

2.打印用户是否同意设置ProfileOwner:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            Log.i("ProfileTest", "Provisioning done.");
        } else {
            Log.i("ProfileTest", "Provisioning failed.");
        }
        return;
    }
    super.onActivityResult(requestCode, resultCode, data);
}

3.在AdminReceiver.java中添加:

@Override
public void onProfileProvisioningComplete(Context context, Intent intent) {
    DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
    ComponentName componentName = new ComponentName(context, AdminReceiver.class);
    dpm.setProfileName(componentName, "Test");
    dpm.setProfileEnabled(componentName);
}

执行完AdminReceiver中代码后,ProfileOwner将正式创建成功,若没有执行AdminReceiver中的代码都是创建失败。

2.4判断ProfileOwner是否设置成功

上面设置完成后,可以使用isProfileOwnerApp方法,使用包名判断该app是否已经被设置为ProfileOwner。
使用例子:

dpm.isProfileOwnerApp("com.our.xxx");

2.5 ProfileOwner使用限制

首次开机后:

1.先设置自己程序的ProfileOwner权限,设置成功后,可以使用google商店(但无法验证google商店是否设置ProfileOwner/DeviceOwner权限成功);

2.先打开google商店,登录后,再设置自己程序的ProfileOwner权限,会失败(提示Not allowed to set the profile owner because there are already some accounts on the profile)。

所以需让自己程序设置为ProfileOwner,然后再使用google相关功能。

三、常用功能

3.1 添加用户权限

成为ProfileOwner后,可以控制用户的权限。
使用例子:

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = new ComponentName(mContext, AdminReceiver.class);
dpm.addUserRestriction(componentName, DISALLOW_OUTGOING_BEAM);

使用addUserRestriction方法可以对该用户添加权限,可以添加的权限如下所示(下表中仅列出测试成功的权限,部分权限没有进行测试):

Key功能
DISALLOW_CONFIG_LOCALE禁止用户更改设备语言
DISALLOW_INSTALL_APPS禁止安装应用
DISALLOW_UNINSTALL_APPS禁止卸载应用
DISALLOW_BLUETOOTH禁止操作蓝牙
DISALLOW_DEBUGGING_FEATURES禁用adb调试
DISALLOW_CONFIG_LOCATION禁用定位gps
DISALLOW_CONFIG_DATE_TIME不允许配置日期、时间和时区
DISALLOW_ADJUST_VOLUME静音,不允许调整音量

 

3.2清除权限

成为ProfileOwner后,可以清除赋给用户的权限。
使用例子:

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = new ComponentName(mContext, AdminReceiver.class);
dpm.clearUserRestriction(componentName, DISALLOW_OUTGOING_BEAM);

可以清除的权限与上面添加权限一致。

3.3暂停应用

成为ProfileOwner后,可以设置哪些应用不可使用,应用图标会置灰,不可点击。
使用例子:

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
ComponentName componentName = new ComponentName(mContext, AdminReceiver.class);
dpm.setPackagesSuspended(componentName, packageNames, suspended);

使用setPackagesSuspended方法可以对该用户的应用进行使用限制,将要控制的应用包名放入数组中,设置对这些应用是可使用还是不可使用,可使用suspended为false,不可使用suspended为true。

3.4其他功能

下面的功能都未进行测试。

接口名称setApplicationHidden
功能描述隐藏应用图标,且应用不可用
参数名称类型
adminComponentName
packageNameString
hiddenboolean
返回值类型说明
booleanboolean Whether the hidden setting of the package was successfully updated.
接口名称setPermissionGrantState
功能描述通过包名设置权限
参数名称类型
adminComponentName
packageNameString
permissionString
grantStateint
返回值类型说明
booleanwhether the permission was successfully granted or revoked
接口名称getPermissionGrantState
功能描述通过包名获取应用程序的运行时权限状态
参数名称类型
adminComponentName
packageNameString
permissionString
返回值类型说明
intThe current grant state specified by device policy

上面只列出部分功能,还有很多关于设备密码以及锁屏等功能相关的方法。

 类似资料: