Add utility methods to create and parse handshake messages.

Bug:131165419
Fixes: 131165419
Test: Added new unit tests for both the new functions in VmsUtilsTest.
Ran the tests on Hawk.
Change-Id: Ie750983762b5706054ace35c5671f88b6457477a
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 258dbd9..7082566 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
@@ -105,6 +105,24 @@
     std::vector<VmsAssociatedLayer> associated_layers;
 };
 
+// An enum to represent the result of parsing START_SESSION message from the VMS service.
+enum VmsSessionStatus {
+    // New server session is received if the new client ID is -1 and the new server ID is not an
+    // invalid ID.
+    kNewServerSession,
+    // Ack to new client session is received if the new client ID is same as the old one and the new
+    // server ID is not an invalid ID.
+    kAckToNewClientSession,
+    // Error codes:
+    // Invalid message with either invalid format or unexpected data.
+    kInvalidMessage,
+    // Invalid server ID. New ID should always be greater than or equal to max_of(0, current server
+    // ID)
+    kInvalidServiceId,
+    // Invalid client ID. New ID should always be either -1 or the current client ID.
+    kInvalidClientId
+};
+
 // Creates an empty base VMS message with some pre-populated default fields.
 std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size);
 
@@ -146,11 +164,21 @@
 // Creates a VehiclePropValue containing a message of type VmsMessageType.DATA.
 // Returns a nullptr if the byte string in bytes is empty.
 //
-// For example, to build a VehiclePropMessage containing a proto, the caller
+// For example, to build a VehiclePropValue message containing a proto, the caller
 // should convert the proto to a byte string using the SerializeToString proto
 // API, then use this inteface to build the VehicleProperty.
 std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes);
 
+// 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);
+
+// Creates a VehiclePropValue message of type VmsMessageType.START_SESSION.
+std::unique_ptr<VehiclePropValue> createStartSessionMessage(const int service_id,
+                                                            const int client_id);
+
 // Returns true if the VehiclePropValue pointed to by value contains a valid Vms
 // message, i.e. the VehicleProperty, VehicleArea, and VmsMessageType are all
 // valid. Note: If the VmsMessageType enum is extended, this function will
@@ -169,12 +197,6 @@
 // function to ParseFromString.
 std::string parseData(const VehiclePropValue& value);
 
-// 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);
@@ -204,6 +226,12 @@
 // has newly started or restarted.
 bool hasServiceNewlyStarted(const VehiclePropValue& availability_change);
 
+// Takes a start session message, current service ID, current client ID; and returns the type/status
+// of the message. It also populates the new service ID with the correct value.
+VmsSessionStatus parseStartSessionMessage(const VehiclePropValue& start_session,
+                                          const int service_id, const int client_id,
+                                          int* new_service_id);
+
 }  // namespace vms
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
index 1863191..111f6ea 100644
--- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -31,6 +31,7 @@
 static constexpr int kLayerNumberSize = 1;
 static constexpr int kLayerSize = 3;
 static constexpr int kLayerAndPublisherSize = 4;
+static constexpr int kSessionIdsSize = 2;
 static constexpr int kPublisherIdIndex =
         toInt(VmsPublisherInformationIntegerValuesIndex::PUBLISHER_ID);
 static constexpr int kSubscriptionStateSequenceNumberIndex =
@@ -41,9 +42,9 @@
 // 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 PUBLISHER_ID_RESPONSE.
+// between SUBSCRIBE and START_SESSION.
 static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE);
-static constexpr int kLastMessageType = toInt(VmsMessageType::PUBLISHER_ID_RESPONSE);
+static constexpr int kLastMessageType = toInt(VmsMessageType::START_SESSION);
 
 std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
     auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
@@ -132,6 +133,28 @@
     return result;
 }
 
+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;
+}
+
+std::unique_ptr<VehiclePropValue> createStartSessionMessage(const int service_id,
+                                                            const int client_id) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kSessionIdsSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+            toInt(VmsMessageType::START_SESSION),
+            service_id,
+            client_id,
+    };
+    return result;
+}
+
 bool isValidVmsProperty(const VehiclePropValue& value) {
     return (value.prop == toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
 }
@@ -159,17 +182,6 @@
     }
 }
 
-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 &&
@@ -256,6 +268,31 @@
             availability_change.value.int32Values[kAvailabilitySequenceNumberIndex] == 0);
 }
 
+VmsSessionStatus parseStartSessionMessage(const VehiclePropValue& start_session,
+                                          const int service_id, const int client_id,
+                                          int* new_service_id) {
+    if (isValidVmsMessage(start_session) &&
+        parseMessageType(start_session) == VmsMessageType::START_SESSION &&
+        start_session.value.int32Values.size() == kSessionIdsSize + 1) {
+        *new_service_id = start_session.value.int32Values[1];
+        const int new_client_id = start_session.value.int32Values[2];
+        if (*new_service_id < std::max(0, service_id)) {
+            *new_service_id = service_id;
+            return VmsSessionStatus::kInvalidServiceId;
+        }
+        if (new_client_id == -1) {
+            return VmsSessionStatus::kNewServerSession;
+        }
+        if (new_client_id == client_id) {
+            return VmsSessionStatus::kAckToNewClientSession;
+        }
+        *new_service_id = service_id;
+        return VmsSessionStatus::kInvalidClientId;
+    }
+    *new_service_id = service_id;
+    return VmsSessionStatus::kInvalidMessage;
+}
+
 }  // namespace vms
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
index 5ea5bd4..2b3efc7 100644
--- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -158,7 +158,7 @@
 TEST(VmsUtilsTest, invalidMessageType) {
     VmsLayer layer(1, 0, 2);
     auto message = createSubscribeMessage(layer);
-    message->value.int32Values[0] = 0;
+    message->value.int32Values[0] = -1;
 
     EXPECT_FALSE(isValidVmsMessage(*message));
 }
@@ -325,6 +325,98 @@
     EXPECT_FALSE(hasServiceNewlyStarted(*message));
 }
 
+TEST(VmsUtilsTest, startSessionRequest) {
+    auto message = createStartSessionMessage(123, 456);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->value.int32Values.size(), 0x3ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::START_SESSION);
+    EXPECT_EQ(message->value.int32Values[1], 123);
+    EXPECT_EQ(message->value.int32Values[2], 456);
+}
+
+TEST(VmsUtilsTest, startSessionServiceNewlyStarted) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 123, -1};
+    EXPECT_EQ(parseStartSessionMessage(*message, 122, 456, &new_service_id),
+              VmsSessionStatus::kNewServerSession);
+    EXPECT_EQ(new_service_id, 123);
+}
+
+TEST(VmsUtilsTest, startSessionServiceNewlyStartedEdgeCase) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, -1};
+    EXPECT_EQ(parseStartSessionMessage(*message, -1, 0, &new_service_id),
+              VmsSessionStatus::kNewServerSession);
+    EXPECT_EQ(new_service_id, 0);
+}
+
+TEST(VmsUtilsTest, startSessionClientNewlyStarted) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 123, 456};
+    EXPECT_EQ(parseStartSessionMessage(*message, -1, 456, &new_service_id),
+              VmsSessionStatus::kAckToNewClientSession);
+    EXPECT_EQ(new_service_id, 123);
+}
+
+TEST(VmsUtilsTest, startSessionClientNewlyStartedWithSameServerId) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 123, 456};
+    EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id),
+              VmsSessionStatus::kAckToNewClientSession);
+    EXPECT_EQ(new_service_id, 123);
+}
+
+TEST(VmsUtilsTest, startSessionClientNewlyStartedEdgeCase) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 0, 0};
+    EXPECT_EQ(parseStartSessionMessage(*message, 0, 0, &new_service_id),
+              VmsSessionStatus::kAckToNewClientSession);
+    EXPECT_EQ(new_service_id, 0);
+}
+
+TEST(VmsUtilsTest, startSessionOldServiceId) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 120, 456};
+    EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id),
+              VmsSessionStatus::kInvalidServiceId);
+    EXPECT_EQ(new_service_id, 123);
+}
+
+TEST(VmsUtilsTest, startSessionInvalidServiceIdEdgeCase) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), -1, 456};
+    EXPECT_EQ(parseStartSessionMessage(*message, -1, 456, &new_service_id),
+              VmsSessionStatus::kInvalidServiceId);
+    EXPECT_EQ(new_service_id, -1);
+}
+
+TEST(VmsUtilsTest, startSessionInvalidClientId) {
+    auto message = createBaseVmsMessage(3);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 123, 457};
+    EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id),
+              VmsSessionStatus::kInvalidClientId);
+    EXPECT_EQ(new_service_id, 123);
+}
+
+TEST(VmsUtilsTest, startSessionInvalidMessageFormat) {
+    auto message = createBaseVmsMessage(2);
+    int new_service_id;
+    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::START_SESSION), 123};
+    EXPECT_EQ(parseStartSessionMessage(*message, 123, 456, &new_service_id),
+              VmsSessionStatus::kInvalidMessage);
+    EXPECT_EQ(new_service_id, 123);
+}
+
 }  // namespace
 
 }  // namespace vms