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 android.car.vms; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.car.CarManagerBase; 23 import android.os.Binder; 24 import android.os.IBinder; 25 import android.os.RemoteException; 26 import android.util.Log; 27 28 import com.android.internal.annotations.GuardedBy; 29 import com.android.internal.util.Preconditions; 30 31 import java.util.concurrent.Executor; 32 33 /** 34 * API implementation for use by Vehicle Map Service subscribers. 35 * 36 * Supports a single client callback that can subscribe and unsubscribe to different data layers. 37 * {@link #setVmsSubscriberClientCallback} must be called before any subscription operations. 38 * 39 * @hide 40 */ 41 @SystemApi 42 public final class VmsSubscriberManager implements CarManagerBase { 43 private static final boolean DBG = true; 44 private static final String TAG = "VmsSubscriberManager"; 45 46 private final IVmsSubscriberService mVmsSubscriberService; 47 private final IVmsSubscriberClient mSubscriberManagerClient; 48 private final Object mClientCallbackLock = new Object(); 49 @GuardedBy("mClientCallbackLock") 50 private VmsSubscriberClientCallback mClientCallback; 51 @GuardedBy("mClientCallbackLock") 52 private Executor mExecutor; 53 54 /** 55 * Callback interface for Vehicle Map Service subscribers. 56 */ 57 public interface VmsSubscriberClientCallback { 58 /** 59 * Called when a data packet is received. 60 * 61 * @param layer subscribed layer that packet was received for 62 * @param payload data packet that was received 63 */ onVmsMessageReceived(@onNull VmsLayer layer, byte[] payload)64 void onVmsMessageReceived(@NonNull VmsLayer layer, byte[] payload); 65 66 /** 67 * Called when set of available data layers changes. 68 * 69 * @param availableLayers set of available data layers 70 */ onLayersAvailabilityChanged(@onNull VmsAvailableLayers availableLayers)71 void onLayersAvailabilityChanged(@NonNull VmsAvailableLayers availableLayers); 72 } 73 74 /** 75 * Hidden constructor - can only be used internally. 76 * 77 * @hide 78 */ VmsSubscriberManager(IBinder service)79 public VmsSubscriberManager(IBinder service) { 80 mVmsSubscriberService = IVmsSubscriberService.Stub.asInterface(service); 81 mSubscriberManagerClient = new IVmsSubscriberClient.Stub() { 82 @Override 83 public void onVmsMessageReceived(VmsLayer layer, byte[] payload) { 84 Executor executor; 85 synchronized (mClientCallbackLock) { 86 executor = mExecutor; 87 } 88 if (executor == null) { 89 if (DBG) { 90 Log.d(TAG, "Executor is null in onVmsMessageReceived"); 91 } 92 return; 93 } 94 Binder.clearCallingIdentity(); 95 executor.execute(() -> { 96 dispatchOnReceiveMessage(layer, payload); 97 }); 98 } 99 100 @Override 101 public void onLayersAvailabilityChanged(VmsAvailableLayers availableLayers) { 102 Executor executor; 103 synchronized (mClientCallbackLock) { 104 executor = mExecutor; 105 } 106 if (executor == null) { 107 if (DBG) { 108 Log.d(TAG, "Executor is null in onLayersAvailabilityChanged"); 109 } 110 return; 111 } 112 Binder.clearCallingIdentity(); 113 executor.execute(() -> { 114 dispatchOnAvailabilityChangeMessage(availableLayers); 115 }); 116 } 117 }; 118 } 119 120 /** 121 * Sets the subscriber client's callback, for receiving layer availability and data events. 122 * 123 * @param executor {@link Executor} to handle the callbacks 124 * @param clientCallback subscriber callback that will handle events 125 * @throws IllegalStateException if the client callback was already set 126 */ setVmsSubscriberClientCallback( @onNull @allbackExecutor Executor executor, @NonNull VmsSubscriberClientCallback clientCallback)127 public void setVmsSubscriberClientCallback( 128 @NonNull @CallbackExecutor Executor executor, 129 @NonNull VmsSubscriberClientCallback clientCallback) { 130 synchronized (mClientCallbackLock) { 131 if (mClientCallback != null) { 132 throw new IllegalStateException("Client callback is already configured."); 133 } 134 mClientCallback = Preconditions.checkNotNull(clientCallback, 135 "clientCallback cannot be null"); 136 mExecutor = Preconditions.checkNotNull(executor, "executor cannot be null"); 137 } 138 try { 139 mVmsSubscriberService.addVmsSubscriberToNotifications(mSubscriberManagerClient); 140 } catch (RemoteException e) { 141 throw e.rethrowFromSystemServer(); 142 } 143 } 144 145 146 /** 147 * Clears the subscriber client's callback. 148 */ clearVmsSubscriberClientCallback()149 public void clearVmsSubscriberClientCallback() { 150 synchronized (mClientCallbackLock) { 151 if (mExecutor == null) return; 152 } 153 try { 154 mVmsSubscriberService.removeVmsSubscriberToNotifications(mSubscriberManagerClient); 155 } catch (RemoteException e) { 156 throw e.rethrowFromSystemServer(); 157 } finally { 158 synchronized (mClientCallbackLock) { 159 mClientCallback = null; 160 mExecutor = null; 161 } 162 } 163 } 164 165 /** 166 * Gets a publisher's self-reported description information. 167 * 168 * @param publisherId publisher ID to retrieve information for 169 * @return serialized publisher information, in a vendor-specific format 170 */ 171 @NonNull getPublisherInfo(int publisherId)172 public byte[] getPublisherInfo(int publisherId) { 173 try { 174 return mVmsSubscriberService.getPublisherInfo(publisherId); 175 } catch (RemoteException e) { 176 throw e.rethrowFromSystemServer(); 177 } 178 } 179 180 /** 181 * Gets all layers available for subscription. 182 * 183 * @return available layers 184 */ 185 @NonNull getAvailableLayers()186 public VmsAvailableLayers getAvailableLayers() { 187 try { 188 return mVmsSubscriberService.getAvailableLayers(); 189 } catch (RemoteException e) { 190 throw e.rethrowFromSystemServer(); 191 } 192 } 193 194 /** 195 * Subscribes to data packets for a specific layer. 196 * 197 * @param layer layer to subscribe to 198 * @throws IllegalStateException if the client callback was not set via 199 * {@link #setVmsSubscriberClientCallback}. 200 */ subscribe(@onNull VmsLayer layer)201 public void subscribe(@NonNull VmsLayer layer) { 202 verifySubscriptionIsAllowed(); 203 try { 204 mVmsSubscriberService.addVmsSubscriber(mSubscriberManagerClient, layer); 205 VmsOperationRecorder.get().subscribe(layer); 206 } catch (RemoteException e) { 207 throw e.rethrowFromSystemServer(); 208 } 209 } 210 211 /** 212 * Subscribes to data packets for a specific layer from a specific publisher. 213 * 214 * @param layer layer to subscribe to 215 * @param publisherId a publisher of the layer 216 * @throws IllegalStateException if the client callback was not set via 217 * {@link #setVmsSubscriberClientCallback}. 218 */ subscribe(@onNull VmsLayer layer, int publisherId)219 public void subscribe(@NonNull VmsLayer layer, int publisherId) { 220 verifySubscriptionIsAllowed(); 221 try { 222 mVmsSubscriberService.addVmsSubscriberToPublisher( 223 mSubscriberManagerClient, layer, publisherId); 224 VmsOperationRecorder.get().subscribe(layer, publisherId); 225 } catch (RemoteException e) { 226 throw e.rethrowFromSystemServer(); 227 } 228 } 229 230 /** 231 * Start monitoring all messages for all layers, regardless of subscriptions. 232 */ startMonitoring()233 public void startMonitoring() { 234 verifySubscriptionIsAllowed(); 235 try { 236 mVmsSubscriberService.addVmsSubscriberPassive(mSubscriberManagerClient); 237 VmsOperationRecorder.get().startMonitoring(); 238 } catch (RemoteException e) { 239 throw e.rethrowFromSystemServer(); 240 } 241 } 242 243 /** 244 * Unsubscribes from data packets for a specific layer. 245 * 246 * @param layer layer to unsubscribe from 247 * @throws IllegalStateException if the client callback was not set via 248 * {@link #setVmsSubscriberClientCallback}. 249 */ unsubscribe(@onNull VmsLayer layer)250 public void unsubscribe(@NonNull VmsLayer layer) { 251 verifySubscriptionIsAllowed(); 252 try { 253 mVmsSubscriberService.removeVmsSubscriber(mSubscriberManagerClient, layer); 254 VmsOperationRecorder.get().unsubscribe(layer); 255 } catch (RemoteException e) { 256 throw e.rethrowFromSystemServer(); 257 } 258 } 259 260 /** 261 * Unsubscribes from data packets for a specific layer from a specific publisher. 262 * 263 * @param layer layer to unsubscribe from 264 * @param publisherId a publisher of the layer 265 * @throws IllegalStateException if the client callback was not set via 266 * {@link #setVmsSubscriberClientCallback}. 267 */ unsubscribe(@onNull VmsLayer layer, int publisherId)268 public void unsubscribe(@NonNull VmsLayer layer, int publisherId) { 269 try { 270 mVmsSubscriberService.removeVmsSubscriberToPublisher( 271 mSubscriberManagerClient, layer, publisherId); 272 VmsOperationRecorder.get().unsubscribe(layer, publisherId); 273 } catch (RemoteException e) { 274 throw e.rethrowFromSystemServer(); 275 } 276 } 277 278 /** 279 * Stop monitoring. Only receive messages for layers which have been subscribed to." 280 */ stopMonitoring()281 public void stopMonitoring() { 282 try { 283 mVmsSubscriberService.removeVmsSubscriberPassive(mSubscriberManagerClient); 284 VmsOperationRecorder.get().stopMonitoring(); 285 } catch (RemoteException e) { 286 throw e.rethrowFromSystemServer(); 287 } 288 } 289 dispatchOnReceiveMessage(VmsLayer layer, byte[] payload)290 private void dispatchOnReceiveMessage(VmsLayer layer, byte[] payload) { 291 VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe(); 292 if (clientCallback == null) { 293 Log.e(TAG, "Cannot dispatch received message."); 294 return; 295 } 296 clientCallback.onVmsMessageReceived(layer, payload); 297 } 298 dispatchOnAvailabilityChangeMessage(VmsAvailableLayers availableLayers)299 private void dispatchOnAvailabilityChangeMessage(VmsAvailableLayers availableLayers) { 300 VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe(); 301 if (clientCallback == null) { 302 Log.e(TAG, "Cannot dispatch availability change message."); 303 return; 304 } 305 clientCallback.onLayersAvailabilityChanged(availableLayers); 306 } 307 getClientCallbackThreadSafe()308 private VmsSubscriberClientCallback getClientCallbackThreadSafe() { 309 VmsSubscriberClientCallback clientCallback; 310 synchronized (mClientCallbackLock) { 311 clientCallback = mClientCallback; 312 } 313 if (clientCallback == null) { 314 Log.e(TAG, "client callback not set."); 315 } 316 return clientCallback; 317 } 318 319 /* 320 * Verifies that the subscriber is in a state where it is allowed to subscribe. 321 */ verifySubscriptionIsAllowed()322 private void verifySubscriptionIsAllowed() { 323 VmsSubscriberClientCallback clientCallback = getClientCallbackThreadSafe(); 324 if (clientCallback == null) { 325 throw new IllegalStateException("Cannot subscribe."); 326 } 327 } 328 329 /** 330 * @hide 331 */ 332 @Override onCarDisconnected()333 public void onCarDisconnected() { 334 } 335 } 336