• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = sanitizeString(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             exceptionMessage = sanitizeString(exceptionMessage);
379         }
380 
381         /**
382          * Ensure that the string is of reasonable size, truncating from the middle if needed.
383          */
sanitizeString(String s)384         private String sanitizeString(String s) {
385             int prefixLength = 10 * 1024;
386             int suffixLength = 10 * 1024;
387             int acceptableLength = prefixLength + suffixLength;
388 
389             if (s != null && s.length() > acceptableLength) {
390                 String replacement =
391                         "\n[TRUNCATED " + (s.length() - acceptableLength) + " CHARS]\n";
392 
393                 StringBuilder sb = new StringBuilder(acceptableLength + replacement.length());
394                 sb.append(s.substring(0, prefixLength));
395                 sb.append(replacement);
396                 sb.append(s.substring(s.length() - suffixLength));
397                 return sb.toString();
398             }
399             return s;
400         }
401 
402         /**
403          * Create an instance of CrashInfo initialized from a Parcel.
404          */
CrashInfo(Parcel in)405         public CrashInfo(Parcel in) {
406             exceptionClassName = in.readString();
407             exceptionMessage = in.readString();
408             throwFileName = in.readString();
409             throwClassName = in.readString();
410             throwMethodName = in.readString();
411             throwLineNumber = in.readInt();
412             stackTrace = in.readString();
413         }
414 
415         /**
416          * Save a CrashInfo instance to a parcel.
417          */
writeToParcel(Parcel dest, int flags)418         public void writeToParcel(Parcel dest, int flags) {
419             int start = dest.dataPosition();
420             dest.writeString(exceptionClassName);
421             dest.writeString(exceptionMessage);
422             dest.writeString(throwFileName);
423             dest.writeString(throwClassName);
424             dest.writeString(throwMethodName);
425             dest.writeInt(throwLineNumber);
426             dest.writeString(stackTrace);
427             int total = dest.dataPosition()-start;
428             if (total > 20*1024) {
429                 Slog.d("Error", "ERR: exClass=" + exceptionClassName);
430                 Slog.d("Error", "ERR: exMsg=" + exceptionMessage);
431                 Slog.d("Error", "ERR: file=" + throwFileName);
432                 Slog.d("Error", "ERR: class=" + throwClassName);
433                 Slog.d("Error", "ERR: method=" + throwMethodName + " line=" + throwLineNumber);
434                 Slog.d("Error", "ERR: stack=" + stackTrace);
435                 Slog.d("Error", "ERR: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start));
436             }
437         }
438 
439         /**
440          * Dump a CrashInfo instance to a Printer.
441          */
dump(Printer pw, String prefix)442         public void dump(Printer pw, String prefix) {
443             pw.println(prefix + "exceptionClassName: " + exceptionClassName);
444             pw.println(prefix + "exceptionMessage: " + exceptionMessage);
445             pw.println(prefix + "throwFileName: " + throwFileName);
446             pw.println(prefix + "throwClassName: " + throwClassName);
447             pw.println(prefix + "throwMethodName: " + throwMethodName);
448             pw.println(prefix + "throwLineNumber: " + throwLineNumber);
449             pw.println(prefix + "stackTrace: " + stackTrace);
450         }
451     }
452 
453     /**
454      * Describes an application not responding error.
455      */
456     public static class AnrInfo {
457         /**
458          * Activity name.
459          */
460         public String activity;
461 
462         /**
463          * Description of the operation that timed out.
464          */
465         public String cause;
466 
467         /**
468          * Additional info, including CPU stats.
469          */
470         public String info;
471 
472         /**
473          * Create an uninitialized instance of AnrInfo.
474          */
AnrInfo()475         public AnrInfo() {
476         }
477 
478         /**
479          * Create an instance of AnrInfo initialized from a Parcel.
480          */
AnrInfo(Parcel in)481         public AnrInfo(Parcel in) {
482             activity = in.readString();
483             cause = in.readString();
484             info = in.readString();
485         }
486 
487         /**
488          * Save an AnrInfo instance to a parcel.
489          */
writeToParcel(Parcel dest, int flags)490         public void writeToParcel(Parcel dest, int flags) {
491             dest.writeString(activity);
492             dest.writeString(cause);
493             dest.writeString(info);
494         }
495 
496         /**
497          * Dump an AnrInfo instance to a Printer.
498          */
dump(Printer pw, String prefix)499         public void dump(Printer pw, String prefix) {
500             pw.println(prefix + "activity: " + activity);
501             pw.println(prefix + "cause: " + cause);
502             pw.println(prefix + "info: " + info);
503         }
504     }
505 
506     /**
507      * Describes a battery usage report.
508      */
509     public static class BatteryInfo {
510         /**
511          * Percentage of the battery that was used up by the process.
512          */
513         public int usagePercent;
514 
515         /**
516          * Duration in microseconds over which the process used the above
517          * percentage of battery.
518          */
519         public long durationMicros;
520 
521         /**
522          * Dump of various info impacting battery use.
523          */
524         public String usageDetails;
525 
526         /**
527          * Checkin details.
528          */
529         public String checkinDetails;
530 
531         /**
532          * Create an uninitialized instance of BatteryInfo.
533          */
BatteryInfo()534         public BatteryInfo() {
535         }
536 
537         /**
538          * Create an instance of BatteryInfo initialized from a Parcel.
539          */
BatteryInfo(Parcel in)540         public BatteryInfo(Parcel in) {
541             usagePercent = in.readInt();
542             durationMicros = in.readLong();
543             usageDetails = in.readString();
544             checkinDetails = in.readString();
545         }
546 
547         /**
548          * Save a BatteryInfo instance to a parcel.
549          */
writeToParcel(Parcel dest, int flags)550         public void writeToParcel(Parcel dest, int flags) {
551             dest.writeInt(usagePercent);
552             dest.writeLong(durationMicros);
553             dest.writeString(usageDetails);
554             dest.writeString(checkinDetails);
555         }
556 
557         /**
558          * Dump a BatteryInfo instance to a Printer.
559          */
dump(Printer pw, String prefix)560         public void dump(Printer pw, String prefix) {
561             pw.println(prefix + "usagePercent: " + usagePercent);
562             pw.println(prefix + "durationMicros: " + durationMicros);
563             pw.println(prefix + "usageDetails: " + usageDetails);
564             pw.println(prefix + "checkinDetails: " + checkinDetails);
565         }
566     }
567 
568     /**
569      * Describes a running service report.
570      */
571     public static class RunningServiceInfo {
572         /**
573          * Duration in milliseconds that the service has been running.
574          */
575         public long durationMillis;
576 
577         /**
578          * Dump of debug information about the service.
579          */
580         public String serviceDetails;
581 
582         /**
583          * Create an uninitialized instance of RunningServiceInfo.
584          */
RunningServiceInfo()585         public RunningServiceInfo() {
586         }
587 
588         /**
589          * Create an instance of RunningServiceInfo initialized from a Parcel.
590          */
RunningServiceInfo(Parcel in)591         public RunningServiceInfo(Parcel in) {
592             durationMillis = in.readLong();
593             serviceDetails = in.readString();
594         }
595 
596         /**
597          * Save a RunningServiceInfo instance to a parcel.
598          */
writeToParcel(Parcel dest, int flags)599         public void writeToParcel(Parcel dest, int flags) {
600             dest.writeLong(durationMillis);
601             dest.writeString(serviceDetails);
602         }
603 
604         /**
605          * Dump a BatteryInfo instance to a Printer.
606          */
dump(Printer pw, String prefix)607         public void dump(Printer pw, String prefix) {
608             pw.println(prefix + "durationMillis: " + durationMillis);
609             pw.println(prefix + "serviceDetails: " + serviceDetails);
610         }
611     }
612 
613     public static final Parcelable.Creator<ApplicationErrorReport> CREATOR
614             = new Parcelable.Creator<ApplicationErrorReport>() {
615         public ApplicationErrorReport createFromParcel(Parcel source) {
616             return new ApplicationErrorReport(source);
617         }
618 
619         public ApplicationErrorReport[] newArray(int size) {
620             return new ApplicationErrorReport[size];
621         }
622     };
623 
describeContents()624     public int describeContents() {
625         return 0;
626     }
627 
628     /**
629      * Dump the report to a Printer.
630      */
dump(Printer pw, String prefix)631     public void dump(Printer pw, String prefix) {
632         pw.println(prefix + "type: " + type);
633         pw.println(prefix + "packageName: " + packageName);
634         pw.println(prefix + "installerPackageName: " + installerPackageName);
635         pw.println(prefix + "processName: " + processName);
636         pw.println(prefix + "time: " + time);
637         pw.println(prefix + "systemApp: " + systemApp);
638 
639         switch (type) {
640             case TYPE_CRASH:
641                 crashInfo.dump(pw, prefix);
642                 break;
643             case TYPE_ANR:
644                 anrInfo.dump(pw, prefix);
645                 break;
646             case TYPE_BATTERY:
647                 batteryInfo.dump(pw, prefix);
648                 break;
649             case TYPE_RUNNING_SERVICE:
650                 runningServiceInfo.dump(pw, prefix);
651                 break;
652         }
653     }
654 }
655