• 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.Car;
20 import android.car.vms.IVmsSubscriberClient;
21 import android.car.vms.IVmsSubscriberService;
22 import android.car.vms.VmsAvailableLayers;
23 import android.car.vms.VmsLayer;
24 import android.content.Context;
25 import android.os.IBinder;
26 import android.os.RemoteException;
27 import android.util.Log;
28 
29 import com.android.car.hal.VmsHalService;
30 import com.android.internal.annotations.GuardedBy;
31 
32 import java.io.PrintWriter;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39 
40 /**
41  * + Receives HAL updates by implementing VmsHalService.VmsHalListener.
42  * + Offers subscriber/publisher services by implementing IVmsService.Stub.
43  */
44 public class VmsSubscriberService extends IVmsSubscriberService.Stub
45         implements CarServiceBase, VmsHalService.VmsHalSubscriberListener {
46     private static final boolean DBG = true;
47     private static final String PERMISSION = Car.PERMISSION_VMS_SUBSCRIBER;
48     private static final String TAG = "VmsSubscriberService";
49 
50     private final Context mContext;
51     private final VmsHalService mHal;
52 
53     @GuardedBy("mSubscriberServiceLock")
54     private final VmsSubscribersManager mSubscribersManager = new VmsSubscribersManager();
55     private final Object mSubscriberServiceLock = new Object();
56 
57     /**
58      * Keeps track of subscribers of this service.
59      */
60     class VmsSubscribersManager {
61         /**
62          * Allows to modify mSubscriberMap and mListenerDeathRecipientMap as a single unit.
63          */
64         private final Object mListenerManagerLock = new Object();
65         @GuardedBy("mListenerManagerLock")
66         private final Map<IBinder, ListenerDeathRecipient> mListenerDeathRecipientMap =
67                 new HashMap<>();
68         @GuardedBy("mListenerManagerLock")
69         private final Map<IBinder, IVmsSubscriberClient> mSubscriberMap = new HashMap<>();
70 
71         class ListenerDeathRecipient implements IBinder.DeathRecipient {
72             private IBinder mSubscriberBinder;
73 
ListenerDeathRecipient(IBinder subscriberBinder)74             ListenerDeathRecipient(IBinder subscriberBinder) {
75                 mSubscriberBinder = subscriberBinder;
76             }
77 
78             /**
79              * Listener died. Remove it from this service.
80              */
81             @Override
binderDied()82             public void binderDied() {
83                 if (DBG) {
84                     Log.d(TAG, "binderDied " + mSubscriberBinder);
85                 }
86 
87                 // Get the Listener from the Binder
88                 IVmsSubscriberClient subscriber = mSubscriberMap.get(mSubscriberBinder);
89 
90                 // Remove the subscriber subscriptions.
91                 if (subscriber != null) {
92                     Log.d(TAG, "Removing subscriptions for dead subscriber: " + subscriber);
93                     mHal.removeDeadSubscriber(subscriber);
94                 } else {
95                     Log.d(TAG, "Handling dead binder with no matching subscriber");
96 
97                 }
98 
99                 // Remove binder
100                 VmsSubscribersManager.this.removeListener(mSubscriberBinder);
101             }
102 
release()103             void release() {
104                 mSubscriberBinder.unlinkToDeath(this, 0);
105             }
106         }
107 
release()108         public void release() {
109             for (ListenerDeathRecipient recipient : mListenerDeathRecipientMap.values()) {
110                 recipient.release();
111             }
112             mListenerDeathRecipientMap.clear();
113             mSubscriberMap.clear();
114         }
115 
116         /**
117          * Adds the subscriber and a death recipient associated to it.
118          *
119          * @param subscriber to be added.
120          * @throws IllegalArgumentException if the subscriber is null.
121          * @throws IllegalStateException    if it was not possible to link a death recipient to the
122          *                                  subscriber.
123          */
add(IVmsSubscriberClient subscriber)124         public void add(IVmsSubscriberClient subscriber) {
125             ICarImpl.assertVmsSubscriberPermission(mContext);
126             if (subscriber == null) {
127                 Log.e(TAG, "register: subscriber is null.");
128                 throw new IllegalArgumentException("subscriber cannot be null.");
129             }
130             if (DBG) {
131                 Log.d(TAG, "register: " + subscriber);
132             }
133             IBinder subscriberBinder = subscriber.asBinder();
134             synchronized (mListenerManagerLock) {
135                 if (mSubscriberMap.containsKey(subscriberBinder)) {
136                     // Already registered, nothing to do.
137                     return;
138                 }
139                 ListenerDeathRecipient deathRecipient =
140                         new ListenerDeathRecipient(subscriberBinder);
141                 try {
142                     subscriberBinder.linkToDeath(deathRecipient, 0);
143                 } catch (RemoteException e) {
144                     Log.e(TAG, "Failed to link death for recipient. ", e);
145                     throw new IllegalStateException(Car.CAR_NOT_CONNECTED_EXCEPTION_MSG);
146                 }
147                 mListenerDeathRecipientMap.put(subscriberBinder, deathRecipient);
148                 mSubscriberMap.put(subscriberBinder, subscriber);
149             }
150         }
151 
152         /**
153          * Removes the subscriber and associated death recipient.
154          *
155          * @param subscriber to be removed.
156          * @throws IllegalArgumentException if subscriber is null.
157          */
remove(IVmsSubscriberClient subscriber)158         public void remove(IVmsSubscriberClient subscriber) {
159             if (DBG) {
160                 Log.d(TAG, "unregisterListener");
161             }
162             ICarImpl.assertPermission(mContext, PERMISSION);
163             if (subscriber == null) {
164                 Log.e(TAG, "unregister: subscriber is null.");
165                 throw new IllegalArgumentException("Listener is null");
166             }
167             IBinder subscriberBinder = subscriber.asBinder();
168             removeListener(subscriberBinder);
169         }
170 
171         // Removes the subscriberBinder from the current state.
172         // The function assumes that binder will exist both in subscriber and death recipients list.
removeListener(IBinder subscriberBinder)173         private void removeListener(IBinder subscriberBinder) {
174             synchronized (mListenerManagerLock) {
175                 boolean found = mSubscriberMap.remove(subscriberBinder) != null;
176                 if (found) {
177                     mListenerDeathRecipientMap.get(subscriberBinder).release();
178                     mListenerDeathRecipientMap.remove(subscriberBinder);
179                 } else {
180                     Log.e(TAG, "removeListener: subscriber was not previously registered.");
181                 }
182             }
183         }
184 
185         /**
186          * Returns list of subscribers currently registered.
187          *
188          * @return list of subscribers.
189          */
getListeners()190         public List<IVmsSubscriberClient> getListeners() {
191             synchronized (mListenerManagerLock) {
192                 return new ArrayList<>(mSubscriberMap.values());
193             }
194         }
195     }
196 
VmsSubscriberService(Context context, VmsHalService hal)197     public VmsSubscriberService(Context context, VmsHalService hal) {
198         mContext = context;
199         mHal = hal;
200     }
201 
202     // Implements CarServiceBase interface.
203     @Override
init()204     public void init() {
205         mHal.addSubscriberListener(this);
206     }
207 
208     @Override
release()209     public void release() {
210         mSubscribersManager.release();
211         mHal.removeSubscriberListener(this);
212     }
213 
214     @Override
dump(PrintWriter writer)215     public void dump(PrintWriter writer) {
216     }
217 
218     // Implements IVmsService interface.
219     @Override
addVmsSubscriberToNotifications(IVmsSubscriberClient subscriber)220     public void addVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
221         ICarImpl.assertVmsSubscriberPermission(mContext);
222         synchronized (mSubscriberServiceLock) {
223             // Add the subscriber so it can subscribe.
224             mSubscribersManager.add(subscriber);
225         }
226     }
227 
228     @Override
removeVmsSubscriberToNotifications(IVmsSubscriberClient subscriber)229     public void removeVmsSubscriberToNotifications(IVmsSubscriberClient subscriber) {
230         ICarImpl.assertVmsSubscriberPermission(mContext);
231         synchronized (mSubscriberServiceLock) {
232             if (mHal.containsSubscriber(subscriber)) {
233                 throw new IllegalArgumentException("Subscriber has active subscriptions.");
234             }
235             mSubscribersManager.remove(subscriber);
236         }
237     }
238 
239     @Override
addVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer)240     public void addVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
241         ICarImpl.assertVmsSubscriberPermission(mContext);
242         synchronized (mSubscriberServiceLock) {
243             // Add the subscriber so it can subscribe.
244             mSubscribersManager.add(subscriber);
245 
246             // Add the subscription for the layer.
247             mHal.addSubscription(subscriber, layer);
248         }
249     }
250 
251     @Override
removeVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer)252     public void removeVmsSubscriber(IVmsSubscriberClient subscriber, VmsLayer layer) {
253         ICarImpl.assertVmsSubscriberPermission(mContext);
254         synchronized (mSubscriberServiceLock) {
255             // Remove the subscription.
256             mHal.removeSubscription(subscriber, layer);
257         }
258     }
259 
260     @Override
addVmsSubscriberToPublisher(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)261     public void addVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
262                                             VmsLayer layer,
263                                             int publisherId) {
264         ICarImpl.assertVmsSubscriberPermission(mContext);
265         synchronized (mSubscriberServiceLock) {
266             // Add the subscriber so it can subscribe.
267             mSubscribersManager.add(subscriber);
268 
269             // Add the subscription for the layer.
270             mHal.addSubscription(subscriber, layer, publisherId);
271         }
272     }
273 
274     @Override
removeVmsSubscriberToPublisher(IVmsSubscriberClient subscriber, VmsLayer layer, int publisherId)275     public void removeVmsSubscriberToPublisher(IVmsSubscriberClient subscriber,
276                                                VmsLayer layer,
277                                                int publisherId) {
278         ICarImpl.assertVmsSubscriberPermission(mContext);
279         synchronized (mSubscriberServiceLock) {
280             // Remove the subscription.
281             mHal.removeSubscription(subscriber, layer, publisherId);
282         }
283     }
284 
285     @Override
addVmsSubscriberPassive(IVmsSubscriberClient subscriber)286     public void addVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
287         ICarImpl.assertVmsSubscriberPermission(mContext);
288         synchronized (mSubscriberServiceLock) {
289             mSubscribersManager.add(subscriber);
290             mHal.addSubscription(subscriber);
291         }
292     }
293 
294     @Override
removeVmsSubscriberPassive(IVmsSubscriberClient subscriber)295     public void removeVmsSubscriberPassive(IVmsSubscriberClient subscriber) {
296         ICarImpl.assertVmsSubscriberPermission(mContext);
297         synchronized (mSubscriberServiceLock) {
298             // Remove the subscription.
299             mHal.removeSubscription(subscriber);
300         }
301     }
302 
303     @Override
getPublisherInfo(int publisherId)304     public byte[] getPublisherInfo(int publisherId) {
305         ICarImpl.assertVmsSubscriberPermission(mContext);
306         synchronized (mSubscriberServiceLock) {
307             return mHal.getPublisherInfo(publisherId);
308         }
309     }
310 
311     @Override
getAvailableLayers()312     public VmsAvailableLayers getAvailableLayers() {
313         return mHal.getAvailableLayers();
314 
315     }
316 
317     // Implements VmsHalSubscriberListener interface
318     @Override
onDataMessage(VmsLayer layer, int publisherId, byte[] payload)319     public void onDataMessage(VmsLayer layer, int publisherId, byte[] payload) {
320         if (DBG) {
321             Log.d(TAG, "Publishing a message for layer: " + layer);
322         }
323 
324         Set<IVmsSubscriberClient> subscribers =
325                 mHal.getSubscribersForLayerFromPublisher(layer, publisherId);
326 
327         for (IVmsSubscriberClient subscriber : subscribers) {
328             try {
329                 subscriber.onVmsMessageReceived(layer, payload);
330             } catch (RemoteException e) {
331                 // If we could not send a record, its likely the connection snapped. Let the binder
332                 // death handle the situation.
333                 Log.e(TAG, "onVmsMessageReceived calling failed: ", e);
334             }
335         }
336     }
337 
338     @Override
onLayersAvaiabilityChange(VmsAvailableLayers availableLayers)339     public void onLayersAvaiabilityChange(VmsAvailableLayers availableLayers) {
340         if (DBG) {
341             Log.d(TAG, "Publishing layers availability change: " + availableLayers);
342         }
343 
344         Set<IVmsSubscriberClient> subscribers;
345         subscribers = new HashSet<>(mSubscribersManager.getListeners());
346 
347         for (IVmsSubscriberClient subscriber : subscribers) {
348             try {
349                 subscriber.onLayersAvailabilityChanged(availableLayers);
350             } catch (RemoteException e) {
351                 // If we could not send a record, its likely the connection snapped. Let the binder
352                 // death handle the situation.
353                 Log.e(TAG, "onLayersAvailabilityChanged calling failed: ", e);
354             }
355         }
356     }
357 }
358