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.Parcel; 26 import android.os.Parcelable; 27 import android.os.SystemProperties; 28 import android.provider.Settings; 29 import android.util.Printer; 30 import android.util.Slog; 31 import com.android.internal.util.FastPrintWriter; 32 33 import java.io.PrintWriter; 34 import 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 54 public 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 */ ApplicationErrorReport()148 public ApplicationErrorReport() { 149 } 150 151 /** 152 * Create an instance of {@link ApplicationErrorReport} initialized from 153 * a parcel. 154 */ ApplicationErrorReport(Parcel in)155 ApplicationErrorReport(Parcel in) { 156 readFromParcel(in); 157 } 158 getErrorReportReceiver(Context context, String packageName, int appFlags)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 */ getErrorReportReceiver(PackageManager pm, String errorPackage, String receiverPackage)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 writeToParcel(Parcel dest, int flags)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 readFromParcel(Parcel in)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 */ CrashInfo()337 public CrashInfo() { 338 } 339 340 /** 341 * Create an instance of CrashInfo initialized from an exception. 342 */ CrashInfo(Throwable tr)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 = 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 379 /** 380 * Create an instance of CrashInfo initialized from a Parcel. 381 */ CrashInfo(Parcel in)382 public CrashInfo(Parcel in) { 383 exceptionClassName = in.readString(); 384 exceptionMessage = in.readString(); 385 throwFileName = in.readString(); 386 throwClassName = in.readString(); 387 throwMethodName = in.readString(); 388 throwLineNumber = in.readInt(); 389 stackTrace = in.readString(); 390 } 391 392 /** 393 * Save a CrashInfo instance to a parcel. 394 */ writeToParcel(Parcel dest, int flags)395 public void writeToParcel(Parcel dest, int flags) { 396 int start = dest.dataPosition(); 397 dest.writeString(exceptionClassName); 398 dest.writeString(exceptionMessage); 399 dest.writeString(throwFileName); 400 dest.writeString(throwClassName); 401 dest.writeString(throwMethodName); 402 dest.writeInt(throwLineNumber); 403 dest.writeString(stackTrace); 404 int total = dest.dataPosition()-start; 405 if (total > 20*1024) { 406 Slog.d("Error", "ERR: exClass=" + exceptionClassName); 407 Slog.d("Error", "ERR: exMsg=" + exceptionMessage); 408 Slog.d("Error", "ERR: file=" + throwFileName); 409 Slog.d("Error", "ERR: class=" + throwClassName); 410 Slog.d("Error", "ERR: method=" + throwMethodName + " line=" + throwLineNumber); 411 Slog.d("Error", "ERR: stack=" + stackTrace); 412 Slog.d("Error", "ERR: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start)); 413 } 414 } 415 416 /** 417 * Dump a CrashInfo instance to a Printer. 418 */ dump(Printer pw, String prefix)419 public void dump(Printer pw, String prefix) { 420 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 421 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 422 pw.println(prefix + "throwFileName: " + throwFileName); 423 pw.println(prefix + "throwClassName: " + throwClassName); 424 pw.println(prefix + "throwMethodName: " + throwMethodName); 425 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 426 pw.println(prefix + "stackTrace: " + stackTrace); 427 } 428 } 429 430 /** 431 * Describes an application not responding error. 432 */ 433 public static class AnrInfo { 434 /** 435 * Activity name. 436 */ 437 public String activity; 438 439 /** 440 * Description of the operation that timed out. 441 */ 442 public String cause; 443 444 /** 445 * Additional info, including CPU stats. 446 */ 447 public String info; 448 449 /** 450 * Create an uninitialized instance of AnrInfo. 451 */ AnrInfo()452 public AnrInfo() { 453 } 454 455 /** 456 * Create an instance of AnrInfo initialized from a Parcel. 457 */ AnrInfo(Parcel in)458 public AnrInfo(Parcel in) { 459 activity = in.readString(); 460 cause = in.readString(); 461 info = in.readString(); 462 } 463 464 /** 465 * Save an AnrInfo instance to a parcel. 466 */ writeToParcel(Parcel dest, int flags)467 public void writeToParcel(Parcel dest, int flags) { 468 dest.writeString(activity); 469 dest.writeString(cause); 470 dest.writeString(info); 471 } 472 473 /** 474 * Dump an AnrInfo instance to a Printer. 475 */ dump(Printer pw, String prefix)476 public void dump(Printer pw, String prefix) { 477 pw.println(prefix + "activity: " + activity); 478 pw.println(prefix + "cause: " + cause); 479 pw.println(prefix + "info: " + info); 480 } 481 } 482 483 /** 484 * Describes a battery usage report. 485 */ 486 public static class BatteryInfo { 487 /** 488 * Percentage of the battery that was used up by the process. 489 */ 490 public int usagePercent; 491 492 /** 493 * Duration in microseconds over which the process used the above 494 * percentage of battery. 495 */ 496 public long durationMicros; 497 498 /** 499 * Dump of various info impacting battery use. 500 */ 501 public String usageDetails; 502 503 /** 504 * Checkin details. 505 */ 506 public String checkinDetails; 507 508 /** 509 * Create an uninitialized instance of BatteryInfo. 510 */ BatteryInfo()511 public BatteryInfo() { 512 } 513 514 /** 515 * Create an instance of BatteryInfo initialized from a Parcel. 516 */ BatteryInfo(Parcel in)517 public BatteryInfo(Parcel in) { 518 usagePercent = in.readInt(); 519 durationMicros = in.readLong(); 520 usageDetails = in.readString(); 521 checkinDetails = in.readString(); 522 } 523 524 /** 525 * Save a BatteryInfo instance to a parcel. 526 */ writeToParcel(Parcel dest, int flags)527 public void writeToParcel(Parcel dest, int flags) { 528 dest.writeInt(usagePercent); 529 dest.writeLong(durationMicros); 530 dest.writeString(usageDetails); 531 dest.writeString(checkinDetails); 532 } 533 534 /** 535 * Dump a BatteryInfo instance to a Printer. 536 */ dump(Printer pw, String prefix)537 public void dump(Printer pw, String prefix) { 538 pw.println(prefix + "usagePercent: " + usagePercent); 539 pw.println(prefix + "durationMicros: " + durationMicros); 540 pw.println(prefix + "usageDetails: " + usageDetails); 541 pw.println(prefix + "checkinDetails: " + checkinDetails); 542 } 543 } 544 545 /** 546 * Describes a running service report. 547 */ 548 public static class RunningServiceInfo { 549 /** 550 * Duration in milliseconds that the service has been running. 551 */ 552 public long durationMillis; 553 554 /** 555 * Dump of debug information about the service. 556 */ 557 public String serviceDetails; 558 559 /** 560 * Create an uninitialized instance of RunningServiceInfo. 561 */ RunningServiceInfo()562 public RunningServiceInfo() { 563 } 564 565 /** 566 * Create an instance of RunningServiceInfo initialized from a Parcel. 567 */ RunningServiceInfo(Parcel in)568 public RunningServiceInfo(Parcel in) { 569 durationMillis = in.readLong(); 570 serviceDetails = in.readString(); 571 } 572 573 /** 574 * Save a RunningServiceInfo instance to a parcel. 575 */ writeToParcel(Parcel dest, int flags)576 public void writeToParcel(Parcel dest, int flags) { 577 dest.writeLong(durationMillis); 578 dest.writeString(serviceDetails); 579 } 580 581 /** 582 * Dump a BatteryInfo instance to a Printer. 583 */ dump(Printer pw, String prefix)584 public void dump(Printer pw, String prefix) { 585 pw.println(prefix + "durationMillis: " + durationMillis); 586 pw.println(prefix + "serviceDetails: " + serviceDetails); 587 } 588 } 589 590 public static final Parcelable.Creator<ApplicationErrorReport> CREATOR 591 = new Parcelable.Creator<ApplicationErrorReport>() { 592 public ApplicationErrorReport createFromParcel(Parcel source) { 593 return new ApplicationErrorReport(source); 594 } 595 596 public ApplicationErrorReport[] newArray(int size) { 597 return new ApplicationErrorReport[size]; 598 } 599 }; 600 describeContents()601 public int describeContents() { 602 return 0; 603 } 604 605 /** 606 * Dump the report to a Printer. 607 */ dump(Printer pw, String prefix)608 public void dump(Printer pw, String prefix) { 609 pw.println(prefix + "type: " + type); 610 pw.println(prefix + "packageName: " + packageName); 611 pw.println(prefix + "installerPackageName: " + installerPackageName); 612 pw.println(prefix + "processName: " + processName); 613 pw.println(prefix + "time: " + time); 614 pw.println(prefix + "systemApp: " + systemApp); 615 616 switch (type) { 617 case TYPE_CRASH: 618 crashInfo.dump(pw, prefix); 619 break; 620 case TYPE_ANR: 621 anrInfo.dump(pw, prefix); 622 break; 623 case TYPE_BATTERY: 624 batteryInfo.dump(pw, prefix); 625 break; 626 case TYPE_RUNNING_SERVICE: 627 runningServiceInfo.dump(pw, prefix); 628 break; 629 } 630 } 631 } 632