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