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