| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package com.android.systemui.util.leak; |
| |
| |
| import android.support.test.filters.SmallTest; |
| import android.support.test.runner.AndroidJUnit4; |
| |
| import com.android.systemui.SysuiTestCase; |
| import com.android.systemui.util.leak.ReferenceTestUtils.CollectionWaiter; |
| |
| import org.junit.Before; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| import java.io.FileDescriptor; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.function.BiConsumer; |
| import java.util.function.Consumer; |
| |
| @SmallTest |
| @RunWith(AndroidJUnit4.class) |
| public class LeakDetectorTest extends SysuiTestCase { |
| |
| private LeakDetector mLeakDetector; |
| |
| // The references for which collection is observed are stored in fields. The allocation and |
| // of these references happens in separate methods (trackObjectWith/trackCollectionWith) |
| // from where they are set to null. The generated code might keep the allocated reference |
| // alive in a dex register when compiling in release mode. As R8 is used to compile this |
| // test the --dontoptimize flag is also required to ensure that these methods are not |
| // inlined, as that would defeat the purpose of having the mutation in methods. |
| private Object mObject; |
| private Collection<?> mCollection; |
| |
| private CollectionWaiter trackObjectWith(Consumer<Object> tracker) { |
| mObject = new Object(); |
| CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mObject); |
| tracker.accept(mObject); |
| return collectionWaiter; |
| } |
| |
| private CollectionWaiter trackCollectionWith( |
| BiConsumer<? super Collection<?>, String> tracker) { |
| mCollection = new ArrayList<>(); |
| CollectionWaiter collectionWaiter = ReferenceTestUtils.createCollectionWaiter(mCollection); |
| tracker.accept(mCollection, "tag"); |
| return collectionWaiter; |
| } |
| |
| @Before |
| public void setup() { |
| mLeakDetector = LeakDetector.create(); |
| |
| // Note: Do not try to factor out object / collection waiter creation. The optimizer will |
| // try and cache accesses to fields and thus create a GC root for the duration of the test |
| // method, thus breaking the test. |
| } |
| |
| @Test |
| public void trackInstance_doesNotLeakTrackedObject() { |
| CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackInstance); |
| mObject = null; |
| collectionWaiter.waitForCollection(); |
| } |
| |
| @Ignore("b/75329085") |
| @Test |
| public void trackCollection_doesNotLeakTrackedObject() { |
| CollectionWaiter collectionWaiter = trackCollectionWith(mLeakDetector::trackCollection); |
| mCollection = null; |
| collectionWaiter.waitForCollection(); |
| } |
| |
| @Test |
| public void trackGarbage_doesNotLeakTrackedObject() { |
| CollectionWaiter collectionWaiter = trackObjectWith(mLeakDetector::trackGarbage); |
| mObject = null; |
| collectionWaiter.waitForCollection(); |
| } |
| |
| @Test |
| public void testDump() throws Exception { |
| Object o1 = new Object(); |
| Object o2 = new Object(); |
| Collection<Object> col1 = new ArrayList<>(); |
| |
| mLeakDetector.trackInstance(o1); |
| mLeakDetector.trackCollection(col1, "tag"); |
| mLeakDetector.trackGarbage(o2); |
| |
| FileOutputStream fos = new FileOutputStream("/dev/null"); |
| mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]); |
| } |
| |
| @Test |
| public void testDisabled() throws Exception { |
| mLeakDetector = new LeakDetector(null, null, null); |
| |
| Object o1 = new Object(); |
| Object o2 = new Object(); |
| Collection<Object> col1 = new ArrayList<>(); |
| |
| mLeakDetector.trackInstance(o1); |
| mLeakDetector.trackCollection(col1, "tag"); |
| mLeakDetector.trackGarbage(o2); |
| |
| FileOutputStream fos = new FileOutputStream("/dev/null"); |
| mLeakDetector.dump(fos.getFD(), new PrintWriter(fos), new String[0]); |
| } |
| } |