• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.vms;
18 
19 import android.car.vms.IVmsSubscriberClient;
20 import android.car.vms.VmsAvailableLayers;
21 import android.car.vms.VmsLayer;
22 import android.car.vms.VmsLayersOffering;
23 import android.car.vms.VmsOperationRecorder;
24 import android.car.vms.VmsSubscriptionState;
25 import android.content.pm.PackageManager;
26 import android.os.Binder;
27 import android.os.IBinder;
28 import android.os.Process;
29 import android.util.Log;
30 
31 import com.android.car.VmsLayersAvailability;
32 import com.android.car.VmsPublishersInfo;
33 import com.android.car.VmsRouting;
34 import com.android.internal.annotations.GuardedBy;
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.CopyOnWriteArrayList;
42 import java.util.function.IntSupplier;
43 
44 /**
45  * Broker service facilitating subscription handling and message passing between
46  * VmsPublisherService, VmsSubscriberService, and VmsHalService.
47  */
48 public class VmsBrokerService {
49     private static final boolean DBG = true;
50     private static final String TAG = "VmsBrokerService";
51 
52     @VisibleForTesting
53     static final String HAL_CLIENT = "HalClient";
54 
55     @VisibleForTesting
56     static final String UNKNOWN_PACKAGE = "UnknownPackage";
57 
58     private CopyOnWriteArrayList<PublisherListener> mPublisherListeners =
59             new CopyOnWriteArrayList<>();
60     private CopyOnWriteArrayList<SubscriberListener> mSubscriberListeners =
61             new CopyOnWriteArrayList<>();
62     private PackageManager mPackageManager;
63     private IntSupplier mGetCallingPid;
64     private IntSupplier mGetCallingUid;
65 
66     private final Object mLock = new Object();
67     @GuardedBy("mLock")
68     private final VmsRouting mRouting = new VmsRouting();
69     @GuardedBy("mLock")
70     private final Map<IBinder, String> mBinderPackage = new HashMap<>();
71     @GuardedBy("mLock")
72     private final Map<IBinder, Map<Integer, VmsLayersOffering>> mOfferings = new HashMap<>();
73     @GuardedBy("mLock")
74     private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
75     @GuardedBy("mLock")
76     private final VmsPublishersInfo mPublishersInfo = new VmsPublishersInfo();
77 
78     /**
79      * The VMS publisher service implements this interface to receive publisher callbacks.
80      */
81     public interface PublisherListener {
82         /**
83          * Callback triggered when publisher subscription state changes.
84          *
85          * @param subscriptionState Current subscription state.
86          */
onSubscriptionChange(VmsSubscriptionState subscriptionState)87         void onSubscriptionChange(VmsSubscriptionState subscriptionState);
88     }
89 
90     /**
91      * The VMS subscriber service implements this interface to receive subscriber callbacks.
92      */
93     public interface SubscriberListener {
94         /**
95          * Callback triggered when data is published for a given layer.
96          *
97          * @param layer       Layer data is being published for
98          * @param publisherId Publisher of data
99          * @param payload     Layer data
100          */
onMessageReceived(VmsLayer layer, int publisherId, byte[] payload)101         void onMessageReceived(VmsLayer layer, int publisherId, byte[] payload);
102 
103         /**
104          * Callback triggered when the layers available for subscription changes.
105          *
106          * @param availableLayers Current layer availability
107          */
onLayersAvailabilityChange(VmsAvailableLayers availableLayers)108         void onLayersAvailabilityChange(VmsAvailableLayers availableLayers);
109     }
110 
111     /**
112      * Constructs new broker service.
113      */
VmsBrokerService(PackageManager packageManager)114     public VmsBrokerService(PackageManager packageManager) {
115         this(packageManager, Binder::getCallingPid, Binder::getCallingUid);
116     }
117 
118     @VisibleForTesting
VmsBrokerService(PackageManager packageManager, IntSupplier getCallingPid, IntSupplier getCallingUid)119     VmsBrokerService(PackageManager packageManager, IntSupplier getCallingPid,
120             IntSupplier getCallingUid) {
121         if (DBG) Log.d(TAG, "Started VmsBrokerService!");
122         mPackageManager = packageManager;
123         mGetCallingPid = getCallingPid;
124         mGetCallingUid = getCallingUid;
125     }
126 
127     /**
128      * Adds a listener for publisher callbacks.
129      *
130      * @param listener Publisher callback listener
131      */
addPublisherListener(PublisherListener listener)132     public void addPublisherListener(PublisherListener listener) {
133         mPublisherListeners.add(listener);
134     }
135 
136     /**
137      * Adds a listener for subscriber callbacks.
138      *
139      * @param listener Subscriber callback listener
140      */
addSubscriberListener(SubscriberListener listener)141     public void addSubscriberListener(SubscriberListener listener) {
142         mSubscriberListeners.add(listener);
143     }
144 
145     /**
146      * Removes a listener for publisher callbacks.
147      *
148      * @param listener Publisher callback listener
149      */
removePublisherListener(PublisherListener listener)150     public void removePublisherListener(PublisherListener listener) {
151         mPublisherListeners.remove(listener);
152     }
153 
154     /**
155      * Removes a listener for subscriber callbacks.
156      *
157      * @param listener Subscriber callback listener
158      */
removeSubscriberListener(SubscriberListener listener)159     public void removeSubscriberListener(SubscriberListener listener) {
160         mSubscriberListeners.remove(listener);
161     }
162 
163     /**
164      * Adds a subscription to all layers.
165      *
166      * @param subscriber Subscriber client to send layer data
167      */
addSubscription(IVmsSubscriberClient subscriber)168     public void addSubscription(IVmsSubscriberClient subscriber) {
169         synchronized (mLock) {
170             mRouting.addSubscription(subscriber);
171             // Add mapping from binder to package name of subscriber.
172             mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
173         }
174     }
175 
176     /**
177      * Removes a subscription to all layers.
178      *
179      * @param subscriber Subscriber client to remove subscription for
180      */
removeSubscription(IVmsSubscriberClient subscriber)181     public void removeSubscription(IVmsSubscriberClient subscriber) {
182         synchronized (mLock) {
183             mRouting.removeSubscription(subscriber);
184         }
185     }
186 
187     /**
188      * Adds a layer subscription.
189      *
190      * @param subscriber Subscriber client to send layer data
191      * @param layer      Layer to send
192      */
addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)193     public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
194         boolean firstSubscriptionForLayer;
195         if (DBG) Log.d(TAG, "Checking for first subscription. Layer: " + layer);
196         synchronized (mLock) {
197             // Check if publishers need to be notified about this change in subscriptions.
198             firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
199 
200             // Add the listeners subscription to the layer
201             mRouting.addSubscription(subscriber, layer);
202 
203             // Add mapping from binder to package name of subscriber.
204             mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
205         }
206         if (firstSubscriptionForLayer) {
207             notifyOfSubscriptionChange();
208         }
209     }
210 
211     /**
212      * Removes a layer subscription.
213      *
214      * @param subscriber Subscriber client to remove subscription for
215      * @param layer      Layer to remove
216      */
removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer)217     public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer) {
218         boolean layerHasSubscribers;
219         synchronized (mLock) {
220             if (!mRouting.hasLayerSubscriptions(layer)) {
221                 if (DBG) Log.d(TAG, "Trying to remove a layer with no subscription: " + layer);
222                 return;
223             }
224 
225             // Remove the listeners subscription to the layer
226             mRouting.removeSubscription(subscriber, layer);
227 
228             // Check if publishers need to be notified about this change in subscriptions.
229             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
230         }
231         if (!layerHasSubscribers) {
232             notifyOfSubscriptionChange();
233         }
234     }
235 
236     /**
237      * Adds a publisher-specific layer subscription.
238      *
239      * @param subscriber  Subscriber client to send layer data
240      * @param layer       Layer to send
241      * @param publisherId Publisher of layer
242      */
addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)243     public void addSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId) {
244         boolean firstSubscriptionForLayer;
245         synchronized (mLock) {
246             // Check if publishers need to be notified about this change in subscriptions.
247             firstSubscriptionForLayer = !(mRouting.hasLayerSubscriptions(layer)
248                     || mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId));
249 
250             // Add the listeners subscription to the layer
251             mRouting.addSubscription(subscriber, layer, publisherId);
252 
253             // Add mapping from binder to package name of subscriber.
254             mBinderPackage.computeIfAbsent(subscriber.asBinder(), k -> getCallingPackage());
255         }
256         if (firstSubscriptionForLayer) {
257             notifyOfSubscriptionChange();
258         }
259     }
260 
261     /**
262      * Removes a publisher-specific layer subscription.
263      *
264      * @param subscriber  Subscriber client to remove subscription for
265      * @param layer       Layer to remove
266      * @param publisherId Publisher of layer
267      */
removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)268     public void removeSubscription(IVmsSubscriberClient subscriber, VmsLayer layer,
269             int publisherId) {
270         boolean layerHasSubscribers;
271         synchronized (mLock) {
272             if (!mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId)) {
273                 Log.i(TAG, "Trying to remove a layer with no subscription: "
274                         + layer + ", publisher ID:" + publisherId);
275                 return;
276             }
277 
278             // Remove the listeners subscription to the layer
279             mRouting.removeSubscription(subscriber, layer, publisherId);
280 
281             // Check if publishers need to be notified about this change in subscriptions.
282             layerHasSubscribers = mRouting.hasLayerSubscriptions(layer)
283                     || mRouting.hasLayerFromPublisherSubscriptions(layer, publisherId);
284         }
285         if (!layerHasSubscribers) {
286             notifyOfSubscriptionChange();
287         }
288     }
289 
290     /**
291      * Removes a disconnected subscriber's subscriptions
292      *
293      * @param subscriber Subscriber that was disconnected
294      */
removeDeadSubscriber(IVmsSubscriberClient subscriber)295     public void removeDeadSubscriber(IVmsSubscriberClient subscriber) {
296         boolean subscriptionStateChanged;
297         synchronized (mLock) {
298             subscriptionStateChanged = mRouting.removeDeadSubscriber(subscriber);
299 
300             // Remove mapping from binder to package name of subscriber.
301             mBinderPackage.remove(subscriber.asBinder());
302         }
303         if (subscriptionStateChanged) {
304             notifyOfSubscriptionChange();
305         }
306     }
307 
308     /**
309      * Gets all subscribers for a specific layer/publisher combination.
310      *
311      * @param layer       Layer to query
312      * @param publisherId Publisher of layer
313      */
getSubscribersForLayerFromPublisher(VmsLayer layer, int publisherId)314     public Set<IVmsSubscriberClient> getSubscribersForLayerFromPublisher(VmsLayer layer,
315             int publisherId) {
316         synchronized (mLock) {
317             return mRouting.getSubscribersForLayerFromPublisher(layer, publisherId);
318         }
319     }
320 
321     /**
322      * Gets the state of all layer subscriptions.
323      */
getSubscriptionState()324     public VmsSubscriptionState getSubscriptionState() {
325         synchronized (mLock) {
326             return mRouting.getSubscriptionState();
327         }
328     }
329 
330     /**
331      * Assigns an idempotent ID for publisherInfo and stores it. The idempotency in this case means
332      * that the same publisherInfo will always, within a trip of the vehicle, return the same ID.
333      * The publisherInfo should be static for a binary and should only change as part of a software
334      * update. The publisherInfo is a serialized proto message which VMS clients can interpret.
335      */
getPublisherId(byte[] publisherInfo)336     public int getPublisherId(byte[] publisherInfo) {
337         if (DBG) Log.i(TAG, "Getting publisher static ID");
338         synchronized (mLock) {
339             return mPublishersInfo.getIdForInfo(publisherInfo);
340         }
341     }
342 
343     /**
344      * Gets the publisher information data registered in {@link #getPublisherId(byte[])}
345      *
346      * @param publisherId Publisher ID to query
347      * @return Publisher information
348      */
getPublisherInfo(int publisherId)349     public byte[] getPublisherInfo(int publisherId) {
350         if (DBG) Log.i(TAG, "Getting information for publisher ID: " + publisherId);
351         synchronized (mLock) {
352             return mPublishersInfo.getPublisherInfo(publisherId);
353         }
354     }
355 
356     /**
357      * Sets the layers offered by the publisher with the given publisher token.
358      *
359      * @param publisherToken Identifier token of publisher
360      * @param offering       Layers offered by publisher
361      */
setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering)362     public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering) {
363         synchronized (mLock) {
364             Map<Integer, VmsLayersOffering> publisherOfferings = mOfferings.computeIfAbsent(
365                     publisherToken, k -> new HashMap<>());
366             publisherOfferings.put(offering.getPublisherId(), offering);
367             updateLayerAvailability();
368         }
369         VmsOperationRecorder.get().setPublisherLayersOffering(offering);
370         notifyOfAvailabilityChange();
371     }
372 
373     /**
374      * Removes a disconnected publisher's offerings
375      *
376      * @param publisherToken Identifier token of publisher to be removed
377      */
removeDeadPublisher(IBinder publisherToken)378     public void removeDeadPublisher(IBinder publisherToken) {
379         synchronized (mLock) {
380             mOfferings.remove(publisherToken);
381             updateLayerAvailability();
382         }
383         notifyOfAvailabilityChange();
384     }
385 
386     /**
387      * Gets all layers available for subscription.
388      *
389      * @return All available layers
390      */
getAvailableLayers()391     public VmsAvailableLayers getAvailableLayers() {
392         synchronized (mLock) {
393             return mAvailableLayers.getAvailableLayers();
394         }
395     }
396 
397     /**
398      * Gets the package name for a given IVmsSubscriberClient
399      */
getPackageName(IVmsSubscriberClient subscriber)400     public String getPackageName(IVmsSubscriberClient subscriber) {
401         synchronized (mLock) {
402             return mBinderPackage.get(subscriber.asBinder());
403         }
404     }
405 
updateLayerAvailability()406     private void updateLayerAvailability() {
407         Set<VmsLayersOffering> allPublisherOfferings = new HashSet<>();
408         synchronized (mLock) {
409             for (Map<Integer, VmsLayersOffering> offerings : mOfferings.values()) {
410                 allPublisherOfferings.addAll(offerings.values());
411             }
412             if (DBG) Log.d(TAG, "New layer availability: " + allPublisherOfferings);
413             mAvailableLayers.setPublishersOffering(allPublisherOfferings);
414         }
415     }
416 
notifyOfSubscriptionChange()417     private void notifyOfSubscriptionChange() {
418         if (DBG) Log.d(TAG, "Notifying publishers on subscriptions");
419 
420         VmsSubscriptionState subscriptionState = getSubscriptionState();
421         // Notify the App publishers
422         for (PublisherListener listener : mPublisherListeners) {
423             listener.onSubscriptionChange(subscriptionState);
424         }
425     }
426 
notifyOfAvailabilityChange()427     private void notifyOfAvailabilityChange() {
428         if (DBG) Log.d(TAG, "Notifying subscribers on layers availability");
429 
430         VmsAvailableLayers availableLayers = getAvailableLayers();
431         // Notify the App subscribers
432         for (SubscriberListener listener : mSubscriberListeners) {
433             listener.onLayersAvailabilityChange(availableLayers);
434         }
435     }
436 
437     // If we're in a binder call, returns back the package name of the caller of the binder call.
getCallingPackage()438     private String getCallingPackage() {
439         int callingPid = mGetCallingPid.getAsInt();
440         // Since the HAL lives in the same process, if the callingPid is equal to this process's
441         // PID, we know it's the HAL client.
442         if (callingPid == Process.myPid()) {
443             return HAL_CLIENT;
444         }
445         int callingUid = mGetCallingUid.getAsInt();
446         String packageName = mPackageManager.getNameForUid(callingUid);
447         if (packageName == null) {
448             return UNKNOWN_PACKAGE;
449         } else {
450             return packageName;
451         }
452     }
453 }
454