Load admin data in DPMS asynchronously during boot.
Bug: 71902030
Bug: 71710099
Test: atest services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Test: Ran boot tests - go/run-boottest
Test: manual
Change-Id: I34970c6f41877c7e3ece4843d47831374d455067
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 5cd0981..bd978e3 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -176,6 +176,12 @@
public abstract void setActiveAdminApps(Set<String> adminApps, int userId);
/**
+ * Called by DevicePolicyManagerService during boot to inform that admin data is loaded and
+ * pushed to UsageStatsService.
+ */
+ public abstract void onAdminDataAvailable();
+
+ /**
* Return usage stats.
*
* @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
diff --git a/core/java/com/android/internal/util/ConcurrentUtils.java b/core/java/com/android/internal/util/ConcurrentUtils.java
index e35f9f4..e08eb58 100644
--- a/core/java/com/android/internal/util/ConcurrentUtils.java
+++ b/core/java/com/android/internal/util/ConcurrentUtils.java
@@ -18,11 +18,13 @@
import android.os.Process;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -86,4 +88,27 @@
}
}
+ /**
+ * Waits for {@link CountDownLatch#countDown()} to be called on the {@param countDownLatch}.
+ * <p>If {@link CountDownLatch#countDown()} doesn't occur within {@param timeoutMs}, this
+ * method will throw {@code IllegalStateException}
+ * <p>If {@code InterruptedException} occurs, this method will interrupt the current thread
+ * and throw {@code IllegalStateException}
+ *
+ * @param countDownLatch the CountDownLatch which {@link CountDownLatch#countDown()} is
+ * being waited on.
+ * @param timeoutMs the maximum time waited for {@link CountDownLatch#countDown()}
+ * @param description a short description of the operation
+ */
+ public static void waitForCountDownNoInterrupt(CountDownLatch countDownLatch, long timeoutMs,
+ String description) {
+ try {
+ if (!countDownLatch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
+ throw new IllegalStateException(description + " timed out.");
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(description + " interrupted.");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index e458f48..971ac8b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -66,4 +66,9 @@
* given network.
*/
public abstract long getSubscriptionOpportunisticQuota(Network network, int quotaType);
+
+ /**
+ * Informs that admin data is loaded and available.
+ */
+ public abstract void onAdminDataAvailable();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 96b06c2..e406d51 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -199,6 +199,7 @@
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -333,6 +334,11 @@
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+ /**
+ * Indicates the maximum wait time for admin data to be available;
+ */
+ private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
+
private static final int MSG_RULES_CHANGED = 1;
private static final int MSG_METERED_IFACES_CHANGED = 2;
private static final int MSG_LIMIT_REACHED = 5;
@@ -384,6 +390,8 @@
private final boolean mSuppressDefaultPolicy;
+ private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
+
/** Defined network policies. */
@GuardedBy("mNetworkPoliciesSecondLock")
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
@@ -672,6 +680,8 @@
mSystemReady = true;
+ waitForAdminData();
+
// read policy from disk
readPolicyAL();
@@ -4590,6 +4600,11 @@
return mSubscriptionOpportunisticQuota.get(getSubIdLocked(network));
}
}
+
+ @Override
+ public void onAdminDataAvailable() {
+ mAdminDataAvailableLatch.countDown();
+ }
}
private int parseSubId(NetworkState state) {
@@ -4617,6 +4632,16 @@
return ArrayUtils.isEmpty(plans) ? null : plans[0];
}
+ /**
+ * This will only ever be called once - during device boot.
+ */
+ private void waitForAdminData() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+ ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
+ WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
+ }
+ }
+
private static boolean hasRule(int uidRules, int rule) {
return (uidRules & rule) != 0;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 99275e8..7a0b1bf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -39,12 +39,6 @@
*/
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.
*
* @see {@link SystemService#onBootPhase}.
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 77b87b6..8d91288 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -198,8 +198,10 @@
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
+import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
+import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.UserRestrictionsUtils;
import com.google.android.collect.Sets;
@@ -511,7 +513,6 @@
@Override
public void onStart() {
publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
- mService.handleStart();
}
@Override
@@ -1743,6 +1744,10 @@
return LocalServices.getService(UsageStatsManagerInternal.class);
}
+ NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+ return LocalServices.getService(NetworkPolicyManagerInternal.class);
+ }
+
NotificationManager getNotificationManager() {
return mContext.getSystemService(NotificationManager.class);
}
@@ -1996,6 +2001,10 @@
KeyChainConnection keyChainBindAsUser(UserHandle user) throws InterruptedException {
return KeyChain.bindAsUser(mContext, user);
}
+
+ void postOnSystemServerInitThreadPool(Runnable runnable) {
+ SystemServerInitThreadPool.get().submit(runnable, LOG_TAG);
+ }
}
/**
@@ -3239,6 +3248,7 @@
switch (phase) {
case SystemService.PHASE_LOCK_SETTINGS_READY:
onLockSettingsReady();
+ loadAdminDataAsync();
break;
case SystemService.PHASE_BOOT_COMPLETED:
ensureDeviceOwnerUserStarted(); // TODO Consider better place to do this.
@@ -3307,11 +3317,6 @@
}
@Override
- void handleStart() {
- pushActiveAdminPackages();
- }
-
- @Override
void handleStartUser(int userId) {
updateScreenCaptureDisabledInWindowManager(userId,
getScreenCaptureDisabled(null, userId));
@@ -3493,6 +3498,14 @@
}
}
+ private void loadAdminDataAsync() {
+ mInjector.postOnSystemServerInitThreadPool(() -> {
+ pushActiveAdminPackages();
+ mUsageStatsManagerInternal.onAdminDataAvailable();
+ mInjector.getNetworkPolicyManagerInternal().onAdminDataAvailable();
+ });
+ }
+
private void pushActiveAdminPackages() {
synchronized (this) {
final List<UserInfo> users = mUserManager.getUsers();
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 5134f52..06f138b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -45,6 +45,7 @@
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.net.NetworkPolicyManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -159,6 +160,11 @@
}
@Override
+ NetworkPolicyManagerInternal getNetworkPolicyManagerInternal() {
+ return services.networkPolicyManagerInternal;
+ }
+
+ @Override
PackageManagerInternal getPackageManagerInternal() {
return services.packageManagerInternal;
}
@@ -438,5 +444,10 @@
KeyChain.KeyChainConnection keyChainBindAsUser(UserHandle user) {
return services.keyChainConnection;
}
+
+ @Override
+ void postOnSystemServerInitThreadPool(Runnable runnable) {
+ runnable.run();
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 1df0ff2..d26a3c7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -186,6 +186,7 @@
initializeDpms();
Mockito.reset(getServices().usageStatsManagerInternal);
+ Mockito.reset(getServices().networkPolicyManagerInternal);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -211,7 +212,6 @@
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
dpms = new DevicePolicyManagerServiceTestable(getServices(), mContext);
- dpms.handleStart();
dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
@@ -283,7 +283,7 @@
assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
}
- public void testHandleStart() throws Exception {
+ public void testLoadAdminData() throws Exception {
// Device owner in SYSTEM_USER
setDeviceOwner();
// Profile owner in CALLER_USER_HANDLE
@@ -307,6 +307,23 @@
MockUtils.checkAdminApps(admin2.getPackageName(),
adminAnotherPackage.getPackageName()),
eq(DpmMockContext.CALLER_USER_HANDLE));
+ verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
+ verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
+ }
+
+ public void testLoadAdminData_noAdmins() throws Exception {
+ final int ANOTHER_USER_ID = 15;
+ getServices().addUser(ANOTHER_USER_ID, 0);
+
+ initializeDpms();
+
+ // Verify
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, DpmMockContext.CALLER_USER_HANDLE);
+ verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
+ null, ANOTHER_USER_ID);
+ verify(getServices().usageStatsManagerInternal).onAdminDataAvailable();
+ verify(getServices().networkPolicyManagerInternal).onAdminDataAvailable();
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 268d424..0343a52 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -58,6 +58,7 @@
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
+import com.android.server.net.NetworkPolicyManagerInternal;
import java.io.File;
import java.io.IOException;
@@ -76,6 +77,7 @@
public final UserManager userManager;
public final UserManagerInternal userManagerInternal;
public final UsageStatsManagerInternal usageStatsManagerInternal;
+ public final NetworkPolicyManagerInternal networkPolicyManagerInternal;
public final PackageManagerInternal packageManagerInternal;
public final UserManagerForMock userManagerForMock;
public final PowerManagerForMock powerManager;
@@ -113,6 +115,8 @@
userManager = mock(UserManager.class);
userManagerInternal = mock(UserManagerInternal.class);
usageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
+ networkPolicyManagerInternal = mock(NetworkPolicyManagerInternal.class);
+
userManagerForMock = mock(UserManagerForMock.class);
packageManagerInternal = mock(PackageManagerInternal.class);
powerManager = mock(PowerManagerForMock.class);
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index ff3d586..6782188 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -78,6 +78,7 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
@@ -90,6 +91,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
/**
* Manages the standby state of an app, listening to various events.
@@ -128,6 +130,11 @@
// Expiration time for predicted bucket
private static final long PREDICTION_TIMEOUT = 12 * ONE_HOUR;
+ /**
+ * Indicates the maximum wait time for admin data to be available;
+ */
+ private static final long WAIT_FOR_ADMIN_DATA_TIMEOUT_MS = 10_000;
+
// To name the lock for stack traces
static class Lock {}
@@ -153,6 +160,8 @@
@GuardedBy("mActiveAdminApps")
private final SparseArray<Set<String>> mActiveAdminApps = new SparseArray<>();
+ private final CountDownLatch mAdminDataAvailableLatch = new CountDownLatch(1);
+
// Messages for the handler
static final int MSG_INFORM_LISTENERS = 3;
static final int MSG_FORCE_IDLE_STATE = 4;
@@ -895,6 +904,20 @@
}
}
+ public void onAdminDataAvailable() {
+ mAdminDataAvailableLatch.countDown();
+ }
+
+ /**
+ * This will only ever be called once - during device boot.
+ */
+ private void waitForAdminData() {
+ if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN)) {
+ ConcurrentUtils.waitForCountDownNoInterrupt(mAdminDataAvailableLatch,
+ WAIT_FOR_ADMIN_DATA_TIMEOUT_MS, "Wait for admin data");
+ }
+ }
+
Set<String> getActiveAdminAppsForTest(int userId) {
synchronized (mActiveAdminApps) {
return mActiveAdminApps.get(userId);
@@ -1224,6 +1247,7 @@
case MSG_ONE_TIME_CHECK_IDLE_STATES:
mHandler.removeMessages(MSG_ONE_TIME_CHECK_IDLE_STATES);
+ waitForAdminData();
checkIdleStates(UserHandle.USER_ALL);
break;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 78cc81f..979feaa 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1030,5 +1030,10 @@
public void setActiveAdminApps(Set<String> packageNames, int userId) {
mAppStandby.setActiveAdminApps(packageNames, userId);
}
+
+ @Override
+ public void onAdminDataAvailable() {
+ mAppStandby.onAdminDataAvailable();
+ }
}
}