• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.compatibilitytest;
18 
19 import android.app.ActivityManager;
20 import android.app.ActivityManager.ProcessErrorStateInfo;
21 import android.app.ActivityManager.RunningAppProcessInfo;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.PackageManager.NameNotFoundException;
27 import android.os.Bundle;
28 import android.test.InstrumentationTestCase;
29 import android.util.Log;
30 
31 import junit.framework.Assert;
32 
33 import java.util.Collection;
34 import java.util.List;
35 
36 /**
37  * Application Compatibility Test that launches an application and detects
38  * crashes.
39  */
40 public class AppCompatibility extends InstrumentationTestCase {
41 
42     private static final String TAG = "AppCompability";
43     private static final String PACKAGE_TO_LAUNCH = "package_to_launch";
44     private static final String APP_LAUNCH_TIMEOUT_MSECS = "app_launch_timeout_ms";
45     private static final String WORKSPACE_LAUNCH_TIMEOUT_MSECS = "workspace_launch_timeout_ms";
46 
47     private int mAppLaunchTimeout = 7000;
48     private int mWorkspaceLaunchTimeout = 2000;
49 
50     private Context mContext;
51     private ActivityManager mActivityManager;
52     private PackageManager mPackageManager;
53     private AppCompatibilityRunner mRunner;
54     private Bundle mArgs;
55 
56     @Override
setUp()57     public void setUp() throws Exception {
58         super.setUp();
59         mRunner = (AppCompatibilityRunner) getInstrumentation();
60         assertNotNull("Could not fetch InstrumentationTestRunner.", mRunner);
61 
62         mContext = mRunner.getTargetContext();
63         Assert.assertNotNull("Could not get the Context", mContext);
64 
65         mActivityManager = (ActivityManager)
66                 mContext.getSystemService(Context.ACTIVITY_SERVICE);
67         Assert.assertNotNull("Could not get Activity Manager", mActivityManager);
68 
69         mPackageManager = mContext.getPackageManager();
70         Assert.assertNotNull("Missing Package Manager", mPackageManager);
71 
72         mArgs = mRunner.getBundle();
73 
74         // Parse optional inputs.
75         String appLaunchTimeoutMsecs = mArgs.getString(APP_LAUNCH_TIMEOUT_MSECS);
76         if (appLaunchTimeoutMsecs != null) {
77             mAppLaunchTimeout = Integer.parseInt(appLaunchTimeoutMsecs);
78         }
79         String workspaceLaunchTimeoutMsecs = mArgs.getString(WORKSPACE_LAUNCH_TIMEOUT_MSECS);
80         if (workspaceLaunchTimeoutMsecs != null) {
81             mWorkspaceLaunchTimeout = Integer.parseInt(workspaceLaunchTimeoutMsecs);
82         }
83     }
84 
85     @Override
tearDown()86     protected void tearDown() throws Exception {
87         super.tearDown();
88     }
89 
90     /**
91      * Actual test case that launches the package and throws an exception on the
92      * first error.
93      *
94      * @throws Exception
95      */
testAppStability()96     public void testAppStability() throws Exception {
97         String packageName = mArgs.getString(PACKAGE_TO_LAUNCH);
98         if (packageName != null) {
99             Log.d(TAG, "Launching app " + packageName);
100             ProcessErrorStateInfo err = launchActivity(packageName);
101             // Make sure there are no errors when launching the application,
102             // otherwise raise an
103             // exception with the first error encountered.
104             assertNull(getStackTrace(err), err);
105             assertTrue("App crashed after launch.", processStillUp(packageName));
106         } else {
107             Log.d(TAG, "Missing argument, use " + PACKAGE_TO_LAUNCH +
108                     " to specify the package to launch");
109         }
110     }
111 
112     /**
113      * Gets the stack trace for the error.
114      *
115      * @param in {@link ProcessErrorStateInfo} to parse.
116      * @return {@link String} the long message of the error.
117      */
getStackTrace(ProcessErrorStateInfo in)118     private String getStackTrace(ProcessErrorStateInfo in) {
119         if (in == null) {
120             return null;
121         } else {
122             return in.stackTrace;
123         }
124     }
125 
126     /**
127      * Returns the process name that the package is going to use.
128      *
129      * @param packageName name of the package
130      * @return process name of the package
131      */
getProcessName(String packageName)132     private String getProcessName(String packageName) {
133         try {
134             PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0);
135             return pi.applicationInfo.processName;
136         } catch (NameNotFoundException e) {
137             return packageName;
138         }
139     }
140 
141     /**
142      * Launches and activity and queries for errors.
143      *
144      * @param packageName {@link String} the package name of the application to
145      *            launch.
146      * @return {@link Collection} of {@link ProcessErrorStateInfo} detected
147      *         during the app launch.
148      */
launchActivity(String packageName)149     private ProcessErrorStateInfo launchActivity(String packageName) {
150         // the recommended way to see if this is a tv or not.
151         boolean isleanback = !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
152             && !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
153         Intent homeIntent = new Intent(Intent.ACTION_MAIN);
154         homeIntent.addCategory(Intent.CATEGORY_HOME);
155         homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
156         Intent intent;
157         if (isleanback) {
158             Log.d(TAG, "Leanback and relax! " + packageName);
159             intent = mPackageManager.getLeanbackLaunchIntentForPackage(packageName);
160         } else {
161             intent = mPackageManager.getLaunchIntentForPackage(packageName);
162         }
163         assertNotNull("Skipping " + packageName + "; missing launch intent", intent);
164 
165         String processName = getProcessName(packageName);
166 
167         // Launch Activity
168         mContext.startActivity(intent);
169 
170         try {
171             Thread.sleep(mAppLaunchTimeout);
172         } catch (InterruptedException e) {
173             // ignore
174         }
175 
176         // Send the "home" intent and wait 2 seconds for us to get there
177         mContext.startActivity(homeIntent);
178         try {
179             Thread.sleep(mWorkspaceLaunchTimeout);
180         } catch (InterruptedException e) {
181             // ignore
182         }
183 
184         // See if there are any errors. We wait until down here to give ANRs as
185         // much time as
186         // possible to occur.
187         final Collection<ProcessErrorStateInfo> postErr =
188                 mActivityManager.getProcessesInErrorState();
189 
190         if (postErr == null) {
191             return null;
192         }
193         for (ProcessErrorStateInfo error : postErr) {
194             if (error.processName.equals(processName)) {
195                 return error;
196             }
197         }
198         return null;
199     }
200 
201     /**
202      * Determine if a given package is still running.
203      *
204      * @param packageName {@link String} package to look for
205      * @return True if package is running, false otherwise.
206      */
processStillUp(String packageName)207     private boolean processStillUp(String packageName) {
208         String processName = getProcessName(packageName);
209         List<RunningAppProcessInfo> runningApps = mActivityManager.getRunningAppProcesses();
210         for (RunningAppProcessInfo app : runningApps) {
211             if (app.processName.equalsIgnoreCase(processName)) {
212                 Log.d(TAG, "Found process " + app.processName);
213                 return true;
214             }
215             for (String relatedPackage : app.pkgList) {
216                 if (relatedPackage.equalsIgnoreCase(processName)) {
217                     Log.d(TAG, "Found process " + app.processName);
218                     return true;
219                 }
220             }
221         }
222         Log.d(TAG, "Failed to find process " + processName + " with package name "
223                 + packageName);
224         return false;
225     }
226 }
227