• 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 
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.app.Service;
23 import android.content.Intent;
24 import android.os.Binder;
25 import android.os.Build;
26 import android.os.Handler;
27 import android.os.IBinder;
28 import android.os.Looper;
29 import android.os.Message;
30 import android.os.Process;
31 import android.os.RemoteException;
32 import android.util.Log;
33 
34 import com.android.internal.annotations.GuardedBy;
35 import com.android.internal.util.Preconditions;
36 
37 import java.lang.ref.WeakReference;
38 
39 /**
40  * API implementation of a Vehicle Map Service publisher client.
41  *
42  * All publisher clients must inherit from this class and export it as a service, and the service
43  * be added to either the {@code vmsPublisherSystemClients} or {@code vmsPublisherUserClients}
44  * arrays in the Car service configuration, depending on which user the client will run as.
45  *
46  * The {@link com.android.car.VmsPublisherService} will then bind to this service, with the
47  * {@link #onVmsPublisherServiceReady()} callback notifying the client implementation when the
48  * connection is established and publisher operations can be called.
49  *
50  * Publishers must also register a publisher ID by calling {@link #getPublisherId(byte[])}.
51  *
52  * @hide
53  */
54 @SystemApi
55 public abstract class VmsPublisherClientService extends Service {
56     private static final boolean DBG = true;
57     private static final String TAG = "VmsPublisherClientService";
58 
59     private final Object mLock = new Object();
60 
61     private Handler mHandler = new VmsEventHandler(this);
62     private final VmsPublisherClientBinder mVmsPublisherClient = new VmsPublisherClientBinder(this);
63     private volatile IVmsPublisherService mVmsPublisherService = null;
64     @GuardedBy("mLock")
65     private IBinder mToken = null;
66 
67     @Override
onBind(Intent intent)68     public IBinder onBind(Intent intent) {
69         if (DBG) {
70             Log.d(TAG, "onBind, intent: " + intent);
71         }
72         return mVmsPublisherClient.asBinder();
73     }
74 
75     @Override
onUnbind(Intent intent)76     public boolean onUnbind(Intent intent) {
77         if (DBG) {
78             Log.d(TAG, "onUnbind, intent: " + intent);
79         }
80         stopSelf();
81         return super.onUnbind(intent);
82     }
83 
setToken(IBinder token)84     private void setToken(IBinder token) {
85         synchronized (mLock) {
86             mToken = token;
87         }
88     }
89 
90     /**
91      * Notifies the client that publisher services are ready.
92      */
onVmsPublisherServiceReady()93     protected abstract void onVmsPublisherServiceReady();
94 
95     /**
96      * Notifies the client of changes in layer subscriptions.
97      *
98      * @param subscriptionState state of layer subscriptions
99      */
onVmsSubscriptionChange(@onNull VmsSubscriptionState subscriptionState)100     public abstract void onVmsSubscriptionChange(@NonNull VmsSubscriptionState subscriptionState);
101 
102     /**
103      * Publishes a data packet to subscribers.
104      *
105      * Publishers must only publish packets for the layers that they have made offerings for.
106      *
107      * @param layer       layer to publish to
108      * @param publisherId ID of the publisher publishing the message
109      * @param payload     data packet to be sent
110      * @throws IllegalStateException if publisher services are not available
111      */
publish(@onNull VmsLayer layer, int publisherId, byte[] payload)112     public final void publish(@NonNull VmsLayer layer, int publisherId, byte[] payload) {
113         Preconditions.checkNotNull(layer, "layer cannot be null");
114         if (DBG) {
115             Log.d(TAG, "Publishing for layer : " + layer);
116         }
117 
118         IBinder token = getTokenForPublisherServiceThreadSafe();
119 
120         try {
121             mVmsPublisherService.publish(token, layer, publisherId, payload);
122         } catch (RemoteException e) {
123             throw e.rethrowFromSystemServer();
124         }
125     }
126 
127     /**
128      * Sets the layers offered by a specific publisher.
129      *
130      * @param offering layers being offered for subscription by the publisher
131      * @throws IllegalStateException if publisher services are not available
132      */
setLayersOffering(@onNull VmsLayersOffering offering)133     public final void setLayersOffering(@NonNull VmsLayersOffering offering) {
134         Preconditions.checkNotNull(offering, "offering cannot be null");
135         if (DBG) {
136             Log.d(TAG, "Setting layers offering : " + offering);
137         }
138 
139         IBinder token = getTokenForPublisherServiceThreadSafe();
140 
141         try {
142             mVmsPublisherService.setLayersOffering(token, offering);
143             VmsOperationRecorder.get().setLayersOffering(offering);
144         } catch (RemoteException e) {
145             throw e.rethrowFromSystemServer();
146         }
147     }
148 
getTokenForPublisherServiceThreadSafe()149     private IBinder getTokenForPublisherServiceThreadSafe() {
150         if (mVmsPublisherService == null) {
151             throw new IllegalStateException("VmsPublisherService not set.");
152         }
153 
154         IBinder token;
155         synchronized (mLock) {
156             token = mToken;
157         }
158         if (token == null) {
159             throw new IllegalStateException("VmsPublisherService does not have a valid token.");
160         }
161         return token;
162     }
163 
164     /**
165      * Acquires a publisher ID for a serialized publisher description.
166      *
167      * Multiple calls to this method with the same information will return the same publisher ID.
168      *
169      * @param publisherInfo serialized publisher description information, in a vendor-specific
170      *                      format
171      * @return a publisher ID for the given publisher description
172      * @throws IllegalStateException if publisher services are not available
173      */
getPublisherId(byte[] publisherInfo)174     public final int getPublisherId(byte[] publisherInfo) {
175         if (mVmsPublisherService == null) {
176             throw new IllegalStateException("VmsPublisherService not set.");
177         }
178         int publisherId;
179         try {
180             Log.i(TAG, "Getting publisher static ID");
181             publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
182         } catch (RemoteException e) {
183             throw e.rethrowFromSystemServer();
184         }
185         VmsOperationRecorder.get().getPublisherId(publisherId);
186         return publisherId;
187     }
188 
189     /**
190      * Gets the state of layer subscriptions.
191      *
192      * @return state of layer subscriptions
193      * @throws IllegalStateException if publisher services are not available
194      */
getSubscriptions()195     public final VmsSubscriptionState getSubscriptions() {
196         if (mVmsPublisherService == null) {
197             throw new IllegalStateException("VmsPublisherService not set.");
198         }
199         try {
200             return mVmsPublisherService.getSubscriptions();
201         } catch (RemoteException e) {
202             throw e.rethrowFromSystemServer();
203         }
204     }
205 
setVmsPublisherService(IVmsPublisherService service)206     private void setVmsPublisherService(IVmsPublisherService service) {
207         mVmsPublisherService = service;
208         onVmsPublisherServiceReady();
209     }
210 
211     /**
212      * Implements the interface that the VMS service uses to communicate with this client.
213      */
214     private static class VmsPublisherClientBinder extends IVmsPublisherClient.Stub {
215         private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
216         @GuardedBy("mSequenceLock")
217         private long mSequence = -1;
218         private final Object mSequenceLock = new Object();
219 
VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService)220         VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
221             mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
222         }
223 
224         @Override
setVmsPublisherService(IBinder token, IVmsPublisherService service)225         public void setVmsPublisherService(IBinder token, IVmsPublisherService service) {
226             assertSystemOrSelf();
227 
228             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
229             if (vmsPublisherClientService == null) return;
230             if (DBG) {
231                 Log.d(TAG, "setting VmsPublisherService.");
232             }
233             Handler handler = vmsPublisherClientService.mHandler;
234             handler.sendMessage(
235                     handler.obtainMessage(VmsEventHandler.SET_SERVICE_CALLBACK, service));
236             vmsPublisherClientService.setToken(token);
237         }
238 
239         @Override
onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)240         public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
241             assertSystemOrSelf();
242 
243             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
244             if (vmsPublisherClientService == null) return;
245             if (DBG) {
246                 Log.d(TAG, "subscription event: " + subscriptionState);
247             }
248             synchronized (mSequenceLock) {
249                 if (subscriptionState.getSequenceNumber() <= mSequence) {
250                     Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
251                             + "; expected new sequence = " + subscriptionState.getSequenceNumber());
252                     // Do not propagate old notifications.
253                     return;
254                 } else {
255                     mSequence = subscriptionState.getSequenceNumber();
256                 }
257             }
258             Handler handler = vmsPublisherClientService.mHandler;
259             handler.sendMessage(
260                     handler.obtainMessage(VmsEventHandler.ON_SUBSCRIPTION_CHANGE_EVENT,
261                             subscriptionState));
262         }
263 
assertSystemOrSelf()264         private void assertSystemOrSelf() {
265             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
266                 if (DBG) Log.d(TAG, "Skipping system user check");
267                 return;
268             }
269 
270             if (!(Binder.getCallingUid() == Process.SYSTEM_UID
271                     || Binder.getCallingPid() == Process.myPid())) {
272                 throw new SecurityException("Caller must be system user or same process");
273             }
274         }
275     }
276 
277     /**
278      * Receives events from the binder thread and dispatches them.
279      */
280     private final static class VmsEventHandler extends Handler {
281         /** Constants handled in the handler */
282         private static final int ON_SUBSCRIPTION_CHANGE_EVENT = 0;
283         private static final int SET_SERVICE_CALLBACK = 1;
284 
285         private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
286 
VmsEventHandler(VmsPublisherClientService service)287         VmsEventHandler(VmsPublisherClientService service) {
288             super(Looper.getMainLooper());
289             mVmsPublisherClientService = new WeakReference<>(service);
290         }
291 
292         @Override
handleMessage(Message msg)293         public void handleMessage(Message msg) {
294             VmsPublisherClientService service = mVmsPublisherClientService.get();
295             if (service == null) return;
296             switch (msg.what) {
297                 case ON_SUBSCRIPTION_CHANGE_EVENT:
298                     VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
299                     service.onVmsSubscriptionChange(subscriptionState);
300                     break;
301                 case SET_SERVICE_CALLBACK:
302                     service.setVmsPublisherService((IVmsPublisherService) msg.obj);
303                     break;
304                 default:
305                     Log.e(TAG, "Event type not handled:  " + msg.what);
306                     break;
307             }
308         }
309     }
310 }
311