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
This commit is contained in:
Prachi Hande
2019-04-23 10:50:07 -07:00
parent d13f2667df
commit 2bc0c5f292
3 changed files with 178 additions and 21 deletions

View File

@@ -105,6 +105,24 @@ struct VmsAvailabilityState {
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 @@ std::unique_ptr<VehiclePropValue> 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<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 @@ 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<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 @@ std::vector<VmsLayer> 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

View File

@@ -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<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
@@ -132,6 +133,28 @@ std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes) {
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::string parseData(const VehiclePropValue& value) {
}
}
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 @@ 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

View File

@@ -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<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