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