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

Commit 101c353a authored by Sudheer Shanka's avatar Sudheer Shanka
Browse files

Update DPMS to push active admins info to UsageStatsService.

Bug: 71710099
Test: atest services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
Test: atest services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Change-Id: Ia46be9008470b0228978306b9992560fc4f2c586
parent d5a6d9b8
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.res.Configuration;

import java.util.List;
import java.util.Set;

/**
 * UsageStatsManager local system service interface.
@@ -158,6 +159,22 @@ public abstract class UsageStatsManagerInternal {
     */
    public abstract void applyRestoredPayload(@UserIdInt int userId, String key, byte[] payload);

    /**
     * Called by DevicePolicyManagerService to inform that a new admin has been added.
     *
     * @param packageName the package in which the admin component is part of.
     * @param userId the userId in which the admin has been added.
     */
    public abstract void onActiveAdminAdded(String packageName, int userId);

    /**
     * Called by DevicePolicyManagerService to inform about the active admins in an user.
     *
     * @param adminApps the set of active admins in {@param userId} or null if there are none.
     * @param userId the userId to which the admin apps belong.
     */
    public abstract void setActiveAdminApps(Set<String> adminApps, int userId);

    /**
     * Return usage stats.
     *
+6 −0
Original line number Diff line number Diff line
@@ -37,6 +37,12 @@ import java.util.List;
 * should be added here to avoid build breakage in downstream branches.
 */
abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
    /**
     * To be called by {@link DevicePolicyManagerService#Lifecycle} when the service is started.
     *
     * @see {@link SystemService#onStart}.
     */
    abstract void handleStart();
    /**
     * To be called by {@link DevicePolicyManagerService#Lifecycle} during the various boot phases.
     *
+50 −2
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -401,6 +402,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    final IPackageManager mIPackageManager;
    final UserManager mUserManager;
    final UserManagerInternal mUserManagerInternal;
    final UsageStatsManagerInternal mUsageStatsManagerInternal;
    final TelephonyManager mTelephonyManager;
    private final LockPatternUtils mLockPatternUtils;
    private final DevicePolicyConstants mConstants;
@@ -504,6 +506,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        @Override
        public void onStart() {
            publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
            mService.handleStart();
        }
        @Override
@@ -1560,6 +1563,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                            removedAdmin = true;
                            policy.mAdminList.remove(i);
                            policy.mAdminMap.remove(aa.info.getComponent());
                            pushActiveAdminPackagesLocked(userHandle);
                        }
                    }
                } catch (RemoteException re) {
@@ -1653,6 +1657,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            return LocalServices.getService(PackageManagerInternal.class);
        }
        UsageStatsManagerInternal getUsageStatsManagerInternal() {
            return LocalServices.getService(UsageStatsManagerInternal.class);
        }
        NotificationManager getNotificationManager() {
            return mContext.getSystemService(NotificationManager.class);
        }
@@ -1923,6 +1931,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        mUserManager = Preconditions.checkNotNull(injector.getUserManager());
        mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
        mUsageStatsManagerInternal = Preconditions.checkNotNull(
                injector.getUsageStatsManagerInternal());
        mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
        mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());
@@ -3189,6 +3199,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    @Override
    void handleStart() {
        pushActiveAdminPackages();
    }
    @Override
    void handleStartUser(int userId) {
        updateScreenCaptureDisabledInWindowManager(userId,
@@ -3357,6 +3372,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                if (replaceIndex == -1) {
                    policy.mAdminList.add(newAdmin);
                    enableIfNecessary(info.getPackageName(), userHandle);
                    mUsageStatsManagerInternal.onActiveAdminAdded(
                            adminReceiver.getPackageName(), userHandle);
                } else {
                    policy.mAdminList.set(replaceIndex, newAdmin);
                }
@@ -3369,6 +3386,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    private void pushActiveAdminPackages() {
        synchronized (this) {
            final List<UserInfo> users = mUserManager.getUsers();
            for (int i = users.size() - 1; i >= 0; --i) {
                final int userId = users.get(i).id;
                mUsageStatsManagerInternal.setActiveAdminApps(
                        getActiveAdminPackagesLocked(userId), userId);
            }
        }
    }
    private void pushActiveAdminPackagesLocked(int userId) {
        mUsageStatsManagerInternal.setActiveAdminApps(
                getActiveAdminPackagesLocked(userId), userId);
    }
    private Set<String> getActiveAdminPackagesLocked(int userId) {
        final DevicePolicyData policy = getUserData(userId);
        Set<String> adminPkgs = null;
        for (int i = policy.mAdminList.size() - 1; i >= 0; --i) {
            final String pkgName = policy.mAdminList.get(i).info.getPackageName();
            if (adminPkgs == null) {
                adminPkgs = new ArraySet<>();
            }
            adminPkgs.add(pkgName);
        }
        return adminPkgs;
    }
    private void transferActiveAdminUncheckedLocked(ComponentName incomingReceiver,
            ComponentName outgoingReceiver, int userHandle) {
        final DevicePolicyData policy = getUserData(userHandle);
@@ -3487,6 +3533,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
    }
    @Override
    public void forceRemoveActiveAdmin(ComponentName adminReceiver, int userHandle) {
        if (!mHasFeature) {
            return;
@@ -3540,7 +3587,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    private boolean isPackageTestOnly(String packageName, int userHandle) {
        final ApplicationInfo ai;
        try {
            ai = mIPackageManager.getApplicationInfo(packageName,
            ai = mInjector.getIPackageManager().getApplicationInfo(packageName,
                    (PackageManager.MATCH_DIRECT_BOOT_AWARE
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle);
        } catch (RemoteException e) {
@@ -3562,7 +3609,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
    }
    private void enforceShell(String method) {
        final int callingUid = Binder.getCallingUid();
        final int callingUid = mInjector.binderGetCallingUid();
        if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
            throw new SecurityException("Non-shell user attempted to call " + method);
        }
@@ -11140,6 +11187,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            if (doProxyCleanup) {
                resetGlobalProxyLocked(policy);
            }
            pushActiveAdminPackagesLocked(userHandle);
            saveSettingsLocked(userHandle);
            updateMaximumTimeToLockLocked(userHandle);
            policy.mRemovingAdmins.remove(adminReceiver);
+6 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.app.IActivityManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.backup.IBackupManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
@@ -151,6 +152,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
            return services.userManagerInternal;
        }

        @Override
        UsageStatsManagerInternal getUsageStatsManagerInternal() {
            return services.usageStatsManagerInternal;
        }

        @Override
        PackageManagerInternal getPackageManagerInternal() {
            return services.packageManagerInternal;
+135 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
@@ -90,6 +91,7 @@ import com.android.server.pm.UserRestrictionsUtils;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

@@ -182,6 +184,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {

        initializeDpms();

        Mockito.reset(getServices().usageStatsManagerInternal);
        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
        setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -207,6 +210,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);

        dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
        dpms.handleStart();
        dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
        dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);

@@ -278,6 +282,32 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
    }

    public void testHandleStart() throws Exception {
        // Device owner in SYSTEM_USER
        setDeviceOwner();
        // Profile owner in CALLER_USER_HANDLE
        setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
        setAsProfileOwner(admin2);
        // Active admin in CALLER_USER_HANDLE
        final int ANOTHER_UID = UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, 1306);
        setUpPackageManagerForFakeAdmin(adminAnotherPackage, ANOTHER_UID, admin2);
        dpm.setActiveAdmin(adminAnotherPackage, /* replace =*/ false,
                DpmMockContext.CALLER_USER_HANDLE);
        assertTrue(dpm.isAdminActiveAsUser(adminAnotherPackage,
                DpmMockContext.CALLER_USER_HANDLE));

        initializeDpms();

        // Verify
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkAdminApps(admin1.getPackageName()),
                eq(UserHandle.USER_SYSTEM));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkAdminApps(admin2.getPackageName(),
                        adminAnotherPackage.getPackageName()),
                eq(DpmMockContext.CALLER_USER_HANDLE));
    }

    /**
     * Caller doesn't have proper permissions.
     */
@@ -330,6 +360,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(DpmMockContext.CALLER_USER_HANDLE),
                anyString());

        verify(getServices().usageStatsManagerInternal).onActiveAdminAdded(
                admin1.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);

        // TODO Verify other calls too.

        // Make sure it's active admin1.
@@ -369,6 +402,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(DpmMockContext.CALLER_USER_HANDLE),
                anyString());

        // times(2) because it was previously called for admin1 which is in the same package
        // as admin2.
        verify(getServices().usageStatsManagerInternal, times(2)).onActiveAdminAdded(
                admin2.getPackageName(), DpmMockContext.CALLER_USER_HANDLE);

        // 4. Add the same admin1 again without replace, which should throw.
        assertExpectException(IllegalArgumentException.class, /* messageRegex= */ null,
                () -> dpm.setActiveAdmin(admin1, /* replace =*/ false));
@@ -384,6 +422,10 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        assertEquals(admin1, admins.get(0));
        assertEquals(admin2, admins.get(1));

        // There shouldn't be any callback to UsageStatsManagerInternal when the admin is being
        // replaced
        verifyNoMoreInteractions(getServices().usageStatsManagerInternal);

        // Another user has no admins.
        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");

@@ -516,6 +558,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                () -> dpm.removeActiveAdmin(admin1));

        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal, times(0)).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);

        // 2. User unlocked.
        when(getServices().userManager.isUserUnlocked(eq(DpmMockContext.CALLER_USER_HANDLE)))
@@ -523,6 +567,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {

        dpm.removeActiveAdmin(admin1);
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);
    }

    /**
@@ -547,6 +593,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {

        dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);

        // TODO DO Still can't be removed in this case.
    }
@@ -588,6 +636,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                isNull(Bundle.class));

        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
@@ -598,6 +648,86 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        // TODO Check other internal calls.
    }

    public void testRemoveActiveAdmin_multipleAdminsInUser() {
        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin1.
        dpm.setActiveAdmin(admin1, /* replace =*/ false);

        assertTrue(dpm.isAdminActive(admin1));
        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        // Add admin2.
        dpm.setActiveAdmin(admin2, /* replace =*/ false);

        assertTrue(dpm.isAdminActive(admin2));
        assertFalse(dpm.isRemovingAdmin(admin2, DpmMockContext.CALLER_USER_HANDLE));

        // Broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));

        // Remove.  No permissions, but same user, so it'll work.
        mContext.callerPermissions.clear();
        dpm.removeActiveAdmin(admin1);

        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
                isNull(String.class),
                any(BroadcastReceiver.class),
                eq(dpms.mHandler),
                eq(Activity.RESULT_OK),
                isNull(String.class),
                isNull(Bundle.class));

        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                MockUtils.checkAdminApps(admin2.getPackageName()),
                eq(DpmMockContext.CALLER_USER_HANDLE));

        // Again broadcast from saveSettingsLocked().
        verify(mContext.spiedContext, times(3)).sendBroadcastAsUser(
                MockUtils.checkIntentAction(
                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
    }

    /**
     * Test for:
     * {@link DevicePolicyManager#forceRemoveActiveAdmin(ComponentName, int)}
     */
    public void testForceRemoveActiveAdmin() throws Exception {
        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);

        // Add admin.
        setupPackageInPackageManager(admin1.getPackageName(),
                /* userId= */ DpmMockContext.CALLER_USER_HANDLE,
                /* appId= */ 10138,
                /* flags= */ ApplicationInfo.FLAG_TEST_ONLY);
        dpm.setActiveAdmin(admin1, /* replace =*/ false);
        assertTrue(dpm.isAdminActive(admin1));

        // Calling from a non-shell uid should fail with a SecurityException
        mContext.binder.callingUid = 123456;
        assertExpectException(SecurityException.class,
                /* messageRegex =*/ "Non-shell user attempted to call",
                () -> dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));

        mContext.binder.callingUid = Process.SHELL_UID;
        dpms.forceRemoveActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);

        mContext.callerPermissions.add(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL);
        // Verify
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);
    }

    /**
     * Test for: @{link DevicePolicyManager#setActivePasswordState}
     *
@@ -954,6 +1084,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
                eq(null),
                eq(true), eq(CAMERA_NOT_DISABLED));

        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, UserHandle.USER_SYSTEM);

        assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));

        // ACTION_DEVICE_OWNER_CHANGED should be sent twice, once for setting the device owner
@@ -1044,6 +1177,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        // Check
        assertFalse(dpm.isProfileOwnerApp(admin1.getPackageName()));
        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE));
        verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
                null, DpmMockContext.CALLER_USER_HANDLE);
    }

    public void testSetProfileOwner_failures() throws Exception {
Loading