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.sysprop.TraceProperties;
20 import android.text.TextUtils;
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.util.Collection;
34 import java.util.List;
35 import java.util.TreeMap;
36 
37 import com.android.traceur.TraceUtils.Streamer;
38 
39 /**
40  * Utility functions for calling atrace
41  */
42 public class AtraceUtils implements TraceUtils.TraceEngine {
43 
44     static final String TAG = "Traceur";
45 
46     private static final String DEBUG_TRACING_FILE = "/sys/kernel/debug/tracing/tracing_on";
47     private static final String TRACING_FILE = "/sys/kernel/tracing/tracing_on";
48 
49     public static String NAME = "ATRACE";
50     private static String OUTPUT_EXTENSION = "ctrace";
51 
getName()52     public String getName() {
53         return NAME;
54     }
55 
getOutputExtension()56     public String getOutputExtension() {
57         return OUTPUT_EXTENSION;
58     }
59 
60     /* Note: longTrace and maxLongTrace* parameters are ignored in atrace mode. */
traceStart(Collection<String> tags, int bufferSizeKb, boolean apps, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)61     public boolean traceStart(Collection<String> tags, int bufferSizeKb, boolean apps,
62             boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) {
63 
64         String appParameter = apps ? "-a '*' " : "";
65         String cmd = "atrace --async_start -c -b " + bufferSizeKb + " "
66             + appParameter + TextUtils.join(" ", tags);
67 
68         Log.v(TAG, "Starting async atrace: " + cmd);
69         try {
70             Process atrace = TraceUtils.exec(cmd);
71             if (atrace.waitFor() != 0) {
72                 Log.e(TAG, "atraceStart failed with: " + atrace.exitValue());
73                 return false;
74             }
75         } catch (Exception e) {
76             throw new RuntimeException(e);
77         }
78         return true;
79     }
80 
traceStop()81     public void traceStop() {
82         String cmd = "atrace --async_stop > /dev/null";
83 
84         Log.v(TAG, "Stopping async atrace: " + cmd);
85         try {
86             Process atrace = TraceUtils.exec(cmd);
87 
88             if (atrace.waitFor() != 0) {
89                 Log.e(TAG, "atraceStop failed with: " + atrace.exitValue());
90             }
91         } catch (Exception e) {
92             throw new RuntimeException(e);
93         }
94     }
95 
traceDump(File outFile)96     public boolean traceDump(File outFile) {
97         String cmd = "atrace --async_stop -z -c -o " + outFile;
98 
99         Log.v(TAG, "Dumping async atrace: " + cmd);
100         try {
101             Process atrace = TraceUtils.exec(cmd);
102 
103             if (atrace.waitFor() != 0) {
104                 Log.e(TAG, "atraceDump failed with: " + atrace.exitValue());
105                 return false;
106             }
107 
108             Process ps = TraceUtils.exec("ps -AT", null, false);
109 
110             new Streamer("atraceDump:ps:stdout",
111                     ps.getInputStream(), new FileOutputStream(outFile, true /* append */));
112 
113             if (ps.waitFor() != 0) {
114                 Log.e(TAG, "atraceDump:ps failed with: " + ps.exitValue());
115                 return false;
116             }
117 
118             // Set the new file world readable to allow it to be adb pulled.
119             outFile.setReadable(true, false); // (readable, ownerOnly)
120             outFile.setWritable(true, false); // (readable, ownerOnly)
121         } catch (Exception e) {
122             throw new RuntimeException(e);
123         }
124         return true;
125     }
126 
isTracingOn()127     public boolean isTracingOn() {
128         boolean userInitiatedTracingFlag =
129             TraceProperties.user_initiated().orElse(false);
130 
131         if (!userInitiatedTracingFlag) {
132             return false;
133         }
134 
135         boolean tracingOnFlag = false;
136 
137         try {
138             List<String> tracingOnContents;
139 
140             Path debugTracingOnPath = Paths.get(DEBUG_TRACING_FILE);
141             Path tracingOnPath = Paths.get(TRACING_FILE);
142 
143             if (Files.isReadable(debugTracingOnPath)) {
144                 tracingOnContents = Files.readAllLines(debugTracingOnPath);
145             } else if (Files.isReadable(tracingOnPath)) {
146                 tracingOnContents = Files.readAllLines(tracingOnPath);
147             } else {
148                 return false;
149             }
150 
151             tracingOnFlag = !tracingOnContents.get(0).equals("0");
152         } catch (IOException e) {
153             throw new RuntimeException(e);
154         }
155 
156         return userInitiatedTracingFlag && tracingOnFlag;
157     }
158 
atraceListCategories()159     public static TreeMap<String,String> atraceListCategories() {
160         String cmd = "atrace --list_categories";
161 
162         Log.v(TAG, "Listing tags: " + cmd);
163         try {
164             Process atrace = TraceUtils.exec(cmd, null, false);
165 
166             BufferedReader stdout = new BufferedReader(
167                     new InputStreamReader(atrace.getInputStream()));
168 
169             if (atrace.waitFor() != 0) {
170                 Log.e(TAG, "atraceListCategories failed with: " + atrace.exitValue());
171             }
172 
173             TreeMap<String, String> result = new TreeMap<>();
174             String line;
175             while ((line = stdout.readLine()) != null) {
176                 String[] fields = line.trim().split(" - ", 2);
177                 if (fields.length == 2) {
178                     result.put(fields[0], fields[1]);
179                 }
180             }
181             return result;
182         } catch (Exception e) {
183             throw new RuntimeException(e);
184         }
185     }
186 }
187