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