Merge "Add TraceConfig trace starts" into main
diff --git a/src_common/com/android/traceur/PerfettoUtils.java b/src_common/com/android/traceur/PerfettoUtils.java
index 98a489d..5d3949e 100644
--- a/src_common/com/android/traceur/PerfettoUtils.java
+++ b/src_common/com/android/traceur/PerfettoUtils.java
@@ -29,6 +29,7 @@
import perfetto.protos.DataSourceDescriptorOuterClass.DataSourceDescriptor;
import perfetto.protos.FtraceDescriptorOuterClass.FtraceDescriptor.AtraceCategory;
+import perfetto.protos.TraceConfigOuterClass.TraceConfig;
import perfetto.protos.TracingServiceStateOuterClass.TracingServiceState;
import perfetto.protos.TracingServiceStateOuterClass.TracingServiceState.DataSource;
@@ -85,6 +86,19 @@
return OUTPUT_EXTENSION;
}
+ // Traceur will not verify that the input TraceConfig will start properly before attempting to
+ // record a trace.
+ public boolean traceStart(TraceConfig config) {
+ if (isTracingOn()) {
+ Log.e(TAG, "Attempting to start perfetto trace but trace is already in progress");
+ return false;
+ } else {
+ recoverExistingRecording();
+ }
+
+ return startPerfettoWithProtoConfig(config);
+ }
+
public boolean traceStart(Collection<String> tags, int bufferSizeKb, boolean winscope,
boolean apps, boolean longTrace, boolean attachToBugreport, int maxLongTraceSizeMb,
int maxLongTraceDurationMinutes) {
@@ -119,7 +133,7 @@
appendProcStatsConfig(config, tags, /* targetBuffer = */ 1);
appendAdditionalDataSources(config, tags, winscope, longTrace, /* targetBuffer = */ 1);
- return startPerfettoWithConfig(config.toString());
+ return startPerfettoWithTextConfig(config.toString());
}
public boolean stackSampleStart(boolean attachToBugreport) {
@@ -141,7 +155,7 @@
appendLinuxPerfConfig(config, /* targetBuffer = */ 0);
appendProcStatsConfig(config, /* tags = */ null, /* targetBuffer = */ 0);
- return startPerfettoWithConfig(config.toString());
+ return startPerfettoWithTextConfig(config.toString());
}
public boolean heapDumpStart(Collection<String> processes, boolean continuousDump,
@@ -172,7 +186,7 @@
/* targetBuffer = */ 0);
appendProcStatsConfig(config, /* tags = */ null, /* targetBuffer = */ 0);
- return startPerfettoWithConfig(config.toString());
+ return startPerfettoWithTextConfig(config.toString());
}
public void traceStop() {
@@ -291,7 +305,7 @@
}
// Starts Perfetto with the provided config string.
- private boolean startPerfettoWithConfig(String config) {
+ private boolean startPerfettoWithTextConfig(String config) {
// If the here-doc ends early, within the config string, exit immediately.
// This should never happen.
if (config.contains(MARKER)) {
@@ -303,7 +317,7 @@
+ " -c - --txt"
+ " <<" + MARKER +"\n" + config + "\n" + MARKER;
- Log.v(TAG, "Starting perfetto trace.");
+ Log.v(TAG, "Starting perfetto trace with text config.");
try {
Process process = TraceUtils.execWithTimeout(cmd, TEMP_DIR, STARTUP_TIMEOUT_MS);
if (process == null) {
@@ -320,6 +334,29 @@
return true;
}
+ // Starts Perfetto with the provided TraceConfig proto.
+ private boolean startPerfettoWithProtoConfig(TraceConfig config) {
+ String cmd = "perfetto --detach=" + PERFETTO_TAG
+ + " -o " + TEMP_TRACE_LOCATION
+ + " -c - ";
+ Log.v(TAG, "Starting perfetto trace with proto config.");
+ try {
+ Process process = TraceUtils.execWithTimeout(cmd, TEMP_DIR,
+ STARTUP_TIMEOUT_MS, config.toByteArray());
+ if (process == null) {
+ return false;
+ } else if (process.exitValue() != 0) {
+ Log.e(TAG, "perfetto trace start failed with: " + process.exitValue());
+ return false;
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ Log.v(TAG, "perfetto traceStart succeeded!");
+ return true;
+ }
+
// Saves an existing temporary recording under a "recovered" filename.
private void recoverExistingRecording() {
File recoveredFile = TraceUtils.getOutputFile(
diff --git a/src_common/com/android/traceur/TraceUtils.java b/src_common/com/android/traceur/TraceUtils.java
index 5a5c153..9942efb 100644
--- a/src_common/com/android/traceur/TraceUtils.java
+++ b/src_common/com/android/traceur/TraceUtils.java
@@ -46,6 +46,8 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import perfetto.protos.TraceConfigOuterClass.TraceConfig;
+
/**
* Utility functions for tracing.
*/
@@ -63,6 +65,18 @@
UNKNOWN, TRACE, STACK_SAMPLES, HEAP_DUMP
}
+ public static boolean traceStart(ContentResolver contentResolver, TraceConfig config,
+ boolean winscope) {
+ // 'winscope' isn't passed to traceStart because the TraceConfig should specify any
+ // winscope-related data sources to be recorded using Perfetto. Winscope data that isn't yet
+ // available in Perfetto is captured using WinscopeUtils instead.
+ if (!mTraceEngine.traceStart(config)) {
+ return false;
+ }
+ WinscopeUtils.traceStart(contentResolver, winscope);
+ return true;
+ }
+
public static boolean traceStart(ContentResolver contentResolver, Collection<String> tags,
int bufferSizeKb, boolean winscope, boolean apps, boolean longTrace,
boolean attachToBugreport, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) {
@@ -159,11 +173,22 @@
return process;
}
- // Returns the Process if the command terminated on time and null if not.
public static Process execWithTimeout(String cmd, String tmpdir, long timeout)
throws IOException {
+ return execWithTimeout(cmd, tmpdir, timeout, null);
+ }
+
+ // Returns the Process if the command terminated on time and null if not.
+ public static Process execWithTimeout(String cmd, String tmpdir, long timeout, byte[] input)
+ throws IOException {
Process process = exec(cmd, tmpdir, true);
try {
+ if (input != null) {
+ OutputStream os = process.getOutputStream();
+ os.write(input);
+ os.flush();
+ os.close();
+ }
if (!process.waitFor(timeout, TimeUnit.MILLISECONDS)) {
Log.e(TAG, "Command '" + cmd + "' has timed out after " + timeout + " ms.");
process.destroyForcibly();