Merge "Enforce DevicePolicyManager.setUserControlDisabledPackages in AppStandbyController" into rvc-dev am: b4083e039e

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22301867

Change-Id: Ibf1c9fb61e6b987d2b5676ab8eb193d96e70515d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
index e15f0f3..0e98bf0 100644
--- a/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/usage/AppStandbyInternal.java
@@ -146,6 +146,8 @@
 
     void setActiveAdminApps(Set<String> adminPkgs, int userId);
 
+    void setAdminProtectedPackages(Set<String> packageNames, int userId);
+
     void onAdminDataAvailable();
 
     void clearCarrierPrivilegedApps();
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 36ccaf9..403e8b5 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -233,6 +233,10 @@
     @GuardedBy("mActiveAdminApps")
     private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
 
+    /** List of admin protected packages. Can contain {@link android.os.UserHandle#USER_ALL}. */
+    @GuardedBy("mAdminProtectedPackages")
+    private final SparseArray<Set<String>> mAdminProtectedPackages = new SparseArray<>();
+
     /**
      * Set of system apps that are headless (don't have any declared activities, enabled or
      * disabled). Presence in this map indicates that the app is a headless system app.
@@ -1019,6 +1023,9 @@
             synchronized (mActiveAdminApps) {
                 mActiveAdminApps.remove(userId);
             }
+            synchronized (mAdminProtectedPackages) {
+                mAdminProtectedPackages.remove(userId);
+            }
         }
     }
 
@@ -1108,6 +1115,10 @@
                 return STANDBY_BUCKET_EXEMPTED;
             }
 
+            if (isAdminProtectedPackages(packageName, userId)) {
+                return STANDBY_BUCKET_EXEMPTED;
+            }
+
             if (isActiveNetworkScorer(packageName)) {
                 return STANDBY_BUCKET_EXEMPTED;
             }
@@ -1510,6 +1521,17 @@
         }
     }
 
+    private boolean isAdminProtectedPackages(String packageName, int userId) {
+        synchronized (mAdminProtectedPackages) {
+            if (mAdminProtectedPackages.contains(UserHandle.USER_ALL)
+                    && mAdminProtectedPackages.get(UserHandle.USER_ALL).contains(packageName)) {
+                return true;
+            }
+            return mAdminProtectedPackages.contains(userId)
+                    && mAdminProtectedPackages.get(userId).contains(packageName);
+        }
+    }
+
     @Override
     public void addActiveDeviceAdmin(String adminPkg, int userId) {
         synchronized (mActiveAdminApps) {
@@ -1534,6 +1556,17 @@
     }
 
     @Override
+    public void setAdminProtectedPackages(Set<String> packageNames, int userId) {
+        synchronized (mAdminProtectedPackages) {
+            if (packageNames == null || packageNames.isEmpty()) {
+                mAdminProtectedPackages.remove(userId);
+            } else {
+                mAdminProtectedPackages.put(userId, packageNames);
+            }
+        }
+    }
+
+    @Override
     public void onAdminDataAvailable() {
         mAdminDataAvailableLatch.countDown();
     }
@@ -1555,6 +1588,13 @@
         }
     }
 
+    @VisibleForTesting
+    Set<String> getAdminProtectedPackagesForTest(int userId) {
+        synchronized (mAdminProtectedPackages) {
+            return mAdminProtectedPackages.get(userId);
+        }
+    }
+
     /**
      * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
      * returns {@code false}.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 92578dc9f..ee82555 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -11996,7 +11996,8 @@
 
     /**
      * Called by Device owner to disable user control over apps. User will not be able to clear
-     * app data or force-stop packages.
+     * app data or force-stop packages. Packages with user control disabled are exempted from
+     * App Standby Buckets.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
      * @param packages The package names for the apps.
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index fa84427..920fe1b 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -199,6 +199,16 @@
     public abstract void setActiveAdminApps(Set<String> adminApps, int userId);
 
     /**
+     * Called by DevicePolicyManagerService to inform about the protected packages for a user.
+     * User control will be disabled for protected packages.
+     *
+     * @param packageNames the set of protected packages for {@code userId}.
+     * @param userId the userId to which the protected packages belong.
+     */
+    public abstract void setAdminProtectedPackages(@Nullable Set<String> packageNames,
+            @UserIdInt int userId);
+
+    /**
      * Called by DevicePolicyManagerService during boot to inform that admin data is loaded and
      * pushed to UsageStatsService.
      */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index e405771..3ca8ffb 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4021,7 +4021,9 @@
         updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
         updateLockTaskFeaturesLocked(policy.mLockTaskFeatures, userHandle);
-        updateUserControlDisabledPackagesLocked(policy.mUserControlDisabledPackages);
+        if (userHandle == UserHandle.USER_SYSTEM) {
+            updateUserControlDisabledPackagesLocked(policy.mUserControlDisabledPackages);
+        }
         if (policy.mStatusBarDisabled) {
             setStatusBarDisabledInternal(policy.mStatusBarDisabled, userHandle);
         }
@@ -4049,6 +4051,8 @@
 
     private void updateUserControlDisabledPackagesLocked(List<String> packages) {
         mInjector.getPackageManagerInternal().setDeviceOwnerProtectedPackages(packages);
+        mUsageStatsManagerInternal.setAdminProtectedPackages(
+                new ArraySet(packages), UserHandle.USER_ALL);
     }
 
     private void updateLockTaskFeaturesLocked(int flags, int userId) {
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 1ced467..8da4fed 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -125,6 +125,9 @@
     private static final String ADMIN_PKG2 = "com.android.admin2";
     private static final String ADMIN_PKG3 = "com.android.admin3";
 
+    private static final String ADMIN_PROTECTED_PKG = "com.android.admin.protected";
+    private static final String ADMIN_PROTECTED_PKG2 = "com.android.admin.protected2";
+
     private static final long MINUTE_MS = 60 * 1000;
     private static final long HOUR_MS = 60 * MINUTE_MS;
     private static final long DAY_MS = 24 * HOUR_MS;
@@ -1370,6 +1373,19 @@
     }
 
     @Test
+    public void testSetAdminProtectedPackages() {
+        assertAdminProtectedPackagesForTest(USER_ID, (String[]) null);
+        assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null);
+
+        setAdminProtectedPackages(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2);
+        assertAdminProtectedPackagesForTest(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2);
+        assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null);
+
+        setAdminProtectedPackages(USER_ID, (String[]) null);
+        assertAdminProtectedPackagesForTest(USER_ID, (String[]) null);
+    }
+
+    @Test
     public void testUserInteraction_CrossProfile() throws Exception {
         mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
         mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
@@ -1593,6 +1609,28 @@
         mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
     }
 
+    private void setAdminProtectedPackages(int userId, String... packageNames) {
+        Set<String> adminProtectedPackages = packageNames != null ? new ArraySet<>(
+                Arrays.asList(packageNames)) : null;
+        mController.setAdminProtectedPackages(adminProtectedPackages, userId);
+    }
+
+    private void assertAdminProtectedPackagesForTest(int userId, String... packageNames) {
+        final Set<String> actualAdminProtectedPackages =
+                mController.getAdminProtectedPackagesForTest(userId);
+        if (packageNames == null) {
+            if (actualAdminProtectedPackages != null && !actualAdminProtectedPackages.isEmpty()) {
+                fail("Admin protected packages should be null; " + getAdminAppsStr(userId,
+                        actualAdminProtectedPackages));
+            }
+            return;
+        }
+        assertEquals(packageNames.length, actualAdminProtectedPackages.size());
+        for (String adminProtectedPackage : packageNames) {
+            assertTrue(actualAdminProtectedPackages.contains(adminProtectedPackage));
+        }
+    }
+
     private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception {
         rearmLatch(pkg);
         mController.setAppStandbyBucket(pkg, user, bucket, reason);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a54f263..c0b3fee 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2303,6 +2303,11 @@
         }
 
         @Override
+        public void setAdminProtectedPackages(Set<String> packageNames, int userId) {
+            mAppStandby.setAdminProtectedPackages(packageNames, userId);
+        }
+
+        @Override
         public void onAdminDataAvailable() {
             mAppStandby.onAdminDataAvailable();
         }