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

Commit 438bf99f authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Split client and server impl am: a6d6fa3d am: 6fc5d411

Change-Id: I9bbfb68474081526cf1918b9e96c42f85d8035e7
parents ea6cdb8e 6fc5d411
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -63,6 +63,8 @@ cc_library_static {
        "impl/vhal_v2_0/CommConn.cpp",
        "impl/vhal_v2_0/CommConn.cpp",
        "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
        "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
        "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
        "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
        "impl/vhal_v2_0/VehicleHalClient.cpp",
        "impl/vhal_v2_0/VehicleHalServer.cpp",
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/VehicleEmulator.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
        "impl/vhal_v2_0/PipeComm.cpp",
        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
        "impl/vhal_v2_0/ProtoMessageConverter.cpp",
+10 −340
Original line number Original line Diff line number Diff line
@@ -35,345 +35,15 @@ namespace V2_0 {


namespace impl {
namespace impl {


void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
class EmulatedPassthroughConnector : public PassthroughConnector {
    if (!mPropCallback) {
  public:
        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
        return;
    }
    return mPropCallback(value, updateStatus);
}

void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
    if (mPropCallback) {
        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
        return;
    }
    mPropCallback = std::move(callback);
}

GeneratorHub* EmulatedVehicleServer::getGenerator() {
    return &mGeneratorHub;
}

VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
    if (!mValuePool) {
        LOG(WARNING) << __func__ << ": Value pool not set!";
    }
    return mValuePool;
}

void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
    if (!valuePool) {
        LOG(WARNING) <<  __func__ << ": Setting value pool to nullptr!";
    }
    mValuePool = valuePool;
}

void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
    constexpr bool updateStatus = true;
    LOG(DEBUG) << __func__ << ": " << toString(value);
    auto updatedPropValue = getValuePool()->obtain(value);
    if (updatedPropValue) {
        updatedPropValue->timestamp = value.timestamp;
        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
        onPropertyValueFromCar(*updatedPropValue, updateStatus);
    }
}

std::vector<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
    std::vector<VehiclePropConfig> vehiclePropConfigs;
    constexpr size_t numOfVehiclePropConfigs =
            sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
    vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
    for (auto& it : kVehicleProperties) {
        vehiclePropConfigs.emplace_back(it.config);
    }
    return vehiclePropConfigs;
}


StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
  private:
    constexpr bool updateStatus = true;
    void dumpUserHal(int fd, std::string indent);

};
    LOG(INFO) << __func__;
    const auto& v = request.value;
    if (!v.int32Values.size()) {
        LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
        return StatusCode::INVALID_ARG;
    }

    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);

    switch (command) {
        case FakeDataCommand::StartLinear: {
            LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
            if (v.int32Values.size() < 2) {
                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
                return StatusCode::INVALID_ARG;
            }
            if (!v.int64Values.size()) {
                LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
                return StatusCode::INVALID_ARG;
            }
            if (v.floatValues.size() < 3) {
                LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
                      << v.floatValues.size();
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = v.int32Values[1];
            getGenerator()->registerGenerator(cookie,
                                              std::make_unique<LinearFakeValueGenerator>(request));
            break;
        }
        case FakeDataCommand::StartJson: {
            LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
            if (v.stringValue.empty()) {
                LOG(ERROR) << __func__ << ": path to JSON file is missing";
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = std::hash<std::string>()(v.stringValue);
            getGenerator()->registerGenerator(cookie,
                                              std::make_unique<JsonFakeValueGenerator>(request));
            break;
        }
        case FakeDataCommand::StopLinear: {
            LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
            if (v.int32Values.size() < 2) {
                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = v.int32Values[1];
            getGenerator()->unregisterGenerator(cookie);
            break;
        }
        case FakeDataCommand::StopJson: {
            LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
            if (v.stringValue.empty()) {
                LOG(ERROR) << __func__ << ": path to JSON file is missing";
                return StatusCode::INVALID_ARG;
            }
            int32_t cookie = std::hash<std::string>()(v.stringValue);
            getGenerator()->unregisterGenerator(cookie);
            break;
        }
        case FakeDataCommand::KeyPress: {
            LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
            int32_t keyCode = request.value.int32Values[2];
            int32_t display = request.value.int32Values[3];
            // Send back to HAL
            onPropertyValueFromCar(
                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
                    updateStatus);
            onPropertyValueFromCar(
                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
                    updateStatus);
            break;
        }
        default: {
            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
            return StatusCode::INVALID_ARG;
        }
    }
    return StatusCode::OK;
}

VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
    VehicleApPowerStateReq state, int32_t param) {
    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
    req->areaId = 0;
    req->timestamp = elapsedRealtimeNano();
    req->status = VehiclePropertyStatus::AVAILABLE;
    req->value.int32Values[0] = toInt(state);
    req->value.int32Values[1] = param;
    return req;
}

VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
        VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
    keyEvent->areaId = 0;
    keyEvent->timestamp = elapsedRealtimeNano();
    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
    keyEvent->value.int32Values[0] = toInt(action);
    keyEvent->value.int32Values[1] = keyCode;
    keyEvent->value.int32Values[2] = targetDisplay;
    return keyEvent;
}

StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
    // Some properties need to be treated non-trivially
    switch (value.prop) {
        case kGenerateFakeDataControllingProperty:
            return handleGenerateFakeDataRequest(value);

        // set the value from vehicle side, used in end to end test.
        case kSetIntPropertyFromVehicleForTest: {
            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
            updatedPropValue->prop = value.value.int32Values[0];
            updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
            updatedPropValue->timestamp = value.value.int64Values[0];
            updatedPropValue->areaId = value.areaId;
            onPropertyValueFromCar(*updatedPropValue, updateStatus);
            return StatusCode::OK;
        }
        case kSetFloatPropertyFromVehicleForTest: {
            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
            updatedPropValue->prop = value.value.int32Values[0];
            updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
            updatedPropValue->timestamp = value.value.int64Values[0];
            updatedPropValue->areaId = value.areaId;
            onPropertyValueFromCar(*updatedPropValue, updateStatus);
            return StatusCode::OK;
        }
        case kSetBooleanPropertyFromVehicleForTest: {
            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
            updatedPropValue->prop = value.value.int32Values[1];
            updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
            updatedPropValue->timestamp = value.value.int64Values[0];
            updatedPropValue->areaId = value.areaId;
            onPropertyValueFromCar(*updatedPropValue, updateStatus);
            return StatusCode::OK;
        }

        case AP_POWER_STATE_REPORT:
            switch (value.value.int32Values[0]) {
                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
                case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
                case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
                    // CPMS is in WAIT_FOR_VHAL state, simply move to ON
                    // Send back to HAL
                    // ALWAYS update status for generated property value
                    onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
                                           true /* updateStatus */);
                    break;
                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
                case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
                    // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
                    // Send back to HAL
                    // ALWAYS update status for generated property value
                    onPropertyValueFromCar(
                            *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
                            true /* updateStatus */);
                    break;
                case toInt(VehicleApPowerStateReport::ON):
                case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
                case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
                    // Do nothing
                    break;
                default:
                    // Unknown state
                    break;
            }
            break;
        case INITIAL_USER_INFO:
            return onSetInitialUserInfo(value, updateStatus);
        default:
            break;
    }

    // In the real vhal, the value will be sent to Car ECU.
    // We just pretend it is done here and send back to HAL
    auto updatedPropValue = getValuePool()->obtain(value);
    updatedPropValue->timestamp = elapsedRealtimeNano();

    onPropertyValueFromCar(*updatedPropValue, updateStatus);
    return StatusCode::OK;
}

/**
 * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
 * indicating what the initial user should be.
 *
 * During normal circumstances, the emulator will reply right away, passing a response if
 * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
 * to boot).
 *
 * But during development / testing, the behavior can be changed using lshal dump, which must use
 * the areaId to indicate what should happen next.
 *
 * So, the behavior of set(INITIAL_USER_INFO) is:
 *
 * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
 *   lshal).
 * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
 *   InitialUserInfoResponseAction::DEFAULT
 * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
 * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
 * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
 *   this error scenario)
 * - if it's 3, then don't send a property change (so Android can emulate a timeout)
 *
 */
StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value,
                                                       bool updateStatus) {
    // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
    // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
    // LOG, it's not worth investigating why...

    if (value.value.int32Values.size() == 0) {
        LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
        return StatusCode::INVALID_ARG;
    }

    if (value.areaId != 0) {
        LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
        return StatusCode::OK;
    }
    LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);

    int32_t requestId = value.value.int32Values[0];

    // Create the update property and set common values
    auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
    updatedValue->prop = INITIAL_USER_INFO;
    updatedValue->timestamp = elapsedRealtimeNano();

    if (mInitialUserResponseFromCmd == nullptr) {
        updatedValue->value.int32Values.resize(2);
        updatedValue->value.int32Values[0] = requestId;
        updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
        LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
                  << toString(*updatedValue);
        onPropertyValueFromCar(*updatedValue, updateStatus);
        return StatusCode::OK;
    }

    // mInitialUserResponseFromCmd is used for just one request
    std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);

    // TODO(b/138709788): rather than populate the raw values directly, it should use the
    // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)

    switch (response->areaId) {
        case 1:
            LOG(INFO) << "returning response with right request id";
            *updatedValue = *response;
            updatedValue->areaId = 0;
            updatedValue->value.int32Values[0] = requestId;
            break;
        case 2:
            LOG(INFO) << "returning response with wrong request id";
            *updatedValue = *response;
            updatedValue->areaId = 0;
            updatedValue->value.int32Values[0] = -requestId;
            break;
        case 3:
            LOG(INFO) << "not generating a property change event because of lshal prop: "
                      << toString(*response);
            return StatusCode::OK;
        default:
            LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
            return StatusCode::INTERNAL_ERROR;
    }

    LOG(INFO) << "updating property to: " << toString(*updatedValue);
    onPropertyValueFromCar(*updatedValue, updateStatus);
    return StatusCode::OK;
}


bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
                                          const hidl_vec<hidl_string>& options) {
                                          const hidl_vec<hidl_string>& options) {
    int fd = handle->data[0];
    int fd = handle->data[0];


@@ -401,7 +71,7 @@ bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
    return true;
    return true;
}
}


void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) {
    if (mInitialUserResponseFromCmd != nullptr) {
    if (mInitialUserResponseFromCmd != nullptr) {
        dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
        dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
                toString(*mInitialUserResponseFromCmd).c_str());
                toString(*mInitialUserResponseFromCmd).c_str());
@@ -410,7 +80,7 @@ void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
    }
    }
}
}


EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
PassthroughConnectorPtr makeEmulatedPassthroughConnector() {
    return std::make_unique<EmulatedPassthroughConnector>();
    return std::make_unique<EmulatedPassthroughConnector>();
}
}


+5 −64
Original line number Original line Diff line number Diff line
@@ -18,9 +18,9 @@
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_


#include <vhal_v2_0/VehicleConnector.h>
#include <vhal_v2_0/VehicleConnector.h>
#include <vhal_v2_0/VehicleHal.h>


#include "GeneratorHub.h"
#include "VehicleHalClient.h"
#include "VehicleHalServer.h"


namespace android {
namespace android {
namespace hardware {
namespace hardware {
@@ -30,69 +30,10 @@ namespace V2_0 {


namespace impl {
namespace impl {


// Extension of the client/server interfaces for emulated vehicle
using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;


class EmulatedVehicleClient : public IVehicleClient {
PassthroughConnectorPtr makeEmulatedPassthroughConnector();
  public:
    // Type of callback function for handling the new property values
    using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;

    // Method from IVehicleClient
    void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;

    void registerPropertyValueCallback(PropertyCallBackType&& callback);

  private:
    PropertyCallBackType mPropCallback;
};

class EmulatedVehicleServer : public IVehicleServer {
  public:
    // Methods from IVehicleServer

    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;

    StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;

    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;

    // Set the Property Value Pool used in this server
    void setValuePool(VehiclePropValuePool* valuePool);

  private:
    GeneratorHub* getGenerator();

    VehiclePropValuePool* getValuePool() const;

    void onFakeValueGenerated(const VehiclePropValue& value);

    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);

    VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);

    VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
                                                         int32_t keyCode, int32_t targetDisplay);

    // private data members

    GeneratorHub mGeneratorHub{
            std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};

    VehiclePropValuePool* mValuePool{nullptr};

    // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
    StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
    void dumpUserHal(int fd, std::string indent);
};

// Helper functions

using EmulatedPassthroughConnector =
        IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;

EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();


}  // namespace impl
}  // namespace impl


+3 −4
Original line number Original line Diff line number Diff line
@@ -87,12 +87,11 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt
    return sensorStore;
    return sensorStore;
}
}


EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
                                       EmulatedVehicleClient* client)
    : mPropStore(propStore),
    : mPropStore(propStore),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
      mRecurrentTimer(
      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
          std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
                                std::placeholders::_1)),
      mVehicleClient(client) {
      mVehicleClient(client) {
    initStaticConfig();
    initStaticConfig();
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
    for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+2 −2
Original line number Original line Diff line number Diff line
@@ -46,7 +46,7 @@ namespace impl {
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
class EmulatedVehicleHal : public EmulatedVehicleHalIface {
public:
public:
    EmulatedVehicleHal(VehiclePropertyStore* propStore,
    EmulatedVehicleHal(VehiclePropertyStore* propStore,
                       EmulatedVehicleClient* client);
                       VehicleHalClient* client);
    ~EmulatedVehicleHal() = default;
    ~EmulatedVehicleHal() = default;


    //  Methods from VehicleHal
    //  Methods from VehicleHal
@@ -85,7 +85,7 @@ private:
    VehiclePropertyStore* mPropStore;
    VehiclePropertyStore* mPropStore;
    std::unordered_set<int32_t> mHvacPowerProps;
    std::unordered_set<int32_t> mHvacPowerProps;
    RecurrentTimer mRecurrentTimer;
    RecurrentTimer mRecurrentTimer;
    EmulatedVehicleClient* mVehicleClient;
    VehicleHalClient* mVehicleClient;
};
};


}  // impl
}  // impl
Loading