1 /* 2 * Copyright (C) 2021 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 com.android.car; 18 19 import static com.android.car.internal.property.CarPropertyHelper.STATUS_OK; 20 import static com.android.car.internal.property.CarPropertyHelper.getVhalSystemErrorCode; 21 import static com.android.car.internal.property.CarPropertyHelper.getVhalVendorErrorCode; 22 23 import android.annotation.IntDef; 24 import android.annotation.Nullable; 25 import android.car.builtin.os.BuildHelper; 26 import android.car.builtin.util.Slogf; 27 import android.car.hardware.property.CarPropertyManager; 28 import android.car.hardware.property.VehicleHalStatusCode; 29 import android.car.hardware.property.VehicleHalStatusCode.VehicleHalStatusCodeInt; 30 import android.hardware.automotive.vehicle.SubscribeOptions; 31 import android.os.IBinder.DeathRecipient; 32 import android.os.RemoteException; 33 import android.os.ServiceSpecificException; 34 35 import com.android.car.hal.HalPropConfig; 36 import com.android.car.hal.HalPropValue; 37 import com.android.car.hal.HalPropValueBuilder; 38 import com.android.car.hal.VehicleHalCallback; 39 import com.android.car.hal.fakevhal.FakeVehicleStub; 40 41 import java.io.FileDescriptor; 42 import java.util.List; 43 44 /** 45 * VehicleStub represents an IVehicle service interface in either AIDL or legacy HIDL version. It 46 * exposes common interface so that the client does not need to care about which version the 47 * underlying IVehicle service is in. 48 */ 49 public abstract class VehicleStub { 50 51 /** 52 * SubscriptionClient represents a client that could subscribe/unsubscribe to properties. 53 */ 54 public interface SubscriptionClient { 55 /** 56 * Subscribes to a property. 57 * 58 * @param options The list of subscribe options. 59 * @throws RemoteException if the remote operation fails. 60 * @throws ServiceSpecificException if VHAL returns service specific error. 61 */ subscribe(SubscribeOptions[] options)62 void subscribe(SubscribeOptions[] options) throws RemoteException, ServiceSpecificException; 63 64 /** 65 * Unsubscribes from a property. 66 * 67 * @param prop The ID for the property to unsubscribe. 68 * @throws RemoteException if the remote operation fails. 69 * @throws ServiceSpecificException if VHAL returns service specific error. 70 */ unsubscribe(int prop)71 void unsubscribe(int prop) throws RemoteException, ServiceSpecificException; 72 } 73 74 public static final int STATUS_TRY_AGAIN = -1; 75 76 // This is same as 77 // {@link CarPropertyAsyncErrorCode} except that it contains 78 // {@code STATUS_TRY_AGAIN}. 79 @IntDef(prefix = {"STATUS_"}, value = { 80 STATUS_OK, 81 CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR, 82 CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE, 83 CarPropertyManager.STATUS_ERROR_TIMEOUT, 84 STATUS_TRY_AGAIN 85 }) 86 public @interface CarPropMgrErrorCode {} 87 88 /** 89 * A request for {@link VehicleStub#getAsync} or {@link VehicleStub#setAsync}. 90 */ 91 public static class AsyncGetSetRequest { 92 private final int mServiceRequestId; 93 private final HalPropValue mHalPropValue; 94 private final long mTimeoutUptimeMs; 95 getServiceRequestId()96 public int getServiceRequestId() { 97 return mServiceRequestId; 98 } 99 getHalPropValue()100 public HalPropValue getHalPropValue() { 101 return mHalPropValue; 102 } 103 getTimeoutUptimeMs()104 public long getTimeoutUptimeMs() { 105 return mTimeoutUptimeMs; 106 } 107 108 /** 109 * Get an instance for AsyncGetSetRequest. 110 */ AsyncGetSetRequest(int serviceRequestId, HalPropValue halPropValue, long timeoutUptimeMs)111 public AsyncGetSetRequest(int serviceRequestId, HalPropValue halPropValue, 112 long timeoutUptimeMs) { 113 mServiceRequestId = serviceRequestId; 114 mHalPropValue = halPropValue; 115 mTimeoutUptimeMs = timeoutUptimeMs; 116 } 117 } 118 119 /** 120 * A result for {@link VehicleStub#getAsync}. 121 */ 122 public static final class GetVehicleStubAsyncResult { 123 private final int mServiceRequestId; 124 @Nullable 125 private final HalPropValue mHalPropValue; 126 @CarPropMgrErrorCode 127 private final int mErrorCode; 128 private final int mVendorErrorCode; 129 getServiceRequestId()130 public int getServiceRequestId() { 131 return mServiceRequestId; 132 } 133 134 @Nullable getHalPropValue()135 public HalPropValue getHalPropValue() { 136 return mHalPropValue; 137 } 138 139 @CarPropMgrErrorCode getErrorCode()140 public int getErrorCode() { 141 return mErrorCode; 142 } 143 getVendorErrorCode()144 public int getVendorErrorCode() { 145 return mVendorErrorCode; 146 } 147 148 /** 149 * Constructs an instance for GetVehicleStubAsyncResult when result returned successfully. 150 */ GetVehicleStubAsyncResult(int serviceRequestId, HalPropValue halPropValue)151 public GetVehicleStubAsyncResult(int serviceRequestId, HalPropValue halPropValue) { 152 mServiceRequestId = serviceRequestId; 153 mHalPropValue = halPropValue; 154 mErrorCode = STATUS_OK; 155 mVendorErrorCode = 0; 156 } 157 158 /** 159 * Constructs an instance for GetVehicleStubAsyncResult when error. 160 */ GetVehicleStubAsyncResult(int serviceRequestId, @CarPropMgrErrorCode int errorCode, int vendorErrorCode)161 public GetVehicleStubAsyncResult(int serviceRequestId, 162 @CarPropMgrErrorCode int errorCode, int vendorErrorCode) { 163 mServiceRequestId = serviceRequestId; 164 mHalPropValue = null; 165 mErrorCode = errorCode; 166 mVendorErrorCode = vendorErrorCode; 167 } 168 } 169 170 /** 171 * A result for {@link VehicleStub#setAsync}. 172 */ 173 public static final class SetVehicleStubAsyncResult { 174 private final int mServiceRequestId; 175 @CarPropMgrErrorCode 176 private final int mErrorCode; 177 private final int mVendorErrorCode; 178 getServiceRequestId()179 public int getServiceRequestId() { 180 return mServiceRequestId; 181 } 182 183 @CarPropMgrErrorCode getErrorCode()184 public int getErrorCode() { 185 return mErrorCode; 186 } 187 getVendorErrorCode()188 public int getVendorErrorCode() { 189 return mVendorErrorCode; 190 } 191 192 /** 193 * Constructs an success result. 194 */ SetVehicleStubAsyncResult(int serviceRequestId)195 public SetVehicleStubAsyncResult(int serviceRequestId) { 196 mServiceRequestId = serviceRequestId; 197 mErrorCode = STATUS_OK; 198 mVendorErrorCode = 0; 199 } 200 201 /** 202 * Constructs an error result. 203 */ SetVehicleStubAsyncResult(int serviceRequestId, @CarPropMgrErrorCode int errorCode, int vendorErrorCode)204 public SetVehicleStubAsyncResult(int serviceRequestId, 205 @CarPropMgrErrorCode int errorCode, int vendorErrorCode) { 206 mServiceRequestId = serviceRequestId; 207 mErrorCode = errorCode; 208 mVendorErrorCode = vendorErrorCode; 209 } 210 } 211 212 /** 213 * A callback for asynchronous operations. 214 */ 215 public abstract static class VehicleStubCallbackInterface { 216 /** 217 * Method called when {@link getAsync} returns results. 218 */ onGetAsyncResults( List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults)219 public abstract void onGetAsyncResults( 220 List<GetVehicleStubAsyncResult> getVehicleStubAsyncResults); 221 222 /** 223 * Method called when {@link setAsync} returns results. 224 */ onSetAsyncResults( List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults)225 public abstract void onSetAsyncResults( 226 List<SetVehicleStubAsyncResult> setVehicleStubAsyncResults); 227 228 /** 229 * Register a callback that will be called when the callback binder died. 230 */ linkToDeath(DeathRecipient recipient)231 public abstract void linkToDeath(DeathRecipient recipient) throws RemoteException; 232 233 /** 234 * Method called when async requests timed-out. 235 * 236 * If the callback's binder is already dead, this function will not be called. 237 */ onRequestsTimeout(List<Integer> serviceRequestIds)238 public abstract void onRequestsTimeout(List<Integer> serviceRequestIds); 239 } 240 241 /** 242 * Gets a property asynchronously. 243 */ getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests, VehicleStubCallbackInterface getVehicleStubAsyncCallback)244 public abstract void getAsync(List<AsyncGetSetRequest> getVehicleStubAsyncRequests, 245 VehicleStubCallbackInterface getVehicleStubAsyncCallback); 246 247 /** 248 * Sets a property asynchronously. 249 */ setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests, VehicleStubCallbackInterface setVehicleStubAsyncCallback)250 public abstract void setAsync(List<AsyncGetSetRequest> setVehicleStubAsyncRequests, 251 VehicleStubCallbackInterface setVehicleStubAsyncCallback); 252 253 /** 254 * Checks whether we are connected to AIDL VHAL: {@code true} or HIDL VHAL: {@code false}. 255 */ isAidlVhal()256 public abstract boolean isAidlVhal(); 257 258 /** 259 * Creates a new VehicleStub to connect to Vehicle HAL. 260 * 261 * Create a new VehicleStub to connect to Vehicle HAL according to which backend (AIDL or HIDL) 262 * is available. This function will throw {@link IllegalStateException} if no vehicle HAL is 263 * available. 264 * 265 * @return a vehicle stub to connect to Vehicle HAL. 266 */ newVehicleStub()267 public static VehicleStub newVehicleStub() throws IllegalStateException { 268 VehicleStub stub = new AidlVehicleStub(); 269 if (stub.isValid()) { 270 if ((BuildHelper.isUserDebugBuild() || BuildHelper.isEngBuild()) 271 && FakeVehicleStub.doesEnableFileExist()) { 272 try { 273 return new FakeVehicleStub(stub); 274 } catch (Exception e) { 275 Slogf.e(CarLog.TAG_SERVICE, e, "Failed to create FakeVehicleStub. " 276 + "Fallback to using real VehicleStub."); 277 } 278 } 279 return stub; 280 } 281 282 Slogf.i(CarLog.TAG_SERVICE, "No AIDL vehicle HAL found, fall back to HIDL version"); 283 284 stub = new HidlVehicleStub(); 285 286 if (!stub.isValid()) { 287 throw new IllegalStateException("Vehicle HAL service is not available."); 288 } 289 290 return stub; 291 } 292 293 /** 294 * Gets a HalPropValueBuilder that could be used to build a HalPropValue. 295 * 296 * @return a builder to build HalPropValue. 297 */ getHalPropValueBuilder()298 public abstract HalPropValueBuilder getHalPropValueBuilder(); 299 300 /** 301 * Returns whether this vehicle stub is connecting to a valid vehicle HAL. 302 * 303 * @return Whether this vehicle stub is connecting to a valid vehicle HAL. 304 */ isValid()305 public abstract boolean isValid(); 306 307 /** 308 * Gets the interface descriptor for the connecting vehicle HAL. 309 * 310 * @return the interface descriptor. 311 * @throws IllegalStateException If unable to get the descriptor. 312 */ getInterfaceDescriptor()313 public abstract String getInterfaceDescriptor() throws IllegalStateException; 314 315 /** 316 * Registers a death recipient that would be called when vehicle HAL died. 317 * 318 * @param recipient A death recipient. 319 * @throws IllegalStateException If unable to register the death recipient. 320 */ linkToDeath(IVehicleDeathRecipient recipient)321 public abstract void linkToDeath(IVehicleDeathRecipient recipient) throws IllegalStateException; 322 323 /** 324 * Unlinks a previously linked death recipient. 325 * 326 * @param recipient A previously linked death recipient. 327 */ unlinkToDeath(IVehicleDeathRecipient recipient)328 public abstract void unlinkToDeath(IVehicleDeathRecipient recipient); 329 330 /** 331 * Gets all property configs. 332 * 333 * @return All the property configs. 334 * @throws RemoteException if the remote operation fails. 335 * @throws ServiceSpecificException if VHAL returns service specific error. 336 */ getAllPropConfigs()337 public abstract HalPropConfig[] getAllPropConfigs() 338 throws RemoteException, ServiceSpecificException; 339 340 /** 341 * Gets a new {@code SubscriptionClient} that could be used to subscribe/unsubscribe. 342 * 343 * Caller MUST unsubscribe all subscribed properties before discarding the client to prevent 344 * resource leak. 345 * 346 * @param callback A callback that could be used to receive events. 347 * @return a {@code SubscriptionClient} that could be used to subscribe/unsubscribe. 348 */ newSubscriptionClient(VehicleHalCallback callback)349 public abstract SubscriptionClient newSubscriptionClient(VehicleHalCallback callback); 350 351 /** 352 * Gets a property. 353 * 354 * @param requestedPropValue The property to get. 355 * @return The vehicle property value. 356 * @throws RemoteException if the remote operation fails. 357 * @throws ServiceSpecificException if VHAL returns service specific error. 358 */ 359 @Nullable get(HalPropValue requestedPropValue)360 public abstract HalPropValue get(HalPropValue requestedPropValue) 361 throws RemoteException, ServiceSpecificException; 362 363 /** 364 * Sets a property. 365 * 366 * @param propValue The property to set. 367 * @throws RemoteException if the remote operation fails. 368 * @throws ServiceSpecificException if VHAL returns service specific error. 369 */ set(HalPropValue propValue)370 public abstract void set(HalPropValue propValue) 371 throws RemoteException, ServiceSpecificException; 372 373 /** 374 * Dumps VHAL debug information. 375 * 376 * Additional arguments could also be provided through {@link args} to debug VHAL. 377 * 378 * @param fd The file descriptor to print output. 379 * @param args Optional additional arguments for the debug command. Can be empty. 380 * @throws RemoteException if the remote operation fails. 381 * @throws ServiceSpecificException if VHAL returns service specific error. 382 */ dump(FileDescriptor fd, List<String> args)383 public abstract void dump(FileDescriptor fd, List<String> args) 384 throws RemoteException, ServiceSpecificException; 385 386 /** 387 * Checks if fake VHAL is enabled. 388 * 389 * @return {@code true} if a FakeVehicleStub instance is created. 390 */ isFakeModeEnabled()391 public boolean isFakeModeEnabled() { 392 return false; 393 } 394 395 /** 396 * Cancels all the on-going async requests with the given request IDs. 397 * 398 * @param requestIds a list of async get/set request IDs. 399 */ cancelRequests(List<Integer> requestIds)400 public void cancelRequests(List<Integer> requestIds) {} 401 402 /** 403 * Converts a StatusCode from VHAL to error code used by CarPropertyManager. 404 * 405 * The returned error code is a two-element array, the first element is a 406 * {@link CarPropMgrErrorCode}, the second element is the vendor error code. 407 */ convertHalToCarPropertyManagerError(int errorCode)408 public static int[] convertHalToCarPropertyManagerError(int errorCode) { 409 int[] result = new int[2]; 410 @VehicleHalStatusCodeInt int systemErrorCode = getVhalSystemErrorCode(errorCode); 411 int vendorErrorCode = getVhalVendorErrorCode(errorCode); 412 result[0] = STATUS_OK; 413 result[1] = vendorErrorCode; 414 switch (systemErrorCode) { 415 case VehicleHalStatusCode.STATUS_OK: 416 break; 417 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE: // Fallthrough 418 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_DISABLED: // Fallthrough 419 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_LOW: // Fallthrough 420 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SPEED_HIGH: // Fallthrough 421 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_POOR_VISIBILITY: // Fallthrough 422 case VehicleHalStatusCode.STATUS_NOT_AVAILABLE_SAFETY: 423 result[0] = CarPropertyManager.STATUS_ERROR_NOT_AVAILABLE; 424 break; 425 case VehicleHalStatusCode.STATUS_TRY_AGAIN: 426 result[0] = STATUS_TRY_AGAIN; 427 break; 428 default: 429 result[0] = CarPropertyManager.STATUS_ERROR_INTERNAL_ERROR; 430 break; 431 } 432 return result; 433 } 434 } 435