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.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