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