diff options
author | Gavin Corkery <gavincorkery@google.com> | 2019-12-20 08:02:11 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2019-12-20 08:02:11 +0000 |
commit | cb6ad6dc8e3ae33a6d82dc4a92b4b32485a1e6be (patch) | |
tree | 714981f47a9a46510a810433e09c9fb0015e7437 | |
parent | cd0dc3caafb1e3c2fe15c1799543662cf27e0585 (diff) | |
parent | 231b3d8f6032d5451b9fb8dc94bcbfacaef9af13 (diff) | |
download | frameworks_base-cb6ad6dc8e3ae33a6d82dc4a92b4b32485a1e6be.tar.gz frameworks_base-cb6ad6dc8e3ae33a6d82dc4a92b4b32485a1e6be.tar.bz2 frameworks_base-cb6ad6dc8e3ae33a6d82dc4a92b4b32485a1e6be.zip |
Merge changes from topic "cp-log-watchdog" into qt-qpr1-dev
* changes:
Log native crashing process
Log watchdog-initiated rollback reason
Add package failure flags to Package Watchdog
-rw-r--r-- | cmds/statsd/src/StatsService.cpp | 8 | ||||
-rw-r--r-- | cmds/statsd/src/StatsService.h | 4 | ||||
-rw-r--r-- | cmds/statsd/src/atoms.proto | 13 | ||||
-rw-r--r-- | core/java/android/os/IStatsManager.aidl | 2 | ||||
-rw-r--r-- | core/java/android/util/StatsLog.java | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/PackageWatchdog.java | 31 | ||||
-rw-r--r-- | services/core/java/com/android/server/am/AppErrors.java | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java | 64 | ||||
-rw-r--r-- | tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java | 73 |
9 files changed, 172 insertions, 35 deletions
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index b665a8b99fb..64b7aae0161 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1394,7 +1394,10 @@ Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& tra Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) { + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& + failingPackageNameIn) { // Note: We skip the usage stats op check here since we do not have a package name. // This is ok since we are overloading the usage_stats permission. // This method only sends data, it does not receive it. @@ -1416,7 +1419,8 @@ Status StatsService::sendWatchdogRollbackOccurredAtom(const int32_t rollbackType } android::util::stats_write(android::util::WATCHDOG_ROLLBACK_OCCURRED, - rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn); + rollbackTypeIn, String8(packageNameIn).string(), packageVersionCodeIn, + rollbackReasonIn, String8(failingPackageNameIn).string()); // Fast return to save disk read. if (rollbackTypeIn != android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 94909487193..5f1335efc2e 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -200,7 +200,9 @@ public: virtual Status sendWatchdogRollbackOccurredAtom( const int32_t rollbackTypeIn, const android::String16& packageNameIn, - const int64_t packageVersionCodeIn) override; + const int64_t packageVersionCodeIn, + const int32_t rollbackReasonIn, + const android::String16& failingPackageNameIn) override; /** * Binder call to get registered experiment IDs. diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 993db511d5d..1b502e2f9eb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -1687,6 +1687,19 @@ message WatchdogRollbackOccurred { optional string package_name = 2; optional int32 package_version_code = 3; + + enum RollbackReasonType { + REASON_UNKNOWN = 0; + REASON_NATIVE_CRASH = 1; + REASON_EXPLICIT_HEALTH_CHECK = 2; + REASON_APP_CRASH = 3; + REASON_APP_NOT_RESPONDING = 4; + } + optional RollbackReasonType rollback_reason = 4; + + // Set by RollbackPackageHealthObserver to be the package that is failing when a rollback + // is initiated. Empty if the package is unknown. + optional string failing_package_name = 5; } /** diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index e3f9326048d..36ea1bcc91d 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -224,7 +224,7 @@ interface IStatsManager { * Logs an event for watchdog rollbacks. */ oneway void sendWatchdogRollbackOccurredAtom(in int rollbackType, in String packageName, - in long packageVersionCode); + in long packageVersionCode, in int rollbackReason, in String failingPackageName); /** * Returns the most recently registered experiment IDs. diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index f7077bb2a41..0bbed845b99 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -179,6 +179,8 @@ public final class StatsLog extends StatsLogInternal { * @param rollbackType state of the rollback. * @param packageName package name being rolled back. * @param packageVersionCode version of the package being rolled back. + * @param rollbackReason reason the package is being rolled back. + * @param failingPackageName the package name causing the failure. * * @return True if the log request was sent to statsd. * @@ -186,7 +188,7 @@ public final class StatsLog extends StatsLogInternal { */ @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS}) public static boolean logWatchdogRollbackOccurred(int rollbackType, String packageName, - long packageVersionCode) { + long packageVersionCode, int rollbackReason, String failingPackageName) { synchronized (sLogLock) { try { IStatsManager service = getIStatsManagerLocked(); @@ -198,7 +200,7 @@ public final class StatsLog extends StatsLogInternal { } service.sendWatchdogRollbackOccurredAtom(rollbackType, packageName, - packageVersionCode); + packageVersionCode, rollbackReason, failingPackageName); return true; } catch (RemoteException e) { sService = null; diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index dee89e5d5c4..501de7f63eb 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -56,6 +56,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; @@ -80,6 +81,22 @@ public class PackageWatchdog { static final String PROPERTY_WATCHDOG_EXPLICIT_HEALTH_CHECK_ENABLED = "watchdog_explicit_health_check_enabled"; + public static final int FAILURE_REASON_UNKNOWN = 0; + public static final int FAILURE_REASON_NATIVE_CRASH = 1; + public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2; + public static final int FAILURE_REASON_APP_CRASH = 3; + public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4; + + @IntDef(prefix = { "FAILURE_REASON_" }, value = { + FAILURE_REASON_UNKNOWN, + FAILURE_REASON_NATIVE_CRASH, + FAILURE_REASON_EXPLICIT_HEALTH_CHECK, + FAILURE_REASON_APP_CRASH, + FAILURE_REASON_APP_NOT_RESPONDING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface FailureReasons {} + // Duration to count package failures before it resets to 0 private static final int DEFAULT_TRIGGER_FAILURE_DURATION_MS = (int) TimeUnit.MINUTES.toMillis(1); @@ -295,14 +312,15 @@ public class PackageWatchdog { } /** - * Called when a process fails either due to a crash or ANR. + * Called when a process fails due to a crash, ANR or explicit health check. * * <p>For each package contained in the process, one registered observer with the least user * impact will be notified for mitigation. * * <p>This method could be called frequently if there is a severe problem on the device. */ - public void onPackageFailure(List<VersionedPackage> packages) { + public void onPackageFailure(List<VersionedPackage> packages, + @FailureReasons int failureReason) { mLongTaskHandler.post(() -> { synchronized (mLock) { if (mAllObservers.isEmpty()) { @@ -333,7 +351,7 @@ public class PackageWatchdog { // Execute action with least user impact if (currentObserverToNotify != null) { - currentObserverToNotify.execute(versionedPackage); + currentObserverToNotify.execute(versionedPackage, failureReason); } } } @@ -404,7 +422,7 @@ public class PackageWatchdog { * * @return {@code true} if action was executed successfully, {@code false} otherwise */ - boolean execute(VersionedPackage versionedPackage); + boolean execute(VersionedPackage versionedPackage, @FailureReasons int failureReason); // TODO(b/120598832): Ensure uniqueness? /** @@ -648,7 +666,8 @@ public class PackageWatchdog { // the tests don't install any packages versionedPkg = new VersionedPackage(failedPackage, 0L); } - registeredObserver.execute(versionedPkg); + registeredObserver.execute(versionedPkg, + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } } } @@ -759,7 +778,7 @@ public class PackageWatchdog { final List<VersionedPackage> pkgList = Collections.singletonList(pkg); final long failureCount = getTriggerFailureCount(); for (int i = 0; i < failureCount; i++) { - onPackageFailure(pkgList); + onPackageFailure(pkgList, FAILURE_REASON_EXPLICIT_HEALTH_CHECK); } }); } diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 1ff6f4dac72..a4c69506713 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -430,7 +430,8 @@ class AppErrors { RescueParty.noteAppCrash(mContext, r.uid); } - mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode()); + mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(), + PackageWatchdog.FAILURE_REASON_APP_CRASH); } final int relaunchReason = r != null @@ -884,7 +885,8 @@ class AppErrors { } // Notify PackageWatchdog without the lock held if (packageList != null) { - mPackageWatchdog.onPackageFailure(packageList); + mPackageWatchdog.onPackageFailure(packageList, + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); } } diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 9c19aeccd59..3a94c931dd5 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -16,6 +16,13 @@ package com.android.server.rollback; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; +import static android.util.StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; @@ -41,6 +48,7 @@ import android.util.StatsLog; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.server.PackageWatchdog; +import com.android.server.PackageWatchdog.FailureReasons; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; @@ -106,11 +114,19 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } @Override - public boolean execute(VersionedPackage failedPackage) { + public boolean execute(VersionedPackage failedPackage, @FailureReasons int rollbackReason) { RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class); VersionedPackage moduleMetadataPackage = getModuleMetadataPackage(); RollbackInfo rollback = getAvailableRollback(rollbackManager, failedPackage); + int reasonToLog = mapFailureReasonToMetric(rollbackReason); + final String failedPackageToLog; + if (rollbackReason == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH) { + failedPackageToLog = SystemProperties.get( + "ro.init.updatable_crashing_process_name", ""); + } else { + failedPackageToLog = failedPackage.getPackageName(); + } if (rollback == null) { Slog.w(TAG, "Expected rollback but no valid rollback found for package: [ " + failedPackage.getPackageName() + "] with versionCode: [" @@ -119,7 +135,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE, + reasonToLog, failedPackageToLog); LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> { int status = result.getIntExtra(RollbackManager.EXTRA_STATUS, RollbackManager.STATUS_FAILURE); @@ -136,11 +153,13 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve moduleMetadataPackage); } else { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + reasonToLog, failedPackageToLog); } } else { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + reasonToLog, failedPackageToLog); } }); @@ -219,12 +238,14 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } if (sessionInfo.isStagedSessionApplied()) { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } else if (sessionInfo.isStagedSessionReady()) { // TODO: What do for staged session ready but not applied } else { logEvent(oldModuleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, ""); } } @@ -303,12 +324,16 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve saveLastStagedRollbackId(rollbackId); logEvent(moduleMetadataPackage, StatsLog - .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED); + .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); } else if (sessionInfo.isStagedSessionFailed() && markStagedSessionHandled(rollbackId)) { logEvent(moduleMetadataPackage, - StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); + StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE, + WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN, + ""); mContext.unregisterReceiver(listener); } } @@ -355,11 +380,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve return rollbackId; } - private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type) { + private static void logEvent(@Nullable VersionedPackage moduleMetadataPackage, int type, + int rollbackReason, @NonNull String failingPackageName) { Slog.i(TAG, "Watchdog event occurred of type: " + type); if (moduleMetadataPackage != null) { StatsLog.logWatchdogRollbackOccurred(type, moduleMetadataPackage.getPackageName(), - moduleMetadataPackage.getVersionCode()); + moduleMetadataPackage.getVersionCode(), rollbackReason, failingPackageName); } } @@ -371,7 +397,7 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve mNumberOfNativeCrashPollsRemaining--; // Check if native watchdog reported a crash if ("1".equals(SystemProperties.get("ro.init.updatable_crashing"))) { - execute(getModuleMetadataPackage()); + execute(getModuleMetadataPackage(), PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); // we stop polling after an attempt to execute rollback, regardless of whether the // attempt succeeds or not } else { @@ -392,4 +418,20 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve + "and mitigate native crashes"); mHandler.post(()->checkAndMitigateNativeCrashes()); } + + private int mapFailureReasonToMetric(@FailureReasons int failureReason) { + switch (failureReason) { + case PackageWatchdog.FAILURE_REASON_NATIVE_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH; + case PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_EXPLICIT_HEALTH_CHECK; + case PackageWatchdog.FAILURE_REASON_APP_CRASH: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_CRASH; + case PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_APP_NOT_RESPONDING; + default: + return WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_UNKNOWN; + } + } + } diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index 232b5cb1702..31c6996217f 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -269,7 +269,8 @@ public class PackageWatchdogTest { // Then fail APP_A below the threshold for (int i = 0; i < watchdog.getTriggerFailureCount() - 1; i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -296,7 +297,8 @@ public class PackageWatchdogTest { // Then fail APP_C (not observed) above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -331,7 +333,8 @@ public class PackageWatchdogTest { // Then fail APP_A (different version) above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { watchdog.onPackageFailure(Arrays.asList( - new VersionedPackage(APP_A, differentVersionCode))); + new VersionedPackage(APP_A, differentVersionCode)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -372,7 +375,8 @@ public class PackageWatchdogTest { watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE), new VersionedPackage(APP_B, VERSION_CODE), new VersionedPackage(APP_C, VERSION_CODE), - new VersionedPackage(APP_D, VERSION_CODE))); + new VersionedPackage(APP_D, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -422,7 +426,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers mTestLooper.dispatchAll(); @@ -439,7 +444,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers mTestLooper.dispatchAll(); @@ -456,7 +462,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers mTestLooper.dispatchAll(); @@ -473,7 +480,8 @@ public class PackageWatchdogTest { // Then fail APP_A again above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers mTestLooper.dispatchAll(); @@ -500,7 +508,8 @@ public class PackageWatchdogTest { // Then fail APP_A above the threshold for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { - watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE))); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_UNKNOWN); } // Run handler so package failures are dispatched to observers @@ -746,6 +755,44 @@ public class PackageWatchdogTest { assertEquals(APP_A, observer.mFailedPackages.get(0)); } + /** Test that observers execute correctly for different failure reasons */ + @Test + public void testFailureReasons() { + PackageWatchdog watchdog = createWatchdog(); + TestObserver observer1 = new TestObserver(OBSERVER_NAME_1); + TestObserver observer2 = new TestObserver(OBSERVER_NAME_2); + TestObserver observer3 = new TestObserver(OBSERVER_NAME_3); + TestObserver observer4 = new TestObserver(OBSERVER_NAME_4); + + watchdog.startObservingHealth(observer1, Arrays.asList(APP_A), SHORT_DURATION); + watchdog.startObservingHealth(observer2, Arrays.asList(APP_B), SHORT_DURATION); + watchdog.startObservingHealth(observer3, Arrays.asList(APP_C), SHORT_DURATION); + watchdog.startObservingHealth(observer4, Arrays.asList(APP_D), SHORT_DURATION); + + for (int i = 0; i < watchdog.getTriggerFailureCount(); i++) { + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_A, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_B, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_C, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_APP_CRASH); + watchdog.onPackageFailure(Arrays.asList(new VersionedPackage(APP_D, VERSION_CODE)), + PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + } + + // Run handler so requests are dispatched to the controller + mTestLooper.dispatchAll(); + + assertTrue(observer1.getLastFailureReason() + == PackageWatchdog.FAILURE_REASON_NATIVE_CRASH); + assertTrue(observer2.getLastFailureReason() + == PackageWatchdog.FAILURE_REASON_EXPLICIT_HEALTH_CHECK); + assertTrue(observer3.getLastFailureReason() + == PackageWatchdog.FAILURE_REASON_APP_CRASH); + assertTrue(observer4.getLastFailureReason() + == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING); + } + private void adoptShellPermissions(String... permissions) { InstrumentationRegistry .getInstrumentation() @@ -801,6 +848,7 @@ public class PackageWatchdogTest { private static class TestObserver implements PackageHealthObserver { private final String mName; private int mImpact; + private int mLastFailureReason; final List<String> mFailedPackages = new ArrayList<>(); TestObserver(String name) { @@ -817,14 +865,19 @@ public class PackageWatchdogTest { return mImpact; } - public boolean execute(VersionedPackage versionedPackage) { + public boolean execute(VersionedPackage versionedPackage, int failureReason) { mFailedPackages.add(versionedPackage.getPackageName()); + mLastFailureReason = failureReason; return true; } public String getName() { return mName; } + + public int getLastFailureReason() { + return mLastFailureReason; + } } private static class TestController extends ExplicitHealthCheckController { |