Merge "Fix the algorithm counting the package failures"

This commit is contained in:
Chun-Wei Wang
2019-09-17 01:49:37 +00:00
committed by Android (Google) Code Review
2 changed files with 45 additions and 17 deletions

View File

@@ -34,6 +34,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.Xml;
@@ -969,6 +970,9 @@ public class PackageWatchdog {
class MonitoredPackage {
//TODO(b/120598832): VersionedPackage?
private final String mName;
// Times when package failures happen sorted in ascending order
@GuardedBy("mLock")
private final LongArrayQueue mFailureHistory = new LongArrayQueue();
// One of STATE_[ACTIVE|INACTIVE|PASSED|FAILED]. Updated on construction and after
// methods that could change the health check state: handleElapsedTimeLocked and
// tryPassHealthCheckLocked
@@ -988,12 +992,6 @@ public class PackageWatchdog {
// of the package, see #getHealthCheckStateLocked
@GuardedBy("mLock")
private long mHealthCheckDurationMs = Long.MAX_VALUE;
// System uptime of first package failure
@GuardedBy("mLock")
private long mUptimeStartMs;
// Number of failures since mUptimeStartMs
@GuardedBy("mLock")
private int mFailures;
MonitoredPackage(String name, long durationMs, boolean hasPassedHealthCheck) {
this(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
@@ -1028,20 +1026,17 @@ public class PackageWatchdog {
*/
@GuardedBy("mLock")
public boolean onFailureLocked() {
// Sliding window algorithm: find out if there exists a window containing failures >=
// mTriggerFailureCount.
final long now = mSystemClock.uptimeMillis();
final long duration = now - mUptimeStartMs;
if (duration > mTriggerFailureDurationMs) {
// TODO(b/120598832): Reseting to 1 is not correct
// because there may be more than 1 failure in the last trigger window from now
// This is the RescueParty impl, will leave for now
mFailures = 1;
mUptimeStartMs = now;
} else {
mFailures++;
mFailureHistory.addLast(now);
while (now - mFailureHistory.peekFirst() > mTriggerFailureDurationMs) {
// Prune values falling out of the window
mFailureHistory.removeFirst();
}
boolean failed = mFailures >= mTriggerFailureCount;
boolean failed = mFailureHistory.size() >= mTriggerFailureCount;
if (failed) {
mFailures = 0;
mFailureHistory.clear();
}
return failed;
}

View File

@@ -765,6 +765,39 @@ public class PackageWatchdogTest {
assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_B);
}
/** Test we are notified when enough failures are triggered within any window. */
@Test
public void testFailureTriggerWindow() {
adoptShellPermissions(
Manifest.permission.WRITE_DEVICE_CONFIG,
Manifest.permission.READ_DEVICE_CONFIG);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_FAILURE_COUNT,
Integer.toString(3), /*makeDefault*/false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK,
PackageWatchdog.PROPERTY_WATCHDOG_TRIGGER_DURATION_MILLIS,
Integer.toString(1000), /*makeDefault*/false);
PackageWatchdog watchdog = createWatchdog();
TestObserver observer = new TestObserver(OBSERVER_NAME_1);
watchdog.startObservingHealth(observer, Arrays.asList(APP_A), Long.MAX_VALUE);
// Raise 2 failures at t=0 and t=900 respectively
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
mTestLooper.dispatchAll();
moveTimeForwardAndDispatch(900);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
mTestLooper.dispatchAll();
// Raise 2 failures at t=1100
moveTimeForwardAndDispatch(200);
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)));
mTestLooper.dispatchAll();
// We should receive APP_A since there are 3 failures within 1000ms window
assertThat(observer.mHealthCheckFailedPackages).containsExactly(APP_A);
}
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()