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