1/*
2 * Copyright (C) 2016 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.os;
18
19import android.annotation.RequiresPermission;
20import android.annotation.SystemApi;
21import android.annotation.SystemService;
22import android.annotation.TestApi;
23import android.content.Context;
24import android.os.IIncidentManager;
25import android.os.ServiceManager;
26import android.provider.Settings;
27import android.util.Slog;
28
29/**
30 * Class to take an incident report.
31 *
32 * @hide
33 */
34@SystemApi
35@TestApi
36@SystemService(Context.INCIDENT_SERVICE)
37public class IncidentManager {
38    private static final String TAG = "incident";
39
40    private Context mContext;
41
42    /**
43     * @hide
44     */
45    public IncidentManager(Context context) {
46        mContext = context;
47    }
48
49    /**
50     * Take an incident report and put it in dropbox.
51     */
52    @RequiresPermission(allOf = {
53            android.Manifest.permission.DUMP,
54            android.Manifest.permission.PACKAGE_USAGE_STATS
55    })
56    public void reportIncident(IncidentReportArgs args) {
57        final IIncidentManager service = IIncidentManager.Stub.asInterface(
58                ServiceManager.getService("incident"));
59        if (service == null) {
60            Slog.e(TAG, "reportIncident can't find incident binder service");
61            return;
62        }
63
64        try {
65            service.reportIncident(args);
66        } catch (RemoteException ex) {
67            Slog.e(TAG, "reportIncident failed", ex);
68        }
69    }
70
71    /**
72     * Convenience method to trigger an incident report and put it in dropbox.
73     * <p>
74     * The fields that are reported will be looked up in the system setting named by
75     * the settingName parameter.  The setting must match one of these patterns:
76     *      The string "disabled": The report will not be taken.
77     *      The string "all": The report will taken with all sections.
78     *      The string "none": The report will taken with no sections, but with the header.
79     *      A comma separated list of field numbers: The report will have these fields.
80     * <p>
81     * The header parameter will be added as a header for the incident report.  Fill in a
82     * {@link android.util.proto.ProtoOutputStream ProtoOutputStream}, and then call the
83     * {@link android.util.proto.ProtoOutputStream#bytes bytes()} method to retrieve
84     * the encoded data for the header.
85     */
86    @RequiresPermission(allOf = {
87            android.Manifest.permission.DUMP,
88            android.Manifest.permission.PACKAGE_USAGE_STATS
89    })
90    public void reportIncident(String settingName, byte[] headerProto) {
91        // Sections
92        String setting = Settings.System.getString(mContext.getContentResolver(), settingName);
93        IncidentReportArgs args;
94        try {
95            args = IncidentReportArgs.parseSetting(setting);
96        } catch (IllegalArgumentException ex) {
97            Slog.w(TAG, "Bad value for incident report setting '" + settingName + "'", ex);
98            return;
99        }
100        if (args == null) {
101            Slog.i(TAG, "Incident report requested but disabled: " + settingName);
102            return;
103        }
104
105        // Header
106        args.addHeader(headerProto);
107
108        // Look up the service
109        final IIncidentManager service = IIncidentManager.Stub.asInterface(
110                ServiceManager.getService("incident"));
111        if (service == null) {
112            Slog.e(TAG, "reportIncident can't find incident binder service");
113            return;
114        }
115
116        // Call the service
117        Slog.i(TAG, "Taking incident report: " + settingName);
118        try {
119            service.reportIncident(args);
120        } catch (RemoteException ex) {
121            Slog.e(TAG, "reportIncident failed", ex);
122        }
123    }
124}
125
126