blob: c0e20f2cb9e4ce722acd8a21e350320ab67effd0 [file] [log] [blame]
Antonio Cortes734010a2017-01-19 20:09:22 -08001/*
2 * Copyright (C) 2017 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 */
16package com.android.car.hal;
17
asafro99e4f082017-02-09 13:11:42 -080018import static com.android.car.CarServiceUtils.toByteArray;
Antonio Cortes734010a2017-01-19 20:09:22 -080019import static java.lang.Integer.toHexString;
20
Antonio Cortes734010a2017-01-19 20:09:22 -080021import android.car.VehicleAreaType;
Antonio Cortesa6845c32017-02-06 09:22:26 -080022import android.car.annotation.FutureFeature;
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -070023import android.car.vms.IVmsSubscriberClient;
Antonio Cortes0bd67c32017-03-13 08:02:40 -070024import android.car.vms.VmsLayer;
Antonio Cortes2febe9f2017-03-24 09:42:17 -070025import android.car.vms.VmsSubscriptionState;
Pavel Maltsevcfe93102017-02-02 12:38:08 -080026import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
27import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
Antonio Cortes747364a2017-02-28 10:37:24 -080028import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
29import android.hardware.automotive.vehicle.V2_1.VmsMessageIntegerValuesIndex;
30import android.hardware.automotive.vehicle.V2_1.VmsMessageType;
Antonio Cortes9db963a2017-03-10 15:15:28 -080031import android.os.SystemClock;
Antonio Cortes734010a2017-01-19 20:09:22 -080032import android.util.Log;
Antonio Cortes734010a2017-01-19 20:09:22 -080033import com.android.car.CarLog;
asafro25a87402017-02-28 16:08:17 -080034import com.android.car.VmsRouting;
Antonio Cortes734010a2017-01-19 20:09:22 -080035import com.android.internal.annotations.GuardedBy;
Antonio Cortes734010a2017-01-19 20:09:22 -080036import java.io.PrintWriter;
Antonio Cortes40b90262017-02-06 11:43:57 -080037import java.util.ArrayList;
asafro99e4f082017-02-09 13:11:42 -080038import java.util.Arrays;
Antonio Cortes734010a2017-01-19 20:09:22 -080039import java.util.Collection;
asafro99e4f082017-02-09 13:11:42 -080040import java.util.HashSet;
Antonio Cortes734010a2017-01-19 20:09:22 -080041import java.util.LinkedList;
42import java.util.List;
asafro99e4f082017-02-09 13:11:42 -080043import java.util.Set;
asafro99e4f082017-02-09 13:11:42 -080044import java.util.concurrent.CopyOnWriteArrayList;
Antonio Cortes734010a2017-01-19 20:09:22 -080045
46/**
47 * This is a glue layer between the VehicleHal and the VmsService. It sends VMS properties back and
48 * forth.
49 */
Antonio Cortesa6845c32017-02-06 09:22:26 -080050@FutureFeature
Antonio Cortes734010a2017-01-19 20:09:22 -080051public class VmsHalService extends HalServiceBase {
52 private static final boolean DBG = true;
53 private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
54 private static final String TAG = "VmsHalService";
asafro99e4f082017-02-09 13:11:42 -080055 private static final Set<Integer> SUPPORTED_MESSAGE_TYPES =
56 new HashSet<Integer>(
57 Arrays.asList(
58 VmsMessageType.SUBSCRIBE,
59 VmsMessageType.UNSUBSCRIBE,
60 VmsMessageType.DATA));
Antonio Cortes734010a2017-01-19 20:09:22 -080061
62 private boolean mIsSupported = false;
asafro99e4f082017-02-09 13:11:42 -080063 private CopyOnWriteArrayList<VmsHalPublisherListener> mPublisherListeners =
64 new CopyOnWriteArrayList<>();
65 private CopyOnWriteArrayList<VmsHalSubscriberListener> mSubscriberListeners =
66 new CopyOnWriteArrayList<>();
Antonio Cortes734010a2017-01-19 20:09:22 -080067 private final VehicleHal mVehicleHal;
asafro25a87402017-02-28 16:08:17 -080068 @GuardedBy("mLock")
69 private VmsRouting mRouting = new VmsRouting();
70 private final Object mLock = new Object();
Antonio Cortes734010a2017-01-19 20:09:22 -080071
72 /**
asafro99e4f082017-02-09 13:11:42 -080073 * The VmsPublisherService implements this interface to receive data from the HAL.
74 */
75 public interface VmsHalPublisherListener {
Antonio Cortes2febe9f2017-03-24 09:42:17 -070076 void onChange(VmsSubscriptionState subscriptionState);
asafro99e4f082017-02-09 13:11:42 -080077 }
78
79 /**
80 * The VmsSubscriberService implements this interface to receive data from the HAL.
81 */
82 public interface VmsHalSubscriberListener {
Antonio Cortes01a60392017-03-22 13:00:02 -070083 void onChange(VmsLayer layer, byte[] payload);
asafro99e4f082017-02-09 13:11:42 -080084 }
85
86 /**
Antonio Cortes734010a2017-01-19 20:09:22 -080087 * The VmsService implements this interface to receive data from the HAL.
88 */
Antonio Cortes734010a2017-01-19 20:09:22 -080089 protected VmsHalService(VehicleHal vehicleHal) {
90 mVehicleHal = vehicleHal;
91 if (DBG) {
92 Log.d(TAG, "started VmsHalService!");
93 }
94 }
95
asafro99e4f082017-02-09 13:11:42 -080096 public void addPublisherListener(VmsHalPublisherListener listener) {
97 mPublisherListeners.add(listener);
Antonio Cortes40b90262017-02-06 11:43:57 -080098 }
99
asafro99e4f082017-02-09 13:11:42 -0800100 public void addSubscriberListener(VmsHalSubscriberListener listener) {
101 mSubscriberListeners.add(listener);
Antonio Cortes734010a2017-01-19 20:09:22 -0800102 }
103
asafro99e4f082017-02-09 13:11:42 -0800104 public void removePublisherListener(VmsHalPublisherListener listener) {
105 mPublisherListeners.remove(listener);
Antonio Cortes734010a2017-01-19 20:09:22 -0800106 }
107
asafro99e4f082017-02-09 13:11:42 -0800108 public void removeSubscriberListener(VmsHalSubscriberListener listener) {
109 mSubscriberListeners.remove(listener);
Antonio Cortes734010a2017-01-19 20:09:22 -0800110 }
111
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700112 public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
asafro25a87402017-02-28 16:08:17 -0800113 synchronized (mLock) {
114 // Check if publishers need to be notified about this change in subscriptions.
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700115 boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
asafro25a87402017-02-28 16:08:17 -0800116
117 // Add the listeners subscription to the layer
118 mRouting.addSubscription(listener, layer);
119
120 // Notify the publishers
121 if (firstSubscriptionForLayer) {
122 notifyPublishers(layer, true);
123 }
124 }
125 }
126
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700127 public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
asafro25a87402017-02-28 16:08:17 -0800128 synchronized (mLock) {
129 if (!mRouting.hasLayerSubscriptions(layer)) {
130 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
131 return;
132 }
133
134 // Remove the listeners subscription to the layer
135 mRouting.removeSubscription(listener, layer);
136
137 // Check if publishers need to be notified about this change in subscriptions.
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700138 boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
asafro25a87402017-02-28 16:08:17 -0800139
140 // Notify the publishers
141 if (!layerHasSubscribers) {
142 notifyPublishers(layer, false);
143 }
144 }
145 }
146
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700147 public void addSubscription(IVmsSubscriberClient listener) {
asafro25a87402017-02-28 16:08:17 -0800148 synchronized (mLock) {
149 mRouting.addSubscription(listener);
150 }
151 }
152
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700153 public void removeSubscription(IVmsSubscriberClient listener) {
asafro25a87402017-02-28 16:08:17 -0800154 synchronized (mLock) {
155 mRouting.removeSubscription(listener);
156 }
157 }
158
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700159 public void removeDeadListener(IVmsSubscriberClient listener) {
asafro25a87402017-02-28 16:08:17 -0800160 synchronized (mLock) {
161 mRouting.removeDeadListener(listener);
162 }
163 }
164
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700165 public Set<IVmsSubscriberClient> getListeners(VmsLayer layer) {
Antonio Cortes8b350092017-03-16 16:02:51 -0700166 synchronized (mLock) {
167 return mRouting.getListeners(layer);
168 }
asafro25a87402017-02-28 16:08:17 -0800169 }
170
171 public boolean isHalSubscribed(VmsLayer layer) {
Antonio Cortes8b350092017-03-16 16:02:51 -0700172 synchronized (mLock) {
173 return mRouting.isHalSubscribed(layer);
174 }
asafro25a87402017-02-28 16:08:17 -0800175 }
176
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700177 public VmsSubscriptionState getSubscriptionState() {
Antonio Cortes8b350092017-03-16 16:02:51 -0700178 synchronized (mLock) {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700179 return mRouting.getSubscriptionState();
Antonio Cortes8b350092017-03-16 16:02:51 -0700180 }
asafro25a87402017-02-28 16:08:17 -0800181 }
182
183 public void addHalSubscription(VmsLayer layer) {
184 synchronized (mLock) {
185 // Check if publishers need to be notified about this change in subscriptions.
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700186 boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
asafro25a87402017-02-28 16:08:17 -0800187
188 // Add the listeners subscription to the layer
189 mRouting.addHalSubscription(layer);
190
191 if (firstSubscriptionForLayer) {
192 notifyPublishers(layer, true);
193 }
194 }
195 }
196
197 public void removeHalSubscription(VmsLayer layer) {
198 synchronized (mLock) {
199 if (!mRouting.hasLayerSubscriptions(layer)) {
200 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
201 return;
202 }
203
204 // Remove the listeners subscription to the layer
205 mRouting.removeHalSubscription(layer);
206
207 // Check if publishers need to be notified about this change in subscriptions.
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700208 boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
asafro25a87402017-02-28 16:08:17 -0800209
210 // Notify the publishers
211 if (!layerHasSubscribers) {
212 notifyPublishers(layer, false);
213 }
214 }
215 }
216
Asaf Rosenfeld2ca6f8c2017-03-20 12:59:33 -0700217 public boolean containsListener(IVmsSubscriberClient listener) {
Antonio Cortes8b350092017-03-16 16:02:51 -0700218 synchronized (mLock) {
219 return mRouting.containsListener(listener);
220 }
asafro25a87402017-02-28 16:08:17 -0800221 }
222
223 /**
224 * Notify all the publishers and the HAL on subscription changes regardless of who triggered
225 * the change.
226 *
Antonio Cortes9db963a2017-03-10 15:15:28 -0800227 * @param layer layer which is being subscribed to or unsubscribed from.
228 * @param hasSubscribers indicates if the notification is for subscription or unsubscription.
asafro25a87402017-02-28 16:08:17 -0800229 */
230 public void notifyPublishers(VmsLayer layer, boolean hasSubscribers) {
231 synchronized (mLock) {
232 // notify the HAL
Antonio Cortes01a60392017-03-22 13:00:02 -0700233 setSubscriptionRequest(layer, hasSubscribers);
asafro25a87402017-02-28 16:08:17 -0800234
235 // Notify the App publishers
236 for (VmsHalPublisherListener listener : mPublisherListeners) {
Antonio Cortes9db963a2017-03-10 15:15:28 -0800237 // Besides the list of layers, also a timestamp is provided to the clients.
238 // They should ignore any notification with a timestamp that is older than the most
239 // recent timestamp they have seen.
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700240 listener.onChange(getSubscriptionState());
asafro25a87402017-02-28 16:08:17 -0800241 }
242 }
243 }
244
Antonio Cortes734010a2017-01-19 20:09:22 -0800245 @Override
246 public void init() {
247 if (DBG) {
248 Log.d(TAG, "init()");
249 }
250 if (mIsSupported) {
251 mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID, 0);
252 }
253 }
254
255 @Override
256 public void release() {
257 if (DBG) {
258 Log.d(TAG, "release()");
259 }
260 if (mIsSupported) {
261 mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID);
262 }
asafro99e4f082017-02-09 13:11:42 -0800263 mPublisherListeners.clear();
264 mSubscriberListeners.clear();
Antonio Cortes734010a2017-01-19 20:09:22 -0800265 }
266
267 @Override
268 public Collection<VehiclePropConfig> takeSupportedProperties(
269 Collection<VehiclePropConfig> allProperties) {
270 List<VehiclePropConfig> taken = new LinkedList<>();
271 for (VehiclePropConfig p : allProperties) {
272 if (p.prop == HAL_PROPERTY_ID) {
273 taken.add(p);
274 mIsSupported = true;
275 if (DBG) {
276 Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop));
277 }
278 break;
279 }
280 }
281 return taken;
282 }
283
284 @Override
285 public void handleHalEvents(List<VehiclePropValue> values) {
asafro25a87402017-02-28 16:08:17 -0800286 if (DBG) {
287 Log.d(TAG, "Handling a VMS property change");
288 }
asafro99e4f082017-02-09 13:11:42 -0800289 for (VehiclePropValue v : values) {
290 ArrayList<Integer> vec = v.value.int32Values;
291 int messageType = vec.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
292 int layerId = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_ID);
293 int layerVersion = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_VERSION);
294
295 // Check if message type is supported.
296 if (!SUPPORTED_MESSAGE_TYPES.contains(messageType)) {
297 throw new IllegalArgumentException("Unexpected message type. " +
298 "Expecting: " + SUPPORTED_MESSAGE_TYPES +
299 ". Got: " + messageType);
300
301 }
302
asafro25a87402017-02-28 16:08:17 -0800303 if (DBG) {
304 Log.d(TAG,
305 "Received message for Type: " + messageType +
306 " Layer Id: " + layerId +
307 "Version: " + layerVersion);
308 }
asafro99e4f082017-02-09 13:11:42 -0800309 // This is a data message intended for subscribers.
310 if (messageType == VmsMessageType.DATA) {
311 // Get the payload.
312 byte[] payload = toByteArray(v.value.bytes);
313
314 // Send the message.
315 for (VmsHalSubscriberListener listener : mSubscriberListeners) {
Antonio Cortes01a60392017-03-22 13:00:02 -0700316 listener.onChange(new VmsLayer(layerId, layerVersion), payload);
asafro99e4f082017-02-09 13:11:42 -0800317 }
asafro25a87402017-02-28 16:08:17 -0800318 } else if (messageType == VmsMessageType.SUBSCRIBE) {
Antonio Cortes7e914102017-03-10 09:09:07 -0800319 addHalSubscription(new VmsLayer(layerId, layerVersion));
asafro25a87402017-02-28 16:08:17 -0800320 } else {
321 // messageType == VmsMessageType.UNSUBSCRIBE
Antonio Cortes7e914102017-03-10 09:09:07 -0800322 removeHalSubscription(new VmsLayer(layerId, layerVersion));
Antonio Cortes734010a2017-01-19 20:09:22 -0800323 }
324 }
325 }
326
327 @Override
328 public void dump(PrintWriter writer) {
329 writer.println(TAG);
330 writer.println("VmsProperty " + (mIsSupported ? "" : "not") + " supported.");
331 }
332
asafro99e4f082017-02-09 13:11:42 -0800333 /**
334 * Updates the VMS HAL property with the given value.
335 *
Antonio Cortes01a60392017-03-22 13:00:02 -0700336 * @param layer layer data to update the hal property.
337 * @param hasSubscribers if it is a subscribe or unsubscribe message.
338 * @return true if the call to the HAL to update the property was successful.
asafro99e4f082017-02-09 13:11:42 -0800339 */
Antonio Cortes01a60392017-03-22 13:00:02 -0700340 public boolean setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers) {
asafro25a87402017-02-28 16:08:17 -0800341 VehiclePropValue vehiclePropertyValue = toVehiclePropValue(
Antonio Cortes01a60392017-03-22 13:00:02 -0700342 hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
asafro99e4f082017-02-09 13:11:42 -0800343 return setPropertyValue(vehiclePropertyValue);
344 }
345
Antonio Cortes01a60392017-03-22 13:00:02 -0700346 public boolean setDataMessage(VmsLayer layer, byte[] payload) {
asafro99e4f082017-02-09 13:11:42 -0800347 VehiclePropValue vehiclePropertyValue = toVehiclePropValue(VmsMessageType.DATA,
Antonio Cortes01a60392017-03-22 13:00:02 -0700348 layer,
349 payload);
asafro99e4f082017-02-09 13:11:42 -0800350 return setPropertyValue(vehiclePropertyValue);
351 }
352
353 public boolean setPropertyValue(VehiclePropValue vehiclePropertyValue) {
354 try {
355 mVehicleHal.set(vehiclePropertyValue);
356 return true;
357 } catch (PropertyTimeoutException e) {
358 Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(HAL_PROPERTY_ID));
359 }
360 return false;
361 }
362
363 /** Creates a {@link VehiclePropValue} */
Antonio Cortes01a60392017-03-22 13:00:02 -0700364 private static VehiclePropValue toVehiclePropValue(int messageType, VmsLayer layer) {
Antonio Cortes734010a2017-01-19 20:09:22 -0800365 VehiclePropValue vehicleProp = new VehiclePropValue();
366 vehicleProp.prop = HAL_PROPERTY_ID;
367 vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
368 VehiclePropValue.RawValue v = vehicleProp.value;
asafro99e4f082017-02-09 13:11:42 -0800369
370 v.int32Values.add(messageType);
Antonio Cortes01a60392017-03-22 13:00:02 -0700371 v.int32Values.add(layer.getId());
372 v.int32Values.add(layer.getVersion());
asafro99e4f082017-02-09 13:11:42 -0800373 return vehicleProp;
374 }
375
Antonio Cortes01a60392017-03-22 13:00:02 -0700376 /** Creates a {@link VehiclePropValue} with payload */
377 private static VehiclePropValue toVehiclePropValue(int messageType,
378 VmsLayer layer,
379 byte[] payload) {
380 VehiclePropValue vehicleProp = toVehiclePropValue(messageType, layer);
asafro99e4f082017-02-09 13:11:42 -0800381 VehiclePropValue.RawValue v = vehicleProp.value;
382 v.bytes.ensureCapacity(payload.length);
383 for (byte b : payload) {
384 v.bytes.add(b);
385 }
Antonio Cortes734010a2017-01-19 20:09:22 -0800386 return vehicleProp;
387 }
asafro25a87402017-02-28 16:08:17 -0800388}