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