blob: c5a51f133047964920a01fa23399b1d2f7dc989b [file] [log] [blame]
Nandana Dutt3386fb72018-12-12 17:26:57 +00001/*
2 * Copyright (C) 2019 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.IntDef;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.RequiresPermission;
23import android.annotation.SystemService;
24import android.content.Context;
25import android.os.IBinder.DeathRecipient;
26
27import java.io.FileDescriptor;
28import java.lang.annotation.Retention;
29import java.lang.annotation.RetentionPolicy;
30
31/**
32 * Class that provides a privileged API to capture and consume bugreports.
33 *
34 * @hide
35 */
36// TODO: Expose API when the implementation is more complete.
37// @SystemApi
38@SystemService(Context.BUGREPORT_SERVICE)
39public class BugreportManager {
40 private final Context mContext;
41 private final IDumpstate mBinder;
42
43 /** @hide */
44 public BugreportManager(@NonNull Context context, IDumpstate binder) {
45 mContext = context;
46 mBinder = binder;
47 }
48
49 /**
50 * An interface describing the listener for bugreport progress and status.
51 */
52 public interface BugreportListener {
53 /**
54 * Called when there is a progress update.
55 * @param progress the progress in [0.0, 100.0]
56 */
57 void onProgress(float progress);
58
59 @Retention(RetentionPolicy.SOURCE)
60 @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
61 BUGREPORT_ERROR_INVALID_INPUT,
62 BUGREPORT_ERROR_RUNTIME
63 })
64
65 /** Possible error codes taking a bugreport can encounter */
66 @interface BugreportErrorCode {}
67
68 /** The input options were invalid */
Nandana Dutt161a4462019-01-16 18:18:38 +000069 int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
Nandana Dutt3386fb72018-12-12 17:26:57 +000070
71 /** A runtime error occured */
Nandana Dutt161a4462019-01-16 18:18:38 +000072 int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
73
74 /** User denied consent to share the bugreport */
75 int BUGREPORT_ERROR_USER_DENIED_CONSENT =
76 IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
Nandana Dutt3386fb72018-12-12 17:26:57 +000077
78 /**
79 * Called when taking bugreport resulted in an error.
80 *
81 * @param errorCode the error that occurred. Possible values are
82 * {@code BUGREPORT_ERROR_INVALID_INPUT}, {@code BUGREPORT_ERROR_RUNTIME}.
83 */
84 void onError(@BugreportErrorCode int errorCode);
85
86 /**
87 * Called when taking bugreport finishes successfully
88 *
89 * @param durationMs time capturing bugreport took in milliseconds
90 * @param title title for the bugreport; helpful in reminding the user why they took it
91 * @param description detailed description for the bugreport
92 */
93 void onFinished(long durationMs, @NonNull String title,
94 @NonNull String description);
95 }
96
97 /**
98 * Starts a bugreport asynchronously.
99 *
100 * @param bugreportFd file to write the bugreport. This should be opened in write-only,
101 * append mode.
102 * @param screenshotFd file to write the screenshot, if necessary. This should be opened
103 * in write-only, append mode.
104 * @param params options that specify what kind of a bugreport should be taken
105 * @param listener callback for progress and status updates
106 */
107 @RequiresPermission(android.Manifest.permission.DUMP)
108 public void startBugreport(@NonNull FileDescriptor bugreportFd,
109 @Nullable FileDescriptor screenshotFd,
110 @NonNull BugreportParams params, @Nullable BugreportListener listener) {
111 // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
112 DumpstateListener dsListener = new DumpstateListener(listener);
113
114 try {
Nandana Dutt161a4462019-01-16 18:18:38 +0000115 // Note: mBinder can get callingUid from the binder transaction.
116 mBinder.startBugreport(-1 /* callingUid */,
117 mContext.getOpPackageName(), bugreportFd, screenshotFd,
118 params.getMode(), dsListener);
Nandana Dutt3386fb72018-12-12 17:26:57 +0000119 } catch (RemoteException e) {
120 throw e.rethrowFromSystemServer();
121 }
122 }
123
Nandana Dutt3386fb72018-12-12 17:26:57 +0000124 private final class DumpstateListener extends IDumpstateListener.Stub
125 implements DeathRecipient {
126 private final BugreportListener mListener;
127
128 DumpstateListener(@Nullable BugreportListener listener) {
129 mListener = listener;
130 }
131
132 @Override
133 public void binderDied() {
134 // TODO(b/111441001): implement
135 }
136
137 @Override
Nandana Dutt432f8c72019-01-14 17:39:13 +0000138 public void onProgress(int progress) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000139 mListener.onProgress(progress);
Nandana Dutt432f8c72019-01-14 17:39:13 +0000140 }
141
142 @Override
143 public void onError(int errorCode) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000144 mListener.onError(errorCode);
Nandana Dutt432f8c72019-01-14 17:39:13 +0000145 }
146
147 @Override
148 public void onFinished(long durationMs, String title, String description)
149 throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000150 mListener.onFinished(durationMs, title, description);
Nandana Dutt432f8c72019-01-14 17:39:13 +0000151 }
152
153 // Old methods; should go away
154 @Override
Nandana Dutt3386fb72018-12-12 17:26:57 +0000155 public void onProgressUpdated(int progress) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000156 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000157 }
158
159 @Override
160 public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000161 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000162 }
163
164 @Override
165 public void onSectionComplete(String title, int status, int size, int durationMs)
166 throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000167 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000168 }
169 }
170}