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