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 239 switch (type) { 240 case TYPE_CRASH: 241 crashInfo.writeToParcel(dest, flags); 242 break; 243 case TYPE_ANR: 244 anrInfo.writeToParcel(dest, flags); 245 break; 246 case TYPE_BATTERY: 247 batteryInfo.writeToParcel(dest, flags); 248 break; 249 case TYPE_RUNNING_SERVICE: 250 runningServiceInfo.writeToParcel(dest, flags); 251 break; 252 } 253 } 254 readFromParcel(Parcel in)255 public void readFromParcel(Parcel in) { 256 type = in.readInt(); 257 packageName = in.readString(); 258 installerPackageName = in.readString(); 259 processName = in.readString(); 260 time = in.readLong(); 261 systemApp = in.readInt() == 1; 262 263 switch (type) { 264 case TYPE_CRASH: 265 crashInfo = new CrashInfo(in); 266 anrInfo = null; 267 batteryInfo = null; 268 runningServiceInfo = null; 269 break; 270 case TYPE_ANR: 271 anrInfo = new AnrInfo(in); 272 crashInfo = null; 273 batteryInfo = null; 274 runningServiceInfo = null; 275 break; 276 case TYPE_BATTERY: 277 batteryInfo = new BatteryInfo(in); 278 anrInfo = null; 279 crashInfo = null; 280 runningServiceInfo = null; 281 break; 282 case TYPE_RUNNING_SERVICE: 283 batteryInfo = null; 284 anrInfo = null; 285 crashInfo = null; 286 runningServiceInfo = new RunningServiceInfo(in); 287 break; 288 } 289 } 290 291 /** 292 * Describes an application crash. 293 */ 294 public static class CrashInfo { 295 /** 296 * Class name of the exception that caused the crash. 297 */ 298 public String exceptionClassName; 299 300 /** 301 * Message stored in the exception. 302 */ 303 public String exceptionMessage; 304 305 /** 306 * File which the exception was thrown from. 307 */ 308 public String throwFileName; 309 310 /** 311 * Class which the exception was thrown from. 312 */ 313 public String throwClassName; 314 315 /** 316 * Method which the exception was thrown from. 317 */ 318 public String throwMethodName; 319 320 /** 321 * Line number the exception was thrown from. 322 */ 323 public int throwLineNumber; 324 325 /** 326 * Stack trace. 327 */ 328 public String stackTrace; 329 330 /** 331 * Create an uninitialized instance of CrashInfo. 332 */ CrashInfo()333 public CrashInfo() { 334 } 335 336 /** 337 * Create an instance of CrashInfo initialized from an exception. 338 */ CrashInfo(Throwable tr)339 public CrashInfo(Throwable tr) { 340 StringWriter sw = new StringWriter(); 341 PrintWriter pw = new FastPrintWriter(sw, false, 256); 342 tr.printStackTrace(pw); 343 pw.flush(); 344 stackTrace = sw.toString(); 345 exceptionMessage = tr.getMessage(); 346 347 // Populate fields with the "root cause" exception 348 Throwable rootTr = tr; 349 while (tr.getCause() != null) { 350 tr = tr.getCause(); 351 if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) { 352 rootTr = tr; 353 } 354 String msg = tr.getMessage(); 355 if (msg != null && msg.length() > 0) { 356 exceptionMessage = msg; 357 } 358 } 359 360 exceptionClassName = rootTr.getClass().getName(); 361 if (rootTr.getStackTrace().length > 0) { 362 StackTraceElement trace = rootTr.getStackTrace()[0]; 363 throwFileName = trace.getFileName(); 364 throwClassName = trace.getClassName(); 365 throwMethodName = trace.getMethodName(); 366 throwLineNumber = trace.getLineNumber(); 367 } else { 368 throwFileName = "unknown"; 369 throwClassName = "unknown"; 370 throwMethodName = "unknown"; 371 throwLineNumber = 0; 372 } 373 } 374 375 /** 376 * Create an instance of CrashInfo initialized from a Parcel. 377 */ CrashInfo(Parcel in)378 public CrashInfo(Parcel in) { 379 exceptionClassName = in.readString(); 380 exceptionMessage = in.readString(); 381 throwFileName = in.readString(); 382 throwClassName = in.readString(); 383 throwMethodName = in.readString(); 384 throwLineNumber = in.readInt(); 385 stackTrace = in.readString(); 386 } 387 388 /** 389 * Save a CrashInfo instance to a parcel. 390 */ writeToParcel(Parcel dest, int flags)391 public void writeToParcel(Parcel dest, int flags) { 392 int start = dest.dataPosition(); 393 dest.writeString(exceptionClassName); 394 dest.writeString(exceptionMessage); 395 dest.writeString(throwFileName); 396 dest.writeString(throwClassName); 397 dest.writeString(throwMethodName); 398 dest.writeInt(throwLineNumber); 399 dest.writeString(stackTrace); 400 int total = dest.dataPosition()-start; 401 if (total > 20*1024) { 402 Slog.d("Error", "ERR: exClass=" + exceptionClassName); 403 Slog.d("Error", "ERR: exMsg=" + exceptionMessage); 404 Slog.d("Error", "ERR: file=" + throwFileName); 405 Slog.d("Error", "ERR: class=" + throwClassName); 406 Slog.d("Error", "ERR: method=" + throwMethodName + " line=" + throwLineNumber); 407 Slog.d("Error", "ERR: stack=" + stackTrace); 408 Slog.d("Error", "ERR: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start)); 409 } 410 } 411 412 /** 413 * Dump a CrashInfo instance to a Printer. 414 */ dump(Printer pw, String prefix)415 public void dump(Printer pw, String prefix) { 416 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 417 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 418 pw.println(prefix + "throwFileName: " + throwFileName); 419 pw.println(prefix + "throwClassName: " + throwClassName); 420 pw.println(prefix + "throwMethodName: " + throwMethodName); 421 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 422 pw.println(prefix + "stackTrace: " + stackTrace); 423 } 424 } 425 426 /** 427 * Describes an application not responding error. 428 */ 429 public static class AnrInfo { 430 /** 431 * Activity name. 432 */ 433 public String activity; 434 435 /** 436 * Description of the operation that timed out. 437 */ 438 public String cause; 439 440 /** 441 * Additional info, including CPU stats. 442 */ 443 public String info; 444 445 /** 446 * Create an uninitialized instance of AnrInfo. 447 */ AnrInfo()448 public AnrInfo() { 449 } 450 451 /** 452 * Create an instance of AnrInfo initialized from a Parcel. 453 */ AnrInfo(Parcel in)454 public AnrInfo(Parcel in) { 455 activity = in.readString(); 456 cause = in.readString(); 457 info = in.readString(); 458 } 459 460 /** 461 * Save an AnrInfo instance to a parcel. 462 */ writeToParcel(Parcel dest, int flags)463 public void writeToParcel(Parcel dest, int flags) { 464 dest.writeString(activity); 465 dest.writeString(cause); 466 dest.writeString(info); 467 } 468 469 /** 470 * Dump an AnrInfo instance to a Printer. 471 */ dump(Printer pw, String prefix)472 public void dump(Printer pw, String prefix) { 473 pw.println(prefix + "activity: " + activity); 474 pw.println(prefix + "cause: " + cause); 475 pw.println(prefix + "info: " + info); 476 } 477 } 478 479 /** 480 * Describes a battery usage report. 481 */ 482 public static class BatteryInfo { 483 /** 484 * Percentage of the battery that was used up by the process. 485 */ 486 public int usagePercent; 487 488 /** 489 * Duration in microseconds over which the process used the above 490 * percentage of battery. 491 */ 492 public long durationMicros; 493 494 /** 495 * Dump of various info impacting battery use. 496 */ 497 public String usageDetails; 498 499 /** 500 * Checkin details. 501 */ 502 public String checkinDetails; 503 504 /** 505 * Create an uninitialized instance of BatteryInfo. 506 */ BatteryInfo()507 public BatteryInfo() { 508 } 509 510 /** 511 * Create an instance of BatteryInfo initialized from a Parcel. 512 */ BatteryInfo(Parcel in)513 public BatteryInfo(Parcel in) { 514 usagePercent = in.readInt(); 515 durationMicros = in.readLong(); 516 usageDetails = in.readString(); 517 checkinDetails = in.readString(); 518 } 519 520 /** 521 * Save a BatteryInfo instance to a parcel. 522 */ writeToParcel(Parcel dest, int flags)523 public void writeToParcel(Parcel dest, int flags) { 524 dest.writeInt(usagePercent); 525 dest.writeLong(durationMicros); 526 dest.writeString(usageDetails); 527 dest.writeString(checkinDetails); 528 } 529 530 /** 531 * Dump a BatteryInfo instance to a Printer. 532 */ dump(Printer pw, String prefix)533 public void dump(Printer pw, String prefix) { 534 pw.println(prefix + "usagePercent: " + usagePercent); 535 pw.println(prefix + "durationMicros: " + durationMicros); 536 pw.println(prefix + "usageDetails: " + usageDetails); 537 pw.println(prefix + "checkinDetails: " + checkinDetails); 538 } 539 } 540 541 /** 542 * Describes a running service report. 543 */ 544 public static class RunningServiceInfo { 545 /** 546 * Duration in milliseconds that the service has been running. 547 */ 548 public long durationMillis; 549 550 /** 551 * Dump of debug information about the service. 552 */ 553 public String serviceDetails; 554 555 /** 556 * Create an uninitialized instance of RunningServiceInfo. 557 */ RunningServiceInfo()558 public RunningServiceInfo() { 559 } 560 561 /** 562 * Create an instance of RunningServiceInfo initialized from a Parcel. 563 */ RunningServiceInfo(Parcel in)564 public RunningServiceInfo(Parcel in) { 565 durationMillis = in.readLong(); 566 serviceDetails = in.readString(); 567 } 568 569 /** 570 * Save a RunningServiceInfo instance to a parcel. 571 */ writeToParcel(Parcel dest, int flags)572 public void writeToParcel(Parcel dest, int flags) { 573 dest.writeLong(durationMillis); 574 dest.writeString(serviceDetails); 575 } 576 577 /** 578 * Dump a BatteryInfo instance to a Printer. 579 */ dump(Printer pw, String prefix)580 public void dump(Printer pw, String prefix) { 581 pw.println(prefix + "durationMillis: " + durationMillis); 582 pw.println(prefix + "serviceDetails: " + serviceDetails); 583 } 584 } 585 586 public static final Parcelable.Creator<ApplicationErrorReport> CREATOR 587 = new Parcelable.Creator<ApplicationErrorReport>() { 588 public ApplicationErrorReport createFromParcel(Parcel source) { 589 return new ApplicationErrorReport(source); 590 } 591 592 public ApplicationErrorReport[] newArray(int size) { 593 return new ApplicationErrorReport[size]; 594 } 595 }; 596 describeContents()597 public int describeContents() { 598 return 0; 599 } 600 601 /** 602 * Dump the report to a Printer. 603 */ dump(Printer pw, String prefix)604 public void dump(Printer pw, String prefix) { 605 pw.println(prefix + "type: " + type); 606 pw.println(prefix + "packageName: " + packageName); 607 pw.println(prefix + "installerPackageName: " + installerPackageName); 608 pw.println(prefix + "processName: " + processName); 609 pw.println(prefix + "time: " + time); 610 pw.println(prefix + "systemApp: " + systemApp); 611 612 switch (type) { 613 case TYPE_CRASH: 614 crashInfo.dump(pw, prefix); 615 break; 616 case TYPE_ANR: 617 anrInfo.dump(pw, prefix); 618 break; 619 case TYPE_BATTERY: 620 batteryInfo.dump(pw, prefix); 621 break; 622 case TYPE_RUNNING_SERVICE: 623 runningServiceInfo.dump(pw, prefix); 624 break; 625 } 626 } 627 } 628