Loading core/java/android/app/admin/DevicePolicyManager.java +4 −0 Original line number Diff line number Diff line Loading @@ -6845,6 +6845,10 @@ public class DevicePolicyManager { * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure * of the VPN provider could break networking for all apps. This method clears any lockdown * allowlist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}. * <p> Starting from {@link android.os.Build.VERSION_CODES#S API 31} calling this method with * {@code vpnPackage} set to {@code null} only removes the existing configuration if it was * previously created by this admin. To remove VPN configuration created by the user use * {@link UserManager#DISALLOW_CONFIG_VPN}. * * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to * remove an existing always-on VPN configuration. Loading core/java/android/app/admin/DevicePolicyManagerInternal.java +0 −1 Original line number Diff line number Diff line Loading @@ -265,5 +265,4 @@ public abstract class DevicePolicyManagerInternal { */ public abstract void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker, @OperationSafetyReason int reason, boolean isSafe); } core/java/android/os/UserManager.java +2 −0 Original line number Diff line number Diff line Loading @@ -575,6 +575,8 @@ public class UserManager { * <p>This restriction also prevents VPNs from starting. However, in Android 7.0 * ({@linkplain android.os.Build.VERSION_CODES#N API level 24}) or higher, the system does * start always-on VPNs created by the device or profile owner. * <p>From Android 12 ({@linkplain android.os.Build.VERSION_CODES#S API level 31}) enforcing * this restriction clears currently active VPN if it was configured by the user. * * <p>Key for user restrictions. * <p>Type: Boolean Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +99 −31 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; Loading Loading @@ -990,13 +991,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions) { final boolean newlyDisallowed = newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); final boolean previouslyDisallowed = prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); final boolean restrictionChanged = (newlyDisallowed != previouslyDisallowed); resetCrossProfileIntentFiltersIfNeeded(userId, newRestrictions, prevRestrictions); resetUserVpnIfNeeded(userId, newRestrictions, prevRestrictions); } private void resetUserVpnIfNeeded( int userId, Bundle newRestrictions, Bundle prevRestrictions) { final boolean newlyEnforced = !prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN) && newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN); if (newlyEnforced) { mDpms.clearUserConfiguredVpns(userId); } } if (restrictionChanged) { private void resetCrossProfileIntentFiltersIfNeeded( int userId, Bundle newRestrictions, Bundle prevRestrictions) { if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE)) { final int parentId = mUserManagerInternal.getProfileParentId(userId); if (parentId == userId) { return; Loading @@ -1007,13 +1019,55 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slogf.i(LOG_TAG, "Resetting cross-profile intent filters on restriction " + "change"); mDpms.resetDefaultCrossProfileIntentFilters(parentId); mContext.sendBroadcastAsUser(new Intent( DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED), mContext.sendBroadcastAsUser( new Intent(DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED), UserHandle.of(userId)); } } } private void clearUserConfiguredVpns(int userId) { final String adminConfiguredVpnPkg; synchronized (getLockObject()) { final ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); if (owner == null) { Slogf.wtf(LOG_TAG, "Admin not found"); return; } adminConfiguredVpnPkg = owner.mAlwaysOnVpnPackage; } // Clear always-on configuration if it wasn't set by the admin. if (adminConfiguredVpnPkg == null) { mInjector.getVpnManager().setAlwaysOnVpnPackageForUser(userId, null, false, null); } // Clear app authorizations to establish VPNs. When DISALLOW_CONFIG_VPN is enforced apps // won't be able to get those authorizations unless it is configured by an admin. final List<AppOpsManager.PackageOps> allVpnOps = mInjector.getAppOpsManager() .getPackagesForOps(new int[] {AppOpsManager.OP_ACTIVATE_VPN}); if (allVpnOps == null) { return; } for (AppOpsManager.PackageOps pkgOps : allVpnOps) { if (UserHandle.getUserId(pkgOps.getUid()) != userId || pkgOps.getPackageName().equals(adminConfiguredVpnPkg)) { continue; } if (pkgOps.getOps().size() != 1) { Slogf.wtf(LOG_TAG, "Unexpected number of ops returned"); continue; } final @Mode int mode = pkgOps.getOps().get(0).getMode(); if (mode == MODE_ALLOWED) { Slogf.i(LOG_TAG, String.format("Revoking VPN authorization for package %s uid %d", pkgOps.getPackageName(), pkgOps.getUid())); mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN, pkgOps.getUid(), pkgOps.getPackageName(), MODE_DEFAULT); } } } private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener { @Override Loading Loading @@ -6559,6 +6613,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_ALWAYS_ON_VPN_PACKAGE); if (vpnPackage == null) { final String prevVpnPackage; synchronized (getLockObject()) { prevVpnPackage = getProfileOwnerOrDeviceOwnerLocked(caller).mAlwaysOnVpnPackage; // If the admin is clearing VPN package but hasn't configure any VPN previously, // ignore it so that it doesn't interfere with user-configured VPNs. if (TextUtils.isEmpty(prevVpnPackage)) { return true; } } revokeVpnAuthorizationForPackage(prevVpnPackage, caller.getUserId()); } final int userId = caller.getUserId(); mInjector.binderWithCleanCallingIdentity(() -> { if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) { Loading @@ -6581,6 +6648,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { userId, vpnPackage, lockdown, lockdownAllowlist)) { throw new UnsupportedOperationException(); } }); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE) .setAdmin(caller.getComponentName()) Loading @@ -6588,7 +6656,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setBoolean(lockdown) .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0) .write(); }); synchronized (getLockObject()) { ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller); if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage) Loading @@ -6601,6 +6668,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } private void revokeVpnAuthorizationForPackage(String vpnPackage, int userId) { mInjector.binderWithCleanCallingIdentity(() -> { try { final ApplicationInfo ai = mIPackageManager.getApplicationInfo( vpnPackage, /* flags= */ 0, userId); if (ai == null) { Slogf.w(LOG_TAG, "Non-existent VPN package: " + vpnPackage); } else { mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN, ai.uid, vpnPackage, MODE_DEFAULT); } } catch (RemoteException e) { Slogf.e(LOG_TAG, "Can't talk to package managed", e); } }); } @Override public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException { Objects.requireNonNull(admin, "ComponentName is null"); Loading Loading @@ -8390,12 +8474,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return who != null && who.equals(profileOwner); } private boolean isProfileOwnerUncheckedLocked(ComponentName who, int userId) { ensureLocked(); final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId); return who != null && who.equals(profileOwner); } /** * Returns {@code true} if the provided caller identity is of a profile owner. * @param caller identity of caller. Loading Loading @@ -13667,16 +13745,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + " is not device owner"); } private ComponentName getOwnerComponent(String packageName, int userId) { if (isDeviceOwnerPackage(packageName, userId)) { return mOwners.getDeviceOwnerComponent(); } if (isProfileOwnerPackage(packageName, userId)) { return mOwners.getProfileOwnerComponent(userId); } return null; } /** * Return device owner or profile owner set on a given user. */ services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package com.android.server.devicepolicy; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_ACTIVATE_VPN; import static android.app.Notification.EXTRA_TEXT; import static android.app.Notification.EXTRA_TITLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; Loading Loading @@ -7436,6 +7439,101 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThrows(SecurityException.class, () -> dpm.setRecommendedGlobalProxy(admin1, null)); } @Test public void testSetAlwaysOnVpnPackage_clearsAdminVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // Set VPN package to admin package. dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null); verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, admin1.getPackageName(), false, null); // Clear VPN package. dpm.setAlwaysOnVpnPackage(admin1, null, false, null); // Change should be propagated to VpnManager verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, null, false, null); // The package should lose authorization to start VPN. verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN, DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT); } @Test public void testSetAlwaysOnVpnPackage_doesntKillUserVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // this time it shouldn't go into VpnManager anymore. dpm.setAlwaysOnVpnPackage(admin1, null, false, null); verifyNoMoreInteractions(getServices().vpnManager); verifyNoMoreInteractions(getServices().appOpsManager); } @Test public void testDisallowConfigVpn_clearsUserVpn() throws Exception { final String userVpnPackage = "org.some.vpn.servcie"; final int userVpnUid = 20374; setDeviceOwner(); setupVpnAuthorization(userVpnPackage, userVpnUid); simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN); verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, null, false, null); verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN, userVpnUid, userVpnPackage, MODE_DEFAULT); } @Test public void testDisallowConfigVpn_doesntKillAdminVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // Set VPN package to admin package. dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null); setupVpnAuthorization(admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID); clearInvocations(getServices().vpnManager); simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN); // Admin-set package should remain always-on and should retain its authorization. verifyNoMoreInteractions(getServices().vpnManager); verify(getServices().appOpsManager, never()).setMode(OP_ACTIVATE_VPN, DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT); } private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) { final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage, userVpnUid, List.of(new AppOpsManager.OpEntry( OP_ACTIVATE_VPN, MODE_ALLOWED, Collections.emptyMap()))); when(getServices().appOpsManager.getPackagesForOps(any(int[].class))) .thenReturn(List.of(vpnOp)); } private void simulateRestrictionAdded(String restriction) { RestrictionsListener listener = new RestrictionsListener( mServiceContext, getServices().userManagerInternal, dpms); final Bundle newRestrictions = new Bundle(); newRestrictions.putBoolean(restriction, true); listener.onUserRestrictionsChanged(UserHandle.USER_SYSTEM, newRestrictions, new Bundle()); } private void setUserUnlocked(int userHandle, boolean unlocked) { when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked); } Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +4 −0 Original line number Diff line number Diff line Loading @@ -6845,6 +6845,10 @@ public class DevicePolicyManager { * <p> Enabling lockdown via {@code lockdownEnabled} argument carries the risk that any failure * of the VPN provider could break networking for all apps. This method clears any lockdown * allowlist set by {@link #setAlwaysOnVpnPackage(ComponentName, String, boolean, Set)}. * <p> Starting from {@link android.os.Build.VERSION_CODES#S API 31} calling this method with * {@code vpnPackage} set to {@code null} only removes the existing configuration if it was * previously created by this admin. To remove VPN configuration created by the user use * {@link UserManager#DISALLOW_CONFIG_VPN}. * * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} to * remove an existing always-on VPN configuration. Loading
core/java/android/app/admin/DevicePolicyManagerInternal.java +0 −1 Original line number Diff line number Diff line Loading @@ -265,5 +265,4 @@ public abstract class DevicePolicyManagerInternal { */ public abstract void notifyUnsafeOperationStateChanged(DevicePolicySafetyChecker checker, @OperationSafetyReason int reason, boolean isSafe); }
core/java/android/os/UserManager.java +2 −0 Original line number Diff line number Diff line Loading @@ -575,6 +575,8 @@ public class UserManager { * <p>This restriction also prevents VPNs from starting. However, in Android 7.0 * ({@linkplain android.os.Build.VERSION_CODES#N API level 24}) or higher, the system does * start always-on VPNs created by the device or profile owner. * <p>From Android 12 ({@linkplain android.os.Build.VERSION_CODES#S API level 31}) enforcing * this restriction clears currently active VPN if it was configured by the user. * * <p>Key for user restrictions. * <p>Type: Boolean Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +99 −31 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.Manifest.permission.REQUEST_PASSWORD_COMPLEXITY; import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED; import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; Loading Loading @@ -990,13 +991,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void onUserRestrictionsChanged(int userId, Bundle newRestrictions, Bundle prevRestrictions) { final boolean newlyDisallowed = newRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); final boolean previouslyDisallowed = prevRestrictions.getBoolean(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE); final boolean restrictionChanged = (newlyDisallowed != previouslyDisallowed); resetCrossProfileIntentFiltersIfNeeded(userId, newRestrictions, prevRestrictions); resetUserVpnIfNeeded(userId, newRestrictions, prevRestrictions); } private void resetUserVpnIfNeeded( int userId, Bundle newRestrictions, Bundle prevRestrictions) { final boolean newlyEnforced = !prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN) && newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_VPN); if (newlyEnforced) { mDpms.clearUserConfiguredVpns(userId); } } if (restrictionChanged) { private void resetCrossProfileIntentFiltersIfNeeded( int userId, Bundle newRestrictions, Bundle prevRestrictions) { if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions, UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE)) { final int parentId = mUserManagerInternal.getProfileParentId(userId); if (parentId == userId) { return; Loading @@ -1007,13 +1019,55 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Slogf.i(LOG_TAG, "Resetting cross-profile intent filters on restriction " + "change"); mDpms.resetDefaultCrossProfileIntentFilters(parentId); mContext.sendBroadcastAsUser(new Intent( DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED), mContext.sendBroadcastAsUser( new Intent(DevicePolicyManager.ACTION_DATA_SHARING_RESTRICTION_APPLIED), UserHandle.of(userId)); } } } private void clearUserConfiguredVpns(int userId) { final String adminConfiguredVpnPkg; synchronized (getLockObject()) { final ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId); if (owner == null) { Slogf.wtf(LOG_TAG, "Admin not found"); return; } adminConfiguredVpnPkg = owner.mAlwaysOnVpnPackage; } // Clear always-on configuration if it wasn't set by the admin. if (adminConfiguredVpnPkg == null) { mInjector.getVpnManager().setAlwaysOnVpnPackageForUser(userId, null, false, null); } // Clear app authorizations to establish VPNs. When DISALLOW_CONFIG_VPN is enforced apps // won't be able to get those authorizations unless it is configured by an admin. final List<AppOpsManager.PackageOps> allVpnOps = mInjector.getAppOpsManager() .getPackagesForOps(new int[] {AppOpsManager.OP_ACTIVATE_VPN}); if (allVpnOps == null) { return; } for (AppOpsManager.PackageOps pkgOps : allVpnOps) { if (UserHandle.getUserId(pkgOps.getUid()) != userId || pkgOps.getPackageName().equals(adminConfiguredVpnPkg)) { continue; } if (pkgOps.getOps().size() != 1) { Slogf.wtf(LOG_TAG, "Unexpected number of ops returned"); continue; } final @Mode int mode = pkgOps.getOps().get(0).getMode(); if (mode == MODE_ALLOWED) { Slogf.i(LOG_TAG, String.format("Revoking VPN authorization for package %s uid %d", pkgOps.getPackageName(), pkgOps.getUid())); mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN, pkgOps.getUid(), pkgOps.getPackageName(), MODE_DEFAULT); } } } private final class UserLifecycleListener implements UserManagerInternal.UserLifecycleListener { @Override Loading Loading @@ -6559,6 +6613,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkCallAuthorization(isDeviceOwner(caller) || isProfileOwner(caller)); checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_ALWAYS_ON_VPN_PACKAGE); if (vpnPackage == null) { final String prevVpnPackage; synchronized (getLockObject()) { prevVpnPackage = getProfileOwnerOrDeviceOwnerLocked(caller).mAlwaysOnVpnPackage; // If the admin is clearing VPN package but hasn't configure any VPN previously, // ignore it so that it doesn't interfere with user-configured VPNs. if (TextUtils.isEmpty(prevVpnPackage)) { return true; } } revokeVpnAuthorizationForPackage(prevVpnPackage, caller.getUserId()); } final int userId = caller.getUserId(); mInjector.binderWithCleanCallingIdentity(() -> { if (vpnPackage != null && !isPackageInstalledForUser(vpnPackage, userId)) { Loading @@ -6581,6 +6648,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { userId, vpnPackage, lockdown, lockdownAllowlist)) { throw new UnsupportedOperationException(); } }); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_ALWAYS_ON_VPN_PACKAGE) .setAdmin(caller.getComponentName()) Loading @@ -6588,7 +6656,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .setBoolean(lockdown) .setInt(lockdownAllowlist != null ? lockdownAllowlist.size() : 0) .write(); }); synchronized (getLockObject()) { ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(caller); if (!TextUtils.equals(vpnPackage, admin.mAlwaysOnVpnPackage) Loading @@ -6601,6 +6668,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return true; } private void revokeVpnAuthorizationForPackage(String vpnPackage, int userId) { mInjector.binderWithCleanCallingIdentity(() -> { try { final ApplicationInfo ai = mIPackageManager.getApplicationInfo( vpnPackage, /* flags= */ 0, userId); if (ai == null) { Slogf.w(LOG_TAG, "Non-existent VPN package: " + vpnPackage); } else { mInjector.getAppOpsManager().setMode(AppOpsManager.OP_ACTIVATE_VPN, ai.uid, vpnPackage, MODE_DEFAULT); } } catch (RemoteException e) { Slogf.e(LOG_TAG, "Can't talk to package managed", e); } }); } @Override public String getAlwaysOnVpnPackage(ComponentName admin) throws SecurityException { Objects.requireNonNull(admin, "ComponentName is null"); Loading Loading @@ -8390,12 +8474,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return who != null && who.equals(profileOwner); } private boolean isProfileOwnerUncheckedLocked(ComponentName who, int userId) { ensureLocked(); final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId); return who != null && who.equals(profileOwner); } /** * Returns {@code true} if the provided caller identity is of a profile owner. * @param caller identity of caller. Loading Loading @@ -13667,16 +13745,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { + " is not device owner"); } private ComponentName getOwnerComponent(String packageName, int userId) { if (isDeviceOwnerPackage(packageName, userId)) { return mOwners.getDeviceOwnerComponent(); } if (isProfileOwnerPackage(packageName, userId)) { return mOwners.getProfileOwnerComponent(userId); } return null; } /** * Return device owner or profile owner set on a given user. */
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +98 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,9 @@ */ package com.android.server.devicepolicy; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.app.AppOpsManager.MODE_DEFAULT; import static android.app.AppOpsManager.OP_ACTIVATE_VPN; import static android.app.Notification.EXTRA_TEXT; import static android.app.Notification.EXTRA_TITLE; import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE; Loading Loading @@ -7436,6 +7439,101 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThrows(SecurityException.class, () -> dpm.setRecommendedGlobalProxy(admin1, null)); } @Test public void testSetAlwaysOnVpnPackage_clearsAdminVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // Set VPN package to admin package. dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null); verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, admin1.getPackageName(), false, null); // Clear VPN package. dpm.setAlwaysOnVpnPackage(admin1, null, false, null); // Change should be propagated to VpnManager verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, null, false, null); // The package should lose authorization to start VPN. verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN, DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT); } @Test public void testSetAlwaysOnVpnPackage_doesntKillUserVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // this time it shouldn't go into VpnManager anymore. dpm.setAlwaysOnVpnPackage(admin1, null, false, null); verifyNoMoreInteractions(getServices().vpnManager); verifyNoMoreInteractions(getServices().appOpsManager); } @Test public void testDisallowConfigVpn_clearsUserVpn() throws Exception { final String userVpnPackage = "org.some.vpn.servcie"; final int userVpnUid = 20374; setDeviceOwner(); setupVpnAuthorization(userVpnPackage, userVpnUid); simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN); verify(getServices().vpnManager).setAlwaysOnVpnPackageForUser( UserHandle.USER_SYSTEM, null, false, null); verify(getServices().appOpsManager).setMode(OP_ACTIVATE_VPN, userVpnUid, userVpnPackage, MODE_DEFAULT); } @Test public void testDisallowConfigVpn_doesntKillAdminVpn() throws Exception { setDeviceOwner(); when(getServices().vpnManager .setAlwaysOnVpnPackageForUser(anyInt(), any(), anyBoolean(), any())) .thenReturn(true); // Set VPN package to admin package. dpm.setAlwaysOnVpnPackage(admin1, admin1.getPackageName(), false, null); setupVpnAuthorization(admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID); clearInvocations(getServices().vpnManager); simulateRestrictionAdded(UserManager.DISALLOW_CONFIG_VPN); // Admin-set package should remain always-on and should retain its authorization. verifyNoMoreInteractions(getServices().vpnManager); verify(getServices().appOpsManager, never()).setMode(OP_ACTIVATE_VPN, DpmMockContext.CALLER_SYSTEM_USER_UID, admin1.getPackageName(), MODE_DEFAULT); } private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) { final AppOpsManager.PackageOps vpnOp = new AppOpsManager.PackageOps(userVpnPackage, userVpnUid, List.of(new AppOpsManager.OpEntry( OP_ACTIVATE_VPN, MODE_ALLOWED, Collections.emptyMap()))); when(getServices().appOpsManager.getPackagesForOps(any(int[].class))) .thenReturn(List.of(vpnOp)); } private void simulateRestrictionAdded(String restriction) { RestrictionsListener listener = new RestrictionsListener( mServiceContext, getServices().userManagerInternal, dpms); final Bundle newRestrictions = new Bundle(); newRestrictions.putBoolean(restriction, true); listener.onUserRestrictionsChanged(UserHandle.USER_SYSTEM, newRestrictions, new Bundle()); } private void setUserUnlocked(int userHandle, boolean unlocked) { when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked); } Loading