Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6327b866 authored by Aditi Nagaraj's avatar Aditi Nagaraj Committed by Android (Google) Code Review
Browse files

Merge "Adding VmsUtils for parsing Vms Vehicle Properties"

parents c8b8599f 8dcab8e6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ cc_library_static {
        "common/src/VehicleObjectPool.cpp",
        "common/src/VehiclePropertyStore.cpp",
        "common/src/VehicleUtils.cpp",
        "common/src/VmsUtils.cpp",
    ],
    local_include_dirs: ["common/include/vhal_v2_0"],
    export_include_dirs: ["common/include"],
@@ -93,6 +94,7 @@ cc_test {
        "tests/VehicleHalManager_test.cpp",
        "tests/VehicleObjectPool_test.cpp",
        "tests/VehiclePropConfigIndex_test.cpp",
        "tests/VmsUtils_test.cpp",
    ],
    header_libs: ["libbase_headers"],
}
+156 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
#define android_hardware_automotive_vehicle_V2_0_VmsUtils_H_

#include <memory>
#include <string>

#include <android/hardware/automotive/vehicle/2.0/types.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace vms {

// VmsUtils are a set of abstractions for creating and parsing Vehicle Property
// updates to VehicleProperty::VEHICLE_MAP_SERVICE. The format for parsing a
// VehiclePropValue update with a VMS message is specified in the Vehicle HIDL.
//
// This interface is meant for use by HAL clients of VMS; corresponding
// functionality is also provided by VMS in the embedded car service.

// A VmsLayer is comprised of a type, subtype, and version.
struct VmsLayer {
    VmsLayer(int type, int subtype, int version) : type(type), subtype(subtype), version(version) {}
    int type;
    int subtype;
    int version;
};

struct VmsLayerAndPublisher {
    VmsLayer layer;
    int publisher_id;
};

// A VmsAssociatedLayer is used by subscribers to specify which publisher IDs
// are acceptable for a given layer.
struct VmsAssociatedLayer {
    VmsLayer layer;
    std::vector<int> publisher_ids;
};

// A VmsLayerOffering refers to a single layer that can be published, along with
// its dependencies. Dependencies can be empty.
struct VmsLayerOffering {
    VmsLayerOffering(VmsLayer layer, std::vector<VmsLayer> dependencies)
        : layer(layer), dependencies(dependencies) {}
    VmsLayerOffering(VmsLayer layer) : layer(layer), dependencies() {}
    VmsLayer layer;
    std::vector<VmsLayer> dependencies;
};

// 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
// currently being subscribed to in the system.
struct VmsSubscriptionsState {
    int sequence_number;
    std::vector<VmsLayer> layers;
    std::vector<VmsAssociatedLayer> associated_layers;
};

struct VmsAvailabilityState {
    int sequence_number;
    std::vector<VmsAssociatedLayer> associated_layers;
};

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.SUBSCRIBE, specifying to the VMS service
// which layer to subscribe to.
std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer);

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.SUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
// which layer and publisher_id to subscribe to.
std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
    const VmsLayerAndPublisher& layer);

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.UNSUBSCRIBE, specifying to the VMS service
// which layer to unsubscribe from.
std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer);

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
// which layer and publisher_id to unsubscribe from.
std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
    const VmsLayerAndPublisher& layer);

// 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);

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.AVAILABILITY_REQUEST.
std::unique_ptr<VehiclePropValue> createAvailabilityRequest();

// Creates a VehiclePropValue containing a message of type
// VmsMessageType.AVAILABILITY_REQUEST.
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
// 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);

// 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
// return false for any new message types added.
bool isValidVmsMessage(const VehiclePropValue& value);

// Returns the message type. Expects that the VehiclePropValue contains a valid
// Vms message, as verified by isValidVmsMessage.
VmsMessageType parseMessageType(const VehiclePropValue& value);

// Constructs a string byte array from a message of type VmsMessageType.DATA.
// Returns an empty string if the message type doesn't match or if the
// VehiclePropValue does not contain a byte array.
//
// A proto message can then be constructed by passing the result of this
// function to ParseFromString.
std::string parseData(const VehiclePropValue& value);

// TODO(aditin): Need to implement additional parsing functions per message
// type.

}  // namespace vms
}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android

#endif  // android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
+162 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "VmsUtils.h"

#include <common/include/vhal_v2_0/VehicleUtils.h>

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace vms {

static constexpr int kMessageIndex = toInt(VmsBaseMessageIntegerValuesIndex::MESSAGE_TYPE);
static constexpr int kMessageTypeSize = 1;
static constexpr int kLayerNumberSize = 1;
static constexpr int kLayerSize = 3;
static constexpr int kLayerAndPublisherSize = 4;

// 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.
static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE);
static constexpr int kLastMessageType = toInt(VmsMessageType::DATA);

std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
    auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
    result->prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE);
    result->areaId = toInt(VehicleArea::GLOBAL);
    return result;
}

std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer) {
    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIBE), layer.type,
                                                  layer.subtype, layer.version};
    return result;
}

std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
    const VmsLayerAndPublisher& layer_publisher) {
    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
    result->value.int32Values = hidl_vec<int32_t>{
        toInt(VmsMessageType::SUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
    return result;
}

std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer) {
    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::UNSUBSCRIBE), layer.type,
                                                  layer.subtype, layer.version};
    return result;
}

std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
    const VmsLayerAndPublisher& layer_publisher) {
    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
    result->value.int32Values = hidl_vec<int32_t>{
        toInt(VmsMessageType::UNSUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
    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;
    }
    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> layer_vector = {offer.layer.type, offer.layer.subtype,
                                             offer.layer.version,
                                             static_cast<int32_t>(offer.dependencies.size())};
        for (const auto& dependency : offer.dependencies) {
            std::vector<int32_t> dependency_layer = {dependency.type, dependency.subtype,
                                                     dependency.version};
            layer_vector.insert(layer_vector.end(), dependency_layer.begin(),
                                dependency_layer.end());
        }
        offers.insert(offers.end(), layer_vector.begin(), layer_vector.end());
    }
    result->value.int32Values = offers;
    return result;
}

std::unique_ptr<VehiclePropValue> createAvailabilityRequest() {
    auto result = createBaseVmsMessage(kMessageTypeSize);
    result->value.int32Values = hidl_vec<int32_t>{
        toInt(VmsMessageType::AVAILABILITY_REQUEST),
    };
    return result;
}

std::unique_ptr<VehiclePropValue> createSubscriptionsRequest() {
    auto result = createBaseVmsMessage(kMessageTypeSize);
    result->value.int32Values = hidl_vec<int32_t>{
        toInt(VmsMessageType::SUBSCRIPTIONS_REQUEST),
    };
    return result;
}

std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes) {
    auto result = createBaseVmsMessage(kMessageTypeSize);
    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::DATA)};
    result->value.bytes = std::vector<uint8_t>(bytes.begin(), bytes.end());
    return result;
}

bool verifyPropertyAndArea(const VehiclePropValue& value) {
    return (value.prop == toInt(VehicleProperty::VEHICLE_MAP_SERVICE) &&
            value.areaId == toInt(VehicleArea::GLOBAL));
}

bool verifyMessageType(const VehiclePropValue& value) {
    return (value.value.int32Values.size() > 0 &&
            value.value.int32Values[kMessageIndex] >= kFirstMessageType &&
            value.value.int32Values[kMessageIndex] <= kLastMessageType);
}

bool isValidVmsMessage(const VehiclePropValue& value) {
    return (verifyPropertyAndArea(value) && verifyMessageType(value));
}

VmsMessageType parseMessageType(const VehiclePropValue& value) {
    return static_cast<VmsMessageType>(value.value.int32Values[kMessageIndex]);
}

std::string parseData(const VehiclePropValue& value) {
    if (isValidVmsMessage(value) && parseMessageType(value) == VmsMessageType::DATA &&
        value.value.bytes.size() > 0) {
        return std::string(value.value.bytes.begin(), value.value.bytes.end());
    } else {
        return std::string();
    }
}

}  // namespace vms
}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
+183 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
#include <gtest/gtest.h>

#include "VehicleHalTestUtils.h"
#include "vhal_v2_0/VmsUtils.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace vms {

namespace {

TEST(VmsUtilsTest, subscribeMessage) {
    VmsLayer layer(1, 0, 2);
    auto message = createSubscribeMessage(layer);
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIBE);

    // Layer
    EXPECT_EQ(message->value.int32Values[1], 1);
    EXPECT_EQ(message->value.int32Values[2], 0);
    EXPECT_EQ(message->value.int32Values[3], 2);
}

TEST(VmsUtilsTest, unsubscribeMessage) {
    VmsLayer layer(1, 0, 2);
    auto message = createUnsubscribeMessage(layer);
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::UNSUBSCRIBE);

    // Layer
    EXPECT_EQ(message->value.int32Values[1], 1);
    EXPECT_EQ(message->value.int32Values[2], 0);
    EXPECT_EQ(message->value.int32Values[3], 2);
}

TEST(VmsUtilsTest, singleOfferingMessage) {
    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(VmsLayer(1, 0, 2))};
    auto message = createOfferingMessage(offering);
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x6ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);

    // Number of layer offerings
    EXPECT_EQ(message->value.int32Values[1], 1);

    // Layer
    EXPECT_EQ(message->value.int32Values[2], 1);
    EXPECT_EQ(message->value.int32Values[3], 0);
    EXPECT_EQ(message->value.int32Values[4], 2);

    // Number of dependencies
    EXPECT_EQ(message->value.int32Values[5], 0);
}

TEST(VmsUtilsTest, offeringWithDependencies) {
    VmsLayer layer(1, 0, 2);
    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2)};
    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
    auto message = createOfferingMessage(offering);
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x9ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);

    // Number of layer offerings
    EXPECT_EQ(message->value.int32Values[1], 1);

    // Layer
    EXPECT_EQ(message->value.int32Values[2], 1);
    EXPECT_EQ(message->value.int32Values[3], 0);
    EXPECT_EQ(message->value.int32Values[4], 2);

    // Number of dependencies
    EXPECT_EQ(message->value.int32Values[5], 1);

    // Dependency 1
    EXPECT_EQ(message->value.int32Values[6], 2);
    EXPECT_EQ(message->value.int32Values[7], 0);
    EXPECT_EQ(message->value.int32Values[8], 2);
}

TEST(VmsUtilsTest, availabilityMessage) {
    auto message = createAvailabilityRequest();
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::AVAILABILITY_REQUEST);
}

TEST(VmsUtilsTest, subscriptionsMessage) {
    auto message = createSubscriptionsRequest();
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIPTIONS_REQUEST);
}

TEST(VmsUtilsTest, dataMessage) {
    std::string bytes = "aaa";
    auto message = createDataMessage(bytes);
    ASSERT_NE(message, nullptr);
    EXPECT_TRUE(isValidVmsMessage(*message));
    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
    EXPECT_EQ(parseMessageType(*message), VmsMessageType::DATA);
    EXPECT_EQ(message->value.bytes.size(), bytes.size());
    EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0);
}

TEST(VmsUtilsTest, emptyMessageInvalid) {
    VehiclePropValue empty_prop;
    EXPECT_FALSE(isValidVmsMessage(empty_prop));
}

TEST(VmsUtilsTest, invalidMessageType) {
    VmsLayer layer(1, 0, 2);
    auto message = createSubscribeMessage(layer);
    message->value.int32Values[0] = 0;

    EXPECT_FALSE(isValidVmsMessage(*message));
}

TEST(VmsUtilsTest, parseDataMessage) {
    std::string bytes = "aaa";
    auto message = createDataMessage(bytes);
    auto data_str = parseData(*message);
    ASSERT_FALSE(data_str.empty());
    EXPECT_EQ(data_str, bytes);
}

TEST(VmsUtilsTest, parseInvalidDataMessage) {
    VmsLayer layer(1, 0, 2);
    auto message = createSubscribeMessage(layer);
    auto data_str = parseData(*message);
    EXPECT_TRUE(data_str.empty());
}

}  // namespace

}  // namespace vms
}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android