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.annotation.FutureFeature; 20 import android.car.vms.IVmsSubscriberClient; 21 import android.car.vms.VmsLayer; 22 import android.car.vms.VmsSubscriptionState; 23 24 import java.util.ArrayList; 25 import java.util.HashSet; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Set; 30 31 import com.android.internal.annotations.GuardedBy; 32 33 /** 34 * Manages all the VMS subscriptions: 35 * + Subscriptions to data messages of individual layer + version. 36 * + Subscriptions to all data messages. 37 * + HAL subscriptions to layer + version. 38 */ 39 @FutureFeature 40 public class VmsRouting { 41 private final Object mLock = new Object(); 42 // A map of Layer + Version to listeners. 43 @GuardedBy("mLock") 44 private Map<VmsLayer, Set<IVmsSubscriberClient>> mLayerSubscriptions = 45 new HashMap<>(); 46 // A set of listeners that are interested in any layer + version. 47 @GuardedBy("mLock") 48 private Set<IVmsSubscriberClient> mPromiscuousSubscribers = 49 new HashSet<>(); 50 // A set of all the layers + versions the HAL is subscribed to. 51 @GuardedBy("mLock") 52 private Set<VmsLayer> mHalSubscriptions = new HashSet<>(); 53 // A sequence number that is increased every time the subscription state is modified. Note that 54 // modifying the list of promiscuous subscribers does not affect the subscription state. 55 @GuardedBy("mLock") 56 private int mSequenceNumber = 0; 57 58 /** 59 * Add a listener subscription to a data messages from layer + version. 60 * 61 * @param listener a VMS subscriber. 62 * @param layer the layer subscribing to. 63 */ addSubscription(IVmsSubscriberClient listener, VmsLayer layer)64 public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) { 65 synchronized (mLock) { 66 ++mSequenceNumber; 67 // Get or create the list of listeners for layer and version. 68 Set<IVmsSubscriberClient> listeners = mLayerSubscriptions.get(layer); 69 70 if (listeners == null) { 71 listeners = new HashSet<>(); 72 mLayerSubscriptions.put(layer, listeners); 73 } 74 // Add the listener to the list. 75 listeners.add(listener); 76 } 77 } 78 79 /** 80 * Add a listener subscription to all data messages. 81 * 82 * @param listener a VMS subscriber. 83 */ addSubscription(IVmsSubscriberClient listener)84 public void addSubscription(IVmsSubscriberClient listener) { 85 synchronized (mLock) { 86 ++mSequenceNumber; 87 mPromiscuousSubscribers.add(listener); 88 } 89 } 90 91 /** 92 * Remove a subscription for a layer + version and make sure to remove the key if there are no 93 * more subscribers. 94 * 95 * @param listener to remove. 96 * @param layer of the subscription. 97 */ removeSubscription(IVmsSubscriberClient listener, VmsLayer layer)98 public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) { 99 synchronized (mLock) { 100 ++mSequenceNumber; 101 Set<IVmsSubscriberClient> listeners = mLayerSubscriptions.get(layer); 102 103 // If there are no listeners we are done. 104 if (listeners == null) { 105 return; 106 } 107 listeners.remove(listener); 108 109 // If there are no more listeners then remove the list. 110 if (listeners.isEmpty()) { 111 mLayerSubscriptions.remove(layer); 112 } 113 } 114 } 115 116 /** 117 * Remove a listener subscription to all data messages. 118 * 119 * @param listener a VMS subscriber. 120 */ removeSubscription(IVmsSubscriberClient listener)121 public void removeSubscription(IVmsSubscriberClient listener) { 122 synchronized (mLock) { 123 ++mSequenceNumber; 124 mPromiscuousSubscribers.remove(listener); 125 } 126 } 127 128 /** 129 * Remove a subscriber from all routes (optional operation). 130 * 131 * @param listener a VMS subscriber. 132 */ removeDeadListener(IVmsSubscriberClient listener)133 public void removeDeadListener(IVmsSubscriberClient listener) { 134 synchronized (mLock) { 135 // Remove the listener from all the routes. 136 for (VmsLayer layer : mLayerSubscriptions.keySet()) { 137 removeSubscription(listener, layer); 138 } 139 // Remove the listener from the loggers. 140 removeSubscription(listener); 141 } 142 } 143 144 /** 145 * Returns all the listeners for a layer and version. This include the subscribers which 146 * explicitly subscribed to this layer and version and the promiscuous subscribers. 147 * 148 * @param layer to get listeners to. 149 * @return a list of the listeners. 150 */ getListeners(VmsLayer layer)151 public Set<IVmsSubscriberClient> getListeners(VmsLayer layer) { 152 Set<IVmsSubscriberClient> listeners = new HashSet<>(); 153 synchronized (mLock) { 154 // Add the subscribers which explicitly subscribed to this layer and version 155 if (mLayerSubscriptions.containsKey(layer)) { 156 listeners.addAll(mLayerSubscriptions.get(layer)); 157 } 158 // Add the promiscuous subscribers. 159 listeners.addAll(mPromiscuousSubscribers); 160 } 161 return listeners; 162 } 163 164 /** 165 * Checks if a listener is subscribed to any messages. 166 * @param listener that may have subscription. 167 * @return true if the listener uis subscribed to messages. 168 */ containsListener(IVmsSubscriberClient listener)169 public boolean containsListener(IVmsSubscriberClient listener) { 170 synchronized (mLock) { 171 // Check if listener is subscribed to a layer. 172 for (Set<IVmsSubscriberClient> layerListeners: mLayerSubscriptions.values()) { 173 if (layerListeners.contains(listener)) { 174 return true; 175 } 176 } 177 // Check is listener is subscribed to all data messages. 178 return mPromiscuousSubscribers.contains(listener); 179 } 180 } 181 182 /** 183 * Add a layer and version to the HAL subscriptions. 184 * @param layer the HAL subscribes to. 185 */ addHalSubscription(VmsLayer layer)186 public void addHalSubscription(VmsLayer layer) { 187 synchronized (mLock) { 188 ++mSequenceNumber; 189 mHalSubscriptions.add(layer); 190 } 191 } 192 193 /** 194 * remove a layer and version to the HAL subscriptions. 195 * @param layer the HAL unsubscribes from. 196 */ removeHalSubscription(VmsLayer layer)197 public void removeHalSubscription(VmsLayer layer) { 198 synchronized (mLock) { 199 ++mSequenceNumber; 200 mHalSubscriptions.remove(layer); 201 } 202 } 203 204 /** 205 * checks if the HAL is subscribed to a layer. 206 * @param layer 207 * @return true if the HAL is subscribed to layer. 208 */ isHalSubscribed(VmsLayer layer)209 public boolean isHalSubscribed(VmsLayer layer) { 210 synchronized (mLock) { 211 return mHalSubscriptions.contains(layer); 212 } 213 } 214 215 /** 216 * checks if there are subscribers to a layer. 217 * @param layer 218 * @return true if there are subscribers to layer. 219 */ hasLayerSubscriptions(VmsLayer layer)220 public boolean hasLayerSubscriptions(VmsLayer layer) { 221 synchronized (mLock) { 222 return mLayerSubscriptions.containsKey(layer) || mHalSubscriptions.contains(layer); 223 } 224 } 225 226 /** 227 * @return a Set of layers and versions which VMS clients are subscribed to. 228 */ getSubscriptionState()229 public VmsSubscriptionState getSubscriptionState() { 230 synchronized (mLock) { 231 List<VmsLayer> layers = new ArrayList<>(); 232 layers.addAll(mLayerSubscriptions.keySet()); 233 layers.addAll(mHalSubscriptions); 234 return new VmsSubscriptionState(mSequenceNumber, layers); 235 } 236 } 237 }