1f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine/*
232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu * Copyright (C) 2013 The Android Open Source Project
3f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
4f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Licensed under the Apache License, Version 2.0 (the "License");
5f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * you may not use this file except in compliance with the License.
6f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * You may obtain a copy of the License at
7f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
8f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *      http://www.apache.org/licenses/LICENSE-2.0
9f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine *
10f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Unless required by applicable law or agreed to in writing, software
11f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * distributed under the License is distributed on an "AS IS" BASIS,
12f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * See the License for the specific language governing permissions and
14f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * limitations under the License.
15f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine */
16f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavinepackage com.android.tests.applaunch;
17f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
18164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.OutputStreamWriter;
19164cca0b341051b659b7276381756012e23427eeGopinath
206266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport android.accounts.Account;
216266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport android.accounts.AccountManager;
22164cca0b341051b659b7276381756012e23427eeGopinathimport android.app.ActivityManagerNative;
23f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.ActivityManager;
24f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.app.ActivityManager.ProcessErrorStateInfo;
25f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.Context;
26f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.Intent;
27f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.PackageManager;
28f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.PackageManager.NameNotFoundException;
29f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.content.pm.ResolveInfo;
30f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.Bundle;
31f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.RemoteException;
32f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.os.UserHandle;
33164cca0b341051b659b7276381756012e23427eeGopinathimport android.app.UiAutomation;
34164cca0b341051b659b7276381756012e23427eeGopinathimport android.app.IActivityManager;
35164cca0b341051b659b7276381756012e23427eeGopinathimport android.app.IActivityManager.WaitResult;
36164cca0b341051b659b7276381756012e23427eeGopinathimport android.support.test.rule.logging.AtraceLogger;
37f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.test.InstrumentationTestCase;
38f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.test.InstrumentationTestRunner;
39f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport android.util.Log;
40164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.File;
41164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.IOException;
4232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhuimport java.util.HashMap;
436266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport java.util.HashSet;
44c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhuimport java.util.LinkedHashMap;
45f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport java.util.List;
46164cca0b341051b659b7276381756012e23427eeGopinathimport java.util.ArrayList;
47f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavineimport java.util.Map;
486266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhuimport java.util.Set;
49164cca0b341051b659b7276381756012e23427eeGopinathimport android.os.ParcelFileDescriptor;
50164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.FileInputStream;
51164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.FileOutputStream;
52164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.InputStream;
53164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.BufferedReader;
54164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.BufferedWriter;
55164cca0b341051b659b7276381756012e23427eeGopinathimport java.io.InputStreamReader;
56f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
57f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine/**
58f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * This test is intended to measure the time it takes for the apps to start.
59f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * Names of the applications are passed in command line, and the
60f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * test starts each application, and reports the start up time in milliseconds.
61f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * The instrumentation expects the following key to be passed on the command line:
62f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * apps - A list of applications to start and their corresponding result keys
63f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * in the following format:
64f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine * -e apps <app name>^<result key>|<app name>^<result key>
65f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine */
66f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavinepublic class AppLaunch extends InstrumentationTestCase {
67f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
68f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private static final int JOIN_TIMEOUT = 10000;
6932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final String TAG = AppLaunch.class.getSimpleName();
706266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    // optional parameter: comma separated list of required account types before proceeding
716266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    // with the app launch
726266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
73164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_APPS = "apps";
74164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRIAL_LAUNCH = "trial_launch";
75164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
76164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_LAUNCH_ORDER = "launch_order";
77164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_DROP_CACHE = "drop_cache";
78164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_SIMPLEPPERF_CMD = "simpleperf_cmd";
79164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
80164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
81164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRACE_DIRECTORY = "trace_directory";
82164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRACE_CATEGORY = "trace_categories";
83164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
84164cca0b341051b659b7276381756012e23427eeGopinath    private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
85349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    private static final String WEARABLE_ACTION_GOOGLE =
86349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz            "com.google.android.wearable.action.GOOGLE";
875aa567a8697ffbb1629816cceda36e3aec041c43Gopinath    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 60000; //60s to allow app to idle
8832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches
89164cca0b341051b659b7276381756012e23427eeGopinath    private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps
90164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
91164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_FILE = "applaunch.txt";
92164cca0b341051b659b7276381756012e23427eeGopinath    private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
93164cca0b341051b659b7276381756012e23427eeGopinath    private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview,"
94164cca0b341051b659b7276381756012e23427eeGopinath            + "input,wm,disk,am,wm";
95164cca0b341051b659b7276381756012e23427eeGopinath    private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
96164cca0b341051b659b7276381756012e23427eeGopinath    private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
97164cca0b341051b659b7276381756012e23427eeGopinath    private static final String TRIAL_LAUNCH = "TRAIL_LAUNCH";
98164cca0b341051b659b7276381756012e23427eeGopinath    private static final String DELIMITER = ",";
99164cca0b341051b659b7276381756012e23427eeGopinath    private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
100164cca0b341051b659b7276381756012e23427eeGopinath    private static final String APP_LAUNCH_CMD = "am start -W -n";
101164cca0b341051b659b7276381756012e23427eeGopinath    private static final String SUCCESS_MESSAGE = "Status: ok";
102164cca0b341051b659b7276381756012e23427eeGopinath    private static final String THIS_TIME = "ThisTime:";
103164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
104164cca0b341051b659b7276381756012e23427eeGopinath    private static final String TRACE_ITERATION = "TRACE_ITERATION - %d";
105164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
106164cca0b341051b659b7276381756012e23427eeGopinath    private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
107164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
108164cca0b341051b659b7276381756012e23427eeGopinath    private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
109164cca0b341051b659b7276381756012e23427eeGopinath
110f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
111f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, Intent> mNameToIntent;
112f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, String> mNameToProcess;
113164cca0b341051b659b7276381756012e23427eeGopinath    private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
114f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private Map<String, String> mNameToResultKey;
115164cca0b341051b659b7276381756012e23427eeGopinath    private Map<String, List<Long>> mNameToLaunchTime;
116f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private IActivityManager mAm;
117164cca0b341051b659b7276381756012e23427eeGopinath    private String mSimplePerfCmd = null;
118164cca0b341051b659b7276381756012e23427eeGopinath    private String mLaunchOrder = null;
119164cca0b341051b659b7276381756012e23427eeGopinath    private boolean mDropCache = false;
12032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private int mLaunchIterations = 10;
121164cca0b341051b659b7276381756012e23427eeGopinath    private int mTraceLaunchCount = 0;
122164cca0b341051b659b7276381756012e23427eeGopinath    private String mTraceDirectoryStr = null;
12332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private Bundle mResult = new Bundle();
1246266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private Set<String> mRequiredAccounts;
125164cca0b341051b659b7276381756012e23427eeGopinath    private boolean mTrailLaunch = true;
126164cca0b341051b659b7276381756012e23427eeGopinath    private File mFile = null;
127164cca0b341051b659b7276381756012e23427eeGopinath    private FileOutputStream mOutputStream = null;
128164cca0b341051b659b7276381756012e23427eeGopinath    private BufferedWriter mBufferedWriter = null;
129164cca0b341051b659b7276381756012e23427eeGopinath
130f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
131e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
132e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void setUp() throws Exception {
133e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.setUp();
134e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
135e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
136e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
137e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    @Override
138e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    protected void tearDown() throws Exception {
139e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
140e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu        super.tearDown();
141e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu    }
142e2a03fe43d1f8eb5a6ada046870dcc35392d8f17Guang Zhu
143164cca0b341051b659b7276381756012e23427eeGopinath    public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
144164cca0b341051b659b7276381756012e23427eeGopinath            IOException, InterruptedException {
145f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        InstrumentationTestRunner instrumentation =
146f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                (InstrumentationTestRunner)getInstrumentation();
1473a34d17412a5a304e39be1966a16627677d2136fSvetoslav        Bundle args = instrumentation.getArguments();
148f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        mAm = ActivityManagerNative.getDefault();
149164cca0b341051b659b7276381756012e23427eeGopinath        String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
150164cca0b341051b659b7276381756012e23427eeGopinath        mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
151164cca0b341051b659b7276381756012e23427eeGopinath        mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
152164cca0b341051b659b7276381756012e23427eeGopinath        mSimplePerfCmd = args.getString(KEY_SIMPLEPPERF_CMD);
153164cca0b341051b659b7276381756012e23427eeGopinath        mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
154f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        createMappings();
155f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        parseArgs(args);
1566266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        checkAccountSignIn();
157f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
158164cca0b341051b659b7276381756012e23427eeGopinath        // Root directory for applaunch file to log the app launch output
159164cca0b341051b659b7276381756012e23427eeGopinath        // Will be useful in case of simpleperf command is used
160164cca0b341051b659b7276381756012e23427eeGopinath        File launchRootDir = null;
161164cca0b341051b659b7276381756012e23427eeGopinath        if (null != launchDirectory && !launchDirectory.isEmpty()) {
162164cca0b341051b659b7276381756012e23427eeGopinath            launchRootDir = new File(launchDirectory);
163164cca0b341051b659b7276381756012e23427eeGopinath            if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
164164cca0b341051b659b7276381756012e23427eeGopinath                throw new IOException("Unable to create the destination directory");
16532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            }
16632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
167164cca0b341051b659b7276381756012e23427eeGopinath
168164cca0b341051b659b7276381756012e23427eeGopinath        try {
169164cca0b341051b659b7276381756012e23427eeGopinath            File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
170164cca0b341051b659b7276381756012e23427eeGopinath            if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
171164cca0b341051b659b7276381756012e23427eeGopinath                throw new IOException("Unable to create the lauch file sub directory");
172164cca0b341051b659b7276381756012e23427eeGopinath            }
173164cca0b341051b659b7276381756012e23427eeGopinath            mFile = new File(launchSubDir, LAUNCH_FILE);
174164cca0b341051b659b7276381756012e23427eeGopinath            mOutputStream = new FileOutputStream(mFile);
175164cca0b341051b659b7276381756012e23427eeGopinath            mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
176164cca0b341051b659b7276381756012e23427eeGopinath                    mOutputStream));
177164cca0b341051b659b7276381756012e23427eeGopinath
178164cca0b341051b659b7276381756012e23427eeGopinath            // Root directory for trace file during the launches
179164cca0b341051b659b7276381756012e23427eeGopinath            File rootTrace = null;
180164cca0b341051b659b7276381756012e23427eeGopinath            File rootTraceSubDir = null;
181164cca0b341051b659b7276381756012e23427eeGopinath            int traceBufferSize = 0;
182164cca0b341051b659b7276381756012e23427eeGopinath            int traceDumpInterval = 0;
183164cca0b341051b659b7276381756012e23427eeGopinath            Set<String> traceCategoriesSet = null;
184164cca0b341051b659b7276381756012e23427eeGopinath            if (null != mTraceDirectoryStr && !mTraceDirectoryStr.isEmpty()) {
185164cca0b341051b659b7276381756012e23427eeGopinath                rootTrace = new File(mTraceDirectoryStr);
186164cca0b341051b659b7276381756012e23427eeGopinath                if (!rootTrace.exists() && !rootTrace.mkdirs()) {
187164cca0b341051b659b7276381756012e23427eeGopinath                    throw new IOException("Unable to create the trace directory");
18832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
189164cca0b341051b659b7276381756012e23427eeGopinath                rootTraceSubDir = new File(rootTrace, TRACE_SUB_DIRECTORY);
190164cca0b341051b659b7276381756012e23427eeGopinath                if (!rootTraceSubDir.exists() && !rootTraceSubDir.mkdirs()) {
191164cca0b341051b659b7276381756012e23427eeGopinath                    throw new IOException("Unable to create the trace sub directory");
19232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
193164cca0b341051b659b7276381756012e23427eeGopinath                assertNotNull("Trace iteration parameter is mandatory",
194164cca0b341051b659b7276381756012e23427eeGopinath                        args.getString(KEY_TRACE_ITERATIONS));
195164cca0b341051b659b7276381756012e23427eeGopinath                mTraceLaunchCount = Integer.parseInt(args.getString(KEY_TRACE_ITERATIONS));
196164cca0b341051b659b7276381756012e23427eeGopinath                String traceCategoriesStr = args
197164cca0b341051b659b7276381756012e23427eeGopinath                        .getString(KEY_TRACE_CATEGORY, DEFAULT_TRACE_CATEGORIES);
198164cca0b341051b659b7276381756012e23427eeGopinath                traceBufferSize = Integer.parseInt(args.getString(KEY_TRACE_BUFFERSIZE,
199164cca0b341051b659b7276381756012e23427eeGopinath                        DEFAULT_TRACE_BUFFER_SIZE));
200164cca0b341051b659b7276381756012e23427eeGopinath                traceDumpInterval = Integer.parseInt(args.getString(KEY_TRACE_DUMPINTERVAL,
201164cca0b341051b659b7276381756012e23427eeGopinath                        DEFAULT_TRACE_DUMP_INTERVAL));
202164cca0b341051b659b7276381756012e23427eeGopinath                traceCategoriesSet = new HashSet<String>();
203164cca0b341051b659b7276381756012e23427eeGopinath                if (!traceCategoriesStr.isEmpty()) {
204164cca0b341051b659b7276381756012e23427eeGopinath                    String[] traceCategoriesSplit = traceCategoriesStr.split(DELIMITER);
205164cca0b341051b659b7276381756012e23427eeGopinath                    for (int i = 0; i < traceCategoriesSplit.length; i++) {
206164cca0b341051b659b7276381756012e23427eeGopinath                        traceCategoriesSet.add(traceCategoriesSplit[i]);
207164cca0b341051b659b7276381756012e23427eeGopinath                    }
2082861a89bed9066e206917c41357a5e589e8482cbGuang Zhu                }
209164cca0b341051b659b7276381756012e23427eeGopinath            }
210164cca0b341051b659b7276381756012e23427eeGopinath
211164cca0b341051b659b7276381756012e23427eeGopinath            // Get the app launch order based on launch order, trial launch,
212164cca0b341051b659b7276381756012e23427eeGopinath            // launch iterations and trace iterations
213164cca0b341051b659b7276381756012e23427eeGopinath            setLaunchOrder();
214164cca0b341051b659b7276381756012e23427eeGopinath
215164cca0b341051b659b7276381756012e23427eeGopinath            for (LaunchOrder launch : mLaunchOrderList) {
216164cca0b341051b659b7276381756012e23427eeGopinath
217164cca0b341051b659b7276381756012e23427eeGopinath                // App launch times for trial launch will not be used for final
218164cca0b341051b659b7276381756012e23427eeGopinath                // launch time calculations.
219164cca0b341051b659b7276381756012e23427eeGopinath                if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
220164cca0b341051b659b7276381756012e23427eeGopinath                    // In the "applaunch.txt" file, trail launches is referenced using
221164cca0b341051b659b7276381756012e23427eeGopinath                    // "TRIAL_LAUNCH"
222164cca0b341051b659b7276381756012e23427eeGopinath                    long launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
223164cca0b341051b659b7276381756012e23427eeGopinath                    if (launchTime < 0) {
224164cca0b341051b659b7276381756012e23427eeGopinath                        List<Long> appLaunchList = new ArrayList<Long>();
225164cca0b341051b659b7276381756012e23427eeGopinath                        appLaunchList.add(-1L);
226164cca0b341051b659b7276381756012e23427eeGopinath                        mNameToLaunchTime.put(launch.getApp(), appLaunchList);
227164cca0b341051b659b7276381756012e23427eeGopinath                        // simply pass the app if launch isn't successful
228164cca0b341051b659b7276381756012e23427eeGopinath                        // error should have already been logged by startApp
229164cca0b341051b659b7276381756012e23427eeGopinath                        continue;
230164cca0b341051b659b7276381756012e23427eeGopinath                    }
231164cca0b341051b659b7276381756012e23427eeGopinath                    sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
232164cca0b341051b659b7276381756012e23427eeGopinath                    closeApp(launch.getApp(), true);
233164cca0b341051b659b7276381756012e23427eeGopinath                    dropCache();
234164cca0b341051b659b7276381756012e23427eeGopinath                    sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
235164cca0b341051b659b7276381756012e23427eeGopinath                }
236164cca0b341051b659b7276381756012e23427eeGopinath
237164cca0b341051b659b7276381756012e23427eeGopinath                // App launch times used for final calculation
238164cca0b341051b659b7276381756012e23427eeGopinath                if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
239164cca0b341051b659b7276381756012e23427eeGopinath                    long launchTime = -1;
240164cca0b341051b659b7276381756012e23427eeGopinath                    if (null != mNameToLaunchTime.get(launch.getApp())) {
241164cca0b341051b659b7276381756012e23427eeGopinath                        long firstLaunchTime = mNameToLaunchTime.get(launch.getApp()).get(0);
242164cca0b341051b659b7276381756012e23427eeGopinath                        if (firstLaunchTime < 0) {
243164cca0b341051b659b7276381756012e23427eeGopinath                            // skip if the app has failures while launched first
244164cca0b341051b659b7276381756012e23427eeGopinath                            continue;
245164cca0b341051b659b7276381756012e23427eeGopinath                        }
246164cca0b341051b659b7276381756012e23427eeGopinath                    }
247164cca0b341051b659b7276381756012e23427eeGopinath                    // In the "applaunch.txt" file app launches are referenced using
248164cca0b341051b659b7276381756012e23427eeGopinath                    // "LAUNCH_ITERATION - ITERATION NUM"
249164cca0b341051b659b7276381756012e23427eeGopinath                    launchTime = startApp(launch.getApp(), true, launch.getLaunchReason());
250164cca0b341051b659b7276381756012e23427eeGopinath                    if (launchTime < 0) {
251164cca0b341051b659b7276381756012e23427eeGopinath                        // if it fails once, skip the rest of the launches
252164cca0b341051b659b7276381756012e23427eeGopinath                        List<Long> appLaunchList = new ArrayList<Long>();
253164cca0b341051b659b7276381756012e23427eeGopinath                        appLaunchList.add(-1L);
254164cca0b341051b659b7276381756012e23427eeGopinath                        mNameToLaunchTime.put(launch.getApp(), appLaunchList);
255164cca0b341051b659b7276381756012e23427eeGopinath                        continue;
256164cca0b341051b659b7276381756012e23427eeGopinath                    } else {
257164cca0b341051b659b7276381756012e23427eeGopinath                        if (null != mNameToLaunchTime.get(launch.getApp())) {
258164cca0b341051b659b7276381756012e23427eeGopinath                            mNameToLaunchTime.get(launch.getApp()).add(launchTime);
259164cca0b341051b659b7276381756012e23427eeGopinath                        } else {
260164cca0b341051b659b7276381756012e23427eeGopinath                            List<Long> appLaunchList = new ArrayList<Long>();
261164cca0b341051b659b7276381756012e23427eeGopinath                            appLaunchList.add(launchTime);
262164cca0b341051b659b7276381756012e23427eeGopinath                            mNameToLaunchTime.put(launch.getApp(), appLaunchList);
263164cca0b341051b659b7276381756012e23427eeGopinath                        }
264164cca0b341051b659b7276381756012e23427eeGopinath                    }
265164cca0b341051b659b7276381756012e23427eeGopinath                    sleep(POST_LAUNCH_IDLE_TIMEOUT);
266164cca0b341051b659b7276381756012e23427eeGopinath                    closeApp(launch.getApp(), true);
267164cca0b341051b659b7276381756012e23427eeGopinath                    dropCache();
268164cca0b341051b659b7276381756012e23427eeGopinath                    sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
269164cca0b341051b659b7276381756012e23427eeGopinath                }
270164cca0b341051b659b7276381756012e23427eeGopinath
271164cca0b341051b659b7276381756012e23427eeGopinath                // App launch times for trace launch will not be used for final
272164cca0b341051b659b7276381756012e23427eeGopinath                // launch time calculations.
273164cca0b341051b659b7276381756012e23427eeGopinath                if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
274164cca0b341051b659b7276381756012e23427eeGopinath                    AtraceLogger atraceLogger = AtraceLogger
275164cca0b341051b659b7276381756012e23427eeGopinath                            .getAtraceLoggerInstance(getInstrumentation());
276164cca0b341051b659b7276381756012e23427eeGopinath                    // Start the trace
277164cca0b341051b659b7276381756012e23427eeGopinath                    try {
278164cca0b341051b659b7276381756012e23427eeGopinath                        atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
279164cca0b341051b659b7276381756012e23427eeGopinath                                traceDumpInterval, rootTraceSubDir,
280164cca0b341051b659b7276381756012e23427eeGopinath                                String.format("%s-%s", launch.getApp(), launch.getLaunchReason()));
281164cca0b341051b659b7276381756012e23427eeGopinath                        startApp(launch.getApp(), true, launch.getLaunchReason());
282164cca0b341051b659b7276381756012e23427eeGopinath                        sleep(POST_LAUNCH_IDLE_TIMEOUT);
283164cca0b341051b659b7276381756012e23427eeGopinath                    } finally {
284164cca0b341051b659b7276381756012e23427eeGopinath                        // Stop the trace
285164cca0b341051b659b7276381756012e23427eeGopinath                        atraceLogger.atraceStop();
286164cca0b341051b659b7276381756012e23427eeGopinath                        closeApp(launch.getApp(), true);
287164cca0b341051b659b7276381756012e23427eeGopinath                        dropCache();
288164cca0b341051b659b7276381756012e23427eeGopinath                        sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
289164cca0b341051b659b7276381756012e23427eeGopinath                    }
290164cca0b341051b659b7276381756012e23427eeGopinath                }
291164cca0b341051b659b7276381756012e23427eeGopinath            }
292164cca0b341051b659b7276381756012e23427eeGopinath        } finally {
293164cca0b341051b659b7276381756012e23427eeGopinath            if (null != mBufferedWriter) {
294164cca0b341051b659b7276381756012e23427eeGopinath                mBufferedWriter.close();
29532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            }
29632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
297164cca0b341051b659b7276381756012e23427eeGopinath
29832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        for (String app : mNameToResultKey.keySet()) {
299164cca0b341051b659b7276381756012e23427eeGopinath            StringBuilder launchTimes = new StringBuilder();
300164cca0b341051b659b7276381756012e23427eeGopinath            for (Long launch : mNameToLaunchTime.get(app)) {
301164cca0b341051b659b7276381756012e23427eeGopinath                launchTimes.append(launch);
302164cca0b341051b659b7276381756012e23427eeGopinath                launchTimes.append(",");
303f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
304164cca0b341051b659b7276381756012e23427eeGopinath            mResult.putString(mNameToResultKey.get(app), launchTimes.toString());
305f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
30632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        instrumentation.sendStatus(0, mResult);
307f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
308f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
309164cca0b341051b659b7276381756012e23427eeGopinath    /**
310164cca0b341051b659b7276381756012e23427eeGopinath     * If launch order is "cyclic" then apps will be launched one after the
311164cca0b341051b659b7276381756012e23427eeGopinath     * other for each iteration count.
312164cca0b341051b659b7276381756012e23427eeGopinath     * If launch order is "sequential" then each app will be launched for given number
313164cca0b341051b659b7276381756012e23427eeGopinath     * iterations at once before launching the other apps.
314164cca0b341051b659b7276381756012e23427eeGopinath     */
315164cca0b341051b659b7276381756012e23427eeGopinath    private void setLaunchOrder() {
316164cca0b341051b659b7276381756012e23427eeGopinath        if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
317164cca0b341051b659b7276381756012e23427eeGopinath            if (mTrailLaunch) {
318164cca0b341051b659b7276381756012e23427eeGopinath                for (String app : mNameToResultKey.keySet()) {
319164cca0b341051b659b7276381756012e23427eeGopinath                    mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
320164cca0b341051b659b7276381756012e23427eeGopinath                }
321164cca0b341051b659b7276381756012e23427eeGopinath            }
322164cca0b341051b659b7276381756012e23427eeGopinath            for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
323164cca0b341051b659b7276381756012e23427eeGopinath                for (String app : mNameToResultKey.keySet()) {
324164cca0b341051b659b7276381756012e23427eeGopinath                    mLaunchOrderList.add(new LaunchOrder(app,
325164cca0b341051b659b7276381756012e23427eeGopinath                            String.format(LAUNCH_ITERATION, launchCount)));
326164cca0b341051b659b7276381756012e23427eeGopinath                }
327164cca0b341051b659b7276381756012e23427eeGopinath            }
328164cca0b341051b659b7276381756012e23427eeGopinath            if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
329164cca0b341051b659b7276381756012e23427eeGopinath                for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
330164cca0b341051b659b7276381756012e23427eeGopinath                    for (String app : mNameToResultKey.keySet()) {
331164cca0b341051b659b7276381756012e23427eeGopinath                        mLaunchOrderList.add(new LaunchOrder(app,
332164cca0b341051b659b7276381756012e23427eeGopinath                                String.format(TRACE_ITERATION, traceCount)));
333164cca0b341051b659b7276381756012e23427eeGopinath                    }
334164cca0b341051b659b7276381756012e23427eeGopinath                }
335164cca0b341051b659b7276381756012e23427eeGopinath            }
336164cca0b341051b659b7276381756012e23427eeGopinath        } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
337164cca0b341051b659b7276381756012e23427eeGopinath            for (String app : mNameToResultKey.keySet()) {
338164cca0b341051b659b7276381756012e23427eeGopinath                if (mTrailLaunch) {
339164cca0b341051b659b7276381756012e23427eeGopinath                    mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH));
340164cca0b341051b659b7276381756012e23427eeGopinath                }
341164cca0b341051b659b7276381756012e23427eeGopinath                for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
342164cca0b341051b659b7276381756012e23427eeGopinath                    mLaunchOrderList.add(new LaunchOrder(app,
343164cca0b341051b659b7276381756012e23427eeGopinath                            String.format(LAUNCH_ITERATION, launchCount)));
344164cca0b341051b659b7276381756012e23427eeGopinath                }
345164cca0b341051b659b7276381756012e23427eeGopinath                if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
346164cca0b341051b659b7276381756012e23427eeGopinath                    for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
347164cca0b341051b659b7276381756012e23427eeGopinath                        mLaunchOrderList.add(new LaunchOrder(app,
348164cca0b341051b659b7276381756012e23427eeGopinath                                String.format(TRACE_ITERATION, traceCount)));
349164cca0b341051b659b7276381756012e23427eeGopinath                    }
350164cca0b341051b659b7276381756012e23427eeGopinath                }
351164cca0b341051b659b7276381756012e23427eeGopinath            }
352164cca0b341051b659b7276381756012e23427eeGopinath        } else {
353164cca0b341051b659b7276381756012e23427eeGopinath            assertTrue("Launch order is not valid parameter", false);
354164cca0b341051b659b7276381756012e23427eeGopinath        }
355164cca0b341051b659b7276381756012e23427eeGopinath    }
356164cca0b341051b659b7276381756012e23427eeGopinath
357164cca0b341051b659b7276381756012e23427eeGopinath    private void dropCache() {
358164cca0b341051b659b7276381756012e23427eeGopinath        if (true == mDropCache) {
359164cca0b341051b659b7276381756012e23427eeGopinath            assertNotNull("Issue in dropping the cache",
360164cca0b341051b659b7276381756012e23427eeGopinath                    getInstrumentation().getUiAutomation()
361164cca0b341051b659b7276381756012e23427eeGopinath                            .executeShellCommand(DROP_CACHE_SCRIPT));
362164cca0b341051b659b7276381756012e23427eeGopinath        }
363164cca0b341051b659b7276381756012e23427eeGopinath    }
364164cca0b341051b659b7276381756012e23427eeGopinath
365f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void parseArgs(Bundle args) {
366c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToResultKey = new LinkedHashMap<String, String>();
367164cca0b341051b659b7276381756012e23427eeGopinath        mNameToLaunchTime = new HashMap<String, List<Long>>();
36832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
36932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        if (launchIterations != null) {
37032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mLaunchIterations = Integer.parseInt(launchIterations);
37132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        }
372f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        String appList = args.getString(KEY_APPS);
373f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (appList == null)
374f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            return;
375f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
376f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        String appNames[] = appList.split("\\|");
377f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        for (String pair : appNames) {
378f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            String[] parts = pair.split("\\^");
379f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            if (parts.length != 2) {
3806fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Log.e(TAG, "The apps key is incorrectly formatted");
381f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                fail();
382f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
383f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
384f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            mNameToResultKey.put(parts[0], parts[1]);
385164cca0b341051b659b7276381756012e23427eeGopinath            mNameToLaunchTime.put(parts[0], null);
386f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
3876266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
3886266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (requiredAccounts != null) {
3896266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            mRequiredAccounts = new HashSet<String>();
3906266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            for (String accountType : requiredAccounts.split(",")) {
3916266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                mRequiredAccounts.add(accountType);
3926266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
3936266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
394164cca0b341051b659b7276381756012e23427eeGopinath        mTrailLaunch = "true".equals(args.getString(KEY_TRIAL_LAUNCH));
395f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
396f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
3976fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim    private boolean hasLeanback(Context context) {
3986fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
3996fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim    }
4006fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim
401f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void createMappings() {
402c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToIntent = new LinkedHashMap<String, Intent>();
403c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        mNameToProcess = new LinkedHashMap<String, String>();
404f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
405f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        PackageManager pm = getInstrumentation().getContext()
406f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                .getPackageManager();
407f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
4086fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
4096fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Intent.CATEGORY_LEANBACK_LAUNCHER :
4106fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim                Intent.CATEGORY_LAUNCHER);
411f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
412349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        resolveLoop(ris, intentToResolve, pm);
4136fc955071afc4125a6a52bf7ab01129416ae0dbfHyungtae Tim Kim        // For Wear
414349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
415349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        ris = pm.queryIntentActivities(intentToResolve, 0);
416349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz        resolveLoop(ris, intentToResolve, pm);
417349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    }
418349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz
419349537b73710655d48e8e3a8472b058d8c1381c8Joshua Schwarz    private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
420f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (ris == null || ris.isEmpty()) {
421f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            Log.i(TAG, "Could not find any apps");
422f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } else {
423f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            for (ResolveInfo ri : ris) {
424f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Intent startIntent = new Intent(intentToResolve);
425f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
426f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
427f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                startIntent.setClassName(ri.activityInfo.packageName,
428f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                        ri.activityInfo.name);
42932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                String appName = ri.loadLabel(pm).toString();
43032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                if (appName != null) {
43132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mNameToIntent.put(appName, startIntent);
43232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mNameToProcess.put(appName, ri.activityInfo.processName);
43332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
434f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
435f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
436f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
437f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
438164cca0b341051b659b7276381756012e23427eeGopinath    private long startApp(String appName, boolean forceStopBeforeLaunch, String launchReason)
439f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            throws NameNotFoundException, RemoteException {
440f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Log.i(TAG, "Starting " + appName);
441f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
442f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent startIntent = mNameToIntent.get(appName);
443c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        if (startIntent == null) {
444c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu            Log.w(TAG, "App does not exist: " + appName);
44532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mResult.putString(mNameToResultKey.get(appName), "App does not exist");
446164cca0b341051b659b7276381756012e23427eeGopinath            return -1L;
447c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu        }
448164cca0b341051b659b7276381756012e23427eeGopinath        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch ,
449164cca0b341051b659b7276381756012e23427eeGopinath                launchReason);
450f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Thread t = new Thread(runnable);
451f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        t.start();
452f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        try {
453f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            t.join(JOIN_TIMEOUT);
454f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } catch (InterruptedException e) {
455f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            // ignore
456f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
457164cca0b341051b659b7276381756012e23427eeGopinath        return runnable.getResult();
458f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
459f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
4606266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    private void checkAccountSignIn() {
4616266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // ensure that the device has the required account types before starting test
4626266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // e.g. device must have a valid Google account sign in to measure a meaningful launch time
4636266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // for Gmail
4646266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
4656266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            return;
4666266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
4676266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        final AccountManager am =
4686266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                (AccountManager) getInstrumentation().getTargetContext().getSystemService(
4696266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                        Context.ACCOUNT_SERVICE);
4706266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        Account[] accounts = am.getAccounts();
4716266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // use set here in case device has multiple accounts of the same type
4726266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        Set<String> foundAccounts = new HashSet<String>();
4736266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        for (Account account : accounts) {
4746266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            if (mRequiredAccounts.contains(account.type)) {
4756266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                foundAccounts.add(account.type);
4766266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
4776266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
4786266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // check if account type matches, if not, fail test with message on what account types
4796266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        // are missing
4806266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        if (mRequiredAccounts.size() != foundAccounts.size()) {
4816266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            mRequiredAccounts.removeAll(foundAccounts);
4826266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            StringBuilder sb = new StringBuilder("Device missing these accounts:");
4836266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            for (String account : mRequiredAccounts) {
4846266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                sb.append(' ');
4856266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu                sb.append(account);
4866266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            }
4876266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu            fail(sb.toString());
4886266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu        }
4896266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu    }
4906266a436f35622f3b48de8d7b245bb5f8a4c567dGuang Zhu
49132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private void closeApp(String appName, boolean forceStopApp) {
492f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
493f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        homeIntent.addCategory(Intent.CATEGORY_HOME);
494f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
495f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
496f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        getInstrumentation().getContext().startActivity(homeIntent);
49732abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        sleep(POST_LAUNCH_IDLE_TIMEOUT);
49832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        if (forceStopApp) {
49932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            Intent startIntent = mNameToIntent.get(appName);
50032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            if (startIntent != null) {
50132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                String packageName = startIntent.getComponent().getPackageName();
50232abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                try {
50332abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
50432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                } catch (RemoteException e) {
50532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    Log.w(TAG, "Error closing app", e);
50632abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
50713f77349778fbe95d665542be6f05006879854e2Guang Zhu            }
50813f77349778fbe95d665542be6f05006879854e2Guang Zhu        }
509f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
510f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
511f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private void sleep(int time) {
512f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        try {
513f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            Thread.sleep(time);
514f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        } catch (InterruptedException e) {
515f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            // ignore
516f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
517f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
518f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
51932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu    private void reportError(String appName, String processName) {
520f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        ActivityManager am = (ActivityManager) getInstrumentation()
521f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
522f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
523f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        if (crashes != null) {
524f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            for (ProcessErrorStateInfo crash : crashes) {
525f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                if (!crash.processName.equals(processName))
526f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                    continue;
527f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
528f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
52932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
530f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                return;
531f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
532f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
533f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
53432abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        mResult.putString(mNameToResultKey.get(appName),
535f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                "Crashed for unknown reason");
536f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        Log.w(TAG, appName
537f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                + " not found in process list, most likely it is crashed");
538f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
539f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
540164cca0b341051b659b7276381756012e23427eeGopinath    private class LaunchOrder {
541164cca0b341051b659b7276381756012e23427eeGopinath        private String mApp;
542164cca0b341051b659b7276381756012e23427eeGopinath        private String mLaunchReason;
543164cca0b341051b659b7276381756012e23427eeGopinath
544164cca0b341051b659b7276381756012e23427eeGopinath        LaunchOrder(String app,String launchReason){
545164cca0b341051b659b7276381756012e23427eeGopinath            mApp = app;
546164cca0b341051b659b7276381756012e23427eeGopinath            mLaunchReason = launchReason;
547164cca0b341051b659b7276381756012e23427eeGopinath        }
548164cca0b341051b659b7276381756012e23427eeGopinath
549164cca0b341051b659b7276381756012e23427eeGopinath        public String getApp() {
550164cca0b341051b659b7276381756012e23427eeGopinath            return mApp;
551164cca0b341051b659b7276381756012e23427eeGopinath        }
552164cca0b341051b659b7276381756012e23427eeGopinath
553164cca0b341051b659b7276381756012e23427eeGopinath        public void setApp(String app) {
554164cca0b341051b659b7276381756012e23427eeGopinath            mApp = app;
555164cca0b341051b659b7276381756012e23427eeGopinath        }
556164cca0b341051b659b7276381756012e23427eeGopinath
557164cca0b341051b659b7276381756012e23427eeGopinath        public String getLaunchReason() {
558164cca0b341051b659b7276381756012e23427eeGopinath            return mLaunchReason;
559164cca0b341051b659b7276381756012e23427eeGopinath        }
560164cca0b341051b659b7276381756012e23427eeGopinath
561164cca0b341051b659b7276381756012e23427eeGopinath        public void setLaunchReason(String launchReason) {
562164cca0b341051b659b7276381756012e23427eeGopinath            mLaunchReason = launchReason;
563164cca0b341051b659b7276381756012e23427eeGopinath        }
564164cca0b341051b659b7276381756012e23427eeGopinath    }
565164cca0b341051b659b7276381756012e23427eeGopinath
566f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    private class AppLaunchRunnable implements Runnable {
567f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        private Intent mLaunchIntent;
568164cca0b341051b659b7276381756012e23427eeGopinath        private Long mResult;
56932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu        private boolean mForceStopBeforeLaunch;
570164cca0b341051b659b7276381756012e23427eeGopinath        private String mLaunchReason;
57132abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu
572164cca0b341051b659b7276381756012e23427eeGopinath        public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch,
573164cca0b341051b659b7276381756012e23427eeGopinath                String launchReason) {
574f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            mLaunchIntent = intent;
57532abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu            mForceStopBeforeLaunch = forceStopBeforeLaunch;
576164cca0b341051b659b7276381756012e23427eeGopinath            mLaunchReason = launchReason;
577eaf08cf7d0aaceb187dd879f7cd53c9d26d4bd75Yuanlang Song            mResult = -1L;
578f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
579f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
580164cca0b341051b659b7276381756012e23427eeGopinath        public Long getResult() {
581f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            return mResult;
582f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
583f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine
584f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        public void run() {
585f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            try {
586c28a062ffd7edbdbd936c750fa3ec3f81b0d1b44Guang Zhu                String packageName = mLaunchIntent.getComponent().getPackageName();
587164cca0b341051b659b7276381756012e23427eeGopinath                String componentName = mLaunchIntent.getComponent().flattenToShortString();
58832abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                if (mForceStopBeforeLaunch) {
58932abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
59032abd66ebd6d63cfc631ce5f4425bb5dc4a4beacGuang Zhu                }
591164cca0b341051b659b7276381756012e23427eeGopinath                String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
592164cca0b341051b659b7276381756012e23427eeGopinath                if (null != mSimplePerfCmd) {
593164cca0b341051b659b7276381756012e23427eeGopinath                    launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
594f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                }
595164cca0b341051b659b7276381756012e23427eeGopinath                Log.v(TAG, "Final launch cmd:" + launchCmd);
596164cca0b341051b659b7276381756012e23427eeGopinath                ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
597164cca0b341051b659b7276381756012e23427eeGopinath                        .executeShellCommand(launchCmd);
598164cca0b341051b659b7276381756012e23427eeGopinath                mResult = Long.parseLong(parseLaunchTimeAndWrite(parcelDesc, String.format
599164cca0b341051b659b7276381756012e23427eeGopinath                        ("App Launch :%s %s",
600164cca0b341051b659b7276381756012e23427eeGopinath                                componentName, mLaunchReason)), 10);
601f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            } catch (RemoteException e) {
602f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine                Log.w(TAG, "Error launching app", e);
603f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine            }
604f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine        }
605164cca0b341051b659b7276381756012e23427eeGopinath
606164cca0b341051b659b7276381756012e23427eeGopinath        /**
607164cca0b341051b659b7276381756012e23427eeGopinath         * Method to parse the launch time info and write the result to file
608164cca0b341051b659b7276381756012e23427eeGopinath         *
609164cca0b341051b659b7276381756012e23427eeGopinath         * @param parcelDesc
610164cca0b341051b659b7276381756012e23427eeGopinath         * @return
611164cca0b341051b659b7276381756012e23427eeGopinath         */
612164cca0b341051b659b7276381756012e23427eeGopinath        private String parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, String headerInfo) {
613164cca0b341051b659b7276381756012e23427eeGopinath            String launchTime = "-1";
614164cca0b341051b659b7276381756012e23427eeGopinath            boolean launchSuccess = false;
615164cca0b341051b659b7276381756012e23427eeGopinath            try {
616164cca0b341051b659b7276381756012e23427eeGopinath                InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
617164cca0b341051b659b7276381756012e23427eeGopinath                StringBuilder appLaunchOuput = new StringBuilder();
618164cca0b341051b659b7276381756012e23427eeGopinath                /* SAMPLE OUTPUT :
619164cca0b341051b659b7276381756012e23427eeGopinath                Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
620164cca0b341051b659b7276381756012e23427eeGopinath                Status: ok
621164cca0b341051b659b7276381756012e23427eeGopinath                Activity: com.google.android.calculator/com.android.calculator2.Calculator
622164cca0b341051b659b7276381756012e23427eeGopinath                ThisTime: 357
623164cca0b341051b659b7276381756012e23427eeGopinath                TotalTime: 357
624164cca0b341051b659b7276381756012e23427eeGopinath                WaitTime: 377
625164cca0b341051b659b7276381756012e23427eeGopinath                Complete*/
626164cca0b341051b659b7276381756012e23427eeGopinath                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
627164cca0b341051b659b7276381756012e23427eeGopinath                        inputStream));
628164cca0b341051b659b7276381756012e23427eeGopinath                String line = null;
629164cca0b341051b659b7276381756012e23427eeGopinath                int lineCount = 1;
630164cca0b341051b659b7276381756012e23427eeGopinath                mBufferedWriter.newLine();
631164cca0b341051b659b7276381756012e23427eeGopinath                mBufferedWriter.write(headerInfo);
632164cca0b341051b659b7276381756012e23427eeGopinath                mBufferedWriter.newLine();
633164cca0b341051b659b7276381756012e23427eeGopinath                while ((line = bufferedReader.readLine()) != null) {
634164cca0b341051b659b7276381756012e23427eeGopinath                    if (lineCount == 2 && line.contains(SUCCESS_MESSAGE)) {
635164cca0b341051b659b7276381756012e23427eeGopinath                        launchSuccess = true;
636164cca0b341051b659b7276381756012e23427eeGopinath                    }
637164cca0b341051b659b7276381756012e23427eeGopinath                    if (launchSuccess && lineCount == 4) {
638164cca0b341051b659b7276381756012e23427eeGopinath                        String launchSplit[] = line.split(":");
639164cca0b341051b659b7276381756012e23427eeGopinath                        launchTime = launchSplit[1].trim();
640164cca0b341051b659b7276381756012e23427eeGopinath                    }
641164cca0b341051b659b7276381756012e23427eeGopinath                    mBufferedWriter.write(line);
642164cca0b341051b659b7276381756012e23427eeGopinath                    mBufferedWriter.newLine();
643164cca0b341051b659b7276381756012e23427eeGopinath                    lineCount++;
644164cca0b341051b659b7276381756012e23427eeGopinath                }
645164cca0b341051b659b7276381756012e23427eeGopinath                mBufferedWriter.flush();
646164cca0b341051b659b7276381756012e23427eeGopinath                inputStream.close();
647164cca0b341051b659b7276381756012e23427eeGopinath            } catch (IOException e) {
648164cca0b341051b659b7276381756012e23427eeGopinath                Log.w(TAG, "Error writing the launch file", e);
649164cca0b341051b659b7276381756012e23427eeGopinath            }
650164cca0b341051b659b7276381756012e23427eeGopinath            return launchTime;
651164cca0b341051b659b7276381756012e23427eeGopinath        }
652164cca0b341051b659b7276381756012e23427eeGopinath
653f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine    }
654f58e5b6cdcecee6184784b3a6ac33f60341de170Maxim Siniavine}
655