From 2bc0c5f292370cff232f377af0bd1c74a7c2b10f Mon Sep 17 00:00:00 2001 From: Prachi Hande Date: Tue, 23 Apr 2019 10:50:07 -0700 Subject: [PATCH] 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 --- .../common/include/vhal_v2_0/VmsUtils.h | 42 +++++++-- .../2.0/default/common/src/VmsUtils.cpp | 63 ++++++++++--- .../2.0/default/tests/VmsUtils_test.cpp | 94 ++++++++++++++++++- 3 files changed, 178 insertions(+), 21 deletions(-) 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 258dbd97a4..7082566d2e 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 @@ struct VmsAvailabilityState { std::vector 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 createBaseVmsMessage(size_t message_size); @@ -146,11 +164,21 @@ std::unique_ptr createSubscriptionsRequest(); // 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 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 createPublisherIdRequest( + const std::string& vms_provider_description); + +// Creates a VehiclePropValue message of type VmsMessageType.START_SESSION. +std::unique_ptr 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 @@ VmsMessageType parseMessageType(const VehiclePropValue& value); // 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 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 @@ std::vector getSubscribedLayers(const VehiclePropValue& subscription_c // 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 1863191ed9..111f6eac8e 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 kPublisherIdSize = 1; 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 @@ static constexpr int kAvailabilitySequenceNumberIndex = // 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 createBaseVmsMessage(size_t message_size) { auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size); @@ -132,6 +133,28 @@ std::unique_ptr createDataMessage(const std::string& bytes) { return result; } +std::unique_ptr createPublisherIdRequest( + const std::string& vms_provider_description) { + auto result = createBaseVmsMessage(kMessageTypeSize); + result->value.int32Values = hidl_vec{ + toInt(VmsMessageType::PUBLISHER_ID_REQUEST), + }; + result->value.bytes = + std::vector(vms_provider_description.begin(), vms_provider_description.end()); + return result; +} + +std::unique_ptr createStartSessionMessage(const int service_id, + const int client_id) { + auto result = createBaseVmsMessage(kMessageTypeSize + kSessionIdsSize); + result->value.int32Values = hidl_vec{ + 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::string parseData(const VehiclePropValue& value) { } } -std::unique_ptr createPublisherIdRequest( - const std::string& vms_provider_description) { - auto result = createBaseVmsMessage(kMessageTypeSize); - result->value.int32Values = hidl_vec{ - toInt(VmsMessageType::PUBLISHER_ID_REQUEST), - }; - result->value.bytes = - std::vector(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 @@ bool hasServiceNewlyStarted(const VehiclePropValue& availability_change) { 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 5ea5bd45c5..2b3efc70f0 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, emptyMessageInvalid) { 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 @@ TEST(VmsUtilsTest, invalidAvailabilityChange) { 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{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{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{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{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{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{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{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{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{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