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.SystemClock; 28 import android.os.SystemProperties; 29 import android.provider.Settings; 30 import android.util.Printer; 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 = pm.getInstallerPackageName(packageName); 172 ComponentName result = getErrorReportReceiver(pm, packageName, candidate); 173 if (result != null) { 174 return result; 175 } 176 177 // if the error app is on the system image, look for system apps 178 // error receiver 179 if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) { 180 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); 181 result = getErrorReportReceiver(pm, packageName, candidate); 182 if (result != null) { 183 return result; 184 } 185 } 186 187 // if there is a default receiver, try that 188 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY); 189 return getErrorReportReceiver(pm, packageName, candidate); 190 } 191 192 /** 193 * Return activity in receiverPackage that handles ACTION_APP_ERROR. 194 * 195 * @param pm PackageManager instance 196 * @param errorPackage package which caused the error 197 * @param receiverPackage candidate package to receive the error 198 * @return activity component within receiverPackage which handles 199 * ACTION_APP_ERROR, or null if not found 200 */ getErrorReportReceiver(PackageManager pm, String errorPackage, String receiverPackage)201 static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage, 202 String receiverPackage) { 203 if (receiverPackage == null || receiverPackage.length() == 0) { 204 return null; 205 } 206 207 // break the loop if it's the error report receiver package that crashed 208 if (receiverPackage.equals(errorPackage)) { 209 return null; 210 } 211 212 Intent intent = new Intent(Intent.ACTION_APP_ERROR); 213 intent.setPackage(receiverPackage); 214 ResolveInfo info = pm.resolveActivity(intent, 0); 215 if (info == null || info.activityInfo == null) { 216 return null; 217 } 218 return new ComponentName(receiverPackage, info.activityInfo.name); 219 } 220 writeToParcel(Parcel dest, int flags)221 public void writeToParcel(Parcel dest, int flags) { 222 dest.writeInt(type); 223 dest.writeString(packageName); 224 dest.writeString(installerPackageName); 225 dest.writeString(processName); 226 dest.writeLong(time); 227 dest.writeInt(systemApp ? 1 : 0); 228 229 switch (type) { 230 case TYPE_CRASH: 231 crashInfo.writeToParcel(dest, flags); 232 break; 233 case TYPE_ANR: 234 anrInfo.writeToParcel(dest, flags); 235 break; 236 case TYPE_BATTERY: 237 batteryInfo.writeToParcel(dest, flags); 238 break; 239 case TYPE_RUNNING_SERVICE: 240 runningServiceInfo.writeToParcel(dest, flags); 241 break; 242 } 243 } 244 readFromParcel(Parcel in)245 public void readFromParcel(Parcel in) { 246 type = in.readInt(); 247 packageName = in.readString(); 248 installerPackageName = in.readString(); 249 processName = in.readString(); 250 time = in.readLong(); 251 systemApp = in.readInt() == 1; 252 253 switch (type) { 254 case TYPE_CRASH: 255 crashInfo = new CrashInfo(in); 256 anrInfo = null; 257 batteryInfo = null; 258 runningServiceInfo = null; 259 break; 260 case TYPE_ANR: 261 anrInfo = new AnrInfo(in); 262 crashInfo = null; 263 batteryInfo = null; 264 runningServiceInfo = null; 265 break; 266 case TYPE_BATTERY: 267 batteryInfo = new BatteryInfo(in); 268 anrInfo = null; 269 crashInfo = null; 270 runningServiceInfo = null; 271 break; 272 case TYPE_RUNNING_SERVICE: 273 batteryInfo = null; 274 anrInfo = null; 275 crashInfo = null; 276 runningServiceInfo = new RunningServiceInfo(in); 277 break; 278 } 279 } 280 281 /** 282 * Describes an application crash. 283 */ 284 public static class CrashInfo { 285 /** 286 * Class name of the exception that caused the crash. 287 */ 288 public String exceptionClassName; 289 290 /** 291 * Message stored in the exception. 292 */ 293 public String exceptionMessage; 294 295 /** 296 * File which the exception was thrown from. 297 */ 298 public String throwFileName; 299 300 /** 301 * Class which the exception was thrown from. 302 */ 303 public String throwClassName; 304 305 /** 306 * Method which the exception was thrown from. 307 */ 308 public String throwMethodName; 309 310 /** 311 * Line number the exception was thrown from. 312 */ 313 public int throwLineNumber; 314 315 /** 316 * Stack trace. 317 */ 318 public String stackTrace; 319 320 /** 321 * Create an uninitialized instance of CrashInfo. 322 */ CrashInfo()323 public CrashInfo() { 324 } 325 326 /** 327 * Create an instance of CrashInfo initialized from an exception. 328 */ CrashInfo(Throwable tr)329 public CrashInfo(Throwable tr) { 330 StringWriter sw = new StringWriter(); 331 PrintWriter pw = new FastPrintWriter(sw, false, 256); 332 tr.printStackTrace(pw); 333 pw.flush(); 334 stackTrace = sw.toString(); 335 exceptionMessage = tr.getMessage(); 336 337 // Populate fields with the "root cause" exception 338 Throwable rootTr = tr; 339 while (tr.getCause() != null) { 340 tr = tr.getCause(); 341 if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) { 342 rootTr = tr; 343 } 344 String msg = tr.getMessage(); 345 if (msg != null && msg.length() > 0) { 346 exceptionMessage = msg; 347 } 348 } 349 350 exceptionClassName = rootTr.getClass().getName(); 351 if (rootTr.getStackTrace().length > 0) { 352 StackTraceElement trace = rootTr.getStackTrace()[0]; 353 throwFileName = trace.getFileName(); 354 throwClassName = trace.getClassName(); 355 throwMethodName = trace.getMethodName(); 356 throwLineNumber = trace.getLineNumber(); 357 } else { 358 throwFileName = "unknown"; 359 throwClassName = "unknown"; 360 throwMethodName = "unknown"; 361 throwLineNumber = 0; 362 } 363 } 364 365 /** 366 * Create an instance of CrashInfo initialized from a Parcel. 367 */ CrashInfo(Parcel in)368 public CrashInfo(Parcel in) { 369 exceptionClassName = in.readString(); 370 exceptionMessage = in.readString(); 371 throwFileName = in.readString(); 372 throwClassName = in.readString(); 373 throwMethodName = in.readString(); 374 throwLineNumber = in.readInt(); 375 stackTrace = in.readString(); 376 } 377 378 /** 379 * Save a CrashInfo instance to a parcel. 380 */ writeToParcel(Parcel dest, int flags)381 public void writeToParcel(Parcel dest, int flags) { 382 dest.writeString(exceptionClassName); 383 dest.writeString(exceptionMessage); 384 dest.writeString(throwFileName); 385 dest.writeString(throwClassName); 386 dest.writeString(throwMethodName); 387 dest.writeInt(throwLineNumber); 388 dest.writeString(stackTrace); 389 } 390 391 /** 392 * Dump a CrashInfo instance to a Printer. 393 */ dump(Printer pw, String prefix)394 public void dump(Printer pw, String prefix) { 395 pw.println(prefix + "exceptionClassName: " + exceptionClassName); 396 pw.println(prefix + "exceptionMessage: " + exceptionMessage); 397 pw.println(prefix + "throwFileName: " + throwFileName); 398 pw.println(prefix + "throwClassName: " + throwClassName); 399 pw.println(prefix + "throwMethodName: " + throwMethodName); 400 pw.println(prefix + "throwLineNumber: " + throwLineNumber); 401 pw.println(prefix + "stackTrace: " + stackTrace); 402 } 403 } 404 405 /** 406 * Describes an application not responding error. 407 */ 408 public static class AnrInfo { 409 /** 410 * Activity name. 411 */ 412 public String activity; 413 414 /** 415 * Description of the operation that timed out. 416 */ 417 public String cause; 418 419 /** 420 * Additional info, including CPU stats. 421 */ 422 public String info; 423 424 /** 425 * Create an uninitialized instance of AnrInfo. 426 */ AnrInfo()427 public AnrInfo() { 428 } 429 430 /** 431 * Create an instance of AnrInfo initialized from a Parcel. 432 */ AnrInfo(Parcel in)433 public AnrInfo(Parcel in) { 434 activity = in.readString(); 435 cause = in.readString(); 436 info = in.readString(); 437 } 438 439 /** 440 * Save an AnrInfo instance to a parcel. 441 */ writeToParcel(Parcel dest, int flags)442 public void writeToParcel(Parcel dest, int flags) { 443 dest.writeString(activity); 444 dest.writeString(cause); 445 dest.writeString(info); 446 } 447 448 /** 449 * Dump an AnrInfo instance to a Printer. 450 */ dump(Printer pw, String prefix)451 public void dump(Printer pw, String prefix) { 452 pw.println(prefix + "activity: " + activity); 453 pw.println(prefix + "cause: " + cause); 454 pw.println(prefix + "info: " + info); 455 } 456 } 457 458 /** 459 * Describes a battery usage report. 460 */ 461 public static class BatteryInfo { 462 /** 463 * Percentage of the battery that was used up by the process. 464 */ 465 public int usagePercent; 466 467 /** 468 * Duration in microseconds over which the process used the above 469 * percentage of battery. 470 */ 471 public long durationMicros; 472 473 /** 474 * Dump of various info impacting battery use. 475 */ 476 public String usageDetails; 477 478 /** 479 * Checkin details. 480 */ 481 public String checkinDetails; 482 483 /** 484 * Create an uninitialized instance of BatteryInfo. 485 */ BatteryInfo()486 public BatteryInfo() { 487 } 488 489 /** 490 * Create an instance of BatteryInfo initialized from a Parcel. 491 */ BatteryInfo(Parcel in)492 public BatteryInfo(Parcel in) { 493 usagePercent = in.readInt(); 494 durationMicros = in.readLong(); 495 usageDetails = in.readString(); 496 checkinDetails = in.readString(); 497 } 498 499 /** 500 * Save a BatteryInfo instance to a parcel. 501 */ writeToParcel(Parcel dest, int flags)502 public void writeToParcel(Parcel dest, int flags) { 503 dest.writeInt(usagePercent); 504 dest.writeLong(durationMicros); 505 dest.writeString(usageDetails); 506 dest.writeString(checkinDetails); 507 } 508 509 /** 510 * Dump a BatteryInfo instance to a Printer. 511 */ dump(Printer pw, String prefix)512 public void dump(Printer pw, String prefix) { 513 pw.println(prefix + "usagePercent: " + usagePercent); 514 pw.println(prefix + "durationMicros: " + durationMicros); 515 pw.println(prefix + "usageDetails: " + usageDetails); 516 pw.println(prefix + "checkinDetails: " + checkinDetails); 517 } 518 } 519 520 /** 521 * Describes a running service report. 522 */ 523 public static class RunningServiceInfo { 524 /** 525 * Duration in milliseconds that the service has been running. 526 */ 527 public long durationMillis; 528 529 /** 530 * Dump of debug information about the service. 531 */ 532 public String serviceDetails; 533 534 /** 535 * Create an uninitialized instance of RunningServiceInfo. 536 */ RunningServiceInfo()537 public RunningServiceInfo() { 538 } 539 540 /** 541 * Create an instance of RunningServiceInfo initialized from a Parcel. 542 */ RunningServiceInfo(Parcel in)543 public RunningServiceInfo(Parcel in) { 544 durationMillis = in.readLong(); 545 serviceDetails = in.readString(); 546 } 547 548 /** 549 * Save a RunningServiceInfo instance to a parcel. 550 */ writeToParcel(Parcel dest, int flags)551 public void writeToParcel(Parcel dest, int flags) { 552 dest.writeLong(durationMillis); 553 dest.writeString(serviceDetails); 554 } 555 556 /** 557 * Dump a BatteryInfo instance to a Printer. 558 */ dump(Printer pw, String prefix)559 public void dump(Printer pw, String prefix) { 560 pw.println(prefix + "durationMillis: " + durationMillis); 561 pw.println(prefix + "serviceDetails: " + serviceDetails); 562 } 563 } 564 565 public static final Parcelable.Creator<ApplicationErrorReport> CREATOR 566 = new Parcelable.Creator<ApplicationErrorReport>() { 567 public ApplicationErrorReport createFromParcel(Parcel source) { 568 return new ApplicationErrorReport(source); 569 } 570 571 public ApplicationErrorReport[] newArray(int size) { 572 return new ApplicationErrorReport[size]; 573 } 574 }; 575 describeContents()576 public int describeContents() { 577 return 0; 578 } 579 580 /** 581 * Dump the report to a Printer. 582 */ dump(Printer pw, String prefix)583 public void dump(Printer pw, String prefix) { 584 pw.println(prefix + "type: " + type); 585 pw.println(prefix + "packageName: " + packageName); 586 pw.println(prefix + "installerPackageName: " + installerPackageName); 587 pw.println(prefix + "processName: " + processName); 588 pw.println(prefix + "time: " + time); 589 pw.println(prefix + "systemApp: " + systemApp); 590 591 switch (type) { 592 case TYPE_CRASH: 593 crashInfo.dump(pw, prefix); 594 break; 595 case TYPE_ANR: 596 anrInfo.dump(pw, prefix); 597 break; 598 case TYPE_BATTERY: 599 batteryInfo.dump(pw, prefix); 600 break; 601 case TYPE_RUNNING_SERVICE: 602 runningServiceInfo.dump(pw, prefix); 603 break; 604 } 605 } 606 } 607