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 17 package com.android.car; 18 19 import android.car.vms.IVmsSubscriberClient; 20 import android.car.vms.VmsAssociatedLayer; 21 import android.car.vms.VmsLayer; 22 import android.car.vms.VmsOperationRecorder; 23 import android.car.vms.VmsSubscriptionState; 24 25 import com.android.internal.annotations.GuardedBy; 26 27 import java.util.ArrayList; 28 import java.util.HashMap; 29 import java.util.HashSet; 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Set; 33 import java.util.stream.Collectors; 34 35 /** 36 * Manages all the VMS subscriptions: 37 * + Subscriptions to data messages of individual layer + version. 38 * + Subscriptions to all data messages. 39 * + HAL subscriptions to layer + version. 40 */ 41 42 public class VmsRouting { 43 private final Object mLock = new Object(); 44 // A map of Layer + Version to subscribers. 45 @GuardedBy("mLock") 46 private Map<VmsLayer, Set<IVmsSubscriberClient>> mLayerSubscriptions = new HashMap<>(); 47 48 @GuardedBy("mLock") 49 private Map<VmsLayer, Map<Integer, Set<IVmsSubscriberClient>>> mLayerSubscriptionsToPublishers = 50 new HashMap<>(); 51 // A set of subscribers that are interested in any layer + version. 52 @GuardedBy("mLock") 53 private Set<IVmsSubscriberClient> mPromiscuousSubscribers = new HashSet<>(); 54 55 // A set of all the layers + versions the HAL is subscribed to. 56 @GuardedBy("mLock") 57 private Set<VmsLayer> mHalSubscriptions = new HashSet<>(); 58 59 @GuardedBy("mLock") 60 private Map<VmsLayer, Set<Integer>> mHalSubscriptionsToPublishers = new HashMap<>(); 61 // A sequence number that is increased every time the subscription state is modified. Note that 62 // modifying the list of promiscuous subscribers does not affect the subscription state. 63 @GuardedBy("mLock") 64 private int mSequenceNumber = 0; 65 66 /** 67 * Add a subscriber subscription to data messages from a VMS layer. 68 * 69 * @param subscriber a VMS subscriber. 70 * @param layer the layer subscribing to. 71 */ addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)72 public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) { 73 //TODO(b/36902947): revise if need to sync, and return value. 74 synchronized (mLock) { 75 ++mSequenceNumber; 76 // Get or create the list of subscribers for layer and version. 77 Set<IVmsSubscriberClient> subscribers = mLayerSubscriptions.get(layer); 78 79 if (subscribers == null) { 80 subscribers = new HashSet<>(); 81 mLayerSubscriptions.put(layer, subscribers); 82 } 83 // Add the subscriber to the list. 84 subscribers.add(subscriber); 85 VmsOperationRecorder.get().addSubscription(mSequenceNumber, layer); 86 } 87 } 88 89 /** 90 * Add a subscriber subscription to all data messages. 91 * 92 * @param subscriber a VMS subscriber. 93 */ addSubscription(IVmsSubscriberClient subscriber)94 public void addSubscription(IVmsSubscriberClient subscriber) { 95 synchronized (mLock) { 96 ++mSequenceNumber; 97 mPromiscuousSubscribers.add(subscriber); 98 VmsOperationRecorder.get().addPromiscuousSubscription(mSequenceNumber); 99 } 100 } 101 102 /** 103 * Add a subscriber subscription to data messages from a VMS layer from a specific publisher. 104 * 105 * @param subscriber a VMS subscriber. 106 * @param layer the layer to subscribing to. 107 * @param publisherId the publisher ID. 108 */ addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)109 public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId) { 110 synchronized (mLock) { 111 ++mSequenceNumber; 112 113 Map<Integer, Set<IVmsSubscriberClient>> publisherIdsToSubscribersForLayer = 114 mLayerSubscriptionsToPublishers.get(layer); 115 116 if (publisherIdsToSubscribersForLayer == null) { 117 publisherIdsToSubscribersForLayer = new HashMap<>(); 118 mLayerSubscriptionsToPublishers.put(layer, publisherIdsToSubscribersForLayer); 119 } 120 121 Set<IVmsSubscriberClient> subscribersForPublisher = 122 publisherIdsToSubscribersForLayer.get(publisherId); 123 124 if (subscribersForPublisher == null) { 125 subscribersForPublisher = new HashSet<>(); 126 publisherIdsToSubscribersForLayer.put(publisherId, subscribersForPublisher); 127 } 128 129 // Add the subscriber to the list. 130 subscribersForPublisher.add(subscriber); 131 } 132 } 133 134 /** 135 * Remove a subscription for a layer + version and make sure to remove the key if there are no 136 * more subscribers. 137 * 138 * @param subscriber to remove. 139 * @param layer of the subscription. 140 */ removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)141 public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) { 142 synchronized (mLock) { 143 ++mSequenceNumber; 144 Set<IVmsSubscriberClient> subscribers = mLayerSubscriptions.get(layer); 145 146 // If there are no subscribers we are done. 147 if (subscribers == null) { 148 return; 149 } 150 subscribers.remove(subscriber); 151 VmsOperationRecorder.get().removeSubscription(mSequenceNumber, layer); 152 153 // If there are no more subscribers then remove the list. 154 if (subscribers.isEmpty()) { 155 mLayerSubscriptions.remove(layer); 156 } 157 } 158 } 159 160 /** 161 * Remove a subscriber subscription to all data messages. 162 * 163 * @param subscriber a VMS subscriber. 164 */ removeSubscription(IVmsSubscriberClient subscriber)165 public void removeSubscription(IVmsSubscriberClient subscriber) { 166 synchronized (mLock) { 167 ++mSequenceNumber; 168 mPromiscuousSubscribers.remove(subscriber); 169 VmsOperationRecorder.get().removePromiscuousSubscription(mSequenceNumber); 170 } 171 } 172 173 /** 174 * Remove a subscription to data messages from a VMS layer from a specific publisher. 175 * 176 * @param subscriber a VMS subscriber. 177 * @param layer the layer to unsubscribing from. 178 * @param publisherId the publisher ID. 179 */ removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)180 public void removeSubscription(IVmsSubscriberClient subscriber, 181 VmsLayer layer, 182 int publisherId) { 183 synchronized (mLock) { 184 ++mSequenceNumber; 185 186 Map<Integer, Set<IVmsSubscriberClient>> subscribersToPublishers = 187 mLayerSubscriptionsToPublishers.get(layer); 188 189 if (subscribersToPublishers == null) { 190 return; 191 } 192 193 Set<IVmsSubscriberClient> subscribers = subscribersToPublishers.get(publisherId); 194 195 if (subscribers == null) { 196 return; 197 } 198 subscribers.remove(subscriber); 199 200 if (subscribers.isEmpty()) { 201 subscribersToPublishers.remove(publisherId); 202 } 203 204 if (subscribersToPublishers.isEmpty()) { 205 mLayerSubscriptionsToPublishers.remove(layer); 206 } 207 } 208 } 209 210 /** 211 * Remove a subscriber from all routes (optional operation). 212 * 213 * @param subscriber a VMS subscriber. 214 */ removeDeadSubscriber(IVmsSubscriberClient subscriber)215 public void removeDeadSubscriber(IVmsSubscriberClient subscriber) { 216 synchronized (mLock) { 217 // Remove the subscriber from all the routes. 218 for (VmsLayer layer : mLayerSubscriptions.keySet()) { 219 removeSubscription(subscriber, layer); 220 } 221 // Remove the subscriber from the loggers. 222 removeSubscription(subscriber); 223 } 224 } 225 226 /** 227 * Returns a list of all the subscribers for a layer from a publisher. This includes 228 * subscribers that subscribed to this layer from all publishers, subscribed to this layer 229 * from a specific publisher, and the promiscuous subscribers. 230 * 231 * @param layer The layer of the message. 232 * @param publisherId the ID of the client that published the message to be routed. 233 * @return a list of the subscribers. 234 */ getSubscribersForLayerFromPublisher(VmsLayer layer, int publisherId)235 public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer, 236 int publisherId) { 237 Set<IVmsSubscriberClient> subscribers = new HashSet<>(); 238 synchronized (mLock) { 239 // Add the subscribers which explicitly subscribed to this layer 240 if (mLayerSubscriptions.containsKey(layer)) { 241 subscribers.addAll(mLayerSubscriptions.get(layer)); 242 } 243 244 // Add the subscribers which explicitly subscribed to this layer and publisher 245 if (mLayerSubscriptionsToPublishers.containsKey(layer)) { 246 if (mLayerSubscriptionsToPublishers.get(layer).containsKey(publisherId)) { 247 subscribers.addAll(mLayerSubscriptionsToPublishers.get(layer).get(publisherId)); 248 } 249 } 250 251 // Add the promiscuous subscribers. 252 subscribers.addAll(mPromiscuousSubscribers); 253 } 254 return subscribers; 255 } 256 257 /** 258 * Returns a list with all the subscribers. 259 */ getAllSubscribers()260 public Set<IVmsSubscriberClient> getAllSubscribers() { 261 Set<IVmsSubscriberClient> subscribers = new HashSet<>(); 262 synchronized (mLock) { 263 for (VmsLayer layer : mLayerSubscriptions.keySet()) { 264 subscribers.addAll(mLayerSubscriptions.get(layer)); 265 } 266 // Add the promiscuous subscribers. 267 subscribers.addAll(mPromiscuousSubscribers); 268 } 269 return subscribers; 270 } 271 272 /** 273 * Checks if a subscriber is subscribed to any messages. 274 * 275 * @param subscriber that may have subscription. 276 * @return true if the subscriber uis subscribed to messages. 277 */ containsSubscriber(IVmsSubscriberClient subscriber)278 public boolean containsSubscriber(IVmsSubscriberClient subscriber) { 279 synchronized (mLock) { 280 // Check if subscriber is subscribed to a layer. 281 for (Set<IVmsSubscriberClient> layerSubscribers : mLayerSubscriptions.values()) { 282 if (layerSubscribers.contains(subscriber)) { 283 return true; 284 } 285 } 286 // Check is subscriber is subscribed to all data messages. 287 return mPromiscuousSubscribers.contains(subscriber); 288 } 289 } 290 291 /** 292 * Add a layer and version to the HAL subscriptions. 293 * 294 * @param layer the HAL subscribes to. 295 */ addHalSubscription(VmsLayer layer)296 public void addHalSubscription(VmsLayer layer) { 297 synchronized (mLock) { 298 ++mSequenceNumber; 299 mHalSubscriptions.add(layer); 300 VmsOperationRecorder.get().addHalSubscription(mSequenceNumber, layer); 301 } 302 } 303 addHalSubscriptionToPublisher(VmsLayer layer, int publisherId)304 public void addHalSubscriptionToPublisher(VmsLayer layer, int publisherId) { 305 synchronized (mLock) { 306 ++mSequenceNumber; 307 308 Set<Integer> publisherIdsForLayer = mHalSubscriptionsToPublishers.get(layer); 309 if (publisherIdsForLayer == null) { 310 publisherIdsForLayer = new HashSet<>(); 311 mHalSubscriptionsToPublishers.put(layer, publisherIdsForLayer); 312 } 313 publisherIdsForLayer.add(publisherId); 314 } 315 } 316 317 /** 318 * remove a layer and version to the HAL subscriptions. 319 * 320 * @param layer the HAL unsubscribes from. 321 */ removeHalSubscription(VmsLayer layer)322 public void removeHalSubscription(VmsLayer layer) { 323 synchronized (mLock) { 324 ++mSequenceNumber; 325 mHalSubscriptions.remove(layer); 326 VmsOperationRecorder.get().removeHalSubscription(mSequenceNumber, layer); 327 } 328 } 329 removeHalSubscriptionToPublisher(VmsLayer layer, int publisherId)330 public void removeHalSubscriptionToPublisher(VmsLayer layer, int publisherId) { 331 synchronized (mLock) { 332 ++mSequenceNumber; 333 334 Set<Integer> publisherIdsForLayer = mHalSubscriptionsToPublishers.get(layer); 335 if (publisherIdsForLayer == null) { 336 return; 337 } 338 publisherIdsForLayer.remove(publisherId); 339 340 if (publisherIdsForLayer.isEmpty()) { 341 mHalSubscriptionsToPublishers.remove(layer); 342 } 343 } 344 } 345 346 /** 347 * checks if the HAL is subscribed to a layer. 348 * 349 * @param layer 350 * @return true if the HAL is subscribed to layer. 351 */ isHalSubscribed(VmsLayer layer)352 public boolean isHalSubscribed(VmsLayer layer) { 353 synchronized (mLock) { 354 return mHalSubscriptions.contains(layer); 355 } 356 } 357 358 /** 359 * checks if there are subscribers to a layer. 360 * 361 * @param layer 362 * @return true if there are subscribers to layer. 363 */ hasLayerSubscriptions(VmsLayer layer)364 public boolean hasLayerSubscriptions(VmsLayer layer) { 365 synchronized (mLock) { 366 return mLayerSubscriptions.containsKey(layer) || mHalSubscriptions.contains(layer); 367 } 368 } 369 370 /** 371 * returns true if there is already a subscription for the layer from publisherId. 372 * 373 * @param layer 374 * @param publisherId 375 * @return 376 */ hasLayerFromPublisherSubscriptions(VmsLayer layer, int publisherId)377 public boolean hasLayerFromPublisherSubscriptions(VmsLayer layer, int publisherId) { 378 synchronized (mLock) { 379 boolean hasClientSubscription = 380 mLayerSubscriptionsToPublishers.containsKey(layer) && 381 mLayerSubscriptionsToPublishers.get(layer).containsKey(publisherId); 382 383 boolean hasHalSubscription = mHalSubscriptionsToPublishers.containsKey(layer) && 384 mHalSubscriptionsToPublishers.get(layer).contains(publisherId); 385 386 return hasClientSubscription || hasHalSubscription; 387 } 388 } 389 390 /** 391 * @return a Set of layers and versions which VMS clients are subscribed to. 392 */ getSubscriptionState()393 public VmsSubscriptionState getSubscriptionState() { 394 synchronized (mLock) { 395 Set<VmsLayer> layers = new HashSet<>(); 396 layers.addAll(mLayerSubscriptions.keySet()); 397 layers.addAll(mHalSubscriptions); 398 399 400 Set<VmsAssociatedLayer> layersFromPublishers = new HashSet<>(); 401 layersFromPublishers.addAll(mLayerSubscriptionsToPublishers.entrySet() 402 .stream() 403 .map(e -> new VmsAssociatedLayer(e.getKey(), e.getValue().keySet())) 404 .collect(Collectors.toSet())); 405 layersFromPublishers.addAll(mHalSubscriptionsToPublishers.entrySet() 406 .stream() 407 .map(e -> new VmsAssociatedLayer(e.getKey(), e.getValue())) 408 .collect(Collectors.toSet())); 409 410 return new VmsSubscriptionState(mSequenceNumber, layers, layersFromPublishers); 411 } 412 } 413 }