/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package com.android.traceur; import android.sysprop.TraceProperties; import android.text.TextUtils; import android.util.Log; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; import java.util.List; import java.util.TreeMap; import com.android.traceur.TraceUtils.Streamer; /** * Utility functions for calling atrace */ public class AtraceUtils implements TraceUtils.TraceEngine { static final String TAG = "Traceur"; private static final String DEBUG_TRACING_FILE = "/sys/kernel/debug/tracing/tracing_on"; private static final String TRACING_FILE = "/sys/kernel/tracing/tracing_on"; public static String NAME = "ATRACE"; private static String OUTPUT_EXTENSION = "ctrace"; public String getName() { return NAME; } public String getOutputExtension() { return OUTPUT_EXTENSION; } /* Note: attachToBugreport, longTrace, maxLongTrace* parameters are ignored in atrace mode. */ public boolean traceStart(Collection tags, int bufferSizeKb, boolean apps, boolean attachToBugreport, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) { String appParameter = apps ? "-a '*' " : ""; String cmd = "atrace --async_start -c -b " + bufferSizeKb + " " + appParameter + TextUtils.join(" ", tags); Log.v(TAG, "Starting async atrace: " + cmd); try { Process atrace = TraceUtils.exec(cmd); if (atrace.waitFor() != 0) { Log.e(TAG, "atraceStart failed with: " + atrace.exitValue()); return false; } } catch (Exception e) { throw new RuntimeException(e); } return true; } public void traceStop() { String cmd = "atrace --async_stop > /dev/null"; Log.v(TAG, "Stopping async atrace: " + cmd); try { Process atrace = TraceUtils.exec(cmd); if (atrace.waitFor() != 0) { Log.e(TAG, "atraceStop failed with: " + atrace.exitValue()); } } catch (Exception e) { throw new RuntimeException(e); } } public boolean traceDump(File outFile) { String cmd = "atrace --async_stop -z -c -o " + outFile; Log.v(TAG, "Dumping async atrace: " + cmd); try { Process atrace = TraceUtils.exec(cmd); if (atrace.waitFor() != 0) { Log.e(TAG, "atraceDump failed with: " + atrace.exitValue()); return false; } Process ps = TraceUtils.exec("ps -AT", null, false); new Streamer("atraceDump:ps:stdout", ps.getInputStream(), new FileOutputStream(outFile, true /* append */)); if (ps.waitFor() != 0) { Log.e(TAG, "atraceDump:ps failed with: " + ps.exitValue()); return false; } // Set the new file world readable to allow it to be adb pulled. outFile.setReadable(true, false); // (readable, ownerOnly) outFile.setWritable(true, false); // (readable, ownerOnly) } catch (Exception e) { throw new RuntimeException(e); } return true; } public boolean isTracingOn() { boolean userInitiatedTracingFlag = TraceProperties.user_initiated().orElse(false); if (!userInitiatedTracingFlag) { return false; } boolean tracingOnFlag = false; try { List tracingOnContents; Path debugTracingOnPath = Paths.get(DEBUG_TRACING_FILE); Path tracingOnPath = Paths.get(TRACING_FILE); if (Files.isReadable(debugTracingOnPath)) { tracingOnContents = Files.readAllLines(debugTracingOnPath); } else if (Files.isReadable(tracingOnPath)) { tracingOnContents = Files.readAllLines(tracingOnPath); } else { return false; } tracingOnFlag = !tracingOnContents.get(0).equals("0"); } catch (IOException e) { throw new RuntimeException(e); } return userInitiatedTracingFlag && tracingOnFlag; } public static TreeMap atraceListCategories() { String cmd = "atrace --list_categories"; Log.v(TAG, "Listing tags: " + cmd); try { Process atrace = TraceUtils.exec(cmd, null, false); BufferedReader stdout = new BufferedReader( new InputStreamReader(atrace.getInputStream())); if (atrace.waitFor() != 0) { Log.e(TAG, "atraceListCategories failed with: " + atrace.exitValue()); } TreeMap result = new TreeMap<>(); String line; while ((line = stdout.readLine()) != null) { String[] fields = line.trim().split(" - ", 2); if (fields.length == 2) { result.put(fields[0], fields[1]); } } return result; } catch (Exception e) { throw new RuntimeException(e); } } }