Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13eb52a2 authored by Lee Shombert's avatar Lee Shombert Committed by Android (Google) Code Review
Browse files

Merge "Allow selective detailed dumps of caches" into tm-dev

parents c54e991b 23e59a07
Loading
Loading
Loading
Loading
+99 −21
Original line number Diff line number Diff line
@@ -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");