• 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.SystemApi;
21 import android.app.Service;
22 import android.content.Intent;
23 import android.os.Handler;
24 import android.os.IBinder;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.os.RemoteException;
28 import android.annotation.Nullable;
29 import android.util.Log;
30 
31 import com.android.internal.annotations.GuardedBy;
32 
33 import java.lang.ref.WeakReference;
34 
35 /**
36  * Services that need VMS publisher services need to inherit from this class and also need to be
37  * declared in the array vmsPublisherClients located in
38  * packages/services/Car/service/res/values/config.xml (most likely, this file will be in an overlay
39  * of the target product.
40  *
41  * The {@link com.android.car.VmsPublisherService} will start this service. The callback
42  * {@link #onVmsPublisherServiceReady()} notifies when VMS publisher services can be used, and the
43  * publisher can request a publisher ID in order to start publishing.
44  *
45  * SystemApi candidate.
46  *
47  * @hide
48  */
49 @SystemApi
50 public abstract class VmsPublisherClientService extends Service {
51     private static final boolean DBG = true;
52     private static final String TAG = "VmsPublisherClient";
53 
54     private final Object mLock = new Object();
55 
56     private Handler mHandler = new VmsEventHandler(this);
57     private final VmsPublisherClientBinder mVmsPublisherClient = new VmsPublisherClientBinder(this);
58     private volatile IVmsPublisherService mVmsPublisherService = null;
59     @GuardedBy("mLock")
60     private IBinder mToken = null;
61 
62     @Override
onBind(Intent intent)63     public IBinder onBind(Intent intent) {
64         if (DBG) {
65             Log.d(TAG, "onBind, intent: " + intent);
66         }
67         return mVmsPublisherClient.asBinder();
68     }
69 
70     @Override
onUnbind(Intent intent)71     public boolean onUnbind(Intent intent) {
72         if (DBG) {
73             Log.d(TAG, "onUnbind, intent: " + intent);
74         }
75         stopSelf();
76         return super.onUnbind(intent);
77     }
78 
setToken(IBinder token)79     private void setToken(IBinder token) {
80         synchronized (mLock) {
81             mToken = token;
82         }
83     }
84 
85     /**
86      * Notifies that the publisher services are ready.
87      */
onVmsPublisherServiceReady()88     protected abstract void onVmsPublisherServiceReady();
89 
90     /**
91      * Publishers need to implement this method to receive notifications of subscription changes.
92      *
93      * @param subscriptionState the state of the subscriptions.
94      */
onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)95     public abstract void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState);
96 
97     /**
98      * Uses the VmsPublisherService binder to publish messages.
99      *
100      * @param layer   the layer to publish to.
101      * @param payload the message to be sent.
102      * @param publisherId the ID that got assigned to the publisher that published the message by
103      *                    VMS core.
104      * @return if the call to the method VmsPublisherService.publish was successful.
105      */
publish(VmsLayer layer, int publisherId, byte[] payload)106     public final void publish(VmsLayer layer, int publisherId, byte[] payload) {
107         if (DBG) {
108             Log.d(TAG, "Publishing for layer : " + layer);
109         }
110 
111         IBinder token = getTokenForPublisherServiceThreadSafe();
112 
113         try {
114             mVmsPublisherService.publish(token, layer, publisherId, payload);
115         } catch (RemoteException e) {
116             Log.e(TAG, "unable to publish message: " + payload, e);
117         }
118     }
119 
120     /**
121      * Uses the VmsPublisherService binder to set the layers offering.
122      *
123      * @param offering the layers that the publisher may publish.
124      * @return if the call to VmsPublisherService.setLayersOffering was successful.
125      */
setLayersOffering(VmsLayersOffering offering)126     public final void setLayersOffering(VmsLayersOffering offering) {
127         if (DBG) {
128             Log.d(TAG, "Setting layers offering : " + offering);
129         }
130 
131         IBinder token = getTokenForPublisherServiceThreadSafe();
132 
133         try {
134             mVmsPublisherService.setLayersOffering(token, offering);
135             VmsOperationRecorder.get().setLayersOffering(offering);
136         } catch (RemoteException e) {
137             Log.e(TAG, "unable to set layers offering: " + offering, e);
138         }
139     }
140 
getTokenForPublisherServiceThreadSafe()141     private IBinder getTokenForPublisherServiceThreadSafe() {
142         if (mVmsPublisherService == null) {
143             throw new IllegalStateException("VmsPublisherService not set.");
144         }
145 
146         IBinder token;
147         synchronized (mLock) {
148             token = mToken;
149         }
150         if (token == null) {
151             throw new IllegalStateException("VmsPublisherService does not have a valid token.");
152         }
153         return token;
154     }
155 
getPublisherId(byte[] publisherInfo)156     public final int getPublisherId(byte[] publisherInfo) {
157         if (mVmsPublisherService == null) {
158             throw new IllegalStateException("VmsPublisherService not set.");
159         }
160         Integer publisherId = null;
161         try {
162             Log.i(TAG, "Getting publisher static ID");
163             publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
164         } catch (RemoteException e) {
165             Log.e(TAG, "unable to invoke binder method.", e);
166         }
167         if (publisherId == null) {
168             throw new IllegalStateException("VmsPublisherService cannot get a publisher static ID.");
169         } else {
170             VmsOperationRecorder.get().getPublisherId(publisherId);
171         }
172         return publisherId;
173     }
174 
175     /**
176      * Uses the VmsPublisherService binder to get the state of the subscriptions.
177      *
178      * @return list of layer/version or null in case of error.
179      */
getSubscriptions()180     public final @Nullable VmsSubscriptionState getSubscriptions() {
181         if (mVmsPublisherService == null) {
182             throw new IllegalStateException("VmsPublisherService not set.");
183         }
184         try {
185             return mVmsPublisherService.getSubscriptions();
186         } catch (RemoteException e) {
187             Log.e(TAG, "unable to invoke binder method.", e);
188         }
189         return null;
190     }
191 
setVmsPublisherService(IVmsPublisherService service)192     private void setVmsPublisherService(IVmsPublisherService service) {
193         mVmsPublisherService = service;
194         onVmsPublisherServiceReady();
195     }
196 
197     /**
198      * Implements the interface that the VMS service uses to communicate with this client.
199      */
200     private static class VmsPublisherClientBinder extends IVmsPublisherClient.Stub {
201         private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
202         @GuardedBy("mSequenceLock")
203         private long mSequence = -1;
204         private final Object mSequenceLock = new Object();
205 
VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService)206         public VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
207             mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
208         }
209 
210         @Override
setVmsPublisherService(IBinder token, IVmsPublisherService service)211         public void setVmsPublisherService(IBinder token, IVmsPublisherService service)
212                 throws RemoteException {
213             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
214             if (vmsPublisherClientService == null) return;
215             if (DBG) {
216                 Log.d(TAG, "setting VmsPublisherService.");
217             }
218             Handler handler = vmsPublisherClientService.mHandler;
219             handler.sendMessage(
220                     handler.obtainMessage(VmsEventHandler.SET_SERVICE_CALLBACK, service));
221             vmsPublisherClientService.setToken(token);
222         }
223 
224         @Override
onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)225         public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)
226                 throws RemoteException {
227             VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
228             if (vmsPublisherClientService == null) return;
229             if (DBG) {
230                 Log.d(TAG, "subscription event: " + subscriptionState);
231             }
232             synchronized (mSequenceLock) {
233                 if (subscriptionState.getSequenceNumber() <= mSequence) {
234                     Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
235                             + "; expected new sequence = " + subscriptionState.getSequenceNumber());
236                     // Do not propagate old notifications.
237                     return;
238                 } else {
239                     mSequence = subscriptionState.getSequenceNumber();
240                 }
241             }
242             Handler handler = vmsPublisherClientService.mHandler;
243             handler.sendMessage(
244                     handler.obtainMessage(VmsEventHandler.ON_SUBSCRIPTION_CHANGE_EVENT,
245                             subscriptionState));
246         }
247     }
248 
249     /**
250      * Receives events from the binder thread and dispatches them.
251      */
252     private final static class VmsEventHandler extends Handler {
253         /** Constants handled in the handler */
254         private static final int ON_SUBSCRIPTION_CHANGE_EVENT = 0;
255         private static final int SET_SERVICE_CALLBACK = 1;
256 
257         private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
258 
VmsEventHandler(VmsPublisherClientService service)259         VmsEventHandler(VmsPublisherClientService service) {
260             super(Looper.getMainLooper());
261             mVmsPublisherClientService = new WeakReference<>(service);
262         }
263 
264         @Override
handleMessage(Message msg)265         public void handleMessage(Message msg) {
266             VmsPublisherClientService service = mVmsPublisherClientService.get();
267             if (service == null) return;
268             switch (msg.what) {
269                 case ON_SUBSCRIPTION_CHANGE_EVENT:
270                     VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
271                     service.onVmsSubscriptionChange(subscriptionState);
272                     break;
273                 case SET_SERVICE_CALLBACK:
274                     service.setVmsPublisherService((IVmsPublisherService) msg.obj);
275                     break;
276                 default:
277                     Log.e(TAG, "Event type not handled:  " + msg.what);
278                     break;
279             }
280         }
281     }
282 }
283