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 Trace()168 private Trace() { 169 } 170 171 /** 172 * Returns true if a trace tag is enabled. 173 * 174 * @param traceTag The trace tag to check. 175 * @return True if the trace tag is valid. 176 * 177 * @hide 178 */ 179 @UnsupportedAppUsage 180 @SystemApi(client = MODULE_LIBRARIES) isTagEnabled(long traceTag)181 public static boolean isTagEnabled(long traceTag) { 182 return nativeIsTagEnabled(traceTag); 183 } 184 185 /** 186 * Writes trace message to indicate the value of a given counter. 187 * 188 * @param traceTag The trace tag. 189 * @param counterName The counter name to appear in the trace. 190 * @param counterValue The counter value. 191 * 192 * @hide 193 */ 194 @UnsupportedAppUsage 195 @SystemApi(client = MODULE_LIBRARIES) traceCounter(long traceTag, @NonNull String counterName, int counterValue)196 public static void traceCounter(long traceTag, @NonNull String counterName, int counterValue) { 197 if (isTagEnabled(traceTag)) { 198 nativeTraceCounter(traceTag, counterName, counterValue); 199 } 200 } 201 202 /** 203 * From Android S, this is no-op. 204 * 205 * Before, set whether application tracing is allowed for this process. This is intended to be 206 * set once at application start-up time based on whether the application is debuggable. 207 * 208 * @hide 209 */ 210 @UnsupportedAppUsage setAppTracingAllowed(boolean allowed)211 public static void setAppTracingAllowed(boolean allowed) { 212 nativeSetAppTracingAllowed(allowed); 213 } 214 215 /** 216 * Set whether tracing is enabled in this process. 217 * @hide 218 */ setTracingEnabled(boolean enabled, int debugFlags)219 public static void setTracingEnabled(boolean enabled, int debugFlags) { 220 nativeSetTracingEnabled(enabled); 221 sZygoteDebugFlags = debugFlags; 222 } 223 224 /** 225 * Writes a trace message to indicate that a given section of code has 226 * begun. Must be followed by a call to {@link #traceEnd} using the same 227 * tag. 228 * 229 * @param traceTag The trace tag. 230 * @param methodName The method name to appear in the trace. 231 * 232 * @hide 233 */ 234 @UnsupportedAppUsage 235 @SystemApi(client = MODULE_LIBRARIES) traceBegin(long traceTag, @NonNull String methodName)236 public static void traceBegin(long traceTag, @NonNull String methodName) { 237 if (isTagEnabled(traceTag)) { 238 nativeTraceBegin(traceTag, methodName); 239 } 240 } 241 242 /** 243 * Writes a trace message to indicate that the current method has ended. 244 * Must be called exactly once for each call to {@link #traceBegin} using the same tag. 245 * 246 * @param traceTag The trace tag. 247 * 248 * @hide 249 */ 250 @UnsupportedAppUsage 251 @SystemApi(client = MODULE_LIBRARIES) traceEnd(long traceTag)252 public static void traceEnd(long traceTag) { 253 if (isTagEnabled(traceTag)) { 254 nativeTraceEnd(traceTag); 255 } 256 } 257 258 /** 259 * Writes a trace message to indicate that a given section of code has 260 * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same 261 * tag, name and cookie. 262 * 263 * If two events with the same methodName overlap in time then they *must* have 264 * different cookie values. If they do not, the trace can become corrupted 265 * in unpredictable ways. 266 * 267 * Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)}, 268 * asynchronous events cannot be not nested. Consider using 269 * {@link #asyncTraceForTrackBegin(long, String, String, int)} 270 * if nested asynchronous events are needed. 271 * 272 * @param traceTag The trace tag. 273 * @param methodName The method name to appear in the trace. 274 * @param cookie Unique identifier for distinguishing simultaneous events 275 * 276 * @hide 277 */ 278 @UnsupportedAppUsage 279 @SystemApi(client = MODULE_LIBRARIES) asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie)280 public static void asyncTraceBegin(long traceTag, @NonNull String methodName, int cookie) { 281 if (isTagEnabled(traceTag)) { 282 nativeAsyncTraceBegin(traceTag, methodName, cookie); 283 } 284 } 285 286 /** 287 * Writes a trace message to indicate that the current method has ended. 288 * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)} 289 * using the same tag, name and cookie. 290 * 291 * See the documentation for {@link #asyncTraceBegin(long, String, int)}. 292 * for inteded usage of this method. 293 * 294 * @param traceTag The trace tag. 295 * @param methodName The method name to appear in the trace. 296 * @param cookie Unique identifier for distinguishing simultaneous events 297 * 298 * @hide 299 */ 300 @UnsupportedAppUsage 301 @SystemApi(client = MODULE_LIBRARIES) asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie)302 public static void asyncTraceEnd(long traceTag, @NonNull String methodName, int cookie) { 303 if (isTagEnabled(traceTag)) { 304 nativeAsyncTraceEnd(traceTag, methodName, cookie); 305 } 306 } 307 308 309 /** 310 * Writes a trace message to indicate that a given section of code has 311 * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same 312 * track name and cookie. 313 * 314 * Events with the same trackName and cookie nest inside each other in the 315 * same way as calls to {@link #traceBegin(long, String)} and 316 * {@link #traceEnd(long)}. 317 * 318 * If two events with the same trackName overlap in time but do not nest 319 * correctly, then they *must* have different cookie values. If they do not, 320 * the trace can become corrupted in unpredictable ways. 321 * 322 * Good Example: 323 * 324 * public void parent() { 325 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "parent", mId); 326 * child() 327 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId); 328 * } 329 * 330 * public void child() { 331 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "child", mId); 332 * // Some code here. 333 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId); 334 * } 335 * 336 * This would be visualized as so: 337 * [ Parent ] 338 * [ Child ] 339 * 340 * Bad Example: 341 * 342 * public static void processData(String dataToProcess) { 343 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", 0); 344 * // Some code here. 345 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", 0); 346 * } 347 * 348 * public static void processDataInParallel({@code List<String>} data) { 349 * ExecutorService executor = Executors.newCachedThreadPool(); 350 * for (String s : data) { 351 * pool.execute(() -> processData(s)); 352 * } 353 * } 354 * 355 * This is invalid because it's possible for processData to be run many times 356 * in parallel (i.e. processData events overlap) but the same cookie is 357 * provided each time. 358 * 359 * To fix this, specify a different id in each invocation of processData: 360 * 361 * public static void processData(String dataToProcess, int id) { 362 * asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", id); 363 * // Some code here. 364 * asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", id); 365 * } 366 * 367 * public static void processDataInParallel({@code List<String>} data) { 368 * ExecutorService executor = Executors.newCachedThreadPool(); 369 * for (int i = 0; i < data.size(); ++i) { 370 * pool.execute(() -> processData(data.get(i), i)); 371 * } 372 * } 373 * 374 * @param traceTag The trace tag. 375 * @param trackName The track where the event should appear in the trace. 376 * @param methodName The method name to appear in the trace. 377 * @param cookie Unique identifier used for nesting events on a single 378 * track. Events which overlap without nesting on the same 379 * track must have different values for cookie. 380 * 381 * @hide 382 */ asyncTraceForTrackBegin(long traceTag, @NonNull String trackName, @NonNull String methodName, int cookie)383 public static void asyncTraceForTrackBegin(long traceTag, 384 @NonNull String trackName, @NonNull String methodName, int cookie) { 385 if (isTagEnabled(traceTag)) { 386 nativeAsyncTraceForTrackBegin(traceTag, trackName, methodName, cookie); 387 } 388 } 389 390 /** 391 * Writes a trace message to indicate that the current method has ended. 392 * Must be called exactly once for each call to 393 * {@link #asyncTraceForTrackBegin(long, String, String, int)} 394 * using the same tag, track name, and cookie. 395 * 396 * See the documentation for {@link #asyncTraceForTrackBegin(long, String, String, int)}. 397 * for inteded usage of this method. 398 * 399 * @param traceTag The trace tag. 400 * @param trackName The track where the event should appear in the trace. 401 * @param cookie Unique identifier used for nesting events on a single 402 * track. Events which overlap without nesting on the same 403 * track must have different values for cookie. 404 * 405 * @hide 406 */ asyncTraceForTrackEnd(long traceTag, @NonNull String trackName, int cookie)407 public static void asyncTraceForTrackEnd(long traceTag, 408 @NonNull String trackName, int cookie) { 409 if (isTagEnabled(traceTag)) { 410 nativeAsyncTraceForTrackEnd(traceTag, trackName, cookie); 411 } 412 } 413 414 /** 415 * Writes a trace message to indicate that a given section of code was invoked. 416 * 417 * @param traceTag The trace tag. 418 * @param methodName The method name to appear in the trace. 419 * @hide 420 */ instant(long traceTag, String methodName)421 public static void instant(long traceTag, String methodName) { 422 if (isTagEnabled(traceTag)) { 423 nativeInstant(traceTag, methodName); 424 } 425 } 426 427 /** 428 * Writes a trace message to indicate that a given section of code was invoked. 429 * 430 * @param traceTag The trace tag. 431 * @param trackName The track where the event should appear in the trace. 432 * @param methodName The method name to appear in the trace. 433 * @hide 434 */ instantForTrack(long traceTag, String trackName, String methodName)435 public static void instantForTrack(long traceTag, String trackName, String methodName) { 436 if (isTagEnabled(traceTag)) { 437 nativeInstantForTrack(traceTag, trackName, methodName); 438 } 439 } 440 441 /** 442 * Checks whether or not tracing is currently enabled. This is useful to avoid intermediate 443 * string creation for trace sections that require formatting. It is not necessary 444 * to guard all Trace method calls as they internally already check this. However it is 445 * recommended to use this to prevent creating any temporary objects that would then be 446 * passed to those methods to reduce runtime cost when tracing isn't enabled. 447 * 448 * @return true if tracing is currently enabled, false otherwise 449 */ isEnabled()450 public static boolean isEnabled() { 451 return isTagEnabled(TRACE_TAG_APP); 452 } 453 454 /** 455 * Writes a trace message to indicate that a given section of code has begun. This call must 456 * be followed by a corresponding call to {@link #endSection()} on the same thread. 457 * 458 * <p class="note"> At this time the vertical bar character '|', newline character '\n', and 459 * null character '\0' are used internally by the tracing mechanism. If sectionName contains 460 * these characters they will be replaced with a space character in the trace. 461 * 462 * @param sectionName The name of the code section to appear in the trace. This may be at 463 * most 127 Unicode code units long. 464 * @throws IllegalArgumentException if {@code sectionName} is too long. 465 */ beginSection(@onNull String sectionName)466 public static void beginSection(@NonNull String sectionName) { 467 if (isTagEnabled(TRACE_TAG_APP)) { 468 if (sectionName.length() > MAX_SECTION_NAME_LEN) { 469 throw new IllegalArgumentException("sectionName is too long"); 470 } 471 nativeTraceBegin(TRACE_TAG_APP, sectionName); 472 } 473 } 474 475 /** 476 * Writes a trace message to indicate that a given section of code has ended. This call must 477 * be preceeded by a corresponding call to {@link #beginSection(String)}. Calling this method 478 * will mark the end of the most recently begun section of code, so care must be taken to 479 * ensure that beginSection / endSection pairs are properly nested and called from the same 480 * thread. 481 */ endSection()482 public static void endSection() { 483 if (isTagEnabled(TRACE_TAG_APP)) { 484 nativeTraceEnd(TRACE_TAG_APP); 485 } 486 } 487 488 /** 489 * Writes a trace message to indicate that a given section of code has 490 * begun. Must be followed by a call to {@link #endAsyncSection(String, int)} with the same 491 * methodName and cookie. Unlike {@link #beginSection(String)} and {@link #endSection()}, 492 * asynchronous events do not need to be nested. The name and cookie used to 493 * begin an event must be used to end it. 494 * 495 * @param methodName The method name to appear in the trace. 496 * @param cookie Unique identifier for distinguishing simultaneous events 497 */ beginAsyncSection(@onNull String methodName, int cookie)498 public static void beginAsyncSection(@NonNull String methodName, int cookie) { 499 asyncTraceBegin(TRACE_TAG_APP, methodName, cookie); 500 } 501 502 /** 503 * Writes a trace message to indicate that the current method has ended. 504 * Must be called exactly once for each call to {@link #beginAsyncSection(String, int)} 505 * using the same name and cookie. 506 * 507 * @param methodName The method name to appear in the trace. 508 * @param cookie Unique identifier for distinguishing simultaneous events 509 */ endAsyncSection(@onNull String methodName, int cookie)510 public static void endAsyncSection(@NonNull String methodName, int cookie) { 511 asyncTraceEnd(TRACE_TAG_APP, methodName, cookie); 512 } 513 514 /** 515 * Writes trace message to indicate the value of a given counter. 516 * 517 * @param counterName The counter name to appear in the trace. 518 * @param counterValue The counter value. 519 */ setCounter(@onNull String counterName, long counterValue)520 public static void setCounter(@NonNull String counterName, long counterValue) { 521 setCounter(TRACE_TAG_APP, counterName, counterValue); 522 } 523 524 /** 525 * Writes trace message to indicate the value of a given counter under a given trace tag. 526 * 527 * @param traceTag The trace tag. 528 * @param counterName The counter name to appear in the trace. 529 * @param counterValue The counter value. 530 * @hide 531 */ setCounter(long traceTag, @NonNull String counterName, long counterValue)532 public static void setCounter(long traceTag, @NonNull String counterName, long counterValue) { 533 if (isTagEnabled(traceTag)) { 534 nativeTraceCounter(traceTag, counterName, counterValue); 535 } 536 } 537 538 /** 539 * Initialize the perfetto SDK. This must be called before any tracing 540 * calls so that perfetto SDK can be used, otherwise libcutils would be 541 * used. 542 * 543 * @hide 544 */ registerWithPerfetto()545 public static void registerWithPerfetto() { 546 PerfettoTrace.register(false /* isBackendInProcess */); 547 PerfettoTrace.registerCategories(); 548 } 549 } 550