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 import android.os.IBinder; 25 import android.util.ArrayMap; 26 import android.util.ArraySet; 27 import android.util.Pair; 28 29 import com.android.internal.annotations.GuardedBy; 30 31 import java.util.Collections; 32 import java.util.HashSet; 33 import java.util.Map; 34 import java.util.Objects; 35 import java.util.Set; 36 import java.util.stream.Collectors; 37 38 /** 39 * Manages all the VMS subscriptions: 40 * + Subscriptions to data messages of individual layer + version. 41 * + Subscriptions to all data messages. 42 * + HAL subscriptions to layer + version. 43 */ 44 45 public class VmsRouting { 46 private final Object mLock = new Object(); 47 48 @GuardedBy("mLock") 49 private Map<IBinder, IVmsSubscriberClient> mSubscribers = new ArrayMap<>(); 50 51 @GuardedBy("mLock") 52 private Set<IBinder> mPassiveSubscribers = new ArraySet<>(); 53 54 @GuardedBy("mLock") 55 private Map<VmsLayer, Set<IBinder>> mLayerSubscriptions = new ArrayMap<>(); 56 57 @GuardedBy("mLock") 58 private Map<VmsLayer, Map<Integer, Set<IBinder>>> mLayerSubscriptionsToPublishers = 59 new ArrayMap<>(); 60 61 @GuardedBy("mLock") 62 private int mSequenceNumber = 0; 63 64 /** 65 * Add a passive subscription to all data messages. 66 * 67 * Passive subscribers receive all published data messages, but are not reflected in the 68 * subscription state sent to publishers. 69 * 70 * @param subscriber VMS subscriber to add 71 */ addSubscription(IVmsSubscriberClient subscriber)72 public void addSubscription(IVmsSubscriberClient subscriber) { 73 int sequenceNumber; 74 synchronized (mLock) { 75 if (!mPassiveSubscribers.add(addSubscriber(subscriber))) { 76 return; 77 } 78 sequenceNumber = mSequenceNumber; 79 } 80 VmsOperationRecorder.get().addPromiscuousSubscription(sequenceNumber); 81 } 82 83 /** 84 * Remove a passive subscription to all data messages. 85 * 86 * @param subscriber VMS subscriber to remove 87 */ removeSubscription(IVmsSubscriberClient subscriber)88 public void removeSubscription(IVmsSubscriberClient subscriber) { 89 int sequenceNumber; 90 synchronized (mLock) { 91 if (!mPassiveSubscribers.remove(subscriber.asBinder())) { 92 return; 93 } 94 sequenceNumber = mSequenceNumber; 95 } 96 VmsOperationRecorder.get().removePromiscuousSubscription(sequenceNumber); 97 } 98 99 /** 100 * Add a subscription to data messages from a VMS layer. 101 * 102 * @param subscriber VMS subscriber to add 103 * @param layer the layer to subscribe to 104 */ addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)105 public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) { 106 int sequenceNumber; 107 synchronized (mLock) { 108 Set<IBinder> subscribers = 109 mLayerSubscriptions.computeIfAbsent(layer, k -> new ArraySet<>()); 110 if (!subscribers.add(addSubscriber(subscriber))) { 111 return; 112 } 113 sequenceNumber = ++mSequenceNumber; 114 } 115 VmsOperationRecorder.get().addSubscription(sequenceNumber, layer); 116 } 117 118 /** 119 * Remove a subscription to data messages from a VMS layer. 120 * 121 * @param subscriber VMS subscriber to remove 122 * @param layer the subscribed layer 123 */ removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)124 public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) { 125 int sequenceNumber; 126 synchronized (mLock) { 127 Set<IBinder> subscribers = 128 mLayerSubscriptions.getOrDefault(layer, Collections.emptySet()); 129 if (!subscribers.remove(subscriber.asBinder())) { 130 return; 131 } 132 sequenceNumber = ++mSequenceNumber; 133 134 if (subscribers.isEmpty()) { 135 // If a layer has no subscribers, remove it 136 mLayerSubscriptions.remove(layer); 137 } 138 } 139 VmsOperationRecorder.get().removeSubscription(sequenceNumber, layer); 140 } 141 142 /** 143 * Add a subscription to data messages from a VMS layer and a specific publisher. 144 * 145 * @param subscriber VMS subscriber to add 146 * @param layer the layer to subscribe to 147 * @param publisherId the publisher ID 148 */ addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)149 public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId) { 150 int sequenceNumber; 151 synchronized (mLock) { 152 Set<IBinder> subscribers = 153 mLayerSubscriptionsToPublishers.computeIfAbsent(layer, k -> new ArrayMap<>()) 154 .computeIfAbsent(publisherId, k -> new ArraySet<>()); 155 if (!subscribers.add(addSubscriber(subscriber))) { 156 return; 157 } 158 sequenceNumber = ++mSequenceNumber; 159 } 160 VmsOperationRecorder.get().addSubscription(sequenceNumber, layer); 161 } 162 163 /** 164 * Remove a subscription to data messages from a VMS layer and a specific publisher. 165 * 166 * @param subscriber VMS subscriber to remove 167 * @param layer the subscribed layer 168 * @param publisherId the publisher ID 169 */ removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)170 public void removeSubscription(IVmsSubscriberClient subscriber, 171 VmsLayer layer, 172 int publisherId) { 173 int sequenceNumber; 174 synchronized (mLock) { 175 Map<Integer, Set<IBinder>> subscribersToPublishers = 176 mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap()); 177 178 Set<IBinder> subscribers = 179 subscribersToPublishers.getOrDefault(publisherId, Collections.emptySet()); 180 if (!subscribers.remove(subscriber.asBinder())) { 181 return; 182 } 183 sequenceNumber = ++mSequenceNumber; 184 185 // If a publisher has no subscribers, remove it 186 if (subscribers.isEmpty()) { 187 subscribersToPublishers.remove(publisherId); 188 } 189 190 // If a layer has no subscribers, remove it 191 if (subscribersToPublishers.isEmpty()) { 192 mLayerSubscriptionsToPublishers.remove(layer); 193 } 194 } 195 VmsOperationRecorder.get().removeSubscription(sequenceNumber, layer); 196 } 197 198 /** 199 * Remove all of a subscriber's subscriptions. 200 * 201 * @param subscriber VMS subscriber to remove 202 * @return {@code true} if the subscription state was modified 203 */ removeDeadSubscriber(IVmsSubscriberClient subscriber)204 public boolean removeDeadSubscriber(IVmsSubscriberClient subscriber) { 205 IBinder subscriberBinder = subscriber.asBinder(); 206 synchronized (mLock) { 207 int startSequenceNumber = mSequenceNumber; 208 209 // Remove the subscriber from the loggers. 210 removeSubscription(subscriber); 211 212 // Remove the subscriber from all layer-based subscriptions. 213 mLayerSubscriptions.entrySet().stream() 214 .filter(e -> e.getValue().contains(subscriberBinder)) 215 .map(Map.Entry::getKey) 216 .collect(Collectors.toSet()) 217 .forEach(layer -> removeSubscription(subscriber, layer)); 218 219 // Remove the subscriber from all publisher-based subscriptions. 220 mLayerSubscriptionsToPublishers.entrySet().stream() 221 .flatMap(layer -> layer.getValue().entrySet().stream() 222 .filter(publisher -> publisher.getValue().contains(subscriberBinder)) 223 .map(publisher -> Pair.create(layer.getKey(), publisher.getKey()))) 224 .collect(Collectors.toSet()) 225 .forEach(layerAndPublisher -> removeSubscription(subscriber, 226 layerAndPublisher.first, layerAndPublisher.second)); 227 228 // Remove the subscriber from the subscriber index 229 mSubscribers.remove(subscriberBinder); 230 231 // If the sequence number was updated, then the subscription state was modified 232 return startSequenceNumber != mSequenceNumber; 233 } 234 } 235 236 /** 237 * Returns a list of all the subscribers a data message should be delivered to. This includes 238 * subscribers that subscribed to this layer from all publishers, subscribed to this layer 239 * from a specific publisher, and passive subscribers. 240 * 241 * @param layer The layer of the message. 242 * @param publisherId the ID of the client that published the message to be routed. 243 * @return a list of the subscribers. 244 */ getSubscribersForLayerFromPublisher(VmsLayer layer, int publisherId)245 public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer, 246 int publisherId) { 247 Set<IBinder> subscribers = new HashSet<>(); 248 synchronized (mLock) { 249 // Add the passive subscribers 250 subscribers.addAll(mPassiveSubscribers); 251 252 // Add the subscribers which explicitly subscribed to this layer 253 subscribers.addAll(mLayerSubscriptions.getOrDefault(layer, Collections.emptySet())); 254 255 // Add the subscribers which explicitly subscribed to this layer and publisher 256 subscribers.addAll( 257 mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap()) 258 .getOrDefault(publisherId, Collections.emptySet())); 259 } 260 return subscribers.stream() 261 .map(binder -> mSubscribers.get(binder)) 262 .filter(Objects::nonNull) 263 .collect(Collectors.toSet()); 264 } 265 266 /** 267 * @return {@code true} if there is an explicit subscription to the layer 268 */ hasLayerSubscriptions(VmsLayer layer)269 public boolean hasLayerSubscriptions(VmsLayer layer) { 270 synchronized (mLock) { 271 return mLayerSubscriptions.containsKey(layer); 272 } 273 } 274 275 /** 276 * @return {@code true} if there is an explicit subscription to the layer and publisherId 277 */ hasLayerFromPublisherSubscriptions(VmsLayer layer, int publisherId)278 public boolean hasLayerFromPublisherSubscriptions(VmsLayer layer, int publisherId) { 279 synchronized (mLock) { 280 return mLayerSubscriptionsToPublishers.containsKey(layer) 281 && mLayerSubscriptionsToPublishers.getOrDefault(layer, Collections.emptyMap()) 282 .containsKey(publisherId); 283 } 284 } 285 286 /** 287 * @return a Set of layers and publishers which VMS clients are subscribed to. 288 */ getSubscriptionState()289 public VmsSubscriptionState getSubscriptionState() { 290 synchronized (mLock) { 291 return new VmsSubscriptionState(mSequenceNumber, 292 new ArraySet<>(mLayerSubscriptions.keySet()), 293 mLayerSubscriptionsToPublishers.entrySet() 294 .stream() 295 .map(e -> new VmsAssociatedLayer(e.getKey(), e.getValue().keySet())) 296 .collect(Collectors.toSet())); 297 } 298 } 299 addSubscriber(IVmsSubscriberClient subscriber)300 private IBinder addSubscriber(IVmsSubscriberClient subscriber) { 301 IBinder subscriberBinder = subscriber.asBinder(); 302 synchronized (mLock) { 303 mSubscribers.putIfAbsent(subscriberBinder, subscriber); 304 } 305 return subscriberBinder; 306 } 307 } 308