Merge "Pass property set error to subscribed clients." into udc-qpr-dev

This commit is contained in:
Treehugger Robot
2023-07-10 21:07:10 +00:00
committed by Android (Google) Code Review
12 changed files with 198 additions and 14 deletions

View File

@@ -1808,6 +1808,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;

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);

View File

@@ -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());

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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] {

View File

@@ -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

View File

@@ -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

View File

@@ -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>&)>