summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lee Shombert <shombert@google.com> 2022-04-26 14:27:14 -0700
committer Lee Shombert <shombert@google.com> 2022-04-28 14:49:33 +0000
commit23e59a07d9d9d15e8d18778b1d66e22a1b7c7e37 (patch)
treebf17a7a387218483e33b4da986e32f5fba018030
parentb5310919c809ae1bb0b30caf86afb02a54a64d3c (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.java120
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");