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