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