Home | History | Annotate | Download | only in leak
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.systemui.util.leak;
     18 
     19 import android.os.Build;
     20 
     21 import com.android.internal.annotations.VisibleForTesting;
     22 import com.android.internal.util.IndentingPrintWriter;
     23 import com.android.systemui.Dumpable;
     24 
     25 import java.io.FileDescriptor;
     26 import java.io.PrintWriter;
     27 import java.io.Writer;
     28 import java.util.Collection;
     29 
     30 /**
     31  * Detects leaks.
     32  */
     33 public class LeakDetector implements Dumpable {
     34 
     35     public static final boolean ENABLED = Build.IS_DEBUGGABLE;
     36 
     37     private final TrackedCollections mTrackedCollections;
     38     private final TrackedGarbage mTrackedGarbage;
     39     private final TrackedObjects mTrackedObjects;
     40 
     41     @VisibleForTesting
     42     public LeakDetector(TrackedCollections trackedCollections,
     43             TrackedGarbage trackedGarbage,
     44             TrackedObjects trackedObjects) {
     45         mTrackedCollections = trackedCollections;
     46         mTrackedGarbage = trackedGarbage;
     47         mTrackedObjects = trackedObjects;
     48     }
     49 
     50     /**
     51      * Tracks an instance that has a high leak risk (i.e. has complex ownership and references
     52      * a large amount of memory).
     53      *
     54      * The LeakDetector will monitor and keep weak references to such instances, dump statistics
     55      * about them in a bugreport, and in the future dump the heap if their count starts growing
     56      * unreasonably.
     57      *
     58      * This should be called when the instance is first constructed.
     59      */
     60     public <T> void trackInstance(T object) {
     61         if (mTrackedObjects != null) {
     62             mTrackedObjects.track(object);
     63         }
     64     }
     65 
     66     /**
     67      * Tracks a collection that is at risk of leaking large objects, e.g. a collection of
     68      * dynamically registered listeners.
     69      *
     70      * The LeakDetector will monitor and keep weak references to such collections, dump
     71      * statistics about them in a bugreport, and in the future dump the heap if their size starts
     72      * growing unreasonably.
     73      *
     74      * This should be called whenever the collection grows.
     75      *
     76      * @param tag A tag for labeling the collection in a bugreport
     77      */
     78     public <T> void trackCollection(Collection<T> collection, String tag) {
     79         if (mTrackedCollections != null) {
     80             mTrackedCollections.track(collection, tag);
     81         }
     82     }
     83 
     84     /**
     85      * Tracks an instance that should become garbage soon.
     86      *
     87      * The LeakDetector will monitor and keep weak references to such garbage, dump
     88      * statistics about them in a bugreport, and in the future dump the heap if it is not
     89      * collected reasonably soon.
     90      *
     91      * This should be called when the last strong reference to the instance is dropped.
     92      */
     93     public void trackGarbage(Object o) {
     94         if (mTrackedGarbage != null) {
     95             mTrackedGarbage.track(o);
     96         }
     97     }
     98 
     99     TrackedGarbage getTrackedGarbage() {
    100         return mTrackedGarbage;
    101     }
    102 
    103     @Override
    104     public void dump(FileDescriptor df, PrintWriter w, String[] args) {
    105         IndentingPrintWriter pw = new IndentingPrintWriter(w, "  ");
    106 
    107         pw.println("SYSUI LEAK DETECTOR");
    108         pw.increaseIndent();
    109 
    110         if (mTrackedCollections != null && mTrackedGarbage != null) {
    111             pw.println("TrackedCollections:");
    112             pw.increaseIndent();
    113             mTrackedCollections.dump(pw, (col) -> !TrackedObjects.isTrackedObject(col));
    114             pw.decreaseIndent();
    115             pw.println();
    116 
    117             pw.println("TrackedObjects:");
    118             pw.increaseIndent();
    119             mTrackedCollections.dump(pw, TrackedObjects::isTrackedObject);
    120             pw.decreaseIndent();
    121             pw.println();
    122 
    123             pw.print("TrackedGarbage:");
    124             pw.increaseIndent();
    125             mTrackedGarbage.dump(pw);
    126             pw.decreaseIndent();
    127         } else {
    128             pw.println("disabled");
    129         }
    130         pw.decreaseIndent();
    131         pw.println();
    132     }
    133 
    134     public static LeakDetector create() {
    135         if (ENABLED) {
    136             TrackedCollections collections = new TrackedCollections();
    137             return new LeakDetector(collections, new TrackedGarbage(collections),
    138                     new TrackedObjects(collections));
    139         } else {
    140             return new LeakDetector(null, null, null);
    141         }
    142     }
    143 }
    144