diff options
| author | 2022-04-26 14:27:14 -0700 | |
|---|---|---|
| committer | 2022-04-28 14:49:33 +0000 | |
| commit | 23e59a07d9d9d15e8d18778b1d66e22a1b7c7e37 (patch) | |
| tree | bf17a7a387218483e33b4da986e32f5fba018030 | |
| parent | b5310919c809ae1bb0b30caf86afb02a54a64d3c (diff) | |
Allow selective detailed dumps of caches
Bug: 227383489
'dumpsys cacheinfo' can now dump more information about caches, by
supplying arguments to the command. If no switches are specified
then the behavior is unchanged from the baseline. If any switches are
specified then zero or more caches are selected; the command dumps
statistics and content for every selected cache.
The four switches each include a key string.
The switch Selects a cache if
--------------------- ------------------
-name-has=<key> the cache name contains the key
-property-has=<key> the property name contains the key
-name-like=<regex> the cache name matches the regex key
-property-like=<regex> the property name matches the regex key
Tested by running the following commands and manually verifying the
output.
dumpsys cacheinfo com.android.systemui
dumpsys cacheinfo com.android.systemui -name-has=OrganizationOwned
dumpsys cacheinfo com.android.systemui -name-like=OrganizationOwned
- no results, as this regex does not match any cache
dumpsys cacheinfo com.android.systemui -name-like=.*OrganizationOwned.*
dumpsys cacheinfo com.android.systemui -property-has=package_info
dumpsys cacheinfo com.android.systemui -property-like=cache_key.package.*
Test:
* atest FrameworksCoreTests:IpcDataCacheTest
* atest FrameworksCoreTests:PropertyInvalidatedCacheTests
Change-Id: I141d7e85ba3ea8b0f2615bbd49537c1170fb5449
| -rw-r--r-- | core/java/android/app/PropertyInvalidatedCache.java | 120 |
1 files changed, 99 insertions, 21 deletions
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index add891d40d95..b49e571f74e1 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -374,10 +374,6 @@ public class PropertyInvalidatedCache<Query, Result> { private static final String TAG = "PropertyInvalidatedCache"; private static final boolean DEBUG = false; private static final boolean VERIFY = false; - // If this is true, dumpsys will dump the cache entries along with cache statistics. - // Most of the time this causes dumpsys to fail because the output stream is too - // large. Only set it to true in development images. - private static final boolean DETAILED = false; // Per-Cache performance counters. As some cache instances are declared static, @GuardedBy("mLock") @@ -1358,7 +1354,69 @@ public class PropertyInvalidatedCache<Query, Result> { } } - private void dumpContents(PrintWriter pw) { + /** + * Switches that can be used to control the detail emitted by a cache dump. The + * "CONTAINS" switches match if the cache (property) name contains the switch + * argument. The "LIKE" switches match if the cache (property) name matches the + * switch argument as a regex. The regular expression must match the entire name, + * which generally means it may need leading/trailing "." expressions. + */ + final static String NAME_CONTAINS = "-name-has="; + final static String NAME_LIKE = "-name-like="; + final static String PROPERTY_CONTAINS = "-property-has="; + final static String PROPERTY_LIKE = "-property-like="; + + /** + * Return true if any argument is a detailed specification switch. + */ + private static boolean anyDetailed(String[] args) { + for (String a : args) { + if (a.startsWith(NAME_CONTAINS) || a.startsWith(NAME_LIKE) + || a.startsWith(PROPERTY_CONTAINS) || a.startsWith(PROPERTY_LIKE)) { + return true; + } + } + return false; + } + + /** + * A helper method to determine if a string matches a switch. + */ + private static boolean chooses(String arg, String key, String reference, boolean contains) { + if (arg.startsWith(key)) { + final String value = arg.substring(key.length()); + if (contains) { + return reference.contains(value); + } else { + return reference.matches(value); + } + } + return false; + } + + /** + * Return true if this cache should be dumped in detail. This method is not called + * unless it has already been determined that there is at least one match requested. + */ + private boolean showDetailed(String[] args) { + for (String a : args) { + if (chooses(a, NAME_CONTAINS, cacheName(), true) + || chooses(a, NAME_LIKE, cacheName(), false) + || chooses(a, PROPERTY_CONTAINS, mPropertyName, true) + || chooses(a, PROPERTY_LIKE, mPropertyName, false)) { + return true; + } + } + return false; + } + + private void dumpContents(PrintWriter pw, boolean detailed, String[] args) { + // If the user has requested specific caches and this is not one of them, return + // immediately. + if (detailed && !showDetailed(args)) { + return; + } + long invalidateCount; long corkedInvalidates; synchronized (sCorkLock) { @@ -1386,9 +1444,15 @@ public class PropertyInvalidatedCache<Query, Result> { mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow)); pw.println(TextUtils.formatSimple(" Enabled: %s", mDisabled ? "false" : "true")); pw.println(""); + pw.flush(); + // No specific cache was requested. This is the default, and no details + // should be dumped. + if (!detailed) { + return; + } Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet(); - if (!DETAILED || cacheEntries.size() == 0) { + if (cacheEntries.size() == 0) { return; } @@ -1399,17 +1463,34 @@ public class PropertyInvalidatedCache<Query, Result> { pw.println(TextUtils.formatSimple(" Key: %s\n Value: %s\n", key, value)); } + pw.flush(); + } + } + + /** + * Dump the corking status. + */ + @GuardedBy("sCorkLock") + private static void dumpCorkInfo(PrintWriter pw) { + ArrayList<Map.Entry<String, Integer>> activeCorks = getActiveCorks(); + if (activeCorks.size() > 0) { + pw.println(" Corking Status:"); + for (int i = 0; i < activeCorks.size(); i++) { + Map.Entry<String, Integer> entry = activeCorks.get(i); + pw.println(TextUtils.formatSimple(" Property Name: %s Count: %d", + entry.getKey(), entry.getValue())); + } } } /** - * Dumps contents of every cache in the process to the provided ParcelFileDescriptor. + * Without arguments, this dumps statistics from every cache in the process to the + * provided ParcelFileDescriptor. Optional switches allow the caller to choose + * specific caches (selection is by cache name or property name); if these switches + * are used then the output includes both cache statistics and cache entries. * @hide */ public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) { - ArrayList<PropertyInvalidatedCache> activeCaches; - ArrayList<Map.Entry<String, Integer>> activeCorks; - try ( FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor()); PrintWriter pw = new FastPrintWriter(fout); @@ -1419,24 +1500,21 @@ public class PropertyInvalidatedCache<Query, Result> { return; } + // See if detailed is requested for any cache. If there is a specific detailed request, + // then only that cache is reported. + boolean detail = anyDetailed(args); + + ArrayList<PropertyInvalidatedCache> activeCaches; synchronized (sCorkLock) { activeCaches = getActiveCaches(); - activeCorks = getActiveCorks(); - - if (activeCorks.size() > 0) { - pw.println(" Corking Status:"); - for (int i = 0; i < activeCorks.size(); i++) { - Map.Entry<String, Integer> entry = activeCorks.get(i); - pw.println(TextUtils.formatSimple(" Property Name: %s Count: %d", - entry.getKey(), entry.getValue())); - } + if (!detail) { + dumpCorkInfo(pw); } } for (int i = 0; i < activeCaches.size(); i++) { PropertyInvalidatedCache currentCache = activeCaches.get(i); - currentCache.dumpContents(pw); - pw.flush(); + currentCache.dumpContents(pw, detail, args); } } catch (IOException e) { Log.e(TAG, "Failed to dump PropertyInvalidatedCache instances"); |