Loading tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +99 −38 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading Loading @@ -32,6 +32,7 @@ import android.test.InstrumentationTestCase; import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestRunner; import android.util.Log; import android.util.Log; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; Loading @@ -48,16 +49,22 @@ import java.util.Map; public class AppLaunch extends InstrumentationTestCase { public class AppLaunch extends InstrumentationTestCase { private static final int JOIN_TIMEOUT = 10000; private static final int JOIN_TIMEOUT = 10000; private static final String TAG = "AppLaunch"; private static final String TAG = AppLaunch.class.getSimpleName(); private static final String KEY_APPS = "apps"; private static final String KEY_APPS = "apps"; private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations"; private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.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 = 2000; //2s between launching apps private Map<String, Intent> mNameToIntent; private Map<String, Intent> mNameToIntent; private Map<String, String> mNameToProcess; private Map<String, String> mNameToProcess; private Map<String, String> mNameToResultKey; private Map<String, String> mNameToResultKey; private Map<String, Long> mNameToLaunchTime; private IActivityManager mAm; private IActivityManager mAm; private int mLaunchIterations = 10; private Bundle mResult = new Bundle(); public void testMeasureStartUpTime() throws RemoteException { public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException { InstrumentationTestRunner instrumentation = InstrumentationTestRunner instrumentation = (InstrumentationTestRunner)getInstrumentation(); (InstrumentationTestRunner)getInstrumentation(); Bundle args = instrumentation.getArguments(); Bundle args = instrumentation.getArguments(); Loading @@ -66,25 +73,59 @@ public class AppLaunch extends InstrumentationTestCase { createMappings(); createMappings(); parseArgs(args); parseArgs(args); Bundle results = new Bundle(); // do initial app launch, without force stopping for (String app : mNameToResultKey.keySet()) { for (String app : mNameToResultKey.keySet()) { try { long launchTime = startApp(app, false); startApp(app, results); if (launchTime <=0 ) { sleep(750); mNameToLaunchTime.put(app, -1L); closeApp(app); // simply pass the app if launch isn't successful sleep(2000); // error should have already been logged by startApp } catch (NameNotFoundException e) { continue; Log.i(TAG, "Application " + app + " not found"); } sleep(INITIAL_LAUNCH_IDLE_TIMEOUT); closeApp(app, false); sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } // do the real app launch now for (int i = 0; i < mLaunchIterations; i++) { for (String app : mNameToResultKey.keySet()) { long totalLaunchTime = mNameToLaunchTime.get(app); long launchTime = 0; if (totalLaunchTime < 0) { // skip if the app has previous failures continue; } launchTime = startApp(app, true); if (launchTime <= 0) { // if it fails once, skip the rest of the launches mNameToLaunchTime.put(app, -1L); continue; } totalLaunchTime += launchTime; mNameToLaunchTime.put(app, totalLaunchTime); sleep(POST_LAUNCH_IDLE_TIMEOUT); closeApp(app, true); sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } } } } instrumentation.sendStatus(0, results); for (String app : mNameToResultKey.keySet()) { long totalLaunchTime = mNameToLaunchTime.get(app); if (totalLaunchTime != -1) { mResult.putDouble(mNameToResultKey.get(app), ((double) totalLaunchTime) / mLaunchIterations); } } instrumentation.sendStatus(0, mResult); } } private void parseArgs(Bundle args) { private void parseArgs(Bundle args) { mNameToResultKey = new LinkedHashMap<String, String>(); mNameToResultKey = new LinkedHashMap<String, String>(); mNameToLaunchTime = new HashMap<String, Long>(); String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS); if (launchIterations != null) { mLaunchIterations = Integer.parseInt(launchIterations); } String appList = args.getString(KEY_APPS); String appList = args.getString(KEY_APPS); if (appList == null) if (appList == null) return; return; Loading @@ -97,6 +138,7 @@ public class AppLaunch extends InstrumentationTestCase { } } mNameToResultKey.put(parts[0], parts[1]); mNameToResultKey.put(parts[0], parts[1]); mNameToLaunchTime.put(parts[0], 0L); } } } } Loading @@ -118,23 +160,26 @@ public class AppLaunch extends InstrumentationTestCase { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); startIntent.setClassName(ri.activityInfo.packageName, startIntent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name); ri.activityInfo.name); mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent); String appName = ri.loadLabel(pm).toString(); mNameToProcess.put(ri.loadLabel(pm).toString(), if (appName != null) { ri.activityInfo.processName); mNameToIntent.put(appName, startIntent); mNameToProcess.put(appName, ri.activityInfo.processName); } } } } } } } private void startApp(String appName, Bundle results) private long startApp(String appName, boolean forceStopBeforeLaunch) throws NameNotFoundException, RemoteException { throws NameNotFoundException, RemoteException { Log.i(TAG, "Starting " + appName); Log.i(TAG, "Starting " + appName); Intent startIntent = mNameToIntent.get(appName); Intent startIntent = mNameToIntent.get(appName); if (startIntent == null) { if (startIntent == null) { Log.w(TAG, "App does not exist: " + appName); Log.w(TAG, "App does not exist: " + appName); return; mResult.putString(mNameToResultKey.get(appName), "App does not exist"); return -1; } } AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent); AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch); Thread t = new Thread(runnable); Thread t = new Thread(runnable); t.start(); t.start(); try { try { Loading @@ -143,20 +188,30 @@ public class AppLaunch extends InstrumentationTestCase { // ignore // ignore } } WaitResult result = runnable.getResult(); WaitResult result = runnable.getResult(); if(t.isAlive() || (result != null && result.result != ActivityManager.START_SUCCESS)) { // report error if any of the following is true: // * launch thread is alive // * result is not null, but: // * result is not START_SUCESS // * or in case of no force stop, result is not TASK_TO_FRONT either if (t.isAlive() || (result != null && ((result.result != ActivityManager.START_SUCCESS) && (!forceStopBeforeLaunch && result.result != ActivityManager.START_TASK_TO_FRONT)))) { Log.w(TAG, "Assuming app " + appName + " crashed."); Log.w(TAG, "Assuming app " + appName + " crashed."); reportError(appName, mNameToProcess.get(appName), results); reportError(appName, mNameToProcess.get(appName)); return; return -1; } } results.putString(mNameToResultKey.get(appName), String.valueOf(result.thisTime)); return result.thisTime; } } private void closeApp(String appName) { private void closeApp(String appName, boolean forceStopApp) { Intent homeIntent = new Intent(Intent.ACTION_MAIN); Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory(Intent.CATEGORY_HOME); homeIntent.addCategory(Intent.CATEGORY_HOME); homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); getInstrumentation().getContext().startActivity(homeIntent); getInstrumentation().getContext().startActivity(homeIntent); sleep(POST_LAUNCH_IDLE_TIMEOUT); if (forceStopApp) { Intent startIntent = mNameToIntent.get(appName); Intent startIntent = mNameToIntent.get(appName); if (startIntent != null) { if (startIntent != null) { String packageName = startIntent.getComponent().getPackageName(); String packageName = startIntent.getComponent().getPackageName(); Loading @@ -167,6 +222,7 @@ public class AppLaunch extends InstrumentationTestCase { } } } } } } } private void sleep(int time) { private void sleep(int time) { try { try { Loading @@ -176,7 +232,7 @@ public class AppLaunch extends InstrumentationTestCase { } } } } private void reportError(String appName, String processName, Bundle results) { private void reportError(String appName, String processName) { ActivityManager am = (ActivityManager) getInstrumentation() ActivityManager am = (ActivityManager) getInstrumentation() .getContext().getSystemService(Context.ACTIVITY_SERVICE); .getContext().getSystemService(Context.ACTIVITY_SERVICE); List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState(); List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState(); Loading @@ -186,12 +242,12 @@ public class AppLaunch extends InstrumentationTestCase { continue; continue; Log.w(TAG, appName + " crashed: " + crash.shortMsg); Log.w(TAG, appName + " crashed: " + crash.shortMsg); results.putString(mNameToResultKey.get(appName), crash.shortMsg); mResult.putString(mNameToResultKey.get(appName), crash.shortMsg); return; return; } } } } results.putString(mNameToResultKey.get(appName), mResult.putString(mNameToResultKey.get(appName), "Crashed for unknown reason"); "Crashed for unknown reason"); Log.w(TAG, appName Log.w(TAG, appName + " not found in process list, most likely it is crashed"); + " not found in process list, most likely it is crashed"); Loading @@ -200,8 +256,11 @@ public class AppLaunch extends InstrumentationTestCase { private class AppLaunchRunnable implements Runnable { private class AppLaunchRunnable implements Runnable { private Intent mLaunchIntent; private Intent mLaunchIntent; private IActivityManager.WaitResult mResult; private IActivityManager.WaitResult mResult; public AppLaunchRunnable(Intent intent) { private boolean mForceStopBeforeLaunch; public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch) { mLaunchIntent = intent; mLaunchIntent = intent; mForceStopBeforeLaunch = forceStopBeforeLaunch; } } public IActivityManager.WaitResult getResult() { public IActivityManager.WaitResult getResult() { Loading @@ -211,7 +270,9 @@ public class AppLaunch extends InstrumentationTestCase { public void run() { public void run() { try { try { String packageName = mLaunchIntent.getComponent().getPackageName(); String packageName = mLaunchIntent.getComponent().getPackageName(); if (mForceStopBeforeLaunch) { mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT); mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT); } String mimeType = mLaunchIntent.getType(); String mimeType = mLaunchIntent.getType(); if (mimeType == null && mLaunchIntent.getData() != null if (mimeType == null && mLaunchIntent.getData() != null && "content".equals(mLaunchIntent.getData().getScheme())) { && "content".equals(mLaunchIntent.getData().getScheme())) { Loading Loading
tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +99 −38 Original line number Original line Diff line number Diff line /* /* * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License. Loading Loading @@ -32,6 +32,7 @@ import android.test.InstrumentationTestCase; import android.test.InstrumentationTestRunner; import android.test.InstrumentationTestRunner; import android.util.Log; import android.util.Log; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.List; import java.util.Map; import java.util.Map; Loading @@ -48,16 +49,22 @@ import java.util.Map; public class AppLaunch extends InstrumentationTestCase { public class AppLaunch extends InstrumentationTestCase { private static final int JOIN_TIMEOUT = 10000; private static final int JOIN_TIMEOUT = 10000; private static final String TAG = "AppLaunch"; private static final String TAG = AppLaunch.class.getSimpleName(); private static final String KEY_APPS = "apps"; private static final String KEY_APPS = "apps"; private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations"; private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.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 = 2000; //2s between launching apps private Map<String, Intent> mNameToIntent; private Map<String, Intent> mNameToIntent; private Map<String, String> mNameToProcess; private Map<String, String> mNameToProcess; private Map<String, String> mNameToResultKey; private Map<String, String> mNameToResultKey; private Map<String, Long> mNameToLaunchTime; private IActivityManager mAm; private IActivityManager mAm; private int mLaunchIterations = 10; private Bundle mResult = new Bundle(); public void testMeasureStartUpTime() throws RemoteException { public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException { InstrumentationTestRunner instrumentation = InstrumentationTestRunner instrumentation = (InstrumentationTestRunner)getInstrumentation(); (InstrumentationTestRunner)getInstrumentation(); Bundle args = instrumentation.getArguments(); Bundle args = instrumentation.getArguments(); Loading @@ -66,25 +73,59 @@ public class AppLaunch extends InstrumentationTestCase { createMappings(); createMappings(); parseArgs(args); parseArgs(args); Bundle results = new Bundle(); // do initial app launch, without force stopping for (String app : mNameToResultKey.keySet()) { for (String app : mNameToResultKey.keySet()) { try { long launchTime = startApp(app, false); startApp(app, results); if (launchTime <=0 ) { sleep(750); mNameToLaunchTime.put(app, -1L); closeApp(app); // simply pass the app if launch isn't successful sleep(2000); // error should have already been logged by startApp } catch (NameNotFoundException e) { continue; Log.i(TAG, "Application " + app + " not found"); } sleep(INITIAL_LAUNCH_IDLE_TIMEOUT); closeApp(app, false); sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } // do the real app launch now for (int i = 0; i < mLaunchIterations; i++) { for (String app : mNameToResultKey.keySet()) { long totalLaunchTime = mNameToLaunchTime.get(app); long launchTime = 0; if (totalLaunchTime < 0) { // skip if the app has previous failures continue; } launchTime = startApp(app, true); if (launchTime <= 0) { // if it fails once, skip the rest of the launches mNameToLaunchTime.put(app, -1L); continue; } totalLaunchTime += launchTime; mNameToLaunchTime.put(app, totalLaunchTime); sleep(POST_LAUNCH_IDLE_TIMEOUT); closeApp(app, true); sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } } } } instrumentation.sendStatus(0, results); for (String app : mNameToResultKey.keySet()) { long totalLaunchTime = mNameToLaunchTime.get(app); if (totalLaunchTime != -1) { mResult.putDouble(mNameToResultKey.get(app), ((double) totalLaunchTime) / mLaunchIterations); } } instrumentation.sendStatus(0, mResult); } } private void parseArgs(Bundle args) { private void parseArgs(Bundle args) { mNameToResultKey = new LinkedHashMap<String, String>(); mNameToResultKey = new LinkedHashMap<String, String>(); mNameToLaunchTime = new HashMap<String, Long>(); String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS); if (launchIterations != null) { mLaunchIterations = Integer.parseInt(launchIterations); } String appList = args.getString(KEY_APPS); String appList = args.getString(KEY_APPS); if (appList == null) if (appList == null) return; return; Loading @@ -97,6 +138,7 @@ public class AppLaunch extends InstrumentationTestCase { } } mNameToResultKey.put(parts[0], parts[1]); mNameToResultKey.put(parts[0], parts[1]); mNameToLaunchTime.put(parts[0], 0L); } } } } Loading @@ -118,23 +160,26 @@ public class AppLaunch extends InstrumentationTestCase { | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); startIntent.setClassName(ri.activityInfo.packageName, startIntent.setClassName(ri.activityInfo.packageName, ri.activityInfo.name); ri.activityInfo.name); mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent); String appName = ri.loadLabel(pm).toString(); mNameToProcess.put(ri.loadLabel(pm).toString(), if (appName != null) { ri.activityInfo.processName); mNameToIntent.put(appName, startIntent); mNameToProcess.put(appName, ri.activityInfo.processName); } } } } } } } private void startApp(String appName, Bundle results) private long startApp(String appName, boolean forceStopBeforeLaunch) throws NameNotFoundException, RemoteException { throws NameNotFoundException, RemoteException { Log.i(TAG, "Starting " + appName); Log.i(TAG, "Starting " + appName); Intent startIntent = mNameToIntent.get(appName); Intent startIntent = mNameToIntent.get(appName); if (startIntent == null) { if (startIntent == null) { Log.w(TAG, "App does not exist: " + appName); Log.w(TAG, "App does not exist: " + appName); return; mResult.putString(mNameToResultKey.get(appName), "App does not exist"); return -1; } } AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent); AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch); Thread t = new Thread(runnable); Thread t = new Thread(runnable); t.start(); t.start(); try { try { Loading @@ -143,20 +188,30 @@ public class AppLaunch extends InstrumentationTestCase { // ignore // ignore } } WaitResult result = runnable.getResult(); WaitResult result = runnable.getResult(); if(t.isAlive() || (result != null && result.result != ActivityManager.START_SUCCESS)) { // report error if any of the following is true: // * launch thread is alive // * result is not null, but: // * result is not START_SUCESS // * or in case of no force stop, result is not TASK_TO_FRONT either if (t.isAlive() || (result != null && ((result.result != ActivityManager.START_SUCCESS) && (!forceStopBeforeLaunch && result.result != ActivityManager.START_TASK_TO_FRONT)))) { Log.w(TAG, "Assuming app " + appName + " crashed."); Log.w(TAG, "Assuming app " + appName + " crashed."); reportError(appName, mNameToProcess.get(appName), results); reportError(appName, mNameToProcess.get(appName)); return; return -1; } } results.putString(mNameToResultKey.get(appName), String.valueOf(result.thisTime)); return result.thisTime; } } private void closeApp(String appName) { private void closeApp(String appName, boolean forceStopApp) { Intent homeIntent = new Intent(Intent.ACTION_MAIN); Intent homeIntent = new Intent(Intent.ACTION_MAIN); homeIntent.addCategory(Intent.CATEGORY_HOME); homeIntent.addCategory(Intent.CATEGORY_HOME); homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); getInstrumentation().getContext().startActivity(homeIntent); getInstrumentation().getContext().startActivity(homeIntent); sleep(POST_LAUNCH_IDLE_TIMEOUT); if (forceStopApp) { Intent startIntent = mNameToIntent.get(appName); Intent startIntent = mNameToIntent.get(appName); if (startIntent != null) { if (startIntent != null) { String packageName = startIntent.getComponent().getPackageName(); String packageName = startIntent.getComponent().getPackageName(); Loading @@ -167,6 +222,7 @@ public class AppLaunch extends InstrumentationTestCase { } } } } } } } private void sleep(int time) { private void sleep(int time) { try { try { Loading @@ -176,7 +232,7 @@ public class AppLaunch extends InstrumentationTestCase { } } } } private void reportError(String appName, String processName, Bundle results) { private void reportError(String appName, String processName) { ActivityManager am = (ActivityManager) getInstrumentation() ActivityManager am = (ActivityManager) getInstrumentation() .getContext().getSystemService(Context.ACTIVITY_SERVICE); .getContext().getSystemService(Context.ACTIVITY_SERVICE); List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState(); List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState(); Loading @@ -186,12 +242,12 @@ public class AppLaunch extends InstrumentationTestCase { continue; continue; Log.w(TAG, appName + " crashed: " + crash.shortMsg); Log.w(TAG, appName + " crashed: " + crash.shortMsg); results.putString(mNameToResultKey.get(appName), crash.shortMsg); mResult.putString(mNameToResultKey.get(appName), crash.shortMsg); return; return; } } } } results.putString(mNameToResultKey.get(appName), mResult.putString(mNameToResultKey.get(appName), "Crashed for unknown reason"); "Crashed for unknown reason"); Log.w(TAG, appName Log.w(TAG, appName + " not found in process list, most likely it is crashed"); + " not found in process list, most likely it is crashed"); Loading @@ -200,8 +256,11 @@ public class AppLaunch extends InstrumentationTestCase { private class AppLaunchRunnable implements Runnable { private class AppLaunchRunnable implements Runnable { private Intent mLaunchIntent; private Intent mLaunchIntent; private IActivityManager.WaitResult mResult; private IActivityManager.WaitResult mResult; public AppLaunchRunnable(Intent intent) { private boolean mForceStopBeforeLaunch; public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch) { mLaunchIntent = intent; mLaunchIntent = intent; mForceStopBeforeLaunch = forceStopBeforeLaunch; } } public IActivityManager.WaitResult getResult() { public IActivityManager.WaitResult getResult() { Loading @@ -211,7 +270,9 @@ public class AppLaunch extends InstrumentationTestCase { public void run() { public void run() { try { try { String packageName = mLaunchIntent.getComponent().getPackageName(); String packageName = mLaunchIntent.getComponent().getPackageName(); if (mForceStopBeforeLaunch) { mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT); mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT); } String mimeType = mLaunchIntent.getType(); String mimeType = mLaunchIntent.getType(); if (mimeType == null && mLaunchIntent.getData() != null if (mimeType == null && mLaunchIntent.getData() != null && "content".equals(mLaunchIntent.getData().getScheme())) { && "content".equals(mLaunchIntent.getData().getScheme())) { Loading