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