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