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