• 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.car.VehicleAreaType;
23 import android.car.vms.IVmsPublisherClient;
24 import android.car.vms.IVmsPublisherService;
25 import android.car.vms.IVmsSubscriberClient;
26 import android.car.vms.IVmsSubscriberService;
27 import android.car.vms.VmsAssociatedLayer;
28 import android.car.vms.VmsAvailableLayers;
29 import android.car.vms.VmsLayer;
30 import android.car.vms.VmsLayerDependency;
31 import android.car.vms.VmsLayersOffering;
32 import android.car.vms.VmsOperationRecorder;
33 import android.car.vms.VmsSubscriptionState;
34 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
35 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
36 import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
37 import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex;
38 import android.hardware.automotive.vehicle.V2_0.VmsMessageType;
39 import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex;
40 import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerIntegerValuesIndex;
41 import android.hardware.automotive.vehicle.V2_0.VmsOfferingMessageIntegerValuesIndex;
42 import android.hardware.automotive.vehicle.V2_0.VmsPublisherInformationIntegerValuesIndex;
43 import android.hardware.automotive.vehicle.V2_0.VmsStartSessionMessageIntegerValuesIndex;
44 import android.os.Handler;
45 import android.os.HandlerThread;
46 import android.os.IBinder;
47 import android.os.Message;
48 import android.os.RemoteException;
49 import android.os.SystemClock;
50 import android.util.ArraySet;
51 import android.util.Log;
52 
53 import androidx.annotation.VisibleForTesting;
54 
55 import com.android.car.CarLog;
56 
57 import java.io.PrintWriter;
58 import java.util.ArrayList;
59 import java.util.Arrays;
60 import java.util.Collection;
61 import java.util.Collections;
62 import java.util.HashSet;
63 import java.util.List;
64 import java.util.Set;
65 import java.util.function.Consumer;
66 import java.util.function.Supplier;
67 
68 /**
69  * VMS client implementation that proxies VmsPublisher/VmsSubscriber API calls to the Vehicle HAL
70  * using HAL-specific message encodings.
71  *
72  * @see android.hardware.automotive.vehicle.V2_0
73  */
74 public class VmsHalService extends HalServiceBase {
75     private static final boolean DBG = true;
76     private static final String TAG = "VmsHalService";
77     private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
78     private static final int NUM_INTEGERS_IN_VMS_LAYER = 3;
79     private static final int UNKNOWN_CLIENT_ID = -1;
80 
81     private final VehicleHal mVehicleHal;
82     private final int mCoreId;
83     private final MessageQueue mMessageQueue;
84     private volatile boolean mIsSupported = false;
85 
86     private IVmsPublisherService mPublisherService;
87     private Consumer<IBinder> mPublisherOnHalConnected;
88     private Runnable mPublisherOnHalDisconnected;
89     private IBinder mPublisherToken;
90 
91     private IVmsSubscriberService mSubscriberService;
92     private Consumer<IVmsSubscriberClient> mSuscriberOnHalDisconnected;
93 
94     private int mSubscriptionStateSequence = -1;
95     private int mAvailableLayersSequence = -1;
96 
97     private final IVmsPublisherClient.Stub mPublisherClient = new IVmsPublisherClient.Stub() {
98         @Override
99         public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
100             mPublisherToken = token;
101             mPublisherService = service;
102         }
103 
104         @Override
105         public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
106             if (DBG) Log.d(TAG, "Handling a subscription state change");
107             // Drop out-of-order notifications
108             if (subscriptionState.getSequenceNumber() <= mSubscriptionStateSequence) {
109                 Log.w(TAG,
110                         String.format("Out of order subscription state received: %d (expecting %d)",
111                                 subscriptionState.getSequenceNumber(),
112                                 mSubscriptionStateSequence + 1));
113                 return;
114             }
115             mSubscriptionStateSequence = subscriptionState.getSequenceNumber();
116             mMessageQueue.enqueue(VmsMessageType.SUBSCRIPTIONS_CHANGE,
117                     createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_CHANGE,
118                             subscriptionState));
119         }
120     };
121 
122     private final IVmsSubscriberClient.Stub mSubscriberClient = new IVmsSubscriberClient.Stub() {
123         @Override
124         public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
125             if (DBG) Log.d(TAG, "Handling a data message for Layer: " + layer);
126             mMessageQueue.enqueue(VmsMessageType.DATA, createDataMessage(layer, payload));
127         }
128 
129         @Override
130         public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) {
131             if (DBG) Log.d(TAG, "Handling a layer availability change");
132             // Drop out-of-order notifications
133             if (availableLayers.getSequence() <= mAvailableLayersSequence) {
134                 Log.w(TAG,
135                         String.format("Out of order layer availability received: %d (expecting %d)",
136                                 availableLayers.getSequence(),
137                                 mAvailableLayersSequence + 1));
138                 return;
139             }
140             mAvailableLayersSequence = availableLayers.getSequence();
141             mMessageQueue.enqueue(VmsMessageType.AVAILABILITY_CHANGE,
142                     createAvailableLayersMessage(VmsMessageType.AVAILABILITY_CHANGE,
143                             availableLayers));
144         }
145     };
146 
147     private class MessageQueue implements Handler.Callback {
148         private final Set<Integer> mSupportedMessageTypes = new ArraySet<>(Arrays.asList(
149                 VmsMessageType.DATA,
150                 VmsMessageType.START_SESSION,
151                 VmsMessageType.AVAILABILITY_CHANGE,
152                 VmsMessageType.SUBSCRIPTIONS_CHANGE
153         ));
154         private HandlerThread mHandlerThread;
155         private Handler mHandler;
156 
init()157         synchronized void init() {
158             mHandlerThread = new HandlerThread(TAG);
159             mHandlerThread.start();
160             mHandler = new Handler(mHandlerThread.getLooper(), this);
161         }
162 
release()163         synchronized void release() {
164             if (mHandlerThread != null) {
165                 mHandlerThread.quitSafely();
166             }
167         }
168 
enqueue(int messageType, Object message)169         synchronized void enqueue(int messageType, Object message) {
170             if (mSupportedMessageTypes.contains(messageType)) {
171                 Message.obtain(mHandler, messageType, message).sendToTarget();
172             } else {
173                 Log.e(TAG, "Unexpected message type: " + VmsMessageType.toString(messageType));
174             }
175         }
176 
clear()177         synchronized void clear() {
178             mSupportedMessageTypes.forEach(mHandler::removeMessages);
179         }
180 
181         @Override
handleMessage(Message msg)182         public boolean handleMessage(Message msg) {
183             int messageType = msg.what;
184             VehiclePropValue vehicleProp = (VehiclePropValue) msg.obj;
185             if (DBG) Log.d(TAG, "Sending " + VmsMessageType.toString(messageType) + " message");
186             try {
187                 setPropertyValue(vehicleProp);
188             } catch (RemoteException e) {
189                 Log.e(TAG, "While sending " + VmsMessageType.toString(messageType));
190             }
191             return true;
192         }
193     }
194 
195     /**
196      * Constructor used by {@link VehicleHal}
197      */
VmsHalService(VehicleHal vehicleHal)198     VmsHalService(VehicleHal vehicleHal) {
199         this(vehicleHal, SystemClock::uptimeMillis);
200     }
201 
202     @VisibleForTesting
VmsHalService(VehicleHal vehicleHal, Supplier<Long> getCoreId)203     VmsHalService(VehicleHal vehicleHal, Supplier<Long> getCoreId) {
204         mVehicleHal = vehicleHal;
205         mCoreId = (int) (getCoreId.get() % Integer.MAX_VALUE);
206         mMessageQueue = new MessageQueue();
207     }
208 
209     /**
210      * Retrieves the callback message handler for use by unit tests.
211      */
212     @VisibleForTesting
getHandler()213     Handler getHandler() {
214         return mMessageQueue.mHandler;
215     }
216 
217     /**
218      * Gets the {@link IVmsPublisherClient} implementation for the HAL's publisher callback.
219      */
setPublisherConnectionCallbacks(Consumer<IBinder> onHalConnected, Runnable onHalDisconnected)220     public void setPublisherConnectionCallbacks(Consumer<IBinder> onHalConnected,
221             Runnable onHalDisconnected) {
222         mPublisherOnHalConnected = onHalConnected;
223         mPublisherOnHalDisconnected = onHalDisconnected;
224     }
225 
226     /**
227      * Sets a reference to the {@link IVmsSubscriberService} implementation for use by the HAL.
228      */
setVmsSubscriberService(IVmsSubscriberService service, Consumer<IVmsSubscriberClient> onHalDisconnected)229     public void setVmsSubscriberService(IVmsSubscriberService service,
230             Consumer<IVmsSubscriberClient> onHalDisconnected) {
231         mSubscriberService = service;
232         mSuscriberOnHalDisconnected = onHalDisconnected;
233     }
234 
235     @Override
takeSupportedProperties( Collection<VehiclePropConfig> allProperties)236     public Collection<VehiclePropConfig> takeSupportedProperties(
237             Collection<VehiclePropConfig> allProperties) {
238         for (VehiclePropConfig p : allProperties) {
239             if (p.prop == HAL_PROPERTY_ID) {
240                 mIsSupported = true;
241                 return Collections.singleton(p);
242             }
243         }
244         return Collections.emptySet();
245     }
246 
247     @Override
init()248     public void init() {
249         if (mIsSupported) {
250             if (DBG) Log.d(TAG, "Initializing VmsHalService VHAL property");
251             mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID);
252         } else {
253             if (DBG) Log.d(TAG, "VmsHalService VHAL property not supported");
254             return; // Do not continue initialization
255         }
256 
257         mMessageQueue.init();
258         mMessageQueue.enqueue(VmsMessageType.START_SESSION,
259                 createStartSessionMessage(mCoreId, UNKNOWN_CLIENT_ID));
260     }
261 
262     @Override
release()263     public void release() {
264         mMessageQueue.release();
265         mSubscriptionStateSequence = -1;
266         mAvailableLayersSequence = -1;
267 
268         if (mIsSupported) {
269             if (DBG) Log.d(TAG, "Releasing VmsHalService VHAL property");
270             mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID);
271         } else {
272             return;
273         }
274 
275         if (mSubscriberService != null) {
276             try {
277                 mSubscriberService.removeVmsSubscriberToNotifications(mSubscriberClient);
278             } catch (RemoteException e) {
279                 Log.e(TAG, "While removing subscriber callback", e);
280             }
281         }
282     }
283 
284     @Override
dump(PrintWriter writer)285     public void dump(PrintWriter writer) {
286         writer.println("*VMS HAL*");
287 
288         writer.println("VmsProperty: " + (mIsSupported ? "supported" : "unsupported"));
289         writer.println("VmsPublisherService: "
290                 + (mPublisherService != null ? "registered " : "unregistered"));
291         writer.println("mSubscriptionStateSequence: " + mSubscriptionStateSequence);
292 
293         writer.println("VmsSubscriberService: "
294                 + (mSubscriberService != null ? "registered" : "unregistered"));
295         writer.println("mAvailableLayersSequence: " + mAvailableLayersSequence);
296     }
297 
298     /**
299      * Consumes/produces HAL messages.
300      *
301      * The format of these messages is defined in:
302      * hardware/interfaces/automotive/vehicle/2.0/types.hal
303      */
304     @Override
handleHalEvents(List<VehiclePropValue> values)305     public void handleHalEvents(List<VehiclePropValue> values) {
306         if (DBG) Log.d(TAG, "Handling a VMS property change");
307         for (VehiclePropValue v : values) {
308             ArrayList<Integer> vec = v.value.int32Values;
309             int messageType = vec.get(VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE);
310 
311             if (DBG) Log.d(TAG, "Received " + VmsMessageType.toString(messageType) + " message");
312             try {
313                 switch (messageType) {
314                     case VmsMessageType.DATA:
315                         handleDataEvent(vec, toByteArray(v.value.bytes));
316                         break;
317                     case VmsMessageType.SUBSCRIBE:
318                         handleSubscribeEvent(vec);
319                         break;
320                     case VmsMessageType.UNSUBSCRIBE:
321                         handleUnsubscribeEvent(vec);
322                         break;
323                     case VmsMessageType.SUBSCRIBE_TO_PUBLISHER:
324                         handleSubscribeToPublisherEvent(vec);
325                         break;
326                     case VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER:
327                         handleUnsubscribeFromPublisherEvent(vec);
328                         break;
329                     case VmsMessageType.PUBLISHER_ID_REQUEST:
330                         handlePublisherIdRequest(toByteArray(v.value.bytes));
331                         break;
332                     case VmsMessageType.PUBLISHER_INFORMATION_REQUEST:
333                         handlePublisherInfoRequest(vec);
334                     case VmsMessageType.OFFERING:
335                         handleOfferingEvent(vec);
336                         break;
337                     case VmsMessageType.AVAILABILITY_REQUEST:
338                         handleAvailabilityRequestEvent();
339                         break;
340                     case VmsMessageType.SUBSCRIPTIONS_REQUEST:
341                         handleSubscriptionsRequestEvent();
342                         break;
343                     case VmsMessageType.START_SESSION:
344                         handleStartSessionEvent(vec);
345                         break;
346                     default:
347                         Log.e(TAG, "Unexpected message type: " + messageType);
348                 }
349             } catch (IndexOutOfBoundsException | RemoteException e) {
350                 Log.e(TAG, "While handling: " + messageType, e);
351             }
352         }
353     }
354 
355     /**
356      * SESSION_START message format:
357      * <ul>
358      * <li>Message type
359      * <li>Core ID
360      * <li>Client ID
361      * </ul>
362      */
handleStartSessionEvent(List<Integer> message)363     private void handleStartSessionEvent(List<Integer> message) {
364         int coreId = message.get(VmsStartSessionMessageIntegerValuesIndex.SERVICE_ID);
365         int clientId = message.get(VmsStartSessionMessageIntegerValuesIndex.CLIENT_ID);
366         if (DBG) {
367             Log.d(TAG,
368                     "Handling a session start event with coreId: " + coreId + " client: "
369                             + clientId);
370         }
371 
372         if (coreId != mCoreId) {
373             if (mPublisherOnHalDisconnected != null) {
374                 mPublisherOnHalDisconnected.run();
375             } else {
376                 Log.w(TAG, "Publisher disconnect callback not registered");
377             }
378             if (mSuscriberOnHalDisconnected != null) {
379                 mSuscriberOnHalDisconnected.accept(mSubscriberClient);
380             } else {
381                 Log.w(TAG, "Subscriber disconnect callback not registered");
382             }
383 
384             // Drop all queued messages and client state
385             mMessageQueue.clear();
386             mSubscriptionStateSequence = -1;
387             mAvailableLayersSequence = -1;
388 
389             // Enqueue an acknowledgement message
390             mMessageQueue.enqueue(VmsMessageType.START_SESSION,
391                     createStartSessionMessage(mCoreId, clientId));
392         }
393 
394         // Notify client manager of connection
395         if (mPublisherOnHalConnected != null) {
396             mPublisherOnHalConnected.accept(mPublisherClient);
397         } else {
398             Log.w(TAG, "Publisher connect callback not registered");
399         }
400 
401         // Notify subscriber service of connection
402         if (mSubscriberService != null) {
403             try {
404                 mSubscriberService.addVmsSubscriberToNotifications(mSubscriberClient);
405             } catch (RemoteException e) {
406                 Log.e(TAG, "While adding subscriber callback", e);
407             }
408 
409             // Publish layer availability to HAL clients (this triggers HAL client initialization)
410             try {
411                 mSubscriberClient.onLayersAvailabilityChanged(
412                         mSubscriberService.getAvailableLayers());
413             } catch (RemoteException e) {
414                 Log.e(TAG, "While publishing layer availability", e);
415             }
416         } else {
417             Log.w(TAG, "Subscriber connect callback not registered");
418         }
419     }
420 
421     /**
422      * DATA message format:
423      * <ul>
424      * <li>Message type
425      * <li>Layer ID
426      * <li>Layer subtype
427      * <li>Layer version
428      * <li>Publisher ID
429      * <li>Payload
430      * </ul>
431      */
handleDataEvent(List<Integer> message, byte[] payload)432     private void handleDataEvent(List<Integer> message, byte[] payload)
433             throws RemoteException {
434         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
435         int publisherId = parsePublisherIdFromMessage(message);
436         if (DBG) {
437             Log.d(TAG,
438                     "Handling a data event for Layer: " + vmsLayer + " Publisher: " + publisherId);
439         }
440         mPublisherService.publish(mPublisherToken, vmsLayer, publisherId, payload);
441     }
442 
443     /**
444      * SUBSCRIBE message format:
445      * <ul>
446      * <li>Message type
447      * <li>Layer ID
448      * <li>Layer subtype
449      * <li>Layer version
450      * </ul>
451      */
handleSubscribeEvent(List<Integer> message)452     private void handleSubscribeEvent(List<Integer> message) throws RemoteException {
453         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
454         if (DBG) Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer);
455         mSubscriberService.addVmsSubscriber(mSubscriberClient, vmsLayer);
456     }
457 
458     /**
459      * SUBSCRIBE_TO_PUBLISHER message format:
460      * <ul>
461      * <li>Message type
462      * <li>Layer ID
463      * <li>Layer subtype
464      * <li>Layer version
465      * <li>Publisher ID
466      * </ul>
467      */
handleSubscribeToPublisherEvent(List<Integer> message)468     private void handleSubscribeToPublisherEvent(List<Integer> message)
469             throws RemoteException {
470         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
471         int publisherId = parsePublisherIdFromMessage(message);
472         if (DBG) {
473             Log.d(TAG,
474                     "Handling a subscribe event for Layer: " + vmsLayer + " Publisher: "
475                             + publisherId);
476         }
477         mSubscriberService.addVmsSubscriberToPublisher(mSubscriberClient, vmsLayer, publisherId);
478     }
479 
480     /**
481      * UNSUBSCRIBE message format:
482      * <ul>
483      * <li>Message type
484      * <li>Layer ID
485      * <li>Layer subtype
486      * <li>Layer version
487      * </ul>
488      */
handleUnsubscribeEvent(List<Integer> message)489     private void handleUnsubscribeEvent(List<Integer> message) throws RemoteException {
490         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
491         if (DBG) Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer);
492         mSubscriberService.removeVmsSubscriber(mSubscriberClient, vmsLayer);
493     }
494 
495     /**
496      * UNSUBSCRIBE_TO_PUBLISHER message format:
497      * <ul>
498      * <li>Message type
499      * <li>Layer ID
500      * <li>Layer subtype
501      * <li>Layer version
502      * <li>Publisher ID
503      * </ul>
504      */
handleUnsubscribeFromPublisherEvent(List<Integer> message)505     private void handleUnsubscribeFromPublisherEvent(List<Integer> message)
506             throws RemoteException {
507         VmsLayer vmsLayer = parseVmsLayerFromMessage(message);
508         int publisherId = parsePublisherIdFromMessage(message);
509         if (DBG) {
510             Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer + " Publisher: "
511                     + publisherId);
512         }
513         mSubscriberService.removeVmsSubscriberToPublisher(mSubscriberClient, vmsLayer, publisherId);
514     }
515 
516     /**
517      * PUBLISHER_ID_REQUEST message format:
518      * <ul>
519      * <li>Message type
520      * <li>Publisher info (bytes)
521      * </ul>
522      *
523      * PUBLISHER_ID_RESPONSE message format:
524      * <ul>
525      * <li>Message type
526      * <li>Publisher ID
527      * </ul>
528      */
handlePublisherIdRequest(byte[] payload)529     private void handlePublisherIdRequest(byte[] payload)
530             throws RemoteException {
531         if (DBG) Log.d(TAG, "Handling a publisher id request event");
532 
533         VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.PUBLISHER_ID_RESPONSE);
534         // Publisher ID
535         vehicleProp.value.int32Values.add(mPublisherService.getPublisherId(payload));
536 
537         setPropertyValue(vehicleProp);
538     }
539 
540 
541     /**
542      * PUBLISHER_INFORMATION_REQUEST message format:
543      * <ul>
544      * <li>Message type
545      * <li>Publisher ID
546      * </ul>
547      *
548      * PUBLISHER_INFORMATION_RESPONSE message format:
549      * <ul>
550      * <li>Message type
551      * <li>Publisher info (bytes)
552      * </ul>
553      */
handlePublisherInfoRequest(List<Integer> message)554     private void handlePublisherInfoRequest(List<Integer> message)
555             throws RemoteException {
556         if (DBG) Log.d(TAG, "Handling a publisher info request event");
557         int publisherId = message.get(VmsPublisherInformationIntegerValuesIndex.PUBLISHER_ID);
558 
559         VehiclePropValue vehicleProp =
560                 createVmsMessage(VmsMessageType.PUBLISHER_INFORMATION_RESPONSE);
561         // Publisher Info
562         appendBytes(vehicleProp.value.bytes, mSubscriberService.getPublisherInfo(publisherId));
563 
564         setPropertyValue(vehicleProp);
565     }
566 
567     /**
568      * OFFERING message format:
569      * <ul>
570      * <li>Message type
571      * <li>Publisher ID
572      * <li>Number of offerings.
573      * <li>Offerings (x number of offerings)
574      * <ul>
575      * <li>Layer ID
576      * <li>Layer subtype
577      * <li>Layer version
578      * <li>Number of layer dependencies.
579      * <li>Layer dependencies (x number of layer dependencies)
580      * <ul>
581      * <li>Layer ID
582      * <li>Layer subtype
583      * <li>Layer version
584      * </ul>
585      * </ul>
586      * </ul>
587      */
handleOfferingEvent(List<Integer> message)588     private void handleOfferingEvent(List<Integer> message) throws RemoteException {
589         // Publisher ID for OFFERING is stored at a different index than in other message types
590         int publisherId = message.get(VmsOfferingMessageIntegerValuesIndex.PUBLISHER_ID);
591         int numLayerDependencies =
592                 message.get(
593                         VmsOfferingMessageIntegerValuesIndex.NUMBER_OF_OFFERS);
594         if (DBG) {
595             Log.d(TAG, "Handling an offering event of " + numLayerDependencies
596                     + " layers for Publisher: " + publisherId);
597         }
598 
599         Set<VmsLayerDependency> offeredLayers = new ArraySet<>(numLayerDependencies);
600         int idx = VmsOfferingMessageIntegerValuesIndex.OFFERING_START;
601         for (int i = 0; i < numLayerDependencies; i++) {
602             VmsLayer offeredLayer = parseVmsLayerAtIndex(message, idx);
603             idx += NUM_INTEGERS_IN_VMS_LAYER;
604 
605             int numDependenciesForLayer = message.get(idx++);
606             if (numDependenciesForLayer == 0) {
607                 offeredLayers.add(new VmsLayerDependency(offeredLayer));
608             } else {
609                 Set<VmsLayer> dependencies = new HashSet<>();
610 
611                 for (int j = 0; j < numDependenciesForLayer; j++) {
612                     VmsLayer dependantLayer = parseVmsLayerAtIndex(message, idx);
613                     idx += NUM_INTEGERS_IN_VMS_LAYER;
614                     dependencies.add(dependantLayer);
615                 }
616                 offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies));
617             }
618         }
619 
620         VmsLayersOffering offering = new VmsLayersOffering(offeredLayers, publisherId);
621         VmsOperationRecorder.get().setHalPublisherLayersOffering(offering);
622         mPublisherService.setLayersOffering(mPublisherToken, offering);
623     }
624 
625     /**
626      * AVAILABILITY_REQUEST message format:
627      * <ul>
628      * <li>Message type
629      * </ul>
630      */
handleAvailabilityRequestEvent()631     private void handleAvailabilityRequestEvent() throws RemoteException {
632         setPropertyValue(
633                 createAvailableLayersMessage(VmsMessageType.AVAILABILITY_RESPONSE,
634                         mSubscriberService.getAvailableLayers()));
635     }
636 
637     /**
638      * SUBSCRIPTION_REQUEST message format:
639      * <ul>
640      * <li>Message type
641      * </ul>
642      */
handleSubscriptionsRequestEvent()643     private void handleSubscriptionsRequestEvent() throws RemoteException {
644         setPropertyValue(
645                 createSubscriptionStateMessage(VmsMessageType.SUBSCRIPTIONS_RESPONSE,
646                         mPublisherService.getSubscriptions()));
647     }
648 
setPropertyValue(VehiclePropValue vehicleProp)649     private void setPropertyValue(VehiclePropValue vehicleProp) throws RemoteException {
650         int messageType = vehicleProp.value.int32Values.get(
651                 VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE);
652 
653         if (!mIsSupported) {
654             Log.w(TAG, "HAL unsupported while attempting to send "
655                     + VmsMessageType.toString(messageType));
656             return;
657         }
658 
659         try {
660             mVehicleHal.set(vehicleProp);
661         } catch (PropertyTimeoutException e) {
662             Log.e(CarLog.TAG_PROPERTY,
663                     "set, property not ready 0x" + toHexString(HAL_PROPERTY_ID));
664             throw new RemoteException(
665                     "Timeout while sending " + VmsMessageType.toString(messageType));
666         }
667     }
668 
669     /**
670      * Creates a SESSION_START type {@link VehiclePropValue}.
671      *
672      * SESSION_START message format:
673      * <ul>
674      * <li>Message type
675      * <li>Core ID
676      * <li>Client ID
677      * </ul>
678      */
createStartSessionMessage(int coreId, int clientId)679     private static VehiclePropValue createStartSessionMessage(int coreId, int clientId) {
680         // Message type + layer
681         VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.START_SESSION);
682         List<Integer> message = vehicleProp.value.int32Values;
683 
684         // Core ID
685         message.add(coreId);
686 
687         // Client ID
688         message.add(clientId);
689 
690         return vehicleProp;
691     }
692 
693     /**
694      * Creates a DATA type {@link VehiclePropValue}.
695      *
696      * DATA message format:
697      * <ul>
698      * <li>Message type
699      * <li>Layer ID
700      * <li>Layer subtype
701      * <li>Layer version
702      * <li>Publisher ID
703      * <li>Payload
704      * </ul>
705      *
706      * @param layer Layer for which message was published.
707      */
createDataMessage(VmsLayer layer, byte[] payload)708     private static VehiclePropValue createDataMessage(VmsLayer layer, byte[] payload) {
709         // Message type + layer
710         VehiclePropValue vehicleProp = createVmsMessage(VmsMessageType.DATA);
711         appendLayer(vehicleProp.value.int32Values, layer);
712         List<Integer> message = vehicleProp.value.int32Values;
713 
714         // Publisher ID
715         // TODO(b/124130256): Set publisher ID of data message
716         message.add(0);
717 
718         // Payload
719         appendBytes(vehicleProp.value.bytes, payload);
720         return vehicleProp;
721     }
722 
723     /**
724      * Creates a SUBSCRIPTION_CHANGE or SUBSCRIPTION_RESPONSE type {@link VehiclePropValue}.
725      *
726      * Both message types have the same format:
727      * <ul>
728      * <li>Message type
729      * <li>Sequence number
730      * <li>Number of layers
731      * <li>Number of associated layers
732      * <li>Layers (x number of layers) (see {@link #appendLayer})
733      * <li>Associated layers (x number of associated layers) (see {@link #appendAssociatedLayer})
734      * </ul>
735      *
736      * @param messageType       Either SUBSCRIPTIONS_CHANGE or SUBSCRIPTIONS_RESPONSE.
737      * @param subscriptionState The subscription state to encode in the message.
738      */
createSubscriptionStateMessage(int messageType, VmsSubscriptionState subscriptionState)739     private static VehiclePropValue createSubscriptionStateMessage(int messageType,
740             VmsSubscriptionState subscriptionState) {
741         // Message type
742         VehiclePropValue vehicleProp = createVmsMessage(messageType);
743         List<Integer> message = vehicleProp.value.int32Values;
744 
745         // Sequence number
746         message.add(subscriptionState.getSequenceNumber());
747 
748         Set<VmsLayer> layers = subscriptionState.getLayers();
749         Set<VmsAssociatedLayer> associatedLayers = subscriptionState.getAssociatedLayers();
750 
751         // Number of layers
752         message.add(layers.size());
753         // Number of associated layers
754         message.add(associatedLayers.size());
755 
756         // Layers
757         for (VmsLayer layer : layers) {
758             appendLayer(message, layer);
759         }
760 
761         // Associated layers
762         for (VmsAssociatedLayer layer : associatedLayers) {
763             appendAssociatedLayer(message, layer);
764         }
765         return vehicleProp;
766     }
767 
768     /**
769      * Creates an AVAILABILITY_CHANGE or AVAILABILITY_RESPONSE type {@link VehiclePropValue}.
770      *
771      * Both message types have the same format:
772      * <ul>
773      * <li>Message type
774      * <li>Sequence number.
775      * <li>Number of associated layers.
776      * <li>Associated layers (x number of associated layers) (see {@link #appendAssociatedLayer})
777      * </ul>
778      *
779      * @param messageType     Either AVAILABILITY_CHANGE or AVAILABILITY_RESPONSE.
780      * @param availableLayers The available layers to encode in the message.
781      */
createAvailableLayersMessage(int messageType, VmsAvailableLayers availableLayers)782     private static VehiclePropValue createAvailableLayersMessage(int messageType,
783             VmsAvailableLayers availableLayers) {
784         // Message type
785         VehiclePropValue vehicleProp = createVmsMessage(messageType);
786         List<Integer> message = vehicleProp.value.int32Values;
787 
788         // Sequence number
789         message.add(availableLayers.getSequence());
790 
791         // Number of associated layers
792         message.add(availableLayers.getAssociatedLayers().size());
793 
794         // Associated layers
795         for (VmsAssociatedLayer layer : availableLayers.getAssociatedLayers()) {
796             appendAssociatedLayer(message, layer);
797         }
798         return vehicleProp;
799     }
800 
801     /**
802      * Creates a base {@link VehiclePropValue} of the requested message type, with no message fields
803      * populated.
804      *
805      * @param messageType Type of message, from {@link VmsMessageType}
806      */
createVmsMessage(int messageType)807     private static VehiclePropValue createVmsMessage(int messageType) {
808         VehiclePropValue vehicleProp = new VehiclePropValue();
809         vehicleProp.prop = HAL_PROPERTY_ID;
810         vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL;
811         vehicleProp.value.int32Values.add(messageType);
812         return vehicleProp;
813     }
814 
815     /**
816      * Appends a {@link VmsLayer} to an encoded VMS message.
817      *
818      * Layer format:
819      * <ul>
820      * <li>Layer ID
821      * <li>Layer subtype
822      * <li>Layer version
823      * </ul>
824      *
825      * @param message Message to append to.
826      * @param layer   Layer to append.
827      */
appendLayer(List<Integer> message, VmsLayer layer)828     private static void appendLayer(List<Integer> message, VmsLayer layer) {
829         message.add(layer.getType());
830         message.add(layer.getSubtype());
831         message.add(layer.getVersion());
832     }
833 
834     /**
835      * Appends a {@link VmsAssociatedLayer} to an encoded VMS message.
836      *
837      * AssociatedLayer format:
838      * <ul>
839      * <li>Layer ID
840      * <li>Layer subtype
841      * <li>Layer version
842      * <li>Number of publishers
843      * <li>Publisher ID (x number of publishers)
844      * </ul>
845      *
846      * @param message Message to append to.
847      * @param layer   Layer to append.
848      */
appendAssociatedLayer(List<Integer> message, VmsAssociatedLayer layer)849     private static void appendAssociatedLayer(List<Integer> message, VmsAssociatedLayer layer) {
850         message.add(layer.getVmsLayer().getType());
851         message.add(layer.getVmsLayer().getSubtype());
852         message.add(layer.getVmsLayer().getVersion());
853         message.add(layer.getPublisherIds().size());
854         message.addAll(layer.getPublisherIds());
855     }
856 
appendBytes(ArrayList<Byte> dst, byte[] src)857     private static void appendBytes(ArrayList<Byte> dst, byte[] src) {
858         dst.ensureCapacity(src.length);
859         for (byte b : src) {
860             dst.add(b);
861         }
862     }
863 
parseVmsLayerFromMessage(List<Integer> message)864     private static VmsLayer parseVmsLayerFromMessage(List<Integer> message) {
865         return parseVmsLayerAtIndex(message,
866                 VmsMessageWithLayerIntegerValuesIndex.LAYER_TYPE);
867     }
868 
parseVmsLayerAtIndex(List<Integer> message, int index)869     private static VmsLayer parseVmsLayerAtIndex(List<Integer> message, int index) {
870         List<Integer> layerValues = message.subList(index, index + NUM_INTEGERS_IN_VMS_LAYER);
871         return new VmsLayer(layerValues.get(0), layerValues.get(1), layerValues.get(2));
872     }
873 
parsePublisherIdFromMessage(List<Integer> message)874     private static int parsePublisherIdFromMessage(List<Integer> message) {
875         return message.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID);
876     }
877 }
878