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