Merge "Add TYPE_HEADING sensor type definitions."
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 49b33d5..0f0ccf1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -67,24 +67,30 @@
}
inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
- const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+ int32_t propId, int32_t areaId,
const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
if (config.areaConfigs.size() == 0) {
return nullptr;
}
- if (isGlobalProp(propValue.prop)) {
+ if (isGlobalProp(propId)) {
return &(config.areaConfigs[0]);
}
for (const auto& c : config.areaConfigs) {
- if (c.areaId == propValue.areaId) {
+ if (c.areaId == areaId) {
return &c;
}
}
return nullptr;
}
+inline const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* getAreaConfig(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config) {
+ return getAreaConfig(propValue.prop, propValue.areaId, config);
+}
+
inline std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>
createVehiclePropValueVec(::aidl::android::hardware::automotive::vehicle::VehiclePropertyType type,
size_t vecSize) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 1a79230..c1fa896 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -21,9 +21,11 @@
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
-#include <android-base/format.h>
+#include <android-base/stringprintf.h>
#include <math/HashCombine.h>
+#include <inttypes.h>
+
namespace android {
namespace hardware {
namespace automotive {
@@ -36,13 +38,14 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::Error;
using ::android::base::Result;
+using ::android::base::StringPrintf;
bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
return area == other.area && token == other.token;
}
std::string VehiclePropertyStore::RecordId::toString() const {
- return ::fmt::format("RecordID{{.areaId={:d}, .token={:d}}}", area, token);
+ return StringPrintf("RecordID{{.areaId=% " PRId32 ", .token=%" PRId64 "}", area, token);
}
size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index d8516b1..4f0b74a 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -19,6 +19,7 @@
#include "PendingRequestPool.h"
+#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
@@ -51,14 +52,14 @@
// Gets the unique ID for this client.
const void* id();
- // Add client requests. The requests would be registered as pending requests until
+ // Adds client requests. The requests would be registered as pending requests until
// {@code tryFinishRequests} is called for them.
// Returns {@code INVALID_ARG} error if any of the requestIds are duplicate with one of the
// pending request IDs or {@code TRY_AGAIN} error if the pending request pool is full and could
// no longer add requests.
::android::base::Result<void> addRequests(const std::unordered_set<int64_t>& requestIds);
- // Mark the requests as finished. Returns a list of request IDs that was pending and has been
+ // Marks the requests as finished. Returns a list of request IDs that was pending and has been
// finished. It must be a set of the requested request IDs.
std::unordered_set<int64_t> tryFinishRequests(const std::unordered_set<int64_t>& requestIds);
@@ -110,9 +111,15 @@
callback);
// Gets the callback to be called when the request for this client has finished.
- std::shared_ptr<const std::function<
- void(std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>)>>
- getResultCallback();
+ std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
+
+ // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+ // callback.
+ static void sendUpdatedValues(
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>
+ callback,
+ std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
+ updatedValues);
protected:
// Gets the callback to be called when the request for this client has timeout.
@@ -121,9 +128,8 @@
private:
// The following members are only initialized during construction.
std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
- std::shared_ptr<const std::function<void(
- std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>)>>
- mResultCallback;
+ std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
+ std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;
static void onGetValueResults(
const void* clientId,
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index b0423a3..b9975bc 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -53,7 +53,7 @@
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
- ~DefaultVehicleHal();
+ ~DefaultVehicleHal() = default;
::ndk::ScopedAStatus getAllPropConfigs(
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
@@ -93,11 +93,42 @@
GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::SetValueResult,
::aidl::android::hardware::automotive::vehicle::SetValueResults>;
+ // A thread safe class to maintain an increasing request ID for each subscribe client. This
+ // class is safe to pass to async callbacks.
+ class SubscribeIdByClient {
+ public:
+ int64_t getId(const CallbackType& callback);
+
+ private:
+ std::mutex mLock;
+ std::unordered_map<CallbackType, int64_t> mIds GUARDED_BY(mLock);
+ };
+
+ // A thread safe class to store all subscribe clients. This class is safe to pass to async
+ // callbacks.
+ class SubscriptionClients {
+ public:
+ SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
+
+ std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
+
+ size_t countClients();
+
+ private:
+ std::mutex mLock;
+ std::unordered_map<CallbackType, std::shared_ptr<SubscriptionClient>> mClients
+ GUARDED_BY(mLock);
+ // PendingRequestPool is thread-safe.
+ std::shared_ptr<PendingRequestPool> mPendingRequestPool;
+ };
+
// The default timeout of get or set value requests is 30s.
// TODO(b/214605968): define TIMEOUT_IN_NANO in IVehicle and allow getValues/setValues/subscribe
// to specify custom timeouts.
static constexpr int64_t TIMEOUT_IN_NANO = 30'000'000'000;
- const std::unique_ptr<IVehicleHardware> mVehicleHardware;
+ // heart beat event interval: 3s
+ static constexpr int64_t HEART_BEAT_INTERVAL_IN_NANO = 3'000'000'000;
+ const std::shared_ptr<IVehicleHardware> mVehicleHardware;
// mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
// lock guard them.
@@ -108,22 +139,17 @@
// PendingRequestPool is thread-safe.
std::shared_ptr<PendingRequestPool> mPendingRequestPool;
// SubscriptionManager is thread-safe.
- std::unique_ptr<SubscriptionManager> mSubscriptionManager;
+ std::shared_ptr<SubscriptionManager> mSubscriptionManager;
std::mutex mLock;
std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients
GUARDED_BY(mLock);
std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>> mSetValuesClients
GUARDED_BY(mLock);
- std::unordered_map<CallbackType, std::shared_ptr<SubscriptionClient>> mSubscriptionClients
- GUARDED_BY(mLock);
- // An increasing request ID we keep for subscribe clients.
- std::unordered_map<CallbackType, int64_t> mSubscribeIdByClient GUARDED_BY(mLock);
-
- template <class T>
- std::shared_ptr<T> getOrCreateClient(
- std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
- const CallbackType& callback) REQUIRES(mLock);
+ // SubscriptionClients is thread-safe.
+ std::shared_ptr<SubscriptionClients> mSubscriptionClients;
+ // RecurrentTimer is thread-safe.
+ RecurrentTimer mRecurrentTimer;
::android::base::Result<void> checkProperty(
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
@@ -136,10 +162,39 @@
const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
requests);
- void getValueFromHardwareCallCallback(
- const CallbackType& callback,
+ ::android::base::Result<void> checkSubscribeOptions(
+ const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
+ options);
+
+ ::android::base::Result<void> checkReadPermission(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+ ::android::base::Result<void> checkWritePermission(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+
+ ::android::base::Result<
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
+ getConfig(int32_t propId) const;
+
+ template <class T>
+ static std::shared_ptr<T> getOrCreateClient(
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
+
+ static void getValueFromHardwareCallCallback(
+ std::weak_ptr<IVehicleHardware> vehicleHardware,
+ std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+ std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+ static void onPropertyChangeEvent(
+ std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
+ updatedValues);
+
+ static void checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+ std::weak_ptr<SubscriptionManager> subscriptionManager);
+
// Test-only
// Set the default timeout for pending requests.
void setTimeout(int64_t timeoutInNano);
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 7d02a05..5ccef55 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -258,7 +258,7 @@
});
auto requestPoolCopy = mRequestPool;
const void* clientId = reinterpret_cast<const void*>(this);
- mResultCallback = std::make_shared<const std::function<void(std::vector<GetValueResult>)>>(
+ mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
[clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
onGetValueResults(clientId, callback, requestPoolCopy, results);
});
@@ -274,6 +274,32 @@
return mTimeoutCallback;
}
+void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
+ std::vector<VehiclePropValue>&& updatedValues) {
+ if (updatedValues.empty()) {
+ return;
+ }
+
+ // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
+ VehiclePropValues vehiclePropValues;
+ int32_t sharedMemoryFileCount = 0;
+ ScopedAStatus status = vectorToStableLargeParcelable(updatedValues, &vehiclePropValues);
+ 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->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
+ !callbackStatus.isOk()) {
+ ALOGE("subscribe: failed to call callback, error: %s, code: %d", status.getMessage(),
+ status.getServiceSpecificError());
+ }
+}
+
void SubscriptionClient::onGetValueResults(const void* clientId,
std::shared_ptr<IVehicleCallback> callback,
std::shared_ptr<PendingRequestPool> requestPool,
@@ -308,27 +334,7 @@
propValues.push_back(std::move(result.prop.value()));
}
- if (propValues.empty()) {
- return;
- }
- // TODO(b/205189110): Use memory pool here and fill in sharedMemoryId.
- VehiclePropValues vehiclePropValues;
- int32_t sharedMemoryFileCount = 0;
- ScopedAStatus status = vectorToStableLargeParcelable(propValues, &vehiclePropValues);
- if (!status.isOk()) {
- int statusCode = status.getServiceSpecificError();
- ALOGE("failed to marshal result into large parcelable, error: "
- "%s, code: %d",
- status.getMessage(), statusCode);
- return;
- }
-
- if (ScopedAStatus callbackStatus =
- callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
- !callbackStatus.isOk()) {
- ALOGE("failed to call callback, error: %s, code: %d", status.getMessage(),
- status.getServiceSpecificError());
- }
+ sendUpdatedValues(callback, std::move(propValues));
}
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 1e76eb7..c4cbc68 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -23,7 +23,9 @@
#include <VehicleUtils.h>
#include <android-base/result.h>
+#include <android-base/stringprintf.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <inttypes.h>
#include <set>
@@ -50,11 +52,16 @@
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
using ::android::base::Error;
using ::android::base::expected;
using ::android::base::Result;
+using ::android::base::StringPrintf;
using ::ndk::ScopedAStatus;
std::string toString(const std::unordered_set<int64_t>& values) {
@@ -70,6 +77,24 @@
} // namespace
+std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
+ const CallbackType& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return getOrCreateClient(&mClients, callback, mPendingRequestPool);
+}
+
+int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ // This would be initialized to 0 if callback does not exist in the map.
+ int64_t subscribeId = (mIds[callback])++;
+ return subscribeId;
+}
+
+size_t DefaultVehicleHal::SubscriptionClients::countClients() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mClients.size();
+}
+
DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware)
: mVehicleHardware(std::move(hardware)),
mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
@@ -90,24 +115,57 @@
mConfigFile = std::move(result.value());
}
- mSubscriptionManager = std::make_unique<SubscriptionManager>(
- [this](const CallbackType& callback, const VehiclePropValue& value) {
- getValueFromHardwareCallCallback(callback, value);
- });
+ mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
+
+ auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
+ // Make a weak copy of IVehicleHardware because subscriptionManager uses IVehicleHardware and
+ // IVehicleHardware uses subscriptionManager. We want to avoid cyclic reference.
+ std::weak_ptr<IVehicleHardware> hardwareCopy = mVehicleHardware;
+ SubscriptionManager::GetValueFunc getValueFunc = std::bind(
+ &DefaultVehicleHal::getValueFromHardwareCallCallback, hardwareCopy, subscribeIdByClient,
+ mSubscriptionClients, std::placeholders::_1, std::placeholders::_2);
+ mSubscriptionManager = std::make_shared<SubscriptionManager>(std::move(getValueFunc));
+
+ std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
+ mVehicleHardware->registerOnPropertyChangeEvent(
+ std::make_unique<IVehicleHardware::PropertyChangeCallback>(
+ [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
+ onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
+ }));
+
+ // Register heartbeat event.
+ mRecurrentTimer.registerTimerCallback(
+ HEART_BEAT_INTERVAL_IN_NANO,
+ std::make_shared<std::function<void()>>([hardwareCopy, subscriptionManagerCopy]() {
+ checkHealth(hardwareCopy, subscriptionManagerCopy);
+ }));
}
-DefaultVehicleHal::~DefaultVehicleHal() {
- // mSubscriptionManager has reference to this, so must be destroyed before other members.
- mSubscriptionManager.reset();
+void DefaultVehicleHal::onPropertyChangeEvent(
+ std::weak_ptr<SubscriptionManager> subscriptionManager,
+ const std::vector<VehiclePropValue>& updatedValues) {
+ auto manager = subscriptionManager.lock();
+ if (manager == nullptr) {
+ ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+ auto updatedValuesByClients = manager->getSubscribedClients(updatedValues);
+ for (const auto& [callback, valuePtrs] : updatedValuesByClients) {
+ std::vector<VehiclePropValue> values;
+ for (const VehiclePropValue* valuePtr : valuePtrs) {
+ values.push_back(*valuePtr);
+ }
+ SubscriptionClient::sendUpdatedValues(callback, std::move(values));
+ }
}
template <class T>
std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
- std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
- const CallbackType& callback) {
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients, const CallbackType& callback,
+ std::shared_ptr<PendingRequestPool> pendingRequestPool) {
if (clients->find(callback) == clients->end()) {
// TODO(b/204943359): Remove client from clients when linkToDeath is implemented.
- (*clients)[callback] = std::make_shared<T>(mPendingRequestPool, callback);
+ (*clients)[callback] = std::make_shared<T>(pendingRequestPool, callback);
}
return (*clients)[callback];
}
@@ -115,26 +173,23 @@
template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>>* clients,
- const CallbackType& callback);
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
template std::shared_ptr<DefaultVehicleHal::SetValuesClient>
DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>>* clients,
- const CallbackType& callback);
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
template std::shared_ptr<SubscriptionClient>
DefaultVehicleHal::getOrCreateClient<SubscriptionClient>(
std::unordered_map<CallbackType, std::shared_ptr<SubscriptionClient>>* clients,
- const CallbackType& callback);
+ const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
-void DefaultVehicleHal::getValueFromHardwareCallCallback(const CallbackType& callback,
- const VehiclePropValue& value) {
- int64_t subscribeId;
- std::shared_ptr<SubscriptionClient> client;
- {
- std::scoped_lock<std::mutex> lockGuard(mLock);
- // This is initialized to 0 if callback does not exist in the map.
- subscribeId = (mSubscribeIdByClient[callback])++;
- client = getOrCreateClient(&mSubscriptionClients, callback);
- }
+void DefaultVehicleHal::getValueFromHardwareCallCallback(
+ std::weak_ptr<IVehicleHardware> vehicleHardware,
+ std::shared_ptr<SubscribeIdByClient> subscribeIdByClient,
+ std::shared_ptr<SubscriptionClients> subscriptionClients, const CallbackType& callback,
+ const VehiclePropValue& value) {
+ int64_t subscribeId = subscribeIdByClient->getId(callback);
+ auto client = subscriptionClients->getClient(callback);
if (auto addRequestResult = client->addRequests({subscribeId}); !addRequestResult.ok()) {
ALOGE("subscribe[%" PRId64 "]: too many pending requests, ignore the getValue request",
subscribeId);
@@ -146,8 +201,12 @@
.prop = value,
}};
- if (StatusCode status =
- mVehicleHardware->getValues(client->getResultCallback(), hardwareRequests);
+ std::shared_ptr<IVehicleHardware> hardware = vehicleHardware.lock();
+ if (hardware == nullptr) {
+ ALOGW("the IVehicleHardware is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+ if (StatusCode status = hardware->getValues(client->getResultCallback(), hardwareRequests);
status != StatusCode::OK) {
// If the hardware returns error, finish all the pending requests for this request because
// we never expect hardware to call callback for these requests.
@@ -174,27 +233,35 @@
return ScopedAStatus::ok();
}
-Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
- int32_t propId = propValue.prop;
+Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
auto it = mConfigsByPropId.find(propId);
if (it == mConfigsByPropId.end()) {
return Error() << "no config for property, ID: " << propId;
}
- const VehiclePropConfig& config = it->second;
- const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, config);
+ return &(it->second);
+}
+
+Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
+ int32_t propId = propValue.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return result.error();
+ }
+ const VehiclePropConfig* config = result.value();
+ const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, *config);
if (!isGlobalProp(propId) && areaConfig == nullptr) {
// Ignore areaId for global property. For non global property, check whether areaId is
// allowed. areaId must appear in areaConfig.
return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
<< ", not listed in config";
}
- if (auto result = checkPropValue(propValue, &config); !result.ok()) {
+ if (auto result = checkPropValue(propValue, config); !result.ok()) {
return Error() << "invalid property value: " << propValue.toString()
- << ", error: " << result.error().message();
+ << ", error: " << getErrorMsg(result);
}
if (auto result = checkValueRange(propValue, areaConfig); !result.ok()) {
return Error() << "property value out of range: " << propValue.toString()
- << ", error: " << result.error().message();
+ << ", error: " << getErrorMsg(result);
}
return {};
}
@@ -215,24 +282,54 @@
ALOGE("getValues: duplicate request ID");
return toScopedAStatus(maybeRequestIds, StatusCode::INVALID_ARG);
}
+
+ // A list of failed result we already know before sending to hardware.
+ std::vector<GetValueResult> failedResults;
+ // The list of requests that we would send to hardware.
+ std::vector<GetValueRequest> hardwareRequests;
+
+ for (const auto& request : getValueRequests) {
+ if (auto result = checkReadPermission(request.prop); !result.ok()) {
+ ALOGW("property does not support reading: %s", getErrorMsg(result).c_str());
+ failedResults.push_back(GetValueResult{
+ .requestId = request.requestId,
+ .status = getErrorCode(result),
+ .prop = {},
+ });
+ } else {
+ hardwareRequests.push_back(request);
+ }
+ }
+
// The set of request Ids that we would send to hardware.
- std::unordered_set<int64_t> hardwareRequestIds(maybeRequestIds.value().begin(),
- maybeRequestIds.value().end());
+ std::unordered_set<int64_t> hardwareRequestIds;
+ for (const auto& request : hardwareRequests) {
+ hardwareRequestIds.insert(request.requestId);
+ }
std::shared_ptr<GetValuesClient> client;
{
std::scoped_lock<std::mutex> lockGuard(mLock);
- client = getOrCreateClient(&mGetValuesClients, callback);
+ client = getOrCreateClient(&mGetValuesClients, callback, mPendingRequestPool);
}
// Register the pending hardware requests and also check for duplicate request Ids.
if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
ALOGE("getValues[%s]: failed to add pending requests, error: %s",
- toString(hardwareRequestIds).c_str(), addRequestResult.error().message().c_str());
+ toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
return toScopedAStatus(addRequestResult);
}
+ if (!failedResults.empty()) {
+ // First send the failed results we already know back to the client.
+ client->sendResults(failedResults);
+ }
+
+ if (hardwareRequests.empty()) {
+ return ScopedAStatus::ok();
+ }
+
if (StatusCode status =
- mVehicleHardware->getValues(client->getResultCallback(), getValueRequests);
+ mVehicleHardware->getValues(client->getResultCallback(), hardwareRequests);
status != StatusCode::OK) {
// If the hardware returns error, finish all the pending requests for this request because
// we never expect hardware to call callback for these requests.
@@ -269,9 +366,17 @@
for (auto& request : setValueRequests) {
int64_t requestId = request.requestId;
+ if (auto result = checkWritePermission(request.value); !result.ok()) {
+ ALOGW("property does not support writing: %s", getErrorMsg(result).c_str());
+ failedResults.push_back(SetValueResult{
+ .requestId = requestId,
+ .status = getErrorCode(result),
+ });
+ continue;
+ }
if (auto result = checkProperty(request.value); !result.ok()) {
- ALOGW("setValues[%" PRId64 "]: property not valid: %s", requestId,
- result.error().message().c_str());
+ ALOGW("setValues[%" PRId64 "]: property is not valid: %s", requestId,
+ getErrorMsg(result).c_str());
failedResults.push_back(SetValueResult{
.requestId = requestId,
.status = StatusCode::INVALID_ARG,
@@ -291,13 +396,13 @@
std::shared_ptr<SetValuesClient> client;
{
std::scoped_lock<std::mutex> lockGuard(mLock);
- client = getOrCreateClient(&mSetValuesClients, callback);
+ client = getOrCreateClient(&mSetValuesClients, callback, mPendingRequestPool);
}
// Register the pending hardware requests and also check for duplicate request Ids.
if (auto addRequestResult = client->addRequests(hardwareRequestIds); !addRequestResult.ok()) {
ALOGE("setValues[%s], failed to add pending requests, error: %s",
- toString(hardwareRequestIds).c_str(), addRequestResult.error().message().c_str());
+ toString(hardwareRequestIds).c_str(), getErrorMsg(addRequestResult).c_str());
return toScopedAStatus(addRequestResult, StatusCode::INVALID_ARG);
}
@@ -306,6 +411,10 @@
client->sendResults(failedResults);
}
+ if (hardwareRequests.empty()) {
+ return ScopedAStatus::ok();
+ }
+
if (StatusCode status =
mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests);
status != StatusCode::OK) {
@@ -360,13 +469,110 @@
return vectorToStableLargeParcelable(std::move(configs), output);
}
-ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType&,
- const std::vector<SubscribeOptions>&, int32_t) {
+Result<void> DefaultVehicleHal::checkSubscribeOptions(
+ const std::vector<SubscribeOptions>& options) {
+ for (const auto& option : options) {
+ int32_t propId = option.propId;
+ if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("no config for property, ID: %" PRId32, propId);
+ }
+ const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+ if (config.changeMode != VehiclePropertyChangeMode::ON_CHANGE &&
+ config.changeMode != VehiclePropertyChangeMode::CONTINUOUS) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "only support subscribing to ON_CHANGE or CONTINUOUS property";
+ }
+
+ if (config.access != VehiclePropertyAccess::READ &&
+ config.access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no read access", propId);
+ }
+
+ if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+ float sampleRate = option.sampleRate;
+ float minSampleRate = config.minSampleRate;
+ float maxSampleRate = config.maxSampleRate;
+ if (sampleRate < minSampleRate || sampleRate > maxSampleRate) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("sample rate: %f out of range, must be within %f and %f",
+ sampleRate, minSampleRate, maxSampleRate);
+ }
+ if (!SubscriptionManager::checkSampleRate(sampleRate)) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << "invalid sample rate: " << sampleRate;
+ }
+ }
+
+ if (isGlobalProp(propId)) {
+ continue;
+ }
+
+ // Non-global property.
+ for (int32_t areaId : option.areaIds) {
+ if (auto areaConfig = getAreaConfig(propId, areaId, config); areaConfig == nullptr) {
+ return Error(toInt(StatusCode::INVALID_ARG))
+ << StringPrintf("invalid area ID: %" PRId32 " for prop ID: %" PRId32
+ ", not listed in config",
+ areaId, propId);
+ }
+ }
+ }
+ return {};
+}
+
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
+ const std::vector<SubscribeOptions>& options,
+ [[maybe_unused]] int32_t maxSharedMemoryFileCount) {
+ // TODO(b/205189110): Use shared memory file count.
+ if (auto result = checkSubscribeOptions(options); !result.ok()) {
+ ALOGE("subscribe: invalid subscribe options: %s", getErrorMsg(result).c_str());
+ return toScopedAStatus(result);
+ }
+
+ std::vector<SubscribeOptions> onChangeSubscriptions;
+ std::vector<SubscribeOptions> continuousSubscriptions;
+ for (const auto& option : options) {
+ int32_t propId = option.propId;
+ // We have already validate config exists.
+ const VehiclePropConfig& config = mConfigsByPropId[propId];
+
+ SubscribeOptions optionCopy = option;
+ // If areaIds is empty, subscribe to all areas.
+ if (optionCopy.areaIds.empty() && !isGlobalProp(propId)) {
+ for (const auto& areaConfig : config.areaConfigs) {
+ optionCopy.areaIds.push_back(areaConfig.areaId);
+ }
+ }
+
+ if (isGlobalProp(propId)) {
+ optionCopy.areaIds = {0};
+ }
+
+ if (config.changeMode == VehiclePropertyChangeMode::CONTINUOUS) {
+ continuousSubscriptions.push_back(std::move(optionCopy));
+ } else {
+ onChangeSubscriptions.push_back(std::move(optionCopy));
+ }
+ }
+ // Since we have already check the sample rates, the following functions must succeed.
+ if (!onChangeSubscriptions.empty()) {
+ mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+ /*isContinuousProperty=*/false);
+ }
+ if (!continuousSubscriptions.empty()) {
+ mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+ /*isContinuousProperty=*/true);
+ }
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType&, const std::vector<int32_t>&) {
- return ScopedAStatus::ok();
+ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType& callback,
+ const std::vector<int32_t>& propIds) {
+ return toScopedAStatus(mSubscriptionManager->unsubscribe(callback, propIds),
+ StatusCode::INVALID_ARG);
}
ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
@@ -378,6 +584,61 @@
return mVehicleHardware.get();
}
+Result<void> DefaultVehicleHal::checkWritePermission(const VehiclePropValue& value) const {
+ int32_t propId = value.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+ }
+ const VehiclePropConfig* config = result.value();
+
+ if (config->access != VehiclePropertyAccess::WRITE &&
+ config->access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no write access", propId);
+ }
+ return {};
+}
+
+Result<void> DefaultVehicleHal::checkReadPermission(const VehiclePropValue& value) const {
+ int32_t propId = value.prop;
+ auto result = getConfig(propId);
+ if (!result.ok()) {
+ return Error(toInt(StatusCode::INVALID_ARG)) << getErrorMsg(result);
+ }
+ const VehiclePropConfig* config = result.value();
+
+ if (config->access != VehiclePropertyAccess::READ &&
+ config->access != VehiclePropertyAccess::READ_WRITE) {
+ return Error(toInt(StatusCode::ACCESS_DENIED))
+ << StringPrintf("Property %" PRId32 " has no read access", propId);
+ }
+ return {};
+}
+
+void DefaultVehicleHal::checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+ std::weak_ptr<SubscriptionManager> subscriptionManager) {
+ auto hardwarePtr = hardware.lock();
+ if (hardwarePtr == nullptr) {
+ ALOGW("the VehicleHardware is destroyed, DefaultVehicleHal is ending");
+ return;
+ }
+
+ StatusCode status = hardwarePtr->checkHealth();
+ if (status != StatusCode::OK) {
+ ALOGE("VHAL check health returns non-okay status");
+ return;
+ }
+ std::vector<VehiclePropValue> values = {{
+ .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ .areaId = 0,
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int64Values = {uptimeMillis()},
+ }};
+ onPropertyChangeEvent(subscriptionManager, values);
+ return;
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index dc9a6ce..ff996fe 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -55,6 +55,8 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
mClientsByPropIdArea.clear();
+ // RecurrentSubscription has reference to mGetValue, so it must be destroyed before mGetValue is
+ // destroyed.
mSubscriptionsByClient.clear();
}
@@ -80,7 +82,6 @@
std::scoped_lock<std::mutex> lockGuard(mLock);
std::vector<int64_t> intervals;
-
for (const auto& option : options) {
float sampleRate = option.sampleRate;
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index d3186fd..54fc17d 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -28,6 +28,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <chrono>
#include <list>
@@ -56,10 +57,14 @@
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::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::VehiclePropErrors;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
@@ -70,12 +75,25 @@
using ::ndk::ScopedFileDescriptor;
using ::testing::Eq;
+using ::testing::UnorderedElementsAre;
using ::testing::UnorderedElementsAreArray;
using ::testing::WhenSortedBy;
constexpr int32_t INVALID_PROP_ID = 0;
// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_ON_CHANGE_PROP = 10002 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t GLOBAL_CONTINUOUS_PROP = 10003 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_ON_CHANGE_PROP = 10004 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t AREA_CONTINUOUS_PROP = 10005 + 0x10000000 + 0x03000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t READ_ONLY_PROP = 10006 + 0x10000000 + 0x01000000 + 0x00400000;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
+constexpr int32_t WRITE_ONLY_PROP = 10007 + 0x10000000 + 0x01000000 + 0x00400000;
int32_t testInt32VecProp(size_t i) {
// VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
@@ -134,6 +152,62 @@
.areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
},
.expectedStatus = StatusCode::INVALID_ARG,
+ },
+ {
+ .name = "no_write_permission",
+ .request =
+ {
+ .prop = READ_ONLY_PROP,
+ .value.int32Values = {0},
+ },
+ .expectedStatus = StatusCode::ACCESS_DENIED,
+ }};
+}
+
+struct SubscribeInvalidOptionsTestCase {
+ std::string name;
+ SubscribeOptions option;
+};
+
+std::vector<SubscribeInvalidOptionsTestCase> getSubscribeInvalidOptionsTestCases() {
+ return {{
+ .name = "invalid_prop",
+ .option =
+ {
+ .propId = INVALID_PROP_ID,
+ },
+ },
+ {
+ .name = "invalid_area_ID",
+ .option =
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ .areaIds = {0},
+ },
+ },
+ {
+ .name = "invalid_sample_rate",
+ .option =
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 0.0,
+ },
+ },
+ {
+ .name = "sample_rate_out_of_range",
+ .option =
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 1000.0,
+ },
+ },
+ {
+ .name = "static_property",
+ .option =
+ {
+ // Default change mode is static.
+ .propId = testInt32VecProp(0),
+ },
}};
}
@@ -147,6 +221,7 @@
for (size_t i = 0; i < 10000; i++) {
testConfigs.push_back(VehiclePropConfig{
.prop = testInt32VecProp(i),
+ .access = VehiclePropertyAccess::READ_WRITE,
.areaConfigs =
{
{
@@ -157,13 +232,93 @@
},
});
}
+ // A property with area config.
testConfigs.push_back(
VehiclePropConfig{.prop = INT32_WINDOW_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
.areaConfigs = {{
.areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
.minInt32Value = 0,
.maxInt32Value = 100,
}}});
+ // A global on-change property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ });
+ // A global continuous property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 100.0,
+ });
+ // A per-area on-change property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = AREA_ON_CHANGE_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {
+ {
+
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ {
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ },
+ });
+ // A per-area continuous property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = AREA_CONTINUOUS_PROP,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ .areaConfigs =
+ {
+ {
+
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ {
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ },
+ });
+ // A read-only property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = READ_ONLY_PROP,
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ });
+ // A write-only property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = WRITE_ONLY_PROP,
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+ .minSampleRate = 0.0,
+ .maxSampleRate = 1000.0,
+ });
+ // Register the heartbeat event property.
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ .access = VehiclePropertyAccess::READ,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ });
hardware->setPropertyConfigs(testConfigs);
mHardwarePtr = hardware.get();
mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
@@ -263,7 +418,8 @@
size_t countClients() {
std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
- return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size();
+ return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
+ mVhal->mSubscriptionClients->countClients();
}
private:
@@ -397,6 +553,39 @@
ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
}
+TEST_F(DefaultVehicleHalTest, testGetValuesNoReadPermission) {
+ GetValueRequests requests = {
+ .sharedMemoryFd = {},
+ .payloads =
+ {
+ {
+ .requestId = 0,
+ .prop =
+ {
+ .prop = WRITE_ONLY_PROP,
+ },
+ },
+ },
+ };
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValue with no read permission should return okay with error "
+ "returned from callback"
+ << ", error: " << status.getMessage();
+ EXPECT_TRUE(getHardware()->nextGetValueRequests().empty()) << "expect no request to hardware";
+
+ auto maybeResult = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeResult.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeResult.value().payloads, std::vector<GetValueResult>({
+ {
+ .requestId = 0,
+ .status = StatusCode::ACCESS_DENIED,
+ },
+ }))
+ << "expect to get ACCESS_DENIED status if no read permission";
+}
+
TEST_F(DefaultVehicleHalTest, testGetValuesFinishBeforeTimeout) {
// timeout: 0.1s
int64_t timeout = 100000000;
@@ -783,6 +972,479 @@
ASSERT_FALSE(status.isOk()) << "duplicate request properties in one request must fail";
}
+TEST_F(DefaultVehicleHalTest, testSubscribeUnsubscribe) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnChangeNormal) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .value.int32Values = {0},
+ };
+ SetValueRequests setValueRequests = {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ };
+ std::vector<SetValueResult> setValueResults = {{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }};
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses(setValueResults);
+ status = getClient()->setValues(getCallbackClient(), setValueRequests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect on change event for the updated value";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalOnchangeUnrelatedEventIgnored) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event. This event should be ignored because we
+ // have not subscribed to it.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "must receive no property update event if the property is not subscribed";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChange) {
+ int testAreaId = toInt(VehicleAreaWindow::ROW_1_LEFT);
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ .areaIds = {testAreaId},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = testAreaId,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect on change event for the updated value";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaOnChangeAllAreas) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_ON_CHANGE_PROP,
+ // No areaIds means subscribing to all area IDs.
+ .areaIds = {},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue1{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .value.int32Values = {0},
+ };
+ VehiclePropValue testValue2{
+ .prop = AREA_ON_CHANGE_PROP,
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ .value.int32Values = {0},
+ };
+
+ // Set the values to trigger property change events for two areas.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ },
+ {
+ .requestId = 1,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue1,
+ },
+ SetValueRequest{
+ .requestId = 1,
+ .value = testValue2,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue1, testValue2))
+ << "results mismatch, expect two on-change events for all updated areas";
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "more results than expected";
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuous) {
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ // Sleep for 1s, which should generate ~20 events.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ // Should trigger about 20 times, check for at least 15 events to be safe.
+ for (size_t i = 0; i < 15; i++) {
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_THAT(maybeResults.value().payloads, UnorderedElementsAre(testValue))
+ << "results mismatch, expect to get the updated value";
+ }
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeAreaContinuous) {
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = AREA_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ .areaIds = {toInt(VehicleAreaWindow::ROW_1_LEFT)},
+ },
+ {
+ .propId = AREA_CONTINUOUS_PROP,
+ .sampleRate = 10.0,
+ .areaIds = {toInt(VehicleAreaWindow::ROW_1_RIGHT)},
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ // Sleep for 1s, which should generate ~20 events.
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+
+ std::vector<VehiclePropValue> events;
+ while (true) {
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ if (!maybeResults.has_value()) {
+ break;
+ }
+ for (const auto& value : maybeResults.value().payloads) {
+ events.push_back(value);
+ }
+ }
+
+ size_t leftCount = 0;
+ size_t rightCount = 0;
+
+ for (const auto& event : events) {
+ ASSERT_EQ(event.prop, AREA_CONTINUOUS_PROP);
+ if (event.areaId == toInt(VehicleAreaWindow::ROW_1_LEFT)) {
+ leftCount++;
+ continue;
+ }
+ rightCount++;
+ }
+
+ // Should trigger about 20 times, check for at least 15 events to be safe.
+ ASSERT_GE(leftCount, static_cast<size_t>(15));
+ // Should trigger about 10 times, check for at least 5 events to be safe.
+ ASSERT_GE(rightCount, static_cast<size_t>(5));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeOnChange) {
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_ON_CHANGE_PROP,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+ VehiclePropValue testValue{
+ .prop = GLOBAL_ON_CHANGE_PROP,
+ .value.int32Values = {0},
+ };
+
+ // Set the value to trigger a property change event.
+ getHardware()->addSetValueResponses({{
+ .requestId = 0,
+ .status = StatusCode::OK,
+ }});
+ status = getClient()->setValues(getCallbackClient(),
+ {
+ .payloads =
+ {
+ SetValueRequest{
+ .requestId = 0,
+ .value = testValue,
+ },
+ },
+ });
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "No property event should be generated after unsubscription";
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeContinuous) {
+ VehiclePropValue testValue{
+ .prop = GLOBAL_CONTINUOUS_PROP,
+ .value.int32Values = {0},
+ };
+ // Set responses for all the hardware getValues requests.
+ getHardware()->setGetValueResponder(
+ [](std::shared_ptr<const IVehicleHardware::GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) {
+ std::vector<GetValueResult> results;
+ for (auto& request : requests) {
+ VehiclePropValue prop = request.prop;
+ prop.value.int32Values = {0};
+ results.push_back({
+ .requestId = request.requestId,
+ .status = StatusCode::OK,
+ .prop = prop,
+ });
+ }
+ (*callback)(results);
+ return StatusCode::OK;
+ });
+
+ std::vector<SubscribeOptions> options = {
+ {
+ .propId = GLOBAL_CONTINUOUS_PROP,
+ .sampleRate = 20.0,
+ },
+ };
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+
+ status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_CONTINUOUS_PROP}));
+
+ ASSERT_TRUE(status.isOk()) << "unsubscribe failed: " << status.getMessage();
+
+ // Clear existing events.
+ while (getCallback()->nextOnPropertyEventResults().has_value()) {
+ // Do nothing.
+ }
+
+ // Wait for a while, make sure no new events are generated.
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+ ASSERT_FALSE(getCallback()->nextOnPropertyEventResults().has_value())
+ << "No property event should be generated after unsubscription";
+}
+
+class SubscribeInvalidOptionsTest
+ : public DefaultVehicleHalTest,
+ public testing::WithParamInterface<SubscribeInvalidOptionsTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ SubscribeInvalidOptionsTests, SubscribeInvalidOptionsTest,
+ ::testing::ValuesIn(getSubscribeInvalidOptionsTestCases()),
+ [](const testing::TestParamInfo<SubscribeInvalidOptionsTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(SubscribeInvalidOptionsTest, testSubscribeInvalidOptions) {
+ std::vector<SubscribeOptions> options = {GetParam().option};
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_FALSE(status.isOk()) << "invalid subscribe options must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testSubscribeNoReadPermission) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = WRITE_ONLY_PROP,
+ }};
+
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_FALSE(status.isOk()) << "subscribe to a write-only property must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::ACCESS_DENIED));
+}
+
+TEST_F(DefaultVehicleHalTest, testUnsubscribeFailure) {
+ auto status = getClient()->unsubscribe(getCallbackClient(),
+ std::vector<int32_t>({GLOBAL_ON_CHANGE_PROP}));
+
+ ASSERT_FALSE(status.isOk()) << "unsubscribe to a not-subscribed property must fail";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testHeartbeatEvent) {
+ std::vector<SubscribeOptions> options = {{
+ .propId = toInt(VehicleProperty::VHAL_HEARTBEAT),
+ }};
+ int64_t currentTime = uptimeMillis();
+ auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+
+ ASSERT_TRUE(status.isOk()) << "unable to subscribe to heartbeat event: " << status.getMessage();
+
+ // We send out a heartbeat event every 3s, so sleep for 3s.
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+
+ auto maybeResults = getCallback()->nextOnPropertyEventResults();
+ ASSERT_TRUE(maybeResults.has_value()) << "no results in callback";
+ ASSERT_EQ(maybeResults.value().payloads.size(), static_cast<size_t>(1));
+ VehiclePropValue gotValue = maybeResults.value().payloads[0];
+ ASSERT_EQ(gotValue.prop, toInt(VehicleProperty::VHAL_HEARTBEAT));
+ ASSERT_EQ(gotValue.value.int64Values.size(), static_cast<size_t>(1));
+ ASSERT_GE(gotValue.value.int64Values[0], currentTime)
+ << "expect to get the latest timestamp with the heartbeat event";
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 7d992af..eec32dd 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -64,6 +64,9 @@
StatusCode MockVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
const std::vector<GetValueRequest>& requests) const {
std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mGetValueResponder != nullptr) {
+ return mGetValueResponder(callback, requests);
+ }
return handleRequestsLocked(__func__, callback, requests, &mGetValueRequests,
&mGetValueResponses);
}
@@ -104,6 +107,13 @@
mSetValueResponses.push_back(responses);
}
+void MockVehicleHardware::setGetValueResponder(
+ std::function<StatusCode(std::shared_ptr<const GetValuesCallback>,
+ const std::vector<GetValueRequest>&)>&& responder) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mGetValueResponder = responder;
+}
+
std::vector<GetValueRequest> MockVehicleHardware::nextGetValueRequests() {
std::scoped_lock<std::mutex> lockGuard(mLock);
std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index 283d1f9..0844de1 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -66,6 +66,12 @@
void addSetValueResponses(
const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&
responses);
+ void setGetValueResponder(
+ std::function<::aidl::android::hardware::automotive::vehicle::StatusCode(
+ std::shared_ptr<const GetValuesCallback>,
+ const std::vector<
+ ::aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>&&
+ responder);
std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>
nextGetValueRequests();
std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>
@@ -92,6 +98,10 @@
mStatusByFunctions GUARDED_BY(mLock);
int64_t mSleepTime GUARDED_BY(mLock) = 0;
std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback 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>&)>
+ mGetValueResponder GUARDED_BY(mLock);
template <class ResultType>
::aidl::android::hardware::automotive::vehicle::StatusCode returnResponse(
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
index fa08d6c..c14f4fd 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -185,7 +185,7 @@
// Theoretically trigger 10 times, but check for at least 9 times to be stable.
EXPECT_GE(getEvents().size(), static_cast<size_t>(9));
- EXPECT_LE(getEvents().size(), static_cast<size_t>(11));
+ EXPECT_LE(getEvents().size(), static_cast<size_t>(15));
}
TEST_F(SubscriptionManagerTest, testSubscribeMultipleAreasContinuous) {
diff --git a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
index 44b434b..3a5f951 100644
--- a/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/aidl_api/android.hardware.bluetooth.audio/current/android/hardware/bluetooth/audio/CodecType.aidl
@@ -41,4 +41,5 @@
APTX_HD = 4,
LDAC = 5,
LC3 = 6,
+ VENDOR = 7,
}
diff --git a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
index 68c60f5..9c33081 100644
--- a/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
+++ b/bluetooth/audio/aidl/android/hardware/bluetooth/audio/CodecType.aidl
@@ -26,4 +26,5 @@
APTX_HD,
LDAC,
LC3,
+ VENDOR,
}
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 92cd0f5..380732f 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -355,6 +355,7 @@
kDefaultOffloadLc3Capability);
break;
case CodecType::UNKNOWN:
+ case CodecType::VENDOR:
codec_capability = {};
break;
}
@@ -420,6 +421,7 @@
}
break;
case CodecType::UNKNOWN:
+ case CodecType::VENDOR:
break;
}
return false;
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
index 41bc9ae..d998478 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,6 @@
WIFI_SCANNING = 3,
AIRPLANE_MODE = 4,
MICROPHONE = 5,
+ BT_MAIN = 6,
+ BT_SCANNING = 7,
}
diff --git a/contexthub/aidl/android/hardware/contexthub/Setting.aidl b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
index f2e55db..91d4c3f 100644
--- a/contexthub/aidl/android/hardware/contexthub/Setting.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/Setting.aidl
@@ -39,4 +39,12 @@
* by CHRE.
*/
MICROPHONE,
+ /**
+ * The main BT toggle in the Android settings for BT connectivity.
+ */
+ BT_MAIN,
+ /**
+ * The "BT scanning" setting for location scans.
+ */
+ BT_SCANNING,
}
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index a47f64e..f0583be 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -300,6 +300,14 @@
testSettingChanged(Setting::MICROPHONE);
}
+TEST_P(ContextHubAidl, TestOnBtMainSettingChanged) {
+ testSettingChanged(Setting::BT_MAIN);
+}
+
+TEST_P(ContextHubAidl, TestOnBtScanningSettingChanged) {
+ testSettingChanged(Setting::BT_SCANNING);
+}
+
std::vector<std::tuple<std::string, int32_t>> generateContextHubMapping() {
std::vector<std::tuple<std::string, int32_t>> tuples;
auto contextHubAidlNames = android::getAidlHalInstanceNames(IContextHub::descriptor);
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
index 31cdded..ad30e30 100644
--- a/neuralnetworks/1.0/utils/Android.bp
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -31,16 +31,11 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
"libarect",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- ],
- export_static_lib_headers: [
- "neuralnetworks_utils_hal_common",
- ],
target: {
android: {
shared_libs: ["libnativewindow"],
@@ -55,19 +50,14 @@
static_libs: [
"android.hardware.neuralnetworks@1.0",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
index 737ff58..4b8999f 100644
--- a/neuralnetworks/1.1/utils/Android.bp
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -31,17 +31,12 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- ],
- export_static_lib_headers: [
- "neuralnetworks_utils_hal_common",
- ],
}
cc_test {
@@ -52,20 +47,15 @@
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
"neuralnetworks_utils_hal_1_1",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index 4eefb0f..4c5f065 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -31,19 +31,14 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_common",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"libfmq",
- ],
- export_static_lib_headers: [
+ "neuralnetworks_types",
"neuralnetworks_utils_hal_common",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
],
product_variables: {
debuggable: { // eng and userdebug builds
@@ -71,7 +66,6 @@
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
@@ -79,13 +73,10 @@
"neuralnetworks_utils_hal_1_2",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
"libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index 7acb4fc..c512dda 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -31,21 +31,16 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_common",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- "neuralnetworks_utils_hal_1_2",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libfmq",
- ],
- export_static_lib_headers: [
+ "neuralnetworks_types",
"neuralnetworks_utils_hal_common",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
+ "neuralnetworks_utils_hal_1_2",
],
target: {
host: {
@@ -69,7 +64,6 @@
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
"neuralnetworks_utils_hal_1_0",
@@ -78,13 +72,10 @@
"neuralnetworks_utils_hal_1_3",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
"libfmq",
"libhidlbase",
- "libhidlmemory",
"liblog",
"libutils",
],
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index 3faa613..9148eac 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -111,19 +111,13 @@
static_libs: [
"libaidlcommonsupport",
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
- "android.hidl.allocator@1.0",
"libbase",
"libbinder_ndk",
"libcutils",
- "libhidlbase",
- "libhidlmemory",
- "liblog",
- "libutils",
],
target: {
android: {
diff --git a/neuralnetworks/aidl/utils/test/MockBuffer.h b/neuralnetworks/aidl/utils/test/MockBuffer.h
index f77fa86..7a05a0f 100644
--- a/neuralnetworks/aidl/utils/test/MockBuffer.h
+++ b/neuralnetworks/aidl/utils/test/MockBuffer.h
@@ -21,7 +21,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockBurst.h b/neuralnetworks/aidl/utils/test/MockBurst.h
index 4cf60b6..609bd30 100644
--- a/neuralnetworks/aidl/utils/test/MockBurst.h
+++ b/neuralnetworks/aidl/utils/test/MockBurst.h
@@ -21,7 +21,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockExecution.h b/neuralnetworks/aidl/utils/test/MockExecution.h
index 216f569..782e54f 100644
--- a/neuralnetworks/aidl/utils/test/MockExecution.h
+++ b/neuralnetworks/aidl/utils/test/MockExecution.h
@@ -21,8 +21,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
index 06f9ea2..29449bb 100644
--- a/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
+++ b/neuralnetworks/aidl/utils/test/MockFencedExecutionCallback.h
@@ -22,7 +22,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/aidl/utils/test/MockPreparedModel.h b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
index 318acc2..a5b3b66 100644
--- a/neuralnetworks/aidl/utils/test/MockPreparedModel.h
+++ b/neuralnetworks/aidl/utils/test/MockPreparedModel.h
@@ -22,8 +22,6 @@
#include <android/binder_interface_utils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
namespace aidl::android::hardware::neuralnetworks::utils {
diff --git a/neuralnetworks/utils/adapter/hidl/Android.bp b/neuralnetworks/utils/adapter/hidl/Android.bp
index d073106..6875daa 100644
--- a/neuralnetworks/utils/adapter/hidl/Android.bp
+++ b/neuralnetworks/utils/adapter/hidl/Android.bp
@@ -30,17 +30,16 @@
local_include_dirs: ["include/nnapi/hal"],
export_include_dirs: ["include"],
static_libs: [
- "neuralnetworks_types",
- "neuralnetworks_utils_hal_1_0",
- "neuralnetworks_utils_hal_1_1",
- "neuralnetworks_utils_hal_1_2",
- "neuralnetworks_utils_hal_1_3",
- ],
- shared_libs: [
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
"android.hardware.neuralnetworks@1.3",
"libfmq",
+ "neuralnetworks_types",
+ "neuralnetworks_utils_hal_1_0",
+ "neuralnetworks_utils_hal_1_1",
+ "neuralnetworks_utils_hal_1_2",
+ "neuralnetworks_utils_hal_1_3",
+ "neuralnetworks_utils_hal_common",
],
}
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index 39927a3..bfba24f 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -39,20 +39,12 @@
srcs: ["test/*.cpp"],
static_libs: [
"libgmock",
- "libneuralnetworks_common",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
- "android.hidl.allocator@1.0",
- "android.hidl.memory@1.0",
"libbase",
"libcutils",
- "libfmq",
- "libhidlbase",
- "libhidlmemory",
- "liblog",
- "libutils",
],
target: {
android: {
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
index c3272ae..452078b 100644
--- a/neuralnetworks/utils/service/Android.bp
+++ b/neuralnetworks/utils/service/Android.bp
@@ -33,6 +33,10 @@
local_include_dirs: ["include/nnapi/hal"],
export_include_dirs: ["include"],
static_libs: [
+ "android.hardware.neuralnetworks@1.0",
+ "android.hardware.neuralnetworks@1.1",
+ "android.hardware.neuralnetworks@1.2",
+ "android.hardware.neuralnetworks@1.3",
"neuralnetworks_types",
"neuralnetworks_utils_hal_1_0",
"neuralnetworks_utils_hal_1_1",
@@ -40,10 +44,4 @@
"neuralnetworks_utils_hal_1_3",
"neuralnetworks_utils_hal_common",
],
- shared_libs: [
- "android.hardware.neuralnetworks@1.0",
- "android.hardware.neuralnetworks@1.1",
- "android.hardware.neuralnetworks@1.2",
- "android.hardware.neuralnetworks@1.3",
- ],
}