• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.car.hal;
18 
19 import static android.os.SystemClock.elapsedRealtime;
20 
21 import android.car.builtin.util.Slogf;
22 import android.hardware.automotive.vehicle.StatusCode;
23 import android.hardware.automotive.vehicle.SubscribeOptions;
24 import android.hardware.automotive.vehicle.VehiclePropError;
25 import android.os.Handler;
26 import android.os.Looper;
27 import android.os.Message;
28 import android.os.RemoteException;
29 import android.os.ServiceSpecificException;
30 
31 import com.android.car.CarLog;
32 import com.android.car.VehicleStub;
33 import com.android.car.VehicleStub.SubscriptionClient;
34 import com.android.car.internal.util.DebugUtils;
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 import java.lang.ref.WeakReference;
38 import java.util.ArrayList;
39 
40 /**
41  * Vehicle HAL client. Interacts directly with Vehicle HAL interface {@link IVehicle}. Contains
42  * some logic for retriable properties, redirects Vehicle notifications into given looper thread.
43  */
44 final class HalClient {
45 
46     @VisibleForTesting
47     static final String TAG = CarLog.tagFor(HalClient.class);
48 
49     /**
50      * If call to vehicle HAL returns StatusCode.TRY_AGAIN, than {@link HalClient} will retry to
51      * invoke that method again for this amount of milliseconds.
52      */
53     private static final int WAIT_CAP_FOR_RETRIABLE_RESULT_MS = 2000;
54 
55     private static final int SLEEP_BETWEEN_RETRIABLE_INVOKES_MS = 50;
56 
57     private final VehicleStub mVehicle;
58     private final SubscriptionClient mSubscriptionClient;
59     private final VehicleCallback mInternalCallback;
60     private final int mWaitCapMs;
61     private final int mSleepMs;
62 
63     /**
64      * Create HalClient object
65      *
66      * @param vehicle interface to the vehicle HAL
67      * @param looper looper that will be used to propagate notifications from vehicle HAL
68      * @param callback to propagate notifications from Vehicle HAL in the provided looper thread
69      */
HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback)70     HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback) {
71         this(
72                 vehicle,
73                 looper,
74                 callback,
75                 WAIT_CAP_FOR_RETRIABLE_RESULT_MS,
76                 SLEEP_BETWEEN_RETRIABLE_INVOKES_MS);
77     }
78 
79     @VisibleForTesting
HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback, int waitCapMs, int sleepMs)80     HalClient(VehicleStub vehicle, Looper looper, HalClientCallback callback, int waitCapMs,
81             int sleepMs) {
82         mVehicle = vehicle;
83         Handler handler = new CallbackHandler(looper, callback);
84         mInternalCallback = new VehicleCallback(handler);
85         mSubscriptionClient = vehicle.newSubscriptionClient(mInternalCallback);
86         mWaitCapMs = waitCapMs;
87         mSleepMs = sleepMs;
88     }
89 
getInternalCallback()90     HalClientCallback getInternalCallback() {
91         return mInternalCallback;
92     }
93 
getAllPropConfigs()94     HalPropConfig[] getAllPropConfigs()
95             throws RemoteException, ServiceSpecificException {
96         return mVehicle.getAllPropConfigs();
97     }
98 
subscribe(SubscribeOptions... options)99     public void subscribe(SubscribeOptions... options)
100             throws RemoteException, ServiceSpecificException {
101         mSubscriptionClient.subscribe(options);
102     }
103 
unsubscribe(int prop)104     public void unsubscribe(int prop) throws RemoteException, ServiceSpecificException {
105         mSubscriptionClient.unsubscribe(prop);
106     }
107 
setValue(HalPropValue propValue)108     public void setValue(HalPropValue propValue)
109             throws IllegalArgumentException, ServiceSpecificException {
110         ObjectWrapper<String> errorMsgWrapper = new ObjectWrapper<>();
111         errorMsgWrapper.object = new String();
112 
113         int status = invokeRetriable(() -> {
114             try {
115                 mVehicle.set(propValue);
116                 errorMsgWrapper.object = new String();
117                 return StatusCode.OK;
118             } catch (RemoteException e) {
119                 errorMsgWrapper.object = e.toString();
120                 return StatusCode.TRY_AGAIN;
121             } catch (ServiceSpecificException e) {
122                 errorMsgWrapper.object = e.toString();
123                 return e.errorCode;
124             }
125         }, mWaitCapMs, mSleepMs);
126 
127         String errorMsg = errorMsgWrapper.object;
128 
129         if (StatusCode.INVALID_ARG == status) {
130             throw new IllegalArgumentException(getValueErrorMessage("set", propValue, errorMsg));
131         }
132 
133         if (StatusCode.OK != status) {
134             throw new ServiceSpecificException(
135                     status, getValueErrorMessage("set", propValue, errorMsg));
136         }
137     }
138 
getHalPropValueBuilder()139     public HalPropValueBuilder getHalPropValueBuilder() {
140         return mVehicle.getHalPropValueBuilder();
141     }
142 
getValueErrorMessage(String action, HalPropValue propValue, String errorMsg)143     private String getValueErrorMessage(String action, HalPropValue propValue, String errorMsg) {
144         return "Failed to " + action + " value for: 0x"
145                 + Integer.toHexString(propValue.getPropId()) + ", areaId: 0x"
146                 + Integer.toHexString(propValue.getAreaId()) + ", error: " + errorMsg;
147     }
148 
getValue(HalPropValue requestedPropValue)149     HalPropValue getValue(HalPropValue requestedPropValue)
150             throws IllegalArgumentException, ServiceSpecificException {
151         // Use a wrapper to create a final object passed to lambda.
152         ObjectWrapper<ValueResult> resultWrapper = new ObjectWrapper<>();
153         resultWrapper.object = new ValueResult();
154         int status = invokeRetriable(() -> {
155             resultWrapper.object = internalGet(requestedPropValue);
156             return resultWrapper.object.status;
157         }, mWaitCapMs, mSleepMs);
158 
159         ValueResult result = resultWrapper.object;
160 
161         if (StatusCode.INVALID_ARG == status) {
162             throw new IllegalArgumentException(
163                     getValueErrorMessage("get", requestedPropValue, result.errorMsg));
164         }
165 
166         if (StatusCode.OK != status || result.propValue == null) {
167             // If propValue is null and status is StatusCode.Ok, change the status to be
168             // NOT_AVAILABLE.
169             if (StatusCode.OK == status) {
170                 status = StatusCode.NOT_AVAILABLE;
171             }
172             throw new ServiceSpecificException(
173                     status, getValueErrorMessage("get", requestedPropValue, result.errorMsg));
174         }
175 
176         return result.propValue;
177     }
178 
internalGet(HalPropValue requestedPropValue)179     private ValueResult internalGet(HalPropValue requestedPropValue) {
180         final ValueResult result = new ValueResult();
181         try {
182             result.propValue = mVehicle.get(requestedPropValue);
183             result.status = StatusCode.OK;
184             result.errorMsg = new String();
185         } catch (ServiceSpecificException e) {
186             result.status = e.errorCode;
187             result.errorMsg = e.toString();
188         } catch (RemoteException e) {
189             result.status = StatusCode.TRY_AGAIN;
190             result.errorMsg = e.toString();
191         }
192 
193         return result;
194     }
195 
196     interface RetriableCallback {
197         /** Returns {@link StatusCode} */
action()198         int action();
199     }
200 
invokeRetriable(RetriableCallback callback, long timeoutMs, long sleepMs)201     private static int invokeRetriable(RetriableCallback callback, long timeoutMs, long sleepMs) {
202         int status = callback.action();
203         long startTime = elapsedRealtime();
204         while (StatusCode.TRY_AGAIN == status && (elapsedRealtime() - startTime) < timeoutMs) {
205             Slogf.d(TAG, "Status before sleeping %d ms: %d", sleepMs, status);
206             try {
207                 Thread.sleep(sleepMs);
208             } catch (InterruptedException e) {
209                 Thread.currentThread().interrupt();
210                 Slogf.w(TAG, "Thread was interrupted while waiting for vehicle HAL.", e);
211                 break;
212             }
213 
214             status = callback.action();
215             Slogf.d(TAG, "Status after waking up: %s", DebugUtils.constantToString(
216                     StatusCode.class, status));
217         }
218         Slogf.d(TAG, "Returning status: %s", DebugUtils.constantToString(
219                 StatusCode.class, status));
220         return status;
221     }
222 
223     private static final class ObjectWrapper<T> {
224         public T object;
225     }
226 
227     private static final class ValueResult {
228         public int status;
229         public String errorMsg = new String();
230         public HalPropValue propValue;
231     }
232 
233     private static final class CallbackHandler extends Handler {
234         private static final int MSG_ON_PROPERTY_EVENT = 1;
235         private static final int MSG_ON_SET_ERROR = 2;
236 
237         private final WeakReference<HalClientCallback> mCallback;
238 
CallbackHandler(Looper looper, HalClientCallback callback)239         CallbackHandler(Looper looper, HalClientCallback callback) {
240             super(looper);
241             mCallback = new WeakReference<HalClientCallback>(callback);
242         }
243 
244         @Override
handleMessage(Message msg)245         public void handleMessage(Message msg) {
246             HalClientCallback callback = mCallback.get();
247             if (callback == null) {
248                 Slogf.i(TAG, "handleMessage null callback");
249                 return;
250             }
251 
252             switch (msg.what) {
253                 case MSG_ON_PROPERTY_EVENT:
254                     callback.onPropertyEvent((ArrayList<HalPropValue>) msg.obj);
255                     break;
256                 case MSG_ON_SET_ERROR:
257                     callback.onPropertySetError((ArrayList<VehiclePropError>) msg.obj);
258                     break;
259                 default:
260                     Slogf.e(TAG, "Unexpected message: %d", msg.what);
261             }
262         }
263     }
264 
265     @VisibleForTesting
266     static final class VehicleCallback implements HalClientCallback {
267         private final Handler mHandler;
268 
VehicleCallback(Handler handler)269         VehicleCallback(Handler handler) {
270             mHandler = handler;
271         }
272 
273         @Override
onPropertyEvent(ArrayList<HalPropValue> propValues)274         public void onPropertyEvent(ArrayList<HalPropValue> propValues) {
275             mHandler.sendMessage(Message.obtain(
276                     mHandler, CallbackHandler.MSG_ON_PROPERTY_EVENT, propValues));
277         }
278 
279         @Override
onPropertySetError(ArrayList<VehiclePropError> errors)280         public void onPropertySetError(ArrayList<VehiclePropError> errors) {
281             mHandler.sendMessage(Message.obtain(
282                         mHandler, CallbackHandler.MSG_ON_SET_ERROR, errors));
283         }
284     }
285 }
286