mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Merge changes from topic "rvc-dev-trout" into rvc-dev
* changes: Merge nested namesapces Split client and server impl Split vehicle client and server interface header Add headers and macros for building VHAL server for AGL
This commit is contained in:
committed by
Android (Google) Code Review
commit
7bb7ec3df4
@@ -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",
|
||||
|
||||
@@ -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 <vector>
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
|
||||
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<VehiclePropConfig> 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<hidl_string>& /* options */) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace android::hardware::automotive::vehicle::V2_0
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
|
||||
#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<VehiclePropConfig> 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<hidl_string>& /* 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<VehiclePropConfig> 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<hidl_string>& /* 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
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.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 <vector>
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
|
||||
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<VehiclePropConfig> 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<hidl_string>& /* options */) {
|
||||
return true;
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
};
|
||||
|
||||
} // namespace android::hardware::automotive::vehicle::V2_0
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <hidl/HidlSupport.h>
|
||||
#endif
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
|
||||
@@ -69,6 +71,8 @@ size_t getVehicleRawValueVectorSize(
|
||||
void copyVehicleRawValue(VehiclePropValue::RawValue* dest,
|
||||
const VehiclePropValue::RawValue& src);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
template<typename T>
|
||||
void shallowCopyHidlVec(hidl_vec<T>* dest, const hidl_vec<T>& 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
|
||||
|
||||
@@ -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<VehiclePropValue>::recycle(o);
|
||||
|
||||
@@ -52,7 +52,7 @@ std::unique_ptr<VehiclePropValue> 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<typename T>
|
||||
inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& 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<typename T>
|
||||
inline void copyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& src) {
|
||||
for (size_t i = 0; i < std::min(dest->size(), src.size()); i++) {
|
||||
(*dest)[i] = src[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void shallowCopyHidlVec(hidl_vec <T>* dest, const hidl_vec <T>& 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
|
||||
|
||||
|
||||
@@ -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 <android/hardware/automotive/vehicle/2.0/IVehicle.h>
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
#include <vhal_v2_0/VehicleUtils.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace automotive {
|
||||
@@ -1017,7 +1019,6 @@ const ConfigDeclaration kVehicleProperties[]{
|
||||
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
|
||||
},
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
} // impl
|
||||
|
||||
@@ -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<hidl_string>& 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<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
|
||||
std::vector<VehiclePropConfig> vehiclePropConfigs;
|
||||
constexpr size_t numOfVehiclePropConfigs =
|
||||
sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
|
||||
vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
|
||||
for (auto& it : kVehicleProperties) {
|
||||
vehiclePropConfigs.emplace_back(it.config);
|
||||
}
|
||||
return vehiclePropConfigs;
|
||||
}
|
||||
|
||||
StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
|
||||
constexpr bool updateStatus = true;
|
||||
|
||||
LOG(INFO) << __func__;
|
||||
const auto& v = request.value;
|
||||
if (!v.int32Values.size()) {
|
||||
LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
|
||||
FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
|
||||
|
||||
switch (command) {
|
||||
case FakeDataCommand::StartLinear: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
|
||||
if (v.int32Values.size() < 2) {
|
||||
LOG(ERROR) << __func__ << ": expected property ID in int32Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
if (!v.int64Values.size()) {
|
||||
LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
if (v.floatValues.size() < 3) {
|
||||
LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
|
||||
<< v.floatValues.size();
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = v.int32Values[1];
|
||||
getGenerator()->registerGenerator(cookie,
|
||||
std::make_unique<LinearFakeValueGenerator>(request));
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StartJson: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
|
||||
if (v.stringValue.empty()) {
|
||||
LOG(ERROR) << __func__ << ": path to JSON file is missing";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = std::hash<std::string>()(v.stringValue);
|
||||
getGenerator()->registerGenerator(cookie,
|
||||
std::make_unique<JsonFakeValueGenerator>(request));
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StopLinear: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
|
||||
if (v.int32Values.size() < 2) {
|
||||
LOG(ERROR) << __func__ << ": expected property ID in int32Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = v.int32Values[1];
|
||||
getGenerator()->unregisterGenerator(cookie);
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StopJson: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
|
||||
if (v.stringValue.empty()) {
|
||||
LOG(ERROR) << __func__ << ": path to JSON file is missing";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = std::hash<std::string>()(v.stringValue);
|
||||
getGenerator()->unregisterGenerator(cookie);
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::KeyPress: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
|
||||
int32_t keyCode = request.value.int32Values[2];
|
||||
int32_t display = request.value.int32Values[3];
|
||||
// Send back to HAL
|
||||
onPropertyValueFromCar(
|
||||
*createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
|
||||
updateStatus);
|
||||
onPropertyValueFromCar(
|
||||
*createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
|
||||
updateStatus);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
|
||||
VehicleApPowerStateReq state, int32_t param) {
|
||||
auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
|
||||
req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
|
||||
req->areaId = 0;
|
||||
req->timestamp = elapsedRealtimeNano();
|
||||
req->status = VehiclePropertyStatus::AVAILABLE;
|
||||
req->value.int32Values[0] = toInt(state);
|
||||
req->value.int32Values[1] = param;
|
||||
return req;
|
||||
}
|
||||
|
||||
VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
|
||||
VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
|
||||
auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
|
||||
keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
|
||||
keyEvent->areaId = 0;
|
||||
keyEvent->timestamp = elapsedRealtimeNano();
|
||||
keyEvent->status = VehiclePropertyStatus::AVAILABLE;
|
||||
keyEvent->value.int32Values[0] = toInt(action);
|
||||
keyEvent->value.int32Values[1] = keyCode;
|
||||
keyEvent->value.int32Values[2] = targetDisplay;
|
||||
return keyEvent;
|
||||
}
|
||||
|
||||
StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
|
||||
// Some properties need to be treated non-trivially
|
||||
switch (value.prop) {
|
||||
case kGenerateFakeDataControllingProperty:
|
||||
return handleGenerateFakeDataRequest(value);
|
||||
|
||||
// set the value from vehicle side, used in end to end test.
|
||||
case kSetIntPropertyFromVehicleForTest: {
|
||||
auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
|
||||
updatedPropValue->prop = value.value.int32Values[0];
|
||||
updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
|
||||
updatedPropValue->timestamp = value.value.int64Values[0];
|
||||
updatedPropValue->areaId = value.areaId;
|
||||
onPropertyValueFromCar(*updatedPropValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
case kSetFloatPropertyFromVehicleForTest: {
|
||||
auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
|
||||
updatedPropValue->prop = value.value.int32Values[0];
|
||||
updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
|
||||
updatedPropValue->timestamp = value.value.int64Values[0];
|
||||
updatedPropValue->areaId = value.areaId;
|
||||
onPropertyValueFromCar(*updatedPropValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
case kSetBooleanPropertyFromVehicleForTest: {
|
||||
auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
|
||||
updatedPropValue->prop = value.value.int32Values[1];
|
||||
updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
|
||||
updatedPropValue->timestamp = value.value.int64Values[0];
|
||||
updatedPropValue->areaId = value.areaId;
|
||||
onPropertyValueFromCar(*updatedPropValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
case AP_POWER_STATE_REPORT:
|
||||
switch (value.value.int32Values[0]) {
|
||||
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
|
||||
case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
|
||||
case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
|
||||
// CPMS is in WAIT_FOR_VHAL state, simply move to ON
|
||||
// Send back to HAL
|
||||
// ALWAYS update status for generated property value
|
||||
onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
|
||||
true /* updateStatus */);
|
||||
break;
|
||||
case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
|
||||
case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
|
||||
// CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
|
||||
// Send back to HAL
|
||||
// ALWAYS update status for generated property value
|
||||
onPropertyValueFromCar(
|
||||
*createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
|
||||
true /* updateStatus */);
|
||||
break;
|
||||
case toInt(VehicleApPowerStateReport::ON):
|
||||
case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
|
||||
case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
// Unknown state
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INITIAL_USER_INFO:
|
||||
return onSetInitialUserInfo(value, updateStatus);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// In the real vhal, the value will be sent to Car ECU.
|
||||
// We just pretend it is done here and send back to HAL
|
||||
auto updatedPropValue = getValuePool()->obtain(value);
|
||||
updatedPropValue->timestamp = elapsedRealtimeNano();
|
||||
|
||||
onPropertyValueFromCar(*updatedPropValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
|
||||
* indicating what the initial user should be.
|
||||
*
|
||||
* During normal circumstances, the emulator will reply right away, passing a response if
|
||||
* InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
|
||||
* to boot).
|
||||
*
|
||||
* But during development / testing, the behavior can be changed using lshal dump, which must use
|
||||
* the areaId to indicate what should happen next.
|
||||
*
|
||||
* So, the behavior of set(INITIAL_USER_INFO) is:
|
||||
*
|
||||
* - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
|
||||
* lshal).
|
||||
* - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
|
||||
* InitialUserInfoResponseAction::DEFAULT
|
||||
* - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
|
||||
* - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
|
||||
* - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
|
||||
* this error scenario)
|
||||
* - if it's 3, then don't send a property change (so Android can emulate a timeout)
|
||||
*
|
||||
*/
|
||||
StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value,
|
||||
bool updateStatus) {
|
||||
// TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
|
||||
// (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
|
||||
// LOG, it's not worth investigating why...
|
||||
|
||||
if (value.value.int32Values.size() == 0) {
|
||||
LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
|
||||
if (value.areaId != 0) {
|
||||
LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
|
||||
mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
|
||||
return StatusCode::OK;
|
||||
}
|
||||
LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
|
||||
|
||||
int32_t requestId = value.value.int32Values[0];
|
||||
|
||||
// Create the update property and set common values
|
||||
auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
|
||||
updatedValue->prop = INITIAL_USER_INFO;
|
||||
updatedValue->timestamp = elapsedRealtimeNano();
|
||||
|
||||
if (mInitialUserResponseFromCmd == nullptr) {
|
||||
updatedValue->value.int32Values.resize(2);
|
||||
updatedValue->value.int32Values[0] = requestId;
|
||||
updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
|
||||
LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
|
||||
<< toString(*updatedValue);
|
||||
onPropertyValueFromCar(*updatedValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
// mInitialUserResponseFromCmd is used for just one request
|
||||
std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
|
||||
|
||||
// TODO(b/138709788): rather than populate the raw values directly, it should use the
|
||||
// libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
|
||||
|
||||
switch (response->areaId) {
|
||||
case 1:
|
||||
LOG(INFO) << "returning response with right request id";
|
||||
*updatedValue = *response;
|
||||
updatedValue->areaId = 0;
|
||||
updatedValue->value.int32Values[0] = requestId;
|
||||
break;
|
||||
case 2:
|
||||
LOG(INFO) << "returning response with wrong request id";
|
||||
*updatedValue = *response;
|
||||
updatedValue->areaId = 0;
|
||||
updatedValue->value.int32Values[0] = -requestId;
|
||||
break;
|
||||
case 3:
|
||||
LOG(INFO) << "not generating a property change event because of lshal prop: "
|
||||
<< toString(*response);
|
||||
return StatusCode::OK;
|
||||
default:
|
||||
LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
|
||||
return StatusCode::INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
LOG(INFO) << "updating property to: " << toString(*updatedValue);
|
||||
onPropertyValueFromCar(*updatedValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
|
||||
const hidl_vec<hidl_string>& options) {
|
||||
bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
|
||||
const hidl_vec<hidl_string>& 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<EmulatedPassthroughConnector>();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
#define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
|
||||
|
||||
#include <vhal_v2_0/VehicleConnector.h>
|
||||
#include <vhal_v2_0/VehicleHal.h>
|
||||
|
||||
#include "GeneratorHub.h"
|
||||
#include "VehicleHalClient.h"
|
||||
#include "VehicleHalServer.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
@@ -30,69 +30,10 @@ namespace V2_0 {
|
||||
|
||||
namespace impl {
|
||||
|
||||
// Extension of the client/server interfaces for emulated vehicle
|
||||
using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
|
||||
using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;
|
||||
|
||||
class EmulatedVehicleClient : public IVehicleClient {
|
||||
public:
|
||||
// Type of callback function for handling the new property values
|
||||
using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
|
||||
|
||||
// Method from IVehicleClient
|
||||
void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
|
||||
|
||||
void registerPropertyValueCallback(PropertyCallBackType&& callback);
|
||||
|
||||
private:
|
||||
PropertyCallBackType mPropCallback;
|
||||
};
|
||||
|
||||
class EmulatedVehicleServer : public IVehicleServer {
|
||||
public:
|
||||
// Methods from IVehicleServer
|
||||
|
||||
std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
|
||||
|
||||
StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
|
||||
|
||||
bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
|
||||
|
||||
// Set the Property Value Pool used in this server
|
||||
void setValuePool(VehiclePropValuePool* valuePool);
|
||||
|
||||
private:
|
||||
GeneratorHub* getGenerator();
|
||||
|
||||
VehiclePropValuePool* getValuePool() const;
|
||||
|
||||
void onFakeValueGenerated(const VehiclePropValue& value);
|
||||
|
||||
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
|
||||
|
||||
VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
|
||||
|
||||
VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
|
||||
int32_t keyCode, int32_t targetDisplay);
|
||||
|
||||
// private data members
|
||||
|
||||
GeneratorHub mGeneratorHub{
|
||||
std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
|
||||
|
||||
VehiclePropValuePool* mValuePool{nullptr};
|
||||
|
||||
// TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
|
||||
std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
|
||||
StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
|
||||
void dumpUserHal(int fd, std::string indent);
|
||||
};
|
||||
|
||||
// Helper functions
|
||||
|
||||
using EmulatedPassthroughConnector =
|
||||
IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
|
||||
using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
|
||||
|
||||
EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
|
||||
PassthroughConnectorPtr makeEmulatedPassthroughConnector();
|
||||
|
||||
} // namespace impl
|
||||
|
||||
|
||||
@@ -87,12 +87,11 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt
|
||||
return sensorStore;
|
||||
}
|
||||
|
||||
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
|
||||
EmulatedVehicleClient* client)
|
||||
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
|
||||
: mPropStore(propStore),
|
||||
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
|
||||
mRecurrentTimer(
|
||||
std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
|
||||
mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
|
||||
std::placeholders::_1)),
|
||||
mVehicleClient(client) {
|
||||
initStaticConfig();
|
||||
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
|
||||
|
||||
@@ -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<int32_t> mHvacPowerProps;
|
||||
RecurrentTimer mRecurrentTimer;
|
||||
EmulatedVehicleClient* mVehicleClient;
|
||||
VehicleHalClient* mVehicleClient;
|
||||
};
|
||||
|
||||
} // impl
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include <android/hardware/automotive/vehicle/2.0/types.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace automotive {
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 <android-base/logging.h>
|
||||
|
||||
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
|
||||
@@ -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 <vhal_v2_0/VehicleClient.h>
|
||||
|
||||
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<void(const VehiclePropValue&, bool updateStatus)>;
|
||||
|
||||
// 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
|
||||
@@ -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 <fstream>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
#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<VehiclePropConfig> VehicleHalServer::onGetAllPropertyConfig() const {
|
||||
std::vector<VehiclePropConfig> vehiclePropConfigs;
|
||||
constexpr size_t numOfVehiclePropConfigs =
|
||||
sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
|
||||
vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
|
||||
for (auto& it : kVehicleProperties) {
|
||||
vehiclePropConfigs.emplace_back(it.config);
|
||||
}
|
||||
return vehiclePropConfigs;
|
||||
}
|
||||
|
||||
StatusCode 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<FakeDataCommand>(v.int32Values[0]);
|
||||
|
||||
switch (command) {
|
||||
case FakeDataCommand::StartLinear: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
|
||||
if (v.int32Values.size() < 2) {
|
||||
LOG(ERROR) << __func__ << ": expected property ID in int32Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
if (!v.int64Values.size()) {
|
||||
LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
if (v.floatValues.size() < 3) {
|
||||
LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
|
||||
<< v.floatValues.size();
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = v.int32Values[1];
|
||||
getGenerator()->registerGenerator(cookie,
|
||||
std::make_unique<LinearFakeValueGenerator>(request));
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StartJson: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
|
||||
if (v.stringValue.empty()) {
|
||||
LOG(ERROR) << __func__ << ": path to JSON file is missing";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = std::hash<std::string>()(v.stringValue);
|
||||
getGenerator()->registerGenerator(cookie,
|
||||
std::make_unique<JsonFakeValueGenerator>(request));
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StopLinear: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
|
||||
if (v.int32Values.size() < 2) {
|
||||
LOG(ERROR) << __func__ << ": expected property ID in int32Values";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = v.int32Values[1];
|
||||
getGenerator()->unregisterGenerator(cookie);
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::StopJson: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
|
||||
if (v.stringValue.empty()) {
|
||||
LOG(ERROR) << __func__ << ": path to JSON file is missing";
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
int32_t cookie = std::hash<std::string>()(v.stringValue);
|
||||
getGenerator()->unregisterGenerator(cookie);
|
||||
break;
|
||||
}
|
||||
case FakeDataCommand::KeyPress: {
|
||||
LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
|
||||
int32_t keyCode = request.value.int32Values[2];
|
||||
int32_t display = request.value.int32Values[3];
|
||||
// Send back to HAL
|
||||
onPropertyValueFromCar(
|
||||
*createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
|
||||
updateStatus);
|
||||
onPropertyValueFromCar(
|
||||
*createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
|
||||
updateStatus);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
|
||||
return StatusCode::INVALID_ARG;
|
||||
}
|
||||
}
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
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<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
|
||||
|
||||
// TODO(b/138709788): rather than populate the raw values directly, it should use the
|
||||
// libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
|
||||
|
||||
switch (response->areaId) {
|
||||
case 1:
|
||||
LOG(INFO) << "returning response with right request id";
|
||||
*updatedValue = *response;
|
||||
updatedValue->areaId = 0;
|
||||
updatedValue->value.int32Values[0] = requestId;
|
||||
break;
|
||||
case 2:
|
||||
LOG(INFO) << "returning response with wrong request id";
|
||||
*updatedValue = *response;
|
||||
updatedValue->areaId = 0;
|
||||
updatedValue->value.int32Values[0] = -requestId;
|
||||
break;
|
||||
case 3:
|
||||
LOG(INFO) << "not generating a property change event because of lshal prop: "
|
||||
<< toString(*response);
|
||||
return StatusCode::OK;
|
||||
default:
|
||||
LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
|
||||
return StatusCode::INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
LOG(INFO) << "updating property to: " << toString(*updatedValue);
|
||||
onPropertyValueFromCar(*updatedValue, updateStatus);
|
||||
return StatusCode::OK;
|
||||
}
|
||||
|
||||
} // namespace android::hardware::automotive::vehicle::V2_0::impl
|
||||
@@ -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 <vhal_v2_0/VehicleObjectPool.h>
|
||||
#include <vhal_v2_0/VehicleServer.h>
|
||||
|
||||
#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<VehiclePropConfig> 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<VehiclePropValue>;
|
||||
|
||||
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<VehiclePropValue> mInitialUserResponseFromCmd;
|
||||
|
||||
private:
|
||||
GeneratorHub mGeneratorHub{
|
||||
std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)};
|
||||
|
||||
VehiclePropValuePool* mValuePool{nullptr};
|
||||
};
|
||||
|
||||
} // namespace android::hardware::automotive::vehicle::V2_0::impl
|
||||
Reference in New Issue
Block a user