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 
17 package com.android.internal.util;
18 
19 import android.os.SystemClock;
20 import android.util.Log;
21 import android.util.SparseLongArray;
22 
23 import java.io.IOException;
24 
25 /**
26  * A trigger implementation with perfetto backend.
27  * @hide
28  */
29 public class PerfettoTrigger {
30     private static final String TAG = "PerfettoTrigger";
31     private static final String TRIGGER_COMMAND = "/system/bin/trigger_perfetto";
32     private static final long THROTTLE_MILLIS = 300000;
33     private static final SparseLongArray sLastInvocationPerTrigger = new SparseLongArray(100);
34     private static final Object sLock = new Object();
35 
36     /**
37      * @param triggerName The name of the trigger. Must match the value defined in the AOT
38      *                    Perfetto config.
39      */
trigger(String triggerName)40     public static void trigger(String triggerName) {
41         // Trace triggering has a non-negligible cost (fork+exec).
42         // To mitigate potential excessive triggering by the API client we ignore calls that happen
43         // too quickly after the most recent trigger.
44         synchronized (sLock) {
45             long lastTrigger = sLastInvocationPerTrigger.get(triggerName.hashCode());
46             long sinceLastTrigger = SystemClock.elapsedRealtime() - lastTrigger;
47             if (sinceLastTrigger < THROTTLE_MILLIS) {
48                 Log.v(TAG, "Not triggering " + triggerName
49                         + " - not enough time since last trigger");
50                 return;
51             }
52 
53             sLastInvocationPerTrigger.put(triggerName.hashCode(), SystemClock.elapsedRealtime());
54         }
55 
56         try {
57             ProcessBuilder pb = new ProcessBuilder(TRIGGER_COMMAND, triggerName);
58             Log.v(TAG, "Triggering " + String.join(" ", pb.command()));
59             pb.start();
60         } catch (IOException e) {
61             Log.w(TAG, "Failed to trigger " + triggerName, e);
62         }
63     }
64 }
65