From d599096596a3332cb855552df1d1fe1a4ba5a5ad Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Thu, 13 Feb 2020 16:37:33 -0800 Subject: [PATCH 1/4] Add headers and macros for building VHAL server for AGL It won't change the logic of Android codes. Bug: 148877226 Bug: 150791171 Test: Android build won't break Change-Id: I07006a4a3e20900a2fa90b84167d114f9ac45cfe (cherry picked from commit 080963546aabc1ee9c06b5309f2d1dc1aec218f0) Merged-In: I07006a4a3e20900a2fa90b84167d114f9ac45cfe --- .../include/vhal_v2_0/VehicleObjectPool.h | 1 + .../common/include/vhal_v2_0/VehicleUtils.h | 6 ++++++ .../default/common/src/VehicleObjectPool.cpp | 2 +- .../2.0/default/common/src/VehicleUtils.cpp | 19 +++++++++++-------- .../default/impl/vhal_v2_0/DefaultConfig.h | 5 +++-- .../impl/vhal_v2_0/FakeValueGenerator.h | 2 ++ .../vhal_v2_0/LinearFakeValueGenerator.cpp | 3 ++- 7 files changed, 26 insertions(+), 12 deletions(-) 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/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/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: From 2f2b3bbef6abf45ef1eb122f19afdb2f82832781 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 14 Feb 2020 11:26:03 -0800 Subject: [PATCH 2/4] Split vehicle client and server interface header Since vehicle client may contains some Android-specific types/headers that may not exist on AGL, we split the header into "client" and "server". It won't change the logic of Android codes. Bug: 148877226 Bug: 150791171 Test: build Change-Id: I550034b071ca6a7ca322fb26b61d76ed4a7307ee (cherry picked from commit 8dfac92fee6e1543f03687ff85cebb0247256766) Merged-In: I550034b071ca6a7ca322fb26b61d76ed4a7307ee --- .../common/include/vhal_v2_0/VehicleClient.h | 73 +++++++++++++++++ .../include/vhal_v2_0/VehicleConnector.h | 82 +------------------ .../common/include/vhal_v2_0/VehicleServer.h | 76 +++++++++++++++++ 3 files changed, 152 insertions(+), 79 deletions(-) create mode 100644 automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h create mode 100644 automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h 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..1e2f3add17 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h @@ -0,0 +1,73 @@ +/* + * 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 { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace 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 V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android 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/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h new file mode 100644 index 0000000000..27ebbeef55 --- /dev/null +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h @@ -0,0 +1,76 @@ +/* + * 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 { +namespace hardware { +namespace automotive { +namespace vehicle { +namespace 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 V2_0 +} // namespace vehicle +} // namespace automotive +} // namespace hardware +} // namespace android From a6d6fa3d9d5e3c27f08f52c4f70a39b6d4f05c88 Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Fri, 14 Feb 2020 11:51:26 -0800 Subject: [PATCH 3/4] Split client and server impl Some of the code in VHAL client implementation contains Android-specific code, and some of the server operations only works in the native case. So we split them up so that the AGL VHAL server can selectivly pick the parts it needs. It won't change the logic of native VHAL. Bug: 148877226 Bug: 150791171 Test: Build Change-Id: Ie142b19a5c435a0b4252ffd297504bde69eb44b0 (cherry picked from commit 7e9e37fa0a6278f1af454229cafc0707c27cd4c3) Merged-In: Ie142b19a5c435a0b4252ffd297504bde69eb44b0 --- automotive/vehicle/2.0/default/Android.bp | 2 + .../vhal_v2_0/EmulatedVehicleConnector.cpp | 350 +---------------- .../impl/vhal_v2_0/EmulatedVehicleConnector.h | 69 +--- .../impl/vhal_v2_0/EmulatedVehicleHal.cpp | 7 +- .../impl/vhal_v2_0/EmulatedVehicleHal.h | 4 +- .../impl/vhal_v2_0/VehicleHalClient.cpp | 39 ++ .../default/impl/vhal_v2_0/VehicleHalClient.h | 39 ++ .../impl/vhal_v2_0/VehicleHalServer.cpp | 353 ++++++++++++++++++ .../default/impl/vhal_v2_0/VehicleHalServer.h | 71 ++++ 9 files changed, 524 insertions(+), 410 deletions(-) create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp create mode 100644 automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h 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/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/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 From f724a227b057ad8fdf6b33082c00923901bd710b Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Tue, 25 Feb 2020 13:20:41 -0800 Subject: [PATCH 4/4] Merge nested namesapces fix the nits in ag/10318156 Bug: 150791171 Test: build Change-Id: I44609f8c7cbeffcb02cb9f2e2f56f3a829de17f6 Merged-In: I44609f8c7cbeffcb02cb9f2e2f56f3a829de17f6 --- .../default/common/include/vhal_v2_0/VehicleClient.h | 12 ++---------- .../default/common/include/vhal_v2_0/VehicleServer.h | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) 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 index 1e2f3add17..5e4bf27d6b 100644 --- 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 @@ -20,11 +20,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { +namespace android::hardware::automotive::vehicle::V2_0 { /** * Vehicle HAL talks to the vehicle through a client, instead of accessing @@ -66,8 +62,4 @@ class IVehicleClient { } }; -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::vehicle::V2_0 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 index 27ebbeef55..ba9799af1b 100644 --- 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 @@ -20,11 +20,7 @@ #include -namespace android { -namespace hardware { -namespace automotive { -namespace vehicle { -namespace V2_0 { +namespace android::hardware::automotive::vehicle::V2_0 { /** * Server lives on the vehicle side to talk to Android HAL. @@ -69,8 +65,4 @@ class IVehicleServer { #endif // __ANDROID__ }; -} // namespace V2_0 -} // namespace vehicle -} // namespace automotive -} // namespace hardware -} // namespace android +} // namespace android::hardware::automotive::vehicle::V2_0