blob: bdd25109ea42683156e84f58ca7144606daee3c3 [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
Justin Paupore0dd31772019-02-07 21:22:34 -080020import android.annotation.Nullable;
Asaf Rosenfeld39e4f032017-09-16 11:33:50 -070021import android.annotation.SystemApi;
Antonio Cortes9db04df2017-02-07 08:38:05 -080022import android.app.Service;
Antonio Cortes9db04df2017-02-07 08:38:05 -080023import android.content.Intent;
24import android.os.Handler;
25import android.os.IBinder;
26import android.os.Looper;
27import android.os.Message;
28import android.os.RemoteException;
29import 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 */
Asaf Rosenfeld39e4f032017-09-16 11:33:50 -070049@SystemApi
Antonio Cortes9db04df2017-02-07 08:38:05 -080050public 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
Asaf Rosenfeldc2faf152018-01-31 13:59:06 -080063 public IBinder onBind(Intent intent) {
Antonio Cortes9db04df2017-02-07 08:38:05 -080064 if (DBG) {
65 Log.d(TAG, "onBind, intent: " + intent);
66 }
67 return mVmsPublisherClient.asBinder();
68 }
69
70 @Override
Asaf Rosenfeldc2faf152018-01-31 13:59:06 -080071 public boolean onUnbind(Intent intent) {
Antonio Cortes9db04df2017-02-07 08:38:05 -080072 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) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800116 throw e.rethrowFromSystemServer();
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700117 }
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) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800137 throw e.rethrowFromSystemServer();
Asaf Rosenfeldeb541d42017-03-31 14:32:10 -0700138 }
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) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800165 throw e.rethrowFromSystemServer();
Asaf Rosenfeld60284892017-05-19 12:59:56 -0700166 }
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) {
Justin Paupore0dd31772019-02-07 21:22:34 -0800187 throw e.rethrowFromSystemServer();
Antonio Cortes9db04df2017-02-07 08:38:05 -0800188 }
Antonio Cortes9db04df2017-02-07 08:38:05 -0800189 }
190
191 private void setVmsPublisherService(IVmsPublisherService service) {
192 mVmsPublisherService = service;
193 onVmsPublisherServiceReady();
194 }
195
196 /**
197 * Implements the interface that the VMS service uses to communicate with this client.
198 */
199 private static class VmsPublisherClientBinder extends IVmsPublisherClient.Stub {
200 private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
Antonio Cortes9db963a2017-03-10 15:15:28 -0800201 @GuardedBy("mSequenceLock")
202 private long mSequence = -1;
203 private final Object mSequenceLock = new Object();
Antonio Cortes9db04df2017-02-07 08:38:05 -0800204
205 public VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
206 mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
207 }
208
209 @Override
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700210 public void setVmsPublisherService(IBinder token, IVmsPublisherService service)
211 throws RemoteException {
Antonio Cortes9db04df2017-02-07 08:38:05 -0800212 VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
213 if (vmsPublisherClientService == null) return;
214 if (DBG) {
215 Log.d(TAG, "setting VmsPublisherService.");
216 }
217 Handler handler = vmsPublisherClientService.mHandler;
218 handler.sendMessage(
219 handler.obtainMessage(VmsEventHandler.SET_SERVICE_CALLBACK, service));
Asaf Rosenfeld7bd684e2017-03-13 16:24:27 -0700220 vmsPublisherClientService.setToken(token);
Antonio Cortes9db04df2017-02-07 08:38:05 -0800221 }
222
223 @Override
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700224 public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState)
Antonio Cortes9db04df2017-02-07 08:38:05 -0800225 throws RemoteException {
226 VmsPublisherClientService vmsPublisherClientService = mVmsPublisherClientService.get();
227 if (vmsPublisherClientService == null) return;
228 if (DBG) {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700229 Log.d(TAG, "subscription event: " + subscriptionState);
Antonio Cortes9db963a2017-03-10 15:15:28 -0800230 }
231 synchronized (mSequenceLock) {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700232 if (subscriptionState.getSequenceNumber() <= mSequence) {
Antonio Cortes9db963a2017-03-10 15:15:28 -0800233 Log.w(TAG, "Sequence out of order. Current sequence = " + mSequence
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700234 + "; expected new sequence = " + subscriptionState.getSequenceNumber());
Antonio Cortes9db963a2017-03-10 15:15:28 -0800235 // Do not propagate old notifications.
236 return;
237 } else {
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700238 mSequence = subscriptionState.getSequenceNumber();
Antonio Cortes9db963a2017-03-10 15:15:28 -0800239 }
Antonio Cortes9db04df2017-02-07 08:38:05 -0800240 }
241 Handler handler = vmsPublisherClientService.mHandler;
242 handler.sendMessage(
243 handler.obtainMessage(VmsEventHandler.ON_SUBSCRIPTION_CHANGE_EVENT,
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700244 subscriptionState));
Antonio Cortes9db04df2017-02-07 08:38:05 -0800245 }
246 }
247
248 /**
249 * Receives events from the binder thread and dispatches them.
250 */
251 private final static class VmsEventHandler extends Handler {
252 /** Constants handled in the handler */
253 private static final int ON_SUBSCRIPTION_CHANGE_EVENT = 0;
254 private static final int SET_SERVICE_CALLBACK = 1;
255
256 private final WeakReference<VmsPublisherClientService> mVmsPublisherClientService;
257
258 VmsEventHandler(VmsPublisherClientService service) {
259 super(Looper.getMainLooper());
260 mVmsPublisherClientService = new WeakReference<>(service);
261 }
262
263 @Override
264 public void handleMessage(Message msg) {
265 VmsPublisherClientService service = mVmsPublisherClientService.get();
266 if (service == null) return;
267 switch (msg.what) {
268 case ON_SUBSCRIPTION_CHANGE_EVENT:
Antonio Cortes2febe9f2017-03-24 09:42:17 -0700269 VmsSubscriptionState subscriptionState = (VmsSubscriptionState) msg.obj;
270 service.onVmsSubscriptionChange(subscriptionState);
Antonio Cortes9db04df2017-02-07 08:38:05 -0800271 break;
272 case SET_SERVICE_CALLBACK:
273 service.setVmsPublisherService((IVmsPublisherService) msg.obj);
274 break;
275 default:
276 Log.e(TAG, "Event type not handled: " + msg.what);
277 break;
278 }
279 }
280 }
Antonio Cortes9db04df2017-02-07 08:38:05 -0800281}