1d423d8580069520c23e96384ccda272f5692d69dBrett Chabot/* 2d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Copyright (C) 2012 The Android Open Source Project 3d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * 4d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Licensed under the Apache License, Version 2.0 (the "License"); 5d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * you may not use this file except in compliance with the License. 6d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * You may obtain a copy of the License at 7d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * 8d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * http://www.apache.org/licenses/LICENSE-2.0 9d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * 10d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Unless required by applicable law or agreed to in writing, software 11d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * distributed under the License is distributed on an "AS IS" BASIS, 12d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * See the License for the specific language governing permissions and 14d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * limitations under the License. 15d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 16d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 17d423d8580069520c23e96384ccda272f5692d69dBrett Chabotpackage com.android.applaunchtest; 18d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 19d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.app.ActivityManager; 20d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.app.ActivityManager.ProcessErrorStateInfo; 21d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.content.ComponentName; 22d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.content.Context; 23d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.content.Intent; 24d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.content.pm.PackageManager; 25d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.content.pm.ResolveInfo; 26d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.test.InstrumentationTestCase; 27d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport android.util.Log; 28d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 29d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.ArrayList; 30d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.Collection; 31d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.Iterator; 32d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.LinkedHashSet; 33d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.List; 34d423d8580069520c23e96384ccda272f5692d69dBrett Chabotimport java.util.Set; 35d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 36d423d8580069520c23e96384ccda272f5692d69dBrett Chabot/** 37d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Simple tests that launches a specified app, and waits for a configurable amount of time for 38d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * crashes and ANRs. 39d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * <p/> 40d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * If no crashes occur, test is considered passed. 41d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * <p/> 42d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Derived from frameworks/base/tests/SmokeTests/... . TODO: consider refactoring to share code 43d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 44d423d8580069520c23e96384ccda272f5692d69dBrett Chabotpublic class AppLaunchTest extends InstrumentationTestCase { 45d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 46d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private static final String TAG = "AppLaunchTest"; 47d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 48d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private ActivityManager mActivityManager; 49d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private PackageManager mPackageManager; 50d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private String mPackageName; 51d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private Context mContext; 52d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private long mWaitTime; 53d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 54d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 55d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * {@inheritDoc} 56d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 57d423d8580069520c23e96384ccda272f5692d69dBrett Chabot @Override 58d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public void setUp() throws Exception { 59d423d8580069520c23e96384ccda272f5692d69dBrett Chabot super.setUp(); 60d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mContext = getInstrumentation().getTargetContext(); 61d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull("failed to get context", mContext); 62d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 63d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mActivityManager = (ActivityManager) 64d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mContext.getSystemService(Context.ACTIVITY_SERVICE); 65d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mPackageManager = mContext.getPackageManager(); 66d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull("failed to get activity manager", mActivityManager); 67d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull("failed to get package manager", mPackageManager); 68d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 69d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertTrue("Unexpected runner: AppLaunchRunner must be used", 70d423d8580069520c23e96384ccda272f5692d69dBrett Chabot getInstrumentation() instanceof AppLaunchRunner); 71d423d8580069520c23e96384ccda272f5692d69dBrett Chabot AppLaunchRunner runner = (AppLaunchRunner)getInstrumentation(); 72d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mPackageName = runner.getAppPackageName(); 73d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mWaitTime = runner.getAppWaitTime(); 74d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull("package name to launch was not provided", mPackageName); 75d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull("time to wait for app launch was not provided", mWaitTime); 76d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 77d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 78d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 79d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A test that runs Launcher-launchable activity for given package name and verifies that no 80d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * ANRs or crashes happened while doing so. 81d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 82d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public void testLaunchActivity() throws Exception { 83d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Set<ProcessError> errSet = new LinkedHashSet<ProcessError>(); 84d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 85d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ResolveInfo app = getLauncherActivity(mPackageName, mPackageManager); 86d423d8580069520c23e96384ccda272f5692d69dBrett Chabot assertNotNull(String.format("Could not find launchable activity for %s", mPackageName), 87d423d8580069520c23e96384ccda272f5692d69dBrett Chabot app); 88d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Collection<ProcessError> errProcs = runOneActivity(app, mWaitTime); 89d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (errProcs != null) { 90d423d8580069520c23e96384ccda272f5692d69dBrett Chabot errSet.addAll(errProcs); 91d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 92d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 93d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (!errSet.isEmpty()) { 94d423d8580069520c23e96384ccda272f5692d69dBrett Chabot fail(String.format("Detected %d errors on launch of app %s:\n%s", errSet.size(), 95d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mPackageName, reportWrappedListContents(errSet))); 96d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 97d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 98d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 99d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 100d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A method to run the specified Activity and return a {@link Collection} of the Activities that 101d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * were in an error state, as listed by {@link ActivityManager.getProcessesInErrorState()}. 102d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * <p /> 103d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * The method will launch the app, wait for waitTime seconds, check for apps in the error state 104d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * and then return. 105d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 106d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public Collection<ProcessError> runOneActivity(ResolveInfo app, long appLaunchWait) { 107d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 108d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Log.i(TAG, String.format("Running activity %s/%s", app.activityInfo.packageName, 109d423d8580069520c23e96384ccda272f5692d69dBrett Chabot app.activityInfo.name)); 110d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 111d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // We check for any Crash or ANR dialogs that are already up, and we ignore them. This is 112d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // so that we don't report crashes that were caused by prior apps. 113d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Collection<ProcessError> preErrProcs = 114d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ProcessError.fromCollection(mActivityManager.getProcessesInErrorState()); 115d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 116d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // launch app, and waitfor it to start/settle 117d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Intent intent = intentForActivity(app); 118d423d8580069520c23e96384ccda272f5692d69dBrett Chabot mContext.startActivity(intent); 119d423d8580069520c23e96384ccda272f5692d69dBrett Chabot try { 120d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Thread.sleep(appLaunchWait); 121d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } catch (InterruptedException e) { 122d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // ignore 123d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 124d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 125d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // TODO: inject event to see if app is responding. The smoke tests press 'Home', but 126d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // we don't want to do that here because we want to take screenshot on app launch 127d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 128d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // See if there are any errors. We wait until down here to give ANRs as much time as 129d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // possible to occur. 130d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Collection<ProcessError> errProcs = 131d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ProcessError.fromCollection(mActivityManager.getProcessesInErrorState()); 132d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 133d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // Distinguish the asynchronous crashes/ANRs from the synchronous ones by checking the 134d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // crash package name against the package name for {@code app} 135d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (errProcs != null) { 136d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Iterator<ProcessError> errIter = errProcs.iterator(); 137d423d8580069520c23e96384ccda272f5692d69dBrett Chabot while (errIter.hasNext()) { 138d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ProcessError err = errIter.next(); 139d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (!packageMatches(app, err)) { 140d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // crash in another package. Just log it for now 141d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Log.w(TAG, String.format("Detected crash in %s when launching %s", 142d423d8580069520c23e96384ccda272f5692d69dBrett Chabot err.info.processName, app.activityInfo.packageName)); 143d423d8580069520c23e96384ccda272f5692d69dBrett Chabot errIter.remove(); 144d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 145d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 146d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 147d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // Take the difference between the remaining current error processes and the ones that were 148d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // present when we started. The result is guaranteed to be: 149d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // 1) Errors that are pertinent to this app's package 150d423d8580069520c23e96384ccda272f5692d69dBrett Chabot // 2) Errors that are pertinent to this particular app invocation 151d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (errProcs != null && preErrProcs != null) { 152d423d8580069520c23e96384ccda272f5692d69dBrett Chabot errProcs.removeAll(preErrProcs); 153d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 154d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 155d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return errProcs; 156d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 157d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 158d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 159d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A helper function that checks whether the specified error could have been caused by the 160d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * specified app. 161d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * 162d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * @param app The app to check against 163d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * @param err The error that we're considering 164d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 165d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private static boolean packageMatches(ResolveInfo app, ProcessError err) { 166d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final String appPkg = app.activityInfo.packageName; 167d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final String errPkg = err.info.processName; 168d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Log.d(TAG, String.format("packageMatches(%s, %s)", appPkg, errPkg)); 169d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return appPkg.equals(errPkg); 170d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 171d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 172d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 173d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A helper function to get the launchable activity for the given package name. 174d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 175d423d8580069520c23e96384ccda272f5692d69dBrett Chabot static ResolveInfo getLauncherActivity(String packageName, PackageManager pm) { 176d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Intent launchable = new Intent(Intent.ACTION_MAIN); 177d423d8580069520c23e96384ccda272f5692d69dBrett Chabot launchable.addCategory(Intent.CATEGORY_LAUNCHER); 178d423d8580069520c23e96384ccda272f5692d69dBrett Chabot launchable.setPackage(packageName); 179d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return pm.resolveActivity(launchable, 0); 180d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 181d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 182d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 183d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A helper function to create an {@link Intent} to run, given a {@link ResolveInfo} specifying 184d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * an activity to be launched. 185d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 186d423d8580069520c23e96384ccda272f5692d69dBrett Chabot static Intent intentForActivity(ResolveInfo app) { 187d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final ComponentName component = new ComponentName(app.activityInfo.packageName, 188d423d8580069520c23e96384ccda272f5692d69dBrett Chabot app.activityInfo.name); 189d423d8580069520c23e96384ccda272f5692d69dBrett Chabot final Intent intent = new Intent(Intent.ACTION_MAIN); 190d423d8580069520c23e96384ccda272f5692d69dBrett Chabot intent.setComponent(component); 191d423d8580069520c23e96384ccda272f5692d69dBrett Chabot intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 192d423d8580069520c23e96384ccda272f5692d69dBrett Chabot intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 193d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return intent; 194d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 195d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 196d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 197d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * Report error reports for {@link ProcessErrorStateInfo} instances that are wrapped inside of 198d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * {@link ProcessError} instances. Just unwraps and calls 199d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * {@see reportListContents(Collection<ProcessErrorStateInfo>)}. 200d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 201d423d8580069520c23e96384ccda272f5692d69dBrett Chabot static String reportWrappedListContents(Collection<ProcessError> errList) { 202d423d8580069520c23e96384ccda272f5692d69dBrett Chabot List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size()); 203d423d8580069520c23e96384ccda272f5692d69dBrett Chabot for (ProcessError err : errList) { 204d423d8580069520c23e96384ccda272f5692d69dBrett Chabot newList.add(err.info); 205d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 206d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return reportListContents(newList); 207d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 208d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 209d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 210d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * This helper function will dump the actual error reports. 211d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * 212d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * @param errList The error report containing one or more error records. 213d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * @return Returns a string containing all of the errors. 214d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 215d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private static String reportListContents(Collection<ProcessErrorStateInfo> errList) { 216d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (errList == null) return null; 217d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 218d423d8580069520c23e96384ccda272f5692d69dBrett Chabot StringBuilder builder = new StringBuilder(); 219d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 220d423d8580069520c23e96384ccda272f5692d69dBrett Chabot Iterator<ProcessErrorStateInfo> iter = errList.iterator(); 221d423d8580069520c23e96384ccda272f5692d69dBrett Chabot while (iter.hasNext()) { 222d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ProcessErrorStateInfo entry = iter.next(); 223d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 224d423d8580069520c23e96384ccda272f5692d69dBrett Chabot String condition; 225d423d8580069520c23e96384ccda272f5692d69dBrett Chabot switch (entry.condition) { 226d423d8580069520c23e96384ccda272f5692d69dBrett Chabot case ActivityManager.ProcessErrorStateInfo.CRASHED: 227d423d8580069520c23e96384ccda272f5692d69dBrett Chabot condition = "a CRASH"; 228d423d8580069520c23e96384ccda272f5692d69dBrett Chabot break; 229d423d8580069520c23e96384ccda272f5692d69dBrett Chabot case ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING: 230d423d8580069520c23e96384ccda272f5692d69dBrett Chabot condition = "an ANR"; 231d423d8580069520c23e96384ccda272f5692d69dBrett Chabot break; 232d423d8580069520c23e96384ccda272f5692d69dBrett Chabot default: 233d423d8580069520c23e96384ccda272f5692d69dBrett Chabot condition = "an unknown error"; 234d423d8580069520c23e96384ccda272f5692d69dBrett Chabot break; 235d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 236d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 237d423d8580069520c23e96384ccda272f5692d69dBrett Chabot builder.append(String.format("Process %s encountered %s (%s)", entry.processName, 238d423d8580069520c23e96384ccda272f5692d69dBrett Chabot condition, entry.shortMsg)); 239d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (entry.condition == ActivityManager.ProcessErrorStateInfo.CRASHED) { 240d423d8580069520c23e96384ccda272f5692d69dBrett Chabot builder.append(String.format(" with stack trace:\n%s\n", entry.stackTrace)); 241d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 242d423d8580069520c23e96384ccda272f5692d69dBrett Chabot builder.append("\n"); 243d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 244d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return builder.toString(); 245d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 246d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 247d423d8580069520c23e96384ccda272f5692d69dBrett Chabot /** 248d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent 249d423d8580069520c23e96384ccda272f5692d69dBrett Chabot * crashes are considered equal). 250d423d8580069520c23e96384ccda272f5692d69dBrett Chabot */ 251d423d8580069520c23e96384ccda272f5692d69dBrett Chabot static class ProcessError { 252d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public final ProcessErrorStateInfo info; 253d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 254d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public ProcessError(ProcessErrorStateInfo newInfo) { 255d423d8580069520c23e96384ccda272f5692d69dBrett Chabot info = newInfo; 256d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 257d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 258d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in) 259d423d8580069520c23e96384ccda272f5692d69dBrett Chabot { 260d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (in == null) { 261d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return null; 262d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 263d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 264d423d8580069520c23e96384ccda272f5692d69dBrett Chabot List<ProcessError> out = new ArrayList<ProcessError>(in.size()); 265d423d8580069520c23e96384ccda272f5692d69dBrett Chabot for (ProcessErrorStateInfo info : in) { 266d423d8580069520c23e96384ccda272f5692d69dBrett Chabot out.add(new ProcessError(info)); 267d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 268d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return out; 269d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 270d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 271d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private boolean strEquals(String a, String b) { 272d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if ((a == null) && (b == null)) { 273d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return true; 274d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } else if ((a == null) || (b == null)) { 275d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return false; 276d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } else { 277d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return a.equals(b); 278d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 279d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 280d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 281d423d8580069520c23e96384ccda272f5692d69dBrett Chabot @Override 282d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public boolean equals(Object other) { 283d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (other == null) return false; 284d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (!(other instanceof ProcessError)) return false; 285d423d8580069520c23e96384ccda272f5692d69dBrett Chabot ProcessError peOther = (ProcessError) other; 286d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 287d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return (info.condition == peOther.info.condition) 288d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && strEquals(info.longMsg, peOther.info.longMsg) 289d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && (info.pid == peOther.info.pid) 290d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && strEquals(info.processName, peOther.info.processName) 291d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && strEquals(info.shortMsg, peOther.info.shortMsg) 292d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && strEquals(info.stackTrace, peOther.info.stackTrace) 293d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && strEquals(info.tag, peOther.info.tag) 294d423d8580069520c23e96384ccda272f5692d69dBrett Chabot && (info.uid == peOther.info.uid); 295d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 296d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 297d423d8580069520c23e96384ccda272f5692d69dBrett Chabot private int hash(Object obj) { 298d423d8580069520c23e96384ccda272f5692d69dBrett Chabot if (obj == null) { 299d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return 13; 300d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } else { 301d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return obj.hashCode(); 302d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 303d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 304d423d8580069520c23e96384ccda272f5692d69dBrett Chabot 305d423d8580069520c23e96384ccda272f5692d69dBrett Chabot @Override 306d423d8580069520c23e96384ccda272f5692d69dBrett Chabot public int hashCode() { 307d423d8580069520c23e96384ccda272f5692d69dBrett Chabot int code = 17; 308d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code += info.condition; 309d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code *= hash(info.longMsg); 310d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code += info.pid; 311d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code *= hash(info.processName); 312d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code *= hash(info.shortMsg); 313d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code *= hash(info.stackTrace); 314d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code *= hash(info.tag); 315d423d8580069520c23e96384ccda272f5692d69dBrett Chabot code += info.uid; 316d423d8580069520c23e96384ccda272f5692d69dBrett Chabot return code; 317d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 318d423d8580069520c23e96384ccda272f5692d69dBrett Chabot } 319d423d8580069520c23e96384ccda272f5692d69dBrett Chabot} 320