1 /* 2 * Copyright (C) 2015 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.traceur; 18 19 import android.system.Os; 20 import android.util.Log; 21 22 import java.io.File; 23 import java.nio.file.Files; 24 import java.nio.file.Paths; 25 import java.util.Collection; 26 import java.util.List; 27 import java.util.TreeMap; 28 import java.util.concurrent.TimeUnit; 29 30 import perfetto.protos.DataSourceDescriptorOuterClass.DataSourceDescriptor; 31 import perfetto.protos.FtraceDescriptorOuterClass.FtraceDescriptor.AtraceCategory; 32 import perfetto.protos.TraceConfigOuterClass.TraceConfig; 33 import perfetto.protos.TracingServiceStateOuterClass.TracingServiceState; 34 import perfetto.protos.TracingServiceStateOuterClass.TracingServiceState.DataSource; 35 36 /** 37 * Utility functions for calling Perfetto 38 */ 39 public class PerfettoUtils { 40 41 static final String TAG = "Traceur"; 42 public static final String NAME = "PERFETTO"; 43 44 private static final String OUTPUT_EXTENSION = "perfetto-trace"; 45 private static final String TEMP_DIR = "/data/local/traces/"; 46 private static final String TEMP_TRACE_LOCATION = "/data/local/traces/.trace-in-progress.trace"; 47 48 private static final String PERFETTO_TAG = "traceur"; 49 private static final String MARKER = "PERFETTO_ARGUMENTS"; 50 private static final int LIST_TIMEOUT_MS = 10000; 51 private static final int STARTUP_TIMEOUT_MS = 10000; 52 private static final int STOP_TIMEOUT_MS = 30000; 53 private static final long MEGABYTES_TO_BYTES = 1024L * 1024L; 54 private static final long SECONDS_TO_MILLISECONDS = 1000L; 55 private static final long MINUTES_TO_MILLISECONDS = 60L * 1000L; 56 57 // This is 2x larger than the default buffer size to account for multiple processes being 58 // specified. 59 private static final int HEAP_DUMP_PER_CPU_BUFFER_SIZE_KB = 32 * 1024; 60 private static final int HEAP_DUMP_MAX_LONG_TRACE_SIZE_MB = 10 * 1024; 61 private static final int HEAP_DUMP_MAX_LONG_TRACE_DURATION_MINUTES = 10; 62 63 // The total amount of memory allocated to the two target buffers will be divided according to a 64 // ratio of (BUFFER_SIZE_RATIO - 1) to 1. 65 private static final int BUFFER_SIZE_RATIO = 32; 66 67 // atrace trace categories that will result in added data sources in the Perfetto config. 68 private static final String CAMERA_TAG = "camera"; 69 private static final String GFX_TAG = "gfx"; 70 private static final String MEMORY_TAG = "memory"; 71 private static final String NETWORK_TAG = "network"; 72 private static final String POWER_TAG = "power"; 73 private static final String SCHED_TAG = "sched"; 74 private static final String WEBVIEW_TAG = "webview"; 75 76 // Custom trace categories. 77 private static final String SYS_STATS_TAG = "sys_stats"; 78 private static final String LOG_TAG = "logs"; 79 private static final String CPU_TAG = "cpu"; 80 getName()81 public String getName() { 82 return NAME; 83 } 84 getOutputExtension()85 public String getOutputExtension() { 86 return OUTPUT_EXTENSION; 87 } 88 89 // Traceur will not verify that the input TraceConfig will start properly before attempting to 90 // record a trace. traceStart(TraceConfig config)91 public boolean traceStart(TraceConfig config) { 92 if (isTracingOn()) { 93 Log.e(TAG, "Attempting to start perfetto trace but trace is already in progress"); 94 return false; 95 } else { 96 recoverExistingRecording(); 97 } 98 99 return startPerfettoWithProtoConfig(config); 100 } 101 traceStart(Collection<String> tags, int bufferSizeKb, boolean winscope, boolean apps, boolean longTrace, boolean attachToBugreport, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)102 public boolean traceStart(Collection<String> tags, int bufferSizeKb, boolean winscope, 103 boolean apps, boolean longTrace, boolean attachToBugreport, int maxLongTraceSizeMb, 104 int maxLongTraceDurationMinutes) { 105 if (isTracingOn()) { 106 Log.e(TAG, "Attempting to start perfetto trace but trace is already in progress"); 107 return false; 108 } else { 109 recoverExistingRecording(); 110 } 111 112 StringBuilder config = new StringBuilder(); 113 appendBaseConfigOptions(config, attachToBugreport, longTrace, maxLongTraceSizeMb, 114 maxLongTraceDurationMinutes); 115 116 // The user chooses a per-CPU buffer size due to atrace limitations. 117 // So we use this to ensure that we reserve the correctly-sized buffer. 118 int numCpus = Runtime.getRuntime().availableProcessors(); 119 120 // Allots 1 / BUFFER_SIZE_RATIO to the small buffer and the remainder to the large buffer. 121 int totalBufferSizeKb = numCpus * bufferSizeKb; 122 int targetBuffer1Kb = totalBufferSizeKb / BUFFER_SIZE_RATIO; 123 int targetBuffer0Kb = totalBufferSizeKb - targetBuffer1Kb; 124 125 // This is target_buffer: 0, which is used for ftrace and the ftrace-derived 126 // android.gpu.memory. 127 appendTraceBuffer(config, targetBuffer0Kb); 128 129 // This is target_buffer: 1, which is used for additional data sources. 130 appendTraceBuffer(config, targetBuffer1Kb); 131 132 appendFtraceConfig(config, tags, apps); 133 appendProcStatsConfig(config, tags, /* targetBuffer = */ 1); 134 appendAdditionalDataSources(config, tags, winscope, longTrace, /* targetBuffer = */ 1); 135 136 return startPerfettoWithTextConfig(config.toString()); 137 } 138 stackSampleStart(boolean attachToBugreport)139 public boolean stackSampleStart(boolean attachToBugreport) { 140 if (isTracingOn()) { 141 Log.e(TAG, "Attemping to start stack sampling but perfetto is already active"); 142 return false; 143 } else { 144 recoverExistingRecording(); 145 } 146 147 StringBuilder config = new StringBuilder(); 148 appendBaseConfigOptions(config, attachToBugreport, /* longTrace = */ false, 149 /* maxLongTraceSizeMb */ 0, /* maxLongTraceDurationMinutes = */ 0); 150 151 // Number of cores * 16MiB. 16MiB was chosen as it is the default for Traceur traces. 152 int targetBufferKb = Runtime.getRuntime().availableProcessors() * (16 * 1024); 153 appendTraceBuffer(config, targetBufferKb); 154 155 appendLinuxPerfConfig(config, /* targetBuffer = */ 0); 156 appendProcStatsConfig(config, /* tags = */ null, /* targetBuffer = */ 0); 157 158 return startPerfettoWithTextConfig(config.toString()); 159 } 160 heapDumpStart(Collection<String> processes, boolean continuousDump, int dumpIntervalSeconds, boolean attachToBugreport)161 public boolean heapDumpStart(Collection<String> processes, boolean continuousDump, 162 int dumpIntervalSeconds, boolean attachToBugreport) { 163 if (isTracingOn()) { 164 Log.e(TAG, "Attempting to start heap dump but perfetto is already active"); 165 return false; 166 } else { 167 recoverExistingRecording(); 168 } 169 170 if (processes.isEmpty()) { 171 Log.e(TAG, "Attempting to start heap dump but list of processes is empty."); 172 return false; 173 } 174 175 StringBuilder config = new StringBuilder(); 176 177 // A long trace is used to avoid data loss. 178 appendBaseConfigOptions(config, attachToBugreport, /* longTrace = */ true, 179 HEAP_DUMP_MAX_LONG_TRACE_SIZE_MB, HEAP_DUMP_MAX_LONG_TRACE_DURATION_MINUTES); 180 181 int targetBufferKb = 182 Runtime.getRuntime().availableProcessors() * HEAP_DUMP_PER_CPU_BUFFER_SIZE_KB; 183 appendTraceBuffer(config, targetBufferKb); 184 185 appendAndroidJavaHprofConfig(config, processes, continuousDump, dumpIntervalSeconds, 186 /* targetBuffer = */ 0); 187 appendProcStatsConfig(config, /* tags = */ null, /* targetBuffer = */ 0); 188 189 return startPerfettoWithTextConfig(config.toString()); 190 } 191 traceStop()192 public void traceStop() { 193 Log.v(TAG, "Stopping perfetto trace."); 194 195 if (!isTracingOn()) { 196 Log.w(TAG, "No trace appears to be in progress. Stopping perfetto trace may not work."); 197 } 198 199 String cmd = "perfetto --stop --attach=" + PERFETTO_TAG; 200 try { 201 Process process = TraceUtils.execWithTimeout(cmd, null, STOP_TIMEOUT_MS); 202 if (process != null && process.exitValue() != 0) { 203 Log.e(TAG, "perfetto traceStop failed with: " + process.exitValue()); 204 } 205 } catch (Exception e) { 206 throw new RuntimeException(e); 207 } 208 } 209 traceDump(File outFile)210 public boolean traceDump(File outFile) { 211 traceStop(); 212 213 // Short-circuit if a trace was not stopped. 214 if (isTracingOn()) { 215 Log.e(TAG, "Trace was not stopped successfully, aborting trace dump."); 216 return false; 217 } 218 219 // Short-circuit if the file we're trying to dump to doesn't exist. 220 if (!Files.exists(Paths.get(TEMP_TRACE_LOCATION))) { 221 Log.e(TAG, "In-progress trace file doesn't exist, aborting trace dump."); 222 return false; 223 } 224 225 Log.v(TAG, "Saving perfetto trace to " + outFile); 226 227 try { 228 Os.rename(TEMP_TRACE_LOCATION, outFile.getCanonicalPath()); 229 } catch (Exception e) { 230 throw new RuntimeException(e); 231 } 232 233 outFile.setReadable(true, false); // (readable, ownerOnly) 234 outFile.setWritable(true, false); // (writable, ownerOnly) 235 return true; 236 } 237 isTracingOn()238 public boolean isTracingOn() { 239 String cmd = "perfetto --is_detached=" + PERFETTO_TAG; 240 241 try { 242 Process process = TraceUtils.exec(cmd); 243 244 // 0 represents a detached process exists with this name 245 // 2 represents no detached process with this name 246 // 1 (or other error code) represents an error 247 int result = process.waitFor(); 248 if (result == 0) { 249 return true; 250 } else if (result == 2) { 251 return false; 252 } else { 253 throw new RuntimeException("Perfetto error: " + result); 254 } 255 } catch (Exception e) { 256 throw new RuntimeException(e); 257 } 258 } 259 perfettoListCategories()260 public static TreeMap<String,String> perfettoListCategories() { 261 String cmd = "perfetto --query-raw"; 262 263 Log.v(TAG, "Listing tags: " + cmd); 264 try { 265 266 TreeMap<String, String> result = new TreeMap<>(); 267 268 // execWithTimeout() cannot be used because stdout must be consumed before the process 269 // is terminated. 270 Process perfetto = TraceUtils.exec(cmd, null, false); 271 TracingServiceState serviceState = 272 TracingServiceState.parseFrom(perfetto.getInputStream()); 273 274 // Destroy the perfetto process if it times out. 275 if (!perfetto.waitFor(LIST_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { 276 Log.e(TAG, "perfettoListCategories timed out after " + LIST_TIMEOUT_MS + " ms."); 277 perfetto.destroyForcibly(); 278 return result; 279 } 280 281 // The perfetto process completed and failed, but does not need to be destroyed. 282 if (perfetto.exitValue() != 0) { 283 Log.e(TAG, "perfettoListCategories failed with: " + perfetto.exitValue()); 284 } 285 286 List<AtraceCategory> categories = null; 287 288 for (DataSource dataSource : serviceState.getDataSourcesList()) { 289 DataSourceDescriptor dataSrcDescriptor = dataSource.getDsDescriptor(); 290 if (dataSrcDescriptor.getName().equals("linux.ftrace")){ 291 categories = dataSrcDescriptor.getFtraceDescriptor().getAtraceCategoriesList(); 292 break; 293 } 294 } 295 296 if (categories != null) { 297 for (AtraceCategory category : categories) { 298 result.put(category.getName(), category.getDescription()); 299 } 300 } 301 return result; 302 } catch (Exception e) { 303 throw new RuntimeException(e); 304 } 305 } 306 307 // Starts Perfetto with the provided config string. startPerfettoWithTextConfig(String config)308 private boolean startPerfettoWithTextConfig(String config) { 309 // If the here-doc ends early, within the config string, exit immediately. 310 // This should never happen. 311 if (config.contains(MARKER)) { 312 throw new RuntimeException("The arguments to the Perfetto command are malformed."); 313 } 314 315 String cmd = "perfetto --detach=" + PERFETTO_TAG 316 + " -o " + TEMP_TRACE_LOCATION 317 + " -c - --txt" 318 + " <<" + MARKER +"\n" + config + "\n" + MARKER; 319 320 Log.v(TAG, "Starting perfetto trace with text config."); 321 try { 322 Process process = TraceUtils.execWithTimeout(cmd, TEMP_DIR, STARTUP_TIMEOUT_MS); 323 if (process == null) { 324 return false; 325 } else if (process.exitValue() != 0) { 326 Log.e(TAG, "perfetto trace start failed with: " + process.exitValue()); 327 return false; 328 } 329 } catch (Exception e) { 330 throw new RuntimeException(e); 331 } 332 333 Log.v(TAG, "perfetto traceStart succeeded!"); 334 return true; 335 } 336 337 // Starts Perfetto with the provided TraceConfig proto. startPerfettoWithProtoConfig(TraceConfig config)338 private boolean startPerfettoWithProtoConfig(TraceConfig config) { 339 String cmd = "perfetto --detach=" + PERFETTO_TAG 340 + " -o " + TEMP_TRACE_LOCATION 341 + " -c - "; 342 Log.v(TAG, "Starting perfetto trace with proto config."); 343 try { 344 Process process = TraceUtils.execWithTimeout(cmd, TEMP_DIR, 345 STARTUP_TIMEOUT_MS, config.toByteArray()); 346 if (process == null) { 347 return false; 348 } else if (process.exitValue() != 0) { 349 Log.e(TAG, "perfetto trace start failed with: " + process.exitValue()); 350 return false; 351 } 352 } catch (Exception e) { 353 throw new RuntimeException(e); 354 } 355 356 Log.v(TAG, "perfetto traceStart succeeded!"); 357 return true; 358 } 359 360 // Saves an existing temporary recording under a "recovered" filename. recoverExistingRecording()361 private void recoverExistingRecording() { 362 File recoveredFile = TraceUtils.getOutputFile( 363 TraceUtils.getRecoveredFilename()); 364 if (!traceDump(recoveredFile)) { 365 Log.w(TAG, "Failed to recover in-progress trace."); 366 } 367 } 368 369 // Appends options that can be used in any of Traceur's Perfetto configs. appendBaseConfigOptions(StringBuilder config, boolean attachToBugreport, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)370 private void appendBaseConfigOptions(StringBuilder config, boolean attachToBugreport, 371 boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) { 372 config.append("write_into_file: true\n"); 373 374 // Ensure that we flush ftrace every 30s even if cpus are idle. 375 config.append("flush_period_ms: 30000\n"); 376 377 // If the user has flagged that in-progress trace sessions should be grabbed during 378 // bugreports, and BetterBug is present. 379 if (attachToBugreport) { 380 config.append("bugreport_score: 500\n"); 381 } 382 383 // Indicates that Perfetto should notify Traceur if the tracing session's status changes. 384 config.append("notify_traceur: true\n"); 385 386 // Allow previous trace contents to be referenced instead of duplicating. 387 config.append("incremental_state_config {\n") 388 .append(" clear_period_ms: 15000\n") 389 .append("}\n"); 390 391 // Add long/short trace-specific options. 392 if (longTrace) { 393 if (maxLongTraceSizeMb != 0) { 394 config.append("max_file_size_bytes: " 395 + (maxLongTraceSizeMb * MEGABYTES_TO_BYTES) + "\n"); 396 } 397 if (maxLongTraceDurationMinutes != 0) { 398 config.append("duration_ms: " 399 + (maxLongTraceDurationMinutes * MINUTES_TO_MILLISECONDS) 400 + "\n"); 401 } 402 403 // Default value for long traces to write to file. 404 config.append("file_write_period_ms: 1000\n"); 405 } else { 406 // For short traces, we don't write to the file. 407 // So, always use the maximum value here: 7 days. 408 config.append("file_write_period_ms: 604800000\n"); 409 } 410 } 411 412 // Specifies an additional buffer of size bufferSizeKb. Data sources can reference specific 413 // buffers in the order that they are added by this method. appendTraceBuffer(StringBuilder config, int bufferSizeKb)414 private void appendTraceBuffer(StringBuilder config, int bufferSizeKb) { 415 config.append("buffers {\n") 416 .append(" size_kb: " + bufferSizeKb + "\n") 417 .append(" fill_policy: RING_BUFFER\n") 418 .append("}\n"); 419 } 420 421 // Appends ftrace-related data sources to buffer 0 (linux.ftrace, android.gpu.memory). appendFtraceConfig(StringBuilder config, Collection<String> tags, boolean apps)422 private void appendFtraceConfig(StringBuilder config, Collection<String> tags, boolean apps) { 423 config.append("data_sources {\n") 424 .append(" config {\n") 425 .append(" name: \"linux.ftrace\"\n") 426 .append(" target_buffer: 0\n") 427 .append(" ftrace_config {\n") 428 .append(" symbolize_ksyms: true\n"); 429 430 for (String tag : tags) { 431 // Tags are expected to be only letters, numbers, and underscores. 432 String cleanTag = tag.replaceAll("[^a-zA-Z0-9_]", ""); 433 if (!cleanTag.equals(tag)) { 434 Log.w(TAG, "Attempting to use an invalid tag: " + tag); 435 } 436 config.append(" atrace_categories: \"" + cleanTag + "\"\n"); 437 } 438 439 if (apps) { 440 config.append(" atrace_apps: \"*\"\n"); 441 } 442 443 // Request a dense encoding of the common sched events (sched_switch, sched_waking). 444 if (tags.contains(SCHED_TAG)) { 445 config.append(" compact_sched {\n"); 446 config.append(" enabled: true\n"); 447 config.append(" }\n"); 448 } 449 450 // These parameters affect only the kernel trace buffer size and how 451 // frequently it gets moved into the userspace buffer defined above. 452 config.append(" buffer_size_kb: 8192\n") 453 .append(" }\n") 454 .append(" }\n") 455 .append("}\n") 456 .append("\n"); 457 458 // Captures initial counter values, updates are captured in ftrace. 459 if (tags.contains(MEMORY_TAG) || tags.contains(GFX_TAG)) { 460 config.append("data_sources: {\n") 461 .append(" config { \n") 462 .append(" name: \"android.gpu.memory\"\n") 463 .append(" target_buffer: 0\n") 464 .append(" }\n") 465 .append("}\n"); 466 } 467 } 468 469 // Appends the linux.process_stats data source to the specified target buffer. appendProcStatsConfig(StringBuilder config, Collection<String> tags, int targetBuffer)470 private void appendProcStatsConfig(StringBuilder config, Collection<String> tags, 471 int targetBuffer) { 472 boolean tagsContainsMemory = (tags != null) ? tags.contains(MEMORY_TAG) : false; 473 // For process association. If the memory tag is enabled, poll periodically instead of just 474 // once at the beginning. 475 config.append("data_sources {\n") 476 .append(" config {\n") 477 .append(" name: \"linux.process_stats\"\n") 478 .append(" target_buffer: " + targetBuffer + "\n") 479 .append(" process_stats_config {\n"); 480 if (tagsContainsMemory) { 481 config.append(" proc_stats_poll_ms: 60000\n"); 482 } else { 483 config.append(" scan_all_processes_on_start: true\n"); 484 } 485 config.append(" }\n") 486 .append(" }\n") 487 .append("}\n"); 488 } 489 490 // Appends the callstack-sampling data source. Sampling frequency is measured in Hz. appendLinuxPerfConfig(StringBuilder config, int targetBuffer)491 private void appendLinuxPerfConfig(StringBuilder config, int targetBuffer) { 492 config.append("data_sources: {\n") 493 .append(" config {\n") 494 .append(" name: \"linux.perf\"\n") 495 .append(" target_buffer: " + targetBuffer + "\n") 496 .append(" perf_event_config {\n") 497 .append(" all_cpus: true\n") 498 .append(" sampling_frequency: 100\n") 499 .append(" }\n") 500 .append(" }\n") 501 .append("}\n"); 502 } 503 504 // Appends the heap dump data source. appendAndroidJavaHprofConfig(StringBuilder config, Collection<String> processes, boolean continuousDump, int dumpIntervalSeconds, int targetBuffer)505 private void appendAndroidJavaHprofConfig(StringBuilder config, Collection<String> processes, 506 boolean continuousDump, int dumpIntervalSeconds, int targetBuffer) { 507 config.append("data_sources: {\n") 508 .append(" config: {\n") 509 .append(" name: \"android.java_hprof\"\n") 510 .append(" target_buffer: " + targetBuffer + "\n") 511 .append(" java_hprof_config: {\n"); 512 for (String process : processes) { 513 config.append(" process_cmdline: \"" + process + "\"\n"); 514 } 515 config.append(" dump_smaps: true\n"); 516 if (continuousDump) { 517 config.append(" continuous_dump_config: {\n") 518 .append(" dump_phase_ms: 0\n") 519 .append(" dump_interval_ms: " 520 + (dumpIntervalSeconds * SECONDS_TO_MILLISECONDS) + "\n") 521 .append(" }\n"); 522 } 523 config.append(" }\n") 524 .append(" }\n") 525 .append("}\n"); 526 } 527 528 // Appends additional data sources to the specified extra buffer based on enabled trace tags. appendAdditionalDataSources(StringBuilder config, Collection<String> tags, boolean winscope, boolean longTrace, int targetBuffer)529 private void appendAdditionalDataSources(StringBuilder config, Collection<String> tags, 530 boolean winscope, boolean longTrace, int targetBuffer) { 531 if (tags.contains(POWER_TAG)) { 532 config.append("data_sources: {\n") 533 .append(" config { \n") 534 .append(" name: \"android.power\"\n") 535 .append(" target_buffer: " + targetBuffer + "\n") 536 .append(" android_power_config {\n"); 537 if (longTrace) { 538 config.append(" battery_poll_ms: 5000\n"); 539 } else { 540 config.append(" battery_poll_ms: 1000\n"); 541 } 542 config.append(" collect_power_rails: true\n") 543 .append(" battery_counters: BATTERY_COUNTER_CAPACITY_PERCENT\n") 544 .append(" battery_counters: BATTERY_COUNTER_CHARGE\n") 545 .append(" battery_counters: BATTERY_COUNTER_CURRENT\n") 546 .append(" }\n") 547 .append(" }\n") 548 .append("}\n"); 549 } 550 551 if (tags.contains(SYS_STATS_TAG)) { 552 config.append("data_sources: {\n") 553 .append(" config { \n") 554 .append(" name: \"linux.sys_stats\"\n") 555 .append(" target_buffer: " + targetBuffer + "\n") 556 .append(" sys_stats_config {\n") 557 .append(" meminfo_period_ms: 1000\n") 558 .append(" psi_period_ms: 1000\n") 559 .append(" vmstat_period_ms: 1000\n") 560 .append(" }\n") 561 .append(" }\n") 562 .append("}\n"); 563 } 564 565 if (tags.contains(LOG_TAG)) { 566 config.append("data_sources: {\n") 567 .append(" config {\n") 568 .append(" name: \"android.log\"\n") 569 .append(" target_buffer: " + targetBuffer + "\n") 570 .append(" }\n") 571 .append("}\n"); 572 } 573 574 if (tags.contains(CPU_TAG)) { 575 appendLinuxPerfConfig(config, /* targetBuffer = */ 1); 576 } 577 578 if (tags.contains(GFX_TAG)) { 579 config.append("data_sources: {\n") 580 .append(" config { \n") 581 .append(" name: \"android.surfaceflinger.frametimeline\"\n") 582 .append(" target_buffer: " + targetBuffer + "\n") 583 .append(" }\n") 584 .append("}\n"); 585 } 586 587 if (tags.contains(CAMERA_TAG)) { 588 config.append("data_sources: {\n") 589 .append(" config { \n") 590 .append(" name: \"android.hardware.camera\"\n") 591 .append(" target_buffer: " + targetBuffer + "\n") 592 .append(" }\n") 593 .append("}\n"); 594 } 595 596 if (tags.contains(NETWORK_TAG)) { 597 config.append("data_sources: {\n") 598 .append(" config { \n") 599 .append(" name: \"android.network_packets\"\n") 600 .append(" target_buffer: " + targetBuffer + "\n") 601 .append(" network_packet_trace_config {\n") 602 .append(" poll_ms: 250\n") 603 .append(" }\n") 604 .append(" }\n") 605 .append("}\n"); 606 // Include the packages_list data source so that we can map UIDs 607 // from Network Tracing to the corresponding package name. 608 config.append("data_sources: {\n") 609 .append(" config { \n") 610 .append(" name: \"android.packages_list\"\n") 611 .append(" target_buffer: " + targetBuffer + "\n") 612 .append(" }\n") 613 .append("}\n"); 614 } 615 616 // Also enable Chrome events when the WebView tag is enabled. 617 if (tags.contains(WEBVIEW_TAG)) { 618 String chromeTraceConfig = "{" + 619 "\\\"record_mode\\\":\\\"record-continuously\\\"," + 620 "\\\"included_categories\\\":[\\\"*\\\"]" + 621 "}"; 622 config.append("data_sources: {\n") 623 .append(" config {\n") 624 .append(" name: \"track_event\"\n") 625 .append(" target_buffer: " + targetBuffer + "\n") 626 .append(" chrome_config {\n") 627 .append(" trace_config: \"" + chromeTraceConfig + "\"\n") 628 .append(" }\n") 629 .append(" track_event_config {\n") 630 .append(" enabled_categories: \"*\"\n") 631 .append(" enabled_categories: \"__metadata\"\n") 632 .append(" timestamp_unit_multiplier: 1000\n") 633 .append(" filter_debug_annotations: false\n") 634 .append(" enable_thread_time_sampling: true\n") 635 .append(" filter_dynamic_event_names: false\n") 636 .append(" }\n") 637 .append(" }\n") 638 .append("}\n") 639 .append("data_sources: {\n") 640 .append(" config {\n") 641 .append(" name: \"org.chromium.trace_metadata\"\n") 642 .append(" target_buffer: " + targetBuffer + "\n") 643 .append(" chrome_config {\n") 644 .append(" trace_config: \"" + chromeTraceConfig + "\"\n") 645 .append(" }\n") 646 .append(" }\n") 647 .append("}\n"); 648 } 649 650 if (winscope) { 651 config.append("data_sources: {\n") 652 .append(" config {\n") 653 .append(" name: \"android.inputmethod\"\n") 654 .append(" target_buffer: " + targetBuffer + "\n") 655 .append(" }\n") 656 .append("}\n"); 657 658 config.append("data_sources: {\n") 659 .append(" config {\n") 660 .append(" name: \"android.surfaceflinger.layers\"\n") 661 .append(" target_buffer: " + targetBuffer + "\n") 662 .append(" surfaceflinger_layers_config: {\n") 663 .append(" mode: MODE_ACTIVE\n") 664 .append(" trace_flags: TRACE_FLAG_INPUT\n") 665 .append(" trace_flags: TRACE_FLAG_COMPOSITION\n") 666 .append(" trace_flags: TRACE_FLAG_HWC\n") 667 .append(" trace_flags: TRACE_FLAG_BUFFERS\n") 668 .append(" trace_flags: TRACE_FLAG_VIRTUAL_DISPLAYS\n") 669 .append(" }\n") 670 .append(" }\n") 671 .append("}\n"); 672 673 config.append("data_sources: {\n") 674 .append(" config {\n") 675 .append(" name: \"android.surfaceflinger.transactions\"\n") 676 .append(" target_buffer: " + targetBuffer + "\n") 677 .append(" surfaceflinger_transactions_config: {\n") 678 .append(" mode: MODE_ACTIVE\n") 679 .append(" }\n") 680 .append(" }\n") 681 .append("}\n"); 682 683 config.append("data_sources: {\n") 684 .append(" config {\n") 685 .append(" name: \"com.android.wm.shell.transition\"\n") 686 .append(" target_buffer: " + targetBuffer + "\n") 687 .append(" }\n") 688 .append("}\n"); 689 690 config.append("data_sources: {\n") 691 .append(" config {\n") 692 .append(" name: \"android.protolog\"\n") 693 .append(" target_buffer: " + targetBuffer + "\n") 694 .append(" protolog_config: {\n") 695 .append(" tracing_mode: ENABLE_ALL\n") 696 .append(" }\n") 697 .append(" }\n") 698 .append("}\n"); 699 700 config.append("data_sources: {\n") 701 .append(" config {\n") 702 .append(" name: \"android.viewcapture\"\n") 703 .append(" target_buffer: " + targetBuffer + "\n") 704 .append(" }\n") 705 .append("}\n"); 706 } 707 } 708 } 709