1 /* 2 * Copyright (C) 2012 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 static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 21 import android.annotation.NonNull; 22 import android.annotation.SystemApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 25 import dalvik.annotation.optimization.CriticalNative; 26 import dalvik.annotation.optimization.FastNative; 27 28 /** 29 * Writes trace events to the system trace buffer. These trace events can be 30 * collected and visualized using the Systrace tool. 31 * 32 * <p>This tracing mechanism is independent of the method tracing mechanism 33 * offered by {@link Debug#startMethodTracing}. In particular, it enables 34 * tracing of events that occur across multiple processes. 35 * <p>For information about using the Systrace tool, read <a 36 * href="{@docRoot}tools/debugging/systrace.html">Analyzing Display and Performance 37 * with Systrace</a>. 38 */ 39 @android.ravenwood.annotation.RavenwoodKeepWholeClass 40 public final class Trace { 41 /* 42 * Writes trace events to the kernel trace buffer. These trace events can be 43 * collected using the "atrace" program for offline analysis. 44 */ 45 46 private static final String TAG = "Trace"; 47 48 // These tags must be kept in sync with system/core/include/cutils/trace.h. 49 // They should also be added to frameworks/native/cmds/atrace/atrace.cpp. 50 /** @hide */ 51 public static final long TRACE_TAG_NEVER = 0; 52 /** @hide */ 53 public static final long TRACE_TAG_ALWAYS = 1L << 0; 54 /** @hide */ 55 public static final long TRACE_TAG_GRAPHICS = 1L << 1; 56 /** @hide */ 57 public static final long TRACE_TAG_INPUT = 1L << 2; 58 /** @hide */ 59 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 60 public static final long TRACE_TAG_VIEW = 1L << 3; 61 /** @hide */ 62 public static final long TRACE_TAG_WEBVIEW = 1L << 4; 63 /** @hide */ 64 public static final long TRACE_TAG_WINDOW_MANAGER = 1L << 5; 65 /** @hide */ 66 public static final long TRACE_TAG_ACTIVITY_MANAGER = 1L << 6; 67 /** @hide */ 68 public static final long TRACE_TAG_SYNC_MANAGER = 1L << 7; 69 /** @hide */ 70 public static final long TRACE_TAG_AUDIO = 1L << 8; 71 /** @hide */ 72 public static final long TRACE_TAG_VIDEO = 1L << 9; 73 /** @hide */ 74 public static final long TRACE_TAG_CAMERA = 1L << 10; 75 /** @hide */ 76 public static final long TRACE_TAG_HAL = 1L << 11; 77 /** @hide */ 78 @UnsupportedAppUsage 79 public static final long TRACE_TAG_APP = 1L << 12; 80 /** @hide */ 81 public static final long TRACE_TAG_RESOURCES = 1L << 13; 82 /** @hide */ 83 public static final long TRACE_TAG_DALVIK = 1L << 14; 84 /** @hide */ 85 public static final long TRACE_TAG_RS = 1L << 15; 86 /** @hide */ 87 public static final long TRACE_TAG_BIONIC = 1L << 16; 88 /** @hide */ 89 public static final long TRACE_TAG_POWER = 1L << 17; 90 /** @hide */ 91 public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18; 92 /** @hide */ 93 public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19; 94 /** @hide */ 95 public static final long TRACE_TAG_DATABASE = 1L << 20; 96 /** @hide */ 97 @SystemApi(client = MODULE_LIBRARIES) 98 public static final long TRACE_TAG_NETWORK = 1L << 21; 99 /** @hide */ 100 public static final long TRACE_TAG_ADB = 1L << 22; 101 /** @hide */ 102 public static final long TRACE_TAG_VIBRATOR = 1L << 23; 103 /** @hide */ 104 @SystemApi 105 public static final long TRACE_TAG_AIDL = 1L << 24; 106 /** @hide */ 107 public static final long TRACE_TAG_NNAPI = 1L << 25; 108 /** @hide */ 109 public static final long TRACE_TAG_RRO = 1L << 26; 110 /** @hide */ 111 public static final long TRACE_TAG_THERMAL = 1L << 27; 112 113 private static final long TRACE_TAG_NOT_READY = 1L << 63; 114 /** @hide **/ 115 public static final int MAX_SECTION_NAME_LEN = 127; 116 117 // Must be volatile to avoid word tearing. 118 // This is only kept in case any apps get this by reflection but do not 119 // check the return value for null. 120 @UnsupportedAppUsage 121 private static volatile long sEnabledTags = TRACE_TAG_NOT_READY; 122 123 private static int sZygoteDebugFlags = 0; 124 125 @UnsupportedAppUsage 126 @CriticalNative 127 @android.ravenwood.annotation.RavenwoodReplace nativeIsTagEnabled(long tag)128 private static native boolean nativeIsTagEnabled(long tag); 129 @android.ravenwood.annotation.RavenwoodReplace nativeSetAppTracingAllowed(boolean allowed)130 private static native void nativeSetAppTracingAllowed(boolean allowed); 131 @android.ravenwood.annotation.RavenwoodReplace nativeSetTracingEnabled(boolean allowed)132 private static native void nativeSetTracingEnabled(boolean allowed); 133 nativeIsTagEnabled$ravenwood(long traceTag)134 private static boolean nativeIsTagEnabled$ravenwood(long traceTag) { 135 // Tracing currently completely disabled under Ravenwood 136 return false; 137 } 138 nativeSetAppTracingAllowed$ravenwood(boolean allowed)139 private static void nativeSetAppTracingAllowed$ravenwood(boolean allowed) { 140 // Tracing currently completely disabled under Ravenwood 141 } 142 nativeSetTracingEnabled$ravenwood(boolean allowed)143 private static void nativeSetTracingEnabled$ravenwood(boolean allowed) { 144 // Tracing currently completely disabled under Ravenwood 145 } 146 147 @FastNative nativeTraceCounter(long tag, String name, long value)148 private static native void nativeTraceCounter(long tag, String name, long value); 149 @FastNative nativeTraceBegin(long tag, String name)150 private static native void nativeTraceBegin(long tag, String name); 151 @FastNative nativeTraceEnd(long tag)152 private static native void nativeTraceEnd(long tag); 153 @FastNative nativeAsyncTraceBegin(long tag, String name, int cookie)154 private static native void nativeAsyncTraceBegin(long tag, String name, int cookie); 155 @FastNative nativeAsyncTraceEnd(long tag, String name, int cookie)156 private static native void nativeAsyncTraceEnd(long tag, String name, int cookie); 157 @FastNative nativeAsyncTraceForTrackBegin(long tag, String trackName, String name, int cookie)158 private static native void nativeAsyncTraceForTrackBegin(long tag, 159 String trackName, String name, int cookie); 160 @FastNative nativeAsyncTraceForTrackEnd(long tag, String trackName, int cookie)161 private static native void nativeAsyncTraceForTrackEnd(long tag, 162 String trackName, int cookie); 163 @FastNative nativeInstant(long tag, String name)164 private static native void nativeInstant(long tag, String name); 165 @FastNative nativeInstantForTrack(long tag, String trackName, String name)166 private static native void nativeInstantForTrack(long tag, String trackName, String name); 167 @FastNative nativeRegisterWithPerfetto()168 private static native void nativeRegisterWithPerfetto(); 169 Trace()170 private Trace() { 171 } 172 173 /** 174 * Returns true if a trace tag is enabled. 175 * 176 * @param traceTag The trace tag to check. 177 * @return True if the trace tag is valid. 178 * 179 * @hide 180 */ 181 @UnsupportedAppUsage 182 @SystemApi(client = MODULE_LIBRARIES) isTagEnabled(long traceTag)183 public static boolean isTagEnabled(long traceTag) { 184 return nativeIsTagEnabled(traceTag); 185 } 186 187 /** 188 * Writes trace message to indicate the value of a given counter. 189 * 190 * @param traceTag The trace tag. 191 * @param counterName The counter name to appear in the trace. 192 * @param counterValue The counter value. 193 * 194 * @hide 195 */ 196 @UnsupportedAppUsage 197 @SystemApi(client = MODULE_LIBRARIES) traceCounter(long traceTag, @NonNull String counterName, int counterValue)198 public static void traceCounter(long traceTag, @NonNull String counterName, int counterValue) { 199 if (isTagEnabled(traceTag)) { 200 nativeTraceCounter(traceTag, counterName, counterValue); 201 } 202 } 203 204 /** 205 * From Android S, this is no-op. 206 * 207 * Before, set whether application tracing is allowed for this process. This is intended to be 208 * set once at application start-up time based on whether the application is debuggable. 209 * 210 * @hide 211 */ 212 @UnsupportedAppUsage setAppTracingAllowed(boolean allowed)213 public static void setAppTracingAllowed(boolean allowed) { 214 nativeSetAppTracingAllowed(allowed); 215 } 216 217 /** 218 * Set whether tracing is enabled in this process. 219 * @hide 220 */ setTracingEnabled(boolean enabled, int debugFlags)221 public static void setTracingEnabled(boolean enabled, int debugFlags) { 222 nativeSetTracingEnabled(enabled); 223 sZygoteDebugFlags = debugFlags; 224 } 225 226 /** 227 * Writes a trace message to indicate that a given section of code has 228 * begun. Must be followed by a call to {@link #traceEnd} using the same 229 * tag. 230 * 231 * @param traceTag The trace tag. 232 * @param methodName The method name to appear in the trace. 233 * 234 * @hide 235 */ 236 @UnsupportedAppUsage 237 @SystemApi(client = MODULE_LIBRARIES) traceBegin(long traceTag, @NonNull String methodName)238 public static void traceBegin(long traceTag, @NonNull String methodName) { 239 if (isTagEnabled(traceTag)) { 240 nativeTraceBegin(traceTag, methodName); 241 } 242 } 243 244 /** 245 * Writes a trace message to indicate that the current method has ended. 246 * Must be called exactly once for each call to {@link #traceBegin} using the same tag. 247 * 248 * @param traceTag The trace tag. 249 * 250 * @hide 251 */ 252 @UnsupportedAppUsage 253 @SystemApi(client = MODULE_LIBRARIES) traceEnd(long traceTag)254 public static void traceEnd(long traceTag) { 255 if (isTagEnabled(traceTag)) { 256 nativeTraceEnd(traceTag); 257 } 258 } 259 260 /** 261 * Writes a trace message to indicate that a given section of code has 262 * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same 263 * tag, name and cookie. 264 * 265 * If two events with the same methodName overlap in time then they *must* have 266 * different cookie values. If they do not, the trace can become corrupted 267 * in unpredictable ways. 268 * 269 * Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)}, 270 * asynchronous events cannot be not nested. Consider using 271 * {@link #asyncTraceForTrackBegin(long, String, String, int)} 272 * if nested asynchronous events are needed. 273 * 274 * @param traceTag The trace tag. 275 * @param methodName The method name to appear in the trace. 276 * @param cookie Unique identifier for distinguishing simultaneous events 277 * 278 * @hide 279 */ 280 @UnsupportedAppUsage 281 @SystemApi(client = MODULE_LIBRARIES) asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie)282 public static void asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie) { 283 if (isTagEnabled(traceTag)) { 284 nativeAsyncTraceBegin(traceTag, methodName, cookie); 285 } 286 } 287 288 /** 289 * Writes a trace message to indicate that the current method has ended. 290 * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)} 291 * using the same tag, name and cookie. 292 * 293 * See the documentation for {@link #asyncTraceBegin(long, String, int)}. 294 * for inteded usage of this method. 295 * 296 * @param traceTag The trace tag. 297 * @param methodName The method name to appear in the trace. 298 * @param cookie Unique identifier for distinguishing simultaneous events 299 * 300 * @hide 301 */ 302 @UnsupportedAppUsage 303 @SystemApi(client = MODULE_LIBRARIES) asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie)304 public static void asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie) { 305 if (isTagEnabled(traceTag)) { 306 nativeAsyncTraceEnd(traceTag, methodName, cookie); 307 } 308 } 309 310 311 /** 312 * Writes a trace message to indicate that a given section of code has 313 * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same 314 * track name and cookie. 315 * 316 * Events with the same trackName and cookie nest inside each other in the 317 * same way as calls to {@link #traceBegin(long, String)} and 318 * {@link #traceEnd(long)}. 319 * 320 * If two events with the same trackName overlap in time but do not nest 321 * correctly, then they *must* have different cookie values. If they do not, 322 * the trace can become corrupted in unpredictable ways. 323 * 324 * Good Example: 325 * 326 * public void parent() { 327 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "parent", mId); 328 * child() 329 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId); 330 * } 331 * 332 * public void child() { 333 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "child", mId); 334 * // Some code here. 335 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId); 336 * } 337 * 338 * This would be visualized as so: 339 * [ Parent ] 340 * [ Child ] 341 * 342 * Bad Example: 343 * 344 * public static void processData(String dataToProcess) { 345 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", 0); 346 * // Some code here. 347 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", 0); 348 * } 349 * 350 * public static void processDataInParallel({@code List<String>} data) { 351 * ExecutorService executor = Executors.newCachedThreadPool(); 352 * for (String s : data) { 353 * pool.execute(() -> processData(s)); 354 * } 355 * } 356 * 357 * This is invalid because it's possible for processData to be run many times 358 * in parallel (i.e. processData events overlap) but the same cookie is 359 * provided each time. 360 * 361 * To fix this, specify a different id in each invocation of processData: 362 * 363 * public static void processData(String dataToProcess, int id) { 364 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", id); 365 * // Some code here. 366 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", id); 367 * } 368 * 369 * public static void processDataInParallel({@code List<String>} data) { 370 * ExecutorService executor = Executors.newCachedThreadPool(); 371 * for (int i = 0; i < data.size(); ++i) { 372 * pool.execute(() -> processData(data.get(i), i)); 373 * } 374 * } 375 * 376 * @param traceTag The trace tag. 377 * @param trackName The track where the event should appear in the trace. 378 * @param methodName The method name to appear in the trace. 379 * @param cookie Unique identifier used for nesting events on a single 380 * track. Events which overlap without nesting on the same 381 * track must have different values for cookie. 382 * 383 * @hide 384 */ asyncTraceForTrackBegin(long traceTag, @NonNull String trackName, @NonNull String methodName, int cookie)385 public static void asyncTraceForTrackBegin(long traceTag, 386 @NonNull String trackName, @NonNull String methodName, int cookie) { 387 if (isTagEnabled(traceTag)) { 388 nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie); 389 } 390 } 391 392 /** 393 * Writes a trace message to indicate that the current method has ended. 394 * Must be called exactly once for each call to 395 * {@link #asyncTraceForTrackBegin(long, String, String, int)} 396 * using the same tag, track name, and cookie. 397 * 398 * See the documentation for {@link #asyncTraceForTrackBegin(long, String, String, int)}. 399 * for inteded usage of this method. 400 * 401 * @param traceTag The trace tag. 402 * @param trackName The track where the event should appear in the trace. 403 * @param cookie Unique identifier used for nesting events on a single 404 * track. Events which overlap without nesting on the same 405 * track must have different values for cookie. 406 * 407 * @hide 408 */ asyncTraceForTrackEnd(long traceTag, @NonNull String trackName, int cookie)409 public static void asyncTraceForTrackEnd(long traceTag, 410 @NonNull String trackName, int cookie) { 411 if (isTagEnabled(traceTag)) { 412 nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie); 413 } 414 } 415 416 /** 417 * Writes a trace message to indicate that a given section of code was invoked. 418 * 419 * @param traceTag The trace tag. 420 * @param methodName The method name to appear in the trace. 421 * @hide 422 */ instant(long traceTag, String methodName)423 public static void instant(long traceTag, String methodName) { 424 if (isTagEnabled(traceTag)) { 425 nativeInstant(traceTag, methodName); 426 } 427 } 428 429 /** 430 * Writes a trace message to indicate that a given section of code was invoked. 431 * 432 * @param traceTag The trace tag. 433 * @param trackName The track where the event should appear in the trace. 434 * @param methodName The method name to appear in the trace. 435 * @hide 436 */ instantForTrack(long traceTag, String trackName, String methodName)437 public static void instantForTrack(long traceTag, String trackName, String methodName) { 438 if (isTagEnabled(traceTag)) { 439 nativeInstantForTrack(traceTag, trackName, methodName); 440 } 441 } 442 443 /** 444 * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate 445 * string creation for trace sections that require formatting. It is not necessary 446 * to guard all Trace method calls as they internally already check this. However it is 447 * recommended to use this to prevent creating any temporary objects that would then be 448 * passed to those methods to reduce runtime cost when tracing isn't enabled. 449 * 450 * @return true if tracing is currently enabled, false otherwise 451 */ isEnabled()452 public static boolean isEnabled() { 453 return isTagEnabled(TRACE_TAG_APP); 454 } 455 456 /** 457 * Writes a trace message to indicate that a given section of code has begun. This call must 458 * be followed by a corresponding call to {@link #endSection()} on the same thread. 459 * 460 * <p class="note"> At this time the vertical bar character '|', newline character '\n', and 461 * null character '\0' are used internally by the tracing mechanism. If sectionName contains 462 * these characters they will be replaced with a space character in the trace. 463 * 464 * @param sectionName The name of the code section to appear in the trace. This may be at 465 * most 127 Unicode code units long. 466 * @throws IllegalArgumentException if {@code sectionName} is too long. 467 */ beginSection(@onNull String sectionName)468 public static void beginSection(@NonNull String sectionName) { 469 if (isTagEnabled(TRACE_TAG_APP)) { 470 if (sectionName.length() > MAX_SECTION_NAME_LEN) { 471 throw new IllegalArgumentException("sectionName is too long"); 472 } 473 nativeTraceBegin(TRACE_TAG_APP, sectionName); 474 } 475 } 476 477 /** 478 * Writes a trace message to indicate that a given section of code has ended. This call must 479 * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method 480 * will mark the end of the most recently begun section of code, so care must be taken to 481 * ensure that beginSection / endSection pairs are properly nested and called from the same 482 * thread. 483 */ endSection()484 public static void endSection() { 485 if (isTagEnabled(TRACE_TAG_APP)) { 486 nativeTraceEnd(TRACE_TAG_APP); 487 } 488 } 489 490 /** 491 * Writes a trace message to indicate that a given section of code has 492 * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same 493 * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()}, 494 * asynchronous events do not need to be nested. The name and cookie used to 495 * begin an event must be used to end it. 496 * 497 * @param methodName The method name to appear in the trace. 498 * @param cookie Unique identifier for distinguishing simultaneous events 499 */ beginAsyncSection(@onNull String methodName, int cookie)500 public static void beginAsyncSection(@NonNull String methodName, int cookie) { 501 asyncTraceBegin(TRACE_TAG_APP, methodName, cookie); 502 } 503 504 /** 505 * Writes a trace message to indicate that the current method has ended. 506 * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)} 507 * using the same name and cookie. 508 * 509 * @param methodName The method name to appear in the trace. 510 * @param cookie Unique identifier for distinguishing simultaneous events 511 */ endAsyncSection(@onNull String methodName, int cookie)512 public static void endAsyncSection(@NonNull String methodName, int cookie) { 513 asyncTraceEnd(TRACE_TAG_APP, methodName, cookie); 514 } 515 516 /** 517 * Writes trace message to indicate the value of a given counter. 518 * 519 * @param counterName The counter name to appear in the trace. 520 * @param counterValue The counter value. 521 */ setCounter(@onNull String counterName, long counterValue)522 public static void setCounter(@NonNull String counterName, long counterValue) { 523 if (isTagEnabled(TRACE_TAG_APP)) { 524 nativeTraceCounter(TRACE_TAG_APP, counterName, counterValue); 525 } 526 } 527 528 /** 529 * Initialize the perfetto SDK. This must be called before any tracing 530 * calls so that perfetto SDK can be used, otherwise libcutils would be 531 * used. 532 * 533 * @hide 534 */ registerWithPerfetto()535 public static void registerWithPerfetto() { 536 nativeRegisterWithPerfetto(); 537 } 538 } 539