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