• 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.SystemClock;
28 import android.os.SystemProperties;
29 import android.provider.Settings;
30 import android.util.Printer;
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 = pm.getInstallerPackageName(packageName);
172         ComponentName result = getErrorReportReceiver(pm, packageName, candidate);
173         if (result != null) {
174             return result;
175         }
176 
177         // if the error app is on the system image, look for system apps
178         // error receiver
179         if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
180             candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
181             result = getErrorReportReceiver(pm, packageName, candidate);
182             if (result != null) {
183                 return result;
184             }
185         }
186 
187         // if there is a default receiver, try that
188         candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
189         return getErrorReportReceiver(pm, packageName, candidate);
190     }
191 
192     /**
193      * Return activity in receiverPackage that handles ACTION_APP_ERROR.
194      *
195      * @param pm PackageManager instance
196      * @param errorPackage package which caused the error
197      * @param receiverPackage candidate package to receive the error
198      * @return activity component within receiverPackage which handles
199      * ACTION_APP_ERROR, or null if not found
200      */
getErrorReportReceiver(PackageManager pm, String errorPackage, String receiverPackage)201     static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,
202             String receiverPackage) {
203         if (receiverPackage == null || receiverPackage.length() == 0) {
204             return null;
205         }
206 
207         // break the loop if it's the error report receiver package that crashed
208         if (receiverPackage.equals(errorPackage)) {
209             return null;
210         }
211 
212         Intent intent = new Intent(Intent.ACTION_APP_ERROR);
213         intent.setPackage(receiverPackage);
214         ResolveInfo info = pm.resolveActivity(intent, 0);
215         if (info == null || info.activityInfo == null) {
216             return null;
217         }
218         return new ComponentName(receiverPackage, info.activityInfo.name);
219     }
220 
writeToParcel(Parcel dest, int flags)221     public void writeToParcel(Parcel dest, int flags) {
222         dest.writeInt(type);
223         dest.writeString(packageName);
224         dest.writeString(installerPackageName);
225         dest.writeString(processName);
226         dest.writeLong(time);
227         dest.writeInt(systemApp ? 1 : 0);
228 
229         switch (type) {
230             case TYPE_CRASH:
231                 crashInfo.writeToParcel(dest, flags);
232                 break;
233             case TYPE_ANR:
234                 anrInfo.writeToParcel(dest, flags);
235                 break;
236             case TYPE_BATTERY:
237                 batteryInfo.writeToParcel(dest, flags);
238                 break;
239             case TYPE_RUNNING_SERVICE:
240                 runningServiceInfo.writeToParcel(dest, flags);
241                 break;
242         }
243     }
244 
readFromParcel(Parcel in)245     public void readFromParcel(Parcel in) {
246         type = in.readInt();
247         packageName = in.readString();
248         installerPackageName = in.readString();
249         processName = in.readString();
250         time = in.readLong();
251         systemApp = in.readInt() == 1;
252 
253         switch (type) {
254             case TYPE_CRASH:
255                 crashInfo = new CrashInfo(in);
256                 anrInfo = null;
257                 batteryInfo = null;
258                 runningServiceInfo = null;
259                 break;
260             case TYPE_ANR:
261                 anrInfo = new AnrInfo(in);
262                 crashInfo = null;
263                 batteryInfo = null;
264                 runningServiceInfo = null;
265                 break;
266             case TYPE_BATTERY:
267                 batteryInfo = new BatteryInfo(in);
268                 anrInfo = null;
269                 crashInfo = null;
270                 runningServiceInfo = null;
271                 break;
272             case TYPE_RUNNING_SERVICE:
273                 batteryInfo = null;
274                 anrInfo = null;
275                 crashInfo = null;
276                 runningServiceInfo = new RunningServiceInfo(in);
277                 break;
278         }
279     }
280 
281     /**
282      * Describes an application crash.
283      */
284     public static class CrashInfo {
285         /**
286          * Class name of the exception that caused the crash.
287          */
288         public String exceptionClassName;
289 
290         /**
291          * Message stored in the exception.
292          */
293         public String exceptionMessage;
294 
295         /**
296          * File which the exception was thrown from.
297          */
298         public String throwFileName;
299 
300         /**
301          * Class which the exception was thrown from.
302          */
303         public String throwClassName;
304 
305         /**
306          * Method which the exception was thrown from.
307          */
308         public String throwMethodName;
309 
310         /**
311          * Line number the exception was thrown from.
312          */
313         public int throwLineNumber;
314 
315         /**
316          * Stack trace.
317          */
318         public String stackTrace;
319 
320         /**
321          * Create an uninitialized instance of CrashInfo.
322          */
CrashInfo()323         public CrashInfo() {
324         }
325 
326         /**
327          * Create an instance of CrashInfo initialized from an exception.
328          */
CrashInfo(Throwable tr)329         public CrashInfo(Throwable tr) {
330             StringWriter sw = new StringWriter();
331             PrintWriter pw = new FastPrintWriter(sw, false, 256);
332             tr.printStackTrace(pw);
333             pw.flush();
334             stackTrace = sw.toString();
335             exceptionMessage = tr.getMessage();
336 
337             // Populate fields with the "root cause" exception
338             Throwable rootTr = tr;
339             while (tr.getCause() != null) {
340                 tr = tr.getCause();
341                 if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {
342                     rootTr = tr;
343                 }
344                 String msg = tr.getMessage();
345                 if (msg != null && msg.length() > 0) {
346                     exceptionMessage = msg;
347                 }
348             }
349 
350             exceptionClassName = rootTr.getClass().getName();
351             if (rootTr.getStackTrace().length > 0) {
352                 StackTraceElement trace = rootTr.getStackTrace()[0];
353                 throwFileName = trace.getFileName();
354                 throwClassName = trace.getClassName();
355                 throwMethodName = trace.getMethodName();
356                 throwLineNumber = trace.getLineNumber();
357             } else {
358                 throwFileName = "unknown";
359                 throwClassName = "unknown";
360                 throwMethodName = "unknown";
361                 throwLineNumber = 0;
362             }
363         }
364 
365         /**
366          * Create an instance of CrashInfo initialized from a Parcel.
367          */
CrashInfo(Parcel in)368         public CrashInfo(Parcel in) {
369             exceptionClassName = in.readString();
370             exceptionMessage = in.readString();
371             throwFileName = in.readString();
372             throwClassName = in.readString();
373             throwMethodName = in.readString();
374             throwLineNumber = in.readInt();
375             stackTrace = in.readString();
376         }
377 
378         /**
379          * Save a CrashInfo instance to a parcel.
380          */
writeToParcel(Parcel dest, int flags)381         public void writeToParcel(Parcel dest, int flags) {
382             dest.writeString(exceptionClassName);
383             dest.writeString(exceptionMessage);
384             dest.writeString(throwFileName);
385             dest.writeString(throwClassName);
386             dest.writeString(throwMethodName);
387             dest.writeInt(throwLineNumber);
388             dest.writeString(stackTrace);
389         }
390 
391         /**
392          * Dump a CrashInfo instance to a Printer.
393          */
dump(Printer pw, String prefix)394         public void dump(Printer pw, String prefix) {
395             pw.println(prefix + "exceptionClassName: " + exceptionClassName);
396             pw.println(prefix + "exceptionMessage: " + exceptionMessage);
397             pw.println(prefix + "throwFileName: " + throwFileName);
398             pw.println(prefix + "throwClassName: " + throwClassName);
399             pw.println(prefix + "throwMethodName: " + throwMethodName);
400             pw.println(prefix + "throwLineNumber: " + throwLineNumber);
401             pw.println(prefix + "stackTrace: " + stackTrace);
402         }
403     }
404 
405     /**
406      * Describes an application not responding error.
407      */
408     public static class AnrInfo {
409         /**
410          * Activity name.
411          */
412         public String activity;
413 
414         /**
415          * Description of the operation that timed out.
416          */
417         public String cause;
418 
419         /**
420          * Additional info, including CPU stats.
421          */
422         public String info;
423 
424         /**
425          * Create an uninitialized instance of AnrInfo.
426          */
AnrInfo()427         public AnrInfo() {
428         }
429 
430         /**
431          * Create an instance of AnrInfo initialized from a Parcel.
432          */
AnrInfo(Parcel in)433         public AnrInfo(Parcel in) {
434             activity = in.readString();
435             cause = in.readString();
436             info = in.readString();
437         }
438 
439         /**
440          * Save an AnrInfo instance to a parcel.
441          */
writeToParcel(Parcel dest, int flags)442         public void writeToParcel(Parcel dest, int flags) {
443             dest.writeString(activity);
444             dest.writeString(cause);
445             dest.writeString(info);
446         }
447 
448         /**
449          * Dump an AnrInfo instance to a Printer.
450          */
dump(Printer pw, String prefix)451         public void dump(Printer pw, String prefix) {
452             pw.println(prefix + "activity: " + activity);
453             pw.println(prefix + "cause: " + cause);
454             pw.println(prefix + "info: " + info);
455         }
456     }
457 
458     /**
459      * Describes a battery usage report.
460      */
461     public static class BatteryInfo {
462         /**
463          * Percentage of the battery that was used up by the process.
464          */
465         public int usagePercent;
466 
467         /**
468          * Duration in microseconds over which the process used the above
469          * percentage of battery.
470          */
471         public long durationMicros;
472 
473         /**
474          * Dump of various info impacting battery use.
475          */
476         public String usageDetails;
477 
478         /**
479          * Checkin details.
480          */
481         public String checkinDetails;
482 
483         /**
484          * Create an uninitialized instance of BatteryInfo.
485          */
BatteryInfo()486         public BatteryInfo() {
487         }
488 
489         /**
490          * Create an instance of BatteryInfo initialized from a Parcel.
491          */
BatteryInfo(Parcel in)492         public BatteryInfo(Parcel in) {
493             usagePercent = in.readInt();
494             durationMicros = in.readLong();
495             usageDetails = in.readString();
496             checkinDetails = in.readString();
497         }
498 
499         /**
500          * Save a BatteryInfo instance to a parcel.
501          */
writeToParcel(Parcel dest, int flags)502         public void writeToParcel(Parcel dest, int flags) {
503             dest.writeInt(usagePercent);
504             dest.writeLong(durationMicros);
505             dest.writeString(usageDetails);
506             dest.writeString(checkinDetails);
507         }
508 
509         /**
510          * Dump a BatteryInfo instance to a Printer.
511          */
dump(Printer pw, String prefix)512         public void dump(Printer pw, String prefix) {
513             pw.println(prefix + "usagePercent: " + usagePercent);
514             pw.println(prefix + "durationMicros: " + durationMicros);
515             pw.println(prefix + "usageDetails: " + usageDetails);
516             pw.println(prefix + "checkinDetails: " + checkinDetails);
517         }
518     }
519 
520     /**
521      * Describes a running service report.
522      */
523     public static class RunningServiceInfo {
524         /**
525          * Duration in milliseconds that the service has been running.
526          */
527         public long durationMillis;
528 
529         /**
530          * Dump of debug information about the service.
531          */
532         public String serviceDetails;
533 
534         /**
535          * Create an uninitialized instance of RunningServiceInfo.
536          */
RunningServiceInfo()537         public RunningServiceInfo() {
538         }
539 
540         /**
541          * Create an instance of RunningServiceInfo initialized from a Parcel.
542          */
RunningServiceInfo(Parcel in)543         public RunningServiceInfo(Parcel in) {
544             durationMillis = in.readLong();
545             serviceDetails = in.readString();
546         }
547 
548         /**
549          * Save a RunningServiceInfo instance to a parcel.
550          */
writeToParcel(Parcel dest, int flags)551         public void writeToParcel(Parcel dest, int flags) {
552             dest.writeLong(durationMillis);
553             dest.writeString(serviceDetails);
554         }
555 
556         /**
557          * Dump a BatteryInfo instance to a Printer.
558          */
dump(Printer pw, String prefix)559         public void dump(Printer pw, String prefix) {
560             pw.println(prefix + "durationMillis: " + durationMillis);
561             pw.println(prefix + "serviceDetails: " + serviceDetails);
562         }
563     }
564 
565     public static final Parcelable.Creator<ApplicationErrorReport> CREATOR
566             = new Parcelable.Creator<ApplicationErrorReport>() {
567         public ApplicationErrorReport createFromParcel(Parcel source) {
568             return new ApplicationErrorReport(source);
569         }
570 
571         public ApplicationErrorReport[] newArray(int size) {
572             return new ApplicationErrorReport[size];
573         }
574     };
575 
describeContents()576     public int describeContents() {
577         return 0;
578     }
579 
580     /**
581      * Dump the report to a Printer.
582      */
dump(Printer pw, String prefix)583     public void dump(Printer pw, String prefix) {
584         pw.println(prefix + "type: " + type);
585         pw.println(prefix + "packageName: " + packageName);
586         pw.println(prefix + "installerPackageName: " + installerPackageName);
587         pw.println(prefix + "processName: " + processName);
588         pw.println(prefix + "time: " + time);
589         pw.println(prefix + "systemApp: " + systemApp);
590 
591         switch (type) {
592             case TYPE_CRASH:
593                 crashInfo.dump(pw, prefix);
594                 break;
595             case TYPE_ANR:
596                 anrInfo.dump(pw, prefix);
597                 break;
598             case TYPE_BATTERY:
599                 batteryInfo.dump(pw, prefix);
600                 break;
601             case TYPE_RUNNING_SERVICE:
602                 runningServiceInfo.dump(pw, prefix);
603                 break;
604         }
605     }
606 }
607