Home | History | Annotate | Download | only in vms
      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
     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
     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 
     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      */
     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      */
     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      */
    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      */
    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 
    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 
    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      */
    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 
    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 
    206         public VmsPublisherClientBinder(VmsPublisherClientService vmsPublisherClientService) {
    207             mVmsPublisherClientService = new WeakReference<>(vmsPublisherClientService);
    208         }
    209 
    210         @Override
    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
    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 
    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:
    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