1 /*
2  * Copyright (C) 2016 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 package com.android.tradefed.util;
17 
18 import com.android.ddmlib.IShellOutputReceiver;
19 import com.android.tradefed.device.DeviceNotAvailableException;
20 import com.android.tradefed.device.ITestDevice;
21 
22 import org.junit.Assert;
23 
24 import java.util.List;
25 import java.util.concurrent.TimeUnit;
26 
27 /**
28  * Utility class to dispatch simple command and collect results
29  * @see <a href="https://android.googlesource.com/platform/system/extras/+/master/simpleperf/">
30  * Introduction of simpleperf</a>
31  */
32 public class SimplePerfUtil {
33 
34     private ITestDevice mDevice;
35 
36     private SimplePerfType mType;
37 
38     private List<String> mArguList;
39     private StringBuilder mCachedCommandPrepend;
40 
SimplePerfUtil(ITestDevice device, SimplePerfType type)41     private SimplePerfUtil(ITestDevice device, SimplePerfType type) {
42         mDevice = device;
43         mType = type;
44         mCachedCommandPrepend = null;
45     }
46 
47     /**
48      * SimplePerfUtil Constructor
49      * <p/>
50      * Caller must define device and simpleperf type when initializing instance
51      *
52      * @param device {@link ITestDevice} test device
53      * @param type {@link SimplePerfType} indicates which simpleperf mode
54      * @return a newly created SimplePerfUtil instance
55      */
newInstance(ITestDevice device, SimplePerfType type)56     public static SimplePerfUtil newInstance(ITestDevice device, SimplePerfType type)
57             throws  NullPointerException {
58         if (device == null || type == null) {
59             throw new NullPointerException();
60         }
61         return new SimplePerfUtil(device, type);
62     }
63 
64     /**
65      * Get argument for simpleperf command
66      *
67      * @return list of subcommand and arguments (nullable)
68      */
getArgumentList()69     public List<String> getArgumentList() {
70         return mArguList;
71     }
72 
73     /**
74      * Set argument on simpleperf command
75      *
76      * @param arguList list of subcommand and arguments
77      */
setArgumentList(List<String> arguList)78     public void setArgumentList(List<String> arguList) {
79         mArguList = arguList;
80         mCachedCommandPrepend = null;
81     }
82 
83     /**
84      * Executes the given adb shell command, with simpleperf wrapped around
85      * <p/>
86      * Simpleperf result will be parsed and return to caller
87      *
88      * @param command command to run on device
89      * @return {@link SimplePerfResult} object contains all result information
90      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
91      * recovered
92      */
executeCommand(String command)93     public SimplePerfResult executeCommand(String command) throws DeviceNotAvailableException {
94         String output = mDevice.executeShellCommand(commandStringPreparer(command));
95         Assert.assertNotNull("ExecuteShellCommand returns null", output);
96         return SimplePerfStatResultParser.parseRawOutput(output);
97     }
98 
99     /**
100      * Executes the given adb shell command, with simpleperf wrapped around
101      * <p/>
102      * It is caller's responsibility to parse simpleperf result through receiver
103      *
104      * @param command command to run on device
105      * @param receiver {@link IShellOutputReceiver} object to direct shell output to
106      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
107      * recovered
108      */
executeCommand(String command, IShellOutputReceiver receiver)109     public void executeCommand(String command, IShellOutputReceiver receiver)
110             throws DeviceNotAvailableException {
111         mDevice.executeShellCommand(commandStringPreparer(command), receiver);
112     }
113 
114     /**
115      * Executes the given adb shell command, with simpleperf wrapped around
116      * <p/>
117      * It is caller's responsibility to parse simpleperf result through receiver
118      *
119      * @param command command to run on device
120      * @param receiver {@link IShellOutputReceiver} object to direct shell output to
121      * @param maxTimeToOutputShellResponse the maximum amount of time during which the command is
122      * allowed to not output any response; unit as specified in <code>timeUnit</code>
123      * @param timeUnit timeUnit unit for <code>maxTimeToOutputShellResponse</code>, see {@link
124      * TimeUnit}
125      * @param retryAttempts the maximum number of times to retry command if it fails due to a
126      * exception. DeviceNotResponsiveException will be thrown if <var>retryAttempts</var> are
127      * performed without success.
128      * @throws DeviceNotAvailableException if connection with device is lost and cannot be
129      * recovered
130      */
executeCommand(String command, IShellOutputReceiver receiver, long maxTimeToOutputShellResponse, TimeUnit timeUnit, int retryAttempts)131     public void executeCommand(String command, IShellOutputReceiver receiver,
132             long maxTimeToOutputShellResponse, TimeUnit timeUnit, int retryAttempts)
133             throws DeviceNotAvailableException {
134         mDevice.executeShellCommand(commandStringPreparer(command), receiver,
135                 maxTimeToOutputShellResponse, timeUnit, retryAttempts);
136     }
137 
commandStringPreparer(String command)138     protected String commandStringPreparer(String command) {
139         if (command == null) {
140             command = "";
141         }
142         return commandPrependPreparer().toString() + command;
143     }
144 
commandPrependPreparer()145     private StringBuilder commandPrependPreparer() {
146         if (mCachedCommandPrepend == null) {
147             StringBuilder sb = new StringBuilder("simpleperf ");
148             sb.append(mType.toString()).append(" ");
149             if (mArguList != null) {
150                 for (String argu : mArguList) {
151                     sb.append(argu).append(" ");
152                 }
153             }
154             mCachedCommandPrepend = sb;
155         }
156         return mCachedCommandPrepend;
157     }
158 
159     /**
160      * Enum of simpleperf command options
161      */
162     public enum SimplePerfType {
163         STAT("stat"),
164         REPORT("report"),
165         RECORD("record"),
166         LIST("list");
167 
168         private final String text;
169 
SimplePerfType(final String text)170         SimplePerfType(final String text) {
171             this.text = text;
172         }
173 
174         @Override
toString()175         public String toString() {
176             return text;
177         }
178     }
179 
180 }
181