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