From 997239631cfd69d60354ae3bc7e029178c52ad19 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Mon, 12 Jun 2023 23:32:39 +0000 Subject: [PATCH] Re-evaluate frozen state in CAO.onCleanupApplicationRecordLocked CachedAppOptimzer.onCleanupApplicationRecordLocked() is unconditionally setting the UID record as unfrozen and sending the corresponding callback. This is wrong as the frozen/unfrozen state may have changed when that process went away. As an example, if the process being cleaned up was the last unfrozen process in the UID, then we would need to send a frozen state changed message. The easiest way to do this (and avoid sending redundant FROZEN messages) is to re-evaluate our UIDs frozen state, compare it to what is recorded in the UidRec and update the record / send a callback only if the frozen state changed from what it previously was. From what I can tell, there's a possibility that the process going away may still be in the UidRecord. Since we don't want to count that processes state, I added a new version of UidRecord.areAllProcessesFrozen() which will skip over a given process record when evaluating the UidRecord frozen state. Test: tested on a pixel 6 Bug: 283537511 Change-Id: If809b04f42e737f3a0379bcd08d6cf4aba70e207 --- .../com/android/server/am/CachedAppOptimizer.java | 12 ++++++++---- .../java/com/android/server/am/UidRecord.java | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index 7773190d22b6e..1fa2bea6e5ea7 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -1525,10 +1525,14 @@ public final class CachedAppOptimizer { opt.setPendingFreeze(false); } - UidRecord uidRec = app.getUidRecord(); - if (uidRec != null && uidRec.isFrozen()) { - uidRec.setFrozen(false); - postUidFrozenMessage(uidRec.getUid(), false); + final UidRecord uidRec = app.getUidRecord(); + if (uidRec != null) { + final boolean isFrozen = uidRec.getNumOfProcs() > 1 + && uidRec.areAllProcessesFrozen(app); + if (isFrozen != uidRec.isFrozen()) { + uidRec.setFrozen(isFrozen); + postUidFrozenMessage(uidRec.getUid(), isFrozen); + } } mFrozenProcesses.delete(app.getPid()); diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index 993088ef106e8..4329afc7e863c 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -345,21 +345,32 @@ public final class UidRecord { } /** + * Check whether all processes in the Uid are frozen. + * + * @param excluding Skip this process record during the check. * @return true if all processes in the Uid are frozen, false otherwise. */ @GuardedBy(anyOf = {"mService", "mProcLock"}) - public boolean areAllProcessesFrozen() { + public boolean areAllProcessesFrozen(ProcessRecord excluding) { for (int i = mProcRecords.size() - 1; i >= 0; i--) { final ProcessRecord app = mProcRecords.valueAt(i); final ProcessCachedOptimizerRecord opt = app.mOptRecord; - if (!opt.isFrozen()) { + if (excluding != app && !opt.isFrozen()) { return false; } } return true; } + /** + * @return true if all processes in the Uid are frozen, false otherwise. + */ + @GuardedBy(anyOf = {"mService", "mProcLock"}) + public boolean areAllProcessesFrozen() { + return areAllProcessesFrozen(null); + } + @GuardedBy(anyOf = {"mService", "mProcLock"}) public void setFrozen(boolean frozen) { mUidIsFrozen = frozen;