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