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