summaryrefslogtreecommitdiff
path: root/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java')
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java238
1 files changed, 206 insertions, 32 deletions
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index d0c261279c9d..28af7cee8f38 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -19,11 +19,16 @@ package com.android.server;
import static com.android.server.PackageWatchdog.TRIGGER_FAILURE_COUNT;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import android.content.Context;
import android.content.pm.VersionedPackage;
+import android.os.Handler;
+import android.os.RemoteException;
import android.os.test.TestLooper;
+import android.util.AtomicFile;
import androidx.test.InstrumentationRegistry;
@@ -36,11 +41,14 @@ import org.junit.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
-// TODO(zezeozue): Write test without using PackageWatchdog#getPackages. Just rely on
+// TODO: Write test without using PackageWatchdog#getPackages. Just rely on
// behavior of observers receiving crash notifications or not to determine if it's registered
+// TODO: Use Truth in tests.
/**
* Test PackageWatchdog.
*/
@@ -77,12 +85,11 @@ public class PackageWatchdogTest {
TestObserver observer3 = new TestObserver(OBSERVER_NAME_3);
// Start observing for observer1 which will be unregistered
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION, false);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
// Start observing for observer2 which will expire
- watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION,
- false);
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
// Start observing for observer3 which will have expiry duration reduced
- watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), LONG_DURATION, false);
+ watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), LONG_DURATION);
// Verify packages observed at start
// 1
@@ -145,9 +152,8 @@ public class PackageWatchdogTest {
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
- watchdog1.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION, false);
- watchdog1.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION,
- false);
+ watchdog1.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog1.startObservingHealth(observer2, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
// Verify 2 observers are registered and saved internally
// 1
@@ -193,8 +199,8 @@ public class PackageWatchdogTest {
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
- watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION, false);
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION, false);
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A below the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT - 1; i++) {
@@ -220,8 +226,8 @@ public class PackageWatchdogTest {
TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
- watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION, false);
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION, false);
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION);
// Then fail APP_C (not observed) above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
@@ -255,7 +261,7 @@ public class PackageWatchdogTest {
}
};
- watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION, false);
+ watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A (different version) above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
@@ -288,13 +294,13 @@ public class PackageWatchdogTest {
// Start observing for all impact observers
watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D),
- SHORT_DURATION, false);
+ SHORT_DURATION);
watchdog.startObservingHealth(observerHigh, Arrays.asList(APP_A, APP_B, APP_C),
- SHORT_DURATION, false);
+ SHORT_DURATION);
watchdog.startObservingHealth(observerMid, Arrays.asList(APP_A, APP_B),
- SHORT_DURATION, false);
+ SHORT_DURATION);
watchdog.startObservingHealth(observerLow, Arrays.asList(APP_A),
- SHORT_DURATION, false);
+ SHORT_DURATION);
// Then fail all apps above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
@@ -346,8 +352,8 @@ public class PackageWatchdogTest {
PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
// Start observing for observerFirst and observerSecond with failure handling
- watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION, false);
- watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION, false);
+ watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION);
+ watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
// Then fail APP_A above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
@@ -424,8 +430,8 @@ public class PackageWatchdogTest {
PackageHealthObserverImpact.USER_IMPACT_HIGH);
// Start observing for observer1 and observer2 with failure handling
- watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION, false);
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION, false);
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
// Then fail APP_A above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
@@ -442,11 +448,12 @@ public class PackageWatchdogTest {
}
/**
- * Test explicit health check status determines package failure or success on expiry
+ * Test package passing explicit health checks does not fail and vice versa.
*/
@Test
- public void testPackageFailureExplicitHealthCheck() throws Exception {
- PackageWatchdog watchdog = createWatchdog();
+ public void testExplicitHealthChecks() throws Exception {
+ TestController controller = new TestController();
+ PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
PackageHealthObserverImpact.USER_IMPACT_HIGH);
TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
@@ -457,21 +464,36 @@ public class PackageWatchdogTest {
// Start observing with explicit health checks for APP_A and APP_B respectively
// with observer1 and observer2
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION, true);
- watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION, true);
- // Explicit health check passed for APP_A (observer1 is aware)
- watchdog.onExplicitHealthCheckPassed(APP_A);
- // Start observing APP_A with explicit health checks for observer3.
+ controller.setSupportedPackages(Arrays.asList(APP_A, APP_B));
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION);
+
+ // Run handler so requests are dispatched to the controller
+ mTestLooper.dispatchAll();
+
+ // Verify we requested health checks for APP_A and APP_B
+ List<String> requestedPackages = controller.getRequestedPackages();
+ assertEquals(2, requestedPackages.size());
+ assertEquals(APP_A, requestedPackages.get(0));
+ assertEquals(APP_B, requestedPackages.get(1));
+
+ // Then health check passed for APP_A (observer1 is aware)
+ controller.setPackagePassed(APP_A);
+
+ // Then start observing APP_A with explicit health checks for observer3.
// Observer3 didn't exist when we got the explicit health check above, so
// it starts out with a non-passing explicit health check and has to wait for a pass
// otherwise it would be notified of APP_A failure on expiry
- watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), SHORT_DURATION, true);
+ watchdog.startObservingHealth(observer3, Arrays.asList(APP_A), SHORT_DURATION);
// Then expire observers
Thread.sleep(SHORT_DURATION);
// Run handler so package failures are dispatched to observers
mTestLooper.dispatchAll();
+ // Verify we cancelled all requests on expiry
+ assertEquals(0, controller.getRequestedPackages().size());
+
// Verify observer1 is not notified
assertEquals(0, observer1.mFailedPackages.size());
@@ -484,9 +506,96 @@ public class PackageWatchdogTest {
assertEquals(APP_A, observer3.mFailedPackages.get(0));
}
+ /**
+ * Test explicit health check state can be disabled and enabled correctly.
+ */
+ @Test
+ public void testExplicitHealthCheckStateChanges() throws Exception {
+ TestController controller = new TestController();
+ PackageWatchdog watchdog = createWatchdog(controller, true /* withPackagesReady */);
+ TestObserver observer = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+
+ // Start observing with explicit health checks for APP_A and APP_B
+ controller.setSupportedPackages(Arrays.asList(APP_A, APP_B, APP_C));
+ watchdog.startObservingHealth(observer, Arrays.asList(APP_A), SHORT_DURATION);
+ watchdog.startObservingHealth(observer, Arrays.asList(APP_B), LONG_DURATION);
+
+ // Run handler so requests are dispatched to the controller
+ mTestLooper.dispatchAll();
+
+ // Verify we requested health checks for APP_A and APP_B
+ List<String> requestedPackages = controller.getRequestedPackages();
+ assertEquals(2, requestedPackages.size());
+ assertEquals(APP_A, requestedPackages.get(0));
+ assertEquals(APP_B, requestedPackages.get(1));
+
+ // Disable explicit health checks (marks APP_A and APP_B as passed)
+ watchdog.setExplicitHealthCheckEnabled(false);
+
+ // Run handler so requests/cancellations are dispatched to the controller
+ mTestLooper.dispatchAll();
+
+ // Verify all checks are cancelled
+ assertEquals(0, controller.getRequestedPackages().size());
+
+ // Then expire APP_A
+ Thread.sleep(SHORT_DURATION);
+ mTestLooper.dispatchAll();
+
+ // Verify APP_A is not failed (APP_B) is not expired yet
+ assertEquals(0, observer.mFailedPackages.size());
+
+ // Re-enable explicit health checks
+ watchdog.setExplicitHealthCheckEnabled(true);
+
+ // Run handler so requests/cancellations are dispatched to the controller
+ mTestLooper.dispatchAll();
+
+ // Verify no requests are made cos APP_A is expired and APP_B was marked as passed
+ assertEquals(0, controller.getRequestedPackages().size());
+
+ // Then set new supported packages
+ controller.setSupportedPackages(Arrays.asList(APP_C));
+ // Start observing APP_A and APP_C; only APP_C has support for explicit health checks
+ watchdog.startObservingHealth(observer, Arrays.asList(APP_A, APP_C), SHORT_DURATION);
+
+ // Run handler so requests/cancellations are dispatched to the controller
+ mTestLooper.dispatchAll();
+
+ // Verify requests are only made for APP_C
+ requestedPackages = controller.getRequestedPackages();
+ assertEquals(1, requestedPackages.size());
+ assertEquals(APP_C, requestedPackages.get(0));
+
+ // Then expire APP_A and APP_C
+ Thread.sleep(SHORT_DURATION);
+ mTestLooper.dispatchAll();
+
+ // Verify only APP_C is failed because explicit health checks was not supported for APP_A
+ assertEquals(1, observer.mFailedPackages.size());
+ assertEquals(APP_C, observer.mFailedPackages.get(0));
+ }
+
private PackageWatchdog createWatchdog() {
- return new PackageWatchdog(InstrumentationRegistry.getContext(),
- mTestLooper.getLooper());
+ return createWatchdog(new TestController(), true /* withPackagesReady */);
+ }
+
+ private PackageWatchdog createWatchdog(TestController controller, boolean withPackagesReady) {
+ Context context = InstrumentationRegistry.getContext();
+ AtomicFile policyFile =
+ new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
+ Handler handler = new Handler(mTestLooper.getLooper());
+ PackageWatchdog watchdog =
+ new PackageWatchdog(context, policyFile, handler, handler, controller);
+ // Verify controller is not automatically started
+ assertFalse(controller.mIsEnabled);
+ if (withPackagesReady) {
+ watchdog.onPackagesReady();
+ // Verify controller by default is started when packages are ready
+ assertTrue(controller.mIsEnabled);
+ }
+ return watchdog;
}
private static class TestObserver implements PackageHealthObserver {
@@ -517,4 +626,69 @@ public class PackageWatchdogTest {
return mName;
}
}
+
+ private static class TestController extends ExplicitHealthCheckController {
+ TestController() {
+ super(null /* controller */);
+ }
+
+ private boolean mIsEnabled;
+ private List<String> mSupportedPackages = new ArrayList<>();
+ private List<String> mRequestedPackages = new ArrayList<>();
+ private Runnable mStateChangedRunnable;
+ private Consumer<String> mPassedConsumer;
+
+ @Override
+ public void request(String packageName) throws RemoteException {
+ if (!mRequestedPackages.contains(packageName)) {
+ mRequestedPackages.add(packageName);
+ }
+ }
+
+ @Override
+ public void cancel(String packageName) throws RemoteException {
+ mRequestedPackages.remove(packageName);
+ }
+
+ @Override
+ public void getSupportedPackages(Consumer<List<String>> consumer) throws RemoteException {
+ consumer.accept(mIsEnabled ? mSupportedPackages : Collections.emptyList());
+ }
+
+ @Override
+ public void getRequestedPackages(Consumer<List<String>> consumer) throws RemoteException {
+ // Pass copy to prevent ConcurrentModificationException during test
+ consumer.accept(
+ mIsEnabled ? new ArrayList<>(mRequestedPackages) : Collections.emptyList());
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mIsEnabled = enabled;
+ mStateChangedRunnable.run();
+ }
+
+ @Override
+ public void setCallbacks(Runnable stateChangedRunnable, Consumer<String> passedConsumer) {
+ mStateChangedRunnable = stateChangedRunnable;
+ mPassedConsumer = passedConsumer;
+ }
+
+ public void setSupportedPackages(List<String> packages) {
+ mSupportedPackages.clear();
+ mSupportedPackages.addAll(packages);
+ }
+
+ public void setPackagePassed(String packageName) {
+ mPassedConsumer.accept(packageName);
+ }
+
+ public List<String> getRequestedPackages() {
+ if (mIsEnabled) {
+ return mRequestedPackages;
+ } else {
+ return Collections.emptyList();
+ }
+ }
+ }
}