AppLaunchpublic class AppLaunch extends android.test.InstrumentationTestCase This test is intended to measure the time it takes for the apps to start.
Names of the applications are passed in command line, and the
test starts each application, and reports the start up time in milliseconds.
The instrumentation expects the following key to be passed on the command line:
apps - A list of applications to start and their corresponding result keys
in the following format:
-e apps ^|^ |
Fields Summary |
---|
private static final int | JOIN_TIMEOUT | private static final String | TAG | private static final String | KEY_APPS | private static final String | KEY_LAUNCH_ITERATIONS | private static final String | KEY_REQUIRED_ACCOUNTS | private static final int | INITIAL_LAUNCH_IDLE_TIMEOUT | private static final int | POST_LAUNCH_IDLE_TIMEOUT | private static final int | BETWEEN_LAUNCH_SLEEP_TIMEOUT | private Map | mNameToIntent | private Map | mNameToProcess | private Map | mNameToResultKey | private Map | mNameToLaunchTime | private android.app.IActivityManager | mAm | private int | mLaunchIterations | private android.os.Bundle | mResult | private Set | mRequiredAccounts |
Methods Summary |
---|
private void | checkAccountSignIn()
// ensure that the device has the required account types before starting test
// e.g. device must have a valid Google account sign in to measure a meaningful launch time
// for Gmail
if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
return;
}
final AccountManager am =
(AccountManager) getInstrumentation().getTargetContext().getSystemService(
Context.ACCOUNT_SERVICE);
Account[] accounts = am.getAccounts();
// use set here in case device has multiple accounts of the same type
Set<String> foundAccounts = new HashSet<String>();
for (Account account : accounts) {
if (mRequiredAccounts.contains(account.type)) {
foundAccounts.add(account.type);
}
}
// check if account type matches, if not, fail test with message on what account types
// are missing
if (mRequiredAccounts.size() != foundAccounts.size()) {
mRequiredAccounts.removeAll(foundAccounts);
StringBuilder sb = new StringBuilder("Device missing these accounts:");
for (String account : mRequiredAccounts) {
sb.append(' ");
sb.append(account);
}
fail(sb.toString());
}
| private void | closeApp(java.lang.String appName, boolean forceStopApp)
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
getInstrumentation().getContext().startActivity(homeIntent);
sleep(POST_LAUNCH_IDLE_TIMEOUT);
if (forceStopApp) {
Intent startIntent = mNameToIntent.get(appName);
if (startIntent != null) {
String packageName = startIntent.getComponent().getPackageName();
try {
mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
} catch (RemoteException e) {
Log.w(TAG, "Error closing app", e);
}
}
}
| private void | createMappings()
mNameToIntent = new LinkedHashMap<String, Intent>();
mNameToProcess = new LinkedHashMap<String, String>();
PackageManager pm = getInstrumentation().getContext()
.getPackageManager();
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
if (ris == null || ris.isEmpty()) {
Log.i(TAG, "Could not find any apps");
} else {
for (ResolveInfo ri : ris) {
Intent startIntent = new Intent(intentToResolve);
startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startIntent.setClassName(ri.activityInfo.packageName,
ri.activityInfo.name);
String appName = ri.loadLabel(pm).toString();
if (appName != null) {
mNameToIntent.put(appName, startIntent);
mNameToProcess.put(appName, ri.activityInfo.processName);
}
}
}
| private void | parseArgs(android.os.Bundle args)
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);
if (appList == null)
return;
String appNames[] = appList.split("\\|");
for (String pair : appNames) {
String[] parts = pair.split("\\^");
if (parts.length != 2) {
Log.e(TAG, "The apps key is incorectly formatted");
fail();
}
mNameToResultKey.put(parts[0], parts[1]);
mNameToLaunchTime.put(parts[0], 0L);
}
String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
if (requiredAccounts != null) {
mRequiredAccounts = new HashSet<String>();
for (String accountType : requiredAccounts.split(",")) {
mRequiredAccounts.add(accountType);
}
}
| private void | reportError(java.lang.String appName, java.lang.String processName)
ActivityManager am = (ActivityManager) getInstrumentation()
.getContext().getSystemService(Context.ACTIVITY_SERVICE);
List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
if (crashes != null) {
for (ProcessErrorStateInfo crash : crashes) {
if (!crash.processName.equals(processName))
continue;
Log.w(TAG, appName + " crashed: " + crash.shortMsg);
mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
return;
}
}
mResult.putString(mNameToResultKey.get(appName),
"Crashed for unknown reason");
Log.w(TAG, appName
+ " not found in process list, most likely it is crashed");
| protected void | setUp()
super.setUp();
getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
| private void | sleep(int time)
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// ignore
}
| private long | startApp(java.lang.String appName, boolean forceStopBeforeLaunch)
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 -1;
}
AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch);
Thread t = new Thread(runnable);
t.start();
try {
t.join(JOIN_TIMEOUT);
} catch (InterruptedException e) {
// ignore
}
WaitResult result = runnable.getResult();
// 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.");
reportError(appName, mNameToProcess.get(appName));
return -1;
}
return result.thisTime;
| protected void | tearDown()
getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
super.tearDown();
| public void | testMeasureStartUpTime()
InstrumentationTestRunner instrumentation =
(InstrumentationTestRunner)getInstrumentation();
Bundle args = instrumentation.getArguments();
mAm = ActivityManagerNative.getDefault();
createMappings();
parseArgs(args);
checkAccountSignIn();
// do initial app launch, without force stopping
for (String app : mNameToResultKey.keySet()) {
long launchTime = startApp(app, false);
if (launchTime <= 0) {
mNameToLaunchTime.put(app, -1L);
// simply pass the app if launch isn't successful
// error should have already been logged by startApp
continue;
} else {
mNameToLaunchTime.put(app, launchTime);
}
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 prevLaunchTime = mNameToLaunchTime.get(app);
long launchTime = 0;
if (prevLaunchTime < 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;
}
// keep the min launch time
if (launchTime < prevLaunchTime) {
mNameToLaunchTime.put(app, launchTime);
}
sleep(POST_LAUNCH_IDLE_TIMEOUT);
closeApp(app, true);
sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
}
}
for (String app : mNameToResultKey.keySet()) {
long launchTime = mNameToLaunchTime.get(app);
if (launchTime != -1) {
mResult.putLong(mNameToResultKey.get(app), launchTime);
}
}
instrumentation.sendStatus(0, mResult);
|
|