1 /** 2 * Copyright (C) 2024 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 17 package com.android.server.profcollect; 18 19 import static com.android.server.profcollect.ProfcollectForwardingService.LOG_TAG; 20 21 import android.os.RemoteException; 22 import android.os.ServiceSpecificException; 23 import android.provider.DeviceConfig; 24 import android.util.Log; 25 26 import com.android.internal.os.BackgroundThread; 27 28 import java.time.Instant; 29 import java.util.concurrent.ThreadLocalRandom; 30 31 final class Utils { 32 33 private static Instant lastTraceTime = Instant.EPOCH; 34 private static final int TRACE_COOLDOWN_SECONDS = 30; 35 withFrequency(String configName, int defaultFrequency)36 static boolean withFrequency(String configName, int defaultFrequency) { 37 int threshold = DeviceConfig.getInt( 38 DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, configName, defaultFrequency); 39 int randomNum = ThreadLocalRandom.current().nextInt(100); 40 return randomNum < threshold; 41 } 42 43 /** 44 * Request a system-wide trace. 45 * Will be ignored if the device does not meet trace criteria or is being rate limited. 46 */ traceSystem(IProfCollectd iprofcollectd, String eventName)47 static boolean traceSystem(IProfCollectd iprofcollectd, String eventName) { 48 if (!checkPrerequisites(iprofcollectd)) { 49 return false; 50 } 51 BackgroundThread.get().getThreadHandler().post(() -> { 52 try { 53 iprofcollectd.trace_system(eventName); 54 } catch (RemoteException | ServiceSpecificException e) { 55 Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); 56 } 57 }); 58 return true; 59 } 60 61 /** 62 * Request a system-wide trace after a delay. 63 * Will be ignored if the device does not meet trace criteria or is being rate limited. 64 */ traceSystem(IProfCollectd iprofcollectd, String eventName, int delayMs)65 static boolean traceSystem(IProfCollectd iprofcollectd, String eventName, int delayMs) { 66 if (!checkPrerequisites(iprofcollectd)) { 67 return false; 68 } 69 BackgroundThread.get().getThreadHandler().postDelayed(() -> { 70 try { 71 iprofcollectd.trace_system(eventName); 72 } catch (RemoteException | ServiceSpecificException e) { 73 Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); 74 } 75 }, delayMs); 76 return true; 77 } 78 79 /** 80 * Request a single-process trace. 81 * Will be ignored if the device does not meet trace criteria or is being rate limited. 82 */ traceProcess(IProfCollectd iprofcollectd, String eventName, String processName, int durationMs)83 static boolean traceProcess(IProfCollectd iprofcollectd, 84 String eventName, String processName, int durationMs) { 85 if (!checkPrerequisites(iprofcollectd)) { 86 return false; 87 } 88 BackgroundThread.get().getThreadHandler().post(() -> { 89 try { 90 iprofcollectd.trace_process(eventName, 91 processName, 92 durationMs); 93 } catch (RemoteException | ServiceSpecificException e) { 94 Log.e(LOG_TAG, "Failed to initiate trace: " + e.getMessage()); 95 } 96 }); 97 return true; 98 } 99 100 /** 101 * Returns true if the last trace is within the cooldown period. If the last trace is outside 102 * the cooldown period, the last trace time is reset to the current time. 103 */ isInCooldownOrReset()104 private static boolean isInCooldownOrReset() { 105 if (!Instant.now().isBefore(lastTraceTime.plusSeconds(TRACE_COOLDOWN_SECONDS))) { 106 lastTraceTime = Instant.now(); 107 return false; 108 } 109 return true; 110 } 111 checkPrerequisites(IProfCollectd iprofcollectd)112 private static boolean checkPrerequisites(IProfCollectd iprofcollectd) { 113 if (iprofcollectd == null) { 114 return false; 115 } 116 if (isInCooldownOrReset()) { 117 return false; 118 } 119 return ProfcollectForwardingService.sVerityEnforced 120 && !ProfcollectForwardingService.sAdbActive 121 && ProfcollectForwardingService.sIsInteractive 122 && !ProfcollectForwardingService.sIsBatteryLow; 123 } 124 } 125