From 950919b221e635458e532c5445f56a24a2ef3e59 Mon Sep 17 00:00:00 2001 From: Li Li Date: Thu, 3 Mar 2022 11:05:39 -0800 Subject: [PATCH] Fix race between WM launching app and AMS freezer If the next top activity is in cached and frozen mode, WM should raise its priority to unfreeze it. This is done by calling AMS.updateOomAdj that will lower its oom adj. However, WM cannot hold the AMS clock here so the updateOomAdj operation is performed in a separate thread asynchronously. Therefore WM can't guarantee AMS will unfreeze next top activity on time. This race will fail the following binder transactions WM sends to the activity. After this race issue between WM/ATMS and AMS is solved, this workaround can be removed. Bug: 213288355 Test: manual stress test, launching all installed apps in a loop Change-Id: I8ac781ee3faf5711984dab22063083e93217d46e --- .../server/am/ActivityManagerService.java | 9 ++++ .../android/server/am/CachedAppOptimizer.java | 44 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 47f9fd535801d..7054a81715723 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -16999,6 +16999,15 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void addPendingTopUid(int uid, int pid) { mPendingStartActivityUids.add(uid, pid); + + // If the next top activity is in cached and frozen mode, WM should raise its priority + // to unfreeze it. This is done by calling AMS.updateOomAdj that will lower its oom adj. + // However, WM cannot hold the AMS clock here so the updateOomAdj operation is performed + // in a separate thread asynchronously. Therefore WM can't guarantee AMS will unfreeze + // next top activity on time. This race will fail the following binder transactions WM + // sends to the activity. After this race issue between WM/ATMS and AMS is solved, this + // workaround can be removed. (b/213288355) + mOomAdjuster.mCachedAppOptimizer.unfreezeProcess(pid); } @Override diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java index b18d390476f02..0c3b984aed734 100644 --- a/services/core/java/com/android/server/am/CachedAppOptimizer.java +++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java @@ -183,6 +183,8 @@ public final class CachedAppOptimizer { private final ActivityManagerGlobalLock mProcLock; + private final Object mFreezerLock = new Object(); + private final OnPropertiesChangedListener mOnFlagsChangedListener = new OnPropertiesChangedListener() { @Override @@ -949,8 +951,8 @@ public final class CachedAppOptimizer { } } - @GuardedBy({"mAm", "mProcLock"}) - void unfreezeAppLSP(ProcessRecord app) { + @GuardedBy({"mAm", "mProcLock", "mFreezerLock"}) + void unfreezeAppInternalLSP(ProcessRecord app) { final int pid = app.getPid(); final ProcessCachedOptimizerRecord opt = app.mOptRecord; if (opt.isPendingFreeze()) { @@ -1035,6 +1037,42 @@ public final class CachedAppOptimizer { } } + @GuardedBy({"mAm", "mProcLock"}) + void unfreezeAppLSP(ProcessRecord app) { + synchronized (mFreezerLock) { + unfreezeAppInternalLSP(app); + } + } + + /** + * This quick function works around the race condition between WM/ATMS and AMS, allowing + * the former to directly unfreeze a frozen process before the latter runs updateOomAdj. + * After the race issue is solved, this workaround can be removed. (b/213288355) + * @param pid pid of the process to be unfrozen + */ + @GuardedBy({"mFreezerLock"}) + void unfreezeProcess(int pid) { + synchronized (mFreezerLock) { + ProcessRecord app = mFrozenProcesses.get(pid); + if (app == null) { + return; + } + Slog.i(TAG_AM, "quick sync unfreeze " + pid); + try { + freezeBinder(pid, false); + } catch (RuntimeException e) { + Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid); + return; + } + + try { + Process.setProcessFrozen(pid, app.uid, false); + } catch (Exception e) { + Slog.e(TAG_AM, "Unable to quick unfreeze " + pid); + } + } + } + /** * To be called when the given app is killed. */ @@ -1464,8 +1502,6 @@ public final class CachedAppOptimizer { return; } - Slog.d(TAG_AM, "froze " + pid + " " + name); - EventLog.writeEvent(EventLogTags.AM_FREEZE, pid, name); // See above for why we're not taking mPhenotypeFlagLock here