Updates to VMS Utils to support HAL Client Publisher

1. Added new API/utility functions to support publishing VMS messages from HAL client.
2. Fixed creation of offering message by adding publisher ID
3. Fixed an existing failing test from VmsHalManager_test.cpp

Bug: 129475485
Bug: 129163926
Fixes: 129475485
Fixes: 129163926
Test: Added tests for all the new and updated functions in VmsUtilsTest.
Ran the tests on Hawk.
Change-Id: Ie561dafb86d137a4fdf3042e033f8cb133b4aca7
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
index 9e32bb5..258dbd9 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -19,6 +19,7 @@
 
 #include <memory>
 #include <string>
+#include <unordered_set>
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
@@ -42,6 +43,20 @@
     int type;
     int subtype;
     int version;
+    bool operator==(const VmsLayer& layer) const {
+        return this->type == layer.type && this->subtype == layer.subtype &&
+               this->version == layer.version;
+    }
+
+    // Class for hash function
+    class VmsLayerHashFunction {
+      public:
+        // Hash of the variables is returned.
+        size_t operator()(const VmsLayer& layer) const {
+            return std::hash<int>()(layer.type) ^ std::hash<int>()(layer.type) ^
+                   std::hash<int>()(layer.type);
+        }
+    };
 };
 
 struct VmsLayerAndPublisher {
@@ -66,6 +81,15 @@
     std::vector<VmsLayer> dependencies;
 };
 
+// A VmsOffers refers to a list of layers that can be published by the publisher
+// with the specified publisher ID.
+struct VmsOffers {
+    VmsOffers(int publisher_id, std::vector<VmsLayerOffering> offerings)
+        : publisher_id(publisher_id), offerings(offerings) {}
+    int publisher_id;
+    std::vector<VmsLayerOffering> offerings;
+};
+
 // A VmsSubscriptionsState is delivered in response to a
 // VmsMessageType.SUBSCRIPTIONS_REQUEST or on the first SUBSCRIBE or last
 // UNSUBSCRIBE for a layer. It indicates which layers or associated_layers are
@@ -81,6 +105,9 @@
     std::vector<VmsAssociatedLayer> associated_layers;
 };
 
+// Creates an empty base VMS message with some pre-populated default fields.
+std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size);
+
 // Creates a VehiclePropValue containing a message of type
 // VmsMessageType.SUBSCRIBE, specifying to the VMS service
 // which layer to subscribe to.
@@ -106,8 +133,7 @@
 // Creates a VehiclePropValue containing a message of type
 // VmsMessageType.OFFERING, specifying to the VMS service which layers are being
 // offered and their dependencies, if any.
-std::unique_ptr<VehiclePropValue> createOfferingMessage(
-    const std::vector<VmsLayerOffering>& offering);
+std::unique_ptr<VehiclePropValue> createOfferingMessage(const VmsOffers& offers);
 
 // Creates a VehiclePropValue containing a message of type
 // VmsMessageType.AVAILABILITY_REQUEST.
@@ -143,8 +169,40 @@
 // function to ParseFromString.
 std::string parseData(const VehiclePropValue& value);
 
-// TODO(aditin): Need to implement additional parsing functions per message
-// type.
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.PUBLISHER_ID_REQUEST with the given publisher information.
+// Returns a nullptr if the input is empty.
+std::unique_ptr<VehiclePropValue> createPublisherIdRequest(
+        const std::string& vms_provider_description);
+
+// Returns the publisher ID by parsing the VehiclePropValue containing the ID.
+// Returns null if the message is invalid.
+int32_t parsePublisherIdResponse(const VehiclePropValue& publisher_id_response);
+
+// Returns true if the new sequence number is greater than the last seen
+// sequence number.
+bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+                           const int last_seen_sequence_number);
+
+// Returns sequence number of the message.
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change);
+
+// Takes a subscription change message and returns the layers that have active
+// subscriptions of the layers that are offered by your HAL client/publisher.
+//
+// A publisher can use this function when receiving a subscription change message
+// to determine which layers to publish data on.
+// The caller of this function can optionally decide to not consume these layers
+// if the subscription change has the sequence number less than the last seen
+// sequence number.
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+                                          const VmsOffers& offers);
+
+// Takes an availability change message and returns true if the parsed message implies that
+// the service has newly started or restarted.
+// If the message has a sequence number 0, it means that the service
+// has newly started or restarted.
+bool hasServiceNewlyStarted(const VehiclePropValue& availability_change);
 
 }  // namespace vms
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
index f001a32..1863191 100644
--- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -27,16 +27,23 @@
 
 static constexpr int kMessageIndex = toInt(VmsBaseMessageIntegerValuesIndex::MESSAGE_TYPE);
 static constexpr int kMessageTypeSize = 1;
+static constexpr int kPublisherIdSize = 1;
 static constexpr int kLayerNumberSize = 1;
 static constexpr int kLayerSize = 3;
 static constexpr int kLayerAndPublisherSize = 4;
+static constexpr int kPublisherIdIndex =
+        toInt(VmsPublisherInformationIntegerValuesIndex::PUBLISHER_ID);
+static constexpr int kSubscriptionStateSequenceNumberIndex =
+        toInt(VmsSubscriptionsStateIntegerValuesIndex::SEQUENCE_NUMBER);
+static constexpr int kAvailabilitySequenceNumberIndex =
+        toInt(VmsAvailabilityStateIntegerValuesIndex::SEQUENCE_NUMBER);
 
 // TODO(aditin): We should extend the VmsMessageType enum to include a first and
 // last, which would prevent breakages in this API. However, for all of the
 // functions in this module, we only need to guarantee that the message type is
-// between SUBSCRIBE and DATA.
+// between SUBSCRIBE and PUBLISHER_ID_RESPONSE.
 static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE);
-static constexpr int kLastMessageType = toInt(VmsMessageType::DATA);
+static constexpr int kLastMessageType = toInt(VmsMessageType::PUBLISHER_ID_RESPONSE);
 
 std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
     auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
@@ -77,17 +84,16 @@
     return result;
 }
 
-std::unique_ptr<VehiclePropValue> createOfferingMessage(
-    const std::vector<VmsLayerOffering>& offering) {
-    int message_size = kMessageTypeSize + kLayerNumberSize;
-    for (const auto& offer : offering) {
-        message_size += kLayerNumberSize + (1 + offer.dependencies.size()) * kLayerSize;
+std::unique_ptr<VehiclePropValue> createOfferingMessage(const VmsOffers& offers) {
+    int message_size = kMessageTypeSize + kPublisherIdSize + kLayerNumberSize;
+    for (const auto& offer : offers.offerings) {
+        message_size += kLayerSize + kLayerNumberSize + (offer.dependencies.size() * kLayerSize);
     }
     auto result = createBaseVmsMessage(message_size);
 
-    std::vector<int32_t> offers = {toInt(VmsMessageType::OFFERING),
-                                   static_cast<int>(offering.size())};
-    for (const auto& offer : offering) {
+    std::vector<int32_t> offerings = {toInt(VmsMessageType::OFFERING), offers.publisher_id,
+                                      static_cast<int>(offers.offerings.size())};
+    for (const auto& offer : offers.offerings) {
         std::vector<int32_t> layer_vector = {offer.layer.type, offer.layer.subtype,
                                              offer.layer.version,
                                              static_cast<int32_t>(offer.dependencies.size())};
@@ -97,9 +103,9 @@
             layer_vector.insert(layer_vector.end(), dependency_layer.begin(),
                                 dependency_layer.end());
         }
-        offers.insert(offers.end(), layer_vector.begin(), layer_vector.end());
+        offerings.insert(offerings.end(), layer_vector.begin(), layer_vector.end());
     }
-    result->value.int32Values = offers;
+    result->value.int32Values = offerings;
     return result;
 }
 
@@ -153,6 +159,103 @@
     }
 }
 
+std::unique_ptr<VehiclePropValue> createPublisherIdRequest(
+        const std::string& vms_provider_description) {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+            toInt(VmsMessageType::PUBLISHER_ID_REQUEST),
+    };
+    result->value.bytes =
+            std::vector<uint8_t>(vms_provider_description.begin(), vms_provider_description.end());
+    return result;
+}
+
+int32_t parsePublisherIdResponse(const VehiclePropValue& publisher_id_response) {
+    if (isValidVmsMessage(publisher_id_response) &&
+        parseMessageType(publisher_id_response) == VmsMessageType::PUBLISHER_ID_RESPONSE &&
+        publisher_id_response.value.int32Values.size() > kPublisherIdIndex) {
+        return publisher_id_response.value.int32Values[kPublisherIdIndex];
+    }
+    return -1;
+}
+
+bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+                           const int last_seen_sequence_number) {
+    return (isValidVmsMessage(subscription_change) &&
+            parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
+            subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex &&
+            subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex] >
+                    last_seen_sequence_number);
+}
+
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change) {
+    if (isValidVmsMessage(subscription_change) &&
+        parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
+        subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+        return subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex];
+    }
+    return -1;
+}
+
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+                                          const VmsOffers& offers) {
+    if (isValidVmsMessage(subscription_change) &&
+        parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
+        subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+        const int32_t num_of_layers = subscription_change.value.int32Values[toInt(
+                VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)];
+        const int32_t num_of_associated_layers = subscription_change.value.int32Values[toInt(
+                VmsSubscriptionsStateIntegerValuesIndex ::NUMBER_OF_ASSOCIATED_LAYERS)];
+
+        std::unordered_set<VmsLayer, VmsLayer::VmsLayerHashFunction> offered_layers;
+        for (const auto& offer : offers.offerings) {
+            offered_layers.insert(offer.layer);
+        }
+        std::vector<VmsLayer> subscribed_layers;
+
+        int current_index = toInt(VmsSubscriptionsStateIntegerValuesIndex::SUBSCRIPTIONS_START);
+        // Add all subscribed layers which are offered by the current publisher.
+        for (int i = 0; i < num_of_layers; i++) {
+            VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
+                                      subscription_change.value.int32Values[current_index + 1],
+                                      subscription_change.value.int32Values[current_index + 2]);
+            if (offered_layers.find(layer) != offered_layers.end()) {
+                subscribed_layers.push_back(layer);
+            }
+            current_index += kLayerSize;
+        }
+        // Add all subscribed associated layers which are offered by the current publisher.
+        // For this, we need to check if the associated layer has a publisher ID which is
+        // same as that of the current publisher.
+        for (int i = 0; i < num_of_associated_layers; i++) {
+            VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
+                                      subscription_change.value.int32Values[current_index + 1],
+                                      subscription_change.value.int32Values[current_index + 2]);
+            current_index += kLayerSize;
+            if (offered_layers.find(layer) != offered_layers.end()) {
+                int32_t num_of_publisher_ids = subscription_change.value.int32Values[current_index];
+                current_index++;
+                for (int j = 0; j < num_of_publisher_ids; j++) {
+                    if (subscription_change.value.int32Values[current_index] ==
+                        offers.publisher_id) {
+                        subscribed_layers.push_back(layer);
+                    }
+                    current_index++;
+                }
+            }
+        }
+        return subscribed_layers;
+    }
+    return {};
+}
+
+bool hasServiceNewlyStarted(const VehiclePropValue& availability_change) {
+    return (isValidVmsMessage(availability_change) &&
+            parseMessageType(availability_change) == VmsMessageType::AVAILABILITY_CHANGE &&
+            availability_change.value.int32Values.size() > kAvailabilitySequenceNumberIndex &&
+            availability_change.value.int32Values[kAvailabilitySequenceNumberIndex] == 0);
+}
+
 }  // namespace vms
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index f64eab5..0975071 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -278,7 +278,6 @@
 
     cb->reset();
     VehiclePropValue actualValue(*subscribedValue.get());
-    actualValue.status = VehiclePropertyStatus::AVAILABLE;
     hal->sendPropEvent(std::move(subscribedValue));
 
     ASSERT_TRUE(cb->waitForExpectedEvents(1)) << "Events received: "
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
index 414c5c2..5ea5bd4 100644
--- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -60,52 +60,64 @@
 }
 
 TEST(VmsUtilsTest, singleOfferingMessage) {
-    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(VmsLayer(1, 0, 2))};
-    auto message = createOfferingMessage(offering);
+    VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 2))}};
+    auto message = createOfferingMessage(offers);
     ASSERT_NE(message, nullptr);
     EXPECT_TRUE(isValidVmsMessage(*message));
     EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
-    EXPECT_EQ(message->value.int32Values.size(), 0x6ul);
+    EXPECT_EQ(message->value.int32Values.size(), 0x7ul);
     EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
 
+    // Publisher ID
+    EXPECT_EQ(message->value.int32Values[1], 123);
+
     // Number of layer offerings
-    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 1);
 
     // Layer
-    EXPECT_EQ(message->value.int32Values[2], 1);
-    EXPECT_EQ(message->value.int32Values[3], 0);
-    EXPECT_EQ(message->value.int32Values[4], 2);
+    EXPECT_EQ(message->value.int32Values[3], 1);
+    EXPECT_EQ(message->value.int32Values[4], 0);
+    EXPECT_EQ(message->value.int32Values[5], 2);
 
     // Number of dependencies
-    EXPECT_EQ(message->value.int32Values[5], 0);
+    EXPECT_EQ(message->value.int32Values[6], 0);
 }
 
 TEST(VmsUtilsTest, offeringWithDependencies) {
     VmsLayer layer(1, 0, 2);
-    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2)};
+    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2), VmsLayer(3, 0, 3)};
     std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
-    auto message = createOfferingMessage(offering);
+    VmsOffers offers = {123, offering};
+    auto message = createOfferingMessage(offers);
     ASSERT_NE(message, nullptr);
     EXPECT_TRUE(isValidVmsMessage(*message));
     EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
-    EXPECT_EQ(message->value.int32Values.size(), 0x9ul);
+    EXPECT_EQ(message->value.int32Values.size(), 0xdul);
     EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
 
+    // Publisher ID
+    EXPECT_EQ(message->value.int32Values[1], 123);
+
     // Number of layer offerings
-    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 1);
 
     // Layer
-    EXPECT_EQ(message->value.int32Values[2], 1);
-    EXPECT_EQ(message->value.int32Values[3], 0);
-    EXPECT_EQ(message->value.int32Values[4], 2);
+    EXPECT_EQ(message->value.int32Values[3], 1);
+    EXPECT_EQ(message->value.int32Values[4], 0);
+    EXPECT_EQ(message->value.int32Values[5], 2);
 
     // Number of dependencies
-    EXPECT_EQ(message->value.int32Values[5], 1);
+    EXPECT_EQ(message->value.int32Values[6], 2);
 
     // Dependency 1
-    EXPECT_EQ(message->value.int32Values[6], 2);
-    EXPECT_EQ(message->value.int32Values[7], 0);
-    EXPECT_EQ(message->value.int32Values[8], 2);
+    EXPECT_EQ(message->value.int32Values[7], 2);
+    EXPECT_EQ(message->value.int32Values[8], 0);
+    EXPECT_EQ(message->value.int32Values[9], 2);
+
+    // Dependency 2
+    EXPECT_EQ(message->value.int32Values[10], 3);
+    EXPECT_EQ(message->value.int32Values[11], 0);
+    EXPECT_EQ(message->value.int32Values[12], 3);
 }
 
 TEST(VmsUtilsTest, availabilityMessage) {
@@ -166,6 +178,153 @@
     EXPECT_TRUE(data_str.empty());
 }
 
+TEST(VmsUtilsTest, publisherIdRequest) {
+    std::string bytes = "pub_id";
+    auto message = createPublisherIdRequest(bytes);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::PUBLISHER_ID_REQUEST);
+    EXPECT_EQ(message->value.bytes.size(), bytes.size());
+    EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0);
+}
+
+TEST(VmsUtilsTest, validPublisherIdResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::PUBLISHER_ID_RESPONSE), 1234};
+    EXPECT_EQ(parsePublisherIdResponse(*message), 1234);
+}
+
+TEST(VmsUtilsTest, invalidPublisherIdResponse) {
+    auto message = createBaseVmsMessage(1);
+    EXPECT_EQ(parsePublisherIdResponse(*message), -1);
+}
+
+TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsState) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
+    EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234);
+}
+
+TEST(VmsUtilsTest, invalidSubscriptionsState) {
+    auto message = createBaseVmsMessage(1);
+    EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), -1);
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumber) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
+    EXPECT_TRUE(isSequenceNumberNewer(*message, 1233));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumber) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
+    EXPECT_FALSE(isSequenceNumberNewer(*message, 1235));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForSameNumber) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
+    EXPECT_FALSE(isSequenceNumberNewer(*message, 1234));
+}
+
+TEST(VmsUtilsTest, subscribedLayers) {
+    VmsOffers offers = {123,
+                        {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
+                         VmsLayerOffering(VmsLayer(2, 0, 1))}};
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+                                                   1234,  // sequence number
+                                                   2,     // number of layers
+                                                   1,     // number of associated layers
+                                                   1,     // layer 1
+                                                   0,
+                                                   1,
+                                                   4,  // layer 2
+                                                   1,
+                                                   1,
+                                                   2,  // associated layer
+                                                   0,
+                                                   1,
+                                                   2,    // number of publisher IDs
+                                                   111,  // publisher IDs
+                                                   123};
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    auto result = getSubscribedLayers(*message, offers);
+    EXPECT_EQ(static_cast<int>(result.size()), 2);
+    EXPECT_EQ(result.at(0), VmsLayer(1, 0, 1));
+    EXPECT_EQ(result.at(1), VmsLayer(2, 0, 1));
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtype) {
+    VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+                                                   1234,  // sequence number
+                                                   1,     // number of layers
+                                                   0,     // number of associated layers
+                                                   1,     // layer 1
+                                                   1,     // different subtype
+                                                   1};
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentVersion) {
+    VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+                                                   1234,  // sequence number
+                                                   1,     // number of layers
+                                                   0,     // number of associated layers
+                                                   1,     // layer 1
+                                                   0,
+                                                   2};  // different version
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherId) {
+    VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+                                                   1234,  // sequence number
+                                                   0,     // number of layers
+                                                   1,     // number of associated layers
+                                                   1,     // associated layer 1
+                                                   0,
+                                                   1,
+                                                   1,     // number of publisher IDs
+                                                   234};  // publisher ID 1
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
+}
+
+TEST(VmsUtilsTest, serviceNewlyStarted) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 0};
+    EXPECT_TRUE(hasServiceNewlyStarted(*message));
+}
+
+TEST(VmsUtilsTest, serviceNotNewlyStarted) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 1234};
+    EXPECT_FALSE(hasServiceNewlyStarted(*message));
+}
+
+TEST(VmsUtilsTest, invalidAvailabilityChange) {
+    auto message = createBaseVmsMessage(1);
+    EXPECT_FALSE(hasServiceNewlyStarted(*message));
+}
+
 }  // namespace
 
 }  // namespace vms