From 8c239da8d54bc2ac93fe666a7ca7825f0e82b923 Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Tue, 28 Apr 2020 15:31:42 -0700 Subject: [PATCH] Maintain global list of caches; purge on low memory Bug: 140788621 Test: m Merged-In: I3ba88e0a6f6c0f26465903988e7432156bd5be20 Change-Id: I3ba88e0a6f6c0f26465903988e7432156bd5be20 (cherry picked from commit 22c2ddb201e52e54d82d2a8dba77c19d74e654ba) --- core/java/android/app/ActivityThread.java | 6 +++++ .../android/app/PropertyInvalidatedCache.java | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index eea1d69b6326a..c6e2d5290d2e2 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6202,6 +6202,12 @@ public final class ActivityThread extends ClientTransactionHandler { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory"); if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level); + if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) { + for (PropertyInvalidatedCache pic : PropertyInvalidatedCache.getActiveCaches()) { + pic.clear(); + } + } + ArrayList callbacks = collectComponentCallbacks(true, null); final int N = callbacks.size(); diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 3110e18985b04..58705434f7745 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -27,11 +27,13 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; import java.util.Random; +import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicLong; /** @@ -197,6 +199,14 @@ public abstract class PropertyInvalidatedCache { @GuardedBy("sCorkLock") private static final HashMap sCorks = new HashMap<>(); + /** + * Weakly references all cache objects in the current process, allowing us to iterate over + * them all for purposes like issuing debug dumps and reacting to memory pressure. + */ + @GuardedBy("sCorkLock") + private static final WeakHashMap sCaches = + new WeakHashMap<>(); + private final Object mLock = new Object(); /** @@ -241,6 +251,9 @@ public abstract class PropertyInvalidatedCache { return size() > maxEntries; } }; + synchronized (sCorkLock) { + sCaches.put(this, null); + } } /** @@ -248,6 +261,9 @@ public abstract class PropertyInvalidatedCache { */ public final void clear() { synchronized (mLock) { + if (DEBUG) { + Log.d(TAG, "clearing cache for " + mPropertyName); + } mCache.clear(); } } @@ -710,4 +726,13 @@ public abstract class PropertyInvalidatedCache { Log.d(TAG, "disabling all caches in the process"); sEnabled = false; } + + /** + * Return a list of caches alive at the current time. + */ + public static ArrayList getActiveCaches() { + synchronized (sCorkLock) { + return new ArrayList(sCaches.keySet()); + } + } }