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

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

Merge changes from topics "presubmit-am-5b7a95f212ff478f89a6c087d9e90e0c",...

Merge changes from topics "presubmit-am-5b7a95f212ff478f89a6c087d9e90e0c", "presubmit-am-cc636b1b7be5428c86072a21533d351e" into tm-dev

* changes:
  Support '--user-hal' in FakeVehicleHardware.
  Make FakeVehicleHardware async.
parents fb5a4273 e3421c3c
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_

#include <ConcurrentQueue.h>
#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
@@ -48,6 +49,8 @@ class FakeVehicleHardware : public IVehicleHardware {

    explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);

    ~FakeVehicleHardware();

    // Get all the property configs.
    std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
    getAllPropertyConfigs() const override;
@@ -102,6 +105,29 @@ class FakeVehicleHardware : public IVehicleHardware {
    // Expose private methods to unit test.
    friend class FakeVehicleHardwareTestHelper;

    template <class CallbackType, class RequestType>
    struct RequestWithCallback {
        RequestType request;
        std::shared_ptr<const CallbackType> callback;
    };

    template <class CallbackType, class RequestType>
    class PendingRequestHandler {
      public:
        PendingRequestHandler(FakeVehicleHardware* hardware);

        void addRequest(RequestType request, std::shared_ptr<const CallbackType> callback);

        void stop();

      private:
        FakeVehicleHardware* mHardware;
        std::thread mThread;
        ConcurrentQueue<RequestWithCallback<CallbackType, RequestType>> mRequests;

        void handleRequestsOnce();
    };

    const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
    const std::unique_ptr<FakeUserHal> mFakeUserHal;
    // RecurrentTimer is thread-safe.
@@ -111,6 +137,13 @@ class FakeVehicleHardware : public IVehicleHardware {
    std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback GUARDED_BY(mLock);
    std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
            mRecurrentActions GUARDED_BY(mLock);
    // PendingRequestHandler is thread-safe.
    mutable PendingRequestHandler<GetValuesCallback,
                                  aidl::android::hardware::automotive::vehicle::GetValueRequest>
            mPendingGetValueRequests;
    mutable PendingRequestHandler<SetValuesCallback,
                                  aidl::android::hardware::automotive::vehicle::SetValueRequest>
            mPendingSetValueRequests;

    void init();
    // Stores the initial value to property store.
@@ -170,6 +203,10 @@ class FakeVehicleHardware : public IVehicleHardware {

    android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
                                                   size_t minSize);
    aidl::android::hardware::automotive::vehicle::GetValueResult handleGetValueRequest(
            const aidl::android::hardware::automotive::vehicle::GetValueRequest& request);
    aidl::android::hardware::automotive::vehicle::SetValueResult handleSetValueRequest(
            const aidl::android::hardware::automotive::vehicle::SetValueRequest& request);
};

}  // namespace fake
+120 −45
Original line number Diff line number Diff line
@@ -139,10 +139,17 @@ FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> v
      mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
      mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
      mFakeUserHal(new FakeUserHal(mValuePool)),
      mRecurrentTimer(new RecurrentTimer()) {
      mRecurrentTimer(new RecurrentTimer()),
      mPendingGetValueRequests(this),
      mPendingSetValueRequests(this) {
    init();
}

FakeVehicleHardware::~FakeVehicleHardware() {
    mPendingGetValueRequests.stop();
    mPendingSetValueRequests.stop();
}

void FakeVehicleHardware::init() {
    for (auto& it : defaultconfig::getDefaultConfigs()) {
        VehiclePropConfig cfg = it.config;
@@ -427,37 +434,25 @@ VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu

StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
                                          const std::vector<SetValueRequest>& requests) {
    std::vector<SetValueResult> results;
    for (auto& request : requests) {
        const VehiclePropValue& value = request.value;
        int propId = value.prop;

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

        SetValueResult setValueResult;
        setValueResult.requestId = request.requestId;

        if (auto result = setValue(value); !result.ok()) {
            ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
                  getIntErrorCode(result));
            setValueResult.status = getErrorCode(result);
        } else {
            setValueResult.status = StatusCode::OK;
        // In a real VHAL implementation, you could either send the setValue request to vehicle bus
        // here in the binder thread, or you could send the request in setValue which runs in
        // the handler thread. If you decide to send the setValue request here, you should not
        // wait for the response here and the handler thread should handle the setValue response.
        mPendingSetValueRequests.addRequest(request, callback);
    }

        results.push_back(std::move(setValueResult));
    }

    // In the real vhal, the values will be sent to Car ECU. We just pretend it is done here and
    // send back the updated property values to client.
    (*callback)(std::move(results));

    return StatusCode::OK;
}

VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
    // In a real VHAL implementation, this will send the request to vehicle bus if not already
    // sent in setValues, and wait for the response from vehicle bus.
    // Here we are just updating mValuePool.
    bool isSpecialValue = false;
    auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);

@@ -484,20 +479,43 @@ VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
    return {};
}

SetValueResult FakeVehicleHardware::handleSetValueRequest(const SetValueRequest& request) {
    SetValueResult setValueResult;
    setValueResult.requestId = request.requestId;

    if (auto result = setValue(request.value); !result.ok()) {
        ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
              getIntErrorCode(result));
        setValueResult.status = getErrorCode(result);
    } else {
        setValueResult.status = StatusCode::OK;
    }

    return setValueResult;
}

StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
                                          const std::vector<GetValueRequest>& requests) const {
    std::vector<GetValueResult> results;
    for (auto& request : requests) {
        const VehiclePropValue& value = request.prop;

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

        // In a real VHAL implementation, you could either send the getValue request to vehicle bus
        // here in the binder thread, or you could send the request in getValue which runs in
        // the handler thread. If you decide to send the getValue request here, you should not
        // wait for the response here and the handler thread should handle the getValue response.
        mPendingGetValueRequests.addRequest(request, callback);
    }

    return StatusCode::OK;
}

GetValueResult FakeVehicleHardware::handleGetValueRequest(const GetValueRequest& request) {
    GetValueResult getValueResult;
    getValueResult.requestId = request.requestId;

        auto result = getValue(value);
    auto result = getValue(request.prop);
    if (!result.ok()) {
        ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
              getIntErrorCode(result));
@@ -506,19 +524,14 @@ StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallbac
        getValueResult.status = StatusCode::OK;
        getValueResult.prop = *result.value();
    }
        results.push_back(std::move(getValueResult));
    }

    // In a real VHAL implementation, getValue would be async and we would call the callback after
    // we actually received the values from vehicle bus. Here we are getting the result
    // synchronously so we could call the callback here.
    (*callback)(std::move(results));

    return StatusCode::OK;
    return getValueResult;
}

FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
        const VehiclePropValue& value) const {
    // In a real VHAL implementation, this will send the request to vehicle bus if not already
    // sent in getValues, and wait for the response from vehicle bus.
    // Here we are just reading value from mValuePool.
    bool isSpecialValue = false;
    auto result = maybeGetSpecialValue(value, &isSpecialValue);
    if (isSpecialValue) {
@@ -564,6 +577,12 @@ DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
        result.buffer = dumpSpecificProperty(options);
    } else if (EqualsIgnoreCase(option, "--set")) {
        result.buffer = dumpSetProperties(options);
    } else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
        if (options.size() == 1) {
            result.buffer = mFakeUserHal->showDumpHelp();
        } else {
            result.buffer = mFakeUserHal->dump(options[1]);
        }
    } else {
        result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
    }
@@ -581,7 +600,9 @@ std::string FakeVehicleHardware::dumpHelp() {
           "[-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";
           "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n\n"
           "Fake user HAL usage: \n" +
           mFakeUserHal->showDumpHelp();
}

std::string FakeVehicleHardware::dumpAllProperties() {
@@ -971,6 +992,60 @@ Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::stri
    return bytes;
}

template <class CallbackType, class RequestType>
FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::PendingRequestHandler(
        FakeVehicleHardware* hardware)
    : mHardware(hardware), mThread([this] {
          while (mRequests.waitForItems()) {
              handleRequestsOnce();
          }
      }) {}

template <class CallbackType, class RequestType>
void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::addRequest(
        RequestType request, std::shared_ptr<const CallbackType> callback) {
    mRequests.push({
            request,
            callback,
    });
}

template <class CallbackType, class RequestType>
void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::stop() {
    mRequests.deactivate();
    if (mThread.joinable()) {
        mThread.join();
    }
}

template <>
void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::GetValuesCallback,
                                                GetValueRequest>::handleRequestsOnce() {
    std::unordered_map<std::shared_ptr<const GetValuesCallback>, std::vector<GetValueResult>>
            callbackToResults;
    for (const auto& rwc : mRequests.flush()) {
        auto result = mHardware->handleGetValueRequest(rwc.request);
        callbackToResults[rwc.callback].push_back(std::move(result));
    }
    for (const auto& [callback, results] : callbackToResults) {
        (*callback)(std::move(results));
    }
}

template <>
void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::SetValuesCallback,
                                                SetValueRequest>::handleRequestsOnce() {
    std::unordered_map<std::shared_ptr<const SetValuesCallback>, std::vector<SetValueResult>>
            callbackToResults;
    for (const auto& rwc : mRequests.flush()) {
        auto result = mHardware->handleSetValueRequest(rwc.request);
        callbackToResults[rwc.callback].push_back(std::move(result));
    }
    for (const auto& [callback, results] : callbackToResults) {
        (*callback)(std::move(results));
    }
}

}  // namespace fake
}  // namespace vehicle
}  // namespace automotive
+73 −3
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@
#include <inttypes.h>
#include <chrono>
#include <condition_variable>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace android {
@@ -99,11 +101,51 @@ class FakeVehicleHardwareTest : public ::testing::Test {
    FakeVehicleHardware* getHardware() { return &mHardware; }

    StatusCode setValues(const std::vector<SetValueRequest>& requests) {
        return getHardware()->setValues(mSetValuesCallback, requests);
        {
            std::scoped_lock<std::mutex> lockGuard(mLock);
            for (const auto& request : requests) {
                mPendingSetValueRequests.insert(request.requestId);
            }
        }
        if (StatusCode status = getHardware()->setValues(mSetValuesCallback, requests);
            status != StatusCode::OK) {
            return status;
        }
        std::unique_lock<std::mutex> lk(mLock);
        // Wait for the onSetValueResults.
        bool result = mCv.wait_for(lk, milliseconds(1000), [this] {
            ScopedLockAssertion lockAssertion(mLock);
            return mPendingSetValueRequests.size() == 0;
        });
        if (!result) {
            ALOGE("wait for callbacks for setValues timed-out");
            return StatusCode::INTERNAL_ERROR;
        }
        return StatusCode::OK;
    }

    StatusCode getValues(const std::vector<GetValueRequest>& requests) {
        return getHardware()->getValues(mGetValuesCallback, requests);
        {
            std::scoped_lock<std::mutex> lockGuard(mLock);
            for (const auto& request : requests) {
                mPendingGetValueRequests.insert(request.requestId);
            }
        }
        if (StatusCode status = getHardware()->getValues(mGetValuesCallback, requests);
            status != StatusCode::OK) {
            return status;
        }
        std::unique_lock<std::mutex> lk(mLock);
        // Wait for the onGetValueResults.
        bool result = mCv.wait_for(lk, milliseconds(1000), [this] {
            ScopedLockAssertion lockAssertion(mLock);
            return mPendingGetValueRequests.size() == 0;
        });
        if (!result) {
            ALOGE("wait for callbacks for getValues timed-out");
            return StatusCode::INTERNAL_ERROR;
        }
        return StatusCode::OK;
    }

    StatusCode setValue(const VehiclePropValue& value) {
@@ -167,7 +209,9 @@ class FakeVehicleHardwareTest : public ::testing::Test {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        for (auto& result : results) {
            mSetValueResults.push_back(result);
            mPendingSetValueRequests.erase(result.requestId);
        }
        mCv.notify_all();
    }

    const std::vector<SetValueResult>& getSetValueResults() {
@@ -179,7 +223,9 @@ class FakeVehicleHardwareTest : public ::testing::Test {
        std::scoped_lock<std::mutex> lockGuard(mLock);
        for (auto& result : results) {
            mGetValueResults.push_back(result);
            mPendingGetValueRequests.erase(result.requestId);
        }
        mCv.notify_all();
    }

    const std::vector<GetValueResult>& getGetValueResults() {
@@ -197,7 +243,7 @@ class FakeVehicleHardwareTest : public ::testing::Test {
            };
            mEventCount[propIdAreaId]++;
        }
        mCv.notify_one();
        mCv.notify_all();
    }

    const std::vector<VehiclePropValue>& getChangedProperties() {
@@ -295,6 +341,8 @@ class FakeVehicleHardwareTest : public ::testing::Test {
    std::vector<SetValueResult> mSetValueResults GUARDED_BY(mLock);
    std::vector<GetValueResult> mGetValueResults GUARDED_BY(mLock);
    std::vector<VehiclePropValue> mChangedProperties GUARDED_BY(mLock);
    std::unordered_set<int64_t> mPendingSetValueRequests GUARDED_BY(mLock);
    std::unordered_set<int64_t> mPendingGetValueRequests GUARDED_BY(mLock);
};

TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
@@ -1357,6 +1405,28 @@ TEST_F(FakeVehicleHardwareTest, testDumpInvalidOptions) {
    ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
}

TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHalHelp) {
    std::vector<std::string> options;
    options.push_back("--user-hal");

    DumpResult result = getHardware()->dump(options);
    ASSERT_FALSE(result.callerShouldDumpState);
    ASSERT_NE(result.buffer, "");
    ASSERT_THAT(result.buffer, ContainsRegex("dumps state used for user management"));
}

TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHal) {
    std::vector<std::string> options;
    options.push_back("--user-hal");
    // Indent: " ".
    options.push_back(" ");

    DumpResult result = getHardware()->dump(options);
    ASSERT_FALSE(result.callerShouldDumpState);
    ASSERT_NE(result.buffer, "");
    ASSERT_THAT(result.buffer, ContainsRegex(" No InitialUserInfo response\n"));
}

struct SetPropTestCase {
    std::string test_name;
    std::vector<std::string> options;