19229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine/*
29229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * Copyright (C) 2012 The Android Open Source Project
39229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine *
49229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * Licensed under the Apache License, Version 2.0 (the "License");
59229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * you may not use this file except in compliance with the License.
69229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * You may obtain a copy of the License at
79229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine *
89229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine *      http://www.apache.org/licenses/LICENSE-2.0
99229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine *
109229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * Unless required by applicable law or agreed to in writing, software
119229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * distributed under the License is distributed on an "AS IS" BASIS,
129229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * See the License for the specific language governing permissions and
149229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * limitations under the License.
159229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine */
169229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavinepackage com.android.tests.memoryusage;
179229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
189229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.app.ActivityManager;
199229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.app.ActivityManager.ProcessErrorStateInfo;
209229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.app.ActivityManager.RunningAppProcessInfo;
21d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavineimport android.app.ActivityManagerNative;
22d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavineimport android.app.IActivityManager;
23e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhuimport android.app.UiAutomation;
249229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.content.Context;
259229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.content.Intent;
269229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.content.pm.PackageManager;
279229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.content.pm.PackageManager.NameNotFoundException;
289229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.content.pm.ResolveInfo;
299229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.os.Bundle;
309229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.os.Debug.MemoryInfo;
31d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavineimport android.os.RemoteException;
32d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavineimport android.os.UserHandle;
339229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.test.InstrumentationTestCase;
349229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport android.util.Log;
359229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
369229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport java.util.ArrayList;
379229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport java.util.HashMap;
386c77e104bcb265d29f357b7fb5737153c048bcdbwsmlbyimport java.util.HashSet;
399229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport java.util.List;
409229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavineimport java.util.Map;
416c77e104bcb265d29f357b7fb5737153c048bcdbwsmlbyimport java.util.Set;
429229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
439229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine/**
449229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * This test is intended to measure the amount of memory applications use when
459229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * they start. Names of the applications are passed in command line, and the
469229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * test starts each application, waits until its memory usage is stabilized and
479229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * reports the total PSS in kilobytes of each processes.
489229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * The instrumentation expects the following key to be passed on the command line:
499229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * apps - A list of applications to start and their corresponding result keys
509229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * in the following format:
519229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine * -e apps <app name>^<result key>|<app name>^<result key>
529229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine */
539229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavinepublic class MemoryUsageTest extends InstrumentationTestCase {
549229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
559229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private static final int SLEEP_TIME = 1000;
569229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private static final int THRESHOLD = 1024;
57d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    private static final int MAX_ITERATIONS = 20;
58d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    private static final int MIN_ITERATIONS = 6;
59d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    private static final int JOIN_TIMEOUT = 10000;
609229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
619229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private static final String TAG = "MemoryUsageInstrumentation";
629229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private static final String KEY_APPS = "apps";
636c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private static final String KEY_PROCS = "persistent";
646c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private static final String LAUNCHER_KEY = "launcher";
652effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine    private Map<String, Intent> mNameToIntent;
662effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine    private Map<String, String> mNameToProcess;
672effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine    private Map<String, String> mNameToResultKey;
686c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private Set<String> mPersistentProcesses;
69d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    private IActivityManager mAm;
70d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
71e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
72e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void setUp() throws Exception {
73e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.setUp();
74e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
75e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
76e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
77e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
78e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void tearDown() throws Exception {
79e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
80e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.tearDown();
81e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
82e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
839229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    public void testMemory() {
849229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        MemoryUsageInstrumentation instrumentation =
85d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                (MemoryUsageInstrumentation) getInstrumentation();
869229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Bundle args = instrumentation.getBundle();
87d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        mAm = ActivityManagerNative.getDefault();
889229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
899229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        createMappings();
909229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        parseArgs(args);
919229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
929229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Bundle results = new Bundle();
932effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        for (String app : mNameToResultKey.keySet()) {
946c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            if (!mPersistentProcesses.contains(app)) {
956c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                String processName;
966c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                try {
976c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                    processName = startApp(app);
986c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                    measureMemory(app, processName, results);
996c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                    closeApp();
1006c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                } catch (NameNotFoundException e) {
1016c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                    Log.i(TAG, "Application " + app + " not found");
1026c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                }
1036c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            } else {
1046c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby                measureMemory(app, app, results);
1059229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
1069229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
1079229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        instrumentation.sendStatus(0, results);
1089229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
1099229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1106c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private String getLauncherPackageName() {
1116c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby      Intent intent = new Intent(Intent.ACTION_MAIN);
1126c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby      intent.addCategory(Intent.CATEGORY_HOME);
1136c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby      ResolveInfo resolveInfo = getInstrumentation().getContext().
1146c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby          getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
1156c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby      return resolveInfo.activityInfo.packageName;
1166c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    }
1179229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1186c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private Map<String, String> parseListToMap(String list) {
1196c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        Map<String, String> map = new HashMap<String, String>();
1206c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        String names[] = list.split("\\|");
1216c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        for (String pair : names) {
1229229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            String[] parts = pair.split("\\^");
1239229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            if (parts.length != 2) {
1249229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                Log.e(TAG, "The apps key is incorectly formatted");
1259229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                fail();
1269229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
1276c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            map.put(parts[0], parts[1]);
1286c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        }
1296c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        return map;
1306c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    }
1319229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1326c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby    private void parseArgs(Bundle args) {
1336c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        mNameToResultKey = new HashMap<String, String>();
1346c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        mPersistentProcesses = new HashSet<String>();
1356c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        String appList = args.getString(KEY_APPS);
1366c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        String procList = args.getString(KEY_PROCS);
1376c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        String mLauncherPackageName = getLauncherPackageName();
1386c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        mPersistentProcesses.add(mLauncherPackageName);
1396c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        mNameToResultKey.put(mLauncherPackageName, LAUNCHER_KEY);
1406c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        if (appList == null && procList == null)
1416c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            return;
1426c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        if (appList != null) {
1436c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            mNameToResultKey.putAll(parseListToMap(appList));
1446c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        }
1456c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby        if (procList != null) {
1466c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            Map<String, String> procMap = parseListToMap(procList);
1476c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            mPersistentProcesses.addAll(procMap.keySet());
1486c77e104bcb265d29f357b7fb5737153c048bcdbwsmlby            mNameToResultKey.putAll(procMap);
1499229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
1509229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
1519229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1529229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private void createMappings() {
1532effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        mNameToIntent = new HashMap<String, Intent>();
1542effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        mNameToProcess = new HashMap<String, String>();
1559229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1569229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        PackageManager pm = getInstrumentation().getContext()
1579229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                .getPackageManager();
1589229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
1599229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
1609229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
1619229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        if (ris == null || ris.isEmpty()) {
1629229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            Log.i(TAG, "Could not find any apps");
1639229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        } else {
1649229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            for (ResolveInfo ri : ris) {
1659229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                Log.i(TAG, "Name: " + ri.loadLabel(pm).toString()
1669229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                        + " package: " + ri.activityInfo.packageName
1679229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                        + " name: " + ri.activityInfo.name);
1689229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                Intent startIntent = new Intent(intentToResolve);
1699229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1709229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
1719229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                startIntent.setClassName(ri.activityInfo.packageName,
1729229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                        ri.activityInfo.name);
1732effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine                mNameToIntent.put(ri.loadLabel(pm).toString(), startIntent);
1742effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine                mNameToProcess.put(ri.loadLabel(pm).toString(),
1759229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                        ri.activityInfo.processName);
1769229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
1779229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
1789229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
1799229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1809229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private String startApp(String appName) throws NameNotFoundException {
1819229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Log.i(TAG, "Starting " + appName);
1829229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1832effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        if (!mNameToProcess.containsKey(appName))
1849229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            throw new NameNotFoundException("Could not find: " + appName);
1859229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
1862effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        String process = mNameToProcess.get(appName);
1872effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        Intent startIntent = mNameToIntent.get(appName);
188d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
189d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent);
190d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        Thread t = new Thread(runnable);
191d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        t.start();
192d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        try {
193d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            t.join(JOIN_TIMEOUT);
194d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        } catch (InterruptedException e) {
195d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            // ignore
196d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        }
197d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
1989229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        return process;
1999229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2009229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
201a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine    private void closeApp() {
202a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
203a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine        homeIntent.addCategory(Intent.CATEGORY_HOME);
204a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
205a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
206a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine        getInstrumentation().getContext().startActivity(homeIntent);
207a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine        sleep(3000);
208a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine    }
209a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine
2109229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private void measureMemory(String appName, String processName,
2119229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            Bundle results) {
2129229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        List<Integer> pssData = new ArrayList<Integer>();
2139229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        int pss = 0;
2149229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        int iteration = 0;
2159229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        while (iteration < MAX_ITERATIONS) {
216a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine            sleep(SLEEP_TIME);
2179229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            pss = getPss(processName);
2189229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            Log.i(TAG, appName + "=" + pss);
2199229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            if (pss < 0) {
2209229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                reportError(appName, processName, results);
2219229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                return;
2229229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
2239229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            pssData.add(pss);
2249229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            if (iteration >= MIN_ITERATIONS && stabilized(pssData)) {
2252effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine                results.putInt(mNameToResultKey.get(appName), pss);
2269229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                return;
2279229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
2289229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            iteration++;
2299229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
2309229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2319229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Log.w(TAG, appName + " memory usage did not stabilize");
2322effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        results.putInt(mNameToResultKey.get(appName), average(pssData));
2339229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2349229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2359229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private int average(List<Integer> pssData) {
2369229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        int sum = 0;
2379229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        for (int sample : pssData) {
2389229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            sum += sample;
2399229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
2409229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2419229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        return sum / pssData.size();
2429229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2439229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2449229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private boolean stabilized(List<Integer> pssData) {
2459229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        if (pssData.size() < 3)
2469229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            return false;
2479229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        int diff1 = Math.abs(pssData.get(pssData.size() - 1) - pssData.get(pssData.size() - 2));
2489229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        int diff2 = Math.abs(pssData.get(pssData.size() - 2) - pssData.get(pssData.size() - 3));
2499229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2509229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Log.i(TAG, "diff1=" + diff1 + " diff2=" + diff2);
2519229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2529229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        return (diff1 + diff2) < THRESHOLD;
2539229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2549229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
255a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine    private void sleep(int time) {
2569229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        try {
257a9d9decf87a040087a9bda4340d53c21cd3e672aMaxim Siniavine            Thread.sleep(time);
2589229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        } catch (InterruptedException e) {
2599229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            // ignore
2609229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
2619229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2629229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2639229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private void reportError(String appName, String processName, Bundle results) {
2649229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        ActivityManager am = (ActivityManager) getInstrumentation()
2659229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
2669229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
2679229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        if (crashes != null) {
2689229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            for (ProcessErrorStateInfo crash : crashes) {
2699229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                if (!crash.processName.equals(processName))
2709229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                    continue;
2719229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2729229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
2732effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine                results.putString(mNameToResultKey.get(appName), crash.shortMsg);
2749229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                return;
2759229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
2769229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
2779229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2782effa64ab7192d9c41cbbe1fd57d61d6d6f94ba8Maxim Siniavine        results.putString(mNameToResultKey.get(appName),
2799229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                "Crashed for unknown reason");
2809229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        Log.w(TAG, appName
2819229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                + " not found in process list, most likely it is crashed");
2829229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
2839229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2849229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    private int getPss(String processName) {
2859229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        ActivityManager am = (ActivityManager) getInstrumentation()
2869229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
2879229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        List<RunningAppProcessInfo> apps = am.getRunningAppProcesses();
2889229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2899229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        for (RunningAppProcessInfo proc : apps) {
2909229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            if (!proc.processName.equals(processName)) {
2919229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine                continue;
2929229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            }
2939229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2949229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            int[] pids = {
295d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                    proc.pid };
2969229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
2979229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            MemoryInfo meminfo = am.getProcessMemoryInfo(pids)[0];
2989229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine            return meminfo.getTotalPss();
2999229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine
3009229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        }
3019229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine        return -1;
3029229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine    }
303d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
304d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    private class AppLaunchRunnable implements Runnable {
305d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        private Intent mLaunchIntent;
306d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
307d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        public AppLaunchRunnable(Intent intent) {
308d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            mLaunchIntent = intent;
309d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        }
310d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
311d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        public void run() {
312d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            try {
313d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                String mimeType = mLaunchIntent.getType();
314d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                if (mimeType == null && mLaunchIntent.getData() != null
315d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                        && "content".equals(mLaunchIntent.getData().getScheme())) {
316d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                    mimeType = mAm.getProviderMimeType(mLaunchIntent.getData(),
317d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                            UserHandle.USER_CURRENT);
318d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                }
319d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine
320f265ea9d8307282ff1da3915978625a94fc2859eDianne Hackborn                mAm.startActivityAndWait(null, null, mLaunchIntent, mimeType,
3211b012d302b56b4adf950035136d1d191a1936d5aJeff Hao                        null, null, 0, mLaunchIntent.getFlags(), null, null,
322d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                        UserHandle.USER_CURRENT_OR_SELF);
323d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            } catch (RemoteException e) {
324d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine                Log.w(TAG, "Error launching app", e);
325d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine            }
326d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine        }
327d85b8d57a0ce0514a1c9ea8f763b95aa94711645Maxim Siniavine    }
3289229700728ec4b7bca28da5325b48a4acb4bfc0dMaxim Siniavine}
329