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.AsyncTask;
21 import android.os.FileUtils;
22 import android.util.Log;
23 
24 import java.io.File;
25 import java.io.IOException;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.text.SimpleDateFormat;
30 import java.util.Arrays;
31 import java.util.Date;
32 import java.util.Locale;
33 import java.util.Collection;
34 import java.util.TreeMap;
35 
36 /**
37  * Utility functions for tracing.
38  * Will call atrace or perfetto depending on the setting.
39  */
40 public class TraceUtils {
41 
42     static final String TAG = "Traceur";
43 
44     public static final String TRACE_DIRECTORY = "/data/local/traces/";
45 
46     // To change Traceur to use atrace to collect traces,
47     // change mTraceEngine to point to AtraceUtils().
48     private static TraceEngine mTraceEngine = new PerfettoUtils();
49 
50     private static final Runtime RUNTIME = Runtime.getRuntime();
51 
52     public interface TraceEngine {
getName()53         public String getName();
getOutputExtension()54         public String getOutputExtension();
traceStart(Collection<String> tags, int bufferSizeKb, boolean apps, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)55         public boolean traceStart(Collection<String> tags, int bufferSizeKb, boolean apps,
56             boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes);
traceStop()57         public void traceStop();
traceDump(File outFile)58         public boolean traceDump(File outFile);
isTracingOn()59         public boolean isTracingOn();
60     }
61 
currentTraceEngine()62     public static String currentTraceEngine() {
63         return mTraceEngine.getName();
64     }
65 
traceStart(Collection<String> tags, int bufferSizeKb, boolean apps, boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes)66     public static boolean traceStart(Collection<String> tags, int bufferSizeKb, boolean apps,
67             boolean longTrace, int maxLongTraceSizeMb, int maxLongTraceDurationMinutes) {
68         return mTraceEngine.traceStart(tags, bufferSizeKb, apps,
69             longTrace, maxLongTraceSizeMb, maxLongTraceDurationMinutes);
70     }
71 
traceStop()72     public static void traceStop() {
73         mTraceEngine.traceStop();
74     }
75 
traceDump(File outFile)76     public static boolean traceDump(File outFile) {
77         return mTraceEngine.traceDump(outFile);
78     }
79 
isTracingOn()80     public static boolean isTracingOn() {
81         return mTraceEngine.isTracingOn();
82     }
83 
listCategories()84     public static TreeMap<String, String> listCategories() {
85         return AtraceUtils.atraceListCategories();
86     }
87 
clearSavedTraces()88     public static void clearSavedTraces() {
89         String cmd = "rm -f " + TRACE_DIRECTORY + "trace-*.*trace";
90 
91         Log.v(TAG, "Clearing trace directory: " + cmd);
92         try {
93             Process rm = exec(cmd);
94 
95             if (rm.waitFor() != 0) {
96                 Log.e(TAG, "clearSavedTraces failed with: " + rm.exitValue());
97             }
98         } catch (Exception e) {
99             throw new RuntimeException(e);
100         }
101     }
102 
exec(String cmd)103     public static Process exec(String cmd) throws IOException {
104         return exec(cmd, null);
105     }
106 
exec(String cmd, String tmpdir)107     public static Process exec(String cmd, String tmpdir) throws IOException {
108         String[] cmdarray = {"sh", "-c", cmd};
109         String[] envp = {"TMPDIR=" + tmpdir};
110         envp = tmpdir == null ? null : envp;
111 
112         Log.v(TAG, "exec: " + Arrays.toString(envp) + " " + Arrays.toString(cmdarray));
113 
114         return RUNTIME.exec(cmdarray, envp);
115     }
116 
getOutputFilename()117     public static String getOutputFilename() {
118         String format = "yyyy-MM-dd-HH-mm-ss";
119         String now = new SimpleDateFormat(format, Locale.US).format(new Date());
120         return String.format("trace-%s-%s-%s.%s", Build.BOARD, Build.ID, now,
121             mTraceEngine.getOutputExtension());
122     }
123 
getOutputFile(String filename)124     public static File getOutputFile(String filename) {
125         return new File(TraceUtils.TRACE_DIRECTORY, filename);
126     }
127 
cleanupOlderFiles(final int minCount, final long minAge)128     protected static void cleanupOlderFiles(final int minCount, final long minAge) {
129         new AsyncTask<Void, Void, Void>() {
130             @Override
131             protected Void doInBackground(Void... params) {
132                 try {
133                     FileUtils.deleteOlderFiles(new File(TRACE_DIRECTORY), minCount, minAge);
134                 } catch (RuntimeException e) {
135                     Log.e(TAG, "Failed to delete older traces", e);
136                 }
137                 return null;
138             }
139         }.execute();
140     }
141 
142 }
143