blob: 3a5b8a86204ed83a360095193ca880651b917a9d [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
Nandana Dutt28d8dd72019-01-25 14:31:05 +000019import android.annotation.CallbackExecutor;
Nandana Dutt3386fb72018-12-12 17:26:57 +000020import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.annotation.RequiresPermission;
Nandana Dutt0a188202019-01-23 20:02:29 +000024import android.annotation.SystemApi;
Nandana Dutt3386fb72018-12-12 17:26:57 +000025import android.annotation.SystemService;
26import android.content.Context;
27import android.os.IBinder.DeathRecipient;
28
29import java.io.FileDescriptor;
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
Nandana Dutt28d8dd72019-01-25 14:31:05 +000032import java.util.concurrent.Executor;
Nandana Dutt3386fb72018-12-12 17:26:57 +000033
34/**
35 * Class that provides a privileged API to capture and consume bugreports.
36 *
37 * @hide
38 */
Nandana Dutt0a188202019-01-23 20:02:29 +000039@SystemApi
Nandana Dutt3386fb72018-12-12 17:26:57 +000040@SystemService(Context.BUGREPORT_SERVICE)
41public class BugreportManager {
42 private final Context mContext;
43 private final IDumpstate mBinder;
44
45 /** @hide */
46 public BugreportManager(@NonNull Context context, IDumpstate binder) {
47 mContext = context;
48 mBinder = binder;
49 }
50
51 /**
Nandana Dutt28d8dd72019-01-25 14:31:05 +000052 * An interface describing the callback for bugreport progress and status.
Nandana Dutt3386fb72018-12-12 17:26:57 +000053 */
Nandana Dutt28d8dd72019-01-25 14:31:05 +000054 public abstract static class BugreportCallback {
55 /** @hide */
56 @Retention(RetentionPolicy.SOURCE)
57 @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
58 BUGREPORT_ERROR_INVALID_INPUT,
59 BUGREPORT_ERROR_RUNTIME,
60 BUGREPORT_ERROR_USER_DENIED_CONSENT,
61 BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT
62 })
63
64 /** Possible error codes taking a bugreport can encounter */
65 public @interface BugreportErrorCode {}
66
67 /** The input options were invalid */
68 public static final int BUGREPORT_ERROR_INVALID_INPUT =
69 IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
70
71 /** A runtime error occured */
72 public static final int BUGREPORT_ERROR_RUNTIME =
73 IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
74
75 /** User denied consent to share the bugreport */
76 public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT =
77 IDumpstateListener.BUGREPORT_ERROR_USER_DENIED_CONSENT;
78
79 /** The request to get user consent timed out. */
80 public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT =
81 IDumpstateListener.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT;
82
Nandana Dutt3386fb72018-12-12 17:26:57 +000083 /**
84 * Called when there is a progress update.
85 * @param progress the progress in [0.0, 100.0]
86 */
Nandana Dutt28d8dd72019-01-25 14:31:05 +000087 public void onProgress(float progress) {}
Nandana Duttbba7e822019-01-23 19:11:01 +000088
Nandana Dutt3386fb72018-12-12 17:26:57 +000089 /**
90 * Called when taking bugreport resulted in an error.
91 *
Nandana Duttbba7e822019-01-23 19:11:01 +000092 * <p>If {@code BUGREPORT_ERROR_USER_DENIED_CONSENT} is passed, then the user did not
93 * consent to sharing the bugreport with the calling app.
94 *
95 * <p>If {@code BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT} is passed, then the consent timed
96 * out, but the bugreport could be available in the internal directory of dumpstate for
97 * manual retrieval.
Nandana Dutt3386fb72018-12-12 17:26:57 +000098 */
Nandana Dutt28d8dd72019-01-25 14:31:05 +000099 public void onError(@BugreportErrorCode int errorCode) {}
Nandana Dutt3386fb72018-12-12 17:26:57 +0000100
101 /**
Nandana Duttb2da22a2019-01-23 08:39:05 +0000102 * Called when taking bugreport finishes successfully.
Nandana Dutt3386fb72018-12-12 17:26:57 +0000103 */
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000104 public void onFinished() {}
Nandana Dutt3386fb72018-12-12 17:26:57 +0000105 }
106
107 /**
Nandana Duttb2da22a2019-01-23 08:39:05 +0000108 * Starts a bugreport.
109 *
110 * <p>This starts a bugreport in the background. However the call itself can take several
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000111 * seconds to return in the worst case. {@code callback} will receive progress and status
Nandana Duttb2da22a2019-01-23 08:39:05 +0000112 * updates.
113 *
114 * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
115 * user consents to sharing with the calling app.
Nandana Dutt3386fb72018-12-12 17:26:57 +0000116 *
117 * @param bugreportFd file to write the bugreport. This should be opened in write-only,
118 * append mode.
119 * @param screenshotFd file to write the screenshot, if necessary. This should be opened
120 * in write-only, append mode.
121 * @param params options that specify what kind of a bugreport should be taken
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000122 * @param callback callback for progress and status updates
Nandana Dutt3386fb72018-12-12 17:26:57 +0000123 */
124 @RequiresPermission(android.Manifest.permission.DUMP)
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000125 public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
126 @Nullable ParcelFileDescriptor screenshotFd,
127 @NonNull BugreportParams params,
128 @NonNull @CallbackExecutor Executor executor,
129 @NonNull BugreportCallback callback) {
Nandana Dutt3386fb72018-12-12 17:26:57 +0000130 // TODO(b/111441001): Enforce android.Manifest.permission.DUMP if necessary.
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000131 DumpstateListener dsListener = new DumpstateListener(executor, callback);
Nandana Dutt3386fb72018-12-12 17:26:57 +0000132 try {
Nandana Dutt161a4462019-01-16 18:18:38 +0000133 // Note: mBinder can get callingUid from the binder transaction.
134 mBinder.startBugreport(-1 /* callingUid */,
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000135 mContext.getOpPackageName(),
136 (bugreportFd != null ? bugreportFd.getFileDescriptor() : new FileDescriptor()),
137 (screenshotFd != null
138 ? screenshotFd.getFileDescriptor() : new FileDescriptor()),
Nandana Dutt161a4462019-01-16 18:18:38 +0000139 params.getMode(), dsListener);
Nandana Dutt3386fb72018-12-12 17:26:57 +0000140 } catch (RemoteException e) {
141 throw e.rethrowFromSystemServer();
142 }
143 }
144
Nandana Duttb2da22a2019-01-23 08:39:05 +0000145 /*
146 * Cancels a currently running bugreport.
147 */
148 @RequiresPermission(android.Manifest.permission.DUMP)
149 public void cancelBugreport() {
150 try {
151 mBinder.cancelBugreport();
152 } catch (RemoteException e) {
153 throw e.rethrowFromSystemServer();
154 }
155 }
156
Nandana Dutt3386fb72018-12-12 17:26:57 +0000157 private final class DumpstateListener extends IDumpstateListener.Stub
158 implements DeathRecipient {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000159 private final Executor mExecutor;
160 private final BugreportCallback mCallback;
Nandana Dutt3386fb72018-12-12 17:26:57 +0000161
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000162 DumpstateListener(Executor executor, @Nullable BugreportCallback callback) {
163 mExecutor = executor;
164 mCallback = callback;
Nandana Dutt3386fb72018-12-12 17:26:57 +0000165 }
166
167 @Override
168 public void binderDied() {
169 // TODO(b/111441001): implement
170 }
171
172 @Override
Nandana Dutt432f8c72019-01-14 17:39:13 +0000173 public void onProgress(int progress) throws RemoteException {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000174 final long identity = Binder.clearCallingIdentity();
175 try {
176 mExecutor.execute(() -> {
177 mCallback.onProgress(progress);
178 });
179 } finally {
180 Binder.restoreCallingIdentity(identity);
181 }
Nandana Dutt432f8c72019-01-14 17:39:13 +0000182 }
183
184 @Override
185 public void onError(int errorCode) throws RemoteException {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000186 final long identity = Binder.clearCallingIdentity();
187 try {
188 mExecutor.execute(() -> {
189 mCallback.onError(errorCode);
190 });
191 } finally {
192 Binder.restoreCallingIdentity(identity);
193 }
Nandana Dutt432f8c72019-01-14 17:39:13 +0000194 }
195
196 @Override
Nandana Duttb2da22a2019-01-23 08:39:05 +0000197 public void onFinished() throws RemoteException {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000198 final long identity = Binder.clearCallingIdentity();
Nandana Duttb2da22a2019-01-23 08:39:05 +0000199 try {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000200 mExecutor.execute(() -> {
201 mCallback.onFinished();
202 });
Nandana Duttb2da22a2019-01-23 08:39:05 +0000203 } finally {
Nandana Dutt28d8dd72019-01-25 14:31:05 +0000204 Binder.restoreCallingIdentity(identity);
Nandana Duttb2da22a2019-01-23 08:39:05 +0000205 // The bugreport has finished. Let's shutdown the service to minimize its footprint.
206 cancelBugreport();
207 }
Nandana Dutt432f8c72019-01-14 17:39:13 +0000208 }
209
210 // Old methods; should go away
211 @Override
Nandana Dutt3386fb72018-12-12 17:26:57 +0000212 public void onProgressUpdated(int progress) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000213 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000214 }
215
216 @Override
217 public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000218 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000219 }
220
221 @Override
222 public void onSectionComplete(String title, int status, int size, int durationMs)
223 throws RemoteException {
Nandana Duttc8c77bc2019-01-15 12:48:12 +0000224 // TODO(b/111441001): remove from interface
Nandana Dutt3386fb72018-12-12 17:26:57 +0000225 }
226 }
227}