mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:50:18 +00:00
Merge "Pass property set error to subscribed clients." into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
9c5889cecb
@@ -1833,6 +1833,7 @@ void FakeVehicleHardware::registerOnPropertyChangeEvent(
|
||||
|
||||
void FakeVehicleHardware::registerOnPropertySetErrorEvent(
|
||||
std::unique_ptr<const PropertySetErrorCallback> callback) {
|
||||
// In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback.
|
||||
if (mOnPropertySetErrorCallback != nullptr) {
|
||||
ALOGE("registerOnPropertySetErrorEvent must only be called once");
|
||||
return;
|
||||
|
||||
@@ -107,12 +107,18 @@ class SubscriptionClient final : public ConnectedClient {
|
||||
// Gets the callback to be called when the request for this client has finished.
|
||||
std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
|
||||
|
||||
// Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
|
||||
// Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
|
||||
// callback.
|
||||
static void sendUpdatedValues(
|
||||
CallbackType callback,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
|
||||
updatedValues);
|
||||
// Marshals the set property error events into largeParcelable and sends it through
|
||||
// {@code onPropertySetError} callback.
|
||||
static void sendPropertySetErrors(
|
||||
CallbackType callback,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
|
||||
vehiclePropErrors);
|
||||
|
||||
protected:
|
||||
// Gets the callback to be called when the request for this client has timeout.
|
||||
|
||||
@@ -249,10 +249,14 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
|
||||
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
|
||||
|
||||
static void onPropertyChangeEvent(
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager,
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
|
||||
updatedValues);
|
||||
|
||||
static void onPropertySetErrorEvent(
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
static void checkHealth(IVehicleHardware* hardware,
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager);
|
||||
|
||||
|
||||
@@ -99,6 +99,12 @@ class SubscriptionManager final {
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
|
||||
updatedValues);
|
||||
|
||||
// For a list of set property error events, returns a map that maps clients subscribing to the
|
||||
// properties to a list of errors for each client.
|
||||
std::unordered_map<CallbackType,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
|
||||
getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
// Checks whether the sample rate is valid.
|
||||
static bool checkSampleRateHz(float sampleRateHz);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
|
||||
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
|
||||
using ::android::base::Result;
|
||||
@@ -300,7 +302,34 @@ void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> cal
|
||||
if (ScopedAStatus callbackStatus =
|
||||
callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
|
||||
!callbackStatus.isOk()) {
|
||||
ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
|
||||
ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
|
||||
"exception: %d, service specific error: %d",
|
||||
callback->asBinder().get(), callbackStatus.getMessage(),
|
||||
callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
|
||||
}
|
||||
}
|
||||
|
||||
void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
|
||||
std::vector<VehiclePropError>&& vehiclePropErrors) {
|
||||
if (vehiclePropErrors.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VehiclePropErrors vehiclePropErrorsLargeParcelable;
|
||||
ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
|
||||
&vehiclePropErrorsLargeParcelable);
|
||||
if (!status.isOk()) {
|
||||
int statusCode = status.getServiceSpecificError();
|
||||
ALOGE("subscribe: failed to marshal result into large parcelable, error: "
|
||||
"%s, code: %d",
|
||||
status.getMessage(), statusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScopedAStatus callbackStatus =
|
||||
callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
|
||||
!callbackStatus.isOk()) {
|
||||
ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
|
||||
"exception: %d, service specific error: %d",
|
||||
callback->asBinder().get(), callbackStatus.getMessage(),
|
||||
callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
|
||||
|
||||
@@ -144,6 +144,11 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHa
|
||||
[subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
|
||||
onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
|
||||
}));
|
||||
mVehicleHardware->registerOnPropertySetErrorEvent(
|
||||
std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
|
||||
[subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
|
||||
onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
|
||||
}));
|
||||
|
||||
// Register heartbeat event.
|
||||
mRecurrentAction = std::make_shared<std::function<void()>>(
|
||||
@@ -177,7 +182,7 @@ DefaultVehicleHal::~DefaultVehicleHal() {
|
||||
}
|
||||
|
||||
void DefaultVehicleHal::onPropertyChangeEvent(
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager,
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<VehiclePropValue>& updatedValues) {
|
||||
auto manager = subscriptionManager.lock();
|
||||
if (manager == nullptr) {
|
||||
@@ -194,6 +199,20 @@ void DefaultVehicleHal::onPropertyChangeEvent(
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultVehicleHal::onPropertySetErrorEvent(
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
auto manager = subscriptionManager.lock();
|
||||
if (manager == nullptr) {
|
||||
ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
|
||||
return;
|
||||
}
|
||||
auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
|
||||
for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
|
||||
SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
|
||||
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
|
||||
@@ -692,15 +711,19 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
|
||||
// Create a new SubscriptionClient if there isn't an existing one.
|
||||
mSubscriptionClients->maybeAddClient(callback);
|
||||
|
||||
// Since we have already check the sample rates, the following functions must succeed.
|
||||
if (!onChangeSubscriptions.empty()) {
|
||||
return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
|
||||
/*isContinuousProperty=*/false));
|
||||
auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
|
||||
/*isContinuousProperty=*/false);
|
||||
if (!result.ok()) {
|
||||
return toScopedAStatus(result);
|
||||
}
|
||||
}
|
||||
if (!continuousSubscriptions.empty()) {
|
||||
return toScopedAStatus(mSubscriptionManager->subscribe(callback,
|
||||
continuousSubscriptions,
|
||||
/*isContinuousProperty=*/true));
|
||||
auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
|
||||
/*isContinuousProperty=*/true);
|
||||
if (!result.ok()) {
|
||||
return toScopedAStatus(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
|
||||
@@ -36,6 +36,7 @@ constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
|
||||
using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
|
||||
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
using ::android::base::Error;
|
||||
using ::android::base::Result;
|
||||
@@ -269,6 +270,32 @@ SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& u
|
||||
return clients;
|
||||
}
|
||||
|
||||
std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
|
||||
SubscriptionManager::getSubscribedClientsForErrorEvents(
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
|
||||
|
||||
for (const auto& errorEvent : errorEvents) {
|
||||
PropIdAreaId propIdAreaId{
|
||||
.propId = errorEvent.propId,
|
||||
.areaId = errorEvent.areaId,
|
||||
};
|
||||
if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
|
||||
clients[client].push_back({
|
||||
.propId = errorEvent.propId,
|
||||
.areaId = errorEvent.areaId,
|
||||
.errorCode = errorEvent.errorCode,
|
||||
});
|
||||
}
|
||||
}
|
||||
return clients;
|
||||
}
|
||||
|
||||
bool SubscriptionManager::isEmpty() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
|
||||
|
||||
@@ -62,6 +62,7 @@ using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
|
||||
@@ -1653,6 +1654,63 @@ TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
|
||||
ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
|
||||
std::vector<SubscribeOptions> options = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaIds = {0},
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaIds = {0},
|
||||
.sampleRate = 1,
|
||||
},
|
||||
};
|
||||
auto status = getClient()->subscribe(getCallbackClient(), options, 0);
|
||||
ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
|
||||
std::vector<SetValueErrorEvent> errorEvents = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INTERNAL_ERROR,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::ACCESS_DENIED,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INVALID_ARG,
|
||||
},
|
||||
};
|
||||
std::vector<VehiclePropError> expectedResults = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INTERNAL_ERROR,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::ACCESS_DENIED,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INVALID_ARG,
|
||||
},
|
||||
};
|
||||
getHardware()->sendOnPropertySetErrorEvent(errorEvents);
|
||||
|
||||
ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
|
||||
auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
|
||||
ASSERT_TRUE(maybeVehiclePropErrors.has_value());
|
||||
const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
|
||||
ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -81,8 +81,14 @@ ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues& resu
|
||||
return result;
|
||||
}
|
||||
|
||||
ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
|
||||
return ScopedAStatus::ok();
|
||||
ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
|
||||
ScopedAStatus result;
|
||||
{
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
result = storeResults(results, &mOnPropertySetErrorResults);
|
||||
}
|
||||
mCond.notify_all();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
|
||||
@@ -105,6 +111,16 @@ size_t MockVehicleCallback::countOnPropertyEventResults() {
|
||||
return mOnPropertyEventResults.size();
|
||||
}
|
||||
|
||||
std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return pop(mOnPropertySetErrorResults);
|
||||
}
|
||||
|
||||
size_t MockVehicleCallback::countOnPropertySetErrorResults() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return mOnPropertySetErrorResults.size();
|
||||
}
|
||||
|
||||
bool MockVehicleCallback::waitForSetValueResults(size_t size, size_t timeoutInNano) {
|
||||
std::unique_lock lk(mLock);
|
||||
return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
|
||||
|
||||
@@ -63,6 +63,9 @@ class MockVehicleCallback final
|
||||
nextSetValueResults();
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
|
||||
nextOnPropertyEventResults();
|
||||
size_t countOnPropertySetErrorResults();
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
|
||||
nextOnPropertySetErrorResults();
|
||||
size_t countOnPropertyEventResults();
|
||||
bool waitForSetValueResults(size_t size, size_t timeoutInNano);
|
||||
bool waitForGetValueResults(size_t size, size_t timeoutInNano);
|
||||
@@ -77,6 +80,8 @@ class MockVehicleCallback final
|
||||
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
|
||||
mOnPropertyEventResults GUARDED_BY(mLock);
|
||||
int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
|
||||
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
|
||||
mOnPropertySetErrorResults GUARDED_BY(mLock);
|
||||
};
|
||||
|
||||
} // namespace vehicle
|
||||
|
||||
@@ -131,8 +131,9 @@ void MockVehicleHardware::registerOnPropertyChangeEvent(
|
||||
}
|
||||
|
||||
void MockVehicleHardware::registerOnPropertySetErrorEvent(
|
||||
std::unique_ptr<const PropertySetErrorCallback>) {
|
||||
// TODO(b/200737967): mock this.
|
||||
std::unique_ptr<const PropertySetErrorCallback> callback) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
mPropertySetErrorCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
|
||||
@@ -254,6 +255,12 @@ template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, S
|
||||
std::list<std::vector<SetValueRequest>>* storedRequests,
|
||||
std::list<std::vector<SetValueResult>>* storedResponses) const;
|
||||
|
||||
void MockVehicleHardware::sendOnPropertySetErrorEvent(
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
(*mPropertySetErrorCallback)(errorEvents);
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -85,6 +85,7 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
aidl::android::hardware::automotive::vehicle::StatusCode status);
|
||||
void setSleepTime(int64_t timeInNano);
|
||||
void setDumpResult(DumpResult result);
|
||||
void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
private:
|
||||
mutable std::mutex mLock;
|
||||
@@ -104,6 +105,7 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
mStatusByFunctions GUARDED_BY(mLock);
|
||||
int64_t mSleepTime GUARDED_BY(mLock) = 0;
|
||||
std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
|
||||
std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
|
||||
std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
|
||||
std::shared_ptr<const GetValuesCallback>,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
|
||||
|
||||
Reference in New Issue
Block a user