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 */ 16package com.android.car.hal; 17 18import static com.android.car.CarServiceUtils.toByteArray; 19 20import static java.lang.Integer.toHexString; 21 22import android.annotation.SystemApi; 23import android.car.VehicleAreaType; 24import android.car.vms.IVmsSubscriberClient; 25import android.car.vms.VmsAssociatedLayer; 26import android.car.vms.VmsAvailableLayers; 27import android.car.vms.VmsLayer; 28import android.car.vms.VmsLayerDependency; 29import android.car.vms.VmsLayersOffering; 30import android.car.vms.VmsOperationRecorder; 31import android.car.vms.VmsSubscriptionState; 32import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 33import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 34import android.hardware.automotive.vehicle.V2_0.VehicleProperty; 35import android.hardware.automotive.vehicle.V2_0.VmsBaseMessageIntegerValuesIndex; 36import android.hardware.automotive.vehicle.V2_0.VmsMessageType; 37import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerAndPublisherIdIntegerValuesIndex; 38import android.hardware.automotive.vehicle.V2_0.VmsMessageWithLayerIntegerValuesIndex; 39import android.hardware.automotive.vehicle.V2_0.VmsOfferingMessageIntegerValuesIndex; 40import android.os.Binder; 41import android.os.IBinder; 42import android.util.Log; 43 44import com.android.car.CarLog; 45import com.android.car.VmsLayersAvailability; 46import com.android.car.VmsPublishersInfo; 47import com.android.car.VmsRouting; 48import com.android.internal.annotations.GuardedBy; 49 50import java.io.PrintWriter; 51import java.util.ArrayList; 52import java.util.Arrays; 53import java.util.Collection; 54import java.util.Collections; 55import java.util.HashMap; 56import java.util.HashSet; 57import java.util.LinkedList; 58import java.util.List; 59import java.util.Map; 60import java.util.Set; 61import java.util.concurrent.CopyOnWriteArrayList; 62 63/** 64 * This is a glue layer between the VehicleHal and the VmsService. It sends VMS properties back and 65 * forth. 66 */ 67@SystemApi 68public class VmsHalService extends HalServiceBase { 69 70 private static final boolean DBG = true; 71 private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE; 72 private static final String TAG = "VmsHalService"; 73 74 private final static List<Integer> AVAILABILITY_MESSAGE_TYPES = Collections.unmodifiableList( 75 Arrays.asList( 76 VmsMessageType.AVAILABILITY_RESPONSE, 77 VmsMessageType.AVAILABILITY_CHANGE)); 78 79 private boolean mIsSupported = false; 80 private CopyOnWriteArrayList<VmsHalPublisherListener> mPublisherListeners = 81 new CopyOnWriteArrayList<>(); 82 private CopyOnWriteArrayList<VmsHalSubscriberListener> mSubscriberListeners = 83 new CopyOnWriteArrayList<>(); 84 85 private final IBinder mHalPublisherToken = new Binder(); 86 private final VehicleHal mVehicleHal; 87 88 private final Object mLock = new Object(); 89 private final VmsRouting mRouting = new VmsRouting(); 90 @GuardedBy("mLock") 91 private final Map<IBinder, VmsLayersOffering> mOfferings = new HashMap<>(); 92 @GuardedBy("mLock") 93 private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability(); 94 private final VmsPublishersInfo mPublishersInfo = new VmsPublishersInfo(); 95 96 /** 97 * The VmsPublisherService implements this interface to receive data from the HAL. 98 */ 99 public interface VmsHalPublisherListener { 100 void onChange(VmsSubscriptionState subscriptionState); 101 } 102 103 /** 104 * The VmsSubscriberService implements this interface to receive data from the HAL. 105 */ 106 public interface VmsHalSubscriberListener { 107 // Notifies the listener on a data Message from a publisher. 108 void onDataMessage(VmsLayer layer, int publisherId, byte[] payload); 109 110 // Notifies the listener on a change in available layers. 111 void onLayersAvaiabilityChange(VmsAvailableLayers availableLayers); 112 } 113 114 /** 115 * The VmsService implements this interface to receive data from the HAL. 116 */ 117 protected VmsHalService(VehicleHal vehicleHal) { 118 mVehicleHal = vehicleHal; 119 if (DBG) { 120 Log.d(TAG, "started VmsHalService!"); 121 } 122 } 123 124 public void addPublisherListener(VmsHalPublisherListener listener) { 125 mPublisherListeners.add(listener); 126 } 127 128 public void addSubscriberListener(VmsHalSubscriberListener listener) { 129 mSubscriberListeners.add(listener); 130 } 131 132 public void removePublisherListener(VmsHalPublisherListener listener) { 133 mPublisherListeners.remove(listener); 134 } 135 136 public void removeSubscriberListener(VmsHalSubscriberListener listener) { 137 mSubscriberListeners.remove(listener); 138 } 139 140 public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) { 141 boolean firstSubscriptionForLayer = false; 142 if (DBG) { 143 Log.d(TAG, "Checking for first subscription. Layer: " + layer); 144 } 145 synchronized (mLock) { 146 // Check if publishers need to be notified about this change in subscriptions. 147 firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer); 148 149 // Add the listeners subscription to the layer 150 mRouting.addSubscription(listener, layer); 151 } 152 if (firstSubscriptionForLayer) { 153 notifyHalPublishers(layer, true); 154 notifyClientPublishers(); 155 } 156 } 157 158 public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) { 159 boolean layerHasSubscribers = true; 160 synchronized (mLock) { 161 if (!mRouting.hasLayerSubscriptions(layer)) { 162 if (DBG) { 163 Log.d(TAG, "Trying to remove a layer with no subscription: " + layer); 164 } 165 return; 166 } 167 168 // Remove the listeners subscription to the layer 169 mRouting.removeSubscription(listener, layer); 170 171 // Check if publishers need to be notified about this change in subscriptions. 172 layerHasSubscribers = mRouting.hasLayerSubscriptions(layer); 173 } 174 if (!layerHasSubscribers) { 175 notifyHalPublishers(layer, false); 176 notifyClientPublishers(); 177 } 178 } 179 180 public void addSubscription(IVmsSubscriberClient listener) { 181 synchronized (mLock) { 182 mRouting.addSubscription(listener); 183 } 184 } 185 186 public void removeSubscription(IVmsSubscriberClient listener) { 187 synchronized (mLock) { 188 mRouting.removeSubscription(listener); 189 } 190 } 191 192 public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId) { 193 boolean firstSubscriptionForLayer = false; 194 synchronized (mLock) { 195 // Check if publishers need to be notified about this change in subscriptions. 196 firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer) || 197 mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)); 198 199 // Add the listeners subscription to the layer 200 mRouting.addSubscription(listener, layer, publisherId); 201 } 202 if (firstSubscriptionForLayer) { 203 notifyHalPublishers(layer, true); 204 notifyClientPublishers(); 205 } 206 } 207 208 public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer, int publisherId) { 209 boolean layerHasSubscribers = true; 210 synchronized (mLock) { 211 if (!mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)) { 212 Log.i(TAG, "Trying to remove a layer with no subscription: " + 213 layer + ", publisher ID:" + publisherId); 214 return; 215 } 216 217 // Remove the listeners subscription to the layer 218 mRouting.removeSubscription(listener, layer, publisherId); 219 220 // Check if publishers need to be notified about this change in subscriptions. 221 layerHasSubscribers = mRouting.hasLayerSubscriptions(layer) || 222 mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId); 223 } 224 if (!layerHasSubscribers) { 225 notifyHalPublishers(layer, false); 226 notifyClientPublishers(); 227 } 228 } 229 230 public void removeDeadSubscriber(IVmsSubscriberClient listener) { 231 synchronized (mLock) { 232 mRouting.removeDeadSubscriber(listener); 233 } 234 } 235 236 public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer, 237 int publisherId) { 238 synchronized (mLock) { 239 return mRouting.getSubscribersForLayerFromPublisher(layer, publisherId); 240 } 241 } 242 243 public Set<IVmsSubscriberClient> getAllSubscribers() { 244 synchronized (mLock) { 245 return mRouting.getAllSubscribers(); 246 } 247 } 248 249 public boolean isHalSubscribed(VmsLayer layer) { 250 synchronized (mLock) { 251 return mRouting.isHalSubscribed(layer); 252 } 253 } 254 255 public VmsSubscriptionState getSubscriptionState() { 256 synchronized (mLock) { 257 return mRouting.getSubscriptionState(); 258 } 259 } 260 261 /** 262 * Assigns an idempotent ID for publisherInfo and stores it. The idempotency in this case means 263 * that the same publisherInfo will always, within a trip of the vehicle, return the same ID. 264 * The publisherInfo should be static for a binary and should only change as part of a software 265 * update. The publisherInfo is a serialized proto message which VMS clients can interpret. 266 */ 267 public int getPublisherId(byte[] publisherInfo) { 268 if (DBG) { 269 Log.i(TAG, "Getting publisher static ID"); 270 } 271 synchronized (mLock) { 272 return mPublishersInfo.getIdForInfo(publisherInfo); 273 } 274 } 275 276 public byte[] getPublisherInfo(int publisherId) { 277 if (DBG) { 278 Log.i(TAG, "Getting information for publisher ID: " + publisherId); 279 } 280 synchronized (mLock) { 281 return mPublishersInfo.getPublisherInfo(publisherId); 282 } 283 } 284 285 private void addHalSubscription(VmsLayer layer) { 286 boolean firstSubscriptionForLayer = true; 287 synchronized (mLock) { 288 // Check if publishers need to be notified about this change in subscriptions. 289 firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer); 290 291 // Add the listeners subscription to the layer 292 mRouting.addHalSubscription(layer); 293 } 294 if (firstSubscriptionForLayer) { 295 notifyHalPublishers(layer, true); 296 notifyClientPublishers(); 297 } 298 } 299 300 private void addHalSubscriptionToPublisher(VmsLayer layer, int publisherId) { 301 boolean firstSubscriptionForLayer = true; 302 synchronized (mLock) { 303 // Check if publishers need to be notified about this change in subscriptions. 304 firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer) || 305 mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)); 306 307 // Add the listeners subscription to the layer 308 mRouting.addHalSubscriptionToPublisher(layer, publisherId); 309 } 310 if (firstSubscriptionForLayer) { 311 notifyHalPublishers(layer, publisherId, true); 312 notifyClientPublishers(); 313 } 314 } 315 316 private void removeHalSubscription(VmsLayer layer) { 317 boolean layerHasSubscribers = true; 318 synchronized (mLock) { 319 if (!mRouting.hasLayerSubscriptions(layer)) { 320 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer); 321 return; 322 } 323 324 // Remove the listeners subscription to the layer 325 mRouting.removeHalSubscription(layer); 326 327 // Check if publishers need to be notified about this change in subscriptions. 328 layerHasSubscribers = mRouting.hasLayerSubscriptions(layer); 329 } 330 if (!layerHasSubscribers) { 331 notifyHalPublishers(layer, false); 332 notifyClientPublishers(); 333 } 334 } 335 336 public void removeHalSubscriptionFromPublisher(VmsLayer layer, int publisherId) { 337 boolean layerHasSubscribers = true; 338 synchronized (mLock) { 339 if (!mRouting.hasLayerSubscriptions(layer)) { 340 Log.i(TAG, "Trying to remove a layer with no subscription: " + layer); 341 return; 342 } 343 344 // Remove the listeners subscription to the layer 345 mRouting.removeHalSubscriptionToPublisher(layer, publisherId); 346 347 // Check if publishers need to be notified about this change in subscriptions. 348 layerHasSubscribers = mRouting.hasLayerSubscriptions(layer) || 349 mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId); 350 } 351 if (!layerHasSubscribers) { 352 notifyHalPublishers(layer, publisherId, false); 353 notifyClientPublishers(); 354 } 355 } 356 357 public boolean containsSubscriber(IVmsSubscriberClient subscriber) { 358 synchronized (mLock) { 359 return mRouting.containsSubscriber(subscriber); 360 } 361 } 362 363 public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering) { 364 synchronized (mLock) { 365 updateOffering(publisherToken, offering); 366 VmsOperationRecorder.get().setPublisherLayersOffering(offering); 367 } 368 } 369 370 public VmsAvailableLayers getAvailableLayers() { 371 synchronized (mLock) { 372 return mAvailableLayers.getAvailableLayers(); 373 } 374 } 375 376 /** 377 * Notify all the publishers and the HAL on subscription changes regardless of who triggered 378 * the change. 379 * 380 * @param layer layer which is being subscribed to or unsubscribed from. 381 * @param hasSubscribers indicates if the notification is for subscription or unsubscription. 382 */ 383 private void notifyHalPublishers(VmsLayer layer, boolean hasSubscribers) { 384 // notify the HAL 385 setSubscriptionRequest(layer, hasSubscribers); 386 } 387 388 private void notifyHalPublishers(VmsLayer layer, int publisherId, boolean hasSubscribers) { 389 // notify the HAL 390 setSubscriptionToPublisherRequest(layer, publisherId, hasSubscribers); 391 } 392 393 private void notifyClientPublishers() { 394 // Notify the App publishers 395 for (VmsHalPublisherListener listener : mPublisherListeners) { 396 // Besides the list of layers, also a timestamp is provided to the clients. 397 // They should ignore any notification with a timestamp that is older than the most 398 // recent timestamp they have seen. 399 listener.onChange(getSubscriptionState()); 400 } 401 } 402 403 /** 404 * Notify all the subscribers and the HAL on layers availability change. 405 * 406 * @param availableLayers the layers which publishers claim they made publish. 407 */ 408 private void notifyOfAvailabilityChange(VmsAvailableLayers availableLayers) { 409 // notify the HAL 410 notifyAvailabilityChangeToHal(availableLayers); 411 412 // Notify the App subscribers 413 for (VmsHalSubscriberListener listener : mSubscriberListeners) { 414 listener.onLayersAvaiabilityChange(availableLayers); 415 } 416 } 417 418 @Override 419 public void init() { 420 if (DBG) { 421 Log.d(TAG, "init()"); 422 } 423 if (mIsSupported) { 424 mVehicleHal.subscribeProperty(this, HAL_PROPERTY_ID); 425 } 426 } 427 428 @Override 429 public void release() { 430 if (DBG) { 431 Log.d(TAG, "release()"); 432 } 433 if (mIsSupported) { 434 mVehicleHal.unsubscribeProperty(this, HAL_PROPERTY_ID); 435 } 436 mPublisherListeners.clear(); 437 mSubscriberListeners.clear(); 438 } 439 440 @Override 441 public Collection<VehiclePropConfig> takeSupportedProperties( 442 Collection<VehiclePropConfig> allProperties) { 443 List<VehiclePropConfig> taken = new LinkedList<>(); 444 for (VehiclePropConfig p : allProperties) { 445 if (p.prop == HAL_PROPERTY_ID) { 446 taken.add(p); 447 mIsSupported = true; 448 if (DBG) { 449 Log.d(TAG, "takeSupportedProperties: " + toHexString(p.prop)); 450 } 451 break; 452 } 453 } 454 return taken; 455 } 456 457 /** 458 * Consumes/produces HAL messages. The format of these messages is defined in: 459 * hardware/interfaces/automotive/vehicle/2.1/types.hal 460 */ 461 @Override 462 public void handleHalEvents(List<VehiclePropValue> values) { 463 if (DBG) { 464 Log.d(TAG, "Handling a VMS property change"); 465 } 466 for (VehiclePropValue v : values) { 467 ArrayList<Integer> vec = v.value.int32Values; 468 int messageType = vec.get(VmsBaseMessageIntegerValuesIndex.MESSAGE_TYPE); 469 470 if (DBG) { 471 Log.d(TAG, "Handling VMS message type: " + messageType); 472 } 473 switch (messageType) { 474 case VmsMessageType.DATA: 475 handleDataEvent(vec, toByteArray(v.value.bytes)); 476 break; 477 case VmsMessageType.SUBSCRIBE: 478 handleSubscribeEvent(vec); 479 break; 480 case VmsMessageType.UNSUBSCRIBE: 481 handleUnsubscribeEvent(vec); 482 break; 483 case VmsMessageType.SUBSCRIBE_TO_PUBLISHER: 484 handleSubscribeToPublisherEvent(vec); 485 break; 486 case VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER: 487 handleUnsubscribeFromPublisherEvent(vec); 488 break; 489 case VmsMessageType.OFFERING: 490 handleOfferingEvent(vec); 491 break; 492 case VmsMessageType.AVAILABILITY_REQUEST: 493 handleHalAvailabilityRequestEvent(); 494 break; 495 case VmsMessageType.SUBSCRIPTIONS_REQUEST: 496 handleSubscriptionsRequestEvent(); 497 break; 498 default: 499 throw new IllegalArgumentException("Unexpected message type: " + messageType); 500 } 501 } 502 } 503 504 private VmsLayer parseVmsLayerFromSimpleMessageIntegerValues(List<Integer> integerValues) { 505 return new VmsLayer(integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_TYPE), 506 integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_SUBTYPE), 507 integerValues.get(VmsMessageWithLayerIntegerValuesIndex.LAYER_VERSION)); 508 } 509 510 private VmsLayer parseVmsLayerFromDataMessageIntegerValues(List<Integer> integerValues) { 511 return parseVmsLayerFromSimpleMessageIntegerValues(integerValues); 512 } 513 514 private int parsePublisherIdFromDataMessageIntegerValues(List<Integer> integerValues) { 515 return integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID); 516 } 517 518 519 /** 520 * Data message format: 521 * <ul> 522 * <li>Message type. 523 * <li>Layer id. 524 * <li>Layer version. 525 * <li>Layer subtype. 526 * <li>Publisher ID. 527 * <li>Payload. 528 * </ul> 529 */ 530 private void handleDataEvent(List<Integer> integerValues, byte[] payload) { 531 VmsLayer vmsLayer = parseVmsLayerFromDataMessageIntegerValues(integerValues); 532 int publisherId = parsePublisherIdFromDataMessageIntegerValues(integerValues); 533 if (DBG) { 534 Log.d(TAG, "Handling a data event for Layer: " + vmsLayer); 535 } 536 537 // Send the message. 538 for (VmsHalSubscriberListener listener : mSubscriberListeners) { 539 listener.onDataMessage(vmsLayer, publisherId, payload); 540 } 541 } 542 543 /** 544 * Subscribe message format: 545 * <ul> 546 * <li>Message type. 547 * <li>Layer id. 548 * <li>Layer version. 549 * <li>Layer subtype. 550 * </ul> 551 */ 552 private void handleSubscribeEvent(List<Integer> integerValues) { 553 VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues); 554 if (DBG) { 555 Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer); 556 } 557 addHalSubscription(vmsLayer); 558 } 559 560 /** 561 * Subscribe message format: 562 * <ul> 563 * <li>Message type. 564 * <li>Layer id. 565 * <li>Layer version. 566 * <li>Layer subtype. 567 * <li>Publisher ID 568 * </ul> 569 */ 570 private void handleSubscribeToPublisherEvent(List<Integer> integerValues) { 571 VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues); 572 if (DBG) { 573 Log.d(TAG, "Handling a subscribe event for Layer: " + vmsLayer); 574 } 575 int publisherId = 576 integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID); 577 addHalSubscriptionToPublisher(vmsLayer, publisherId); 578 } 579 580 /** 581 * Unsubscribe message format: 582 * <ul> 583 * <li>Message type. 584 * <li>Layer id. 585 * <li>Layer version. 586 * </ul> 587 */ 588 private void handleUnsubscribeEvent(List<Integer> integerValues) { 589 VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues); 590 if (DBG) { 591 Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer); 592 } 593 removeHalSubscription(vmsLayer); 594 } 595 596 /** 597 * Unsubscribe message format: 598 * <ul> 599 * <li>Message type. 600 * <li>Layer id. 601 * <li>Layer version. 602 * </ul> 603 */ 604 private void handleUnsubscribeFromPublisherEvent(List<Integer> integerValues) { 605 VmsLayer vmsLayer = parseVmsLayerFromSimpleMessageIntegerValues(integerValues); 606 int publisherId = 607 integerValues.get(VmsMessageWithLayerAndPublisherIdIntegerValuesIndex.PUBLISHER_ID); 608 if (DBG) { 609 Log.d(TAG, "Handling an unsubscribe event for Layer: " + vmsLayer); 610 } 611 removeHalSubscriptionFromPublisher(vmsLayer, publisherId); 612 } 613 614 private static int NUM_INTEGERS_IN_VMS_LAYER = 3; 615 616 private VmsLayer parseVmsLayerFromIndex(List<Integer> integerValues, int index) { 617 int layerType = integerValues.get(index++); 618 int layerSutype = integerValues.get(index++); 619 int layerVersion = integerValues.get(index++); 620 return new VmsLayer(layerType, layerSutype, layerVersion); 621 } 622 623 /** 624 * Offering message format: 625 * <ul> 626 * <li>Message type. 627 * <li>Publisher ID. 628 * <li>Number of offerings. 629 * <li>Each offering consists of: 630 * <ul> 631 * <li>Layer id. 632 * <li>Layer version. 633 * <li>Number of layer dependencies. 634 * <li>Layer type/subtype/version. 635 * </ul> 636 * </ul> 637 */ 638 private void handleOfferingEvent(List<Integer> integerValues) { 639 int publisherId = integerValues.get(VmsOfferingMessageIntegerValuesIndex.PUBLISHER_ID); 640 int numLayersDependencies = 641 integerValues.get( 642 VmsOfferingMessageIntegerValuesIndex.NUMBER_OF_OFFERS); 643 int idx = VmsOfferingMessageIntegerValuesIndex.OFFERING_START; 644 645 Set<VmsLayerDependency> offeredLayers = new HashSet<>(); 646 647 // An offering is layerId, LayerVersion, LayerType, NumDeps, <LayerId, LayerVersion> X NumDeps. 648 for (int i = 0; i < numLayersDependencies; i++) { 649 VmsLayer offeredLayer = parseVmsLayerFromIndex(integerValues, idx); 650 idx += NUM_INTEGERS_IN_VMS_LAYER; 651 652 int numDependenciesForLayer = integerValues.get(idx++); 653 if (numDependenciesForLayer == 0) { 654 offeredLayers.add(new VmsLayerDependency(offeredLayer)); 655 } else { 656 Set<VmsLayer> dependencies = new HashSet<>(); 657 658 for (int j = 0; j < numDependenciesForLayer; j++) { 659 VmsLayer dependantLayer = parseVmsLayerFromIndex(integerValues, idx); 660 idx += NUM_INTEGERS_IN_VMS_LAYER; 661 dependencies.add(dependantLayer); 662 } 663 offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies)); 664 } 665 } 666 // Store the HAL offering. 667 VmsLayersOffering offering = new VmsLayersOffering(offeredLayers, publisherId); 668 synchronized (mLock) { 669 updateOffering(mHalPublisherToken, offering); 670 VmsOperationRecorder.get().setHalPublisherLayersOffering(offering); 671 } 672 } 673 674 /** 675 * Availability message format: 676 * <ul> 677 * <li>Message type. 678 * <li>Number of layers. 679 * <li>Layer type/subtype/version. 680 * </ul> 681 */ 682 private void handleHalAvailabilityRequestEvent() { 683 synchronized (mLock) { 684 VmsAvailableLayers availableLayers = mAvailableLayers.getAvailableLayers(); 685 VehiclePropValue vehiclePropertyValue = 686 toAvailabilityUpdateVehiclePropValue( 687 availableLayers, 688 VmsMessageType.AVAILABILITY_RESPONSE); 689 690 setPropertyValue(vehiclePropertyValue); 691 } 692 } 693 694 /** 695 * VmsSubscriptionRequestFormat: 696 * <ul> 697 * <li>Message type. 698 * </ul> 699 * <p> 700 * VmsSubscriptionResponseFormat: 701 * <ul> 702 * <li>Message type. 703 * <li>Sequence number. 704 * <li>Number of layers. 705 * <li>Layer type/subtype/version. 706 * </ul> 707 */ 708 private void handleSubscriptionsRequestEvent() { 709 VmsSubscriptionState subscription = getSubscriptionState(); 710 VehiclePropValue vehicleProp = 711 toTypedVmsVehiclePropValue(VmsMessageType.SUBSCRIPTIONS_RESPONSE); 712 VehiclePropValue.RawValue v = vehicleProp.value; 713 v.int32Values.add(subscription.getSequenceNumber()); 714 Set<VmsLayer> layers = subscription.getLayers(); 715 v.int32Values.add(layers.size()); 716 717 //TODO(asafro): get the real number of associated layers in the subscriptions 718 // state and send the associated layers themselves. 719 v.int32Values.add(0); 720 721 for (VmsLayer layer : layers) { 722 v.int32Values.add(layer.getType()); 723 v.int32Values.add(layer.getSubtype()); 724 v.int32Values.add(layer.getVersion()); 725 } 726 setPropertyValue(vehicleProp); 727 } 728 729 private void updateOffering(IBinder publisherToken, VmsLayersOffering offering) { 730 VmsAvailableLayers availableLayers; 731 synchronized (mLock) { 732 mOfferings.put(publisherToken, offering); 733 734 // Update layers availability. 735 mAvailableLayers.setPublishersOffering(mOfferings.values()); 736 737 availableLayers = mAvailableLayers.getAvailableLayers(); 738 } 739 notifyOfAvailabilityChange(availableLayers); 740 } 741 742 @Override 743 public void dump(PrintWriter writer) { 744 writer.println(TAG); 745 writer.println("VmsProperty " + (mIsSupported ? "" : "not") + " supported."); 746 } 747 748 /** 749 * Updates the VMS HAL property with the given value. 750 * 751 * @param layer layer data to update the hal property. 752 * @param hasSubscribers if it is a subscribe or unsubscribe message. 753 * @return true if the call to the HAL to update the property was successful. 754 */ 755 public boolean setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers) { 756 VehiclePropValue vehiclePropertyValue = toTypedVmsVehiclePropValueWithLayer( 757 hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer); 758 return setPropertyValue(vehiclePropertyValue); 759 } 760 761 public boolean setSubscriptionToPublisherRequest(VmsLayer layer, 762 int publisherId, 763 boolean hasSubscribers) { 764 VehiclePropValue vehiclePropertyValue = toTypedVmsVehiclePropValueWithLayer( 765 hasSubscribers ? 766 VmsMessageType.SUBSCRIBE_TO_PUBLISHER : 767 VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER, layer); 768 vehiclePropertyValue.value.int32Values.add(publisherId); 769 return setPropertyValue(vehiclePropertyValue); 770 } 771 772 public boolean setDataMessage(VmsLayer layer, byte[] payload) { 773 VehiclePropValue vehiclePropertyValue = 774 toTypedVmsVehiclePropValueWithLayer(VmsMessageType.DATA, layer); 775 VehiclePropValue.RawValue v = vehiclePropertyValue.value; 776 v.bytes.ensureCapacity(payload.length); 777 for (byte b : payload) { 778 v.bytes.add(b); 779 } 780 return setPropertyValue(vehiclePropertyValue); 781 } 782 783 public boolean notifyAvailabilityChangeToHal(VmsAvailableLayers availableLayers) { 784 VehiclePropValue vehiclePropertyValue = 785 toAvailabilityUpdateVehiclePropValue( 786 availableLayers, 787 VmsMessageType.AVAILABILITY_CHANGE); 788 789 return setPropertyValue(vehiclePropertyValue); 790 } 791 792 public boolean setPropertyValue(VehiclePropValue vehiclePropertyValue) { 793 try { 794 mVehicleHal.set(vehiclePropertyValue); 795 return true; 796 } catch (PropertyTimeoutException e) { 797 Log.e(CarLog.TAG_PROPERTY, "set, property not ready 0x" + toHexString(HAL_PROPERTY_ID)); 798 } 799 return false; 800 } 801 802 private static VehiclePropValue toTypedVmsVehiclePropValue(int messageType) { 803 VehiclePropValue vehicleProp = new VehiclePropValue(); 804 vehicleProp.prop = HAL_PROPERTY_ID; 805 vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL; 806 VehiclePropValue.RawValue v = vehicleProp.value; 807 808 v.int32Values.add(messageType); 809 return vehicleProp; 810 } 811 812 /** 813 * Creates a {@link VehiclePropValue} 814 */ 815 private static VehiclePropValue toTypedVmsVehiclePropValueWithLayer( 816 int messageType, VmsLayer layer) { 817 VehiclePropValue vehicleProp = toTypedVmsVehiclePropValue(messageType); 818 VehiclePropValue.RawValue v = vehicleProp.value; 819 v.int32Values.add(layer.getType()); 820 v.int32Values.add(layer.getSubtype()); 821 v.int32Values.add(layer.getVersion()); 822 return vehicleProp; 823 } 824 825 private static VehiclePropValue toAvailabilityUpdateVehiclePropValue( 826 VmsAvailableLayers availableLayers, int messageType) { 827 828 if (!AVAILABILITY_MESSAGE_TYPES.contains(messageType)) { 829 throw new IllegalArgumentException("Unsupported availability type: " + messageType); 830 } 831 VehiclePropValue vehicleProp = 832 toTypedVmsVehiclePropValue(messageType); 833 populateAvailabilityPropValueFields(availableLayers, vehicleProp); 834 return vehicleProp; 835 836 } 837 838 private static void populateAvailabilityPropValueFields( 839 VmsAvailableLayers availableAssociatedLayers, 840 VehiclePropValue vehicleProp) { 841 VehiclePropValue.RawValue v = vehicleProp.value; 842 v.int32Values.add(availableAssociatedLayers.getSequence()); 843 int numLayers = availableAssociatedLayers.getAssociatedLayers().size(); 844 v.int32Values.add(numLayers); 845 for (VmsAssociatedLayer layer : availableAssociatedLayers.getAssociatedLayers()) { 846 v.int32Values.add(layer.getVmsLayer().getType()); 847 v.int32Values.add(layer.getVmsLayer().getSubtype()); 848 v.int32Values.add(layer.getVmsLayer().getVersion()); 849 v.int32Values.add(layer.getPublisherIds().size()); 850 for (int publisherId : layer.getPublisherIds()) { 851 v.int32Values.add(publisherId); 852 } 853 } 854 } 855} 856