diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index 8e579012cd..e529675203 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -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", diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h new file mode 100644 index 0000000000..5e4bf27d6b --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include + +#include + +namespace android::hardware::automotive::vehicle::V2_0 { + +/** + * Vehicle HAL talks to the vehicle through a client, instead of accessing + * the car bus directly, to give us more flexibility on the implementation. + * Android OS do not need direct access to the vehicle, and the communication + * channel is also customizable. + * + * Client lives on the Android (HAL) side to talk to the vehicle + */ +class IVehicleClient { + public: + IVehicleClient() = default; + + IVehicleClient(const IVehicleClient&) = delete; + + IVehicleClient& operator=(const IVehicleClient&) = delete; + + IVehicleClient(IVehicleClient&&) = default; + + virtual ~IVehicleClient() = default; + + // Get configuration of all properties from server + virtual std::vector getAllPropertyConfig() const = 0; + + // Send the set property request to server + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0; + + // Receive a new property value from server + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; + + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { + return true; + } +}; + +} // namespace android::hardware::automotive::vehicle::V2_0 diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h index 00b5afe217..2908a55c25 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h @@ -21,6 +21,9 @@ #include +#include "VehicleClient.h" +#include "VehicleServer.h" + namespace android { namespace hardware { namespace automotive { @@ -33,85 +36,6 @@ namespace V2_0 { * regardless of the underlying communication channels. */ -/** - * Vehicle HAL talks to the vehicle through a client, instead of accessing - * the car bus directly, to give us more flexibility on the implementation. - * Android OS do not need direct access to the vehicle, and the communication - * channel is also customizable. - * - * Client lives on the Android (HAL) side to talk to the vehicle - */ -class IVehicleClient { - public: - IVehicleClient() = default; - - IVehicleClient(const IVehicleClient&) = delete; - - IVehicleClient& operator=(const IVehicleClient&) = delete; - - IVehicleClient(IVehicleClient&&) = default; - - virtual ~IVehicleClient() = default; - - // Get configuration of all properties from server - virtual std::vector getAllPropertyConfig() const = 0; - - // Send the set property request to server - // updateStatus indicate if VHal should change the status of the value - // it should be false except injecting values for e2e tests - virtual StatusCode setProperty(const VehiclePropValue& value, bool updateStatus) = 0; - - // Receive a new property value from server - // updateStatus is true if and only if the value is - // generated by car (ECU/fake generator/injected) - virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0; - - // Dump method forwarded from HIDL's debug() - // If implemented, it must return whether the caller should dump its state. - virtual bool dump(const hidl_handle& /* handle */, const hidl_vec& /* options */) { - return true; - } -}; - -/** - * Server lives on the vehicle side to talk to Android HAL - */ -class IVehicleServer { - public: - IVehicleServer() = default; - - IVehicleServer(const IVehicleServer&) = delete; - - IVehicleServer& operator=(const IVehicleServer&) = delete; - - IVehicleServer(IVehicleServer&&) = default; - - virtual ~IVehicleServer() = default; - - // Receive the get property configuration request from HAL. - // Return a list of all property config - virtual std::vector onGetAllPropertyConfig() const = 0; - - // Receive the set property request from HAL. - // Process the setting and return the status code - // updateStatus indicate if VHal should change the status of the value - // it should be false except injecting values for e2e tests - virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0; - - // Receive a new property value from car (via direct connection to the car bus or the emulator) - // and forward the value to HAL - // updateStatus is true if and only if the value is - // generated by car (ECU/fake generator/injected) - virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; - - // Dump method forwarded from HIDL's debug() - // If implemented, it must return whether the caller should dump its state. - virtual bool onDump(const hidl_handle& /* handle */, - const hidl_vec& /* options */) { - return true; - } -}; - /** * If Android has direct access to the vehicle, then the client and * the server may act in passthrough mode to avoid extra IPC diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h index 946e74ddda..e3cbf2e7cd 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h @@ -21,6 +21,7 @@ #include #include #include +#include #include diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h new file mode 100644 index 0000000000..ba9799af1b --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include + +#include + +namespace android::hardware::automotive::vehicle::V2_0 { + +/** + * Server lives on the vehicle side to talk to Android HAL. + * Note that the server may not be run on Android + */ +class IVehicleServer { + public: + IVehicleServer() = default; + + IVehicleServer(const IVehicleServer&) = delete; + + IVehicleServer& operator=(const IVehicleServer&) = delete; + + IVehicleServer(IVehicleServer&&) = default; + + virtual ~IVehicleServer() = default; + + // Receive the get property configuration request from HAL. + // Return a list of all property config + virtual std::vector onGetAllPropertyConfig() const = 0; + + // Receive the set property request from HAL. + // Process the setting and return the status code + // updateStatus indicate if VHal should change the status of the value + // it should be false except injecting values for e2e tests + virtual StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) = 0; + + // Receive a new property value from car (via direct connection to the car bus or the emulator) + // and forward the value to HAL + // updateStatus is true if and only if the value is + // generated by car (ECU/fake generator/injected) + virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0; + + // TODO (chenhaosjtuacm): fix this since there are no HIDL in non-Android OS +#ifdef __ANDROID__ + // Dump method forwarded from HIDL's debug() + // If implemented, it must return whether the caller should dump its state. + virtual bool onDump(const hidl_handle& /* handle */, + const hidl_vec& /* options */) { + return true; + } +#endif // __ANDROID__ +}; + +} // namespace android::hardware::automotive::vehicle::V2_0 diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h index f97dfa1bba..955341504c 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h @@ -19,7 +19,9 @@ #include +#ifdef __ANDROID__ #include +#endif #include @@ -69,6 +71,8 @@ size_t getVehicleRawValueVectorSize( void copyVehicleRawValue(VehiclePropValue::RawValue* dest, const VehiclePropValue::RawValue& src); +#ifdef __ANDROID__ + template void shallowCopyHidlVec(hidl_vec* dest, const hidl_vec& src); @@ -76,6 +80,8 @@ void shallowCopyHidlStr(hidl_string* dest, const hidl_string& src); void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src); +#endif // __ANDROID__ + } // namespace V2_0 } // namespace vehicle } // namespace automotive diff --git a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp index 40dd56e73d..0947c9fe8c 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleObjectPool.cpp @@ -131,7 +131,7 @@ void VehiclePropValuePool::InternalPool::recycle(VehiclePropValue* o) { ALOGE("Discarding value for prop 0x%x because it contains " "data that is not consistent with this pool. " "Expected type: %d, vector size: %zu", - o->prop, mPropType, mVectorSize); + o->prop, toInt(mPropType), mVectorSize); delete o; } else { ObjectPool::recycle(o); diff --git a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp index 5b6816ee21..c16b29a2e7 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleUtils.cpp @@ -52,7 +52,7 @@ std::unique_ptr createVehiclePropValue( case VehiclePropertyType::MIXED: break; // Valid, but nothing to do. default: - ALOGE("createVehiclePropValue: unknown type: %d", type); + ALOGE("createVehiclePropValue: unknown type: %d", toInt(type)); val.reset(nullptr); } return val; @@ -78,13 +78,6 @@ size_t getVehicleRawValueVectorSize( } } -template -inline void copyHidlVec(hidl_vec * dest, const hidl_vec & src) { - for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) { - (*dest)[i] = src[i]; - } -} - void copyVehicleRawValue(VehiclePropValue::RawValue* dest, const VehiclePropValue::RawValue& src) { dest->int32Values = src.int32Values; @@ -94,6 +87,15 @@ void copyVehicleRawValue(VehiclePropValue::RawValue* dest, dest->stringValue = src.stringValue; } +#ifdef __ANDROID__ + +template +inline void copyHidlVec(hidl_vec * dest, const hidl_vec & src) { + for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) { + (*dest)[i] = src[i]; + } +} + template void shallowCopyHidlVec(hidl_vec * dest, const hidl_vec & src) { if (src.size() > 0) { @@ -123,6 +125,7 @@ void shallowCopy(VehiclePropValue* dest, const VehiclePropValue& src) { shallowCopyHidlStr(&dest->value.stringValue, src.value.stringValue); } +#endif // __ANDROID__ //} // namespace utils diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h index 4b9480030e..53c9ffb99f 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h @@ -17,9 +17,11 @@ #ifndef android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ #define android_hardware_automotive_vehicle_V2_0_impl_DefaultConfig_H_ -#include +#include #include +#include + namespace android { namespace hardware { namespace automotive { @@ -1017,7 +1019,6 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, - }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp index 7f90914302..9c3c95facd 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp @@ -35,346 +35,16 @@ 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); -} +class EmulatedPassthroughConnector : public PassthroughConnector { + public: + bool onDump(const hidl_handle& fd, const hidl_vec& options) override; -void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { - if (mPropCallback) { - LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!"; - return; - } - mPropCallback = std::move(callback); -} + private: + void dumpUserHal(int fd, std::string indent); +}; -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 EmulatedVehicleServer::onGetAllPropertyConfig() const { - std::vector 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) { - 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(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(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()(v.stringValue); - getGenerator()->registerGenerator(cookie, - std::make_unique(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()(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 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, - const hidl_vec& options) { +bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle, + const hidl_vec& options) { int fd = handle->data[0]; if (options.size() > 0) { @@ -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()); @@ -410,7 +80,7 @@ void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) { } } -EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() { +PassthroughConnectorPtr makeEmulatedPassthroughConnector() { return std::make_unique(); } diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h index 4850d32d94..57cbb8b893 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h @@ -18,9 +18,9 @@ #define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_ #include -#include -#include "GeneratorHub.h" +#include "VehicleHalClient.h" +#include "VehicleHalServer.h" namespace android { namespace hardware { @@ -30,69 +30,10 @@ namespace V2_0 { namespace impl { -// Extension of the client/server interfaces for emulated vehicle +using PassthroughConnector = IPassThroughConnector; +using PassthroughConnectorPtr = std::unique_ptr; -class EmulatedVehicleClient : public IVehicleClient { - public: - // Type of callback function for handling the new property values - using PropertyCallBackType = std::function; - - // 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 onGetAllPropertyConfig() const override; - - StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; - - bool onDump(const hidl_handle& fd, const hidl_vec& 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 mInitialUserResponseFromCmd; - StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); - void dumpUserHal(int fd, std::string indent); -}; - -// Helper functions - -using EmulatedPassthroughConnector = - IPassThroughConnector; -using EmulatedPassthroughConnectorPtr = std::unique_ptr; - -EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector(); +PassthroughConnectorPtr makeEmulatedPassthroughConnector(); } // namespace impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp index 692c7f791f..6d5f23f7fc 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp @@ -87,12 +87,11 @@ static std::unique_ptr 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++) { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h index ebc405e04a..ebf19951b3 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h @@ -46,7 +46,7 @@ namespace impl { class EmulatedVehicleHal : public EmulatedVehicleHalIface { public: EmulatedVehicleHal(VehiclePropertyStore* propStore, - EmulatedVehicleClient* client); + VehicleHalClient* client); ~EmulatedVehicleHal() = default; // Methods from VehicleHal @@ -85,7 +85,7 @@ private: VehiclePropertyStore* mPropStore; std::unordered_set mHvacPowerProps; RecurrentTimer mRecurrentTimer; - EmulatedVehicleClient* mVehicleClient; + VehicleHalClient* mVehicleClient; }; } // impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h index d6ad77df73..2dc502b9e0 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h @@ -19,6 +19,8 @@ #include +#include + namespace android { namespace hardware { namespace automotive { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp index 7bdc97cd2b..96aaafe0b0 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp @@ -46,7 +46,8 @@ VehiclePropValue LinearFakeValueGenerator::nextEvent() { if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) { mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion; } - VehiclePropValue event = {.prop = mGenCfg.propId}; + // TODO: (chenhaosjtuacm) remove "{}" if AGL compiler updated + VehiclePropValue event = {.timestamp = {}, .areaId = {}, .prop = mGenCfg.propId}; auto& value = event.value; switch (getPropType(event.prop)) { case VehiclePropertyType::INT32: diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp new file mode 100644 index 0000000000..25ffc6d70d --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VehicleHalClient.h" + +#include + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) { + if (!mPropCallback) { + LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!"; + return; + } + return mPropCallback(value, updateStatus); +} + +void VehicleHalClient::registerPropertyValueCallback(PropertyCallBackType&& callback) { + if (mPropCallback) { + LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!"; + return; + } + mPropCallback = std::move(callback); +} + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h new file mode 100644 index 0000000000..6559e2aa84 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +// The common client operations that may be used by both native and +// virtualized VHAL clients. +class VehicleHalClient : public IVehicleClient { + public: + // Type of callback function for handling the new property values + using PropertyCallBackType = std::function; + + // Method from IVehicleClient + void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override; + + void registerPropertyValueCallback(PropertyCallBackType&& callback); + + private: + PropertyCallBackType mPropCallback; +}; + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp new file mode 100644 index 0000000000..a91ca8e770 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VehicleHalServer.h" + +#include + +#include +#include + +#include "DefaultConfig.h" +#include "JsonFakeValueGenerator.h" +#include "LinearFakeValueGenerator.h" +#include "Obd2SensorStore.h" + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +GeneratorHub* VehicleHalServer::getGenerator() { + return &mGeneratorHub; +} + +VehiclePropValuePool* VehicleHalServer::getValuePool() const { + if (!mValuePool) { + LOG(WARNING) << __func__ << ": Value pool not set!"; + } + return mValuePool; +} + +void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) { + if (!valuePool) { + LOG(WARNING) << __func__ << ": Setting value pool to nullptr!"; + } + mValuePool = valuePool; +} + +void VehicleHalServer::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 VehicleHalServer::onGetAllPropertyConfig() const { + std::vector 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 VehicleHalServer::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(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(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()(v.stringValue); + getGenerator()->registerGenerator(cookie, + std::make_unique(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()(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; +} + +VehicleHalServer::VehiclePropValuePtr VehicleHalServer::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; +} + +VehicleHalServer::VehiclePropValuePtr VehicleHalServer::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 VehicleHalServer::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 VehicleHalServer::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 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; +} + +} // namespace android::hardware::automotive::vehicle::V2_0::impl diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h new file mode 100644 index 0000000000..b1ae106331 --- /dev/null +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 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. + */ + +#pragma once + +#include +#include + +#include "GeneratorHub.h" + +namespace android::hardware::automotive::vehicle::V2_0::impl { + +// This contains the common server operations that will be used by +// both native and virtualized VHAL server. Notice that in the virtualized +// scenario, the server may be run on a different OS than Android. +class VehicleHalServer : public IVehicleServer { + public: + // Methods from IVehicleServer + + std::vector onGetAllPropertyConfig() const override; + + StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override; + + // Set the Property Value Pool used in this server + void setValuePool(VehiclePropValuePool* valuePool); + + private: + using VehiclePropValuePtr = recyclable_ptr; + + GeneratorHub* getGenerator(); + + VehiclePropValuePool* getValuePool() const; + + void onFakeValueGenerated(const VehiclePropValue& value); + + StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request); + + VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param); + + VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode, + int32_t targetDisplay); + + StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus); + + // data members + + protected: + // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class + std::unique_ptr mInitialUserResponseFromCmd; + + private: + GeneratorHub mGeneratorHub{ + std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)}; + + VehiclePropValuePool* mValuePool{nullptr}; +}; + +} // namespace android::hardware::automotive::vehicle::V2_0::impl