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