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