diff options
author | Maxim Siniavine <siniavine@google.com> | 2012-10-02 15:56:03 -0700 |
---|---|---|
committer | Maxim Siniavine <siniavine@google.com> | 2012-11-20 18:01:55 -0800 |
commit | f58e5b6cdcecee6184784b3a6ac33f60341de170 (patch) | |
tree | 1559e7a690c4dabcff9a456affa6ee0a23a3400b /tests | |
parent | 89ac38bf70bb21e34c8c29b96e6316343ee46e87 (diff) | |
download | frameworks_base-f58e5b6cdcecee6184784b3a6ac33f60341de170.zip frameworks_base-f58e5b6cdcecee6184784b3a6ac33f60341de170.tar.gz frameworks_base-f58e5b6cdcecee6184784b3a6ac33f60341de170.tar.bz2 |
Added app launch test.
The test will start each app and report the time it takes for
the app to start in milliseconds.
Change-Id: I974ac36f70f0d982aa01e46824fe138eb641d680
Diffstat (limited to 'tests')
-rw-r--r-- | tests/AppLaunch/Android.mk | 17 | ||||
-rw-r--r-- | tests/AppLaunch/AndroidManifest.xml | 13 | ||||
-rw-r--r-- | tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java | 216 |
3 files changed, 246 insertions, 0 deletions
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk new file mode 100644 index 0000000..c0560fd --- /dev/null +++ b/tests/AppLaunch/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +# Only compile source java files in this apk. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := AppLaunch + +LOCAL_CERTIFICATE := platform +LOCAL_JAVA_LIBRARIES := android.test.runner + +include $(BUILD_PACKAGE) + +# Use the following include to make our test apk. +include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file diff --git a/tests/AppLaunch/AndroidManifest.xml b/tests/AppLaunch/AndroidManifest.xml new file mode 100644 index 0000000..ac6760b --- /dev/null +++ b/tests/AppLaunch/AndroidManifest.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.tests.applaunch" + android:sharedUserId="android.uid.system" > + <instrumentation android:label="Measure app start up time" + android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.tests.applaunch" /> + + <application android:label="App Launch Test"> + <uses-library android:name="android.test.runner" /> + </application> +</manifest>
\ No newline at end of file diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java new file mode 100644 index 0000000..e9374e0 --- /dev/null +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tests.applaunch; + +import android.app.ActivityManager; +import android.app.ActivityManager.ProcessErrorStateInfo; +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.UserHandle; +import android.test.InstrumentationTestCase; +import android.test.InstrumentationTestRunner; +import android.util.Log; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 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 <app name>^<result key>|<app name>^<result key> + */ +public class AppLaunch extends InstrumentationTestCase { + + private static final int JOIN_TIMEOUT = 10000; + private static final String TAG = "AppLaunch"; + private static final String KEY_APPS = "apps"; + + private Map<String, Intent> mNameToIntent; + private Map<String, String> mNameToProcess; + private Map<String, String> mNameToResultKey; + + private IActivityManager mAm; + + public void testMeasureStartUpTime() throws RemoteException { + InstrumentationTestRunner instrumentation = + (InstrumentationTestRunner)getInstrumentation(); + Bundle args = instrumentation.getBundle(); + mAm = ActivityManagerNative.getDefault(); + + createMappings(); + parseArgs(args); + + Bundle results = new Bundle(); + for (String app : mNameToResultKey.keySet()) { + try { + startApp(app, results); + closeApp(); + } catch (NameNotFoundException e) { + Log.i(TAG, "Application " + app + " not found"); + } + + } + instrumentation.sendStatus(0, results); + } + + private void parseArgs(Bundle args) { + mNameToResultKey = new HashMap<String, String>(); + 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]); + } + } + + private void createMappings() { + mNameToIntent = new HashMap<String, Intent>(); + mNameToProcess = new HashMap<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); + mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent); + mNameToProcess.put(ri.loadLabel(pm).toString(), + ri.activityInfo.processName); + } + } + } + + private void startApp(String appName, Bundle results) + throws NameNotFoundException, RemoteException { + Log.i(TAG, "Starting " + appName); + + Intent startIntent = mNameToIntent.get(appName); + AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent); + Thread t = new Thread(runnable); + long startTime = System.currentTimeMillis(); + t.start(); + try { + t.join(JOIN_TIMEOUT); + } catch (InterruptedException e) { + // ignore + } + if(t.isAlive() || (runnable.getResult() != null && + runnable.getResult().result != ActivityManager.START_SUCCESS)) { + Log.w(TAG, "Assuming app " + appName + " crashed."); + reportError(appName, mNameToProcess.get(appName), results); + return; + } + long startUpTime = System.currentTimeMillis() - startTime; + results.putString(mNameToResultKey.get(appName), String.valueOf(startUpTime)); + sleep(5000); + } + + private void closeApp() { + 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(3000); + } + + private void sleep(int time) { + try { + Thread.sleep(time); + } catch (InterruptedException e) { + // ignore + } + } + + private void reportError(String appName, String processName, Bundle results) { + 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); + results.putString(mNameToResultKey.get(appName), crash.shortMsg); + return; + } + } + + results.putString(mNameToResultKey.get(appName), + "Crashed for unknown reason"); + Log.w(TAG, appName + + " not found in process list, most likely it is crashed"); + } + + private class AppLaunchRunnable implements Runnable { + private Intent mLaunchIntent; + private IActivityManager.WaitResult mResult; + public AppLaunchRunnable(Intent intent) { + mLaunchIntent = intent; + } + + public IActivityManager.WaitResult getResult() { + return mResult; + } + + public void run() { + try { + String mimeType = mLaunchIntent.getType(); + if (mimeType == null && mLaunchIntent.getData() != null + && "content".equals(mLaunchIntent.getData().getScheme())) { + mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(), + UserHandle.USER_CURRENT); + } + + mResult = mAm.startActivityAndWait(null, mLaunchIntent, mimeType, + null, null, 0, mLaunchIntent.getFlags(), null, null, null, + UserHandle.USER_CURRENT); + } catch (RemoteException e) { + Log.w(TAG, "Error launching app", e); + } + } + } +} |