• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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  */
16 package com.android.car.hal;
17 
18 import static com.android.car.CarServiceUtils.toByteArray;
19 
20 import static java.lang.Integer.toHexString;
21 
22 import android.annotation.SystemApi;
23 import android.car.VehicleAreaType;
24 import android.car.vms.IVmsSubscriberClient;
25 import android.car.vms.VmsAssociatedLayer;
26 import android.car.vms.VmsAvailableLayers;
27 import android.car.vms.VmsLayer;
28 import android.car.vms.VmsLayerDependency;
29 import android.car.vms.VmsLayersOffering;
30 import android.car.vms.VmsOperationRecorder;
31 import android.car.vms.VmsSubscriptionState;
32 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
33 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
34 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
35 import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
36 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
37 import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex;
38 import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerIntegerValuesIndex;
39 import android.hardware.automotive.vehicle.V2_0.VmsOfferingMessageIntegerValuesIndex;
40 import android.os.Binder;
41 import android.os.IBinder;
42 import android.util.Log;
43 
44 import com.android.car.CarLog;
45 import com.android.car.VmsLayersAvailability;
46 import com.android.car.VmsPublishersInfo;
47 import com.android.car.VmsRouting;
48 import com.android.internal.annotations.GuardedBy;
49 
50 import java.io.PrintWriter;
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.Collections;
55 import java.util.HashMap;
56 import java.util.HashSet;
57 import java.util.LinkedList;
58 import java.util.List;
59 import java.util.Map;
60 import java.util.Set;
61 import java.util.concurrent.CopyOnWriteArrayList;
62 
63 /**
64  * This is a glue layer between the VehicleHal and the VmsService. It sends VMS properties back and
65  * forth.
66  */
67 @SystemApi
68 public class VmsHalService extends HalServiceBase {
69 
70     private static final boolean DBG = true;
71     private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
72     private static final String TAG = "VmsHalService";
73 
74     private final static List<Integer> AVAILABILITY_MESSAGE_TYPES = Collections.unmodifiableList(
75             Arrays.asList(
76                     VmsMessageType.AVAILABILITY_RESPONSE,
77                     VmsMessageType.AVAILABILITY_CHANGE));
78 
79     private boolean mIsSupported = false;
80     private CopyOnWriteArrayList<VmsHalPublisherListener> mPublisherListeners =
81             new CopyOnWriteArrayList<>();
82     private CopyOnWriteArrayList<VmsHalSubscriberListener> mSubscriberListeners =
83             new CopyOnWriteArrayList<>();
84 
85     private final IBinder mHalPublisherToken = new Binder();
86     private final VehicleHal mVehicleHal;
87 
88     private final Object mLock = new Object();
89     private final VmsRouting mRouting = new VmsRouting();
90     @GuardedBy("mLock")
91     private final Map<IBinder, VmsLayersOffering> mOfferings = new HashMap<>();
92     @GuardedBy("mLock")
93     private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
94     private final VmsPublishersInfo mPublishersInfo = new VmsPublishersInfo();
95 
96     /**
97      * The VmsPublisherService implements this interface to receive data from the HAL.
98      */
99     public interface VmsHalPublisherListener {
onChange(VmsSubscriptionState subscriptionState)100         void onChange(VmsSubscriptionState subscriptionState);
101     }
102 
103     /**
104      * The VmsSubscriberService implements this interface to receive data from the HAL.
105      */
106     public interface VmsHalSubscriberListener {
107         // Notifies the listener on a data Message from a publisher.
onDataMessage(VmsLayer layer, int publisherId, byte[] payload)108         void onDataMessage(VmsLayer layer, int publisherId, byte[] payload);
109 
110         // Notifies the listener on a change in available layers.
onLayersAvaiabilityChange(VmsAvailableLayers availableLayers)111         void onLayersAvaiabilityChange(VmsAvailableLayers availableLayers);
112     }
113 
114     /**
115      * The VmsService implements this interface to receive data from the HAL.
116      */
VmsHalService(VehicleHal vehicleHal)117     protected VmsHalService(VehicleHal vehicleHal) {
118         mVehicleHal = vehicleHal;
119         if (DBG) {
120             Log.d(TAG, "started VmsHalService!");
121         }
122     }
123 
addPublisherListener(VmsHalPublisherListener listener)124     public void addPublisherListener(VmsHalPublisherListener listener) {
125         mPublisherListeners.add(listener);
126     }
127 
addSubscriberListener(VmsHalSubscriberListener listener)128     public void addSubscriberListener(VmsHalSubscriberListener listener) {
129         mSubscriberListeners.add(listener);
130     }
131 
removePublisherListener(VmsHalPublisherListener listener)132     public void removePublisherListener(VmsHalPublisherListener listener) {
133         mPublisherListeners.remove(listener);
134     }
135 
removeSubscriberListener(VmsHalSubscriberListener listener)136     public void removeSubscriberListener(VmsHalSubscriberListener listener) {
137         mSubscriberListeners.remove(listener);
138     }
139 
addSubscription(IVmsSubscriberClient listener, VmsLayer layer)140     public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
141         boolean firstSubscriptionForLayer = false;
142         if (DBG) {
143             Log.d(TAG, "Checking for first subscription. Layer: " + layer);
144         }
145         synchronized (mLock) {
146             // Check if publishers need to be notified about this change in subscriptions.
147             firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
148 
149             // Add the listeners subscription to the layer
150             mRouting.addSubscription(listener, layer);
151         }
152         if (firstSubscriptionForLayer) {
153             notifyHalPublishers(layer, true);
154             notifyClientPublishers();
155         }
156     }
157 
removeSubscription(IVmsSubscriberClient listener, VmsLayer layer)158     public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
159         boolean layerHasSubscribers = true;
160         synchronized (mLock) {
161             if (!mRouting.hasLayerSubscriptions(layer)) {
162                 if (DBG) {
163                     Log.d(TAG, "Trying to remove a layer with no subscription: " + layer);
164                 }
165                 return;
166             }
167 
168             // Remove the listeners subscription to the layer
169             mRouting.removeSubscription(listener, layer);
170 
171             // Check if publishers need to be notified about this change in subscriptions.
172             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
173         }
174         if (!layerHasSubscribers) {
175             notifyHalPublishers(layer, false);
176             notifyClientPublishers();
177         }
178     }
179 
addSubscription(IVmsSubscriberClient listener)180     public void addSubscription(IVmsSubscriberClient listener) {
181         synchronized (mLock) {
182             mRouting.addSubscription(listener);
183         }
184     }
185 
removeSubscription(IVmsSubscriberClient listener)186     public void removeSubscription(IVmsSubscriberClient listener) {
187         synchronized (mLock) {
188             mRouting.removeSubscription(listener);
189         }
190     }
191 
addSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId)192     public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId) {
193         boolean firstSubscriptionForLayer = false;
194         synchronized (mLock) {
195             // Check if publishers need to be notified about this change in subscriptions.
196             firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer) ||
197                     mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId));
198 
199             // Add the listeners subscription to the layer
200             mRouting.addSubscription(listener, layer, publisherId);
201         }
202         if (firstSubscriptionForLayer) {
203             notifyHalPublishers(layer, true);
204             notifyClientPublishers();
205         }
206     }
207 
removeSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId)208     public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId) {
209         boolean layerHasSubscribers = true;
210         synchronized (mLock) {
211             if (!mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)) {
212                 Log.i(TAG, "Trying to remove a layer with no subscription: " +
213                         layer + ", publisher ID:" + publisherId);
214                 return;
215             }
216 
217             // Remove the listeners subscription to the layer
218             mRouting.removeSubscription(listener, layer, publisherId);
219 
220             // Check if publishers need to be notified about this change in subscriptions.
221             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer) ||
222                     mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId);
223         }
224         if (!layerHasSubscribers) {
225             notifyHalPublishers(layer, false);
226             notifyClientPublishers();
227         }
228     }
229 
removeDeadSubscriber(IVmsSubscriberClient listener)230     public void removeDeadSubscriber(IVmsSubscriberClient listener) {
231         synchronized (mLock) {
232             mRouting.removeDeadSubscriber(listener);
233         }
234     }
235 
getSubscribersForLayerFromPublisher(VmsLayer layer, int publisherId)236     public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer,
237                                                                          int publisherId) {
238         synchronized (mLock) {
239             return mRouting.getSubscribersForLayerFromPublisher(layer, publisherId);
240         }
241     }
242 
getAllSubscribers()243     public Set<IVmsSubscriberClient> getAllSubscribers() {
244         synchronized (mLock) {
245             return mRouting.getAllSubscribers();
246         }
247     }
248 
isHalSubscribed(VmsLayer layer)249     public boolean isHalSubscribed(VmsLayer layer) {
250         synchronized (mLock) {
251             return mRouting.isHalSubscribed(layer);
252         }
253     }
254 
getSubscriptionState()255     public VmsSubscriptionState getSubscriptionState() {
256         synchronized (mLock) {
257             return mRouting.getSubscriptionState();
258         }
259     }
260 
261     /**
262      * Assigns an idempotent ID for publisherInfo and stores it. The idempotency in this case means
263      * that the same publisherInfo will always, within a trip of the vehicle, return the same ID.
264      * The publisherInfo should be static for a binary and should only change as part of a software
265      * update. The publisherInfo is a serialized proto message which VMS clients can interpret.
266      */
getPublisherId(byte[] publisherInfo)267     public int getPublisherId(byte[] publisherInfo) {
268         if (DBG) {
269             Log.i(TAG, "Getting publisher static ID");
270         }
271         synchronized (mLock) {
272             return mPublishersInfo.getIdForInfo(publisherInfo);
273         }
274     }
275 
getPublisherInfo(int publisherId)276     public byte[] getPublisherInfo(int publisherId) {
277         if (DBG) {
278             Log.i(TAG, "Getting information for publisher ID: " + publisherId);
279         }
280         synchronized (mLock) {
281             return mPublishersInfo.getPublisherInfo(publisherId);
282         }
283     }
284 
addHalSubscription(VmsLayer layer)285     private void addHalSubscription(VmsLayer layer) {
286         boolean firstSubscriptionForLayer = true;
287         synchronized (mLock) {
288             // Check if publishers need to be notified about this change in subscriptions.
289             firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
290 
291             // Add the listeners subscription to the layer
292             mRouting.addHalSubscription(layer);
293         }
294         if (firstSubscriptionForLayer) {
295             notifyHalPublishers(layer, true);
296             notifyClientPublishers();
297         }
298     }
299 
addHalSubscriptionToPublisher(VmsLayer layer, int publisherId)300     private void addHalSubscriptionToPublisher(VmsLayer layer, int publisherId) {
301         boolean firstSubscriptionForLayer = true;
302         synchronized (mLock) {
303             // Check if publishers need to be notified about this change in subscriptions.
304             firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer) ||
305                     mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId));
306 
307             // Add the listeners subscription to the layer
308             mRouting.addHalSubscriptionToPublisher(layer, publisherId);
309         }
310         if (firstSubscriptionForLayer) {
311             notifyHalPublishers(layer, publisherId, true);
312             notifyClientPublishers();
313         }
314     }
315 
removeHalSubscription(VmsLayer layer)316     private void removeHalSubscription(VmsLayer layer) {
317         boolean layerHasSubscribers = true;
318         synchronized (mLock) {
319             if (!mRouting.hasLayerSubscriptions(layer)) {
320                 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
321                 return;
322             }
323 
324             // Remove the listeners subscription to the layer
325             mRouting.removeHalSubscription(layer);
326 
327             // Check if publishers need to be notified about this change in subscriptions.
328             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
329         }
330         if (!layerHasSubscribers) {
331             notifyHalPublishers(layer, false);
332             notifyClientPublishers();
333         }
334     }
335 
removeHalSubscriptionFromPublisher(VmsLayer layer, int publisherId)336     public void removeHalSubscriptionFromPublisher(VmsLayer layer, int publisherId) {
337         boolean layerHasSubscribers = true;
338         synchronized (mLock) {
339             if (!mRouting.hasLayerSubscriptions(layer)) {
340                 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
341                 return;
342             }
343 
344             // Remove the listeners subscription to the layer
345             mRouting.removeHalSubscriptionToPublisher(layer, publisherId);
346 
347             // Check if publishers need to be notified about this change in subscriptions.
348             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer) ||
349                     mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId);
350         }
351         if (!layerHasSubscribers) {
352             notifyHalPublishers(layer, publisherId, false);
353             notifyClientPublishers();
354         }
355     }
356 
containsSubscriber(IVmsSubscriberClient subscriber)357     public boolean containsSubscriber(IVmsSubscriberClient subscriber) {
358         synchronized (mLock) {
359             return mRouting.containsSubscriber(subscriber);
360         }
361     }
362 
setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering)363     public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering) {
364         synchronized (mLock) {
365             updateOffering(publisherToken, offering);
366             VmsOperationRecorder.get().setPublisherLayersOffering(offering);
367         }
368     }
369 
getAvailableLayers()370     public VmsAvailableLayers getAvailableLayers() {
371         synchronized (mLock) {
372             return mAvailableLayers.getAvailableLayers();
373         }
374     }
375 
376     /**
377      * Notify all the publishers and the HAL on subscription changes regardless of who triggered
378      * the change.
379      *
380      * @param layer          layer which is being subscribed to or unsubscribed from.
381      * @param hasSubscribers indicates if the notification is for subscription or unsubscription.
382      */
notifyHalPublishers(VmsLayer layer, boolean hasSubscribers)383     private void notifyHalPublishers(VmsLayer layer, boolean hasSubscribers) {
384         // notify the HAL
385         setSubscriptionRequest(layer, hasSubscribers);
386     }
387 
notifyHalPublishers(VmsLayer layer, int publisherId, boolean hasSubscribers)388     private void notifyHalPublishers(VmsLayer layer, int publisherId, boolean hasSubscribers) {
389         // notify the HAL
390         setSubscriptionToPublisherRequest(layer, publisherId, hasSubscribers);
391     }
392 
notifyClientPublishers()393     private void notifyClientPublishers() {
394         // Notify the App publishers
395         for (VmsHalPublisherListener listener : mPublisherListeners) {
396             // Besides the list of layers, also a timestamp is provided to the clients.
397             // They should ignore any notification with a timestamp that is older than the most
398             // recent timestamp they have seen.
399             listener.onChange(getSubscriptionState());
400         }
401     }
402 
403     /**
404      * Notify all the subscribers and the HAL on layers availability change.
405      *
406      * @param availableLayers the layers which publishers claim they made publish.
407      */
notifyOfAvailabilityChange(VmsAvailableLayers availableLayers)408     private void notifyOfAvailabilityChange(VmsAvailableLayers availableLayers) {
409         // notify the HAL
410         notifyAvailabilityChangeToHal(availableLayers);
411 
412         // Notify the App subscribers
413         for (VmsHalSubscriberListener listener : mSubscriberListeners) {
414             listener.onLayersAvaiabilityChange(availableLayers);
415         }
416     }
417 
418     @Override
init()419     public void init() {
420         if (DBG) {
421             Log.d(TAG, "init()");
422         }
423         if (mIsSupported) {
424             mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID);
425         }
426     }
427 
428     @Override
release()429     public void release() {
430         if (DBG) {
431             Log.d(TAG, "release()");
432         }
433         if (mIsSupported) {
434             mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID);
435         }
436         mPublisherListeners.clear();
437         mSubscriberListeners.clear();
438     }
439 
440     @Override
takeSupportedProperties( Collection<VehiclePropConfig> allProperties)441     public Collection<VehiclePropConfig> takeSupportedProperties(
442             Collection<VehiclePropConfig> allProperties) {
443         List<VehiclePropConfig> taken = new LinkedList<>();
444         for (VehiclePropConfig p : allProperties) {
445             if (p.prop == HAL_PROPERTY_ID) {
446                 taken.add(p);
447                 mIsSupported = true;
448                 if (DBG) {
449                     Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop));
450                 }
451                 break;
452             }
453         }
454         return taken;
455     }
456 
457     /**
458      * Consumes/produces HAL messages. The format of these messages is defined in:
459      * hardware/interfaces/automotive/vehicle/2.1/types.hal
460      */
461     @Override
handleHalEvents(List<VehiclePropValue> values)462     public void handleHalEvents(List<VehiclePropValue> values) {
463         if (DBG) {
464             Log.d(TAG, "Handling a VMS property change");
465         }
466         for (VehiclePropValue v : values) {
467             ArrayList<Integer> vec = v.value.int32Values;
468             int messageType = vec.get(VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE);
469 
470             if (DBG) {
471                 Log.d(TAG, "Handling VMS message type: " + messageType);
472             }
473             switch (messageType) {
474                 case VmsMessageType.DATA:
475                     handleDataEvent(vec, toByteArray(v.value.bytes));
476                     break;
477                 case VmsMessageType.SUBSCRIBE:
478                     handleSubscribeEvent(vec);
479                     break;
480                 case VmsMessageType.UNSUBSCRIBE:
481                     handleUnsubscribeEvent(vec);
482                     break;
483                 case VmsMessageType.SUBSCRIBE_TO_PUBLISHER:
484                     handleSubscribeToPublisherEvent(vec);
485                     break;
486                 case VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER:
487                     handleUnsubscribeFromPublisherEvent(vec);
488                     break;
489                 case VmsMessageType.OFFERING:
490                     handleOfferingEvent(vec);
491                     break;
492                 case VmsMessageType.AVAILABILITY_REQUEST:
493                     handleHalAvailabilityRequestEvent();
494                     break;
495                 case VmsMessageType.SUBSCRIPTIONS_REQUEST:
496                     handleSubscriptionsRequestEvent();
497                     break;
498                 default:
499                     throw new IllegalArgumentException("Unexpected message type: " + messageType);
500             }
501         }
502     }
503 
parseVmsLayerFromSimpleMessageIntegerValues(List<Integer> integerValues)504     private VmsLayer parseVmsLayerFromSimpleMessageIntegerValues(List<Integer> integerValues) {
505         return new VmsLayer(integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_TYPE),
506                 integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_SUBTYPE),
507                 integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_VERSION));
508     }
509 
parseVmsLayerFromDataMessageIntegerValues(List<Integer> integerValues)510     private VmsLayer parseVmsLayerFromDataMessageIntegerValues(List<Integer> integerValues) {
511         return parseVmsLayerFromSimpleMessageIntegerValues(integerValues);
512     }
513 
parsePublisherIdFromDataMessageIntegerValues(List<Integer> integerValues)514     private int parsePublisherIdFromDataMessageIntegerValues(List<Integer> integerValues) {
515         return integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID);
516     }
517 
518 
519     /**
520      * Data message format:
521      * <ul>
522      * <li>Message type.
523      * <li>Layer id.
524      * <li>Layer version.
525      * <li>Layer subtype.
526      * <li>Publisher ID.
527      * <li>Payload.
528      * </ul>
529      */
handleDataEvent(List<Integer> integerValues, byte[] payload)530     private void handleDataEvent(List<Integer> integerValues, byte[] payload) {
531         VmsLayer vmsLayer = parseVmsLayerFromDataMessageIntegerValues(integerValues);
532         int publisherId = parsePublisherIdFromDataMessageIntegerValues(integerValues);
533         if (DBG) {
534             Log.d(TAG, "Handling a data event for Layer: " + vmsLayer);
535         }
536 
537         // Send the message.
538         for (VmsHalSubscriberListener listener : mSubscriberListeners) {
539             listener.onDataMessage(vmsLayer, publisherId, payload);
540         }
541     }
542 
543     /**
544      * Subscribe message format:
545      * <ul>
546      * <li>Message type.
547      * <li>Layer id.
548      * <li>Layer version.
549      * <li>Layer subtype.
550      * </ul>
551      */
handleSubscribeEvent(List<Integer> integerValues)552     private void handleSubscribeEvent(List<Integer> integerValues) {
553         VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues);
554         if (DBG) {
555             Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer);
556         }
557         addHalSubscription(vmsLayer);
558     }
559 
560     /**
561      * Subscribe message format:
562      * <ul>
563      * <li>Message type.
564      * <li>Layer id.
565      * <li>Layer version.
566      * <li>Layer subtype.
567      * <li>Publisher ID
568      * </ul>
569      */
handleSubscribeToPublisherEvent(List<Integer> integerValues)570     private void handleSubscribeToPublisherEvent(List<Integer> integerValues) {
571         VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues);
572         if (DBG) {
573             Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer);
574         }
575         int publisherId =
576                 integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID);
577         addHalSubscriptionToPublisher(vmsLayer, publisherId);
578     }
579 
580     /**
581      * Unsubscribe message format:
582      * <ul>
583      * <li>Message type.
584      * <li>Layer id.
585      * <li>Layer version.
586      * </ul>
587      */
handleUnsubscribeEvent(List<Integer> integerValues)588     private void handleUnsubscribeEvent(List<Integer> integerValues) {
589         VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues);
590         if (DBG) {
591             Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer);
592         }
593         removeHalSubscription(vmsLayer);
594     }
595 
596     /**
597      * Unsubscribe message format:
598      * <ul>
599      * <li>Message type.
600      * <li>Layer id.
601      * <li>Layer version.
602      * </ul>
603      */
handleUnsubscribeFromPublisherEvent(List<Integer> integerValues)604     private void handleUnsubscribeFromPublisherEvent(List<Integer> integerValues) {
605         VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues);
606         int publisherId =
607                 integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID);
608         if (DBG) {
609             Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer);
610         }
611         removeHalSubscriptionFromPublisher(vmsLayer, publisherId);
612     }
613 
614     private static int NUM_INTEGERS_IN_VMS_LAYER = 3;
615 
parseVmsLayerFromIndex(List<Integer> integerValues, int index)616     private VmsLayer parseVmsLayerFromIndex(List<Integer> integerValues, int index) {
617         int layerType = integerValues.get(index++);
618         int layerSutype = integerValues.get(index++);
619         int layerVersion = integerValues.get(index++);
620         return new VmsLayer(layerType, layerSutype, layerVersion);
621     }
622 
623     /**
624      * Offering message format:
625      * <ul>
626      * <li>Message type.
627      * <li>Publisher ID.
628      * <li>Number of offerings.
629      * <li>Each offering consists of:
630      * <ul>
631      * <li>Layer id.
632      * <li>Layer version.
633      * <li>Number of layer dependencies.
634      * <li>Layer type/subtype/version.
635      * </ul>
636      * </ul>
637      */
handleOfferingEvent(List<Integer> integerValues)638     private void handleOfferingEvent(List<Integer> integerValues) {
639         int publisherId = integerValues.get(VmsOfferingMessageIntegerValuesIndex.PUBLISHER_ID);
640         int numLayersDependencies =
641                 integerValues.get(
642                         VmsOfferingMessageIntegerValuesIndex.NUMBER_OF_OFFERS);
643         int idx = VmsOfferingMessageIntegerValuesIndex.OFFERING_START;
644 
645         Set<VmsLayerDependency> offeredLayers = new HashSet<>();
646 
647         // An offering is layerId, LayerVersion, LayerType, NumDeps, <LayerId, LayerVersion> X NumDeps.
648         for (int i = 0; i < numLayersDependencies; i++) {
649             VmsLayer offeredLayer = parseVmsLayerFromIndex(integerValues, idx);
650             idx += NUM_INTEGERS_IN_VMS_LAYER;
651 
652             int numDependenciesForLayer = integerValues.get(idx++);
653             if (numDependenciesForLayer == 0) {
654                 offeredLayers.add(new VmsLayerDependency(offeredLayer));
655             } else {
656                 Set<VmsLayer> dependencies = new HashSet<>();
657 
658                 for (int j = 0; j < numDependenciesForLayer; j++) {
659                     VmsLayer dependantLayer = parseVmsLayerFromIndex(integerValues, idx);
660                     idx += NUM_INTEGERS_IN_VMS_LAYER;
661                     dependencies.add(dependantLayer);
662                 }
663                 offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies));
664             }
665         }
666         // Store the HAL offering.
667         VmsLayersOffering offering = new VmsLayersOffering(offeredLayers, publisherId);
668         synchronized (mLock) {
669             updateOffering(mHalPublisherToken, offering);
670             VmsOperationRecorder.get().setHalPublisherLayersOffering(offering);
671         }
672     }
673 
674     /**
675      * Availability message format:
676      * <ul>
677      * <li>Message type.
678      * <li>Number of layers.
679      * <li>Layer type/subtype/version.
680      * </ul>
681      */
handleHalAvailabilityRequestEvent()682     private void handleHalAvailabilityRequestEvent() {
683         synchronized (mLock) {
684             VmsAvailableLayers availableLayers = mAvailableLayers.getAvailableLayers();
685             VehiclePropValue vehiclePropertyValue =
686                     toAvailabilityUpdateVehiclePropValue(
687                             availableLayers,
688                             VmsMessageType.AVAILABILITY_RESPONSE);
689 
690             setPropertyValue(vehiclePropertyValue);
691         }
692     }
693 
694     /**
695      * VmsSubscriptionRequestFormat:
696      * <ul>
697      * <li>Message type.
698      * </ul>
699      * <p>
700      * VmsSubscriptionResponseFormat:
701      * <ul>
702      * <li>Message type.
703      * <li>Sequence number.
704      * <li>Number of layers.
705      * <li>Layer type/subtype/version.
706      * </ul>
707      */
handleSubscriptionsRequestEvent()708     private void handleSubscriptionsRequestEvent() {
709         VmsSubscriptionState subscription = getSubscriptionState();
710         VehiclePropValue vehicleProp =
711                 toTypedVmsVehiclePropValue(VmsMessageType.SUBSCRIPTIONS_RESPONSE);
712         VehiclePropValue.RawValue v = vehicleProp.value;
713         v.int32Values.add(subscription.getSequenceNumber());
714         Set<VmsLayer> layers = subscription.getLayers();
715         v.int32Values.add(layers.size());
716 
717         //TODO(asafro): get the real number of associated layers in the subscriptions
718         //              state and send the associated layers themselves.
719         v.int32Values.add(0);
720 
721         for (VmsLayer layer : layers) {
722             v.int32Values.add(layer.getType());
723             v.int32Values.add(layer.getSubtype());
724             v.int32Values.add(layer.getVersion());
725         }
726         setPropertyValue(vehicleProp);
727     }
728 
updateOffering(IBinder publisherToken, VmsLayersOffering offering)729     private void updateOffering(IBinder publisherToken, VmsLayersOffering offering) {
730         VmsAvailableLayers availableLayers;
731         synchronized (mLock) {
732             mOfferings.put(publisherToken, offering);
733 
734             // Update layers availability.
735             mAvailableLayers.setPublishersOffering(mOfferings.values());
736 
737             availableLayers = mAvailableLayers.getAvailableLayers();
738         }
739         notifyOfAvailabilityChange(availableLayers);
740     }
741 
742     @Override
dump(PrintWriter writer)743     public void dump(PrintWriter writer) {
744         writer.println(TAG);
745         writer.println("VmsProperty " + (mIsSupported ? "" : "not") + " supported.");
746     }
747 
748     /**
749      * Updates the VMS HAL property with the given value.
750      *
751      * @param layer          layer data to update the hal property.
752      * @param hasSubscribers if it is a subscribe or unsubscribe message.
753      * @return true if the call to the HAL to update the property was successful.
754      */
setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers)755     public boolean setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers) {
756         VehiclePropValue vehiclePropertyValue = toTypedVmsVehiclePropValueWithLayer(
757                 hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
758         return setPropertyValue(vehiclePropertyValue);
759     }
760 
setSubscriptionToPublisherRequest(VmsLayer layer, int publisherId, boolean hasSubscribers)761     public boolean setSubscriptionToPublisherRequest(VmsLayer layer,
762                                                      int publisherId,
763                                                      boolean hasSubscribers) {
764         VehiclePropValue vehiclePropertyValue = toTypedVmsVehiclePropValueWithLayer(
765                 hasSubscribers ?
766                         VmsMessageType.SUBSCRIBE_TO_PUBLISHER :
767                         VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER, layer);
768         vehiclePropertyValue.value.int32Values.add(publisherId);
769         return setPropertyValue(vehiclePropertyValue);
770     }
771 
setDataMessage(VmsLayer layer, byte[] payload)772     public boolean setDataMessage(VmsLayer layer, byte[] payload) {
773         VehiclePropValue vehiclePropertyValue =
774                 toTypedVmsVehiclePropValueWithLayer(VmsMessageType.DATA, layer);
775         VehiclePropValue.RawValue v = vehiclePropertyValue.value;
776         v.bytes.ensureCapacity(payload.length);
777         for (byte b : payload) {
778             v.bytes.add(b);
779         }
780         return setPropertyValue(vehiclePropertyValue);
781     }
782 
notifyAvailabilityChangeToHal(VmsAvailableLayers availableLayers)783     public boolean notifyAvailabilityChangeToHal(VmsAvailableLayers availableLayers) {
784         VehiclePropValue vehiclePropertyValue =
785                 toAvailabilityUpdateVehiclePropValue(
786                         availableLayers,
787                         VmsMessageType.AVAILABILITY_CHANGE);
788 
789         return setPropertyValue(vehiclePropertyValue);
790     }
791 
setPropertyValue(VehiclePropValue vehiclePropertyValue)792     public boolean setPropertyValue(VehiclePropValue vehiclePropertyValue) {
793         try {
794             mVehicleHal.set(vehiclePropertyValue);
795             return true;
796         } catch (PropertyTimeoutException e) {
797             Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(HAL_PROPERTY_ID));
798         }
799         return false;
800     }
801 
toTypedVmsVehiclePropValue(int messageType)802     private static VehiclePropValue toTypedVmsVehiclePropValue(int messageType) {
803         VehiclePropValue vehicleProp = new VehiclePropValue();
804         vehicleProp.prop = HAL_PROPERTY_ID;
805         vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
806         VehiclePropValue.RawValue v = vehicleProp.value;
807 
808         v.int32Values.add(messageType);
809         return vehicleProp;
810     }
811 
812     /**
813      * Creates a {@link VehiclePropValue}
814      */
toTypedVmsVehiclePropValueWithLayer( int messageType, VmsLayer layer)815     private static VehiclePropValue toTypedVmsVehiclePropValueWithLayer(
816             int messageType, VmsLayer layer) {
817         VehiclePropValue vehicleProp = toTypedVmsVehiclePropValue(messageType);
818         VehiclePropValue.RawValue v = vehicleProp.value;
819         v.int32Values.add(layer.getType());
820         v.int32Values.add(layer.getSubtype());
821         v.int32Values.add(layer.getVersion());
822         return vehicleProp;
823     }
824 
toAvailabilityUpdateVehiclePropValue( VmsAvailableLayers availableLayers, int messageType)825     private static VehiclePropValue toAvailabilityUpdateVehiclePropValue(
826             VmsAvailableLayers availableLayers, int messageType) {
827 
828         if (!AVAILABILITY_MESSAGE_TYPES.contains(messageType)) {
829             throw new IllegalArgumentException("Unsupported availability type: " + messageType);
830         }
831         VehiclePropValue vehicleProp =
832                 toTypedVmsVehiclePropValue(messageType);
833         populateAvailabilityPropValueFields(availableLayers, vehicleProp);
834         return vehicleProp;
835 
836     }
837 
populateAvailabilityPropValueFields( VmsAvailableLayers availableAssociatedLayers, VehiclePropValue vehicleProp)838     private static void populateAvailabilityPropValueFields(
839             VmsAvailableLayers availableAssociatedLayers,
840             VehiclePropValue vehicleProp) {
841         VehiclePropValue.RawValue v = vehicleProp.value;
842         v.int32Values.add(availableAssociatedLayers.getSequence());
843         int numLayers = availableAssociatedLayers.getAssociatedLayers().size();
844         v.int32Values.add(numLayers);
845         for (VmsAssociatedLayer layer : availableAssociatedLayers.getAssociatedLayers()) {
846             v.int32Values.add(layer.getVmsLayer().getType());
847             v.int32Values.add(layer.getVmsLayer().getSubtype());
848             v.int32Values.add(layer.getVmsLayer().getVersion());
849             v.int32Values.add(layer.getPublisherIds().size());
850             for (int publisherId : layer.getPublisherIds()) {
851                 v.int32Values.add(publisherId);
852             }
853         }
854     }
855 }
856