Merge "Add more ways to run AppLaunch."

This commit is contained in:
TreeHugger Robot
2018-02-15 20:39:58 +00:00
committed by Android (Google) Code Review

View File

@@ -65,6 +65,7 @@ public class AppLaunch extends InstrumentationTestCase {
private static final int JOIN_TIMEOUT = 10000;
private static final String TAG = AppLaunch.class.getSimpleName();
// optional parameter: comma separated list of required account types before proceeding
// with the app launch
private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
@@ -73,32 +74,36 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
private static final String KEY_LAUNCH_ORDER = "launch_order";
private static final String KEY_DROP_CACHE = "drop_cache";
private static final String KEY_SIMULATE_MAINTANANCE = "simulate_maintanance";
private static final String KEY_SIMPLEPPERF_CMD = "simpleperf_cmd";
private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
private static final String KEY_TRACE_DIRECTORY = "trace_directory";
private static final String KEY_TRACE_CATEGORY = "trace_categories";
private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
private static final String KEY_COMPILER_FILTERS = "compiler_filters";
private static final String SIMPLEPERF_APP_CMD =
"simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
private static final String WEARABLE_ACTION_GOOGLE =
"com.google.android.wearable.action.GOOGLE";
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
private static final String LAUNCH_FILE = "applaunch.txt";
private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview,"
+ "input,wm,disk,am,wm";
private static final String DEFAULT_TRACE_CATEGORIES =
"sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
private static final String TRIAL_LAUNCH = "TRAIL_LAUNCH";
private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
private static final String DELIMITER = ",";
private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
private static final String APP_LAUNCH_CMD = "am start -W -n";
private static final String SUCCESS_MESSAGE = "Status: ok";
private static final String PROFILE_COMPILE_SUCCESS = "Success";
private static final String COMPILE_SUCCESS = "Success";
private static final String THIS_TIME = "ThisTime:";
private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
@@ -106,14 +111,15 @@ public class AppLaunch extends InstrumentationTestCase {
private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
private static final String SPEED_PROFILE_CMD = "cmd package compile -f -m speed-profile %s";
private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
private static final String SPEED_PROFILE_FILTER = "speed-profile";
private static final String VERIFY_FILTER = "verify";
private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
private Map<String, Intent> mNameToIntent;
private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
private Map<String, String> mNameToResultKey;
private Map<String, List<Long>> mNameToLaunchTime;
private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
private IActivityManager mAm;
private String mSimplePerfCmd = null;
private String mLaunchOrder = null;
@@ -123,12 +129,10 @@ public class AppLaunch extends InstrumentationTestCase {
private String mTraceDirectoryStr = null;
private Bundle mResult = new Bundle();
private Set<String> mRequiredAccounts;
private boolean mTrailLaunch = true;
private File mFile = null;
private FileOutputStream mOutputStream = null;
private boolean mTrialLaunch = false;
private BufferedWriter mBufferedWriter = null;
private boolean mSimulateMaintanance = false;
private boolean mSimplePerfAppOnly = false;
private String[] mCompilerFilters = null;
@Override
protected void setUp() throws Exception {
@@ -142,6 +146,16 @@ public class AppLaunch extends InstrumentationTestCase {
super.tearDown();
}
private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
}
private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
List<AppLaunchResult> results =
mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
}
public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
IOException, InterruptedException {
InstrumentationTestRunner instrumentation =
@@ -149,11 +163,6 @@ public class AppLaunch extends InstrumentationTestCase {
Bundle args = instrumentation.getArguments();
mAm = ActivityManager.getService();
String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
mSimplePerfCmd = args.getString(KEY_SIMPLEPPERF_CMD);
mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
mSimulateMaintanance = Boolean.parseBoolean(args.getString(KEY_SIMULATE_MAINTANANCE));
createMappings();
parseArgs(args);
@@ -171,13 +180,14 @@ public class AppLaunch extends InstrumentationTestCase {
try {
File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
throw new IOException("Unable to create the lauch file sub directory");
}
mFile = new File(launchSubDir, LAUNCH_FILE);
mOutputStream = new FileOutputStream(mFile);
File file = new File(launchSubDir, LAUNCH_FILE);
FileOutputStream outputStream = new FileOutputStream(file);
mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
mOutputStream));
outputStream));
// Root directory for trace file during the launches
File rootTrace = null;
@@ -217,70 +227,67 @@ public class AppLaunch extends InstrumentationTestCase {
setLaunchOrder();
for (LaunchOrder launch : mLaunchOrderList) {
dropCache();
// App launch times for trial launch will not be used for final
// launch time calculations.
if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
// In the "applaunch.txt" file, trail launches is referenced using
// "TRIAL_LAUNCH"
long launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
if (launchTime < 0) {
List<Long> appLaunchList = new ArrayList<Long>();
appLaunchList.add(-1L);
mNameToLaunchTime.put(launch.getApp(), appLaunchList);
String appPkgName = mNameToIntent.get(launch.getApp())
.getComponent().getPackageName();
if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(VERIFY_FILTER, appPkgName));
} else if (launch.getCompilerFilter() != null) {
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(launch.getCompilerFilter(), appPkgName));
}
// We only need to run a trial for the speed-profile filter, but we always
// run one for "applaunch.txt" consistency.
AppLaunchResult launchResult =
startApp(launch.getApp(), true, launch.getLaunchReason());
if (launchResult.mLaunchTime < 0) {
addLaunchResult(launch, new AppLaunchResult());
// simply pass the app if launch isn't successful
// error should have already been logged by startApp
continue;
}
sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
closeApp(launch.getApp(), true);
dropCache();
if (mSimulateMaintanance) {
String appPkgName = mNameToIntent.get(launch.getApp())
.getComponent().getPackageName();
assertTrue(String.format("Not able to speed profile the app : %s",
appPkgName), profileCompileApp(appPkgName));
if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
// Send SIGUSR1 to force dumping a profile.
String sendSignalCommand =
String.format("killall -s SIGUSR1 %s", appPkgName);
getInstrumentation().getUiAutomation().executeShellCommand(
sendSignalCommand);
assertTrue(String.format("Not able to compile the app : %s", appPkgName),
compileApp(launch.getCompilerFilter(), appPkgName));
}
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times used for final calculation
if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
long launchTime = -1;
if (null != mNameToLaunchTime.get(launch.getApp())) {
long firstLaunchTime = mNameToLaunchTime.get(launch.getApp()).get(0);
if (firstLaunchTime < 0) {
// skip if the app has failures while launched first
continue;
}
else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
AppLaunchResult launchResults = null;
if (hasFailureOnFirstLaunch(launch)) {
// skip if the app has failures while launched first
continue;
}
// In the "applaunch.txt" file app launches are referenced using
// "LAUNCH_ITERATION - ITERATION NUM"
launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
if (launchTime < 0) {
launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
if (launchResults.mLaunchTime < 0) {
addLaunchResult(launch, new AppLaunchResult());
// if it fails once, skip the rest of the launches
List<Long> appLaunchList = new ArrayList<Long>();
appLaunchList.add(-1L);
mNameToLaunchTime.put(launch.getApp(), appLaunchList);
continue;
} else {
if (null != mNameToLaunchTime.get(launch.getApp())) {
mNameToLaunchTime.get(launch.getApp()).add(launchTime);
} else {
List<Long> appLaunchList = new ArrayList<Long>();
appLaunchList.add(launchTime);
mNameToLaunchTime.put(launch.getApp(), appLaunchList);
}
addLaunchResult(launch, launchResults);
}
sleep(POST_LAUNCH_IDLE_TIMEOUT);
closeApp(launch.getApp(), true);
dropCache();
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
// App launch times for trace launch will not be used for final
// launch time calculations.
if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
AtraceLogger atraceLogger = AtraceLogger
.getAtraceLoggerInstance(getInstrumentation());
// Start the trace
@@ -293,11 +300,10 @@ public class AppLaunch extends InstrumentationTestCase {
} finally {
// Stop the trace
atraceLogger.atraceStop();
closeApp(launch.getApp(), true);
dropCache();
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
}
closeApp(launch.getApp(), true);
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
} finally {
if (null != mBufferedWriter) {
@@ -306,29 +312,45 @@ public class AppLaunch extends InstrumentationTestCase {
}
for (String app : mNameToResultKey.keySet()) {
StringBuilder launchTimes = new StringBuilder();
for (Long launch : mNameToLaunchTime.get(app)) {
launchTimes.append(launch);
launchTimes.append(",");
for (String compilerFilter : mCompilerFilters) {
StringBuilder launchTimes = new StringBuilder();
StringBuilder cpuCycles = new StringBuilder();
StringBuilder majorFaults = new StringBuilder();
for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
launchTimes.append(result.mLaunchTime);
launchTimes.append(",");
if (mSimplePerfAppOnly) {
cpuCycles.append(result.mCpuCycles);
cpuCycles.append(",");
majorFaults.append(result.mMajorFaults);
majorFaults.append(",");
}
}
String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
if (mSimplePerfAppOnly) {
mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
cpuCycles.toString());
mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
majorFaults.toString());
}
}
mResult.putString(mNameToResultKey.get(app), launchTimes.toString());
}
instrumentation.sendStatus(0, mResult);
}
/**
* Compile the app package using speed compile command and return true or false
* Compile the app package using compilerFilter and return true or false
* based on status of the compilation command.
*/
private boolean profileCompileApp(String appPkgName) throws IOException {
Log.i(TAG, "Starting to speed profile " + appPkgName);
private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
executeShellCommand(String.format(SPEED_PROFILE_CMD, appPkgName));
executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
new FileInputStream(result.getFileDescriptor())))) {
String line;
while ((line = bufferedReader.readLine()) != null) {
if (line.contains(PROFILE_COMPILE_SUCCESS)) {
if (line.contains(COMPILE_SUCCESS)) {
return true;
}
}
@@ -344,38 +366,42 @@ public class AppLaunch extends InstrumentationTestCase {
*/
private void setLaunchOrder() {
if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
if (mTrailLaunch) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
}
}
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app,
String.format(LAUNCH_ITERATION, launchCount)));
}
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
for (String compilerFilter : mCompilerFilters) {
if (mTrialLaunch) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app,
String.format(TRACE_ITERATION, traceCount)));
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
}
}
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
String.format(LAUNCH_ITERATION, launchCount)));
}
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
for (String app : mNameToResultKey.keySet()) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
String.format(TRACE_ITERATION, traceCount)));
}
}
}
}
} else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
for (String app : mNameToResultKey.keySet()) {
if (mTrailLaunch) {
mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
}
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
mLaunchOrderList.add(new LaunchOrder(app,
String.format(LAUNCH_ITERATION, launchCount)));
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
mLaunchOrderList.add(new LaunchOrder(app,
String.format(TRACE_ITERATION, traceCount)));
for (String compilerFilter : mCompilerFilters) {
for (String app : mNameToResultKey.keySet()) {
if (mTrialLaunch) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
}
for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
String.format(LAUNCH_ITERATION, launchCount)));
}
if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
String.format(TRACE_ITERATION, traceCount)));
}
}
}
}
@@ -385,7 +411,7 @@ public class AppLaunch extends InstrumentationTestCase {
}
private void dropCache() {
if (true == mDropCache) {
if (mDropCache) {
assertNotNull("Issue in dropping the cache",
getInstrumentation().getUiAutomation()
.executeShellCommand(DROP_CACHE_SCRIPT));
@@ -394,7 +420,7 @@ public class AppLaunch extends InstrumentationTestCase {
private void parseArgs(Bundle args) {
mNameToResultKey = new LinkedHashMap<String, String>();
mNameToLaunchTime = new HashMap<String, List<Long>>();
mNameToLaunchTime = new HashMap<>();
String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
if (launchIterations != null) {
mLaunchIterations = Integer.parseInt(launchIterations);
@@ -421,7 +447,38 @@ public class AppLaunch extends InstrumentationTestCase {
mRequiredAccounts.add(accountType);
}
}
mTrailLaunch = "true".equals(args.getString(KEY_TRIAL_LAUNCH));
String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
if (compilerFilterList != null) {
// If a compiler filter is passed, we make a trial launch to force compilation
// of the apps.
mTrialLaunch = true;
mCompilerFilters = compilerFilterList.split("\\|");
} else {
// Just pass a null compiler filter to use the current state of the app.
mCompilerFilters = new String[1];
}
// Pre-populate the results map to avoid null checks.
for (String app : mNameToLaunchTime.keySet()) {
HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
mNameToLaunchTime.put(app, map);
for (String compilerFilter : mCompilerFilters) {
map.put(compilerFilter, new ArrayList<>());
}
}
mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
}
}
private boolean hasLeanback(Context context) {
@@ -465,17 +522,17 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
private long startApp(String appName, boolean forceStopBeforeLaunch, String launchReason)
throws NameNotFoundException, RemoteException {
private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
String launchReason) throws NameNotFoundException, RemoteException {
Log.i(TAG, "Starting " + appName);
Intent startIntent = mNameToIntent.get(appName);
if (startIntent == null) {
Log.w(TAG, "App does not exist: " + appName);
mResult.putString(mNameToResultKey.get(appName), "App does not exist");
return -1L;
return new AppLaunchResult();
}
AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch ,
AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
launchReason);
Thread t = new Thread(runnable);
t.start();
@@ -569,10 +626,12 @@ public class AppLaunch extends InstrumentationTestCase {
private class LaunchOrder {
private String mApp;
private String mCompilerFilter;
private String mLaunchReason;
LaunchOrder(String app,String launchReason){
LaunchOrder(String app, String compilerFilter, String launchReason){
mApp = app;
mCompilerFilter = compilerFilter;
mLaunchReason = launchReason;
}
@@ -584,6 +643,10 @@ public class AppLaunch extends InstrumentationTestCase {
mApp = app;
}
public String getCompilerFilter() {
return mCompilerFilter;
}
public String getLaunchReason() {
return mLaunchReason;
}
@@ -593,9 +656,31 @@ public class AppLaunch extends InstrumentationTestCase {
}
}
private class AppLaunchResult {
long mLaunchTime;
long mCpuCycles;
long mMajorFaults;
AppLaunchResult() {
mLaunchTime = -1L;
mCpuCycles = -1L;
mMajorFaults = -1L;
}
AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
try {
mLaunchTime = Long.parseLong(launchTime, 10);
mCpuCycles = Long.parseLong(cpuCycles, 10);
mMajorFaults = Long.parseLong(majorFaults, 10);
} catch (NumberFormatException e) {
Log.e(TAG, "Error parsing result", e);
}
}
}
private class AppLaunchRunnable implements Runnable {
private Intent mLaunchIntent;
private Long mResult;
private AppLaunchResult mLaunchResult;
private boolean mForceStopBeforeLaunch;
private String mLaunchReason;
@@ -604,14 +689,15 @@ public class AppLaunch extends InstrumentationTestCase {
mLaunchIntent = intent;
mForceStopBeforeLaunch = forceStopBeforeLaunch;
mLaunchReason = launchReason;
mResult = -1L;
mLaunchResult = new AppLaunchResult();
}
public Long getResult() {
return mResult;
public AppLaunchResult getResult() {
return mLaunchResult;
}
public void run() {
File launchFile = null;
try {
String packageName = mLaunchIntent.getComponent().getPackageName();
String componentName = mLaunchIntent.getComponent().flattenToShortString();
@@ -619,17 +705,38 @@ public class AppLaunch extends InstrumentationTestCase {
mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
}
String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
if (null != mSimplePerfCmd) {
if (mSimplePerfAppOnly) {
try {
// executeShellCommand cannot handle shell specific actions, like '&'.
// Therefore, we create a file containing the command and make that
// the command to launch.
launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
launchFile.setExecutable(true);
try (FileOutputStream stream = new FileOutputStream(launchFile);
BufferedWriter writer =
new BufferedWriter(new OutputStreamWriter(stream))) {
String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
writer.write(cmd);
}
launchCmd = launchFile.getAbsolutePath();
} catch (IOException e) {
Log.w(TAG, "Error writing the launch command", e);
return;
}
} else if (null != mSimplePerfCmd) {
launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
}
Log.v(TAG, "Final launch cmd:" + launchCmd);
ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
.executeShellCommand(launchCmd);
mResult = Long.parseLong(parseLaunchTimeAndWrite(parcelDesc, String.format
("App Launch :%s %s",
componentName, mLaunchReason)), 10);
mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
("App Launch :%s %s", componentName, mLaunchReason));
} catch (RemoteException e) {
Log.w(TAG, "Error launching app", e);
} finally {
if (launchFile != null) {
launchFile.delete();
}
}
}
@@ -639,12 +746,14 @@ public class AppLaunch extends InstrumentationTestCase {
* @param parcelDesc
* @return
*/
private String parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, String headerInfo) {
private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
String headerInfo) {
String launchTime = "-1";
String cpuCycles = "-1";
String majorFaults = "-1";
boolean launchSuccess = false;
try {
InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
StringBuilder appLaunchOuput = new StringBuilder();
/* SAMPLE OUTPUT :
Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
Status: ok
@@ -653,6 +762,11 @@ public class AppLaunch extends InstrumentationTestCase {
TotalTime: 357
WaitTime: 377
Complete*/
/* WITH SIMPLEPERF :
Performance counter statistics,
6595722690,cpu-cycles,4.511040,GHz,(100%),
0,major-faults,0.000,/sec,(100%),
Total test time,1.462129,seconds,*/
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
inputStream));
String line = null;
@@ -669,6 +783,23 @@ public class AppLaunch extends InstrumentationTestCase {
String launchSplit[] = line.split(":");
launchTime = launchSplit[1].trim();
}
if (mSimplePerfAppOnly) {
// Parse simpleperf output.
if (lineCount == 9) {
if (!line.contains("cpu-cycles")) {
Log.e(TAG, "Error in simpleperf output");
} else {
cpuCycles = line.split(",")[0].trim();
}
} else if (lineCount == 10) {
if (!line.contains("major-faults")) {
Log.e(TAG, "Error in simpleperf output");
} else {
majorFaults = line.split(",")[0].trim();
}
}
}
mBufferedWriter.write(line);
mBufferedWriter.newLine();
lineCount++;
@@ -678,7 +809,7 @@ public class AppLaunch extends InstrumentationTestCase {
} catch (IOException e) {
Log.w(TAG, "Error writing the launch file", e);
}
return launchTime;
return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
}
}