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 20 import android.support.test.filters.SmallTest; 21 import android.support.test.runner.AndroidJUnit4; 22 23 import com.android.systemui.SysuiTestCase; 24 import com.android.systemui.util.leak.ReferenceTestUtils.CollectionWaiter; 25 26 import org.junit.Before; 27 import org.junit.Ignore; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 31 import java.io.FileDescriptor; 32 import java.io.FileNotFoundException; 33 import java.io.FileOutputStream; 34 import java.io.PrintWriter; 35 import java.util.ArrayList; 36 import java.util.Collection; 37 import java.util.function.BiConsumer; 38 import java.util.function.Consumer; 39 40 @SmallTest 41 @RunWith(AndroidJUnit4.class) 42 public class LeakDetectorTest extends SysuiTestCase { 43 44 private LeakDetector mLeakDetector; 45 46 // The references for which collection is observed are stored in fields. The allocation and 47 // of these references happens in separate methods (trackObjectWith/trackCollectionWith) 48 // from where they are set to null. The generated code might keep the allocated reference 49 // alive in a dex register when compiling in release mode. As R8 is used to compile this 50 // test the --dontoptimize flag is also required to ensure that these methods are not 51 // inlined, as that would defeat the purpose of having the mutation in methods. 52 private Object mObject; 53 private Collection<?> mCollection; 54 55 private CollectionWaiter trackObjectWith(Consumer<Object> tracker) { 56 mObject = new Object(); 57 CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mObject); 58 tracker.accept(mObject); 59 return collectionWaiter; 60 } 61 62 private CollectionWaiter trackCollectionWith( 63 BiConsumer<? super Collection<?>, String> tracker) { 64 mCollection = new ArrayList<>(); 65 CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mCollection); 66 tracker.accept(mCollection, "tag"); 67 return collectionWaiter; 68 } 69 70 @Before 71 public void setup() { 72 mLeakDetector = LeakDetector.create(); 73 74 // Note: Do not try to factor out object / collection waiter creation. The optimizer will 75 // try and cache accesses to fields and thus create a GC root for the duration of the test 76 // method, thus breaking the test. 77 } 78 79 @Test 80 public void trackInstance_doesNotLeakTrackedObject() { 81 CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackInstance); 82 mObject = null; 83 collectionWaiter.waitForCollection(); 84 } 85 86 @Ignore("b/75329085") 87 @Test 88 public void trackCollection_doesNotLeakTrackedObject() { 89 CollectionWaiter collectionWaiter = trackCollectionWith(mLeakDetector::trackCollection); 90 mCollection = null; 91 collectionWaiter.waitForCollection(); 92 } 93 94 @Test 95 public void trackGarbage_doesNotLeakTrackedObject() { 96 CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackGarbage); 97 mObject = null; 98 collectionWaiter.waitForCollection(); 99 } 100 101 @Test 102 public void testDump() throws Exception { 103 Object o1 = new Object(); 104 Object o2 = new Object(); 105 Collection<Object> col1 = new ArrayList<>(); 106 107 mLeakDetector.trackInstance(o1); 108 mLeakDetector.trackCollection(col1, "tag"); 109 mLeakDetector.trackGarbage(o2); 110 111 FileOutputStream fos = new FileOutputStream("/dev/null"); 112 mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]); 113 } 114 115 @Test 116 public void testDisabled() throws Exception { 117 mLeakDetector = new LeakDetector(null, null, null); 118 119 Object o1 = new Object(); 120 Object o2 = new Object(); 121 Collection<Object> col1 = new ArrayList<>(); 122 123 mLeakDetector.trackInstance(o1); 124 mLeakDetector.trackCollection(col1, "tag"); 125 mLeakDetector.trackGarbage(o2); 126 127 FileOutputStream fos = new FileOutputStream("/dev/null"); 128 mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]); 129 } 130 } 131