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

Commit 5b9f0657 authored by Sudheer Shanka's avatar Sudheer Shanka Committed by Android (Google) Code Review
Browse files

Merge "Update DPMS to push active admins info to UsageStatsService."

parents fdb4c48c 101c353a
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
@@ -96,6 +96,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);
        }
@@ -11163,6 +11210,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