aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsaf Rosenfeld <asafro@google.com>2017-03-31 14:32:10 -0700
committerAsaf Rosenfeld <asafro@google.com>2017-04-05 14:46:53 -0700
commiteb541d4fae5171ca480069ff821581226df3ddb0 (patch)
tree9acf9c02636ca2fe6e4fb787358d478c4252836a
parentf50230d087f356300957af2317b4b0f4df6631e6 (diff)
downloadCar-eb541d4fae5171ca480069ff821581226df3ddb0.tar.gz
Adding availability HAL support
Test: Added tests that inject offering and check change in availability. Also verified the following pass: runtest -x ../tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java runtest -x ../tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java runtest -x ../tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java runtest -x ../tests/carservice_unit_test/src/com/android/car/VmsRoutingTest.java runtest -x ../tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java Change-Id: Ia641499a60e79a2c8665257d94e1050a070da18d
-rw-r--r--car-lib/src/android/car/vms/VmsLayer.java4
-rw-r--r--car-lib/src/android/car/vms/VmsLayerDependency.java4
-rw-r--r--car-lib/src/android/car/vms/VmsLayersOffering.java5
-rw-r--r--car-lib/src/android/car/vms/VmsPublisherClientService.java43
-rw-r--r--service/src/com/android/car/VmsLayersAvailability.java4
-rw-r--r--service/src/com/android/car/VmsPublisherService.java8
-rw-r--r--service/src/com/android/car/VmsRouting.java26
-rw-r--r--service/src/com/android/car/VmsSubscriberService.java25
-rw-r--r--service/src/com/android/car/hal/VmsHalService.java348
-rw-r--r--tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java17
-rw-r--r--tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java11
-rw-r--r--tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java33
-rw-r--r--tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java136
-rw-r--r--tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java10
14 files changed, 542 insertions, 132 deletions
diff --git a/car-lib/src/android/car/vms/VmsLayer.java b/car-lib/src/android/car/vms/VmsLayer.java
index 702daec9ef..afd0ae7835 100644
--- a/car-lib/src/android/car/vms/VmsLayer.java
+++ b/car-lib/src/android/car/vms/VmsLayer.java
@@ -24,8 +24,10 @@ import java.util.Objects;
/**
* A VMS Layer which can be subscribed to by VMS clients.
- * Consists of the layer ID and the layer version.
+ * Consists of the layer ID and the layer major version.
*
+ * This class does not contain the minor version since all minor version are backward and forward
+ * compatible and should not be used for routing messages.
* @hide
*/
@FutureFeature
diff --git a/car-lib/src/android/car/vms/VmsLayerDependency.java b/car-lib/src/android/car/vms/VmsLayerDependency.java
index bb588ebf7a..e14c7ecbc2 100644
--- a/car-lib/src/android/car/vms/VmsLayerDependency.java
+++ b/car-lib/src/android/car/vms/VmsLayerDependency.java
@@ -80,6 +80,10 @@ public final class VmsLayerDependency implements Parcelable {
}
};
+ public String toString() {
+ return "VmsLayerDependency{ Layer: " + mLayer + " Dependency: " + mDependency + "}";
+ }
+
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(mLayer, flags);
diff --git a/car-lib/src/android/car/vms/VmsLayersOffering.java b/car-lib/src/android/car/vms/VmsLayersOffering.java
index 12b3dd30b2..51a0b995be 100644
--- a/car-lib/src/android/car/vms/VmsLayersOffering.java
+++ b/car-lib/src/android/car/vms/VmsLayersOffering.java
@@ -55,6 +55,11 @@ public final class VmsLayersOffering implements Parcelable {
};
@Override
+ public String toString() {
+ return "VmsLayersOffering{" + mDependencies+ "}";
+ }
+
+ @Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelableList(mDependencies, flags);
}
diff --git a/car-lib/src/android/car/vms/VmsPublisherClientService.java b/car-lib/src/android/car/vms/VmsPublisherClientService.java
index 2743ff157b..85fd2c2b8d 100644
--- a/car-lib/src/android/car/vms/VmsPublisherClientService.java
+++ b/car-lib/src/android/car/vms/VmsPublisherClientService.java
@@ -106,6 +106,41 @@ public abstract class VmsPublisherClientService extends Service {
if (DBG) {
Log.d(TAG, "Publishing for layer : " + layer);
}
+
+ IBinder token = getTokenForPublisherServiceThreadSafe();
+
+ try {
+ mVmsPublisherService.publish(token, layer, payload);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "unable to publish message: " + payload, e);
+ }
+ return false;
+ }
+
+ /**
+ * Uses the VmsPublisherService binder to set the layers offering.
+ *
+ * @param offering the layers that the publisher may publish.
+ * @return if the call to VmsPublisherService.setLayersOffering was successful.
+ */
+ public final boolean setLayersOffering(VmsLayersOffering offering) {
+ if (DBG) {
+ Log.d(TAG, "Setting layers offering : " + offering);
+ }
+
+ IBinder token = getTokenForPublisherServiceThreadSafe();
+
+ try {
+ mVmsPublisherService.setLayersOffering(token, offering);
+ return true;
+ } catch (RemoteException e) {
+ Log.e(TAG, "unable to set layers offering: " + offering, e);
+ }
+ return false;
+ }
+
+ private IBinder getTokenForPublisherServiceThreadSafe() {
if (mVmsPublisherService == null) {
throw new IllegalStateException("VmsPublisherService not set.");
}
@@ -117,13 +152,7 @@ public abstract class VmsPublisherClientService extends Service {
if (token == null) {
throw new IllegalStateException("VmsPublisherService does not have a valid token.");
}
- try {
- mVmsPublisherService.publish(token, layer, payload);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "unable to publish message: " + payload, e);
- }
- return false;
+ return token;
}
/**
diff --git a/service/src/com/android/car/VmsLayersAvailability.java b/service/src/com/android/car/VmsLayersAvailability.java
index 5f5ac3085e..d6e89f2bc0 100644
--- a/service/src/com/android/car/VmsLayersAvailability.java
+++ b/service/src/com/android/car/VmsLayersAvailability.java
@@ -83,7 +83,7 @@ public class VmsLayersAvailability {
/**
* Returns a collection of all the layers which may be published.
*/
- public Collection<VmsLayer> getAvailableLayers() {
+ public Set<VmsLayer> getAvailableLayers() {
synchronized (mLock) {
return mAvailableLayers;
}
@@ -93,7 +93,7 @@ public class VmsLayersAvailability {
* Returns a collection of all the layers which publishers could have published if the
* dependencies were satisfied.
*/
- public Collection<VmsLayer> getUnavailableLayers() {
+ public Set<VmsLayer> getUnavailableLayers() {
synchronized (mLock) {
return mUnavailableLayers;
}
diff --git a/service/src/com/android/car/VmsPublisherService.java b/service/src/com/android/car/VmsPublisherService.java
index 8f7fba353b..8bb0167d8d 100644
--- a/service/src/com/android/car/VmsPublisherService.java
+++ b/service/src/com/android/car/VmsPublisherService.java
@@ -56,7 +56,6 @@ public class VmsPublisherService extends IVmsPublisherService.Stub
private final Context mContext;
private final VmsHalService mHal;
private final VmsPublisherManager mPublisherManager;
- private final Map<IBinder, VmsLayersOffering> mRawOffering = new HashMap<>();
public VmsPublisherService(Context context, VmsHalService hal) {
mContext = context;
@@ -96,12 +95,7 @@ public class VmsPublisherService extends IVmsPublisherService.Stub
@Override
public void setLayersOffering(IBinder token, VmsLayersOffering offering) {
- // Store the raw dependencies
- mRawOffering.put(token, offering);
-
- //TODO(asafro): Calculate the new available layers
-
- //TODO(asafro): Notify the subscribers that there is a change in availability
+ mHal.setPublisherLayersOffering(token, offering);
}
// Implements IVmsPublisherService interface.
diff --git a/service/src/com/android/car/VmsRouting.java b/service/src/com/android/car/VmsRouting.java
index fc2cbaca7b..2829cc0623 100644
--- a/service/src/com/android/car/VmsRouting.java
+++ b/service/src/com/android/car/VmsRouting.java
@@ -20,16 +20,14 @@ import android.car.annotation.FutureFeature;
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.VmsLayer;
import android.car.vms.VmsSubscriptionState;
-
+import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import com.android.internal.annotations.GuardedBy;
-
/**
* Manages all the VMS subscriptions:
* + Subscriptions to data messages of individual layer + version.
@@ -62,6 +60,7 @@ public class VmsRouting {
* @param layer the layer subscribing to.
*/
public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
+ //TODO(b/36902947): revise if need to sync, and return value.
synchronized (mLock) {
++mSequenceNumber;
// Get or create the list of listeners for layer and version.
@@ -142,8 +141,8 @@ public class VmsRouting {
}
/**
- * Returns all the listeners for a layer and version. This include the subscribers which
- * explicitly subscribed to this layer and version and the promiscuous subscribers.
+ * Returns a list with all the listeners for a layer and version. This include the subscribers
+ * which explicitly subscribed to this layer and version and the promiscuous subscribers.
*
* @param layer to get listeners to.
* @return a list of the listeners.
@@ -162,6 +161,21 @@ public class VmsRouting {
}
/**
+ * Returns a list with all the listeners.
+ */
+ public Set<IVmsSubscriberClient> getAllListeners() {
+ Set<IVmsSubscriberClient> listeners = new HashSet<>();
+ synchronized (mLock) {
+ for (VmsLayer layer : mLayerSubscriptions.keySet()) {
+ listeners.addAll(mLayerSubscriptions.get(layer));
+ }
+ // Add the promiscuous subscribers.
+ listeners.addAll(mPromiscuousSubscribers);
+ }
+ return listeners;
+ }
+
+ /**
* Checks if a listener is subscribed to any messages.
* @param listener that may have subscription.
* @return true if the listener uis subscribed to messages.
diff --git a/service/src/com/android/car/VmsSubscriberService.java b/service/src/com/android/car/VmsSubscriberService.java
index 97ed27ff8c..eabb0a6a1a 100644
--- a/service/src/com/android/car/VmsSubscriberService.java
+++ b/service/src/com/android/car/VmsSubscriberService.java
@@ -269,18 +269,13 @@ public class VmsSubscriberService extends IVmsSubscriberService.Stub
// Implements VmsHalSubscriberListener interface
@Override
- public void onChange(VmsLayer layer, byte[] payload) {
+ public void onDataMessage(VmsLayer layer, byte[] payload) {
if(DBG) {
Log.d(TAG, "Publishing a message for layer: " + layer);
}
Set<IVmsSubscriberClient> listeners = mHal.getListeners(layer);
- // If there are no listeners we're done.
- if ((listeners == null)) {
- return;
- }
-
for (IVmsSubscriberClient subscriber : listeners) {
try {
subscriber.onVmsMessageReceived(layer, payload);
@@ -290,6 +285,24 @@ public class VmsSubscriberService extends IVmsSubscriberService.Stub
Log.e(TAG, "onVmsMessageReceived calling failed: ", e);
}
}
+ }
+
+ @Override
+ public void onLayersAvaiabilityChange(List<VmsLayer> availableLayers) {
+ if(DBG) {
+ Log.d(TAG, "Publishing layers availability change: " + availableLayers);
+ }
+
+ Set<IVmsSubscriberClient> listeners = mHal.getAllListeners();
+ for (IVmsSubscriberClient subscriber : listeners) {
+ try {
+ subscriber.onLayersAvailabilityChange(availableLayers);
+ } catch (RemoteException e) {
+ // If we could not send a record, its likely the connection snapped. Let the binder
+ // death handle the situation.
+ Log.e(TAG, "onLayersAvailabilityChange calling failed: ", e);
+ }
+ }
}
}
diff --git a/service/src/com/android/car/hal/VmsHalService.java b/service/src/com/android/car/hal/VmsHalService.java
index c23f36a7e7..8a361178c7 100644
--- a/service/src/com/android/car/hal/VmsHalService.java
+++ b/service/src/com/android/car/hal/VmsHalService.java
@@ -22,24 +22,32 @@ import android.car.VehicleAreaType;
import android.car.annotation.FutureFeature;
import android.car.vms.IVmsSubscriberClient;
import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsSubscriptionState;
import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_1.VmsMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsBaseMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_1.VmsMessageType;
-import android.os.SystemClock;
+import android.hardware.automotive.vehicle.V2_1.VmsOfferingMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsSimpleMessageIntegerValuesIndex;
+import android.os.Binder;
+import android.os.IBinder;
import android.util.Log;
import com.android.car.CarLog;
+import com.android.car.VmsLayersAvailability;
import com.android.car.VmsRouting;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -49,25 +57,27 @@ import java.util.concurrent.CopyOnWriteArrayList;
*/
@FutureFeature
public class VmsHalService extends HalServiceBase {
+
private static final boolean DBG = true;
private static final int HAL_PROPERTY_ID = VehicleProperty.VEHICLE_MAP_SERVICE;
private static final String TAG = "VmsHalService";
- private static final Set<Integer> SUPPORTED_MESSAGE_TYPES =
- new HashSet<Integer>(
- Arrays.asList(
- VmsMessageType.SUBSCRIBE,
- VmsMessageType.UNSUBSCRIBE,
- VmsMessageType.DATA));
private boolean mIsSupported = false;
private CopyOnWriteArrayList<VmsHalPublisherListener> mPublisherListeners =
new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<VmsHalSubscriberListener> mSubscriberListeners =
new CopyOnWriteArrayList<>();
+
+ private final IBinder mHalPublisherToken = new Binder();
private final VehicleHal mVehicleHal;
- @GuardedBy("mLock")
- private VmsRouting mRouting = new VmsRouting();
- private final Object mLock = new Object();
+
+ private final Object mRoutingLock = new Object();
+ private final VmsRouting mRouting = new VmsRouting();
+ private final Object mAvailabilityLock = new Object();
+ @GuardedBy("mAvailabilityLock")
+ private final Map<IBinder, VmsLayersOffering> mOfferings = new HashMap<>();
+ @GuardedBy("mAvailabilityLock")
+ private final VmsLayersAvailability mAvailableLayers = new VmsLayersAvailability();
/**
* The VmsPublisherService implements this interface to receive data from the HAL.
@@ -80,7 +90,11 @@ public class VmsHalService extends HalServiceBase {
* The VmsSubscriberService implements this interface to receive data from the HAL.
*/
public interface VmsHalSubscriberListener {
- void onChange(VmsLayer layer, byte[] payload);
+ // Notify listener on a data Message.
+ void onDataMessage(VmsLayer layer, byte[] payload);
+
+ // Notify listener on a change in available layers.
+ void onLayersAvaiabilityChange(List<VmsLayer> availableLayers);
}
/**
@@ -110,22 +124,22 @@ public class VmsHalService extends HalServiceBase {
}
public void addSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
- synchronized (mLock) {
+ boolean firstSubscriptionForLayer = false;
+ synchronized (mRoutingLock) {
// Check if publishers need to be notified about this change in subscriptions.
- boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
+ firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
// Add the listeners subscription to the layer
mRouting.addSubscription(listener, layer);
-
- // Notify the publishers
- if (firstSubscriptionForLayer) {
- notifyPublishers(layer, true);
- }
+ }
+ if (firstSubscriptionForLayer) {
+ notifyPublishers(layer, true);
}
}
public void removeSubscription(IVmsSubscriberClient listener, VmsLayer layer) {
- synchronized (mLock) {
+ boolean layerHasSubscribers = true;
+ synchronized (mRoutingLock) {
if (!mRouting.hasLayerSubscriptions(layer)) {
Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
return;
@@ -135,67 +149,72 @@ public class VmsHalService extends HalServiceBase {
mRouting.removeSubscription(listener, layer);
// Check if publishers need to be notified about this change in subscriptions.
- boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
-
- // Notify the publishers
- if (!layerHasSubscribers) {
- notifyPublishers(layer, false);
- }
+ layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
+ }
+ if (!layerHasSubscribers) {
+ notifyPublishers(layer, false);
}
}
public void addSubscription(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.addSubscription(listener);
}
}
public void removeSubscription(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.removeSubscription(listener);
}
}
public void removeDeadListener(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
mRouting.removeDeadListener(listener);
}
}
public Set<IVmsSubscriberClient> getListeners(VmsLayer layer) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.getListeners(layer);
}
}
+ public Set<IVmsSubscriberClient> getAllListeners() {
+ synchronized (mRoutingLock) {
+ return mRouting.getAllListeners();
+ }
+ }
+
public boolean isHalSubscribed(VmsLayer layer) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.isHalSubscribed(layer);
}
}
public VmsSubscriptionState getSubscriptionState() {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.getSubscriptionState();
}
}
public void addHalSubscription(VmsLayer layer) {
- synchronized (mLock) {
+ boolean firstSubscriptionForLayer = true;
+ synchronized (mRoutingLock) {
// Check if publishers need to be notified about this change in subscriptions.
- boolean firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
+ firstSubscriptionForLayer = !mRouting.hasLayerSubscriptions(layer);
// Add the listeners subscription to the layer
mRouting.addHalSubscription(layer);
-
- if (firstSubscriptionForLayer) {
- notifyPublishers(layer, true);
- }
+ }
+ if (firstSubscriptionForLayer) {
+ notifyPublishers(layer, true);
}
}
public void removeHalSubscription(VmsLayer layer) {
- synchronized (mLock) {
+ boolean layerHasSubscribers = true;
+ synchronized (mRoutingLock) {
if (!mRouting.hasLayerSubscriptions(layer)) {
Log.i(TAG, "Trying to remove a layer with no subscription: " + layer);
return;
@@ -205,21 +224,35 @@ public class VmsHalService extends HalServiceBase {
mRouting.removeHalSubscription(layer);
// Check if publishers need to be notified about this change in subscriptions.
- boolean layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
-
- // Notify the publishers
- if (!layerHasSubscribers) {
- notifyPublishers(layer, false);
- }
+ layerHasSubscribers = mRouting.hasLayerSubscriptions(layer);
+ }
+ if (!layerHasSubscribers) {
+ notifyPublishers(layer, false);
}
}
public boolean containsListener(IVmsSubscriberClient listener) {
- synchronized (mLock) {
+ synchronized (mRoutingLock) {
return mRouting.containsListener(listener);
}
}
+ public void setPublisherLayersOffering(IBinder publisherToken, VmsLayersOffering offering){
+ Set<VmsLayer> availableLayers = Collections.EMPTY_SET;
+ synchronized (mAvailabilityLock) {
+ updateOffering(publisherToken, offering);
+ availableLayers = mAvailableLayers.getAvailableLayers();
+ }
+ notifySubscribers(availableLayers);
+ }
+
+ public Set<VmsLayer> getAvailableLayers() {
+ //TODO(b/36872877): wrap available layers in VmsAvailabilityState similar to VmsSubscriptionState.
+ synchronized (mAvailabilityLock) {
+ return mAvailableLayers.getAvailableLayers();
+ }
+ }
+
/**
* Notify all the publishers and the HAL on subscription changes regardless of who triggered
* the change.
@@ -227,18 +260,31 @@ public class VmsHalService extends HalServiceBase {
* @param layer layer which is being subscribed to or unsubscribed from.
* @param hasSubscribers indicates if the notification is for subscription or unsubscription.
*/
- public void notifyPublishers(VmsLayer layer, boolean hasSubscribers) {
- synchronized (mLock) {
- // notify the HAL
- setSubscriptionRequest(layer, hasSubscribers);
-
- // Notify the App publishers
- for (VmsHalPublisherListener listener : mPublisherListeners) {
- // Besides the list of layers, also a timestamp is provided to the clients.
- // They should ignore any notification with a timestamp that is older than the most
- // recent timestamp they have seen.
- listener.onChange(getSubscriptionState());
- }
+ private void notifyPublishers(VmsLayer layer, boolean hasSubscribers) {
+ // notify the HAL
+ setSubscriptionRequest(layer, hasSubscribers);
+
+ // Notify the App publishers
+ for (VmsHalPublisherListener listener : mPublisherListeners) {
+ // Besides the list of layers, also a timestamp is provided to the clients.
+ // They should ignore any notification with a timestamp that is older than the most
+ // recent timestamp they have seen.
+ listener.onChange(getSubscriptionState());
+ }
+ }
+
+ /**
+ * Notify all the subscribers and the HAL on layers availability change.
+ *
+ * @param availableLayers the layers which publishers claim they made publish.
+ */
+ private void notifySubscribers(Set<VmsLayer> availableLayers) {
+ // notify the HAL
+ setAvailableLayers(availableLayers);
+
+ // Notify the App subscribers
+ for (VmsHalSubscriberListener listener : mSubscriberListeners) {
+ listener.onLayersAvaiabilityChange(new ArrayList<>(availableLayers));
}
}
@@ -288,40 +334,126 @@ public class VmsHalService extends HalServiceBase {
}
for (VehiclePropValue v : values) {
ArrayList<Integer> vec = v.value.int32Values;
- int messageType = vec.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
- int layerId = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_ID);
- int layerVersion = vec.get(VmsMessageIntegerValuesIndex.VMS_LAYER_VERSION);
-
- // Check if message type is supported.
- if (!SUPPORTED_MESSAGE_TYPES.contains(messageType)) {
- throw new IllegalArgumentException("Unexpected message type. " +
- "Expecting: " + SUPPORTED_MESSAGE_TYPES +
- ". Got: " + messageType);
-
- }
+ int messageType = vec.get(VmsBaseMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
if (DBG) {
- Log.d(TAG,
- "Received message for Type: " + messageType +
- " Layer Id: " + layerId +
- "Version: " + layerVersion);
+ Log.d(TAG, "Handling VMS message type: " + messageType);
}
- // This is a data message intended for subscribers.
- if (messageType == VmsMessageType.DATA) {
- // Get the payload.
- byte[] payload = toByteArray(v.value.bytes);
-
- // Send the message.
- for (VmsHalSubscriberListener listener : mSubscriberListeners) {
- listener.onChange(new VmsLayer(layerId, layerVersion), payload);
- }
- } else if (messageType == VmsMessageType.SUBSCRIBE) {
- addHalSubscription(new VmsLayer(layerId, layerVersion));
+ switch(messageType) {
+ case VmsMessageType.DATA:
+ handleDataEvent(vec, toByteArray(v.value.bytes));
+ break;
+ case VmsMessageType.SUBSCRIBE:
+ handleSubscribeEvent(vec);
+ break;
+ case VmsMessageType.UNSUBSCRIBE:
+ handleUnsubscribeEvent(vec);
+ break;
+ case VmsMessageType.OFFERING:
+ handleOfferingEvent(vec);
+ break;
+ case VmsMessageType.AVAILABILITY:
+ handleAvailabilityEvent();
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected message type: " + messageType);
+ }
+ }
+ }
+
+ private void handleDataEvent(List<Integer> integerValues, byte[] payload) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling a data event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+
+ // Send the message.
+ for (VmsHalSubscriberListener listener : mSubscriberListeners) {
+ listener.onDataMessage(new VmsLayer(layerId, layerVersion), payload);
+ }
+ }
+
+ private void handleSubscribeEvent(List<Integer> integerValues) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling a subscribe event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+ addHalSubscription(new VmsLayer(layerId, layerVersion));
+ }
+
+ private void handleUnsubscribeEvent(List<Integer> integerValues) {
+ int layerId = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = integerValues.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ if (DBG) {
+ Log.d(TAG,
+ "Handling an unsubscribe event for Layer Id: " + layerId +
+ " Version: " + layerVersion);
+ }
+ removeHalSubscription(new VmsLayer(layerId, layerVersion));
+ }
+
+ private void handleOfferingEvent(List<Integer> integerValues) {
+ int numLayersDependencies =
+ integerValues.get(VmsOfferingMessageIntegerValuesIndex.VMS_NUMBER_OF_LAYERS_DEPENDENCIES);
+ int idx = VmsOfferingMessageIntegerValuesIndex.FIRST_DEPENDENCIES_INDEX;
+
+ List<VmsLayerDependency> offeredLayers = new ArrayList<>();
+
+ // An offering is layerId, LayerVersion, NumDeps, <LayerId, LayerVersion> X NumDeps.
+ for (int i = 0; i < numLayersDependencies; i++) {
+ int layerId = integerValues.get(idx++);
+ int layerVersion = integerValues.get(idx++);
+ VmsLayer offeredLayer = new VmsLayer(layerId, layerVersion);
+
+ int numDependenciesForLayer = integerValues.get(idx++);
+ if (numDependenciesForLayer == 0) {
+ offeredLayers.add(new VmsLayerDependency(offeredLayer));
} else {
- // messageType == VmsMessageType.UNSUBSCRIBE
- removeHalSubscription(new VmsLayer(layerId, layerVersion));
+ Set<VmsLayer> dependencies = new HashSet<>();
+
+ for (int j = 0; j < numDependenciesForLayer; j++) {
+ int dependantLayerId = integerValues.get(idx++);
+ int dependantLayerVersion = integerValues.get(idx++);
+
+ VmsLayer dependantLayer = new VmsLayer(dependantLayerId, dependantLayerVersion);
+ dependencies.add(dependantLayer);
+ }
+ offeredLayers.add(new VmsLayerDependency(offeredLayer, dependencies));
}
}
+ // Store the HAL offering.
+ VmsLayersOffering offering = new VmsLayersOffering(offeredLayers);
+ synchronized (mAvailabilityLock) {
+ updateOffering(mHalPublisherToken, offering);
+ }
+ }
+
+ private void handleAvailabilityEvent() {
+ synchronized (mAvailabilityLock) {
+ Collection<VmsLayer> availableLayers = mAvailableLayers.getAvailableLayers();
+ VehiclePropValue vehiclePropertyValue = toVehiclePropValue(
+ VmsMessageType.AVAILABILITY, availableLayers);
+ setPropertyValue(vehiclePropertyValue);
+ }
+ }
+
+ private void updateOffering(IBinder publisherToken, VmsLayersOffering offering) {
+ Set<VmsLayer> availableLayers = Collections.EMPTY_SET;
+ synchronized (mAvailabilityLock) {
+ mOfferings.put(publisherToken, offering);
+
+ // Update layers availability.
+ mAvailableLayers.setPublishersOffering(mOfferings.values());
+
+ availableLayers = mAvailableLayers.getAvailableLayers();
+ }
+ notifySubscribers(availableLayers);
}
@Override
@@ -339,14 +471,21 @@ public class VmsHalService extends HalServiceBase {
*/
public boolean setSubscriptionRequest(VmsLayer layer, boolean hasSubscribers) {
VehiclePropValue vehiclePropertyValue = toVehiclePropValue(
- hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
+ hasSubscribers ? VmsMessageType.SUBSCRIBE : VmsMessageType.UNSUBSCRIBE, layer);
return setPropertyValue(vehiclePropertyValue);
}
public boolean setDataMessage(VmsLayer layer, byte[] payload) {
VehiclePropValue vehiclePropertyValue = toVehiclePropValue(VmsMessageType.DATA,
- layer,
- payload);
+ layer,
+ payload);
+ return setPropertyValue(vehiclePropertyValue);
+ }
+
+ public boolean setAvailableLayers(Collection<VmsLayer> availableLayers) {
+ VehiclePropValue vehiclePropertyValue = toVehiclePropValue(VmsMessageType.AVAILABILITY,
+ availableLayers);
+
return setPropertyValue(vehiclePropertyValue);
}
@@ -361,13 +500,20 @@ public class VmsHalService extends HalServiceBase {
}
/** Creates a {@link VehiclePropValue} */
- private static VehiclePropValue toVehiclePropValue(int messageType, VmsLayer layer) {
+ private static VehiclePropValue toVehiclePropValue(int messageType) {
VehiclePropValue vehicleProp = new VehiclePropValue();
vehicleProp.prop = HAL_PROPERTY_ID;
vehicleProp.areaId = VehicleAreaType.VEHICLE_AREA_TYPE_NONE;
VehiclePropValue.RawValue v = vehicleProp.value;
v.int32Values.add(messageType);
+ return vehicleProp;
+ }
+
+ /** Creates a {@link VehiclePropValue} */
+ private static VehiclePropValue toVehiclePropValue(int messageType, VmsLayer layer) {
+ VehiclePropValue vehicleProp = toVehiclePropValue(messageType);
+ VehiclePropValue.RawValue v = vehicleProp.value;
v.int32Values.add(layer.getId());
v.int32Values.add(layer.getVersion());
return vehicleProp;
@@ -375,8 +521,8 @@ public class VmsHalService extends HalServiceBase {
/** Creates a {@link VehiclePropValue} with payload */
private static VehiclePropValue toVehiclePropValue(int messageType,
- VmsLayer layer,
- byte[] payload) {
+ VmsLayer layer,
+ byte[] payload) {
VehiclePropValue vehicleProp = toVehiclePropValue(messageType, layer);
VehiclePropValue.RawValue v = vehicleProp.value;
v.bytes.ensureCapacity(payload.length);
@@ -385,4 +531,18 @@ public class VmsHalService extends HalServiceBase {
}
return vehicleProp;
}
-} \ No newline at end of file
+
+ /** Creates a {@link VehiclePropValue} with payload */
+ private static VehiclePropValue toVehiclePropValue(int messageType,
+ Collection<VmsLayer> layers) {
+ VehiclePropValue vehicleProp = toVehiclePropValue(messageType);
+ VehiclePropValue.RawValue v = vehicleProp.value;
+ int numLayers = layers.size();
+ v.int32Values.add(numLayers);
+ for (VmsLayer layer : layers) {
+ v.int32Values.add(layer.getId());
+ v.int32Values.add(layer.getVersion());
+ }
+ return vehicleProp;
+ }
+}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
index fbea6d27bb..cc7342154c 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientMockService.java
@@ -18,8 +18,12 @@ package com.android.car.test;
import android.car.annotation.FutureFeature;
import android.car.vms.VmsLayer;
+import android.car.vms.VmsLayerDependency;
+import android.car.vms.VmsLayersOffering;
import android.car.vms.VmsPublisherClientService;
import android.car.vms.VmsSubscriptionState;
+import java.util.List;
+import java.util.ArrayList;
/**
* This service is launched during the tests in VmsPublisherSubscriberTest. It publishes a property
@@ -36,12 +40,14 @@ public class VmsPublisherClientMockService extends VmsPublisherClientService {
public void onVmsSubscriptionChange(VmsSubscriptionState subscriptionState) {
// Case when the publisher finished initialization before the subscription request.
publishIfNeeded(subscriptionState);
+ declareOffering(subscriptionState);
}
@Override
public void onVmsPublisherServiceReady() {
// Case when the subscription request was sent before the publisher was ready.
- publishIfNeeded(getSubscriptions());
+ VmsSubscriptionState subscriptionState = getSubscriptions();
+ publishIfNeeded(subscriptionState);
}
private void publishIfNeeded(VmsSubscriptionState subscriptionState) {
@@ -51,4 +57,13 @@ public class VmsPublisherClientMockService extends VmsPublisherClientService {
}
}
}
+
+ private void declareOffering(VmsSubscriptionState subscriptionState) {
+ List<VmsLayerDependency> dependencies = new ArrayList<>();
+ for( VmsLayer layer : subscriptionState.getLayers()) {
+ dependencies.add(new VmsLayerDependency(layer));
+ }
+ VmsLayersOffering offering = new VmsLayersOffering(dependencies);
+ setLayersOffering(offering);
+ }
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
index aa1431e13d..c22f63abe6 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherClientServiceTest.java
@@ -28,7 +28,8 @@ import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyAccess;
import android.hardware.automotive.vehicle.V2_0.VehiclePropertyChangeMode;
import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
-import android.hardware.automotive.vehicle.V2_1.VmsMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsBaseMessageIntegerValuesIndex;
+import android.hardware.automotive.vehicle.V2_1.VmsSimpleMessageIntegerValuesIndex;
import android.hardware.automotive.vehicle.V2_1.VmsMessageType;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
@@ -139,9 +140,9 @@ public class VmsPublisherClientServiceTest extends MockedCarTestBase {
// the semaphore will not be released.
assertTrue(mHalHandlerSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
VehiclePropValue.RawValue rawValue = mHalHandler.getValue().value;
- int messageType = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
- int layerId = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_LAYER_ID);
- int layerVersion = rawValue.int32Values.get(VmsMessageIntegerValuesIndex.VMS_LAYER_VERSION);
+ int messageType = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_MESSAGE_TYPE);
+ int layerId = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_ID);
+ int layerVersion = rawValue.int32Values.get(VmsSimpleMessageIntegerValuesIndex.VMS_LAYER_VERSION);
byte[] payload = new byte[rawValue.bytes.size()];
for (int i = 0; i < rawValue.bytes.size(); ++i) {
payload[i] = rawValue.bytes.get(i);
@@ -161,7 +162,7 @@ public class VmsPublisherClientServiceTest extends MockedCarTestBase {
// If this is the data message release the semaphone so the test can continue.
ArrayList<Integer> int32Values = value.value.int32Values;
- if (int32Values.get(VmsMessageIntegerValuesIndex.VMS_MESSAGE_TYPE) ==
+ if (int32Values.get(VmsBaseMessageIntegerValuesIndex.VMS_MESSAGE_TYPE) ==
VmsMessageType.DATA) {
mHalHandlerSemaphore.release();
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java b/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
index e86b3fa9ea..20fa0b6476 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsPublisherSubscriberTest.java
@@ -32,7 +32,9 @@ import android.hardware.automotive.vehicle.V2_1.VehicleProperty;
import com.android.car.vehiclehal.test.MockedVehicleHal;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -45,10 +47,12 @@ public class VmsPublisherSubscriberTest extends MockedCarTestBase {
public static final VmsLayer LAYER = new VmsLayer(LAYER_ID, LAYER_VERSION);
public static final byte[] PAYLOAD = new byte[]{2, 3, 5, 7, 11, 13, 17};
+ private static final List<VmsLayer> AVAILABLE_LAYERS = new ArrayList<>(Arrays.asList(LAYER));
private HalHandler mHalHandler;
// Used to block until a value is propagated to the TestListener.onVmsMessageReceived.
private Semaphore mSubscriberSemaphore;
+ private Semaphore mAvailabilitySemaphore;
@Override
protected synchronized void configureMockedHal() {
@@ -92,6 +96,7 @@ public class VmsPublisherSubscriberTest extends MockedCarTestBase {
if (!VmsTestUtils.canRunTest(TAG)) return;
super.setUp();
mSubscriberSemaphore = new Semaphore(0);
+ mAvailabilitySemaphore = new Semaphore(0);
}
@Override
@@ -121,12 +126,30 @@ public class VmsPublisherSubscriberTest extends MockedCarTestBase {
assertTrue(Arrays.equals(PAYLOAD, listener.getPayload()));
}
+ /**
+ * The Mock service offers all the subscribed layers as available layers, so in this
+ * test the listener subscribes to a layer and verifies that it gets the notification that it
+ * is available.
+ */
+ public void testAvailability() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(LAYER);
+
+ assertTrue(mAvailabilitySemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(AVAILABLE_LAYERS, listener.getAvailalbeLayers());
+ }
+
private class HalHandler implements MockedVehicleHal.VehicleHalPropertyHandler {
}
private class TestListener implements VmsSubscriberManager.VmsSubscriberClientListener {
private VmsLayer mLayer;
private byte[] mPayload;
+ private List<VmsLayer> mAvailableLayers;
@Override
public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
@@ -139,9 +162,9 @@ public class VmsPublisherSubscriberTest extends MockedCarTestBase {
@Override
public void onLayersAvailabilityChange(List<VmsLayer> availableLayers) {
- //TODO(asafro): test availability changes on publisher update when logic is implemented.
- // for that need to add Offering support in VmsPublisherClientService
- // and update VmsPublisherClientMockService
+ assertEquals(AVAILABLE_LAYERS, availableLayers);
+ mAvailableLayers = availableLayers;
+ mAvailabilitySemaphore.release();
}
@Override
@@ -156,5 +179,9 @@ public class VmsPublisherSubscriberTest extends MockedCarTestBase {
public byte[] getPayload() {
return mPayload;
}
+
+ public List<VmsLayer> getAvailalbeLayers() {
+ return mAvailableLayers;
+ }
}
}
diff --git a/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java b/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
index 79cddad743..063d5cff32 100644
--- a/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
+++ b/tests/carservice_test/src/com/android/car/test/VmsSubscriberManagerTest.java
@@ -32,6 +32,7 @@ import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;
import com.android.car.vehiclehal.VehiclePropValueBuilder;
import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Semaphore;
@@ -46,6 +47,20 @@ public class VmsSubscriberManagerTest extends MockedCarTestBase {
private static final VmsLayer SUBSCRIPTION_LAYER = new VmsLayer(SUBSCRIPTION_LAYER_ID,
SUBSCRIPTION_LAYER_VERSION);
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_ID_1 = 4;
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1 = 5;
+ private static final VmsLayer SUBSCRIPTION_DEPENDANT_LAYER_1 =
+ new VmsLayer(SUBSCRIPTION_DEPENDANT_LAYER_ID_1, SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1);
+
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_ID_2 = 6;
+ private static final int SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2 = 7;
+ private static final VmsLayer SUBSCRIPTION_DEPENDANT_LAYER_2 =
+ new VmsLayer(SUBSCRIPTION_DEPENDANT_LAYER_ID_2, SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2);
+
+ private static final int SUBSCRIPTION_UNSUPPORTED_LAYER_ID = 100;
+ private static final int SUBSCRIPTION_UNSUPPORTED_LAYER_VERSION = 200;
+
+
private HalHandler mHalHandler;
// Used to block until the HAL property is updated in HalHandler.onPropertySet.
private Semaphore mHalHandlerSemaphore;
@@ -132,6 +147,120 @@ public class VmsSubscriberManagerTest extends MockedCarTestBase {
assertTrue(Arrays.equals(expectedPayload, listener.getPayload()));
}
+
+ // Test injecting a value in the HAL and verifying it propagates to a subscriber.
+ public void testSimpleAvailableLayers() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(SUBSCRIPTION_LAYER);
+
+ // Inject a value and wait for its callback in TestListener.onLayersAvailabilityChange.
+ VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build();
+ /*
+ Offering:
+ Layer | Dependency
+ ====================
+ (2, 3) | {}
+
+ Expected availability:
+ {(2, 3)}
+ */
+ v.value.int32Values.addAll(
+ Arrays.asList(
+ VmsMessageType.OFFERING, // MessageType
+ 1, // Number of offered layers
+
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ 0 // number of dependencies for layer
+ )
+ );
+
+ assertEquals(0, mSubscriberSemaphore.availablePermits());
+
+ List<VmsLayer> expectedAvailableLayers = new ArrayList<>(Arrays.asList(SUBSCRIPTION_LAYER));
+
+ getMockedVehicleHal().injectEvent(v);
+ assertTrue(mSubscriberSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(expectedAvailableLayers, listener.getAvailableLayers());
+ }
+
+ // Test injecting a value in the HAL and verifying it propagates to a subscriber.
+ public void testComplexAvailableLayers() throws Exception {
+ if (!VmsTestUtils.canRunTest(TAG)) return;
+ VmsSubscriberManager vmsSubscriberManager = (VmsSubscriberManager) getCar().getCarManager(
+ Car.VMS_SUBSCRIBER_SERVICE);
+ TestListener listener = new TestListener();
+ vmsSubscriberManager.setListener(listener);
+ vmsSubscriberManager.subscribe(SUBSCRIPTION_LAYER);
+
+ // Inject a value and wait for its callback in TestListener.onLayersAvailabilityChange.
+ VehiclePropValue v = VehiclePropValueBuilder.newBuilder(VehicleProperty.VEHICLE_MAP_SERVICE)
+ .setAreaId(VehicleAreaType.VEHICLE_AREA_TYPE_NONE)
+ .setTimestamp(SystemClock.elapsedRealtimeNanos())
+ .build();
+ /*
+ Offering:
+ Layer | Dependency
+ ====================
+ (2, 3) | {}
+ (4, 5) | {(2, 3)}
+ (6, 7) | {(2, 3), (4, 5)}
+ (6, 7) | {(100, 200)}
+
+ Expected availability:
+ {(2, 3), (4, 5), (6, 7)}
+ */
+
+ v.value.int32Values.addAll(
+ Arrays.asList(
+ VmsMessageType.OFFERING, // MessageType
+ 4, // Number of offered layers
+
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ 0, // number of dependencies for layer
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1,
+ 1, // number of dependencies for layer
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_2,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2,
+ 2, // number of dependencies for layer
+ SUBSCRIPTION_LAYER_ID,
+ SUBSCRIPTION_LAYER_VERSION,
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_1,
+
+ SUBSCRIPTION_DEPENDANT_LAYER_ID_2,
+ SUBSCRIPTION_DEPENDANT_LAYER_VERSION_2,
+ 1, // number of dependencies for layer
+ SUBSCRIPTION_UNSUPPORTED_LAYER_ID,
+ SUBSCRIPTION_UNSUPPORTED_LAYER_VERSION
+ )
+ );
+
+ assertEquals(0, mSubscriberSemaphore.availablePermits());
+
+ List<VmsLayer> expectedAvailableLayers =
+ new ArrayList<>(Arrays.asList(SUBSCRIPTION_LAYER,
+ SUBSCRIPTION_DEPENDANT_LAYER_1,
+ SUBSCRIPTION_DEPENDANT_LAYER_2));
+
+ getMockedVehicleHal().injectEvent(v);
+ assertTrue(mSubscriberSemaphore.tryAcquire(2L, TimeUnit.SECONDS));
+ assertEquals(expectedAvailableLayers, listener.getAvailableLayers());
+ }
+
private class HalHandler implements VehicleHalPropertyHandler {
private VehiclePropValue mValue;
@@ -165,6 +294,7 @@ public class VmsSubscriberManagerTest extends MockedCarTestBase {
private class TestListener implements VmsSubscriberClientListener{
private VmsLayer mLayer;
private byte[] mPayload;
+ private List<VmsLayer> mAvailableLayers = new ArrayList<>();
@Override
public void onVmsMessageReceived(VmsLayer layer, byte[] payload) {
@@ -177,6 +307,8 @@ public class VmsSubscriberManagerTest extends MockedCarTestBase {
@Override
public void onLayersAvailabilityChange(List<VmsLayer> availableLayers) {
Log.d(TAG, "onLayersAvailabilityChange: Layers: " + availableLayers);
+ mAvailableLayers.addAll(availableLayers);
+ mSubscriberSemaphore.release();
}
@Override
@@ -191,5 +323,9 @@ public class VmsSubscriberManagerTest extends MockedCarTestBase {
public byte[] getPayload() {
return mPayload;
}
+
+ public List<VmsLayer> getAvailableLayers() {
+ return mAvailableLayers;
+ }
}
}
diff --git a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java b/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
index 07a0122dea..0a907e1076 100644
--- a/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/VmsLayersAvailabilityTest.java
@@ -21,6 +21,7 @@ import android.car.vms.VmsLayerDependency;
import android.car.vms.VmsLayersOffering;
import android.test.AndroidTestCase;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -62,6 +63,15 @@ public class VmsLayersAvailabilityTest extends AndroidTestCase {
super.setUp();
}
+ public void testNoOffering() {
+ assertTrue(mLayersAvailability.getAvailableLayers().isEmpty());
+ }
+
+ public void testEmptyOffering() {
+ mLayersAvailability.setPublishersOffering(Collections.EMPTY_LIST);
+ assertTrue(mLayersAvailability.getAvailableLayers().isEmpty());
+ }
+
public void testSingleLayerNoDeps() throws Exception {
Set<VmsLayer> expectedAvailableLayers = new HashSet<>();
expectedAvailableLayers.add(LAYER_X);