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