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