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