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

Commit 1c1fdca0 authored by Hao Chen's avatar Hao Chen
Browse files

Protobuf message converter should be a public utility library

Test: Built, and flashed to Osprey (go/enable-google-vhal-on-osprey)

```
# See value changed in Vehicle HAL tab, KitchenSink app:
$ python packages/services/Car/tools/emulator/prop_event_simulator.py
--property
VEHICLEPROPERTY_HVAC_AC_ON --area 0 --value 1

# unit tests
$ atest android.hardware.automotive.vehicle@2.0-default-impl-unit-tests
```

Change-Id: I3841870614f316f2f0e2f54283674223a0b036f4
parent ad122248
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ cc_library_static {
        "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
        "impl/vhal_v2_0/SocketComm.cpp",
        "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
        "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
@@ -98,6 +99,21 @@ cc_test {
    test_suites: ["general-tests"],
}

cc_test {
    name: "android.hardware.automotive.vehicle@2.0-default-impl-unit-tests",
    vendor: true,
    defaults: ["vhal_v2_0_defaults"],
    srcs: [
        "impl/vhal_v2_0/tests/ProtoMessageConverter_test.cpp",
    ],
    static_libs: [
        "android.hardware.automotive.vehicle@2.0-default-impl-lib",
        "android.hardware.automotive.vehicle@2.0-libproto-native",
        "libprotobuf-cpp-lite",
    ],
    test_suites: ["general-tests"],
}

cc_binary {
    name: "android.hardware.automotive.vehicle@2.0-service",
    defaults: ["vhal_v2_0_defaults"],
+216 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#define LOG_TAG "ProtoMsgConverter"

#include <memory>
#include <vector>

#include <log/log.h>

#include <vhal_v2_0/VehicleUtils.h>

#include "ProtoMessageConverter.h"

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

namespace impl {

namespace proto_msg_converter {

// If protobuf class PROTO_VALUE has value in field PROTO_VARNAME,
// then casting the value by CAST and copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
#define CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
                                                  VHAL_TYPE_VARNAME, CAST)                     \
    if (PROTO_VALUE.has_##PROTO_VARNAME()) {                                                   \
        (VHAL_TYPE_VALUE)->VHAL_TYPE_VARNAME = CAST(PROTO_VALUE.PROTO_VARNAME());              \
    }

// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME, every element of PROTO_VECNAME
// is casted by CAST
#define CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
                                            VHAL_TYPE_VECNAME, CAST)                     \
    do {                                                                                 \
        (VHAL_TYPE_VALUE)->VHAL_TYPE_VECNAME.resize(PROTO_VALUE.PROTO_VECNAME##_size()); \
        size_t idx = 0;                                                                  \
        for (auto& value : PROTO_VALUE.PROTO_VECNAME()) {                                \
            VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME[idx++] = CAST(value);                     \
        }                                                                                \
    } while (0)

// If protobuf message has value in field PROTO_VARNAME,
// then copying it to VHAL_TYPE_VALUE->VHAL_TYPE_VARNAME
#define CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, \
                                             VHAL_TYPE_VARNAME)                           \
    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(                                            \
            PROTO_VALUE, PROTO_VARNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VARNAME, /*NO CAST*/)

// Copying the vector PROTO_VECNAME of protobuf class PROTO_VALUE to
// VHAL_TYPE_VALUE->VHAL_TYPE_VECNAME
#define COPY_PROTOBUF_VEC_TO_VHAL_TYPE(PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, \
                                       VHAL_TYPE_VECNAME)                           \
    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(                                            \
            PROTO_VALUE, PROTO_VECNAME, VHAL_TYPE_VALUE, VHAL_TYPE_VECNAME, /*NO CAST*/)

void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg) {
    protoCfg->set_prop(cfg.prop);
    protoCfg->set_access(toInt(cfg.access));
    protoCfg->set_change_mode(toInt(cfg.changeMode));
    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));

    for (auto& configElement : cfg.configArray) {
        protoCfg->add_config_array(configElement);
    }

    if (cfg.configString.size() > 0) {
        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
    }

    protoCfg->clear_area_configs();
    for (auto& areaConfig : cfg.areaConfigs) {
        auto* protoACfg = protoCfg->add_area_configs();
        protoACfg->set_area_id(areaConfig.areaId);

        switch (getPropType(cfg.prop)) {
            case VehiclePropertyType::STRING:
            case VehiclePropertyType::BOOLEAN:
            case VehiclePropertyType::INT32_VEC:
            case VehiclePropertyType::INT64_VEC:
            case VehiclePropertyType::FLOAT_VEC:
            case VehiclePropertyType::BYTES:
            case VehiclePropertyType::MIXED:
                // Do nothing.  These types don't have min/max values
                break;
            case VehiclePropertyType::INT64:
                protoACfg->set_min_int64_value(areaConfig.minInt64Value);
                protoACfg->set_max_int64_value(areaConfig.maxInt64Value);
                break;
            case VehiclePropertyType::FLOAT:
                protoACfg->set_min_float_value(areaConfig.minFloatValue);
                protoACfg->set_max_float_value(areaConfig.maxFloatValue);
                break;
            case VehiclePropertyType::INT32:
                protoACfg->set_min_int32_value(areaConfig.minInt32Value);
                protoACfg->set_max_int32_value(areaConfig.maxInt32Value);
                break;
            default:
                ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
                break;
        }
    }

    protoCfg->set_min_sample_rate(cfg.minSampleRate);
    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
}

void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg) {
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, prop, cfg, prop);
    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, access, cfg, access,
                                              static_cast<VehiclePropertyAccess>);
    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, change_mode, cfg, changeMode,
                                              static_cast<VehiclePropertyChangeMode>);
    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, config_array, cfg, configArray);
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, config_string, cfg, configString);

    auto cast_to_acfg = [](const emulator::VehicleAreaConfig& protoAcfg) {
        VehicleAreaConfig acfg;
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, area_id, &acfg, areaId);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int32_value, &acfg, minInt32Value);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int32_value, &acfg, maxInt32Value);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_int64_value, &acfg, minInt64Value);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_int64_value, &acfg, maxInt64Value);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, min_float_value, &acfg, minFloatValue);
        CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoAcfg, max_float_value, &acfg, maxFloatValue);
        return acfg;
    };

    CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoCfg, area_configs, cfg, areaConfigs, cast_to_acfg);

    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, min_sample_rate, cfg, minSampleRate);
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoCfg, max_sample_rate, cfg, maxSampleRate);
}

void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val) {
    protoVal->set_prop(val.prop);
    protoVal->set_value_type(toInt(getPropType(val.prop)));
    protoVal->set_timestamp(val.timestamp);
    protoVal->set_status((emulator::VehiclePropStatus)(val.status));
    protoVal->set_area_id(val.areaId);

    // Copy value data if it is set.
    //  - for bytes and strings, this is indicated by size > 0
    //  - for int32, int64, and float, copy the values if vectors have data
    if (val.value.stringValue.size() > 0) {
        protoVal->set_string_value(val.value.stringValue.c_str(), val.value.stringValue.size());
    }

    if (val.value.bytes.size() > 0) {
        protoVal->set_bytes_value(val.value.bytes.data(), val.value.bytes.size());
    }

    for (auto& int32Value : val.value.int32Values) {
        protoVal->add_int32_values(int32Value);
    }

    for (auto& int64Value : val.value.int64Values) {
        protoVal->add_int64_values(int64Value);
    }

    for (auto& floatValue : val.value.floatValues) {
        protoVal->add_float_values(floatValue);
    }
}

void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal) {
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, prop, val, prop);
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, timestamp, val, timestamp);
    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, status, val, status,
                                              static_cast<VehiclePropertyStatus>);
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, area_id, val, areaId);

    // Copy value data
    CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, string_value, val, value.stringValue);

    auto cast_proto_bytes_to_vec = [](auto&& bytes) {
        return std::vector<uint8_t>(bytes.begin(), bytes.end());
    };
    CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE(protoVal, bytes_value, val, value.bytes,
                                              cast_proto_bytes_to_vec);

    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int32_values, val, value.int32Values);
    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, int64_values, val, value.int64Values);
    COPY_PROTOBUF_VEC_TO_VHAL_TYPE(protoVal, float_values, val, value.floatValues);
}

#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
#undef CHECK_COPY_PROTOBUF_VAR_TO_VHAL_TYPE
#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
#undef CHECK_CAST_COPY_PROTOBUF_VAR_TO_VHAL_TYPE

}  // namespace proto_msg_converter

}  // namespace impl

}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android
+56 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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_impl_ProtoMessageConverter_H_
#define android_hardware_automotive_vehicle_V2_0_impl_ProtoMessageConverter_H_

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

#include "VehicleHalProto.pb.h"

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

namespace impl {

namespace proto_msg_converter {

// VehiclePropConfig

void toProto(emulator::VehiclePropConfig* protoCfg, const VehiclePropConfig& cfg);

void fromProto(VehiclePropConfig* cfg, const emulator::VehiclePropConfig& protoCfg);

// VehiclePropValue

void toProto(emulator::VehiclePropValue* protoVal, const VehiclePropValue& val);

void fromProto(VehiclePropValue* val, const emulator::VehiclePropValue& protoVal);

}  // namespace proto_msg_converter

}  // namespace impl

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

#endif  // android_hardware_automotive_vehicle_V2_0_impl_VehicleHalEmulator_H_
+3 −80
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <vhal_v2_0/VehicleUtils.h>

#include "PipeComm.h"
#include "ProtoMessageConverter.h"
#include "SocketComm.h"

#include "VehicleEmulator.h"
@@ -217,90 +218,12 @@ void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,

void VehicleEmulator::populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
                                                 const VehiclePropConfig& cfg) {
    protoCfg->set_prop(cfg.prop);
    protoCfg->set_access(toInt(cfg.access));
    protoCfg->set_change_mode(toInt(cfg.changeMode));
    protoCfg->set_value_type(toInt(getPropType(cfg.prop)));

    for (auto& configElement : cfg.configArray) {
        protoCfg->add_config_array(configElement);
    }

    if (cfg.configString.size() > 0) {
        protoCfg->set_config_string(cfg.configString.c_str(), cfg.configString.size());
    }

    // Populate the min/max values based on property type
    switch (getPropType(cfg.prop)) {
        case VehiclePropertyType::STRING:
        case VehiclePropertyType::BOOLEAN:
        case VehiclePropertyType::INT32_VEC:
        case VehiclePropertyType::INT64_VEC:
        case VehiclePropertyType::FLOAT_VEC:
        case VehiclePropertyType::BYTES:
        case VehiclePropertyType::MIXED:
            // Do nothing.  These types don't have min/max values
            break;
        case VehiclePropertyType::INT64:
            if (cfg.areaConfigs.size() > 0) {
                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
                aCfg->set_min_int64_value(cfg.areaConfigs[0].minInt64Value);
                aCfg->set_max_int64_value(cfg.areaConfigs[0].maxInt64Value);
            }
            break;
        case VehiclePropertyType::FLOAT:
            if (cfg.areaConfigs.size() > 0) {
                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
                aCfg->set_min_float_value(cfg.areaConfigs[0].minFloatValue);
                aCfg->set_max_float_value(cfg.areaConfigs[0].maxFloatValue);
            }
            break;
        case VehiclePropertyType::INT32:
            if (cfg.areaConfigs.size() > 0) {
                emulator::VehicleAreaConfig* aCfg = protoCfg->add_area_configs();
                aCfg->set_min_int32_value(cfg.areaConfigs[0].minInt32Value);
                aCfg->set_max_int32_value(cfg.areaConfigs[0].maxInt32Value);
            }
            break;
        default:
            ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
            break;
    }

    protoCfg->set_min_sample_rate(cfg.minSampleRate);
    protoCfg->set_max_sample_rate(cfg.maxSampleRate);
    return proto_msg_converter::toProto(protoCfg, cfg);
}

void VehicleEmulator::populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
                                                    const VehiclePropValue* val) {
    protoVal->set_prop(val->prop);
    protoVal->set_value_type(toInt(getPropType(val->prop)));
    protoVal->set_timestamp(val->timestamp);
    protoVal->set_status((emulator::VehiclePropStatus)(val->status));
    protoVal->set_area_id(val->areaId);

    // Copy value data if it is set.
    //  - for bytes and strings, this is indicated by size > 0
    //  - for int32, int64, and float, copy the values if vectors have data
    if (val->value.stringValue.size() > 0) {
        protoVal->set_string_value(val->value.stringValue.c_str(), val->value.stringValue.size());
    }

    if (val->value.bytes.size() > 0) {
        protoVal->set_bytes_value(val->value.bytes.data(), val->value.bytes.size());
    }

    for (auto& int32Value : val->value.int32Values) {
        protoVal->add_int32_values(int32Value);
    }

    for (auto& int64Value : val->value.int64Values) {
        protoVal->add_int64_values(int64Value);
    }

    for (auto& floatValue : val->value.floatValues) {
        protoVal->add_float_values(floatValue);
    }
    return proto_msg_converter::toProto(protoVal, *val);
}

}  // impl
+110 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 <gtest/gtest.h>

#include <utils/SystemClock.h>

#include "vhal_v2_0/DefaultConfig.h"
#include "vhal_v2_0/ProtoMessageConverter.h"
#include "vhal_v2_0/VehicleUtils.h"

namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
namespace V2_0 {
namespace impl {
namespace proto_msg_converter {

namespace {

void CheckPropConfigConversion(const VehiclePropConfig& config) {
    emulator::VehiclePropConfig protoCfg;
    VehiclePropConfig tmpConfig;

    toProto(&protoCfg, config);
    fromProto(&tmpConfig, protoCfg);

    EXPECT_EQ(config.prop, tmpConfig.prop);
    EXPECT_EQ(config.access, tmpConfig.access);
    EXPECT_EQ(config.changeMode, tmpConfig.changeMode);
    EXPECT_EQ(config.configString, tmpConfig.configString);
    EXPECT_EQ(config.minSampleRate, tmpConfig.minSampleRate);
    EXPECT_EQ(config.maxSampleRate, tmpConfig.maxSampleRate);
    EXPECT_EQ(config.configArray, tmpConfig.configArray);

    EXPECT_EQ(config.areaConfigs.size(), tmpConfig.areaConfigs.size());

    auto cfgType = getPropType(config.prop);
    for (size_t idx = 0; idx < std::min(config.areaConfigs.size(), tmpConfig.areaConfigs.size());
         ++idx) {
        auto& lhs = config.areaConfigs[idx];
        auto& rhs = tmpConfig.areaConfigs[idx];
        EXPECT_EQ(lhs.areaId, rhs.areaId);
        switch (cfgType) {
            case VehiclePropertyType::INT64:
                EXPECT_EQ(lhs.minInt64Value, rhs.minInt64Value);
                EXPECT_EQ(lhs.maxInt64Value, rhs.maxInt64Value);
                break;
            case VehiclePropertyType::FLOAT:
                EXPECT_EQ(lhs.minFloatValue, rhs.minFloatValue);
                EXPECT_EQ(lhs.maxFloatValue, rhs.maxFloatValue);
                break;
            case VehiclePropertyType::INT32:
                EXPECT_EQ(lhs.minInt32Value, rhs.minInt32Value);
                EXPECT_EQ(lhs.maxInt32Value, rhs.maxInt32Value);
                break;
            default:
                // ignore min/max values
                break;
        }
    }
}

void CheckPropValueConversion(const VehiclePropValue& val) {
    emulator::VehiclePropValue protoVal;
    VehiclePropValue tmpVal;

    toProto(&protoVal, val);
    fromProto(&tmpVal, protoVal);

    EXPECT_EQ(val, tmpVal);
}

TEST(ProtoMessageConverterTest, basic) {
    for (auto& property : impl::kVehicleProperties) {
        CheckPropConfigConversion(property.config);

        VehiclePropValue prop;
        prop.timestamp = elapsedRealtimeNano();
        prop.areaId = 123;
        prop.prop = property.config.prop;
        prop.value = property.initialValue;
        prop.status = VehiclePropertyStatus::ERROR;
        CheckPropValueConversion(prop);
    }
}

}  // namespace

}  // namespace proto_msg_converter
}  // namespace impl
}  // namespace V2_0
}  // namespace vehicle
}  // namespace automotive
}  // namespace hardware
}  // namespace android