1 /* 2 * Copyright (C) 2020 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.tradefed.invoker.logger; 17 18 import com.android.tradefed.build.IBuildProvider; 19 import com.android.tradefed.device.metric.IMetricCollector; 20 import com.android.tradefed.postprocessor.IPostProcessor; 21 import com.android.tradefed.targetprep.ITargetPreparer; 22 import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; 23 import com.android.tradefed.testtype.IRemoteTest; 24 25 import com.google.common.collect.ImmutableSet; 26 27 import java.util.HashMap; 28 import java.util.Map; 29 import java.util.Set; 30 import java.util.concurrent.ConcurrentHashMap; 31 32 /** A utility to track the usage of the different Trade Fedederation objects. */ 33 public class TfObjectTracker { 34 35 public static final String TF_OBJECTS_TRACKING_KEY = "tf_objects_tracking"; 36 private static final Set<Class<?>> TRACKED_CLASSES = 37 ImmutableSet.of( 38 IBuildProvider.class, 39 IMetricCollector.class, 40 IMultiTargetPreparer.class, 41 IPostProcessor.class, 42 IRemoteTest.class, 43 ITargetPreparer.class); 44 TfObjectTracker()45 private TfObjectTracker() {} 46 47 private static final Map<ThreadGroup, Map<String, Long>> mPerGroupUsage = 48 new ConcurrentHashMap<ThreadGroup, Map<String, Long>>(); 49 50 /** Count the occurrence of a give class and its super classes until the Tradefed interface. */ countWithParents(Class<?> object)51 public static void countWithParents(Class<?> object) { 52 if (!count(object)) { 53 return; 54 } 55 // Track all the super class until not a TF interface to get a full picture. 56 countWithParents(object.getSuperclass()); 57 } 58 59 /** 60 * Count explicitly one class and its occurrences 61 * 62 * @param className The object to track 63 * @param occurrences current num of known occurrences 64 */ directCount(String className, long occurrences)65 public static void directCount(String className, long occurrences) { 66 ThreadGroup group = Thread.currentThread().getThreadGroup(); 67 if (mPerGroupUsage.get(group) == null) { 68 mPerGroupUsage.put(group, new ConcurrentHashMap<>()); 69 } 70 Map<String, Long> countMap = mPerGroupUsage.get(group); 71 long count = 0; 72 if (countMap.get(className) != null) { 73 count = countMap.get(className); 74 } 75 count += occurrences; 76 countMap.put(className, count); 77 } 78 79 /** 80 * Count the current occurrence only if it's part of the tracked objects. 81 * 82 * @param object The object to track 83 * @return True if the object was tracked, false otherwise. 84 */ count(Class<?> object)85 private static boolean count(Class<?> object) { 86 ThreadGroup group = Thread.currentThread().getThreadGroup(); 87 String qualifiedName = object.getName(); 88 89 boolean tracked = false; 90 for (Class<?> classTracked : TRACKED_CLASSES) { 91 if (classTracked.isAssignableFrom(object)) { 92 tracked = true; 93 break; 94 } 95 } 96 if (!tracked) { 97 return false; 98 } 99 // Don't track internal classes for now but return true to track subclass if needed. 100 if (qualifiedName.contains("$")) { 101 return true; 102 } 103 if (mPerGroupUsage.get(group) == null) { 104 mPerGroupUsage.put(group, new ConcurrentHashMap<>()); 105 } 106 Map<String, Long> countMap = mPerGroupUsage.get(group); 107 long count = 0; 108 if (countMap.get(qualifiedName) != null) { 109 count = countMap.get(qualifiedName); 110 } 111 count++; 112 countMap.put(qualifiedName, count); 113 return true; 114 } 115 116 /** Returns the usage of the tracked objects. */ getUsage()117 public static Map<String, Long> getUsage() { 118 ThreadGroup group = Thread.currentThread().getThreadGroup(); 119 if (mPerGroupUsage.get(group) == null) { 120 mPerGroupUsage.put(group, new ConcurrentHashMap<>()); 121 } 122 return new HashMap<>(mPerGroupUsage.get(group)); 123 } 124 125 /** Stop tracking the current invocation. This is called automatically by the harness. */ clearTracking()126 public static void clearTracking() { 127 ThreadGroup group = Thread.currentThread().getThreadGroup(); 128 mPerGroupUsage.remove(group); 129 } 130 } 131