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 android.os; 18 19 import com.android.internal.ravenwood.RavenwoodEnvironment; 20 21 import dalvik.annotation.optimization.CriticalNative; 22 import dalvik.annotation.optimization.FastNative; 23 24 import libcore.util.NativeAllocationRegistry; 25 26 import java.util.concurrent.atomic.AtomicInteger; 27 28 /** 29 * Writes trace events to the perfetto trace buffer. These trace events can be 30 * collected and visualized using the Perfetto UI. 31 * 32 * <p>This tracing mechanism is independent of the method tracing mechanism 33 * offered by {@link Debug#startMethodTracing} or {@link Trace}. 34 * 35 * @hide 36 */ 37 @android.ravenwood.annotation.RavenwoodKeepWholeClass 38 public final class PerfettoTrace { 39 private static final String TAG = "PerfettoTrace"; 40 41 // Keep in sync with C++ 42 private static final int PERFETTO_TE_TYPE_SLICE_BEGIN = 1; 43 private static final int PERFETTO_TE_TYPE_SLICE_END = 2; 44 private static final int PERFETTO_TE_TYPE_INSTANT = 3; 45 private static final int PERFETTO_TE_TYPE_COUNTER = 4; 46 47 private static final boolean IS_FLAG_ENABLED = android.os.Flags.perfettoSdkTracingV2(); 48 49 /** 50 * For fetching the next flow event id in a process. 51 */ 52 private static final AtomicInteger sFlowEventId = new AtomicInteger(); 53 54 public static final PerfettoTrace.Category MQ_CATEGORY = new PerfettoTrace.Category("mq"); 55 56 /** 57 * Perfetto category a trace event belongs to. 58 * Registering a category is not sufficient to capture events within the category, it must 59 * also be enabled in the trace config. 60 */ 61 @android.ravenwood.annotation.RavenwoodKeepWholeClass 62 public static final class Category implements PerfettoTrackEventExtra.PerfettoPointer { 63 private static final NativeAllocationRegistry sRegistry = 64 NativeAllocationRegistry.createMalloced( 65 Category.class.getClassLoader(), native_delete()); 66 67 private final long mPtr; 68 private final long mExtraPtr; 69 private final String mName; 70 private final String mTag; 71 private final String mSeverity; 72 private boolean mIsRegistered; 73 74 /** 75 * Category ctor. 76 * 77 * @param name The category name. 78 */ Category(String name)79 public Category(String name) { 80 this(name, "", ""); 81 } 82 83 /** 84 * Category ctor. 85 * 86 * @param name The category name. 87 * @param tag An atrace tag name that this category maps to. 88 */ Category(String name, String tag)89 public Category(String name, String tag) { 90 this(name, tag, ""); 91 } 92 93 /** 94 * Category ctor. 95 * 96 * @param name The category name. 97 * @param tag An atrace tag name that this category maps to. 98 * @param severity A Log style severity string for the category. 99 */ Category(String name, String tag, String severity)100 public Category(String name, String tag, String severity) { 101 mName = name; 102 mTag = tag; 103 mSeverity = severity; 104 mPtr = native_init(name, tag, severity); 105 mExtraPtr = native_get_extra_ptr(mPtr); 106 if (!RavenwoodEnvironment.getInstance().isRunningOnRavenwood()) { 107 sRegistry.registerNativeAllocation(this, mPtr); 108 } 109 } 110 111 @FastNative 112 @android.ravenwood.annotation.RavenwoodReplace native_init(String name, String tag, String severity)113 private static native long native_init(String name, String tag, String severity); 114 @CriticalNative 115 @android.ravenwood.annotation.RavenwoodReplace native_delete()116 private static native long native_delete(); 117 @CriticalNative native_register(long ptr)118 private static native void native_register(long ptr); 119 @CriticalNative native_unregister(long ptr)120 private static native void native_unregister(long ptr); 121 @CriticalNative native_is_enabled(long ptr)122 private static native boolean native_is_enabled(long ptr); 123 @CriticalNative 124 @android.ravenwood.annotation.RavenwoodReplace native_get_extra_ptr(long ptr)125 private static native long native_get_extra_ptr(long ptr); 126 native_init$ravenwood(String name, String tag, String severity)127 private static long native_init$ravenwood(String name, String tag, String severity) { 128 // Tracing currently completely disabled under Ravenwood 129 return 0; 130 } 131 native_delete$ravenwood()132 private static long native_delete$ravenwood() { 133 // Tracing currently completely disabled under Ravenwood 134 return 0; 135 } 136 native_get_extra_ptr$ravenwood(long ptr)137 private static long native_get_extra_ptr$ravenwood(long ptr) { 138 // Tracing currently completely disabled under Ravenwood 139 return 0; 140 } 141 142 /** 143 * Register the category. 144 */ register()145 public Category register() { 146 native_register(mPtr); 147 mIsRegistered = true; 148 return this; 149 } 150 151 /** 152 * Unregister the category. 153 */ unregister()154 public Category unregister() { 155 native_unregister(mPtr); 156 mIsRegistered = false; 157 return this; 158 } 159 160 /** 161 * Whether the category is enabled or not. 162 */ 163 @android.ravenwood.annotation.RavenwoodReplace isEnabled()164 public boolean isEnabled() { 165 return IS_FLAG_ENABLED && native_is_enabled(mPtr); 166 } 167 isEnabled$ravenwood()168 public boolean isEnabled$ravenwood() { 169 // Tracing currently completely disabled under Ravenwood 170 return false; 171 } 172 173 /** 174 * Whether the category is registered or not. 175 */ isRegistered()176 public boolean isRegistered() { 177 return mIsRegistered; 178 } 179 180 /** 181 * Returns the native pointer for the category. 182 */ 183 @Override getPtr()184 public long getPtr() { 185 return mExtraPtr; 186 } 187 } 188 189 /** 190 * Manages a perfetto tracing session. 191 * Constructing this object with a config automatically starts a tracing session. Each session 192 * must be closed after use and then the resulting trace bytes can be read. 193 * 194 * The session could be in process or system wide, depending on {@code isBackendInProcess}. 195 * This functionality is intended for testing. 196 */ 197 public static final class Session { 198 private final long mPtr; 199 200 /** 201 * Session ctor. 202 */ Session(boolean isBackendInProcess, byte[] config)203 public Session(boolean isBackendInProcess, byte[] config) { 204 mPtr = native_start_session(isBackendInProcess, config); 205 } 206 207 /** 208 * Closes the session and returns the trace. 209 */ close()210 public byte[] close() { 211 return native_stop_session(mPtr); 212 } 213 } 214 215 @CriticalNative native_get_process_track_uuid()216 private static native long native_get_process_track_uuid(); 217 @CriticalNative native_get_thread_track_uuid(long tid)218 private static native long native_get_thread_track_uuid(long tid); 219 220 @FastNative native_activate_trigger(String name, int ttlMs)221 private static native void native_activate_trigger(String name, int ttlMs); 222 @FastNative native_register(boolean isBackendInProcess)223 private static native void native_register(boolean isBackendInProcess); 224 native_start_session(boolean isBackendInProcess, byte[] config)225 private static native long native_start_session(boolean isBackendInProcess, byte[] config); native_stop_session(long ptr)226 private static native byte[] native_stop_session(long ptr); 227 228 /** 229 * Writes a trace message to indicate a given section of code was invoked. 230 * 231 * @param category The perfetto category. 232 * @param eventName The event name to appear in the trace. 233 */ instant(Category category, String eventName)234 public static PerfettoTrackEventExtra.Builder instant(Category category, String eventName) { 235 return PerfettoTrackEventExtra.builder(category.isEnabled()) 236 .init(PERFETTO_TE_TYPE_INSTANT, category) 237 .setEventName(eventName); 238 } 239 240 /** 241 * Writes a trace message to indicate the start of a given section of code. 242 * 243 * @param category The perfetto category. 244 * @param eventName The event name to appear in the trace. 245 */ begin(Category category, String eventName)246 public static PerfettoTrackEventExtra.Builder begin(Category category, String eventName) { 247 return PerfettoTrackEventExtra.builder(category.isEnabled()) 248 .init(PERFETTO_TE_TYPE_SLICE_BEGIN, category) 249 .setEventName(eventName); 250 } 251 252 /** 253 * Writes a trace message to indicate the end of a given section of code. 254 * 255 * @param category The perfetto category. 256 */ end(Category category)257 public static PerfettoTrackEventExtra.Builder end(Category category) { 258 return PerfettoTrackEventExtra.builder(category.isEnabled()) 259 .init(PERFETTO_TE_TYPE_SLICE_END, category); 260 } 261 262 /** 263 * Writes a trace message to indicate the value of a given section of code. 264 * 265 * @param category The perfetto category. 266 * @param value The value of the counter. 267 */ counter(Category category, long value)268 public static PerfettoTrackEventExtra.Builder counter(Category category, long value) { 269 return PerfettoTrackEventExtra.builder(category.isEnabled()) 270 .init(PERFETTO_TE_TYPE_COUNTER, category) 271 .setCounter(value); 272 } 273 274 /** 275 * Writes a trace message to indicate the value of a given section of code. 276 * 277 * @param category The perfetto category. 278 * @param value The value of the counter. 279 * @param trackName The trackName for the event. 280 */ counter( Category category, long value, String trackName)281 public static PerfettoTrackEventExtra.Builder counter( 282 Category category, long value, String trackName) { 283 return counter(category, value).usingProcessCounterTrack(trackName); 284 } 285 286 /** 287 * Writes a trace message to indicate the value of a given section of code. 288 * 289 * @param category The perfetto category. 290 * @param value The value of the counter. 291 */ counter(Category category, double value)292 public static PerfettoTrackEventExtra.Builder counter(Category category, double value) { 293 return PerfettoTrackEventExtra.builder(category.isEnabled()) 294 .init(PERFETTO_TE_TYPE_COUNTER, category) 295 .setCounter(value); 296 } 297 298 /** 299 * Writes a trace message to indicate the value of a given section of code. 300 * 301 * @param category The perfetto category. 302 * @param value The value of the counter. 303 * @param trackName The trackName for the event. 304 */ counter( Category category, double value, String trackName)305 public static PerfettoTrackEventExtra.Builder counter( 306 Category category, double value, String trackName) { 307 return counter(category, value).usingProcessCounterTrack(trackName); 308 } 309 310 /** 311 * Returns the next flow id to be used. 312 */ getFlowId()313 public static int getFlowId() { 314 return sFlowEventId.incrementAndGet(); 315 } 316 317 /** 318 * Returns the global track uuid that can be used as a parent track uuid. 319 */ getGlobalTrackUuid()320 public static long getGlobalTrackUuid() { 321 return 0; 322 } 323 324 /** 325 * Returns the process track uuid that can be used as a parent track uuid. 326 */ getProcessTrackUuid()327 public static long getProcessTrackUuid() { 328 if (!IS_FLAG_ENABLED) { 329 return 0; 330 } 331 return native_get_process_track_uuid(); 332 } 333 334 /** 335 * Given a thread tid, returns the thread track uuid that can be used as a parent track uuid. 336 */ getThreadTrackUuid(long tid)337 public static long getThreadTrackUuid(long tid) { 338 if (!IS_FLAG_ENABLED) { 339 return 0; 340 } 341 return native_get_thread_track_uuid(tid); 342 } 343 344 /** 345 * Activates a trigger by name {@code triggerName} with expiry in {@code ttlMs}. 346 */ activateTrigger(String triggerName, int ttlMs)347 public static void activateTrigger(String triggerName, int ttlMs) { 348 if (!IS_FLAG_ENABLED) { 349 return; 350 } 351 native_activate_trigger(triggerName, ttlMs); 352 } 353 354 /** 355 * Registers the process with Perfetto. 356 */ register(boolean isBackendInProcess)357 public static void register(boolean isBackendInProcess) { 358 native_register(isBackendInProcess); 359 } 360 361 /** 362 * Registers categories with Perfetto. 363 */ registerCategories()364 public static void registerCategories() { 365 MQ_CATEGORY.register(); 366 } 367 } 368