ApplicationErrorReport.java revision 271c2fe0eb36fbf872535bedf3ee8156e3087847
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.SystemClock; 28import android.os.SystemProperties; 29import android.provider.Settings; 30import android.util.Printer; 31 32import java.io.PrintWriter; 33import java.io.StringWriter; 34 35/** 36 * Describes an application error. 37 * 38 * A report has a type, which is one of 39 * <ul> 40 * <li> {@link #TYPE_NONE} uninitialized instance of {@link ApplicationErrorReport}. 41 * <li> {@link #TYPE_CRASH} application crash. Information about the crash 42 * is stored in {@link #crashInfo}. 43 * <li> {@link #TYPE_ANR} application not responding. Information about the 44 * ANR is stored in {@link #anrInfo}. 45 * <li> {@link #TYPE_BATTERY} user reported application is using too much 46 * battery. Information about the battery use is stored in {@link #batteryInfo}. 47 * <li> {@link #TYPE_RUNNING_SERVICE} user reported application is leaving an 48 * unneeded serive running. Information about the battery use is stored in 49 * {@link #runningServiceInfo}. 50 * </ul> 51 */ 52 53public class ApplicationErrorReport implements Parcelable { 54 // System property defining error report receiver for system apps 55 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps"; 56 57 // System property defining default error report receiver 58 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; 59 60 /** 61 * Uninitialized error report. 62 */ 63 public static final int TYPE_NONE = 0; 64 65 /** 66 * An error report about an application crash. 67 */ 68 public static final int TYPE_CRASH = 1; 69 70 /** 71 * An error report about an application that's not responding. 72 */ 73 public static final int TYPE_ANR = 2; 74 75 /** 76 * An error report about an application that's consuming too much battery. 77 */ 78 public static final int TYPE_BATTERY = 3; 79 80 /** 81 * A report from a user to a developer about a running service that the 82 * user doesn't think should be running. 83 */ 84 public static final int TYPE_RUNNING_SERVICE = 5; 85 86 /** 87 * Type of this report. Can be one of {@link #TYPE_NONE}, 88 * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, {@link #TYPE_BATTERY}, 89 * or {@link #TYPE_RUNNING_SERVICE}. 90 */ 91 public int type; 92 93 /** 94 * Package name of the application. 95 */ 96 public String packageName; 97 98 /** 99 * Package name of the application which installed the application this 100 * report pertains to. 101 * This identifies which Market the application came from. 102 */ 103 public String installerPackageName; 104 105 /** 106 * Process name of the application. 107 */ 108 public String processName; 109 110 /** 111 * Time at which the error occurred. 112 */ 113 public long time; 114 115 /** 116 * Set if the app is on the system image. 117 */ 118 public boolean systemApp; 119 120 /** 121 * If this report is of type {@link #TYPE_CRASH}, contains an instance 122 * of CrashInfo describing the crash; otherwise null. 123 */ 124 public CrashInfo crashInfo; 125 126 /** 127 * If this report is of type {@link #TYPE_ANR}, contains an instance 128 * of AnrInfo describing the ANR; otherwise null. 129 */ 130 public AnrInfo anrInfo; 131 132 /** 133 * If this report is of type {@link #TYPE_BATTERY}, contains an instance 134 * of BatteryInfo; otherwise null. 135 */ 136 public BatteryInfo batteryInfo; 137 138 /** 139 * If this report is of type {@link #TYPE_RUNNING_SERVICE}, contains an instance 140 * of RunningServiceInfo; otherwise null. 141 */ 142 public RunningServiceInfo runningServiceInfo; 143 144 /** 145 * Create an uninitialized instance of {@link ApplicationErrorReport}. 146 */ 147 public ApplicationErrorReport() { 148 } 149 150 /** 151 * Create an instance of {@link ApplicationErrorReport} initialized from 152 * a parcel. 153 */ 154 ApplicationErrorReport(Parcel in) { 155 readFromParcel(in); 156 } 157 158 public static ComponentName getErrorReportReceiver(Context context, 159 String packageName, int appFlags) { 160 // check if error reporting is enabled in secure settings 161 int enabled = Settings.Secure.getInt(context.getContentResolver(), 162 Settings.Secure.SEND_ACTION_APP_ERROR, 0); 163 if (enabled == 0) { 164 return null; 165 } 166 167 PackageManager pm = context.getPackageManager(); 168 169 // look for receiver in the installer package 170 String candidate = pm.getInstallerPackageName(packageName); 171 ComponentName result = getErrorReportReceiver(pm, packageName, candidate); 172 if (result != null) { 173 return result; 174 } 175 176 // if the error app is on the system image, look for system apps 177 // error receiver 178 if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { 179 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); 180 result = getErrorReportReceiver(pm, packageName, candidate); 181 if (result != null) { 182 return result; 183 } 184 } 185 186 // if there is a default receiver, try that 187 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY); 188 return getErrorReportReceiver(pm, packageName, candidate); 189 } 190 191 /** 192 * Return activity in receiverPackage that handles ACTION_APP_ERROR. 193 * 194 * @param pm PackageManager instance 195 * @param errorPackage package which caused the error 196 * @param receiverPackage candidate package to receive the error 197 * @return activity component within receiverPackage which handles 198 * ACTION_APP_ERROR, or null if not found 199 */ 200 static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage, 201 String receiverPackage) { 202 if (receiverPackage == null || receiverPackage.length() == 0) { 203 return null; 204 } 205 206 // break the loop if it's the error report receiver package that crashed 207 if (receiverPackage.equals(errorPackage)) { 208 return null; 209 } 210 211 Intent intent = new Intent(Intent.ACTION_APP_ERROR); 212 intent.setPackage(receiverPackage); 213 ResolveInfo info = pm.resolveActivity(intent, 0); 214 if (info == null || info.activityInfo == null) { 215 return null; 216 } 217 return new ComponentName(receiverPackage, info.activityInfo.name); 218 } 219 220 public void writeToParcel(Parcel dest, int flags) { 221 dest.writeInt(type); 222 dest.writeString(packageName); 223 dest.writeString(installerPackageName); 224 dest.writeString(processName); 225 dest.writeLong(time); 226 dest.writeInt(systemApp ? 1 : 0); 227 228 switch (type) { 229 case TYPE_CRASH: 230 crashInfo.writeToParcel(dest, flags); 231 break; 232 case TYPE_ANR: 233 anrInfo.writeToParcel(dest, flags); 234 break; 235 case TYPE_BATTERY: 236 batteryInfo.writeToParcel(dest, flags); 237 break; 238 case TYPE_RUNNING_SERVICE: 239 runningServiceInfo.writeToParcel(dest, flags); 240 break; 241 } 242 } 243 244 public void readFromParcel(Parcel in) { 245 type = in.readInt(); 246 packageName = in.readString(); 247 installerPackageName = in.readString(); 248 processName = in.readString(); 249 time = in.readLong(); 250 systemApp = in.readInt() == 1; 251 252 switch (type) { 253 case TYPE_CRASH: 254 crashInfo = new CrashInfo(in); 255 anrInfo = null; 256 batteryInfo = null; 257 runningServiceInfo = null; 258 break; 259 case TYPE_ANR: 260 anrInfo = new AnrInfo(in); 261 crashInfo = null; 262 batteryInfo = null; 263 runningServiceInfo = null; 264 break; 265 case TYPE_BATTERY: 266 batteryInfo = new BatteryInfo(in); 267 anrInfo = null; 268 crashInfo = null; 269 runningServiceInfo = null; 270 break; 271 case TYPE_RUNNING_SERVICE: 272 batteryInfo = null; 273 anrInfo = null; 274 crashInfo = null; 275 runningServiceInfo = new RunningServiceInfo(in); 276 break; 277 } 278 } 279 280 /** 281 * Describes an application crash. 282 */ 283 public static class CrashInfo { 284 /** 285 * Class name of the exception that caused the crash. 286 */ 287 public String exceptionClassName; 288 289 /** 290 * Message stored in the exception. 291 */ 292 public String exceptionMessage; 293 294 /** 295 * File which the exception was thrown from. 296 */ 297 public String throwFileName; 298 299 /** 300 * Class which the exception was thrown from. 301 */ 302 public String throwClassName; 303 304 /** 305 * Method which the exception was thrown from. 306 */ 307 public String throwMethodName; 308 309 /** 310 * Line number the exception was thrown from. 311 */ 312 public int throwLineNumber; 313 314 /** 315 * Stack trace. 316 */ 317 public String stackTrace; 318 319 /** 320 * Create an uninitialized instance of CrashInfo. 321 */ 322 public CrashInfo() { 323 } 324 325 /** 326 * Create an instance of CrashInfo initialized from an exception. 327 */ 328 public CrashInfo(Throwable tr) { 329 StringWriter sw = new StringWriter(); 330 tr.printStackTrace(new PrintWriter(sw)); 331 stackTrace = sw.toString(); 332 exceptionMessage = tr.getMessage(); 333 334 // Populate fields with the "root cause" exception 335 while (tr.getCause() != null) { 336 tr = tr.getCause(); 337 String msg = tr.getMessage(); 338 if (msg != null && msg.length() > 0) { 339 exceptionMessage = msg; 340 } 341 } 342 343 exceptionClassName = tr.getClass().getName(); 344 StackTraceElement trace = tr.getStackTrace()[0]; 345 throwFileName = trace.getFileName(); 346 throwClassName = trace.getClassName(); 347 throwMethodName = trace.getMethodName(); 348 throwLineNumber = trace.getLineNumber(); 349 } 350 351 /** 352 * Create an instance of CrashInfo initialized from a Parcel. 353 */ 354 public CrashInfo(Parcel in) { 355 exceptionClassName = in.readString(); 356 exceptionMessage = in.readString(); 357 throwFileName = in.readString(); 358 throwClassName = in.readString(); 359 throwMethodName = in.readString(); 360 throwLineNumber = in.readInt(); 361 stackTrace = in.readString(); 362 } 363 364 /** 365 * Save a CrashInfo instance to a parcel. 366 */ 367 public void writeToParcel(Parcel dest, int flags) { 368 dest.writeString(exceptionClassName); 369 dest.writeString(exceptionMessage); 370 dest.writeString(throwFileName); 371 dest.writeString(throwClassName); 372 dest.writeString(throwMethodName); 373 dest.writeInt(throwLineNumber); 374 dest.writeString(stackTrace); 375 } 376 377 /** 378 * Dump a CrashInfo instance to a Printer. 379 */ 380 public void dump(Printer pw, String prefix) { 381 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 382 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 383 pw.println(prefix + "throwFileName: " + throwFileName); 384 pw.println(prefix + "throwClassName: " + throwClassName); 385 pw.println(prefix + "throwMethodName: " + throwMethodName); 386 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 387 pw.println(prefix + "stackTrace: " + stackTrace); 388 } 389 } 390 391 /** 392 * Describes an application not responding error. 393 */ 394 public static class AnrInfo { 395 /** 396 * Activity name. 397 */ 398 public String activity; 399 400 /** 401 * Description of the operation that timed out. 402 */ 403 public String cause; 404 405 /** 406 * Additional info, including CPU stats. 407 */ 408 public String info; 409 410 /** 411 * Create an uninitialized instance of AnrInfo. 412 */ 413 public AnrInfo() { 414 } 415 416 /** 417 * Create an instance of AnrInfo initialized from a Parcel. 418 */ 419 public AnrInfo(Parcel in) { 420 activity = in.readString(); 421 cause = in.readString(); 422 info = in.readString(); 423 } 424 425 /** 426 * Save an AnrInfo instance to a parcel. 427 */ 428 public void writeToParcel(Parcel dest, int flags) { 429 dest.writeString(activity); 430 dest.writeString(cause); 431 dest.writeString(info); 432 } 433 434 /** 435 * Dump an AnrInfo instance to a Printer. 436 */ 437 public void dump(Printer pw, String prefix) { 438 pw.println(prefix + "activity: " + activity); 439 pw.println(prefix + "cause: " + cause); 440 pw.println(prefix + "info: " + info); 441 } 442 } 443 444 /** 445 * Describes a battery usage report. 446 */ 447 public static class BatteryInfo { 448 /** 449 * Percentage of the battery that was used up by the process. 450 */ 451 public int usagePercent; 452 453 /** 454 * Duration in microseconds over which the process used the above 455 * percentage of battery. 456 */ 457 public long durationMicros; 458 459 /** 460 * Dump of various info impacting battery use. 461 */ 462 public String usageDetails; 463 464 /** 465 * Checkin details. 466 */ 467 public String checkinDetails; 468 469 /** 470 * Create an uninitialized instance of BatteryInfo. 471 */ 472 public BatteryInfo() { 473 } 474 475 /** 476 * Create an instance of BatteryInfo initialized from a Parcel. 477 */ 478 public BatteryInfo(Parcel in) { 479 usagePercent = in.readInt(); 480 durationMicros = in.readLong(); 481 usageDetails = in.readString(); 482 checkinDetails = in.readString(); 483 } 484 485 /** 486 * Save a BatteryInfo instance to a parcel. 487 */ 488 public void writeToParcel(Parcel dest, int flags) { 489 dest.writeInt(usagePercent); 490 dest.writeLong(durationMicros); 491 dest.writeString(usageDetails); 492 dest.writeString(checkinDetails); 493 } 494 495 /** 496 * Dump a BatteryInfo instance to a Printer. 497 */ 498 public void dump(Printer pw, String prefix) { 499 pw.println(prefix + "usagePercent: " + usagePercent); 500 pw.println(prefix + "durationMicros: " + durationMicros); 501 pw.println(prefix + "usageDetails: " + usageDetails); 502 pw.println(prefix + "checkinDetails: " + checkinDetails); 503 } 504 } 505 506 /** 507 * Describes a running service report. 508 */ 509 public static class RunningServiceInfo { 510 /** 511 * Duration in milliseconds that the service has been running. 512 */ 513 public long durationMillis; 514 515 /** 516 * Dump of debug information about the service. 517 */ 518 public String serviceDetails; 519 520 /** 521 * Create an uninitialized instance of RunningServiceInfo. 522 */ 523 public RunningServiceInfo() { 524 } 525 526 /** 527 * Create an instance of RunningServiceInfo initialized from a Parcel. 528 */ 529 public RunningServiceInfo(Parcel in) { 530 durationMillis = in.readLong(); 531 serviceDetails = in.readString(); 532 } 533 534 /** 535 * Save a RunningServiceInfo instance to a parcel. 536 */ 537 public void writeToParcel(Parcel dest, int flags) { 538 dest.writeLong(durationMillis); 539 dest.writeString(serviceDetails); 540 } 541 542 /** 543 * Dump a BatteryInfo instance to a Printer. 544 */ 545 public void dump(Printer pw, String prefix) { 546 pw.println(prefix + "durationMillis: " + durationMillis); 547 pw.println(prefix + "serviceDetails: " + serviceDetails); 548 } 549 } 550 551 public static final Parcelable.Creator<ApplicationErrorReport> CREATOR 552 = new Parcelable.Creator<ApplicationErrorReport>() { 553 public ApplicationErrorReport createFromParcel(Parcel source) { 554 return new ApplicationErrorReport(source); 555 } 556 557 public ApplicationErrorReport[] newArray(int size) { 558 return new ApplicationErrorReport[size]; 559 } 560 }; 561 562 public int describeContents() { 563 return 0; 564 } 565 566 /** 567 * Dump the report to a Printer. 568 */ 569 public void dump(Printer pw, String prefix) { 570 pw.println(prefix + "type: " + type); 571 pw.println(prefix + "packageName: " + packageName); 572 pw.println(prefix + "installerPackageName: " + installerPackageName); 573 pw.println(prefix + "processName: " + processName); 574 pw.println(prefix + "time: " + time); 575 pw.println(prefix + "systemApp: " + systemApp); 576 577 switch (type) { 578 case TYPE_CRASH: 579 crashInfo.dump(pw, prefix); 580 break; 581 case TYPE_ANR: 582 anrInfo.dump(pw, prefix); 583 break; 584 case TYPE_BATTERY: 585 batteryInfo.dump(pw, prefix); 586 break; 587 case TYPE_RUNNING_SERVICE: 588 runningServiceInfo.dump(pw, prefix); 589 break; 590 } 591 } 592} 593