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

Commit 81fa064d authored by Yu Shan's avatar Yu Shan Committed by Android (Google) Code Review
Browse files

Merge changes from topic "move_conn_lib"

* changes:
  Move VehicleHalProto out from vhal_v2_0.
  Support set property in dump.
  Support debug dump
  Prevent log spam.
  Optimize some code path to move instead of copy data.
parents 803420a3 6cd2fd7e
Loading
Loading
Loading
Loading
+0 −110
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.
 */

syntax = "proto2";

package vhal_proto;

// CMD messages are from workstation --> VHAL
// RESP messages are from VHAL --> workstation
enum MsgType {
    GET_CONFIG_CMD                      = 0;
    GET_CONFIG_RESP                     = 1;
    GET_CONFIG_ALL_CMD                  = 2;
    GET_CONFIG_ALL_RESP                 = 3;
    GET_PROPERTY_CMD                    = 4;
    GET_PROPERTY_RESP                   = 5;
    GET_PROPERTY_ALL_CMD                = 6;
    GET_PROPERTY_ALL_RESP               = 7;
    SET_PROPERTY_CMD                    = 8;
    SET_PROPERTY_RESP                   = 9;
    SET_PROPERTY_ASYNC                  = 10;
    DEBUG_CMD                           = 11;
    DEBUG_RESP                          = 12;
}
enum Status {
    RESULT_OK                           = 0;
    ERROR_UNKNOWN                       = 1;
    ERROR_UNIMPLEMENTED_CMD             = 2;
    ERROR_INVALID_PROPERTY              = 3;
    ERROR_INVALID_AREA_ID               = 4;
    ERROR_PROPERTY_UNINITIALIZED        = 5;
    ERROR_WRITE_ONLY_PROPERTY           = 6;
    ERROR_MEMORY_ALLOC_FAILED           = 7;
    ERROR_INVALID_OPERATION             = 8;
}

enum VehiclePropStatus {
    AVAILABLE                           = 0;
    UNAVAILABLE                         = 1;
    ERROR                               = 2;
}

message VehicleAreaConfig {
    required int32  area_id             = 1;
    optional sint32 min_int32_value     = 2;
    optional sint32 max_int32_value     = 3;
    optional sint64 min_int64_value     = 4;
    optional sint64 max_int64_value     = 5;
    optional float  min_float_value     = 6;
    optional float  max_float_value     = 7;
}

message VehiclePropConfig {
    required int32             prop                = 1;
    optional int32             access              = 2;
    optional int32             change_mode         = 3;
    optional int32             value_type          = 4;
    optional int32             supported_areas     = 5;     // Deprecated - DO NOT USE
    repeated VehicleAreaConfig area_configs        = 6;
    optional int32             config_flags        = 7;
    repeated int32             config_array        = 8;
    optional string            config_string       = 9;
    optional float             min_sample_rate     = 10;
    optional float             max_sample_rate     = 11;
};

message VehiclePropValue {
    // common data
    required int32  prop                = 1;
    optional int32  value_type          = 2;
    optional int64  timestamp           = 3;    // required for valid data from HAL, skipped for set
    optional VehiclePropStatus  status  = 10;   // required for valid data from HAL, skipped for set

    // values
    optional int32  area_id             = 4;
    repeated sint32 int32_values        = 5;    // this also covers boolean value.
    repeated sint64 int64_values        = 6;
    repeated float  float_values        = 7;
    optional string string_value        = 8;
    optional bytes  bytes_value         = 9;
};

// This structure is used to notify what values to get from the Vehicle HAL
message VehiclePropGet {
    required int32 prop                 = 1;
    optional int32 area_id              = 2;
};

message EmulatorMessage {
    required MsgType           msg_type       = 1;
    optional Status            status         = 2; // Only for RESP messages
    repeated VehiclePropGet    prop           = 3; // Provided for getConfig, getProperty commands
    repeated VehiclePropConfig config         = 4;
    repeated VehiclePropValue  value          = 5;
    repeated string            debug_commands = 6; // Required for debug command
    optional string            debug_result   = 7; // Required for debug RESP messages
};
+37 −4
Original line number Diff line number Diff line
@@ -23,7 +23,9 @@
#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
#include <android-base/parseint.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>

#include <map>
@@ -37,7 +39,7 @@ namespace automotive {
namespace vehicle {
namespace fake {

class FakeVehicleHardware final : public IVehicleHardware {
class FakeVehicleHardware : public IVehicleHardware {
  public:
    FakeVehicleHardware();

@@ -78,13 +80,15 @@ class FakeVehicleHardware final : public IVehicleHardware {
    void registerOnPropertySetErrorEvent(
            std::unique_ptr<const PropertySetErrorCallback> callback) override;

  protected:
    // mValuePool is also used in mServerSidePropStore.
    const std::shared_ptr<VehiclePropValuePool> mValuePool;
    const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;

  private:
    // Expose private methods to unit test.
    friend class FakeVehicleHardwareTestHelper;

    // mValuePool is also used in mServerSidePropStore.
    const std::shared_ptr<VehiclePropValuePool> mValuePool;
    const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
    const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
    const std::unique_ptr<FakeUserHal> mFakeUserHal;
    std::mutex mCallbackLock;
@@ -120,6 +124,35 @@ class FakeVehicleHardware final : public IVehicleHardware {
    ::android::base::Result<VehiclePropValuePool::RecyclableType> getUserHalProp(
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
    bool isHvacPropAndHvacNotAvailable(int32_t propId);

    std::string dumpAllProperties();
    std::string dumpOnePropertyByConfig(
            int rowNumber,
            const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config);
    std::string dumpOnePropertyById(int32_t propId, int32_t areaId);
    std::string dumpHelp();
    std::string dumpListProperties();
    std::string dumpSpecificProperty(const std::vector<std::string>& options);
    std::string dumpSetProperties(const std::vector<std::string>& options);

    template <typename T>
    ::android::base::Result<T> safelyParseInt(int index, const std::string& s) {
        T out;
        if (!::android::base::ParseInt(s, &out)) {
            return ::android::base::Error() << ::android::base::StringPrintf(
                           "non-integer argument at index %d: %s\n", index, s.c_str());
        }
        return out;
    }
    ::android::base::Result<float> safelyParseFloat(int index, const std::string& s);
    std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
                                             size_t* index);
    ::android::base::Result<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
    parseSetPropOptions(const std::vector<std::string>& options);
    ::android::base::Result<std::vector<uint8_t>> parseHexString(const std::string& s);

    ::android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
                                                     size_t minSize);
};

}  // namespace fake
+353 −5
Original line number Diff line number Diff line
@@ -14,6 +14,9 @@
 * limitations under the License.
 */

#define LOG_TAG "FakeVehicleHardware"
#define FAKE_VEHICLEHARDWARE_DEBUG false  // STOPSHIP if true.

#include "FakeVehicleHardware.h"

#include <DefaultConfig.h>
@@ -22,7 +25,9 @@
#include <PropertyUtils.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
#include <android-base/parsedouble.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>

@@ -56,12 +61,31 @@ using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;

using ::android::base::EqualsIgnoreCase;
using ::android::base::Error;
using ::android::base::ParseFloat;
using ::android::base::Result;
using ::android::base::StartsWith;
using ::android::base::StringPrintf;

const char* VENDOR_OVERRIDE_DIR = "/vendor/etc/automotive/vhaloverride/";
const char* OVERRIDE_PROPERTY = "persist.vendor.vhal_init_value_override";

// A list of supported options for "--set" command.
const std::unordered_set<std::string> SET_PROP_OPTIONS = {
        // integer.
        "-i",
        // 64bit integer.
        "-i64",
        // float.
        "-f",
        // string.
        "-s",
        // bytes in hex format, e.g. 0xDEADBEEF.
        "-b",
        // Area id in integer.
        "-a"};

}  // namespace

void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
@@ -387,7 +411,9 @@ StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallbac
        const VehiclePropValue& value = request.value;
        int propId = value.prop;

        if (FAKE_VEHICLEHARDWARE_DEBUG) {
            ALOGD("Set value for property ID: %d", propId);
        }

        SetValueResult setValueResult;
        setValueResult.requestId = request.requestId;
@@ -434,7 +460,10 @@ StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
    std::vector<GetValueResult> results;
    for (auto& request : requests) {
        const VehiclePropValue& value = request.prop;

        if (FAKE_VEHICLEHARDWARE_DEBUG) {
            ALOGD("getValues(%d)", value.prop);
        }

        GetValueResult getValueResult;
        getValueResult.requestId = request.requestId;
@@ -476,14 +505,290 @@ StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
    return StatusCode::OK;
}

DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
    DumpResult result;
    // TODO(b/201830716): Implement this.
    result.callerShouldDumpState = false;
    if (options.size() == 0) {
        // We only want caller to dump default state when there is no options.
        result.callerShouldDumpState = true;
        result.buffer = dumpAllProperties();
        return result;
    }
    std::string option = options[0];
    if (EqualsIgnoreCase(option, "--help")) {
        result.buffer = dumpHelp();
        return result;
    } else if (EqualsIgnoreCase(option, "--list")) {
        result.buffer = dumpListProperties();
    } else if (EqualsIgnoreCase(option, "--get")) {
        result.buffer = dumpSpecificProperty(options);
    } else if (EqualsIgnoreCase(option, "--set")) {
        result.buffer = dumpSetProperties(options);
    } else {
        result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
    }
    return result;
}

std::string FakeVehicleHardware::dumpHelp() {
    return "Usage: \n\n"
           "[no args]: dumps (id and value) all supported properties \n"
           "--help: shows this help\n"
           "--list: lists the ids of all supported properties\n"
           "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"
           "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] "
           "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
           "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
           "Notice that the string, bytes and area value can be set just once, while the other can"
           " have multiple values (so they're used in the respective array), "
           "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n";
}

std::string FakeVehicleHardware::dumpAllProperties() {
    auto configs = mServerSidePropStore->getAllConfigs();
    if (configs.size() == 0) {
        return "no properties to dump\n";
    }
    std::string msg = StringPrintf("dumping %zu properties\n", configs.size());
    int rowNumber = 1;
    for (const VehiclePropConfig& config : configs) {
        msg += dumpOnePropertyByConfig(rowNumber++, config);
    }
    return msg;
}

std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
                                                         const VehiclePropConfig& config) {
    size_t numberAreas = config.areaConfigs.size();
    std::string msg = "";
    if (numberAreas == 0) {
        msg += StringPrintf("%d: ", rowNumber);
        msg += dumpOnePropertyById(config.prop, /* areaId= */ 0);
        return msg;
    }
    for (size_t j = 0; j < numberAreas; ++j) {
        if (numberAreas > 1) {
            msg += StringPrintf("%d-%zu: ", rowNumber, j);
        } else {
            msg += StringPrintf("%d: ", rowNumber);
        }
        msg += dumpOnePropertyById(config.prop, config.areaConfigs[j].areaId);
    }
    return msg;
}

std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
    VehiclePropValue value = {
            .prop = propId,
            .areaId = areaId,
    };
    bool isSpecialValue = false;
    auto result = maybeGetSpecialValue(value, &isSpecialValue);
    if (!isSpecialValue) {
        result = mServerSidePropStore->readValue(value);
    }
    if (!result.ok()) {
        return StringPrintf("failed to read property value: %d, error: %s, code: %d\n", propId,
                            getErrorMsg(result).c_str(), getIntErrorCode(result));

    } else {
        return result.value()->toString() + "\n";
    }
}

std::string FakeVehicleHardware::dumpListProperties() {
    auto configs = mServerSidePropStore->getAllConfigs();
    if (configs.size() == 0) {
        return "no properties to list\n";
    }
    int rowNumber = 1;
    std::string msg = StringPrintf("listing %zu properties\n", configs.size());
    for (const auto& config : configs) {
        msg += StringPrintf("%d: %d\n", rowNumber++, config.prop);
    }
    return msg;
}

Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
                                                     size_t minSize) {
    size_t size = options.size();
    if (size >= minSize) {
        return {};
    }
    return Error() << StringPrintf("Invalid number of arguments: required at least %zu, got %zu\n",
                                   minSize, size);
}

std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
    if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
        return getErrorMsg(result);
    }

    // options[0] is the command itself...
    int rowNumber = 1;
    size_t size = options.size();
    std::string msg = "";
    for (size_t i = 1; i < size; ++i) {
        auto propResult = safelyParseInt<int32_t>(i, options[i]);
        if (!propResult.ok()) {
            msg += getErrorMsg(propResult);
            continue;
        }
        int32_t prop = propResult.value();
        auto result = mServerSidePropStore->getConfig(prop);
        if (!result.ok()) {
            msg += StringPrintf("No property %d\n", prop);
            continue;
        }
        msg += dumpOnePropertyByConfig(rowNumber++, *result.value());
    }
    return msg;
}

std::vector<std::string> FakeVehicleHardware::getOptionValues(
        const std::vector<std::string>& options, size_t* index) {
    std::vector<std::string> values;
    while (*index < options.size()) {
        std::string option = options[*index];
        if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
            return std::move(values);
        }
        values.push_back(option);
        (*index)++;
    }
    return std::move(values);
}

Result<VehiclePropValue> FakeVehicleHardware::parseSetPropOptions(
        const std::vector<std::string>& options) {
    // Options format:
    // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a]
    size_t optionIndex = 1;
    auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
    if (!result.ok()) {
        return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
                                       options[optionIndex].c_str(), getErrorMsg(result).c_str());
    }
    VehiclePropValue prop = {};
    prop.prop = result.value();
    prop.status = VehiclePropertyStatus::AVAILABLE;
    optionIndex++;
    std::unordered_set<std::string> parsedOptions;

    while (optionIndex < options.size()) {
        std::string type = options[optionIndex];
        optionIndex++;
        size_t currentIndex = optionIndex;
        std::vector<std::string> values = getOptionValues(options, &optionIndex);
        if (parsedOptions.find(type) != parsedOptions.end()) {
            return Error() << StringPrintf("Duplicate \"%s\" options\n", type.c_str());
        }
        parsedOptions.insert(type);
        if (EqualsIgnoreCase(type, "-i")) {
            if (values.size() == 0) {
                return Error() << "No values specified when using \"-i\"\n";
            }
            prop.value.int32Values.resize(values.size());
            for (size_t i = 0; i < values.size(); i++) {
                auto int32Result = safelyParseInt<int32_t>(currentIndex + i, values[i]);
                if (!int32Result.ok()) {
                    return Error()
                           << StringPrintf("Value: \"%s\" is not a valid int: %s\n",
                                           values[i].c_str(), getErrorMsg(int32Result).c_str());
                }
                prop.value.int32Values[i] = int32Result.value();
            }
        } else if (EqualsIgnoreCase(type, "-i64")) {
            if (values.size() == 0) {
                return Error() << "No values specified when using \"-i64\"\n";
            }
            prop.value.int64Values.resize(values.size());
            for (size_t i = 0; i < values.size(); i++) {
                auto int64Result = safelyParseInt<int64_t>(currentIndex + i, values[i]);
                if (!int64Result.ok()) {
                    return Error()
                           << StringPrintf("Value: \"%s\" is not a valid int64: %s\n",
                                           values[i].c_str(), getErrorMsg(int64Result).c_str());
                }
                prop.value.int64Values[i] = int64Result.value();
            }
        } else if (EqualsIgnoreCase(type, "-f")) {
            if (values.size() == 0) {
                return Error() << "No values specified when using \"-f\"\n";
            }
            prop.value.floatValues.resize(values.size());
            for (size_t i = 0; i < values.size(); i++) {
                auto floatResult = safelyParseFloat(currentIndex + i, values[i]);
                if (!floatResult.ok()) {
                    return Error()
                           << StringPrintf("Value: \"%s\" is not a valid float: %s\n",
                                           values[i].c_str(), getErrorMsg(floatResult).c_str());
                }
                prop.value.floatValues[i] = floatResult.value();
            }
        } else if (EqualsIgnoreCase(type, "-s")) {
            if (values.size() != 1) {
                return Error() << "Expect exact one value when using \"-s\"\n";
            }
            prop.value.stringValue = values[0];
        } else if (EqualsIgnoreCase(type, "-b")) {
            if (values.size() != 1) {
                return Error() << "Expect exact one value when using \"-b\"\n";
            }
            auto bytesResult = parseHexString(values[0]);
            if (!bytesResult.ok()) {
                return Error() << StringPrintf("value: \"%s\" is not a valid hex string: %s\n",
                                               values[0].c_str(), getErrorMsg(bytesResult).c_str());
            }
            prop.value.byteValues = std::move(bytesResult.value());
        } else if (EqualsIgnoreCase(type, "-a")) {
            if (values.size() != 1) {
                return Error() << "Expect exact one value when using \"-a\"\n";
            }
            auto int32Result = safelyParseInt<int32_t>(currentIndex, values[0]);
            if (!int32Result.ok()) {
                return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
                                               values[0].c_str(), getErrorMsg(int32Result).c_str());
            }
            prop.areaId = int32Result.value();
        } else {
            return Error() << StringPrintf("Unknown option: %s\n", type.c_str());
        }
    }

    return prop;
}

std::string FakeVehicleHardware::dumpSetProperties(const std::vector<std::string>& options) {
    if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
        return getErrorMsg(result);
    }

    auto parseResult = parseSetPropOptions(options);
    if (!parseResult.ok()) {
        return getErrorMsg(parseResult);
    }
    VehiclePropValue prop = std::move(parseResult.value());
    ALOGD("Dump: Setting property: %s", prop.toString().c_str());

    bool isSpecialValue = false;
    auto setResult = maybeSetSpecialValue(prop, &isSpecialValue);

    if (!isSpecialValue) {
        auto updatedValue = mValuePool->obtain(prop);
        updatedValue->timestamp = elapsedRealtimeNano();
        setResult = mServerSidePropStore->writeValue(std::move(updatedValue));
    }

    if (setResult.ok()) {
        return StringPrintf("Set property: %s\n", prop.toString().c_str());
    }
    return StringPrintf("failed to set property: %s, error: %s\n", prop.toString().c_str(),
                        getErrorMsg(setResult).c_str());
}

StatusCode FakeVehicleHardware::checkHealth() {
    // TODO(b/201830716): Implement this.
    // Always return OK for checkHealth.
    return StatusCode::OK;
}

@@ -544,6 +849,49 @@ void FakeVehicleHardware::overrideProperties(const char* overrideDir) {
    }
}

Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
    float out;
    if (!ParseFloat(s, &out)) {
        return Error() << StringPrintf("non-float argument at index %d: %s\n", index, s.c_str());
    }
    return out;
}

Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::string& s) {
    std::vector<uint8_t> bytes;
    if (s.size() % 2 != 0) {
        return Error() << StringPrintf("invalid hex string: %s, should have even size\n",
                                       s.c_str());
    }
    if (!StartsWith(s, "0x")) {
        return Error() << StringPrintf("hex string should start with \"0x\", got %s\n", s.c_str());
    }
    std::string subs = s.substr(2);
    std::transform(subs.begin(), subs.end(), subs.begin(),
                   [](unsigned char c) { return std::tolower(c); });

    bool highDigit = true;
    for (size_t i = 0; i < subs.size(); i++) {
        char c = subs[i];
        uint8_t v;
        if (c >= '0' && c <= '9') {
            v = c - '0';
        } else if (c >= 'a' && c <= 'f') {
            v = c - 'a' + 10;
        } else {
            return Error() << StringPrintf("invalid character %c in hex string %s\n", c,
                                           subs.c_str());
        }
        if (highDigit) {
            bytes.push_back(v * 16);
        } else {
            bytes[bytes.size() - 1] += v;
        }
        highDigit = !highDigit;
    }
    return bytes;
}

}  // namespace fake
}  // namespace vehicle
}  // namespace automotive
+259 −0

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ class GetSetValuesClient final : public ConnectedClient {
    GetSetValuesClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);

    // Sends the results to this client.
    void sendResults(const std::vector<ResultType>& results);
    void sendResults(std::vector<ResultType>&& results);

    // Sends each result separately to this client. Each result would be sent through one callback
    // invocation.
Loading