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 
239         switch (type) {
240             case TYPE_CRASH:
241                 crashInfo.writeToParcel(dest, flags);
242                 break;
243             case TYPE_ANR:
244                 anrInfo.writeToParcel(dest, flags);
245                 break;
246             case TYPE_BATTERY:
247                 batteryInfo.writeToParcel(dest, flags);
248                 break;
249             case TYPE_RUNNING_SERVICE:
250                 runningServiceInfo.writeToParcel(dest, flags);
251                 break;
252         }
253     }
254 
readFromParcel(Parcel in)255     public void readFromParcel(Parcel in) {
256         type = in.readInt();
257         packageName = in.readString();
258         installerPackageName = in.readString();
259         processName = in.readString();
260         time = in.readLong();
261         systemApp = in.readInt() == 1;
262 
263         switch (type) {
264             case TYPE_CRASH:
265                 crashInfo = new CrashInfo(in);
266                 anrInfo = null;
267                 batteryInfo = null;
268                 runningServiceInfo = null;
269                 break;
270             case TYPE_ANR:
271                 anrInfo = new AnrInfo(in);
272                 crashInfo = null;
273                 batteryInfo = null;
274                 runningServiceInfo = null;
275                 break;
276             case TYPE_BATTERY:
277                 batteryInfo = new BatteryInfo(in);
278                 anrInfo = null;
279                 crashInfo = null;
280                 runningServiceInfo = null;
281                 break;
282             case TYPE_RUNNING_SERVICE:
283                 batteryInfo = null;
284                 anrInfo = null;
285                 crashInfo = null;
286                 runningServiceInfo = new RunningServiceInfo(in);
287                 break;
288         }
289     }
290 
291     /**
292      * Describes an application crash.
293      */
294     public static class CrashInfo {
295         /**
296          * Class name of the exception that caused the crash.
297          */
298         public String exceptionClassName;
299 
300         /**
301          * Message stored in the exception.
302          */
303         public String exceptionMessage;
304 
305         /**
306          * File which the exception was thrown from.
307          */
308         public String throwFileName;
309 
310         /**
311          * Class which the exception was thrown from.
312          */
313         public String throwClassName;
314 
315         /**
316          * Method which the exception was thrown from.
317          */
318         public String throwMethodName;
319 
320         /**
321          * Line number the exception was thrown from.
322          */
323         public int throwLineNumber;
324 
325         /**
326          * Stack trace.
327          */
328         public String stackTrace;
329 
330         /**
331          * Create an uninitialized instance of CrashInfo.
332          */
CrashInfo()333         public CrashInfo() {
334         }
335 
336         /**
337          * Create an instance of CrashInfo initialized from an exception.
338          */
CrashInfo(Throwable tr)339         public CrashInfo(Throwable tr) {
340             StringWriter sw = new StringWriter();
341             PrintWriter pw = new FastPrintWriter(sw, false, 256);
342             tr.printStackTrace(pw);
343             pw.flush();
344             stackTrace = sw.toString();
345             exceptionMessage = tr.getMessage();
346 
347             // Populate fields with the "root cause" exception
348             Throwable rootTr = tr;
349             while (tr.getCause() != null) {
350                 tr = tr.getCause();
351                 if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {
352                     rootTr = tr;
353                 }
354                 String msg = tr.getMessage();
355                 if (msg != null && msg.length() > 0) {
356                     exceptionMessage = msg;
357                 }
358             }
359 
360             exceptionClassName = rootTr.getClass().getName();
361             if (rootTr.getStackTrace().length > 0) {
362                 StackTraceElement trace = rootTr.getStackTrace()[0];
363                 throwFileName = trace.getFileName();
364                 throwClassName = trace.getClassName();
365                 throwMethodName = trace.getMethodName();
366                 throwLineNumber = trace.getLineNumber();
367             } else {
368                 throwFileName = "unknown";
369                 throwClassName = "unknown";
370                 throwMethodName = "unknown";
371                 throwLineNumber = 0;
372             }
373         }
374 
375         /**
376          * Create an instance of CrashInfo initialized from a Parcel.
377          */
CrashInfo(Parcel in)378         public CrashInfo(Parcel in) {
379             exceptionClassName = in.readString();
380             exceptionMessage = in.readString();
381             throwFileName = in.readString();
382             throwClassName = in.readString();
383             throwMethodName = in.readString();
384             throwLineNumber = in.readInt();
385             stackTrace = in.readString();
386         }
387 
388         /**
389          * Save a CrashInfo instance to a parcel.
390          */
writeToParcel(Parcel dest, int flags)391         public void writeToParcel(Parcel dest, int flags) {
392             int start = dest.dataPosition();
393             dest.writeString(exceptionClassName);
394             dest.writeString(exceptionMessage);
395             dest.writeString(throwFileName);
396             dest.writeString(throwClassName);
397             dest.writeString(throwMethodName);
398             dest.writeInt(throwLineNumber);
399             dest.writeString(stackTrace);
400             int total = dest.dataPosition()-start;
401             if (total > 20*1024) {
402                 Slog.d("Error", "ERR: exClass=" + exceptionClassName);
403                 Slog.d("Error", "ERR: exMsg=" + exceptionMessage);
404                 Slog.d("Error", "ERR: file=" + throwFileName);
405                 Slog.d("Error", "ERR: class=" + throwClassName);
406                 Slog.d("Error", "ERR: method=" + throwMethodName + " line=" + throwLineNumber);
407                 Slog.d("Error", "ERR: stack=" + stackTrace);
408                 Slog.d("Error", "ERR: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start));
409             }
410         }
411 
412         /**
413          * Dump a CrashInfo instance to a Printer.
414          */
dump(Printer pw, String prefix)415         public void dump(Printer pw, String prefix) {
416             pw.println(prefix + "exceptionClassName: " + exceptionClassName);
417             pw.println(prefix + "exceptionMessage: " + exceptionMessage);
418             pw.println(prefix + "throwFileName: " + throwFileName);
419             pw.println(prefix + "throwClassName: " + throwClassName);
420             pw.println(prefix + "throwMethodName: " + throwMethodName);
421             pw.println(prefix + "throwLineNumber: " + throwLineNumber);
422             pw.println(prefix + "stackTrace: " + stackTrace);
423         }
424     }
425 
426     /**
427      * Describes an application not responding error.
428      */
429     public static class AnrInfo {
430         /**
431          * Activity name.
432          */
433         public String activity;
434 
435         /**
436          * Description of the operation that timed out.
437          */
438         public String cause;
439 
440         /**
441          * Additional info, including CPU stats.
442          */
443         public String info;
444 
445         /**
446          * Create an uninitialized instance of AnrInfo.
447          */
AnrInfo()448         public AnrInfo() {
449         }
450 
451         /**
452          * Create an instance of AnrInfo initialized from a Parcel.
453          */
AnrInfo(Parcel in)454         public AnrInfo(Parcel in) {
455             activity = in.readString();
456             cause = in.readString();
457             info = in.readString();
458         }
459 
460         /**
461          * Save an AnrInfo instance to a parcel.
462          */
writeToParcel(Parcel dest, int flags)463         public void writeToParcel(Parcel dest, int flags) {
464             dest.writeString(activity);
465             dest.writeString(cause);
466             dest.writeString(info);
467         }
468 
469         /**
470          * Dump an AnrInfo instance to a Printer.
471          */
dump(Printer pw, String prefix)472         public void dump(Printer pw, String prefix) {
473             pw.println(prefix + "activity: " + activity);
474             pw.println(prefix + "cause: " + cause);
475             pw.println(prefix + "info: " + info);
476         }
477     }
478 
479     /**
480      * Describes a battery usage report.
481      */
482     public static class BatteryInfo {
483         /**
484          * Percentage of the battery that was used up by the process.
485          */
486         public int usagePercent;
487 
488         /**
489          * Duration in microseconds over which the process used the above
490          * percentage of battery.
491          */
492         public long durationMicros;
493 
494         /**
495          * Dump of various info impacting battery use.
496          */
497         public String usageDetails;
498 
499         /**
500          * Checkin details.
501          */
502         public String checkinDetails;
503 
504         /**
505          * Create an uninitialized instance of BatteryInfo.
506          */
BatteryInfo()507         public BatteryInfo() {
508         }
509 
510         /**
511          * Create an instance of BatteryInfo initialized from a Parcel.
512          */
BatteryInfo(Parcel in)513         public BatteryInfo(Parcel in) {
514             usagePercent = in.readInt();
515             durationMicros = in.readLong();
516             usageDetails = in.readString();
517             checkinDetails = in.readString();
518         }
519 
520         /**
521          * Save a BatteryInfo instance to a parcel.
522          */
writeToParcel(Parcel dest, int flags)523         public void writeToParcel(Parcel dest, int flags) {
524             dest.writeInt(usagePercent);
525             dest.writeLong(durationMicros);
526             dest.writeString(usageDetails);
527             dest.writeString(checkinDetails);
528         }
529 
530         /**
531          * Dump a BatteryInfo instance to a Printer.
532          */
dump(Printer pw, String prefix)533         public void dump(Printer pw, String prefix) {
534             pw.println(prefix + "usagePercent: " + usagePercent);
535             pw.println(prefix + "durationMicros: " + durationMicros);
536             pw.println(prefix + "usageDetails: " + usageDetails);
537             pw.println(prefix + "checkinDetails: " + checkinDetails);
538         }
539     }
540 
541     /**
542      * Describes a running service report.
543      */
544     public static class RunningServiceInfo {
545         /**
546          * Duration in milliseconds that the service has been running.
547          */
548         public long durationMillis;
549 
550         /**
551          * Dump of debug information about the service.
552          */
553         public String serviceDetails;
554 
555         /**
556          * Create an uninitialized instance of RunningServiceInfo.
557          */
RunningServiceInfo()558         public RunningServiceInfo() {
559         }
560 
561         /**
562          * Create an instance of RunningServiceInfo initialized from a Parcel.
563          */
RunningServiceInfo(Parcel in)564         public RunningServiceInfo(Parcel in) {
565             durationMillis = in.readLong();
566             serviceDetails = in.readString();
567         }
568 
569         /**
570          * Save a RunningServiceInfo instance to a parcel.
571          */
writeToParcel(Parcel dest, int flags)572         public void writeToParcel(Parcel dest, int flags) {
573             dest.writeLong(durationMillis);
574             dest.writeString(serviceDetails);
575         }
576 
577         /**
578          * Dump a BatteryInfo instance to a Printer.
579          */
dump(Printer pw, String prefix)580         public void dump(Printer pw, String prefix) {
581             pw.println(prefix + "durationMillis: " + durationMillis);
582             pw.println(prefix + "serviceDetails: " + serviceDetails);
583         }
584     }
585 
586     public static final Parcelable.Creator<ApplicationErrorReport> CREATOR
587             = new Parcelable.Creator<ApplicationErrorReport>() {
588         public ApplicationErrorReport createFromParcel(Parcel source) {
589             return new ApplicationErrorReport(source);
590         }
591 
592         public ApplicationErrorReport[] newArray(int size) {
593             return new ApplicationErrorReport[size];
594         }
595     };
596 
describeContents()597     public int describeContents() {
598         return 0;
599     }
600 
601     /**
602      * Dump the report to a Printer.
603      */
dump(Printer pw, String prefix)604     public void dump(Printer pw, String prefix) {
605         pw.println(prefix + "type: " + type);
606         pw.println(prefix + "packageName: " + packageName);
607         pw.println(prefix + "installerPackageName: " + installerPackageName);
608         pw.println(prefix + "processName: " + processName);
609         pw.println(prefix + "time: " + time);
610         pw.println(prefix + "systemApp: " + systemApp);
611 
612         switch (type) {
613             case TYPE_CRASH:
614                 crashInfo.dump(pw, prefix);
615                 break;
616             case TYPE_ANR:
617                 anrInfo.dump(pw, prefix);
618                 break;
619             case TYPE_BATTERY:
620                 batteryInfo.dump(pw, prefix);
621                 break;
622             case TYPE_RUNNING_SERVICE:
623                 runningServiceInfo.dump(pw, prefix);
624                 break;
625         }
626     }
627 }
628