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.Nullable;
22 import android.annotation.SystemApi;
23 import android.app.Service;
24 import android.car.Car;
25 import android.car.annotation.RequiredFeature;
26 import android.car.vms.VmsClientManager.VmsClientCallback;
27 import android.content.Intent;
28 import android.os.Binder;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.util.Log;
33 import android.util.Slog;
34 
35 import com.android.car.internal.os.HandlerExecutor;
36 import com.android.internal.annotations.GuardedBy;
37 import com.android.internal.annotations.VisibleForTesting;
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  * @deprecated Use {@link VmsClientManager} instead
53  * @hide
54  */
55 @RequiredFeature(Car.VEHICLE_MAP_SERVICE)
56 @Deprecated
57 @SystemApi
58 public abstract class VmsPublisherClientService extends Service {
59     private static final String TAG = "VmsPublisherClientSvc";
60 
61     private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
62 
63 
64     private final Handler mHandler = new Handler(Looper.getMainLooper());
65     private final VmsClientCallback mClientCallback = new PublisherClientCallback();
66 
67     private final Object mLock = new Object();
68     @GuardedBy("mLock")
69     private @Nullable Car mCar;
70     @GuardedBy("mLock")
71     private @Nullable VmsClient mClient;
72 
73     @Override
onCreate()74     public void onCreate() {
75         if (DBG) Slog.d(TAG, "Connecting to Car service");
76         synchronized (mLock) {
77             mCar = Car.createCar(this, mHandler, Car.CAR_WAIT_TIMEOUT_DO_NOT_WAIT,
78                     this::onCarLifecycleChanged);
79         }
80     }
81 
82     @Override
onDestroy()83     public void onDestroy() {
84         if (DBG) Slog.d(TAG, "Disconnecting from Car service");
85         synchronized (mLock) {
86             if (mCar != null) {
87                 mCar.disconnect();
88                 mCar = null;
89             }
90         }
91     }
92 
93     @Override
onBind(Intent intent)94     public IBinder onBind(Intent intent) {
95         if (DBG) Slog.d(TAG, "onBind, intent: " + intent);
96         return new Binder();
97     }
98 
99     /**
100      * @hide
101      */
102     @VisibleForTesting
onCarLifecycleChanged(Car car, boolean ready)103     protected void onCarLifecycleChanged(Car car, boolean ready) {
104         if (DBG) Slog.d(TAG, "Car service ready: " + ready);
105         if (ready) {
106             VmsClientManager clientManager =
107                     (VmsClientManager) car.getCarManager(Car.VEHICLE_MAP_SERVICE);
108             if (DBG) Slog.d(TAG, "VmsClientManager: " + clientManager);
109             if (clientManager == null) {
110                 Slog.e(TAG, "VmsClientManager is not available");
111                 return;
112             }
113             clientManager.registerVmsClientCallback(new HandlerExecutor(mHandler), mClientCallback,
114                     /* legacyClient= */ true);
115         }
116     }
117 
118     /**
119      * Notifies the client that publisher services are ready.
120      */
onVmsPublisherServiceReady()121     protected abstract void onVmsPublisherServiceReady();
122 
123     /**
124      * Notifies the client of changes in layer subscriptions.
125      *
126      * @param subscriptionState state of layer subscriptions
127      */
onVmsSubscriptionChange(@onNull VmsSubscriptionState subscriptionState)128     public abstract void onVmsSubscriptionChange(@NonNull VmsSubscriptionState subscriptionState);
129 
130     /**
131      * Publishes a data packet to subscribers.
132      *
133      * Publishers must only publish packets for the layers that they have made offerings for.
134      *
135      * @param layer       layer to publish to
136      * @param publisherId ID of the publisher publishing the message
137      * @param payload     data packet to be sent
138      * @throws IllegalStateException if publisher services are not available
139      */
publish(@onNull VmsLayer layer, int publisherId, byte[] payload)140     public final void publish(@NonNull VmsLayer layer, int publisherId, byte[] payload) {
141         getVmsClient().publishPacket(publisherId, layer, payload);
142     }
143 
144     /**
145      * Sets the layers offered by a specific publisher.
146      *
147      * @param offering layers being offered for subscription by the publisher
148      * @throws IllegalStateException if publisher services are not available
149      */
setLayersOffering(@onNull VmsLayersOffering offering)150     public final void setLayersOffering(@NonNull VmsLayersOffering offering) {
151         getVmsClient().setProviderOfferings(offering.getPublisherId(), offering.getDependencies());
152     }
153 
154     /**
155      * Acquires a publisher ID for a serialized publisher description.
156      *
157      * Multiple calls to this method with the same information will return the same publisher ID.
158      *
159      * @param publisherInfo serialized publisher description information, in a vendor-specific
160      *                      format
161      * @return a publisher ID for the given publisher description
162      * @throws IllegalStateException if publisher services are not available
163      */
getPublisherId(byte[] publisherInfo)164     public final int getPublisherId(byte[] publisherInfo) {
165         return getVmsClient().registerProvider(publisherInfo);
166     }
167 
168     /**
169      * Gets the state of layer subscriptions.
170      *
171      * @return state of layer subscriptions
172      * @throws IllegalStateException if publisher services are not available
173      */
getSubscriptions()174     public final VmsSubscriptionState getSubscriptions() {
175         return getVmsClient().getSubscriptionState();
176     }
177 
getVmsClient()178     private VmsClient getVmsClient() {
179         synchronized (mLock) {
180             if (mClient == null) {
181                 throw new IllegalStateException("VMS client connection is not ready");
182             }
183             return mClient;
184         }
185     }
186 
187     private class PublisherClientCallback implements VmsClientCallback {
188         @Override
onClientConnected(VmsClient client)189         public void onClientConnected(VmsClient client) {
190             synchronized (mLock) {
191                 mClient = client;
192             }
193             onVmsPublisherServiceReady();
194         }
195 
196         @Override
onSubscriptionStateChanged(VmsSubscriptionState subscriptionState)197         public void onSubscriptionStateChanged(VmsSubscriptionState subscriptionState) {
198             onVmsSubscriptionChange(subscriptionState);
199         }
200 
201         @Override
onLayerAvailabilityChanged(VmsAvailableLayers availableLayers)202         public void onLayerAvailabilityChanged(VmsAvailableLayers availableLayers) {
203             // Ignored
204         }
205 
206         @Override
onPacketReceived(int providerId, VmsLayer layer, byte[] packet)207         public void onPacketReceived(int providerId, VmsLayer layer, byte[] packet) {
208             // Does not subscribe to packets
209         }
210     }
211 }
212