1 /* 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 17 package android.car; 18 19 import android.annotation.FloatRange; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.RequiresPermission; 23 import android.os.Handler; 24 import android.os.IBinder; 25 import android.os.ParcelFileDescriptor; 26 import android.os.RemoteException; 27 28 import com.android.internal.util.Preconditions; 29 30 import libcore.io.IoUtils; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 import java.lang.ref.WeakReference; 35 36 /** 37 * Car specific bugreport manager. Only available for userdebug and eng builds. 38 * 39 * @hide 40 */ 41 public final class CarBugreportManager extends CarManagerBase { 42 43 private final ICarBugreportService mService; 44 45 /** 46 * Callback from carbugreport manager. Callback methods are always called on the main thread. 47 */ 48 public abstract static class CarBugreportManagerCallback { 49 50 @Retention(RetentionPolicy.SOURCE) 51 @IntDef(prefix = {"CAR_BUGREPORT_ERROR_"}, value = { 52 CAR_BUGREPORT_DUMPSTATE_FAILED, 53 CAR_BUGREPORT_IN_PROGRESS, 54 CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED, 55 CAR_BUGREPORT_SERVICE_NOT_AVAILABLE 56 }) 57 58 public @interface CarBugreportErrorCode { 59 } 60 61 /** Dumpstate failed to generate bugreport. */ 62 public static final int CAR_BUGREPORT_DUMPSTATE_FAILED = 1; 63 64 /** 65 * Another bugreport is in progress. 66 */ 67 public static final int CAR_BUGREPORT_IN_PROGRESS = 2; 68 69 /** Cannot connect to dumpstate */ 70 public static final int CAR_BUGREPORT_DUMPSTATE_CONNECTION_FAILED = 3; 71 72 /** Car bugreport service is not available (true for user builds) */ 73 public static final int CAR_BUGREPORT_SERVICE_NOT_AVAILABLE = 4; 74 75 /** 76 * Called when bugreport progress changes. 77 * 78 * <p>It's never called after {@link #onError} or {@link #onFinished}. 79 * 80 * @param progress - a number in [0.0, 100.0]. 81 */ onProgress(@loatRangefrom = 0f, to = 100f) float progress)82 public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) { 83 } 84 85 /** 86 * Called on an error condition with one of the error codes listed above. 87 * 88 * @param errorCode the error code that defines failure reason. 89 */ onError(@arBugreportErrorCode int errorCode)90 public void onError(@CarBugreportErrorCode int errorCode) { 91 } 92 93 /** 94 * Called when taking bugreport finishes successfully. 95 */ onFinished()96 public void onFinished() { 97 } 98 } 99 100 /** 101 * Internal wrapper class to service. 102 */ 103 private static final class CarBugreportManagerCallbackWrapper extends 104 ICarBugreportCallback.Stub { 105 106 private final WeakReference<CarBugreportManagerCallback> mWeakCallback; 107 private final WeakReference<Handler> mWeakHandler; 108 109 /** 110 * Create a new callback wrapper. 111 * 112 * @param callback the callback passed from app 113 * @param handler the handler to execute callbacks on 114 */ CarBugreportManagerCallbackWrapper(CarBugreportManagerCallback callback, Handler handler)115 CarBugreportManagerCallbackWrapper(CarBugreportManagerCallback callback, 116 Handler handler) { 117 mWeakCallback = new WeakReference<>(callback); 118 mWeakHandler = new WeakReference<>(handler); 119 } 120 121 @Override onProgress(@loatRangefrom = 0f, to = 100f) float progress)122 public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) { 123 CarBugreportManagerCallback callback = mWeakCallback.get(); 124 Handler handler = mWeakHandler.get(); 125 if (handler != null && callback != null) { 126 handler.post(() -> callback.onProgress(progress)); 127 } 128 } 129 130 @Override onError(@arBugreportManagerCallback.CarBugreportErrorCode int errorCode)131 public void onError(@CarBugreportManagerCallback.CarBugreportErrorCode int errorCode) { 132 CarBugreportManagerCallback callback = mWeakCallback.get(); 133 Handler handler = mWeakHandler.get(); 134 if (handler != null && callback != null) { 135 handler.post(() -> callback.onError(errorCode)); 136 } 137 } 138 139 @Override onFinished()140 public void onFinished() { 141 CarBugreportManagerCallback callback = mWeakCallback.get(); 142 Handler handler = mWeakHandler.get(); 143 if (handler != null && callback != null) { 144 handler.post(callback::onFinished); 145 } 146 } 147 } 148 149 /** 150 * Get an instance of the CarBugreportManager 151 * 152 * Should not be obtained directly by clients, use {@link Car#getCarManager(String)} instead. 153 */ CarBugreportManager(Car car, IBinder service)154 public CarBugreportManager(Car car, IBinder service) { 155 super(car); 156 mService = ICarBugreportService.Stub.asInterface(service); 157 } 158 159 /** 160 * Request a bug report. A zipped (i.e. legacy) bugreport is generated in the background 161 * using dumpstate. This API also generates extra files that does not exist in the legacy 162 * bugreport and makes them available through a extra output file. Currently the extra 163 * output contains the screenshots for all the physical displays. 164 * 165 * <p>The file descriptor is closed when bugreport is written or if an exception happens. 166 * 167 * <p>This method is enabled only for one bug reporting app. It can be configured using 168 * {@code config_car_bugreport_application} string that is defined in 169 * {@code packages/services/Car/service/res/values/config.xml}. To learn more please 170 * see {@code packages/services/Car/tests/BugReportApp/README.md}. 171 * 172 * @param output the zipped bugreport file 173 * @param extraOutput a zip file that contains extra files generated for automotive. 174 * @param callback the callback for reporting dump status 175 */ 176 @RequiresPermission(android.Manifest.permission.DUMP) requestBugreport( @onNull ParcelFileDescriptor output, @NonNull ParcelFileDescriptor extraOutput, @NonNull CarBugreportManagerCallback callback)177 public void requestBugreport( 178 @NonNull ParcelFileDescriptor output, 179 @NonNull ParcelFileDescriptor extraOutput, 180 @NonNull CarBugreportManagerCallback callback) { 181 Preconditions.checkNotNull(output); 182 Preconditions.checkNotNull(extraOutput); 183 Preconditions.checkNotNull(callback); 184 try { 185 CarBugreportManagerCallbackWrapper wrapper = 186 new CarBugreportManagerCallbackWrapper(callback, getEventHandler()); 187 mService.requestBugreport(output, extraOutput, wrapper); 188 } catch (RemoteException e) { 189 handleRemoteExceptionFromCarService(e); 190 } finally { 191 IoUtils.closeQuietly(output); 192 IoUtils.closeQuietly(extraOutput); 193 } 194 } 195 196 @Override onCarDisconnected()197 public void onCarDisconnected() { 198 } 199 } 200