Merge "Add utility methods to create and parse handshake messages." into qt-dev
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