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