• 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 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