blob: 33ca1f3037a78f9e05000905a715012c863c04de [file] [log] [blame]
Antonio Cortes9db04df2017-02-07 08:38:05 -08001/*
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
17package android.car.vms;
18
19
20import android.app.Service;
21import android.car.annotation.FutureFeature;
22import android.content.Intent;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Looper;
26import android.os.Message;
27import android.os.RemoteException;
Antonio Cortes9db963a2017-03-10 15:15:28 -080028import android.annotation.Nullable;
Antonio Cortes9db04df2017-02-07 08:38:05 -080029import android.util.Log;
30
Antonio Cortes9db963a2017-03-10 15:15:28 -080031import com.android.internal.annotations.GuardedBy;
32
Antonio Cortes9db04df2017-02-07 08:38:05 -080033import 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
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -070042 * {@link #onVmsPublisherServiceReady()} notifies when VMS publisher services can be used, and the
43 * publisher can request a publisher ID in order to start publishing.
Antonio Cortes9db04df2017-02-07 08:38:05 -080044 *
45 * SystemApi candidate.
46 *
47 * @hide
48 */
49@FutureFeature
50public abstract class VmsPublisherClientService extends Service {
51 private static final boolean DBG = true;
52 private static final String TAG = "VmsPublisherClient";
53
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -070054 private final Object mLock = new Object();
55
Antonio Cortes9db04df2017-02-07 08:38:05 -080056 private Handler mHandler = new VmsEventHandler(this);
57 private final VmsPublisherClientBinder mVmsPublisherClient = new VmsPublisherClientBinder(this);
58 private volatile IVmsPublisherService mVmsPublisherService = null;
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -070059 @GuardedBy("mLock")
Asaf Rosenfelde8369b62017-03-17 14:11:56 -070060 private IBinder mToken = null;
Antonio Cortes9db04df2017-02-07 08:38:05 -080061
62 @Override
63 public final IBinder onBind(Intent intent) {
64 if (DBG) {
65 Log.d(TAG, "onBind, intent: " + intent);
66 }
67 return mVmsPublisherClient.asBinder();
68 }
69
70 @Override
71 public final boolean onUnbind(Intent intent) {
72 if (DBG) {
73 Log.d(TAG, "onUnbind, intent: " + intent);
74 }
75 stopSelf();
76 return super.onUnbind(intent);
77 }
78
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -070079 private void setToken(IBinder token) {
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -070080 synchronized (mLock) {
81 mToken = token;
82 }
83 }
84
Antonio Cortes9db04df2017-02-07 08:38:05 -080085 /**
86 * Notifies that the publisher services are ready.
87 */
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -070088 protected abstract void onVmsPublisherServiceReady();
Antonio Cortes9db04df2017-02-07 08:38:05 -080089
90 /**
91 * Publishers need to implement this method to receive notifications of subscription changes.
Antonio Cortes9db04df2017-02-07 08:38:05 -080092 *
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -070093 * @param subscriptionState the state of the subscriptions.
Antonio Cortes9db04df2017-02-07 08:38:05 -080094 */
Antonio Cortes2febe9f2017-03-24 09:42:17 -070095 public abstract void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState);
Antonio Cortes9db04df2017-02-07 08:38:05 -080096
97 /**
98 * Uses the VmsPublisherService binder to publish messages.
99 *
Antonio Cortes01a60392017-03-22 13:00:02 -0700100 * @param layer the layer to publish to.
Antonio Cortes9db04df2017-02-07 08:38:05 -0800101 * @param payload the message to be sent.
Asaf Rosenfeld800cb072017-07-18 10:56:11 -0700102 * @param publisherId the ID that got assigned to the publisher that published the message by
103 * VMS core.
Antonio Cortes9db04df2017-02-07 08:38:05 -0800104 * @return if the call to the method VmsPublisherService.publish was successful.
105 */
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700106 public final void publish(VmsLayer layer, int publisherId, byte[] payload) {
asafro25a87402017-02-28 16:08:17 -0800107 if (DBG) {
Antonio Cortes01a60392017-03-22 13:00:02 -0700108 Log.d(TAG, "Publishing for layer : " + layer);
asafro25a87402017-02-28 16:08:17 -0800109 }
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700110
111 IBinder token = getTokenForPublisherServiceThreadSafe();
112
113 try {
Asaf Rosenfeld800cb072017-07-18 10:56:11 -0700114 mVmsPublisherService.publish(token, layer, publisherId, payload);
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700115 } catch (RemoteException e) {
116 Log.e(TAG, "unable to publish message: " + payload, e);
117 }
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700118 }
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 */
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700126 public final void setLayersOffering(VmsLayersOffering offering) {
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700127 if (DBG) {
128 Log.d(TAG, "Setting layers offering : " + offering);
129 }
130
131 IBinder token = getTokenForPublisherServiceThreadSafe();
132
133 try {
134 mVmsPublisherService.setLayersOffering(token, offering);
Demyn Plantenberg3ca12892017-06-20 21:01:34 -0700135 VmsOperationRecorder.get().setLayersOffering(offering);
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700136 } catch (RemoteException e) {
137 Log.e(TAG, "unable to set layers offering: " + offering, e);
138 }
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700139 }
140
141 private IBinder getTokenForPublisherServiceThreadSafe() {
Antonio Cortes9db04df2017-02-07 08:38:05 -0800142 if (mVmsPublisherService == null) {
143 throw new IllegalStateException("VmsPublisherService not set.");
144 }
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700145
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 }
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700153 return token;
Antonio Cortes9db04df2017-02-07 08:38:05 -0800154 }
155
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700156 public final int getPublisherId(byte[] publisherInfo) {
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700157 if (mVmsPublisherService == null) {
158 throw new IllegalStateException("VmsPublisherService not set.");
159 }
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700160 Integer publisherId = null;
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700161 try {
162 Log.i(TAG, "Getting publisher static ID");
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700163 publisherId = mVmsPublisherService.getPublisherId(publisherInfo);
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700164 } catch (RemoteException e) {
165 Log.e(TAG, "unable to invoke binder method.", e);
166 }
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700167 if (publisherId == null) {
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700168 throw new IllegalStateException("VmsPublisherService cannot get a publisher static ID.");
Demyn Plantenberg3ca12892017-06-20 21:01:34 -0700169 } else {
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700170 VmsOperationRecorder.get().getPublisherId(publisherId);
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700171 }
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700172 return publisherId;
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700173 }
174
Antonio Cortes9db04df2017-02-07 08:38:05 -0800175 /**
Asaf Rosenfeld2e45d812017-08-31 23:51:12 -0700176 * Uses the VmsPublisherService binder to get the state of the subscriptions.
Antonio Cortes9db04df2017-02-07 08:38:05 -0800177 *
Antonio Cortes9db963a2017-03-10 15:15:28 -0800178 * @return list of layer/version or null in case of error.
Antonio Cortes9db04df2017-02-07 08:38:05 -0800179 */
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700180 public final @Nullable VmsSubscriptionState getSubscriptions() {
Antonio Cortes9db04df2017-02-07 08:38:05 -0800181 if (mVmsPublisherService == null) {
182 throw new IllegalStateException("VmsPublisherService not set.");
183 }
184 try {
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700185 return mVmsPublisherService.getSubscriptions();
Antonio Cortes9db04df2017-02-07 08:38:05 -0800186 } catch (RemoteException e) {
187 Log.e(TAG, "unable to invoke binder method.", e);
188 }
Antonio Cortes9db963a2017-03-10 15:15:28 -0800189 return null;
Antonio Cortes9db04df2017-02-07 08:38:05 -0800190 }
191
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;
Antonio Cortes9db963a2017-03-10 15:15:28 -0800202 @GuardedBy("mSequenceLock")
203 private long mSequence = -1;
204 private final Object mSequenceLock = new Object();
Antonio Cortes9db04df2017-02-07 08:38:05 -0800205
206 public VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
207 mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
208 }
209
210 @Override
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700211 public void setVmsPublisherService(IBinder token, IVmsPublisherService service)
212 throws RemoteException {
Antonio Cortes9db04df2017-02-07 08:38:05 -0800213 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));
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700221 vmsPublisherClientService.setToken(token);
Antonio Cortes9db04df2017-02-07 08:38:05 -0800222 }
223
224 @Override
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700225 public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)
Antonio Cortes9db04df2017-02-07 08:38:05 -0800226 throws RemoteException {
227 VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
228 if (vmsPublisherClientService == null) return;
229 if (DBG) {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700230 Log.d(TAG, "subscription event: " + subscriptionState);
Antonio Cortes9db963a2017-03-10 15:15:28 -0800231 }
232 synchronized (mSequenceLock) {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700233 if (subscriptionState.getSequenceNumber() <= mSequence) {
Antonio Cortes9db963a2017-03-10 15:15:28 -0800234 Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700235 + "; expected new sequence = " + subscriptionState.getSequenceNumber());
Antonio Cortes9db963a2017-03-10 15:15:28 -0800236 // Do not propagate old notifications.
237 return;
238 } else {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700239 mSequence = subscriptionState.getSequenceNumber();
Antonio Cortes9db963a2017-03-10 15:15:28 -0800240 }
Antonio Cortes9db04df2017-02-07 08:38:05 -0800241 }
242 Handler handler = vmsPublisherClientService.mHandler;
243 handler.sendMessage(
244 handler.obtainMessage(VmsEventHandler.ON_SUBSCRIPTION_CHANGE_EVENT,
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700245 subscriptionState));
Antonio Cortes9db04df2017-02-07 08:38:05 -0800246 }
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
259 VmsEventHandler(VmsPublisherClientService service) {
260 super(Looper.getMainLooper());
261 mVmsPublisherClientService = new WeakReference<>(service);
262 }
263
264 @Override
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:
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700270 VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
271 service.onVmsSubscriptionChange(subscriptionState);
Antonio Cortes9db04df2017-02-07 08:38:05 -0800272 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 }
Antonio Cortes9db04df2017-02-07 08:38:05 -0800282}