1340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk/*
2340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * Copyright (C) 2017 The Android Open Source Project
3340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk *
4340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * except in compliance with the License. You may obtain a copy of the License at
6340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk *
7340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk *      http://www.apache.org/licenses/LICENSE-2.0
8340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk *
9340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
10340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * KIND, either express or implied. See the License for the specific language governing
12340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk * permissions and limitations under the License.
13340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk */
14340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
15340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpackage android.testing;
16340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
17340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport android.util.ArrayMap;
18340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport android.util.Log;
19340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
20340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport org.junit.Assert;
21340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport org.junit.rules.TestWatcher;
22340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport org.junit.runner.Description;
23340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
24340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.io.PrintWriter;
25340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.io.StringWriter;
26340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.util.ArrayList;
27340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.util.HashMap;
28340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.util.List;
29340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkimport java.util.Map;
30340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
31340b0e5216b4fcc435e0459b1ca46155a572100dJason Monkpublic class LeakCheck extends TestWatcher {
32340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
33340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    private final Map<String, Tracker> mTrackers = new HashMap<>();
34340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
35340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    public LeakCheck() {
36340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
37340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
38340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    @Override
39340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    protected void succeeded(Description description) {
40340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        verify();
41340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
42340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
43340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    public Tracker getTracker(String tag) {
44340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        Tracker t = mTrackers.get(tag);
45340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        if (t == null) {
46340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            t = new Tracker();
47340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            mTrackers.put(tag, t);
48340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
49340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        return t;
50340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
51340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
52340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    public void verify() {
53340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        mTrackers.values().forEach(Tracker::verify);
54340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
55340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
56340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    public static class LeakInfo {
57340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        private static final String TAG = "LeakInfo";
58340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        private List<Throwable> mThrowables = new ArrayList<>();
59340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
60340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        LeakInfo() {
61340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
62340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
63340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        public void addAllocation(Throwable t) {
64340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
65340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            mThrowables.add(t);
66340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
67340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
68340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        public void clearAllocations() {
69340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            mThrowables.clear();
70340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
71340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
72340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        void verify() {
73340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            if (mThrowables.size() == 0) return;
74340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            Log.e(TAG, "Listener or binding not properly released");
75340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            for (Throwable t : mThrowables) {
76340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk                Log.e(TAG, "Allocation found", t);
77340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            }
78340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            StringWriter writer = new StringWriter();
79340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            mThrowables.get(0).printStackTrace(new PrintWriter(writer));
80340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            Assert.fail("Listener or binding not properly released\n"
81340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk                    + writer.toString());
82340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
83340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
84340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
85340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    public static class Tracker {
86340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
87340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
88340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        public LeakInfo getLeakInfo(Object object) {
89340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            LeakInfo leakInfo = mObjects.get(object);
90340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            if (leakInfo == null) {
91340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk                leakInfo = new LeakInfo();
92340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk                mObjects.put(object, leakInfo);
93340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            }
94340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            return leakInfo;
95340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
96340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk
97340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        void verify() {
98340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk            mObjects.values().forEach(LeakInfo::verify);
99340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk        }
100340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk    }
101340b0e5216b4fcc435e0459b1ca46155a572100dJason Monk}
102