summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yisroel Forta <yforta@google.com> 2024-05-23 23:01:35 +0000
committer Yisroel Forta <yforta@google.com> 2024-05-24 15:13:24 +0000
commit4b99fe8aec29fe67ccb753cad382218f95fe75f5 (patch)
treedd8ce1fa2a85f8ee0818da4f4a16d640e17edb6c
parent5efe00ed04bfccb6b3aeddffa495030db830f1d6 (diff)
Handle failed AppStartInfo record write
The IOException this catches can leave the write in a bad state causing it to fail later and crash system server. Store whether individual record writes succeeded and then fail the write if not. Also manually delete record as it's unlikely to work any better on the next persist. This was manually confirmed to be the problem by throwing IOException in AppStartInfo#writeToProto and confirming system server crashes. Test: manually throw an IOException in AppStartInfo#writeToProto, ensure write fails and system server lives Bug: 342319837 Flag: EXEMPT - bugfix Change-Id: Id0fa47fdade53bd8f262fbdb8aa1f75136aadcbd
-rw-r--r--services/core/java/com/android/server/am/AppStartInfoTracker.java37
1 files changed, 29 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/am/AppStartInfoTracker.java b/services/core/java/com/android/server/am/AppStartInfoTracker.java
index 79a85182ac09..a8227fa8e38b 100644
--- a/services/core/java/com/android/server/am/AppStartInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppStartInfoTracker.java
@@ -83,6 +83,7 @@ public final class AppStartInfoTracker {
private static final int FOREACH_ACTION_NONE = 0;
private static final int FOREACH_ACTION_REMOVE_ITEM = 1;
private static final int FOREACH_ACTION_STOP_ITERATION = 2;
+ private static final int FOREACH_ACTION_REMOVE_AND_STOP_ITERATION = 3;
private static final String MONITORING_MODE_EMPTY_TEXT = "No records";
@@ -659,8 +660,13 @@ public final class AppStartInfoTracker {
}
}
+ /**
+ * Run provided callback for each packake in start info dataset.
+ *
+ * @return whether the for each completed naturally, false if it was stopped manually.
+ */
@GuardedBy("mLock")
- private void forEachPackageLocked(
+ private boolean forEachPackageLocked(
BiFunction<String, SparseArray<AppStartInfoContainer>, Integer> callback) {
if (callback != null) {
ArrayMap<String, SparseArray<AppStartInfoContainer>> map = mData.getMap();
@@ -670,14 +676,17 @@ public final class AppStartInfoTracker {
map.removeAt(i);
break;
case FOREACH_ACTION_STOP_ITERATION:
- i = 0;
- break;
+ return false;
+ case FOREACH_ACTION_REMOVE_AND_STOP_ITERATION:
+ map.removeAt(i);
+ return false;
case FOREACH_ACTION_NONE:
default:
break;
}
}
}
+ return true;
}
@GuardedBy("mLock")
@@ -870,13 +879,14 @@ public final class AppStartInfoTracker {
}
AtomicFile af = new AtomicFile(mProcStartInfoFile);
FileOutputStream out = null;
+ boolean succeeded;
long now = System.currentTimeMillis();
try {
out = af.startWrite();
ProtoOutputStream proto = new ProtoOutputStream(out);
proto.write(AppsStartInfoProto.LAST_UPDATE_TIMESTAMP, now);
synchronized (mLock) {
- forEachPackageLocked(
+ succeeded = forEachPackageLocked(
(packageName, records) -> {
long token = proto.start(AppsStartInfoProto.PACKAGES);
proto.write(AppsStartInfoProto.Package.PACKAGE_NAME, packageName);
@@ -884,19 +894,30 @@ public final class AppStartInfoTracker {
for (int j = 0; j < uidArraySize; j++) {
try {
records.valueAt(j)
- .writeToProto(proto, AppsStartInfoProto.Package.USERS);
+ .writeToProto(proto, AppsStartInfoProto.Package.USERS);
} catch (IOException e) {
Slog.w(TAG, "Unable to write app start info into persistent"
+ "storage: " + e);
+ // There was likely an issue with this record that won't resolve
+ // next time we try to persist so remove it. Also stop iteration
+ // as we failed the write and need to start again from scratch.
+ return AppStartInfoTracker
+ .FOREACH_ACTION_REMOVE_AND_STOP_ITERATION;
}
}
proto.end(token);
return AppStartInfoTracker.FOREACH_ACTION_NONE;
});
- mLastAppStartInfoPersistTimestamp = now;
+ if (succeeded) {
+ mLastAppStartInfoPersistTimestamp = now;
+ }
+ }
+ if (succeeded) {
+ proto.flush();
+ af.finishWrite(out);
+ } else {
+ af.failWrite(out);
}
- proto.flush();
- af.finishWrite(out);
} catch (IOException e) {
Slog.w(TAG, "Unable to write historical app start info into persistent storage: " + e);
af.failWrite(out);