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