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 * Class name of the exception that caused the crash. 303 */ 304 public String exceptionClassName; 305 306 /** 307 * Message stored in the exception. 308 */ 309 public String exceptionMessage; 310 311 /** 312 * File which the exception was thrown from. 313 */ 314 public String throwFileName; 315 316 /** 317 * Class which the exception was thrown from. 318 */ 319 public String throwClassName; 320 321 /** 322 * Method which the exception was thrown from. 323 */ 324 public String throwMethodName; 325 326 /** 327 * Line number the exception was thrown from. 328 */ 329 public int throwLineNumber; 330 331 /** 332 * Stack trace. 333 */ 334 public String stackTrace; 335 336 /** 337 * Crash tag for some context. 338 * @hide 339 */ 340 public String crashTag; 341 342 /** 343 * Create an uninitialized instance of CrashInfo. 344 */ CrashInfo()345 public CrashInfo() { 346 } 347 348 /** 349 * Create an instance of CrashInfo initialized from an exception. 350 */ CrashInfo(Throwable tr)351 public CrashInfo(Throwable tr) { 352 StringWriter sw = new StringWriter(); 353 PrintWriter pw = new FastPrintWriter(sw, false, 256); 354 tr.printStackTrace(pw); 355 pw.flush(); 356 stackTrace = sanitizeString(sw.toString()); 357 exceptionMessage = tr.getMessage(); 358 359 // Populate fields with the "root cause" exception 360 Throwable rootTr = tr; 361 while (tr.getCause() != null) { 362 tr = tr.getCause(); 363 if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) { 364 rootTr = tr; 365 } 366 String msg = tr.getMessage(); 367 if (msg != null && msg.length() > 0) { 368 exceptionMessage = msg; 369 } 370 } 371 372 exceptionClassName = rootTr.getClass().getName(); 373 if (rootTr.getStackTrace().length > 0) { 374 StackTraceElement trace = rootTr.getStackTrace()[0]; 375 throwFileName = trace.getFileName(); 376 throwClassName = trace.getClassName(); 377 throwMethodName = trace.getMethodName(); 378 throwLineNumber = trace.getLineNumber(); 379 } else { 380 throwFileName = "unknown"; 381 throwClassName = "unknown"; 382 throwMethodName = "unknown"; 383 throwLineNumber = 0; 384 } 385 386 exceptionMessage = sanitizeString(exceptionMessage); 387 } 388 389 /** {@hide} */ appendStackTrace(String tr)390 public void appendStackTrace(String tr) { 391 stackTrace = sanitizeString(stackTrace + tr); 392 } 393 394 /** 395 * Ensure that the string is of reasonable size, truncating from the middle if needed. 396 */ sanitizeString(String s)397 private String sanitizeString(String s) { 398 int prefixLength = 10 * 1024; 399 int suffixLength = 10 * 1024; 400 int acceptableLength = prefixLength + suffixLength; 401 402 if (s != null && s.length() > acceptableLength) { 403 String replacement = 404 "\n[TRUNCATED " + (s.length() - acceptableLength) + " CHARS]\n"; 405 406 StringBuilder sb = new StringBuilder(acceptableLength + replacement.length()); 407 sb.append(s.substring(0, prefixLength)); 408 sb.append(replacement); 409 sb.append(s.substring(s.length() - suffixLength)); 410 return sb.toString(); 411 } 412 return s; 413 } 414 415 /** 416 * Create an instance of CrashInfo initialized from a Parcel. 417 */ CrashInfo(Parcel in)418 public CrashInfo(Parcel in) { 419 exceptionClassName = in.readString(); 420 exceptionMessage = in.readString(); 421 throwFileName = in.readString(); 422 throwClassName = in.readString(); 423 throwMethodName = in.readString(); 424 throwLineNumber = in.readInt(); 425 stackTrace = in.readString(); 426 crashTag = in.readString(); 427 } 428 429 /** 430 * Save a CrashInfo instance to a parcel. 431 */ writeToParcel(Parcel dest, int flags)432 public void writeToParcel(Parcel dest, int flags) { 433 int start = dest.dataPosition(); 434 dest.writeString(exceptionClassName); 435 dest.writeString(exceptionMessage); 436 dest.writeString(throwFileName); 437 dest.writeString(throwClassName); 438 dest.writeString(throwMethodName); 439 dest.writeInt(throwLineNumber); 440 dest.writeString(stackTrace); 441 dest.writeString(crashTag); 442 int total = dest.dataPosition()-start; 443 if (Binder.CHECK_PARCEL_SIZE && total > 20*1024) { 444 Slog.d("Error", "ERR: exClass=" + exceptionClassName); 445 Slog.d("Error", "ERR: exMsg=" + exceptionMessage); 446 Slog.d("Error", "ERR: file=" + throwFileName); 447 Slog.d("Error", "ERR: class=" + throwClassName); 448 Slog.d("Error", "ERR: method=" + throwMethodName + " line=" + throwLineNumber); 449 Slog.d("Error", "ERR: stack=" + stackTrace); 450 Slog.d("Error", "ERR: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start)); 451 } 452 } 453 454 /** 455 * Dump a CrashInfo instance to a Printer. 456 */ dump(Printer pw, String prefix)457 public void dump(Printer pw, String prefix) { 458 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 459 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 460 pw.println(prefix + "throwFileName: " + throwFileName); 461 pw.println(prefix + "throwClassName: " + throwClassName); 462 pw.println(prefix + "throwMethodName: " + throwMethodName); 463 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 464 pw.println(prefix + "stackTrace: " + stackTrace); 465 } 466 } 467 468 /** 469 * Parcelable version of {@link CrashInfo} 470 * 471 * @hide 472 */ 473 public static class ParcelableCrashInfo extends CrashInfo implements Parcelable { 474 /** 475 * Create an uninitialized instance of CrashInfo. 476 */ ParcelableCrashInfo()477 public ParcelableCrashInfo() { 478 } 479 480 /** 481 * Create an instance of CrashInfo initialized from an exception. 482 */ ParcelableCrashInfo(Throwable tr)483 public ParcelableCrashInfo(Throwable tr) { 484 super(tr); 485 } 486 ParcelableCrashInfo(Parcel in)487 public ParcelableCrashInfo(Parcel in) { 488 super(in); 489 } 490 describeContents()491 public int describeContents() { 492 return 0; 493 } 494 495 public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCrashInfo> CREATOR = 496 new Parcelable.Creator<ParcelableCrashInfo>() { 497 @Override 498 public ParcelableCrashInfo createFromParcel(Parcel in) { 499 return new ParcelableCrashInfo(in); 500 } 501 502 @Override 503 public ParcelableCrashInfo[] newArray(int size) { 504 return new ParcelableCrashInfo[size]; 505 } 506 }; 507 } 508 509 /** 510 * Describes an application not responding error. 511 */ 512 public static class AnrInfo { 513 /** 514 * Activity name. 515 */ 516 public String activity; 517 518 /** 519 * Description of the operation that timed out. 520 */ 521 public String cause; 522 523 /** 524 * Additional info, including CPU stats. 525 */ 526 public String info; 527 528 /** 529 * Create an uninitialized instance of AnrInfo. 530 */ AnrInfo()531 public AnrInfo() { 532 } 533 534 /** 535 * Create an instance of AnrInfo initialized from a Parcel. 536 */ AnrInfo(Parcel in)537 public AnrInfo(Parcel in) { 538 activity = in.readString(); 539 cause = in.readString(); 540 info = in.readString(); 541 } 542 543 /** 544 * Save an AnrInfo instance to a parcel. 545 */ writeToParcel(Parcel dest, int flags)546 public void writeToParcel(Parcel dest, int flags) { 547 dest.writeString(activity); 548 dest.writeString(cause); 549 dest.writeString(info); 550 } 551 552 /** 553 * Dump an AnrInfo instance to a Printer. 554 */ dump(Printer pw, String prefix)555 public void dump(Printer pw, String prefix) { 556 pw.println(prefix + "activity: " + activity); 557 pw.println(prefix + "cause: " + cause); 558 pw.println(prefix + "info: " + info); 559 } 560 } 561 562 /** 563 * Describes a battery usage report. 564 */ 565 public static class BatteryInfo { 566 /** 567 * Percentage of the battery that was used up by the process. 568 */ 569 public int usagePercent; 570 571 /** 572 * Duration in microseconds over which the process used the above 573 * percentage of battery. 574 */ 575 public long durationMicros; 576 577 /** 578 * Dump of various info impacting battery use. 579 */ 580 public String usageDetails; 581 582 /** 583 * Checkin details. 584 */ 585 public String checkinDetails; 586 587 /** 588 * Create an uninitialized instance of BatteryInfo. 589 */ BatteryInfo()590 public BatteryInfo() { 591 } 592 593 /** 594 * Create an instance of BatteryInfo initialized from a Parcel. 595 */ BatteryInfo(Parcel in)596 public BatteryInfo(Parcel in) { 597 usagePercent = in.readInt(); 598 durationMicros = in.readLong(); 599 usageDetails = in.readString(); 600 checkinDetails = in.readString(); 601 } 602 603 /** 604 * Save a BatteryInfo instance to a parcel. 605 */ writeToParcel(Parcel dest, int flags)606 public void writeToParcel(Parcel dest, int flags) { 607 dest.writeInt(usagePercent); 608 dest.writeLong(durationMicros); 609 dest.writeString(usageDetails); 610 dest.writeString(checkinDetails); 611 } 612 613 /** 614 * Dump a BatteryInfo instance to a Printer. 615 */ dump(Printer pw, String prefix)616 public void dump(Printer pw, String prefix) { 617 pw.println(prefix + "usagePercent: " + usagePercent); 618 pw.println(prefix + "durationMicros: " + durationMicros); 619 pw.println(prefix + "usageDetails: " + usageDetails); 620 pw.println(prefix + "checkinDetails: " + checkinDetails); 621 } 622 } 623 624 /** 625 * Describes a running service report. 626 */ 627 public static class RunningServiceInfo { 628 /** 629 * Duration in milliseconds that the service has been running. 630 */ 631 public long durationMillis; 632 633 /** 634 * Dump of debug information about the service. 635 */ 636 public String serviceDetails; 637 638 /** 639 * Create an uninitialized instance of RunningServiceInfo. 640 */ RunningServiceInfo()641 public RunningServiceInfo() { 642 } 643 644 /** 645 * Create an instance of RunningServiceInfo initialized from a Parcel. 646 */ RunningServiceInfo(Parcel in)647 public RunningServiceInfo(Parcel in) { 648 durationMillis = in.readLong(); 649 serviceDetails = in.readString(); 650 } 651 652 /** 653 * Save a RunningServiceInfo instance to a parcel. 654 */ writeToParcel(Parcel dest, int flags)655 public void writeToParcel(Parcel dest, int flags) { 656 dest.writeLong(durationMillis); 657 dest.writeString(serviceDetails); 658 } 659 660 /** 661 * Dump a BatteryInfo instance to a Printer. 662 */ dump(Printer pw, String prefix)663 public void dump(Printer pw, String prefix) { 664 pw.println(prefix + "durationMillis: " + durationMillis); 665 pw.println(prefix + "serviceDetails: " + serviceDetails); 666 } 667 } 668 669 public static final @android.annotation.NonNull Parcelable.Creator<ApplicationErrorReport> CREATOR 670 = new Parcelable.Creator<ApplicationErrorReport>() { 671 public ApplicationErrorReport createFromParcel(Parcel source) { 672 return new ApplicationErrorReport(source); 673 } 674 675 public ApplicationErrorReport[] newArray(int size) { 676 return new ApplicationErrorReport[size]; 677 } 678 }; 679 describeContents()680 public int describeContents() { 681 return 0; 682 } 683 684 /** 685 * Dump the report to a Printer. 686 */ dump(Printer pw, String prefix)687 public void dump(Printer pw, String prefix) { 688 pw.println(prefix + "type: " + type); 689 pw.println(prefix + "packageName: " + packageName); 690 pw.println(prefix + "installerPackageName: " + installerPackageName); 691 pw.println(prefix + "processName: " + processName); 692 pw.println(prefix + "time: " + time); 693 pw.println(prefix + "systemApp: " + systemApp); 694 695 switch (type) { 696 case TYPE_CRASH: 697 crashInfo.dump(pw, prefix); 698 break; 699 case TYPE_ANR: 700 anrInfo.dump(pw, prefix); 701 break; 702 case TYPE_BATTERY: 703 batteryInfo.dump(pw, prefix); 704 break; 705 case TYPE_RUNNING_SERVICE: 706 runningServiceInfo.dump(pw, prefix); 707 break; 708 } 709 } 710 } 711