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

Commit d6e2a91c authored by Felipe Leme's avatar Felipe Leme
Browse files

Fixed UMS.getDevicePolicyManagerInternal() usage.

It can be null (on devices that doesn't define the device_admin
feature)

Test: atest FrameworksMockingServicesTests --test-filter=".*UserManagerServiceMockedTest.testGetApplicationRestrictionsForUser.*"
Fixes: 428867650
Flag: EXEMPT (trivial bug fix)

Change-Id: I8f9be08f2d7ab9e6d68e2345fad5d169e89dbf35
parent c787bd61
Loading
Loading
Loading
Loading
+49 −21
Original line number Diff line number Diff line
@@ -1926,8 +1926,17 @@ public class UserManagerService extends IUserManager.Stub {
        availabilityIntent.putExtra(Intent.EXTRA_USER_HANDLE,
                profileInfo.getUserHandle().getIdentifier());
        if (profileInfo.isManagedProfile()) {
            getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers(
                    availabilityIntent, parentHandle, /* requiresPermission= */ true);
            var dpmi = getDevicePolicyManagerInternal();
            if (dpmi == null) {
                // This should never happen because the profile is a managed profile, but it doesn't
                // hurt to check...
                Slogf.wtf(LOG_TAG, "broadcastProfileAvailabilityChanges(profile=%s, parent=%s): "
                        + "not calling dmpi.broadcastIntentToManifestReceivers() because dpmi is "
                        + "null", profileInfo, parentHandle);
            } else {
                dpmi.broadcastIntentToManifestReceivers(availabilityIntent, parentHandle,
                    /* requiresPermission= */ true);
            }
        }
        availabilityIntent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -3229,7 +3238,8 @@ public class UserManagerService extends IUserManager.Stub {
                return false;
            }
        }
        return !getDevicePolicyManagerInternal().isUserOrganizationManaged(userId);
        var dpmi = getDevicePolicyManagerInternal();
        return dpmi == null || !dpmi.isUserOrganizationManaged(userId);
    }

    @Override
@@ -7314,13 +7324,22 @@ public class UserManagerService extends IUserManager.Stub {
        mContext.sendBroadcastAsUser(intent, parentHandle, /* receiverPermission= */null);
    }

    private void sendManagedProfileRemovedBroadcast(int parentUserId, int removedUserId) {
    private void sendManagedProfileRemovedBroadcast(@UserIdInt int parentUserId,
            @UserIdInt int removedUserId) {
        var dpmi = getDevicePolicyManagerInternal();
        if (dpmi == null) {
            // This should never happen (because current caller checks if removed used is of type
            // UserManager.USER_TYPE_PROFILE_MANAGED), but it doesn't hurt to check...
            Slogf.wtf(LOG_TAG, "sendManagedProfileRemovedBroadcast(parent=%d, removed=%d): ignoring"
                    + " as device doesn't have DPMI", parentUserId, removedUserId);
            return;
        }
        Intent managedProfileIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED);
        managedProfileIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(removedUserId));
        managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId);
        final UserHandle parentHandle = UserHandle.of(parentUserId);
        getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers(
                managedProfileIntent, parentHandle, /* requiresPermission= */ false);
        dpmi.broadcastIntentToManifestReceivers(managedProfileIntent, parentHandle,
                /* requiresPermission= */ false);
        managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                | Intent.FLAG_RECEIVER_FOREGROUND);
        mContext.sendBroadcastAsUser(managedProfileIntent, parentHandle,
@@ -7338,25 +7357,29 @@ public class UserManagerService extends IUserManager.Stub {
                || !UserHandle.isSameApp(Binder.getCallingUid(), getUidForPackage(packageName))) {
            checkSystemOrRoot("get application restrictions for other user/app " + packageName);
        }

        if (android.app.admin.flags.Flags.appRestrictionsCoexistence()) {
            List<Bundle> restrictions =
                    getDevicePolicyManagerInternal().getApplicationRestrictionsPerAdminForUser(
                            packageName, userId);
            if (restrictions.isEmpty()) {
            List<Bundle> restrictions = null;
            var dpmi = getDevicePolicyManagerInternal();
            if (dpmi != null) {
                restrictions = dpmi.getApplicationRestrictionsPerAdminForUser(packageName, userId);
            }
            if (restrictions == null || restrictions.isEmpty()) {
                return Bundle.EMPTY;
            } else {
                if (restrictions.size() > 1) {
                    Slog.w(LOG_TAG, "Application restriction list contains more than one element.");
            }
            int size = restrictions.size();
            if (size > 1) {
                Slogf.w(LOG_TAG, "Application restriction list contains more than one (%d) element;"
                        + " returning first", size);
            }
            return restrictions.getFirst();
        }
        } else {

        synchronized (mAppRestrictionsLock) {
            // Read the restrictions from XML
            return readApplicationRestrictionsLAr(packageName, userId);
        }
    }
    }

    @Override
    public void setApplicationRestrictions(String packageName, Bundle restrictions,
@@ -8961,8 +8984,13 @@ public class UserManagerService extends IUserManager.Stub {
        return mPmInternal;
    }

    /** Returns the internal device policy manager interface. */
    private DevicePolicyManagerInternal getDevicePolicyManagerInternal() {
    /**
     * Returns the internal device policy manager interface.
     *
     * <p>NOTE: it's {@code null} when the device doesn't have the
     * {@code android.software.device_admin} feature.
     */
    private @Nullable DevicePolicyManagerInternal getDevicePolicyManagerInternal() {
        if (mDevicePolicyManagerInternal == null) {
            mDevicePolicyManagerInternal =
                    LocalServices.getService(DevicePolicyManagerInternal.class);
+72 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
 */
package com.android.server.pm;

import static android.app.admin.flags.Flags.FLAG_APP_RESTRICTIONS_COEXISTENCE;
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_EMBEDDED;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
@@ -71,10 +72,12 @@ import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.KeyguardManager;
import android.app.PropertyInvalidatedCache;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.ServiceSpecificException;
import android.os.SystemProperties;
@@ -206,6 +209,7 @@ public final class UserManagerServiceMockedTest {
    private @Mock StorageManager mStorageManager;
    private @Mock LockSettingsInternal mLockSettingsInternal;
    private @Mock PackageManagerInternal mPackageManagerInternal;
    private @Mock DevicePolicyManagerInternal mDevicePolicyManagerInternal;
    private @Mock KeyguardManager mKeyguardManager;
    private @Mock PowerManager mPowerManager;
    private @Mock TelecomManager mTelecomManager;
@@ -1580,7 +1584,7 @@ public final class UserManagerServiceMockedTest {
    @EnableFlags(FLAG_DEMOTE_MAIN_USER)
    public void testSetMainUser_userNotFound() {
        assumeDoesntHaveMainUser();
        int userId = 666;
        int userId = OTHER_USER_ID;

        expect.withMessage("setMainUser(%s)", userId).that(mUms.setMainUser(userId)).isFalse();

@@ -1870,6 +1874,62 @@ public final class UserManagerServiceMockedTest {
        assertThat(mUsers.get(USER_ID).info.isAdmin()).isTrue();
    }

    // NOTE: tests for getApplicationRestrictionsForUser were added to check when DPMI is null, so
    // they don't encompass all scenarios (like when FLAG_APP_RESTRICTIONS_COEXISTENCE is not set)

    @Test
    public void testGetApplicationRestrictionsForUser_invalidUser() {
        mockCallingUserId(USER_ID);

        assertThrows(SecurityException.class, () -> mUms
                .getApplicationRestrictionsForUser(mRealContext.getPackageName(), OTHER_USER_ID));
    }

    @Test
    public void testGetApplicationRestrictionsForUser_differentPackage() {
        // Should throw because it's not the same as the calling uid package
        assertThrows(SecurityException.class,
                () -> mUms.getApplicationRestrictions("Age, the name is Pack Age"));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_APP_RESTRICTIONS_COEXISTENCE)
    public void testGetApplicationRestrictionsForUser_flagEnabled_noDPMI() {
        mockGetLocalService(DevicePolicyManagerInternal.class, null);

        var result = mUms.getApplicationRestrictions(mRealContext.getPackageName());

        assertThat(result).isSameInstanceAs(Bundle.EMPTY);
    }

    @Test
    @RequiresFlagsEnabled(FLAG_APP_RESTRICTIONS_COEXISTENCE)
    public void testGetApplicationRestrictionsForUser_flagEnabled_noRestrictions() {
        String pkg = mRealContext.getPackageName();
        mockCallingUserId(USER_ID);
        mockDpmiGetApplicationRestrictionsPerAdminForUser(pkg, USER_ID);
        mockGetLocalService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);

        var result = mUms.getApplicationRestrictions(pkg);

        assertThat(result).isSameInstanceAs(Bundle.EMPTY);
    }

    @Test
    @RequiresFlagsEnabled(FLAG_APP_RESTRICTIONS_COEXISTENCE)
    public void testGetApplicationRestrictionsForUser_flagEnabled_multipleRestrictions() {
        String pkg = mRealContext.getPackageName();
        Bundle bundle1 = new Bundle();
        Bundle bundle2 = new Bundle();
        mockCallingUserId(USER_ID);
        mockDpmiGetApplicationRestrictionsPerAdminForUser(pkg, USER_ID, bundle1, bundle2);
        mockGetLocalService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);

        var result = mUms.getApplicationRestrictions(pkg);

        assertThat(result).isSameInstanceAs(bundle1);
    }

    /**
     * Returns true if the user's XML file has Default restrictions
     * @param userId Id of the user.
@@ -2024,6 +2084,17 @@ public final class UserManagerServiceMockedTest {
        doReturn(userId).when(UserHandle::getCallingUserId);
    }

    private void mockDpmiGetApplicationRestrictionsPerAdminForUser(String pkgName,
            @UserIdInt int userId, Bundle...bundles) {
        List<Bundle> list = Arrays.asList(bundles);

        Log.d(TAG, "mockDpmiGetApplicationRestrictionsPerAdminForAnyUser(" + pkgName
                + ", " + userId + "): will return " + list);
        when(mDevicePolicyManagerInternal
                .getApplicationRestrictionsPerAdminForUser(pkgName, userId))
                        .thenReturn(list);
    }

    private void expectUserJourneyLogged(@UserIdInt int userId, @UserJourney int journey) {
        verify(mUserJourneyLogger).logUserJourneyBegin(userId, journey);
    }