aboutsummaryrefslogtreecommitdiff
path: root/service/src/com/android/car/VmsPublisherService.java
diff options
context:
space:
mode:
authorAntonio Cortes <antoniocortes@google.com>2017-02-06 16:54:58 -0800
committerAntonio Cortes <antoniocortes@google.com>2017-02-13 16:21:20 -0800
commit6b3544cf13ee99d6704216c96d40f89aff9bdc2b (patch)
tree2cea1ac8f8dff3f3b1091c8b194efca5949a16d5 /service/src/com/android/car/VmsPublisherService.java
parent8addba1fa1741f87f08e5568ae68caf347bc197a (diff)
downloadCar-6b3544cf13ee99d6704216c96d40f89aff9bdc2b.tar.gz
VMS skeleton code: VmsPublisherService
Implementing VMS publisher interfaces and service. The service (VmsPublisherService) starts/binds to clients (IVmsPublisherClient) and provides them with an interface (IVmsPublisherService) to publish data. The next change will include the VmsPublisherClientService which is the main interface for clients and the test. This is a post-O feature. Bug: b/34976096 Test: Flashed a Mojave board and verified there was no Car service crashes. Change-Id: I360e78e4849b4e9d36855153a808ca5aef2630c5
Diffstat (limited to 'service/src/com/android/car/VmsPublisherService.java')
-rw-r--r--service/src/com/android/car/VmsPublisherService.java244
1 files changed, 244 insertions, 0 deletions
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
new file mode 100644
index 0000000000..94476767f7
--- /dev/null
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car;
+
+import android.car.annotation.FutureFeature;
+import android.car.vms.IVmsPublisherClient;
+import android.car.vms.IVmsPublisherService;
+import android.car.vms.VmsProperty;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.car.hal.VmsHalService;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * + Receives HAL updates by implementing VmsHalService.VmsHalListener.
+ * + Binds to publishers and configures them to use this service.
+ * + Notifies publishers of subscription changes.
+ */
+@FutureFeature
+public class VmsPublisherService extends IVmsPublisherService.Stub
+ implements CarServiceBase, VmsHalService.VmsHalListener {
+ private static final boolean DBG = true;
+ private static final String TAG = "VmsPublisherService";
+
+ private final Context mContext;
+ private final VmsHalService mHal;
+ private final VmsPublisherManager mPublisherManager;
+
+ public VmsPublisherService(Context context, VmsHalService hal) {
+ mContext = context;
+ mHal = hal;
+ mPublisherManager = new VmsPublisherManager(this);
+ }
+
+ // Implements CarServiceBase interface.
+ @Override
+ public void init() {
+ mHal.addListener(this);
+ // Launch publishers.
+ String[] publisherNames = mContext.getResources().getStringArray(
+ R.array.vmsPublisherClients);
+ for (String publisherName : publisherNames) {
+ if (TextUtils.isEmpty(publisherName)) {
+ Log.e(TAG, "empty publisher name");
+ continue;
+ }
+ ComponentName name = ComponentName.unflattenFromString(publisherName);
+ if (name == null) {
+ Log.e(TAG, "invalid publisher name: " + publisherName);
+ }
+ mPublisherManager.bind(name);
+ }
+ }
+
+ @Override
+ public void release() {
+ mPublisherManager.release();
+ mHal.removeListener(this);
+ }
+
+ @Override
+ public void dump(PrintWriter writer) {
+ }
+
+ // Implements IVmsPublisherService interface.
+ @Override
+ public void publish(int layer, int version, VmsProperty value) {
+ ICarImpl.assertVmsPublisherPermission(mContext);
+ // TODO(antoniocortes): update to latest VmsProperty structure.
+ mHal.setProperty(value);
+ }
+
+ @Override
+ public boolean hasSubscribers(int layer, int version) {
+ ICarImpl.assertVmsPublisherPermission(mContext);
+ // TODO(antoniocortes): implement this logic.
+ return true;
+ }
+
+ // Implements VmsHalListener interface
+ @Override
+ public void onChange(VmsProperty message) {
+ // TODO(antoniocortes): notify publishers if this message causes a subscription change.
+ }
+
+ /**
+ * Keeps track of publishers that are using this service.
+ */
+ private static class VmsPublisherManager {
+ /**
+ * Allows to modify mPublisherMap and mPublisherConnectionMap as a single unit.
+ */
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<String, PublisherConnection> mPublisherConnectionMap = new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<String, IVmsPublisherClient> mPublisherMap = new HashMap<>();
+ private final WeakReference<VmsPublisherService> mPublisherService;
+
+ public VmsPublisherManager(VmsPublisherService publisherService) {
+ mPublisherService = new WeakReference<>(publisherService);
+ }
+
+ /**
+ * Tries to bind to a publisher.
+ *
+ * @param name publisher component name (e.g. android.car.vms.logger/.LoggingService).
+ */
+ public void bind(ComponentName name) {
+ VmsPublisherService publisherService = mPublisherService.get();
+ if (publisherService == null) return;
+ String publisherName = name.flattenToString();
+ if (DBG) {
+ Log.d(TAG, "binding to: " + publisherName);
+ }
+ synchronized (mLock) {
+ if (mPublisherConnectionMap.containsKey(publisherName)) {
+ // Already registered, nothing to do.
+ return;
+ }
+ Intent intent = new Intent();
+ intent.setComponent(name);
+ // Explicitly start service as we do not use BIND_AUTO_CREATE flag to handle crash.
+ publisherService.mContext.startService(intent);
+ PublisherConnection connection = new PublisherConnection();
+ if (publisherService.mContext.bindService(intent, connection,
+ Context.BIND_IMPORTANT)) {
+ mPublisherConnectionMap.put(publisherName, connection);
+ } else {
+ Log.e(TAG, "unable to bind to: " + publisherName);
+ }
+ }
+ }
+
+ /**
+ * Removes the publisher and associated connection.
+ *
+ * @param name publisher component name (e.g. android.car.vms.Logger).
+ */
+ public void unbind(ComponentName name) {
+ VmsPublisherService publisherService = mPublisherService.get();
+ if (publisherService == null) return;
+ String publisherName = name.flattenToString();
+ if (DBG) {
+ Log.d(TAG, "unbinding from: " + publisherName);
+ }
+ synchronized (mLock) {
+ boolean found = mPublisherMap.remove(publisherName) != null;
+ if (found) {
+ PublisherConnection connection = mPublisherConnectionMap.get(publisherName);
+ publisherService.mContext.unbindService(connection);
+ mPublisherConnectionMap.remove(publisherName);
+ } else {
+ Log.e(TAG, "unbind: unknown publisher." + publisherName);
+ }
+ }
+ }
+
+ /**
+ * Returns the list of publishers currently registered.
+ *
+ * @return list of publishers.
+ */
+ public List<IVmsPublisherClient> getClients() {
+ synchronized (mLock) {
+ return new ArrayList<>(mPublisherMap.values());
+ }
+ }
+
+ public void release() {
+ VmsPublisherService publisherService = mPublisherService.get();
+ if (publisherService == null) return;
+ for (PublisherConnection connection : mPublisherConnectionMap.values()) {
+ publisherService.mContext.unbindService(connection);
+ }
+ mPublisherConnectionMap.clear();
+ mPublisherMap.clear();
+ }
+
+ class PublisherConnection implements ServiceConnection {
+ /**
+ * Once the service binds to a publisher service, the publisher binder is added to
+ * mPublisherMap
+ * and the publisher is configured to use this service.
+ */
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ VmsPublisherService publisherService = mPublisherService.get();
+ if (publisherService == null) return;
+ if (DBG) {
+ Log.d(TAG, "onServiceConnected, name: " + name + ", binder: " + binder);
+ }
+ IVmsPublisherClient service = IVmsPublisherClient.Stub.asInterface(binder);
+ synchronized (mLock) {
+ mPublisherMap.put(name.flattenToString(), service);
+ }
+ try {
+ service.setVmsPublisherService(publisherService);
+ } catch (RemoteException e) {
+ Log.e(TAG, "unable to configure publisher: " + name);
+ }
+ }
+
+ /**
+ * Tries to rebind to the publisher service.
+ */
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ String publisherName = name.flattenToString();
+ Log.d(TAG, "onServiceDisconnected, name: " + publisherName);
+ VmsPublisherManager.this.unbind(name);
+ VmsPublisherManager.this.bind(name);
+ }
+ }
+ }
+}