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.SystemClock;
20e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
21e1e0b483be87d23383832aa6b558364a730c690fAdrian Roosimport java.lang.ref.Reference;
22e1e0b483be87d23383832aa6b558364a730c690fAdrian Roosimport java.lang.ref.ReferenceQueue;
23e1e0b483be87d23383832aa6b558364a730c690fAdrian Roosimport java.lang.ref.WeakReference;
24e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
25e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos/**
26e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos * Utilities for writing tests that manipulate weak or other references.
27e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos */
28e1e0b483be87d23383832aa6b558364a730c690fAdrian Roospublic class ReferenceTestUtils {
29e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
30e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    /** Returns a runnable that blocks until {@code o} has been collected. */
31e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    public static CollectionWaiter createCollectionWaiter(Object o) {
32e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        ReferenceQueue<Object> q = new ReferenceQueue<>();
33e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        Reference<?> ref = new WeakReference<>(o, q);
34e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        o = null; // Ensure this variable can't be referenced from the lambda.
35e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
36e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        return () -> {
37e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            Runtime.getRuntime().gc();
38e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            while (true) {
39e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                try {
40e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                    if (q.remove(5_000) == ref) {
41e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                        return;
42e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                    } else {
43e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                        throw new RuntimeException("timeout while waiting for object collection");
44e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                    }
45e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                } catch (InterruptedException e) {
46e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                    Thread.currentThread().interrupt();
47e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                }
48e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            }
49e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        };
50e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    }
51e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
52e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    public static void waitForCondition(Condition p) {
53e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        long deadline = SystemClock.uptimeMillis() + 5_000;
54e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        while (!p.apply()) {
55e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            if (SystemClock.uptimeMillis() > deadline) {
56e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos                throw new RuntimeException("timeout while waiting for condition");
57e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            }
58e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos            SystemClock.sleep(100);
59e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        }
60e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    }
61e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
62e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    public interface Condition {
63e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        boolean apply();
64e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    }
65e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos
66e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    public interface CollectionWaiter {
67e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos        void waitForCollection();
68e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos    }
69e1e0b483be87d23383832aa6b558364a730c690fAdrian Roos}
70