• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }