Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 63ec472b authored by Amos Bianchi's avatar Amos Bianchi
Browse files

Exempt device lock controller and kiosk roles from metered restrictions.

Bug: 352771686
Test: atest FrameworksServicesTests:DevicePolicyManagerTest
Flag: EXEMPT bugfix

Change-Id: I84741fbb34ee17ef421790d1a3340a2f9412c376
parent 32b5fb53
Loading
Loading
Loading
Loading
+30 −5
Original line number Diff line number Diff line
@@ -871,6 +871,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                EXEMPT_FROM_POWER_RESTRICTIONS, OPSTR_SYSTEM_EXEMPT_FROM_POWER_RESTRICTIONS);
    }
    private static final Set<String> METERED_DATA_RESTRICTION_EXEMPT_ROLES =
            new ArraySet<>();
    static {
        // TODO(b/362545319): reference role name from role manager once it's exposed.
        final String roleDeviceLockController =
                "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";
        METERED_DATA_RESTRICTION_EXEMPT_ROLES.add(roleDeviceLockController);
        METERED_DATA_RESTRICTION_EXEMPT_ROLES.add(RoleManager.ROLE_FINANCED_DEVICE_KIOSK);
    }
    /**
     * Admin apps targeting Android S+ may not use
     * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality
@@ -1959,6 +1969,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            return UserManager.isHeadlessSystemUserMode();
        }
        List<String> roleManagerGetRoleHoldersAsUser(String role, UserHandle userHandle) {
            return getRoleManager().getRoleHoldersAsUser(role, userHandle);
        }
        @SuppressWarnings("AndroidFrameworkPendingIntentMutability")
        PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
                @NonNull Intent intent, int flags, Bundle options, UserHandle user) {
@@ -17920,15 +17934,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
        });
    }
    private Set<String> getMeteredDataRestrictionExemptPackages(int userId) {
        final Set<String> exemptPkgs = new ArraySet<>();
        for (String role: METERED_DATA_RESTRICTION_EXEMPT_ROLES) {
            String pkg = getRoleHolderPackageNameOnUser(role, userId);
            if (pkg != null) {
                exemptPkgs.add(pkg);
            }
        }
        return exemptPkgs;
    }
    private List<String> removeInvalidPkgsForMeteredDataRestriction(
            int userId, List<String> pkgNames) {
        final Set<String> exemptRolePkgs = getMeteredDataRestrictionExemptPackages(userId);
        synchronized (getLockObject()) {
            final Set<String> activeAdmins = getActiveAdminPackagesLocked(userId);
            final List<String> excludedPkgs = new ArrayList<>();
            for (int i = pkgNames.size() - 1; i >= 0; --i) {
                final String pkgName = pkgNames.get(i);
                // If the package is an active admin, don't restrict it.
                if (activeAdmins.contains(pkgName)) {
                // If the package is an active admin or exempt role, don't restrict it.
                if (activeAdmins.contains(pkgName) || exemptRolePkgs.contains(pkgName)) {
                    excludedPkgs.add(pkgName);
                    continue;
                }
@@ -21839,8 +21866,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     */
    @Nullable
    private String getRoleHolderPackageNameOnUser(String role, int userId) {
        RoleManager roleManager = mContext.getSystemService(RoleManager.class);
        // Clear calling identity as the RoleManager APIs require privileged permissions.
        return mInjector.binderWithCleanCallingIdentity(() -> {
            List<UserInfo> users;
@@ -21852,7 +21877,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
            }
            for (UserInfo user : users) {
                List<String> roleHolders =
                        roleManager.getRoleHoldersAsUser(role, user.getUserHandle());
                        mInjector.roleManagerGetRoleHoldersAsUser(role, user.getUserHandle());
                if (!roleHolders.isEmpty()) {
                    return roleHolders.get(0);
                }
+6 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ import com.android.server.wm.ActivityTaskManagerInternal;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
@@ -324,6 +325,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
            return services.userManagerForMock.isHeadlessSystemUserMode();
        }

        @Override
        List<String> roleManagerGetRoleHoldersAsUser(String role, UserHandle userHandle) {
            return services.roleManagerForMock.getRoleHoldersAsUser(role, userHandle);
        }

        @Override
        PendingIntent pendingIntentGetActivityAsUser(Context context, int requestCode,
                Intent intent, int flags, Bundle options, UserHandle user) {
+47 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ import android.app.admin.PasswordMetrics;
import android.app.admin.PreferentialNetworkServiceConfig;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.WifiSsidPolicy;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -2888,6 +2889,52 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(CALLER_USER_HANDLE));
    }

    @Test
    public void testSetMeteredDataDisabledPackagesExemptRoles() throws Exception {
        // TODO(b/362545319): reference role name from role manager once it's exposed.
        final String controllerRole = "android.app.role.SYSTEM_FINANCED_DEVICE_CONTROLLER";

        setAsProfileOwner(admin1);

        assertThat(dpm.getMeteredDataDisabledPackages(admin1)).isEmpty();

        // Setup
        final ArrayList<String> pkgsToRestrict = new ArrayList<>();
        final ArrayList<String> pkgsExpectedAsNotRestricted = new ArrayList<>();
        final String packageWithControllerRole = "com.example.controller";
        final String packageWithKioskRole = "com.example.kiosk";
        final String packageWithNotExemptRole = "com.example.notexempt";

        pkgsToRestrict.add(packageWithControllerRole);
        pkgsToRestrict.add(packageWithKioskRole);
        pkgsToRestrict.add(packageWithNotExemptRole);

        pkgsExpectedAsNotRestricted.add(packageWithControllerRole);
        pkgsExpectedAsNotRestricted.add(packageWithKioskRole);

        setupPackageInPackageManager(packageWithControllerRole, CALLER_USER_HANDLE, 123, 0);
        setupPackageInPackageManager(packageWithKioskRole, CALLER_USER_HANDLE, 456, 0);
        setupPackageInPackageManager(packageWithNotExemptRole, CALLER_USER_HANDLE, 789, 0);

        when(getServices().roleManagerForMock.getRoleHoldersAsUser(controllerRole,
                UserHandle.of(CALLER_USER_HANDLE)))
                .thenReturn(new ArrayList<>(Arrays.asList(packageWithControllerRole)));
        when(getServices().roleManagerForMock.getRoleHoldersAsUser(
                RoleManager.ROLE_FINANCED_DEVICE_KIOSK,
                UserHandle.of(CALLER_USER_HANDLE)))
                .thenReturn(new ArrayList<>(Arrays.asList(packageWithKioskRole)));

        List<String> excludedPkgs = dpm.setMeteredDataDisabledPackages(admin1, pkgsToRestrict);

        // Verify
        assertThat(excludedPkgs).containsExactlyElementsIn(pkgsExpectedAsNotRestricted);
        assertThat(dpm.getMeteredDataDisabledPackages(admin1))
                .isEqualTo(Arrays.asList(packageWithNotExemptRole));
        verify(getServices().networkPolicyManagerInternal).setMeteredRestrictedPackages(
                MockUtils.checkApps(packageWithNotExemptRole),
                eq(CALLER_USER_HANDLE));
    }

    @Test
    public void testSetGetMeteredDataDisabledPackages_deviceAdmin() {
        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+8 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ public class MockSystemServices {
    public final DevicePolicyManager devicePolicyManager;
    public final LocationManager locationManager;
    public final RoleManager roleManager;
    public final RoleManagerForMock roleManagerForMock;
    public final SubscriptionManager subscriptionManager;
    /** Note this is a partial mock, not a real mock. */
    public final PackageManager packageManager;
@@ -200,6 +201,7 @@ public class MockSystemServices {
        devicePolicyManager = mock(DevicePolicyManager.class);
        locationManager = mock(LocationManager.class);
        roleManager = realContext.getSystemService(RoleManager.class);
        roleManagerForMock = mock(RoleManagerForMock.class);
        subscriptionManager = mock(SubscriptionManager.class);

        // Package manager is huge, so we use a partial mock instead.
@@ -495,6 +497,12 @@ public class MockSystemServices {
        }
    }

    public static class RoleManagerForMock {
        public List<String> getRoleHoldersAsUser(String role, UserHandle userHandle) {
            return new ArrayList<>();
        }
    }

    public static class SettingsForMock {
        public int settingsSecureGetIntForUser(String name, int def, int userHandle) {
            return 0;