diff options
| author | 2020-10-26 17:35:06 +0000 | |
|---|---|---|
| committer | 2020-10-26 17:35:06 +0000 | |
| commit | d9d9dbae1e0316a01be310c39c17b87cbe263445 (patch) | |
| tree | 4a307d96f02207064cd16ba9b197270a6025bffc | |
| parent | 23fb7a6adc797328ff5e2165a778656e04423add (diff) | |
| parent | dfd4162711f387d2a08b844be09af8d0182f6435 (diff) | |
Merge "[am/incremental] make package unstartable if it crashes/ANRs while loading"
7 files changed, 77 insertions, 0 deletions
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index 4c8925bd4828..70cf04522c45 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -1122,4 +1122,8 @@ public abstract class PackageManagerInternal { public abstract IncrementalStatesInfo getIncrementalStatesInfo(String packageName, int filterCallingUid, int userId); + /** + * Notifies that a package has crashed or ANR'd. + */ + public abstract void notifyPackageCrashOrAnr(String packageName); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 32d95f594ce9..51cbfcf64322 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -7595,6 +7595,10 @@ public class ActivityManagerService extends IActivityManager.Stub eventType, r, processName, null, null, null, null, null, null, crashInfo); mAppErrors.crashApplication(r, crashInfo); + // Notify package manager service to possibly update package state + if (r != null && r.info != null && r.info.packageName != null) { + mPackageManagerInt.notifyPackageCrashOrAnr(r.info.packageName); + } } public void handleApplicationStrictModeViolation( diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 53c6758585cf..ccdd6a746239 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -1764,6 +1764,12 @@ class ProcessRecord implements WindowProcessListener { makeAppNotRespondingLocked(activityShortComponentName, annotation != null ? "ANR " + annotation : "ANR", info.toString()); + // Notify package manager service to possibly update package state + if (aInfo != null && aInfo.packageName != null) { + mService.getPackageManagerInternalLocked().notifyPackageCrashOrAnr( + aInfo.packageName); + } + // mUiHandler can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mUiHandler != null) { diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java index 26ace47776be..72803ac35a3f 100644 --- a/services/core/java/com/android/server/pm/IncrementalStates.java +++ b/services/core/java/com/android/server/pm/IncrementalStates.java @@ -119,6 +119,33 @@ public final class IncrementalStates { } } + /** + * Change the startable state if the app has crashed or ANR'd during loading. + * If the app is not loading (i.e., fully loaded), this event doesn't change startable state. + */ + public void onCrashOrAnr() { + if (DEBUG) { + Slog.i(TAG, "received package crash or ANR event"); + } + final boolean startableStateChanged; + synchronized (mLock) { + if (mStartableState.isStartable() && mLoadingState.isLoading()) { + // Changing from startable -> unstartable only if app is still loading. + mStartableState.adoptNewStartableStateLocked(false); + startableStateChanged = true; + } else { + // If the app is fully loaded, the crash or ANR is caused by the app itself, so + // we do not change the startable state. + startableStateChanged = false; + } + } + if (startableStateChanged) { + mHandler.post(PooledLambda.obtainRunnable( + IncrementalStates::reportStartableState, + IncrementalStates.this).recycleOnUse()); + } + } + private void reportStartableState() { final Callback callback; final boolean startable; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 410fbe57bf26..37c39551bf40 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -25843,6 +25843,20 @@ public class PackageManagerService extends IPackageManager.Stub } return ps.getIncrementalStates(); } + + @Override + public void notifyPackageCrashOrAnr(@NonNull String packageName) { + final PackageSetting ps; + synchronized (mLock) { + ps = mSettings.mPackages.get(packageName); + if (ps == null) { + Slog.w(TAG, "Failed notifyPackageCrash. Package " + packageName + + " is not installed"); + return; + } + } + ps.setStatesOnCrashOrAnr(); + } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index be7c7c6ff1d6..ac76cf71ef67 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -772,6 +772,14 @@ public abstract class PackageSettingBase extends SettingBase { } /** + * Called to indicate that the running app has crashed or ANR'd. This might change the startable + * state of the package, depending on whether the package is fully loaded. + */ + public void setStatesOnCrashOrAnr() { + incrementalStates.onCrashOrAnr(); + } + + /** * Called to set the callback to listen for startable state changes. */ public void setIncrementalStatesCallback(IncrementalStates.Callback callback) { diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java index 86758f18a407..40d959d9793d 100644 --- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java @@ -222,4 +222,18 @@ public class IncrementalStatesTest { assertTrue(mFullyLoadedCalled.block(WAIT_TIMEOUT_MILLIS)); assertFalse(mIncrementalStates.isLoading()); } + + /** + * Test startability transitions if app crashes or anrs + */ + @Test + public void testStartableTransition_AppCrashOrAnr() { + mIncrementalStates.onCrashOrAnr(); + assertFalse(mIncrementalStates.isStartable()); + mIncrementalStates.setProgress(1.0f); + assertTrue(mIncrementalStates.isStartable()); + mIncrementalStates.onCrashOrAnr(); + // Test that if fully loaded, app remains startable even if it has crashed + assertTrue(mIncrementalStates.isStartable()); + } } |