Loading automotive/vehicle/2.0/default/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,8 @@ cc_library_static { "impl/vhal_v2_0/CommConn.cpp", "impl/vhal_v2_0/EmulatedVehicleConnector.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/PipeComm.cpp", "impl/vhal_v2_0/ProtoMessageConverter.cpp", Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +10 −340 Original line number Diff line number Diff line Loading @@ -35,345 +35,15 @@ namespace V2_0 { namespace impl { void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { if (!mPropCallback) { LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; 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; } class EmulatedPassthroughConnector : public PassthroughConnector { public: bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { constexpr bool updateStatus = true; 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; } private: void dumpUserHal(int fd, std::string indent); }; bool EmulatedVehicleServer::onDump(const hidl_handle& handle, bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, const hidl_vec<hidl_string>& options) { int fd = handle->data[0]; Loading Loading @@ -401,7 +71,7 @@ bool EmulatedVehicleServer::onDump(const hidl_handle& handle, return true; } void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) { if (mInitialUserResponseFromCmd != nullptr) { dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(), toString(*mInitialUserResponseFromCmd).c_str()); Loading @@ -410,7 +80,7 @@ void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { } } EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { PassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique<EmulatedPassthroughConnector>(); } Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +5 −64 Original line number Diff line number Diff line Loading @@ -18,9 +18,9 @@ #define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_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 hardware { Loading @@ -30,69 +30,10 @@ namespace V2_0 { 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 { 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(); PassthroughConnectorPtr makeEmulatedPassthroughConnector(); } // namespace impl Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -87,12 +87,11 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt return sensorStore; } EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, EmulatedVehicleClient* client) EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer( std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), mVehicleClient(client) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { Loading automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +2 −2 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ namespace impl { class EmulatedVehicleHal : public EmulatedVehicleHalIface { public: EmulatedVehicleHal(VehiclePropertyStore* propStore, EmulatedVehicleClient* client); VehicleHalClient* client); ~EmulatedVehicleHal() = default; // Methods from VehicleHal Loading Loading @@ -85,7 +85,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; EmulatedVehicleClient* mVehicleClient; VehicleHalClient* mVehicleClient; }; } // impl Loading Loading
automotive/vehicle/2.0/default/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,8 @@ cc_library_static { "impl/vhal_v2_0/CommConn.cpp", "impl/vhal_v2_0/EmulatedVehicleConnector.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/PipeComm.cpp", "impl/vhal_v2_0/ProtoMessageConverter.cpp", Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +10 −340 Original line number Diff line number Diff line Loading @@ -35,345 +35,15 @@ namespace V2_0 { namespace impl { void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { if (!mPropCallback) { LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; 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; } class EmulatedPassthroughConnector : public PassthroughConnector { public: bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) { constexpr bool updateStatus = true; 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; } private: void dumpUserHal(int fd, std::string indent); }; bool EmulatedVehicleServer::onDump(const hidl_handle& handle, bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, const hidl_vec<hidl_string>& options) { int fd = handle->data[0]; Loading Loading @@ -401,7 +71,7 @@ bool EmulatedVehicleServer::onDump(const hidl_handle& handle, return true; } void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) { if (mInitialUserResponseFromCmd != nullptr) { dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(), toString(*mInitialUserResponseFromCmd).c_str()); Loading @@ -410,7 +80,7 @@ void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { } } EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { PassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique<EmulatedPassthroughConnector>(); } Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +5 −64 Original line number Diff line number Diff line Loading @@ -18,9 +18,9 @@ #define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_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 hardware { Loading @@ -30,69 +30,10 @@ namespace V2_0 { 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 { 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(); PassthroughConnectorPtr makeEmulatedPassthroughConnector(); } // namespace impl Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -87,12 +87,11 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt return sensorStore; } EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, EmulatedVehicleClient* client) EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client) : mPropStore(propStore), mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)), mRecurrentTimer( std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)), mVehicleClient(client) { initStaticConfig(); for (size_t i = 0; i < arraysize(kVehicleProperties); i++) { Loading
automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +2 −2 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ namespace impl { class EmulatedVehicleHal : public EmulatedVehicleHalIface { public: EmulatedVehicleHal(VehiclePropertyStore* propStore, EmulatedVehicleClient* client); VehicleHalClient* client); ~EmulatedVehicleHal() = default; // Methods from VehicleHal Loading Loading @@ -85,7 +85,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set<int32_t> mHvacPowerProps; RecurrentTimer mRecurrentTimer; EmulatedVehicleClient* mVehicleClient; VehicleHalClient* mVehicleClient; }; } // impl Loading