ApplicationErrorReport.java revision 21f1bd17b2dfe361acbb28453b3f3b1a110932fa
1/* 2 * Copyright (C) 2008 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 17package android.app; 18 19import android.content.ComponentName; 20import android.content.Context; 21import android.content.Intent; 22import android.content.pm.ApplicationInfo; 23import android.content.pm.PackageManager; 24import android.content.pm.ResolveInfo; 25import android.os.Parcel; 26import android.os.Parcelable; 27import android.os.SystemProperties; 28import android.provider.Settings; 29import android.util.Printer; 30import java.io.PrintWriter; 31import java.io.StringWriter; 32 33/** 34 * Describes an application error. 35 * 36 * A report has a type, which is one of 37 * <ul> 38 * <li> {@link #TYPE_CRASH} application crash. Information about the crash 39 * is stored in {@link #crashInfo}. 40 * <li> {@link #TYPE_ANR} application not responding. Information about the 41 * ANR is stored in {@link #anrInfo}. 42 * <li> {@link #TYPE_NONE} uninitialized instance of {@link ApplicationErrorReport}. 43 * </ul> 44 * 45 * @hide 46 */ 47 48public class ApplicationErrorReport implements Parcelable { 49 // System property defining error report receiver for system apps 50 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps"; 51 52 // System property defining default error report receiver 53 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; 54 55 56 /** 57 * Uninitialized error report. 58 */ 59 public static final int TYPE_NONE = 0; 60 61 /** 62 * An error report about an application crash. 63 */ 64 public static final int TYPE_CRASH = 1; 65 66 /** 67 * An error report about an application that's not responding. 68 */ 69 public static final int TYPE_ANR = 2; 70 71 /** 72 * An error report about an application that's consuming too much battery. 73 */ 74 public static final int TYPE_BATTERY = 3; 75 76 /** 77 * Type of this report. Can be one of {@link #TYPE_NONE}, 78 * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}. 79 */ 80 public int type; 81 82 /** 83 * Package name of the application. 84 */ 85 public String packageName; 86 87 /** 88 * Package name of the application which installed the application this 89 * report pertains to. 90 * This identifies which Market the application came from. 91 */ 92 public String installerPackageName; 93 94 /** 95 * Process name of the application. 96 */ 97 public String processName; 98 99 /** 100 * Time at which the error occurred. 101 */ 102 public long time; 103 104 /** 105 * Set if the app is on the system image. 106 */ 107 public boolean systemApp; 108 109 /** 110 * If this report is of type {@link #TYPE_CRASH}, contains an instance 111 * of CrashInfo describing the crash; otherwise null. 112 */ 113 public CrashInfo crashInfo; 114 115 /** 116 * If this report is of type {@link #TYPE_ANR}, contains an instance 117 * of AnrInfo describing the ANR; otherwise null. 118 */ 119 public AnrInfo anrInfo; 120 121 /** 122 * Text containing battery usage data. 123 */ 124 public String batteryText; 125 126 /** 127 * Create an uninitialized instance of {@link ApplicationErrorReport}. 128 */ 129 public ApplicationErrorReport() { 130 } 131 132 /** 133 * Create an instance of {@link ApplicationErrorReport} initialized from 134 * a parcel. 135 */ 136 ApplicationErrorReport(Parcel in) { 137 readFromParcel(in); 138 } 139 140 public static ComponentName getErrorReportReceiver(Context context, 141 String packageName, int appFlags) { 142 // check if error reporting is enabled in secure settings 143 int enabled = Settings.Secure.getInt(context.getContentResolver(), 144 Settings.Secure.SEND_ACTION_APP_ERROR, 0); 145 if (enabled == 0) { 146 return null; 147 } 148 149 PackageManager pm = context.getPackageManager(); 150 151 // look for receiver in the installer package 152 String candidate = pm.getInstallerPackageName(packageName); 153 ComponentName result = getErrorReportReceiver(pm, packageName, candidate); 154 if (result != null) { 155 return result; 156 } 157 158 // if the error app is on the system image, look for system apps 159 // error receiver 160 if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { 161 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); 162 result = getErrorReportReceiver(pm, packageName, candidate); 163 if (result != null) { 164 return result; 165 } 166 } 167 168 // if there is a default receiver, try that 169 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY); 170 return getErrorReportReceiver(pm, packageName, candidate); 171 } 172 173 /** 174 * Return activity in receiverPackage that handles ACTION_APP_ERROR. 175 * 176 * @param pm PackageManager isntance 177 * @param errorPackage package which caused the error 178 * @param receiverPackage candidate package to receive the error 179 * @return activity component within receiverPackage which handles 180 * ACTION_APP_ERROR, or null if not found 181 */ 182 static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage, 183 String receiverPackage) { 184 if (receiverPackage == null || receiverPackage.length() == 0) { 185 return null; 186 } 187 188 // break the loop if it's the error report receiver package that crashed 189 if (receiverPackage.equals(errorPackage)) { 190 return null; 191 } 192 193 Intent intent = new Intent(Intent.ACTION_APP_ERROR); 194 intent.setPackage(receiverPackage); 195 ResolveInfo info = pm.resolveActivity(intent, 0); 196 if (info == null || info.activityInfo == null) { 197 return null; 198 } 199 return new ComponentName(receiverPackage, info.activityInfo.name); 200 } 201 202 public void writeToParcel(Parcel dest, int flags) { 203 dest.writeInt(type); 204 dest.writeString(packageName); 205 dest.writeString(installerPackageName); 206 dest.writeString(processName); 207 dest.writeLong(time); 208 dest.writeInt(systemApp ? 1 : 0); 209 210 switch (type) { 211 case TYPE_CRASH: 212 crashInfo.writeToParcel(dest, flags); 213 break; 214 case TYPE_ANR: 215 anrInfo.writeToParcel(dest, flags); 216 break; 217 case TYPE_BATTERY: 218 dest.writeString(batteryText); 219 break; 220 } 221 } 222 223 public void readFromParcel(Parcel in) { 224 type = in.readInt(); 225 packageName = in.readString(); 226 installerPackageName = in.readString(); 227 processName = in.readString(); 228 time = in.readLong(); 229 systemApp = in.readInt() == 1; 230 231 switch (type) { 232 case TYPE_CRASH: 233 crashInfo = new CrashInfo(in); 234 anrInfo = null; 235 batteryText = null; 236 break; 237 case TYPE_ANR: 238 anrInfo = new AnrInfo(in); 239 crashInfo = null; 240 batteryText = null; 241 break; 242 case TYPE_BATTERY: 243 batteryText = in.readString(); 244 anrInfo = null; 245 crashInfo = null; 246 break; 247 } 248 } 249 250 /** 251 * Describes an application crash. 252 */ 253 public static class CrashInfo { 254 /** 255 * Class name of the exception that caused the crash. 256 */ 257 public String exceptionClassName; 258 259 /** 260 * Message stored in the exception. 261 */ 262 public String exceptionMessage; 263 264 /** 265 * File which the exception was thrown from. 266 */ 267 public String throwFileName; 268 269 /** 270 * Class which the exception was thrown from. 271 */ 272 public String throwClassName; 273 274 /** 275 * Method which the exception was thrown from. 276 */ 277 public String throwMethodName; 278 279 /** 280 * Line number the exception was thrown from. 281 */ 282 public int throwLineNumber; 283 284 /** 285 * Stack trace. 286 */ 287 public String stackTrace; 288 289 /** 290 * Create an uninitialized instance of CrashInfo. 291 */ 292 public CrashInfo() { 293 } 294 295 /** 296 * Create an instance of CrashInfo initialized from an exception. 297 */ 298 public CrashInfo(Throwable tr) { 299 StringWriter sw = new StringWriter(); 300 tr.printStackTrace(new PrintWriter(sw)); 301 stackTrace = sw.toString(); 302 exceptionMessage = tr.getMessage(); 303 304 // Populate fields with the "root cause" exception 305 while (tr.getCause() != null) { 306 tr = tr.getCause(); 307 String msg = tr.getMessage(); 308 if (msg != null && msg.length() > 0) { 309 exceptionMessage = msg; 310 } 311 } 312 313 exceptionClassName = tr.getClass().getName(); 314 StackTraceElement trace = tr.getStackTrace()[0]; 315 throwFileName = trace.getFileName(); 316 throwClassName = trace.getClassName(); 317 throwMethodName = trace.getMethodName(); 318 throwLineNumber = trace.getLineNumber(); 319 } 320 321 /** 322 * Create an instance of CrashInfo initialized from a Parcel. 323 */ 324 public CrashInfo(Parcel in) { 325 exceptionClassName = in.readString(); 326 exceptionMessage = in.readString(); 327 throwFileName = in.readString(); 328 throwClassName = in.readString(); 329 throwMethodName = in.readString(); 330 throwLineNumber = in.readInt(); 331 stackTrace = in.readString(); 332 } 333 334 /** 335 * Save a CrashInfo instance to a parcel. 336 */ 337 public void writeToParcel(Parcel dest, int flags) { 338 dest.writeString(exceptionClassName); 339 dest.writeString(exceptionMessage); 340 dest.writeString(throwFileName); 341 dest.writeString(throwClassName); 342 dest.writeString(throwMethodName); 343 dest.writeInt(throwLineNumber); 344 dest.writeString(stackTrace); 345 } 346 347 /** 348 * Dump a CrashInfo instance to a Printer. 349 */ 350 public void dump(Printer pw, String prefix) { 351 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 352 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 353 pw.println(prefix + "throwFileName: " + throwFileName); 354 pw.println(prefix + "throwClassName: " + throwClassName); 355 pw.println(prefix + "throwMethodName: " + throwMethodName); 356 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 357 pw.println(prefix + "stackTrace: " + stackTrace); 358 } 359 } 360 361 /** 362 * Describes an application not responding error. 363 */ 364 public static class AnrInfo { 365 /** 366 * Activity name. 367 */ 368 public String activity; 369 370 /** 371 * Description of the operation that timed out. 372 */ 373 public String cause; 374 375 /** 376 * Additional info, including CPU stats. 377 */ 378 public String info; 379 380 /** 381 * Create an uninitialized instance of AnrInfo. 382 */ 383 public AnrInfo() { 384 } 385 386 /** 387 * Create an instance of AnrInfo initialized from a Parcel. 388 */ 389 public AnrInfo(Parcel in) { 390 activity = in.readString(); 391 cause = in.readString(); 392 info = in.readString(); 393 } 394 395 /** 396 * Save an AnrInfo instance to a parcel. 397 */ 398 public void writeToParcel(Parcel dest, int flags) { 399 dest.writeString(activity); 400 dest.writeString(cause); 401 dest.writeString(info); 402 } 403 404 /** 405 * Dump an AnrInfo instance to a Printer. 406 */ 407 public void dump(Printer pw, String prefix) { 408 pw.println(prefix + "activity: " + activity); 409 pw.println(prefix + "cause: " + cause); 410 pw.println(prefix + "info: " + info); 411 } 412 } 413 414 public static final Parcelable.Creator<ApplicationErrorReport> CREATOR 415 = new Parcelable.Creator<ApplicationErrorReport>() { 416 public ApplicationErrorReport createFromParcel(Parcel source) { 417 return new ApplicationErrorReport(source); 418 } 419 420 public ApplicationErrorReport[] newArray(int size) { 421 return new ApplicationErrorReport[size]; 422 } 423 }; 424 425 public int describeContents() { 426 return 0; 427 } 428 429 /** 430 * Dump the report to a Printer. 431 */ 432 public void dump(Printer pw, String prefix) { 433 pw.println(prefix + "type: " + type); 434 pw.println(prefix + "packageName: " + packageName); 435 pw.println(prefix + "installerPackageName: " + installerPackageName); 436 pw.println(prefix + "processName: " + processName); 437 pw.println(prefix + "time: " + time); 438 pw.println(prefix + "systemApp: " + systemApp); 439 440 switch (type) { 441 case TYPE_CRASH: 442 crashInfo.dump(pw, prefix); 443 break; 444 case TYPE_ANR: 445 anrInfo.dump(pw, prefix); 446 break; 447 case TYPE_BATTERY: 448 pw.println(batteryText); 449 break; 450 } 451 } 452} 453