• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.performanceapp.tests;
18 
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileOutputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.ArrayList;
25 import java.util.List;
26 
27 import android.app.ActivityManager;
28 import android.app.ActivityManager.RunningAppProcessInfo;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.pm.ActivityInfo;
33 import android.content.pm.PackageInfo;
34 import android.content.pm.PackageManager.NameNotFoundException;
35 import android.os.Bundle;
36 import android.os.Environment;
37 import android.os.ParcelFileDescriptor;
38 import android.support.test.InstrumentationRegistry;
39 import android.test.InstrumentationTestCase;
40 import android.test.suitebuilder.annotation.MediumTest;
41 import android.util.Log;
42 
43 /**
44  * To test the App launch performance on the given target package for the list of activities. It
45  * launches the activities present in the target package the number of times in launch count or it
46  * launches only the activities mentioned in custom activity list the launch count times and returns
47  * the path to the files where the atrace logs are stored corresponding to each activity launch
48  */
49 public class AppLaunchTests extends InstrumentationTestCase {
50 
51     private static final String TAG = "AppLaunchInstrumentation";
52     private static final String TARGETPACKAGE = "targetpackage";
53     private static final String SIMPLEPERF_BIN = "simpleperf_bin";
54     private static final String SIMPLEPERF_EVT = "simpleperf_event";
55     private static final String SIMPLEPERF_DATA = "simpleperf_data";
56     private static final String DISPATCHER = "dispatcher";
57     private static final String ACTIVITYLIST = "activitylist";
58     private static final String LAUNCHCOUNT = "launchcount";
59     private static final String RECORDTRACE = "recordtrace";
60     private static final String ATRACE_START = "atrace --async_start am view gfx";
61     private static final String ATRACE_DUMP = "atrace --async_dump";
62     private static final String ATRACE_STOP = "atrace --async_stop";
63     private static final String FORCE_STOP = "am force-stop ";
64 
65     private Context mContext;
66     private Bundle mResult;
67     private String mTargetPackageName;
68     private String mSimpleperfBin;
69     private String mSimpleperfEvt;
70     private String mSimpleperfDir;
71     private String mDispatcher;
72     private int mLaunchCount;
73     private String mCustomActivityList;
74     private PackageInfo mPackageInfo;
75     private boolean mRecordTrace = true;
76     private List<String> mActivityList;
77 
78     /**
79      * {@inheritDoc}
80      */
81     @Override
setUp()82     public void setUp() throws Exception {
83         super.setUp();
84         mContext = getInstrumentation().getTargetContext();
85         assertNotNull("Failed to get context", mContext);
86         Bundle args = InstrumentationRegistry.getArguments();
87         assertNotNull("Unable to get the args", args);
88         mTargetPackageName = args.getString(TARGETPACKAGE);
89         assertNotNull("Target package name not set", mTargetPackageName);
90         mSimpleperfEvt = args.getString(SIMPLEPERF_EVT);
91         mDispatcher = args.getString(DISPATCHER);
92         if (mDispatcher != null && !mDispatcher.isEmpty()) {
93             mSimpleperfBin = args.getString(SIMPLEPERF_BIN);
94             mSimpleperfEvt = args.getString(SIMPLEPERF_EVT);
95             mSimpleperfDir = args.getString(SIMPLEPERF_DATA);
96         }
97         mCustomActivityList = args.getString(ACTIVITYLIST);
98         if (mCustomActivityList == null || mCustomActivityList.isEmpty()) {
99             // Get full list of activities from the target package
100             mActivityList = getActivityList("");
101         } else {
102             // Get only the user defined list of activities from the target package
103             mActivityList = getActivityList(mCustomActivityList);
104         }
105         assertTrue("Activity List is empty", (mActivityList.size() > 0));
106         mLaunchCount = Integer.parseInt(args.getString(LAUNCHCOUNT));
107         assertTrue("Invalid Launch Count", mLaunchCount > 0);
108         if (args.getString(RECORDTRACE) != null
109                 && args.getString(RECORDTRACE).equalsIgnoreCase("false")) {
110             mRecordTrace = false;
111         }
112         mResult = new Bundle();
113     }
114 
115     @MediumTest
testAppLaunchPerformance()116     public void testAppLaunchPerformance() throws Exception {
117         assertTrue("Cannot write in External File", isExternalStorageWritable());
118         File root = Environment.getExternalStorageDirectory();
119         assertNotNull("Unable to get the root of the external storage", root);
120         File logsDir = new File(root, "atrace_logs");
121         assertTrue("Unable to create the directory to store atrace logs", logsDir.mkdir());
122         if (mDispatcher != null && !mDispatcher.isEmpty()) {
123             if (mSimpleperfDir == null)
124                 mSimpleperfDir = "/sdcard/perf_simpleperf/";
125             File simpleperfDir = new File(mSimpleperfDir);
126             assertTrue("Unable to create the directory to store simpleperf data", simpleperfDir.mkdir());
127         }
128         for (int count = 0; count < mLaunchCount; count++) {
129             for (String activityName : mActivityList) {
130                 ComponentName cn = new ComponentName(mTargetPackageName,
131                         mDispatcher != null ? mDispatcher : activityName);
132                 Intent intent = new Intent(Intent.ACTION_MAIN);
133                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
134                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
135                 intent.setComponent(cn);
136 
137                 if (mDispatcher != null) {
138                     intent.putExtra("ACTIVITY_NAME", activityName);
139                     intent.putExtra("SIMPLEPERF_DIR", mSimpleperfDir);
140                     intent.putExtra("SIMPLEPERF_EVT", mSimpleperfEvt);
141                     intent.putExtra("SIMPLEPERF_BIN", mSimpleperfBin);
142                 }
143 
144                 // Start the atrace
145                 if (mRecordTrace) {
146                     assertNotNull(
147                             "Unable to start atrace async",
148                             getInstrumentation().getUiAutomation()
149                                     .executeShellCommand(ATRACE_START));
150                     // Sleep for 10 secs to make sure atrace command is started
151                     Thread.sleep(10 * 1000);
152                 }
153 
154                 // Launch the activity
155                 mContext.startActivity(intent);
156                 Thread.sleep(5 * 1000);
157 
158                 // Make sure we stops simpleperf
159                 if (mDispatcher != null) {
160                     try {
161                         Runtime.getRuntime().exec("pkill -l SIGINT simpleperf").waitFor();
162                     } catch (Exception e) {
163                         Log.v(TAG, "simpleperf throw exception");
164                         e.printStackTrace();
165                     }
166                 }
167 
168                 // Dump atrace info and write it to file
169                 if (mRecordTrace) {
170                     int processId = getProcessId(mTargetPackageName);
171                     assertTrue("Not able to retrive the process id for the package:"
172                             + mTargetPackageName, processId > 0);
173                     String fileName = String.format("%s-%d-%d", activityName, count, processId);
174                     ParcelFileDescriptor parcelFile =
175                             getInstrumentation().getUiAutomation().executeShellCommand(ATRACE_DUMP);
176                     assertNotNull("Unable to get the File descriptor to standard out",
177                             parcelFile);
178                     InputStream inputStream = new FileInputStream(parcelFile.getFileDescriptor());
179                     File file = new File(logsDir, fileName);
180                     FileOutputStream outputStream = new FileOutputStream(file);
181                     try {
182                         byte[] buffer = new byte[1024];
183                         int length;
184                         while ((length = inputStream.read(buffer)) > 0) {
185                             outputStream.write(buffer, 0, length);
186                         }
187                     } catch (IOException e) {
188                         Log.w(TAG, "Error writing atrace info to file", e);
189                     }
190                     inputStream.close();
191                     outputStream.close();
192 
193                     // Stop the atrace
194                     assertNotNull(
195                             "Unable to stop the atrace",
196                             getInstrumentation().getUiAutomation().executeShellCommand(ATRACE_STOP));
197 
198                     // To keep track of the activity name,list of atrace file name
199                     registerTraceFileNames(activityName, fileName);
200                 }
201                 assertNotNull("Unable to stop recent activity launched",
202                         getInstrumentation().getUiAutomation().executeShellCommand(
203                                 FORCE_STOP + mTargetPackageName));
204                 Thread.sleep(5 * 1000);
205             }
206         }
207         getInstrumentation().sendStatus(0, mResult);
208     }
209 
210     /**
211      * Method to check if external storage is writable
212      * @return
213      */
isExternalStorageWritable()214     public boolean isExternalStorageWritable() {
215         return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
216     }
217 
218     /**
219      * Method to get list of activities present in given target package If customActivityList is
220      * passed then include only those activities
221      * @return list of activity names
222      */
getActivityList(String customActivityList)223     private List<String> getActivityList(String customActivityList) {
224         mActivityList = new ArrayList<String>();
225         try {
226             mPackageInfo = mContext.getPackageManager().getPackageInfo(
227                     mTargetPackageName, 1);
228             assertNotNull("Unable to get  the target package info", mPackageInfo);
229         } catch (NameNotFoundException e) {
230             fail(String.format("Target application: %s not found", mTargetPackageName));
231         }
232         for (ActivityInfo activityInfo : mPackageInfo.activities) {
233             mActivityList.add(activityInfo.name);
234         }
235         if (!customActivityList.isEmpty()) {
236             List<String> finalActivityList = new
237                     ArrayList<String>();
238             String customList[] = customActivityList.split(",");
239             for (int count = 0; count < customList.length; count++) {
240                 if (mActivityList.contains(customList[count])) {
241                     finalActivityList.add(customList[count]);
242                 } else {
243                     fail(String.format("Activity: %s not present in the target package : %s ",
244                             customList[count], mTargetPackageName));
245                 }
246             }
247             mActivityList = finalActivityList;
248         }
249         return mActivityList;
250     }
251 
252     /**
253      * Method to retrieve process id from the activity manager
254      * @param processName
255      * @return
256      */
getProcessId(String processName)257     private int getProcessId(String processName) {
258         ActivityManager am = (ActivityManager) getInstrumentation()
259                 .getContext().getSystemService(Context.ACTIVITY_SERVICE);
260         List<RunningAppProcessInfo> appsInfo = am.getRunningAppProcesses();
261         assertNotNull("Unable to retrieve running apps info", appsInfo);
262         for (RunningAppProcessInfo appInfo : appsInfo) {
263             if (appInfo.processName.equals(processName)) {
264                 return appInfo.pid;
265             }
266         }
267         return -1;
268     }
269 
270     /**
271      * To add the process id to the result map
272      * @param activityNamereturn
273      * @return
274      * @throws IOException
275      */
registerTraceFileNames(String activityName, String absPath)276     private void registerTraceFileNames(String activityName, String absPath)
277             throws IOException {
278         if (mResult.containsKey(activityName)) {
279             String existingResult = (String) mResult.get(activityName);
280             mResult.putString(activityName, existingResult + "," + absPath);
281         } else {
282             mResult.putString(activityName, "" + absPath);
283         }
284     }
285 }
286 
287