• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Build;
20 import android.os.SystemProperties;
21 import android.util.Log;
22 
23 import java.io.BufferedReader;
24 import java.io.File;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.InputStreamReader;
29 import java.io.OutputStream;
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.text.SimpleDateFormat;
34 import java.util.Arrays;
35 import java.util.Date;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.TreeMap;
39 
40 /**
41  * Utility functions for calling atrace
42  */
43 public class AtraceUtils {
44 
45     static final String TAG = "Traceur";
46 
47     public static final String TRACE_DIRECTORY = "/data/local/traces/";
48 
49     private static final String DEBUG_TRACING_FILE = "/sys/kernel/debug/tracing/tracing_on";
50     private static final String TRACING_FILE = "/sys/kernel/tracing/tracing_on";
51 
52     private static final Runtime RUNTIME = Runtime.getRuntime();
53 
atraceStart(String tags, int bufferSizeKb, boolean apps)54     public static boolean atraceStart(String tags, int bufferSizeKb, boolean apps) {
55         String appParameter = apps ? "-a '*' " : "";
56         String cmd = "atrace --async_start -c -b " + bufferSizeKb + " " + appParameter + tags;
57 
58         Log.v(TAG, "Starting async atrace: " + cmd);
59         try {
60             Process atrace = exec(cmd);
61             if (atrace.waitFor() != 0) {
62                 Log.e(TAG, "atraceStart failed with: " + atrace.exitValue());
63                 return false;
64             }
65         } catch (Exception e) {
66             throw new RuntimeException(e);
67         }
68         return true;
69     }
70 
atraceStop()71     public static void atraceStop() {
72         String cmd = "atrace --async_stop > /dev/null";
73 
74         Log.v(TAG, "Stopping async atrace: " + cmd);
75         try {
76             Process atrace = exec(cmd);
77 
78             if (atrace.waitFor() != 0) {
79                 Log.e(TAG, "atraceStop failed with: " + atrace.exitValue());
80             }
81         } catch (Exception e) {
82             throw new RuntimeException(e);
83         }
84     }
atraceDump(File outFile)85     public static boolean atraceDump(File outFile) {
86         String cmd = "atrace --async_stop -z -c -o " + outFile;
87 
88         Log.v(TAG, "Dumping async atrace: " + cmd);
89         try {
90             Process atrace = exec(cmd);
91 
92             if (atrace.waitFor() != 0) {
93                 Log.e(TAG, "atraceDump failed with: " + atrace.exitValue());
94                 return false;
95             }
96 
97             Process ps = exec("ps -AT");
98 
99             new Streamer("atraceDump:ps:stdout",
100                     ps.getInputStream(), new FileOutputStream(outFile, true /* append */));
101 
102             if (ps.waitFor() != 0) {
103                 Log.e(TAG, "atraceDump:ps failed with: " + ps.exitValue());
104                 return false;
105             }
106 
107             // Set the new file world readable to allow it to be adb pulled.
108             outFile.setReadable(true, false); // (readable, ownerOnly)
109         } catch (Exception e) {
110             throw new RuntimeException(e);
111         }
112         return true;
113     }
114 
atraceListCategories()115     public static TreeMap<String,String> atraceListCategories() {
116         String cmd = "atrace --list_categories";
117 
118         Log.v(TAG, "Listing tags: " + cmd);
119         try {
120             Process atrace = exec(cmd);
121 
122             new Logger("atraceListCat:stderr", atrace.getErrorStream());
123             BufferedReader stdout = new BufferedReader(
124                     new InputStreamReader(atrace.getInputStream()));
125 
126             if (atrace.waitFor() != 0) {
127                 Log.e(TAG, "atraceListCategories failed with: " + atrace.exitValue());
128             }
129 
130             TreeMap<String, String> result = new TreeMap<>();
131             String line;
132             while ((line = stdout.readLine()) != null) {
133                 String[] fields = line.trim().split(" - ", 2);
134                 if (fields.length == 2) {
135                     result.put(fields[0], fields[1]);
136                 }
137             }
138             return result;
139         } catch (Exception e) {
140             throw new RuntimeException(e);
141         }
142     }
143 
clearSavedTraces()144     public static void clearSavedTraces() {
145         String cmd = "rm -f " + TRACE_DIRECTORY + "trace-*.ctrace";
146 
147         Log.v(TAG, "Clearing trace directory: " + cmd);
148         try {
149             Process rm = exec(cmd);
150 
151             if (rm.waitFor() != 0) {
152                 Log.e(TAG, "clearSavedTraces failed with: " + rm.exitValue());
153             }
154         } catch (Exception e) {
155             throw new RuntimeException(e);
156         }
157     }
158 
exec(String cmd)159     private static Process exec(String cmd) throws IOException {
160         String[] cmdarray = {"sh", "-c", cmd};
161         Log.v(TAG, "exec: " + Arrays.toString(cmdarray));
162         return RUNTIME.exec(cmdarray);
163     }
164 
isTracingOn()165     public static boolean isTracingOn() {
166         boolean userInitiatedTracingFlag =
167             "1".equals(SystemProperties.get("debug.atrace.user_initiated", ""));
168 
169         if (!userInitiatedTracingFlag) {
170             return false;
171         }
172 
173         boolean tracingOnFlag = false;
174 
175         try {
176             List<String> tracingOnContents;
177 
178             Path debugTracingOnPath = Paths.get(DEBUG_TRACING_FILE);
179             Path tracingOnPath = Paths.get(TRACING_FILE);
180 
181             if (Files.isReadable(debugTracingOnPath)) {
182                 tracingOnContents = Files.readAllLines(debugTracingOnPath);
183             } else if (Files.isReadable(tracingOnPath)) {
184                 tracingOnContents = Files.readAllLines(tracingOnPath);
185             } else {
186                 return false;
187             }
188 
189             tracingOnFlag = !tracingOnContents.get(0).equals("0");
190         } catch (IOException e) {
191             throw new RuntimeException(e);
192         }
193 
194         return userInitiatedTracingFlag && tracingOnFlag;
195     }
196 
getOutputFilename()197     public static String getOutputFilename() {
198         String format = "yyyy-MM-dd-HH-mm-ss";
199         String now = new SimpleDateFormat(format, Locale.US).format(new Date());
200         return String.format("trace-%s-%s-%s.ctrace", Build.BOARD, Build.ID, now);
201     }
202 
getOutputFile(String filename)203     public static File getOutputFile(String filename) {
204         return new File(AtraceUtils.TRACE_DIRECTORY, filename);
205     }
206 
207     /**
208      * Streams data from an InputStream to an OutputStream
209      */
210     private static class Streamer {
211         private boolean mDone;
212 
Streamer(final String tag, final InputStream in, final OutputStream out)213         Streamer(final String tag, final InputStream in, final OutputStream out) {
214             new Thread(tag) {
215                 @Override
216                 public void run() {
217                     int read;
218                     byte[] buf = new byte[2 << 10];
219                     try {
220                         while ((read = in.read(buf)) != -1) {
221                             out.write(buf, 0, read);
222                         }
223                     } catch (IOException e) {
224                         Log.e(TAG, "Error while streaming " + tag);
225                     } finally {
226                         try {
227                             out.close();
228                         } catch (IOException e) {
229                             // Welp.
230                         }
231                         synchronized (Streamer.this) {
232                             mDone = true;
233                             Streamer.this.notify();
234                         }
235                     }
236                 }
237             }.start();
238         }
239 
isDone()240         synchronized boolean isDone() {
241             return mDone;
242         }
243 
waitForDone()244         synchronized void waitForDone() {
245             while (!isDone()) {
246                 try {
247                     wait();
248                 } catch (InterruptedException e) {
249                     Thread.currentThread().interrupt();
250                 }
251             }
252         }
253     }
254 
255     /**
256      * Streams data from an InputStream to an OutputStream
257      */
258     private static class Logger {
259 
Logger(final String tag, final InputStream in)260         Logger(final String tag, final InputStream in) {
261             new Thread(tag) {
262                 @Override
263                 public void run() {
264                     int read;
265                     String line;
266                     BufferedReader r = new BufferedReader(new InputStreamReader(in));
267                     try {
268                         while ((line = r.readLine()) != null) {
269                             Log.e(TAG, tag + ": " + line);
270                         }
271                     } catch (IOException e) {
272                         Log.e(TAG, "Error while streaming " + tag);
273                     } finally {
274                         try {
275                             r.close();
276                         } catch (IOException e) {
277                             // Welp.
278                         }
279                     }
280                 }
281             }.start();
282         }
283     }
284 }
285