1 /**
2  * Copyright (C) 2019 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 package com.android.launcher3.util;
17 
18 import java.util.LinkedList;
19 import java.util.function.IntConsumer;
20 
21 public class TraceHelperForTest extends TraceHelper {
22 
23     private static final TraceHelperForTest INSTANCE_FOR_TEST = new TraceHelperForTest();
24 
25     private final ThreadLocal<LinkedList<TraceInfo>> mStack =
26             ThreadLocal.withInitial(LinkedList::new);
27 
28     private RaceConditionReproducer mRaceConditionReproducer;
29     private IntConsumer mFlagsChangeListener;
30 
setRaceConditionReproducer(RaceConditionReproducer reproducer)31     public static void setRaceConditionReproducer(RaceConditionReproducer reproducer) {
32         TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
33         INSTANCE_FOR_TEST.mRaceConditionReproducer = reproducer;
34     }
35 
cleanup()36     public static void cleanup() {
37         INSTANCE_FOR_TEST.mRaceConditionReproducer = null;
38         INSTANCE_FOR_TEST.mFlagsChangeListener = null;
39     }
40 
setFlagsChangeListener(IntConsumer listener)41     public static void setFlagsChangeListener(IntConsumer listener) {
42         TraceHelper.INSTANCE = INSTANCE_FOR_TEST;
43         INSTANCE_FOR_TEST.mFlagsChangeListener = listener;
44     }
45 
TraceHelperForTest()46     private TraceHelperForTest() { }
47 
48     @Override
beginSection(String sectionName, int flags)49     public Object beginSection(String sectionName, int flags) {
50         LinkedList<TraceInfo> stack = mStack.get();
51         TraceInfo info = new TraceInfo(sectionName, flags);
52         stack.add(info);
53 
54         if ((flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
55                  && mRaceConditionReproducer != null) {
56             mRaceConditionReproducer.onEvent(RaceConditionReproducer.enterEvt(sectionName));
57         }
58         updateBinderTracking(stack);
59 
60         super.beginSection(sectionName, flags);
61         return info;
62     }
63 
64     @Override
endSection(Object token)65     public void endSection(Object token) {
66         LinkedList<TraceInfo> stack = mStack.get();
67         if (stack.size() == 0) {
68             new Throwable().printStackTrace();
69         }
70         TraceInfo info = (TraceInfo) token;
71         stack.remove(info);
72         if ((info.flags & TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS) != 0
73                 && mRaceConditionReproducer != null) {
74             mRaceConditionReproducer.onEvent(RaceConditionReproducer.exitEvt(info.sectionName));
75         }
76         updateBinderTracking(stack);
77 
78         super.endSection(token);
79     }
80 
81     @Override
beginFlagsOverride(int flags)82     public Object beginFlagsOverride(int flags) {
83         LinkedList<TraceInfo> stack = mStack.get();
84         TraceInfo info = new TraceInfo(null, flags);
85         stack.add(info);
86         updateBinderTracking(stack);
87         super.beginFlagsOverride(flags);
88         return info;
89     }
90 
91     @Override
endFlagsOverride(Object token)92     public void endFlagsOverride(Object token) {
93         super.endFlagsOverride(token);
94         LinkedList<TraceInfo> stack = mStack.get();
95         TraceInfo info = (TraceInfo) token;
96         stack.remove(info);
97         updateBinderTracking(stack);
98     }
99 
updateBinderTracking(LinkedList<TraceInfo> stack)100     private void updateBinderTracking(LinkedList<TraceInfo> stack) {
101         if (mFlagsChangeListener != null) {
102             mFlagsChangeListener.accept(stack.stream()
103                     .mapToInt(info -> info.flags).reduce(0, (a, b) -> a | b));
104         }
105     }
106 
107     private static class TraceInfo {
108         public final String sectionName;
109         public final int flags;
110 
TraceInfo(String sectionName, int flags)111         TraceInfo(String sectionName, int flags) {
112             this.sectionName = sectionName;
113             this.flags = flags;
114         }
115     }
116 }
117