欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android10设置ProfileOwner失败的源码解析

程序员文章站 2022-06-15 10:53:46
ProfileOwner的设置可以通过反射DevicePolicyManager中的方法,直接将当前或者指定的用户下的程序设置为ProfileOwner。但是Android9都是有效的,到Android10却不生效了,报错信息为:IllegalStateException: Unable to set non-default profile owner post-setup ...为什么会报这个错误呢,来看看源码中什么情况会报这个错误。DevicePolicyManager中有两个方法都可以...

ProfileOwner的设置可以通过反射DevicePolicyManager中的方法,直接将当前或者指定的用户下的程序设置为ProfileOwner。
但是Android9都是有效的,到Android10却不生效了,报错信息为:

IllegalStateException: Unable to set non-default profile owner post-setup ...

为什么会报这个错误呢,来看看源码中什么情况会报这个错误。

DevicePolicyManager中有两个方法都可以设置ProfileOwner,分别是setProfileOwner、setActiveProfileOwner。
setProfileOwner可以将DeviceAdmin设置为ProfileOwner。
setActiveProfileOwner可以将普通用户设置为ProfileOwner。

分别来看看两个方法的源码:
setProfileOwner:

public boolean setProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName,
        int userHandle) throws IllegalArgumentException {
    if (mService != null) {
        try {
            if (ownerName == null) {
                ownerName = "";
            }
            return mService.setProfileOwner(admin, ownerName, userHandle);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }
    return false;
}

可以看到直接使用了mService.setProfileOwner(admin, ownerName, userHandle)进行设置,其中userHandle是由方法传入的,所以可以设置指定的用户设置为ProfileOwner。

setActiveProfileOwner:

public boolean setActiveProfileOwner(@NonNull ComponentName admin, @Deprecated String ownerName)
        throws IllegalArgumentException {
    throwIfParentInstance("setActiveProfileOwner");
    if (mService != null) {
        try {
            final int myUserId = myUserId();
            mService.setActiveAdmin(admin, false, myUserId);
            return mService.setProfileOwner(admin, ownerName, myUserId);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }
    return false;
}

这是一个打有@Deprecated的方法,是废弃的,主要做了三件事,第一件事是获取当前用户id,第二件事是将当前用户设置为DeviceAdmin,第三件事是将当前用户设置为ProfileOwner,同样设置ProfileOwner的方法是mService.setProfileOwner(admin, ownerName, myUserId)。

两种方式都是使用mService的setProfileOwner方法,接下来看看setProfileOwner方法的实现。
setProfileOwner具体实现是在DevicePolicyManagerService.java中,这是frameworks层代码,可以去源码网站查看。

@Override
public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
    if (!mHasFeature) {
        return false;
    }
    if (who == null
            || !isPackageInstalledForUser(who.getPackageName(), userHandle)) {
        throw new IllegalArgumentException("Component " + who
                + " not installed for userId:" + userHandle);
    }

    final boolean hasIncompatibleAccountsOrNonAdb =
            hasIncompatibleAccountsOrNonAdbNoLock(userHandle, who);
    synchronized (getLockObject()) {
        enforceCanSetProfileOwnerLocked(who, userHandle, hasIncompatibleAccountsOrNonAdb);
    
    ...
}

到目前为止,Android9与Android10差别不大,在setProfileOwner方法中,会先进入到enforceCanSetProfileOwnerLocked方法,而引起Android10报错的代码就在这个方法中。

来看看Android9中enforceCanSetProfileOwnerLocked代码的实现:

private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle,
        boolean hasIncompatibleAccountsOrNonAdb) {
    UserInfo info = getUserInfo(userHandle);
    if (info == null) {
        // User doesn't exist.
        throw new IllegalArgumentException(
                "Attempted to set profile owner for invalid userId: " + userHandle);
    }
    if (info.isGuest()) {
        throw new IllegalStateException("Cannot set a profile owner on a guest");
    }
    if (mOwners.hasProfileOwner(userHandle)) {
        throw new IllegalStateException("Trying to set the profile owner, but profile owner "
                + "is already set.");
    }
    if (mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == userHandle) {
        throw new IllegalStateException("Trying to set the profile owner, but the user "
                + "already has a device owner.");
    }
    if (isAdb()) {
        if ((mIsWatch || hasUserSetupCompleted(userHandle))
                && hasIncompatibleAccountsOrNonAdb) {
            throw new IllegalStateException("Not allowed to set the profile owner because "
                    + "there are already some accounts on the profile");
        }
        return;
    }
    enforceCanManageProfileAndDeviceOwners();
    if ((mIsWatch || hasUserSetupCompleted(userHandle)) && !isCallerWithSystemUid()) {
        throw new IllegalStateException("Cannot set the profile owner on a user which is "
                + "already set-up");
    }
}

Android10中enforceCanSetProfileOwnerLocked代码的实现:

private void enforceCanSetProfileOwnerLocked(@Nullable ComponentName owner, int userHandle,
        boolean hasIncompatibleAccountsOrNonAdb) {
    UserInfo info = getUserInfo(userHandle);
    if (info == null) {
        // User doesn't exist.
        throw new IllegalArgumentException(
                "Attempted to set profile owner for invalid userId: " + userHandle);
    }
    if (info.isGuest()) {
        throw new IllegalStateException("Cannot set a profile owner on a guest");
    }
    if (mOwners.hasProfileOwner(userHandle)) {
        throw new IllegalStateException("Trying to set the profile owner, but profile owner "
                + "is already set.");
    }
    if (mOwners.hasDeviceOwner() && mOwners.getDeviceOwnerUserId() == userHandle) {
        throw new IllegalStateException("Trying to set the profile owner, but the user "
                + "already has a device owner.");
    }
    if (isAdb()) {
        if ((mIsWatch || hasUserSetupCompleted(userHandle))
                && hasIncompatibleAccountsOrNonAdb) {
            throw new IllegalStateException("Not allowed to set the profile owner because "
                    + "there are already some accounts on the profile");
        }
        return;
    }
    enforceCanManageProfileAndDeviceOwners();

    if ((mIsWatch || hasUserSetupCompleted(userHandle))) {
        if (!isCallerWithSystemUid()) {
            throw new IllegalStateException("Cannot set the profile owner on a user which is "
                    + "already set-up");
        }

        if (!mIsWatch) {
            // Only the default supervision profile owner can be set as profile owner after SUW
            final String supervisor = mContext.getResources().getString(
                    com.android.internal.R.string
                            .config_defaultSupervisionProfileOwnerComponent);
            if (supervisor == null) {
                throw new IllegalStateException("Unable to set profile owner post-setup, no"
                        + "default supervisor profile owner defined");
            }

            final ComponentName supervisorComponent = ComponentName.unflattenFromString(
                    supervisor);
            if (!owner.equals(supervisorComponent)) {
                throw new IllegalStateException("Unable to set non-default profile owner"
                        + " post-setup " + owner);
            }
        }
    }
}

通过Android9与10的比较可以看处从enforceCanManageProfileAndDeviceOwners()方法以上都是一样的,不一样出在这个方法的下面,并且可以看到Unable to set non-default profile owner post-setup错误是由哪里报出来的。

Android9与10不同的一段就是Android10会多出来一个判断:

if (!mIsWatch) {
    // Only the default supervision profile owner can be set as profile owner after SUW
    final String supervisor = mContext.getResources().getString(
                    com.android.internal.R.string
                            .config_defaultSupervisionProfileOwnerComponent);
    if (supervisor == null) {
        throw new IllegalStateException("Unable to set profile owner post-setup, no"
                        + "default supervisor profile owner defined");
    }

    final ComponentName supervisorComponent = ComponentName.unflattenFromString(
                    supervisor);
    if (!owner.equals(supervisorComponent)) {
        throw new IllegalStateException("Unable to set non-default profile owner"
                        + " post-setup " + owner);
    }
}

首先mIsWatch是判断是否是穿戴手表类型的设备,是穿戴手表为true,反之为false,那么不是穿戴手表类型的设备会进入到下面的判断。
然后获取config_defaultSupervisionProfileOwnerComponent的String内容,这个String是系统的,获取出来后,会使用这个String生成ComponentName。
ComponentName中unflattenFromString方法:

public static @Nullable ComponentName unflattenFromString(@NonNull String str) {
    int sep = str.indexOf('/');
    if (sep < 0 || (sep+1) >= str.length()) {
        return null;
    }
    String pkg = str.substring(0, sep);
    String cls = str.substring(sep+1);
    if (cls.length() > 0 && cls.charAt(0) == '.') {
        cls = pkg + cls;
    }
    return new ComponentName(pkg, cls);
}

根据上面的代码可以推测出config_defaultSupervisionProfileOwnerComponent的内容应该为: com.xxx.xxx/com.xxx.xxx.classname或者com.xxx.xxx/.classname

最后会让两个ComponentName进行比较,ComponentName中equals方法:

@Override
public boolean equals(Object obj) {
    try {
        if (obj != null) {
            ComponentName other = (ComponentName)obj;
            // Note: no null checks, because mPackage and mClass can
            // never be null.
            return mPackage.equals(other.mPackage)
                    && mClass.equals(other.mClass);
        }
    } catch (ClassCastException e) {
    }
    return false;
}

上面的代码就是将ComponentName的package与class与另外一个进行比较,比较不相同就会报Unable to set non-default profile owner post-setup错误。

根据上面的分析,获取到的config_defaultSupervisionProfileOwnerComponent的内容不是您想要设置的包以及包中的类,所以会报错。

怎么让config_defaultSupervisionProfileOwnerComponent这个值是您想要的值呢,目前是对系统进行修改,没有找到其他的方法,经系统修改值之后,Android10可以顺利的设置ProfileOwner。

本文地址:https://blog.csdn.net/qq_33208587/article/details/114320353

相关标签: android