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