Merge "wifi: Fix single AP iface isn't deleted" into tm-dev
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 09446cd..38d6eff 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -34,6 +34,7 @@
#include <hwbinder/IPCThreadState.h>
+#include <android-base/expected.h>
#include <android-base/logging.h>
#include <system/audio_config.h>
@@ -130,6 +131,33 @@
using IDevice = ::android::hardware::audio::CPP_VERSION::IDevice;
using IDevicesFactory = ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
+ static android::base::expected<std::vector<std::string>, std::string> getAllFactoryInstances() {
+ using ::android::hardware::audio::CPP_VERSION::IDevicesFactory;
+ const std::string factoryDescriptor = IDevicesFactory::descriptor;
+ // Make sure that the instance is the exact minor version.
+ // Using a 7.1 factory for 7.0 test is not always possible because
+ // 7.1 can be configured via the XML config to use features that are
+ // absent in 7.0.
+ auto instances = ::android::hardware::getAllHalInstanceNames(factoryDescriptor);
+ if (instances.empty()) return instances;
+ // Use the default instance for checking the implementation version.
+ auto defaultInstance = IDevicesFactory::getService("default");
+ if (defaultInstance == nullptr) {
+ return ::android::base::unexpected("Failed to obtain IDevicesFactory/default");
+ }
+ std::string actualDescriptor;
+ auto intDescRet = defaultInstance->interfaceDescriptor(
+ [&](const auto& descriptor) { actualDescriptor = descriptor; });
+ if (!intDescRet.isOk()) {
+ return ::android::base::unexpected("Failed to obtain interface descriptor: " +
+ intDescRet.description());
+ }
+ if (factoryDescriptor == actualDescriptor)
+ return instances;
+ else
+ return {};
+ }
+
virtual ~HidlTest() = default;
// public access to avoid annoyances when using this method in template classes
// derived from test classes
@@ -174,9 +202,11 @@
}
TEST(CheckConfig, audioPolicyConfigurationValidation) {
- const auto factories = ::android::hardware::getAllHalInstanceNames(
- ::android::hardware::audio::CPP_VERSION::IDevicesFactory::descriptor);
- if (factories.size() == 0) {
+ const auto factories = HidlTest::getAllFactoryInstances();
+ if (!factories.ok()) {
+ FAIL() << factories.error();
+ }
+ if (factories.value().size() == 0) {
GTEST_SKIP() << "Skipping audioPolicyConfigurationValidation because no factory instances "
"are found.";
}
@@ -205,11 +235,11 @@
const std::vector<DeviceParameter>& getDeviceParameters() {
static std::vector<DeviceParameter> parameters = [] {
std::vector<DeviceParameter> result;
- const auto factories = ::android::hardware::getAllHalInstanceNames(
- ::android::hardware::audio::CPP_VERSION::IDevicesFactory::descriptor);
+ const auto factories = HidlTest::getAllFactoryInstances();
+ if (!factories.ok()) return result;
const auto devices = getCachedPolicyConfig().getModulesWithDevicesNames();
result.reserve(devices.size());
- for (const auto& factoryName : factories) {
+ for (const auto& factoryName : factories.value()) {
for (const auto& deviceName : devices) {
if (DeviceManager::getInstance().get(factoryName, deviceName) != nullptr) {
result.emplace_back(factoryName, deviceName);
@@ -224,9 +254,9 @@
const std::vector<DeviceParameter>& getDeviceParametersForFactoryTests() {
static std::vector<DeviceParameter> parameters = [] {
std::vector<DeviceParameter> result;
- const auto factories = ::android::hardware::getAllHalInstanceNames(
- ::android::hardware::audio::CPP_VERSION::IDevicesFactory::descriptor);
- for (const auto& factoryName : factories) {
+ const auto factories = HidlTest::getAllFactoryInstances();
+ if (!factories.ok()) return result;
+ for (const auto& factoryName : factories.value()) {
result.emplace_back(factoryName,
DeviceManager::getInstance().getPrimary(factoryName) != nullptr
? DeviceManager::kPrimaryDevice
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index dc9b876..47fc54b 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -90,6 +90,14 @@
* area ID) are not allowed in a single call. This function must return
* {@link StatusCode#INVALID_ARG} for duplicate properties.
*
+ * The {@link VehiclePropValue#timestamp} field in request is ignored. The
+ * {@link VehiclePropValue#timestamp} field in {@link GetValueResult} must
+ * be the system uptime since boot when the value changes for
+ * ON_CHANGE property or when the value is checked according to polling rate
+ * for CONTINUOUS property. Note that for CONTINUOUS property, VHAL client
+ * reading the property multiple times between the polling interval will get
+ * the same timestamp.
+ *
* @param callback A callback interface, whose 'onGetValues' would be called
* after the value is fetched. Caller should use
* {@code android-automotive-large-parcelable} library to parse the
@@ -104,7 +112,7 @@
* Set vehicle property values.
*
* The {@link IVehicleCallback#onSetValues} function would be called after
- * the values set request are sent through vehicle bus or are failed to set.
+ * the values set request are sent through vehicle bus or failed to set.
* If the bus protocol supports confirmation, the callback would be called
* after getting the confirmation.
*
@@ -152,11 +160,36 @@
* Clients must be able to subscribe to multiple properties at a time
* depending on data provided in options argument.
*
- * For one callback, the is only one subscription for one property.
+ * For one callback, there is only one subscription for one property.
* A new subscription with a different sample rate would override the old
* subscription. One property could be subscribed multiple times for
* different callbacks.
*
+ * If error is returned, some of the properties failed to subscribe.
+ * Caller is safe to try again, since subscribing to an already subscribed
+ * property is okay.
+ *
+ * The specified sample rate is just a guidance. It is not guaranteed that
+ * the sample rate is achievable depending on how the polling refresh rate
+ * is. The actual property event rate might be higher/lower than the
+ * specified sampleRate, for example, if the polling rate can be 5 times/s
+ * or 10 times/s, subscribing to a sample rate of 7 might use the 5 times/s
+ * polling rate, thus generating 5 events/s. We only require that on
+ * average, the {@code minSampleRate} and {@code maxSampleRate} can be
+ * achieved, all the sampleRate within min and max would on average
+ * generates events with rate >= {@code minSampleRate} and <=
+ * {@code maxSampleRate}.
+ *
+ * The {@link VehiclePropValue#timestamp} field for each property event must
+ * be the system uptime since boot when the value changes for
+ * ON_CHANGE property or when the value is checked according to polling rate
+ * for CONTINUOUS property. Note that for CONTINUOUS property, VHAL client
+ * reading the property multiple times between the polling interval will get
+ * the same timestamp.
+ * For example, if the polling rate for a property is 10 times/s, no matter
+ * what the sampleRate specified in {@code options}, the timestamp for
+ * the timestamp is updated 10 times/s.
+ *
* @param callback The subscription callbacks.
* {@link IVehicleCallback#onPropertyEvent} would be called when a new
* property event arrives.
@@ -189,8 +222,13 @@
/**
* Unsubscribes from property events.
*
- * If 'callback' is not valid or 'propIds' were not subscribed for this
- * 'callback', this method must return {@link StatusCode#INVALID_ARG}.
+ * If 'callback' is not valid this method must return
+ * {@link StatusCode#INVALID_ARG}. If a specified propId was not subscribed
+ * before, this method must ignore that propId.
+ *
+ * If error is returned, some of the properties failed to unsubscribe.
+ * Caller is safe to try again, since unsubscribing an already unsubscribed
+ * property is okay.
*
* @param callback The callback used in the previous subscription.
* @param propIds The IDs for the properties to unsubscribe.
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index fda0da9..4d96fd3 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -292,8 +292,9 @@
.prop = toInt(VehicleProperty::EV_CHARGE_CURRENT_DRAW_LIMIT),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {/*max current draw allowed by vehicle in amperes=*/20},
},
- .initialValue = {.floatValues = {(float)VehicleUnit::AMPERE}}},
+ .initialValue = {.floatValues = {(float)12.5}}},
{.config =
{
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index e799a28..34b2b24 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -17,10 +17,12 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
+#include <ConcurrentQueue.h>
#include <DefaultConfig.h>
#include <FakeObd2Frame.h>
#include <FakeUserHal.h>
#include <IVehicleHardware.h>
+#include <RecurrentTimer.h>
#include <VehicleHalTypes.h>
#include <VehiclePropertyStore.h>
#include <android-base/parseint.h>
@@ -47,6 +49,8 @@
explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
+ ~FakeVehicleHardware();
+
// Get all the property configs.
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
getAllPropertyConfigs() const override;
@@ -82,6 +86,10 @@
void registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) override;
+ // Update the sample rate for the [propId, areaId] pair.
+ aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
+ int32_t propId, int32_t areaId, float sampleRate) override;
+
protected:
// mValuePool is also used in mServerSidePropStore.
const std::shared_ptr<VehiclePropValuePool> mValuePool;
@@ -97,13 +105,45 @@
// Expose private methods to unit test.
friend class FakeVehicleHardwareTestHelper;
+ template <class CallbackType, class RequestType>
+ struct RequestWithCallback {
+ RequestType request;
+ std::shared_ptr<const CallbackType> callback;
+ };
+
+ template <class CallbackType, class RequestType>
+ class PendingRequestHandler {
+ public:
+ PendingRequestHandler(FakeVehicleHardware* hardware);
+
+ void addRequest(RequestType request, std::shared_ptr<const CallbackType> callback);
+
+ void stop();
+
+ private:
+ FakeVehicleHardware* mHardware;
+ std::thread mThread;
+ ConcurrentQueue<RequestWithCallback<CallbackType, RequestType>> mRequests;
+
+ void handleRequestsOnce();
+ };
+
const std::unique_ptr<obd2frame::FakeObd2Frame> mFakeObd2Frame;
const std::unique_ptr<FakeUserHal> mFakeUserHal;
- std::mutex mCallbackLock;
- std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback
- GUARDED_BY(mCallbackLock);
- std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback
- GUARDED_BY(mCallbackLock);
+ // RecurrentTimer is thread-safe.
+ std::unique_ptr<RecurrentTimer> mRecurrentTimer;
+ std::mutex mLock;
+ std::unique_ptr<const PropertyChangeCallback> mOnPropertyChangeCallback GUARDED_BY(mLock);
+ std::unique_ptr<const PropertySetErrorCallback> mOnPropertySetErrorCallback GUARDED_BY(mLock);
+ std::unordered_map<PropIdAreaId, std::shared_ptr<RecurrentTimer::Callback>, PropIdAreaIdHash>
+ mRecurrentActions GUARDED_BY(mLock);
+ // PendingRequestHandler is thread-safe.
+ mutable PendingRequestHandler<GetValuesCallback,
+ aidl::android::hardware::automotive::vehicle::GetValueRequest>
+ mPendingGetValueRequests;
+ mutable PendingRequestHandler<SetValuesCallback,
+ aidl::android::hardware::automotive::vehicle::SetValueRequest>
+ mPendingSetValueRequests;
void init();
// Stores the initial value to property store.
@@ -163,6 +203,10 @@
android::base::Result<void> checkArgumentsSize(const std::vector<std::string>& options,
size_t minSize);
+ aidl::android::hardware::automotive::vehicle::GetValueResult handleGetValueRequest(
+ const aidl::android::hardware::automotive::vehicle::GetValueRequest& request);
+ aidl::android::hardware::automotive::vehicle::SetValueResult handleSetValueRequest(
+ const aidl::android::hardware::automotive::vehicle::SetValueRequest& request);
};
} // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index f8b64f2..7b3de58 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -66,6 +66,7 @@
using ::android::base::Error;
using ::android::base::ParseFloat;
using ::android::base::Result;
+using ::android::base::ScopedLockAssertion;
using ::android::base::StartsWith;
using ::android::base::StringPrintf;
@@ -131,21 +132,24 @@
}
FakeVehicleHardware::FakeVehicleHardware()
- : mValuePool(new VehiclePropValuePool),
- mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
- mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
- mFakeUserHal(new FakeUserHal(mValuePool)) {
- init();
-}
+ : FakeVehicleHardware(std::make_unique<VehiclePropValuePool>()) {}
FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
: mValuePool(std::move(valuePool)),
mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
- mFakeUserHal(new FakeUserHal(mValuePool)) {
+ mFakeUserHal(new FakeUserHal(mValuePool)),
+ mRecurrentTimer(new RecurrentTimer()),
+ mPendingGetValueRequests(this),
+ mPendingSetValueRequests(this) {
init();
}
+FakeVehicleHardware::~FakeVehicleHardware() {
+ mPendingGetValueRequests.stop();
+ mPendingSetValueRequests.stop();
+}
+
void FakeVehicleHardware::init() {
for (auto& it : defaultconfig::getDefaultConfigs()) {
VehiclePropConfig cfg = it.config;
@@ -430,37 +434,25 @@
StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
const std::vector<SetValueRequest>& requests) {
- std::vector<SetValueResult> results;
for (auto& request : requests) {
- const VehiclePropValue& value = request.value;
- int propId = value.prop;
-
if (FAKE_VEHICLEHARDWARE_DEBUG) {
- ALOGD("Set value for property ID: %d", propId);
+ ALOGD("Set value for property ID: %d", request.value.prop);
}
- SetValueResult setValueResult;
- setValueResult.requestId = request.requestId;
-
- if (auto result = setValue(value); !result.ok()) {
- ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
- getIntErrorCode(result));
- setValueResult.status = getErrorCode(result);
- } else {
- setValueResult.status = StatusCode::OK;
- }
-
- results.push_back(std::move(setValueResult));
+ // In a real VHAL implementation, you could either send the setValue request to vehicle bus
+ // here in the binder thread, or you could send the request in setValue which runs in
+ // the handler thread. If you decide to send the setValue request here, you should not
+ // wait for the response here and the handler thread should handle the setValue response.
+ mPendingSetValueRequests.addRequest(request, callback);
}
- // In the real vhal, the values will be sent to Car ECU. We just pretend it is done here and
- // send back the updated property values to client.
- (*callback)(std::move(results));
-
return StatusCode::OK;
}
VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
+ // In a real VHAL implementation, this will send the request to vehicle bus if not already
+ // sent in setValues, and wait for the response from vehicle bus.
+ // Here we are just updating mValuePool.
bool isSpecialValue = false;
auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
@@ -487,41 +479,59 @@
return {};
}
-StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
- const std::vector<GetValueRequest>& requests) const {
- std::vector<GetValueResult> results;
- for (auto& request : requests) {
- const VehiclePropValue& value = request.prop;
+SetValueResult FakeVehicleHardware::handleSetValueRequest(const SetValueRequest& request) {
+ SetValueResult setValueResult;
+ setValueResult.requestId = request.requestId;
- if (FAKE_VEHICLEHARDWARE_DEBUG) {
- ALOGD("getValues(%d)", value.prop);
- }
-
- GetValueResult getValueResult;
- getValueResult.requestId = request.requestId;
-
- auto result = getValue(value);
- if (!result.ok()) {
- ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
- getIntErrorCode(result));
- getValueResult.status = getErrorCode(result);
- } else {
- getValueResult.status = StatusCode::OK;
- getValueResult.prop = *result.value();
- }
- results.push_back(std::move(getValueResult));
+ if (auto result = setValue(request.value); !result.ok()) {
+ ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
+ getIntErrorCode(result));
+ setValueResult.status = getErrorCode(result);
+ } else {
+ setValueResult.status = StatusCode::OK;
}
- // In a real VHAL implementation, getValue would be async and we would call the callback after
- // we actually received the values from vehicle bus. Here we are getting the result
- // synchronously so we could call the callback here.
- (*callback)(std::move(results));
+ return setValueResult;
+}
+
+StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) const {
+ for (auto& request : requests) {
+ if (FAKE_VEHICLEHARDWARE_DEBUG) {
+ ALOGD("getValues(%d)", request.prop.prop);
+ }
+
+ // In a real VHAL implementation, you could either send the getValue request to vehicle bus
+ // here in the binder thread, or you could send the request in getValue which runs in
+ // the handler thread. If you decide to send the getValue request here, you should not
+ // wait for the response here and the handler thread should handle the getValue response.
+ mPendingGetValueRequests.addRequest(request, callback);
+ }
return StatusCode::OK;
}
+GetValueResult FakeVehicleHardware::handleGetValueRequest(const GetValueRequest& request) {
+ GetValueResult getValueResult;
+ getValueResult.requestId = request.requestId;
+
+ auto result = getValue(request.prop);
+ if (!result.ok()) {
+ ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
+ getIntErrorCode(result));
+ getValueResult.status = getErrorCode(result);
+ } else {
+ getValueResult.status = StatusCode::OK;
+ getValueResult.prop = *result.value();
+ }
+ return getValueResult;
+}
+
FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
const VehiclePropValue& value) const {
+ // In a real VHAL implementation, this will send the request to vehicle bus if not already
+ // sent in getValues, and wait for the response from vehicle bus.
+ // Here we are just reading value from mValuePool.
bool isSpecialValue = false;
auto result = maybeGetSpecialValue(value, &isSpecialValue);
if (isSpecialValue) {
@@ -567,6 +577,12 @@
result.buffer = dumpSpecificProperty(options);
} else if (EqualsIgnoreCase(option, "--set")) {
result.buffer = dumpSetProperties(options);
+ } else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
+ if (options.size() == 1) {
+ result.buffer = mFakeUserHal->showDumpHelp();
+ } else {
+ result.buffer = mFakeUserHal->dump(options[1]);
+ }
} else {
result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
}
@@ -584,7 +600,9 @@
"[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. "
"Notice that the string, bytes and area value can be set just once, while the other can"
" have multiple values (so they're used in the respective array), "
- "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n";
+ "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n\n"
+ "Fake user HAL usage: \n" +
+ mFakeUserHal->showDumpHelp();
}
std::string FakeVehicleHardware::dumpAllProperties() {
@@ -837,18 +855,57 @@
void FakeVehicleHardware::registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) {
- std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ std::scoped_lock<std::mutex> lockGuard(mLock);
mOnPropertyChangeCallback = std::move(callback);
}
void FakeVehicleHardware::registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) {
- std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ std::scoped_lock<std::mutex> lockGuard(mLock);
mOnPropertySetErrorCallback = std::move(callback);
}
+StatusCode FakeVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
+ // DefaultVehicleHal makes sure that sampleRate must be within minSampleRate and maxSampleRate.
+ // For fake implementation, we would write the same value with a new timestamp into propStore
+ // at sample rate.
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+
+ PropIdAreaId propIdAreaId{
+ .propId = propId,
+ .areaId = areaId,
+ };
+ if (mRecurrentActions.find(propIdAreaId) != mRecurrentActions.end()) {
+ mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propIdAreaId]);
+ }
+ if (sampleRate == 0) {
+ return StatusCode::OK;
+ }
+ int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
+ auto action = std::make_shared<RecurrentTimer::Callback>([this, propId, areaId] {
+ // Refresh the property value. In real implementation, this should poll the latest value
+ // from vehicle bus. Here, we are just refreshing the existing value with a new timestamp.
+ auto result = getValue(VehiclePropValue{
+ .prop = propId,
+ .areaId = areaId,
+ });
+ if (!result.ok()) {
+ // Failed to read current value, skip refreshing.
+ return;
+ }
+ result.value()->timestamp = elapsedRealtimeNano();
+ // Must remove the value before writing, otherwise, we would generate no update event since
+ // the value is the same.
+ mServerSidePropStore->removeValue(*result.value());
+ mServerSidePropStore->writeValue(std::move(result.value()));
+ });
+ mRecurrentTimer->registerTimerCallback(interval, action);
+ mRecurrentActions[propIdAreaId] = action;
+ return StatusCode::OK;
+}
+
void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
- std::scoped_lock<std::mutex> lockGuard(mCallbackLock);
+ std::scoped_lock<std::mutex> lockGuard(mLock);
if (mOnPropertyChangeCallback == nullptr) {
return;
@@ -935,6 +992,60 @@
return bytes;
}
+template <class CallbackType, class RequestType>
+FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::PendingRequestHandler(
+ FakeVehicleHardware* hardware)
+ : mHardware(hardware), mThread([this] {
+ while (mRequests.waitForItems()) {
+ handleRequestsOnce();
+ }
+ }) {}
+
+template <class CallbackType, class RequestType>
+void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::addRequest(
+ RequestType request, std::shared_ptr<const CallbackType> callback) {
+ mRequests.push({
+ request,
+ callback,
+ });
+}
+
+template <class CallbackType, class RequestType>
+void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::stop() {
+ mRequests.deactivate();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+template <>
+void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::GetValuesCallback,
+ GetValueRequest>::handleRequestsOnce() {
+ std::unordered_map<std::shared_ptr<const GetValuesCallback>, std::vector<GetValueResult>>
+ callbackToResults;
+ for (const auto& rwc : mRequests.flush()) {
+ auto result = mHardware->handleGetValueRequest(rwc.request);
+ callbackToResults[rwc.callback].push_back(std::move(result));
+ }
+ for (const auto& [callback, results] : callbackToResults) {
+ (*callback)(std::move(results));
+ }
+}
+
+template <>
+void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::SetValuesCallback,
+ SetValueRequest>::handleRequestsOnce() {
+ std::unordered_map<std::shared_ptr<const SetValuesCallback>, std::vector<SetValueResult>>
+ callbackToResults;
+ for (const auto& rwc : mRequests.flush()) {
+ auto result = mHardware->handleSetValueRequest(rwc.request);
+ callbackToResults[rwc.callback].push_back(std::move(result));
+ }
+ for (const auto& [callback, results] : callbackToResults) {
+ (*callback)(std::move(results));
+ }
+}
+
} // namespace fake
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 7a7fb37..3e8f634 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -25,12 +25,17 @@
#include <android-base/expected.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
#include <inttypes.h>
+#include <chrono>
+#include <condition_variable>
+#include <unordered_map>
+#include <unordered_set>
#include <vector>
namespace android {
@@ -53,6 +58,7 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::base::expected;
+using ::android::base::ScopedLockAssertion;
using ::android::base::StringPrintf;
using ::android::base::unexpected;
using ::testing::ContainerEq;
@@ -60,6 +66,8 @@
using ::testing::Eq;
using ::testing::WhenSortedBy;
+using std::chrono::milliseconds;
+
constexpr int INVALID_PROP_ID = 0;
constexpr char CAR_MAKE[] = "Default Car";
@@ -93,11 +101,51 @@
FakeVehicleHardware* getHardware() { return &mHardware; }
StatusCode setValues(const std::vector<SetValueRequest>& requests) {
- return getHardware()->setValues(mSetValuesCallback, requests);
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ for (const auto& request : requests) {
+ mPendingSetValueRequests.insert(request.requestId);
+ }
+ }
+ if (StatusCode status = getHardware()->setValues(mSetValuesCallback, requests);
+ status != StatusCode::OK) {
+ return status;
+ }
+ std::unique_lock<std::mutex> lk(mLock);
+ // Wait for the onSetValueResults.
+ bool result = mCv.wait_for(lk, milliseconds(1000), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mPendingSetValueRequests.size() == 0;
+ });
+ if (!result) {
+ ALOGE("wait for callbacks for setValues timed-out");
+ return StatusCode::INTERNAL_ERROR;
+ }
+ return StatusCode::OK;
}
StatusCode getValues(const std::vector<GetValueRequest>& requests) {
- return getHardware()->getValues(mGetValuesCallback, requests);
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ for (const auto& request : requests) {
+ mPendingGetValueRequests.insert(request.requestId);
+ }
+ }
+ if (StatusCode status = getHardware()->getValues(mGetValuesCallback, requests);
+ status != StatusCode::OK) {
+ return status;
+ }
+ std::unique_lock<std::mutex> lk(mLock);
+ // Wait for the onGetValueResults.
+ bool result = mCv.wait_for(lk, milliseconds(1000), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mPendingGetValueRequests.size() == 0;
+ });
+ if (!result) {
+ ALOGE("wait for callbacks for getValues timed-out");
+ return StatusCode::INTERNAL_ERROR;
+ }
+ return StatusCode::OK;
}
StatusCode setValue(const VehiclePropValue& value) {
@@ -158,30 +206,69 @@
}
void onSetValues(std::vector<SetValueResult> results) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
for (auto& result : results) {
mSetValueResults.push_back(result);
+ mPendingSetValueRequests.erase(result.requestId);
}
+ mCv.notify_all();
}
- const std::vector<SetValueResult>& getSetValueResults() { return mSetValueResults; }
+ const std::vector<SetValueResult>& getSetValueResults() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mSetValueResults;
+ }
void onGetValues(std::vector<GetValueResult> results) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
for (auto& result : results) {
mGetValueResults.push_back(result);
+ mPendingGetValueRequests.erase(result.requestId);
}
+ mCv.notify_all();
}
- const std::vector<GetValueResult>& getGetValueResults() { return mGetValueResults; }
+ const std::vector<GetValueResult>& getGetValueResults() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mGetValueResults;
+ }
void onPropertyChangeEvent(std::vector<VehiclePropValue> values) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
for (auto& value : values) {
mChangedProperties.push_back(value);
+ PropIdAreaId propIdAreaId{
+ .propId = value.prop,
+ .areaId = value.areaId,
+ };
+ mEventCount[propIdAreaId]++;
}
+ mCv.notify_all();
}
- const std::vector<VehiclePropValue>& getChangedProperties() { return mChangedProperties; }
+ const std::vector<VehiclePropValue>& getChangedProperties() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return mChangedProperties;
+ }
- void clearChangedProperties() { mChangedProperties.clear(); }
+ bool waitForChangedProperties(int32_t propId, int32_t areaId, size_t count,
+ milliseconds timeout) {
+ PropIdAreaId propIdAreaId{
+ .propId = propId,
+ .areaId = areaId,
+ };
+ std::unique_lock<std::mutex> lk(mLock);
+ return mCv.wait_for(lk, timeout, [this, propIdAreaId, count] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mEventCount[propIdAreaId] >= count;
+ });
+ }
+
+ void clearChangedProperties() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mEventCount.clear();
+ mChangedProperties.clear();
+ }
static void addSetValueRequest(std::vector<SetValueRequest>& requests,
std::vector<SetValueResult>& expectedResults, int64_t requestId,
@@ -246,11 +333,16 @@
private:
FakeVehicleHardware mHardware;
- std::vector<SetValueResult> mSetValueResults;
- std::vector<GetValueResult> mGetValueResults;
- std::vector<VehiclePropValue> mChangedProperties;
std::shared_ptr<IVehicleHardware::SetValuesCallback> mSetValuesCallback;
std::shared_ptr<IVehicleHardware::GetValuesCallback> mGetValuesCallback;
+ std::condition_variable mCv;
+ std::mutex mLock;
+ std::unordered_map<PropIdAreaId, size_t, PropIdAreaIdHash> mEventCount GUARDED_BY(mLock);
+ std::vector<SetValueResult> mSetValueResults GUARDED_BY(mLock);
+ std::vector<GetValueResult> mGetValueResults GUARDED_BY(mLock);
+ std::vector<VehiclePropValue> mChangedProperties GUARDED_BY(mLock);
+ std::unordered_set<int64_t> mPendingSetValueRequests GUARDED_BY(mLock);
+ std::unordered_set<int64_t> mPendingGetValueRequests GUARDED_BY(mLock);
};
TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
@@ -1313,6 +1405,28 @@
ASSERT_THAT(result.buffer, ContainsRegex("Invalid option: --invalid"));
}
+TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHalHelp) {
+ std::vector<std::string> options;
+ options.push_back("--user-hal");
+
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex("dumps state used for user management"));
+}
+
+TEST_F(FakeVehicleHardwareTest, testDumpFakeUserHal) {
+ std::vector<std::string> options;
+ options.push_back("--user-hal");
+ // Indent: " ".
+ options.push_back(" ");
+
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer, ContainsRegex(" No InitialUserInfo response\n"));
+}
+
struct SetPropTestCase {
std::string test_name;
std::vector<std::string> options;
@@ -1510,6 +1624,35 @@
ASSERT_EQ(result.value().value.byteValues, std::vector<uint8_t>({0x04, 0x03, 0x02, 0x01}));
}
+TEST_F(FakeVehicleHardwareTest, testUpdateSampleRate) {
+ int32_t propSpeed = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
+ int32_t propSteering = toInt(VehicleProperty::PERF_STEERING_ANGLE);
+ int32_t areaId = 0;
+ getHardware()->updateSampleRate(propSpeed, areaId, 5);
+
+ ASSERT_TRUE(waitForChangedProperties(propSpeed, areaId, /*count=*/5, milliseconds(1500)))
+ << "not enough events generated for speed";
+
+ getHardware()->updateSampleRate(propSteering, areaId, 10);
+
+ ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/10, milliseconds(1500)))
+ << "not enough events generated for steering";
+
+ int64_t timestamp = elapsedRealtimeNano();
+ // Disable refreshing for propSpeed.
+ getHardware()->updateSampleRate(propSpeed, areaId, 0);
+ clearChangedProperties();
+
+ ASSERT_TRUE(waitForChangedProperties(propSteering, areaId, /*count=*/5, milliseconds(1500)))
+ << "should still receive steering events after disable polling for speed";
+ auto updatedValues = getChangedProperties();
+ for (auto& value : updatedValues) {
+ ASSERT_GE(value.timestamp, timestamp);
+ ASSERT_EQ(value.prop, propSteering);
+ ASSERT_EQ(value.areaId, areaId);
+ }
+}
+
} // namespace fake
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 4a38827..759db41 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -80,6 +80,35 @@
const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
requests) const = 0;
+ // Update the sampling rate for the specified property and the specified areaId (0 for global
+ // property) if server supports it. The property must be a continuous property.
+ // {@code sampleRate} means that for this specific property, the server must generate at least
+ // this many OnPropertyChange events per seconds.
+ // A sampleRate of 0 means the property is no longer subscribed and server does not need to
+ // generate any onPropertyEvent for this property.
+ // This would be called if sample rate is updated for a subscriber, a new subscriber is added
+ // or an existing subscriber is removed. For example:
+ // 1. We have no subscriber for speed.
+ // 2. A new subscriber is subscribing speed for 10 times/s, updsateSampleRate would be called
+ // with sampleRate as 10. The impl is now polling vehicle speed from bus 10 times/s.
+ // 3. A new subscriber is subscribing speed for 5 times/s, because it is less than 10
+ // times/sec, updateSampleRate would not be called.
+ // 4. The initial subscriber is removed, updateSampleRate would be called with sampleRate as
+ // 5, because now it only needs to report event 5times/sec. The impl can now poll vehicle
+ // speed 5 times/s. If the impl is still polling at 10 times/s, that is okay as long as
+ // the polling rate is larger than 5times/s. DefaultVehicleHal would ignore the additional
+ // events.
+ // 5. The second subscriber is removed, updateSampleRate would be called with sampleRate as 0.
+ // The impl can optionally disable the polling for vehicle speed.
+ //
+ // If the impl is always polling at {@code maxSampleRate} as specified in config, then this
+ // function can be a no-op.
+ virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
+ [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId,
+ [[maybe_unused]] float sampleRate) {
+ return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+ }
+
// Dump debug information in the server.
virtual DumpResult dump(const std::vector<std::string>& options) = 0;
diff --git a/automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
similarity index 100%
rename from automotive/vehicle/aidl/impl/vhal/include/RecurrentTimer.h
rename to automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 6d7d131..c94bad6 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -21,6 +21,7 @@
#include <android-base/format.h>
#include <android-base/result.h>
+#include <math/HashCombine.h>
#include <utils/Log.h>
namespace android {
@@ -310,6 +311,24 @@
return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
}
+struct PropIdAreaId {
+ int32_t propId;
+ int32_t areaId;
+
+ inline bool operator==(const PropIdAreaId& other) const {
+ return areaId == other.areaId && propId == other.propId;
+ }
+};
+
+struct PropIdAreaIdHash {
+ inline size_t operator()(const PropIdAreaId& propIdAreaId) const {
+ size_t res = 0;
+ hashCombine(res, propIdAreaId.propId);
+ hashCombine(res, propIdAreaId.areaId);
+ return res;
+ }
+};
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
similarity index 100%
rename from automotive/vehicle/aidl/impl/vhal/src/RecurrentTimer.cpp
rename to automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
diff --git a/automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
similarity index 100%
rename from automotive/vehicle/aidl/impl/vhal/test/RecurrentTimerTest.cpp
rename to automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp
index 49f48f7..5abcaf6 100644
--- a/automotive/vehicle/aidl/impl/vhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/vhal/Android.bp
@@ -54,7 +54,6 @@
srcs: [
"src/ConnectedClient.cpp",
"src/DefaultVehicleHal.cpp",
- "src/RecurrentTimer.cpp",
"src/SubscriptionManager.cpp",
],
static_libs: [
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index f646b6b..9c29816 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -17,10 +17,11 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
-#include "ConnectedClient.h"
-#include "ParcelableUtils.h"
-#include "PendingRequestPool.h"
-#include "SubscriptionManager.h"
+#include <ConnectedClient.h>
+#include <ParcelableUtils.h>
+#include <PendingRequestPool.h>
+#include <RecurrentTimer.h>
+#include <SubscriptionManager.h>
#include <ConcurrentQueue.h>
#include <IVehicleHardware.h>
@@ -163,7 +164,7 @@
static constexpr int64_t TIMEOUT_IN_NANO = 30'000'000'000;
// heart beat event interval: 3s
static constexpr int64_t HEART_BEAT_INTERVAL_IN_NANO = 3'000'000'000;
- const std::shared_ptr<IVehicleHardware> mVehicleHardware;
+ std::unique_ptr<IVehicleHardware> mVehicleHardware;
// mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
// lock guard them.
@@ -188,6 +189,8 @@
// mBinderImpl is only going to be changed in test.
std::unique_ptr<IBinder> mBinderImpl;
+ // Only initialized once.
+ std::shared_ptr<std::function<void()>> mRecurrentAction;
// RecurrentTimer is thread-safe.
RecurrentTimer mRecurrentTimer;
@@ -243,18 +246,12 @@
std::unordered_map<const AIBinder*, 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,
+ static void checkHealth(IVehicleHardware* hardware,
std::weak_ptr<SubscriptionManager> subscriptionManager);
static void onBinderDied(void* cookie);
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index b0d6701..7c8f1b4 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -17,15 +17,16 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_SubscriptionManager_H_
-#include "RecurrentTimer.h"
-
+#include <IVehicleHardware.h>
#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
#include <android-base/result.h>
#include <android-base/thread_annotations.h>
#include <mutex>
+#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <vector>
@@ -35,43 +36,58 @@
namespace automotive {
namespace vehicle {
+// A class to represent all the subscription configs for a continuous [propId, areaId].
+class ContSubConfigs final {
+ public:
+ using ClientIdType = const AIBinder*;
+
+ void addClient(const ClientIdType& clientId, float sampleRate);
+ void removeClient(const ClientIdType& clientId);
+ float getMaxSampleRate();
+
+ private:
+ float mMaxSampleRate = 0.;
+ std::unordered_map<ClientIdType, float> mSampleRates;
+
+ void refreshMaxSampleRate();
+};
+
// A thread-safe subscription manager that manages all VHAL subscriptions.
class SubscriptionManager final {
public:
using ClientIdType = const AIBinder*;
using CallbackType =
std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
- using GetValueFunc = std::function<void(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
- explicit SubscriptionManager(GetValueFunc&& action);
+ explicit SubscriptionManager(IVehicleHardware* hardware);
~SubscriptionManager();
// Subscribes to properties according to {@code SubscribeOptions}. Note that all option must
// contain non-empty areaIds field, which contains all area IDs to subscribe. As a result,
// the options here is different from the options passed from VHAL client.
- // Returns error if any of the subscribe options is not valid. If error is returned, no
- // properties would be subscribed.
+ // Returns error if any of the subscribe options is not valid or one of the properties failed
+ // to subscribe. Part of the properties maybe be subscribed successfully if this function
+ // returns error. Caller is safe to retry since subscribing to an already subscribed property
+ // is okay.
// Returns ok if all the options are parsed correctly and all the properties are subscribed.
- android::base::Result<void> subscribe(
+ VhalResult<void> subscribe(
const CallbackType& callback,
const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
options,
bool isContinuousProperty);
// Unsubscribes from the properties for the client.
- // Returns error if the client was not subscribed before or one of the given property was not
- // subscribed. If error is returned, no property would be unsubscribed.
+ // Returns error if the client was not subscribed before, or one of the given property was not
+ // subscribed, or one of the property failed to unsubscribe. Caller is safe to retry since
+ // unsubscribing to an already unsubscribed property is okay (it would be ignored).
// Returns ok if all the requested properties for the client are unsubscribed.
- android::base::Result<void> unsubscribe(ClientIdType client,
- const std::vector<int32_t>& propIds);
+ VhalResult<void> unsubscribe(ClientIdType client, const std::vector<int32_t>& propIds);
// Unsubscribes from all the properties for the client.
- // Returns error if the client was not subscribed before. If error is returned, no property
- // would be unsubscribed.
+ // Returns error if the client was not subscribed before or one of the subscribed properties
+ // for the client failed to unsubscribe. Caller is safe to retry.
// Returns ok if all the properties for the client are unsubscribed.
- android::base::Result<void> unsubscribe(ClientIdType client);
+ VhalResult<void> unsubscribe(ClientIdType client);
// For a list of updated properties, returns a map that maps clients subscribing to
// the updated properties to a list of updated values. This would only return on-change property
@@ -83,6 +99,11 @@
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
updatedValues);
+ // Gets the sample rate for the continuous property. Returns {@code std::nullopt} if the
+ // property has not been subscribed before or is not a continuous property.
+ std::optional<float> getSampleRate(const ClientIdType& clientId, int32_t propId,
+ int32_t areaId);
+
// Checks whether the sample rate is valid.
static bool checkSampleRate(float sampleRate);
@@ -90,65 +111,28 @@
// Friend class for testing.
friend class DefaultVehicleHalTest;
- struct PropIdAreaId {
- int32_t propId;
- int32_t areaId;
-
- bool operator==(const PropIdAreaId& other) const;
- };
-
- struct PropIdAreaIdHash {
- size_t operator()(const PropIdAreaId& propIdAreaId) const;
- };
-
- // A class to represent a registered subscription.
- class Subscription {
- public:
- Subscription() = default;
-
- Subscription(const Subscription&) = delete;
-
- virtual ~Subscription() = default;
-
- virtual bool isOnChange();
- };
-
- // A subscription for OnContinuous property. The registered action would be called recurrently
- // until this class is destructed.
- class RecurrentSubscription final : public Subscription {
- public:
- explicit RecurrentSubscription(std::shared_ptr<RecurrentTimer> timer,
- std::function<void()>&& action, int64_t interval);
- ~RecurrentSubscription();
-
- bool isOnChange() override;
-
- private:
- std::shared_ptr<std::function<void()>> mAction;
- std::shared_ptr<RecurrentTimer> mTimer;
- };
-
- // A subscription for OnChange property.
- class OnChangeSubscription final : public Subscription {
- public:
- bool isOnChange() override;
- };
+ IVehicleHardware* mVehicleHardware;
mutable std::mutex mLock;
std::unordered_map<PropIdAreaId, std::unordered_map<ClientIdType, CallbackType>,
PropIdAreaIdHash>
mClientsByPropIdArea GUARDED_BY(mLock);
- std::unordered_map<ClientIdType, std::unordered_map<PropIdAreaId, std::unique_ptr<Subscription>,
- PropIdAreaIdHash>>
- mSubscriptionsByClient GUARDED_BY(mLock);
- // RecurrentTimer is thread-safe.
- std::shared_ptr<RecurrentTimer> mTimer;
- const GetValueFunc mGetValue;
+ std::unordered_map<ClientIdType, std::unordered_set<PropIdAreaId, PropIdAreaIdHash>>
+ mSubscribedPropsByClient GUARDED_BY(mLock);
+ std::unordered_map<PropIdAreaId, ContSubConfigs, PropIdAreaIdHash> mContSubConfigsByPropIdArea
+ GUARDED_BY(mLock);
- static android::base::Result<int64_t> getInterval(float sampleRate);
+ VhalResult<void> updateSampleRateLocked(const ClientIdType& clientId,
+ const PropIdAreaId& propIdAreaId, float sampleRate)
+ REQUIRES(mLock);
+ VhalResult<void> removeSampleRateLocked(const ClientIdType& clientId,
+ const PropIdAreaId& propIdAreaId) REQUIRES(mLock);
// Checks whether the manager is empty. For testing purpose.
bool isEmpty();
+
+ // Get the interval in nanoseconds accroding to sample rate.
+ static android::base::Result<int64_t> getInterval(float sampleRate);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 82f2c1b..b191aef 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -144,15 +144,11 @@
}
mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
+ 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));
+ IVehicleHardware* hardwarePtr = mVehicleHardware.get();
+ mSubscriptionManager = std::make_shared<SubscriptionManager>(hardwarePtr);
std::weak_ptr<SubscriptionManager> subscriptionManagerCopy = mSubscriptionManager;
mVehicleHardware->registerOnPropertyChangeEvent(
@@ -162,11 +158,11 @@
}));
// Register heartbeat event.
- mRecurrentTimer.registerTimerCallback(
- HEART_BEAT_INTERVAL_IN_NANO,
- std::make_shared<std::function<void()>>([hardwareCopy, subscriptionManagerCopy]() {
- checkHealth(hardwareCopy, subscriptionManagerCopy);
- }));
+ mRecurrentAction =
+ std::make_shared<std::function<void()>>([hardwarePtr, subscriptionManagerCopy]() {
+ checkHealth(hardwarePtr, subscriptionManagerCopy);
+ });
+ mRecurrentTimer.registerTimerCallback(HEART_BEAT_INTERVAL_IN_NANO, mRecurrentAction);
mBinderImpl = std::make_unique<AIBinderImpl>();
mOnBinderDiedUnlinkedHandlerThread = std::thread([this] { onBinderDiedUnlinkedHandler(); });
@@ -183,6 +179,13 @@
if (mOnBinderDiedUnlinkedHandlerThread.joinable()) {
mOnBinderDiedUnlinkedHandlerThread.join();
}
+ // mRecurrentAction uses pointer to mVehicleHardware, so it has to be unregistered before
+ // mVehicleHardware.
+ mRecurrentTimer.unregisterTimerCallback(mRecurrentAction);
+ // mSubscriptionManager uses pointer to mVehicleHardware, so it has to be destroyed before
+ // mVehicleHardware.
+ mSubscriptionManager.reset();
+ mVehicleHardware.reset();
}
void DefaultVehicleHal::onPropertyChangeEvent(
@@ -294,43 +297,6 @@
std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients,
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
-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 (client == nullptr) {
- ALOGW("subscribe[%" PRId64 "]: the client has died", subscribeId);
- return;
- }
- if (auto addRequestResult = client->addRequests({subscribeId}); !addRequestResult.ok()) {
- ALOGE("subscribe[%" PRId64 "]: too many pending requests, ignore the getValue request",
- subscribeId);
- return;
- }
-
- std::vector<GetValueRequest> hardwareRequests = {{
- .requestId = subscribeId,
- .prop = value,
- }};
-
- 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.
- client->tryFinishRequests({subscribeId});
- ALOGE("subscribe[%" PRId64 "]: failed to get value from VehicleHardware, code: %d",
- subscribeId, toInt(status));
- }
-}
-
void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
}
@@ -705,12 +671,13 @@
// Since we have already check the sample rates, the following functions must succeed.
if (!onChangeSubscriptions.empty()) {
- mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
- /*isContinuousProperty=*/false);
+ return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+ /*isContinuousProperty=*/false));
}
if (!continuousSubscriptions.empty()) {
- mSubscriptionManager->subscribe(callback, continuousSubscriptions,
- /*isContinuousProperty=*/true);
+ return toScopedAStatus(mSubscriptionManager->subscribe(callback,
+ continuousSubscriptions,
+ /*isContinuousProperty=*/true));
}
}
return ScopedAStatus::ok();
@@ -718,8 +685,7 @@
ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType& callback,
const std::vector<int32_t>& propIds) {
- return toScopedAStatus(mSubscriptionManager->unsubscribe(callback->asBinder().get(), propIds),
- StatusCode::INVALID_ARG);
+ return toScopedAStatus(mSubscriptionManager->unsubscribe(callback->asBinder().get(), propIds));
}
ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
@@ -763,15 +729,9 @@
return {};
}
-void DefaultVehicleHal::checkHealth(std::weak_ptr<IVehicleHardware> hardware,
+void DefaultVehicleHal::checkHealth(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();
+ StatusCode status = hardware->checkHealth();
if (status != StatusCode::OK) {
ALOGE("VHAL check health returns non-okay status");
return;
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index 21bfba6..2694401 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -16,8 +16,11 @@
#include "SubscriptionManager.h"
-#include <math/HashCombine.h>
+#include <android-base/stringprintf.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <inttypes.h>
namespace android {
namespace hardware {
@@ -31,33 +34,21 @@
} // namespace
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::VehiclePropValue;
using ::android::base::Error;
using ::android::base::Result;
+using ::android::base::StringPrintf;
using ::ndk::ScopedAStatus;
-bool SubscriptionManager::PropIdAreaId::operator==(const PropIdAreaId& other) const {
- return areaId == other.areaId && propId == other.propId;
-}
-
-size_t SubscriptionManager::PropIdAreaIdHash::operator()(PropIdAreaId const& propIdAreaId) const {
- size_t res = 0;
- hashCombine(res, propIdAreaId.propId);
- hashCombine(res, propIdAreaId.areaId);
- return res;
-}
-
-SubscriptionManager::SubscriptionManager(GetValueFunc&& action)
- : mTimer(std::make_shared<RecurrentTimer>()), mGetValue(std::move(action)) {}
+SubscriptionManager::SubscriptionManager(IVehicleHardware* hardware) : mVehicleHardware(hardware) {}
SubscriptionManager::~SubscriptionManager() {
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();
+ mSubscribedPropsByClient.clear();
}
bool SubscriptionManager::checkSampleRate(float sampleRate) {
@@ -76,9 +67,84 @@
return interval;
}
-Result<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCallback>& callback,
- const std::vector<SubscribeOptions>& options,
- bool isContinuousProperty) {
+void ContSubConfigs::refreshMaxSampleRate() {
+ float maxSampleRate = 0.;
+ // This is not called frequently so a brute-focre is okay. More efficient way exists but this
+ // is simpler.
+ for (const auto& [_, sampleRate] : mSampleRates) {
+ if (sampleRate > maxSampleRate) {
+ maxSampleRate = sampleRate;
+ }
+ }
+ mMaxSampleRate = maxSampleRate;
+}
+
+void ContSubConfigs::addClient(const ClientIdType& clientId, float sampleRate) {
+ mSampleRates[clientId] = sampleRate;
+ refreshMaxSampleRate();
+}
+
+void ContSubConfigs::removeClient(const ClientIdType& clientId) {
+ mSampleRates.erase(clientId);
+ refreshMaxSampleRate();
+}
+
+float ContSubConfigs::getMaxSampleRate() {
+ return mMaxSampleRate;
+}
+
+VhalResult<void> SubscriptionManager::updateSampleRateLocked(const ClientIdType& clientId,
+ const PropIdAreaId& propIdAreaId,
+ float sampleRate) {
+ // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
+ ContSubConfigs infoCopy = mContSubConfigsByPropIdArea[propIdAreaId];
+ infoCopy.addClient(clientId, sampleRate);
+ if (infoCopy.getMaxSampleRate() ==
+ mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRate()) {
+ mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
+ return {};
+ }
+ float newRate = infoCopy.getMaxSampleRate();
+ int32_t propId = propIdAreaId.propId;
+ int32_t areaId = propIdAreaId.areaId;
+ if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRate);
+ status != StatusCode::OK) {
+ return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
+ ", area"
+ ": %" PRId32 ", sample rate: %f",
+ propId, areaId, newRate);
+ }
+ mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
+ return {};
+}
+
+VhalResult<void> SubscriptionManager::removeSampleRateLocked(const ClientIdType& clientId,
+ const PropIdAreaId& propIdAreaId) {
+ // Make a copy so that we don't modify 'mContSubConfigsByPropIdArea' on failure cases.
+ ContSubConfigs infoCopy = mContSubConfigsByPropIdArea[propIdAreaId];
+ infoCopy.removeClient(clientId);
+ if (infoCopy.getMaxSampleRate() ==
+ mContSubConfigsByPropIdArea[propIdAreaId].getMaxSampleRate()) {
+ mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
+ return {};
+ }
+ float newRate = infoCopy.getMaxSampleRate();
+ int32_t propId = propIdAreaId.propId;
+ int32_t areaId = propIdAreaId.areaId;
+ if (auto status = mVehicleHardware->updateSampleRate(propId, areaId, newRate);
+ status != StatusCode::OK) {
+ return StatusError(status) << StringPrintf("failed to update sample rate for prop: %" PRId32
+ ", area"
+ ": %" PRId32 ", sample rate: %f",
+ propId, areaId, newRate);
+ }
+ mContSubConfigsByPropIdArea[propIdAreaId] = infoCopy;
+ return {};
+}
+
+VhalResult<void> SubscriptionManager::subscribe(const std::shared_ptr<IVehicleCallback>& callback,
+ const std::vector<SubscribeOptions>& options,
+ bool isContinuousProperty) {
std::scoped_lock<std::mutex> lockGuard(mLock);
std::vector<int64_t> intervals;
@@ -88,109 +154,108 @@
if (isContinuousProperty) {
auto intervalResult = getInterval(sampleRate);
if (!intervalResult.ok()) {
- return intervalResult.error();
+ return StatusError(StatusCode::INVALID_ARG) << intervalResult.error().message();
}
- intervals.push_back(intervalResult.value());
}
if (option.areaIds.empty()) {
ALOGE("area IDs to subscribe must not be empty");
- return Error() << "area IDs to subscribe must not be empty";
+ return StatusError(StatusCode::INVALID_ARG)
+ << "area IDs to subscribe must not be empty";
}
}
- size_t intervalIndex = 0;
ClientIdType clientId = callback->asBinder().get();
+
for (const auto& option : options) {
int32_t propId = option.propId;
const std::vector<int32_t>& areaIds = option.areaIds;
- int64_t interval = 0;
- if (isContinuousProperty) {
- interval = intervals[intervalIndex];
- intervalIndex++;
- }
for (int32_t areaId : areaIds) {
PropIdAreaId propIdAreaId = {
.propId = propId,
.areaId = areaId,
};
if (isContinuousProperty) {
- VehiclePropValue propValueRequest{
- .prop = propId,
- .areaId = areaId,
- };
- mSubscriptionsByClient[clientId][propIdAreaId] =
- std::make_unique<RecurrentSubscription>(
- mTimer,
- [this, callback, propValueRequest] {
- mGetValue(callback, propValueRequest);
- },
- interval);
- } else {
- mSubscriptionsByClient[clientId][propIdAreaId] =
- std::make_unique<OnChangeSubscription>();
+ if (auto result = updateSampleRateLocked(clientId, propIdAreaId, option.sampleRate);
+ !result.ok()) {
+ return result;
+ }
}
+
+ mSubscribedPropsByClient[clientId].insert(propIdAreaId);
mClientsByPropIdArea[propIdAreaId][clientId] = callback;
}
}
return {};
}
-Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
- const std::vector<int32_t>& propIds) {
+VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId,
+ const std::vector<int32_t>& propIds) {
std::scoped_lock<std::mutex> lockGuard(mLock);
- if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
- return Error() << "No property was subscribed for the callback";
+ if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
+ return StatusError(StatusCode::INVALID_ARG)
+ << "No property was subscribed for the callback";
}
std::unordered_set<int32_t> subscribedPropIds;
- for (auto const& [propIdAreaId, _] : mSubscriptionsByClient[clientId]) {
+ for (auto const& propIdAreaId : mSubscribedPropsByClient[clientId]) {
subscribedPropIds.insert(propIdAreaId.propId);
}
for (int32_t propId : propIds) {
if (subscribedPropIds.find(propId) == subscribedPropIds.end()) {
- return Error() << "property ID: " << propId << " is not subscribed";
+ return StatusError(StatusCode::INVALID_ARG)
+ << "property ID: " << propId << " is not subscribed";
}
}
- auto& subscriptions = mSubscriptionsByClient[clientId];
- auto it = subscriptions.begin();
- while (it != subscriptions.end()) {
- int32_t propId = it->first.propId;
+ auto& propIdAreaIds = mSubscribedPropsByClient[clientId];
+ auto it = propIdAreaIds.begin();
+ while (it != propIdAreaIds.end()) {
+ int32_t propId = it->propId;
if (std::find(propIds.begin(), propIds.end(), propId) != propIds.end()) {
- auto& clients = mClientsByPropIdArea[it->first];
+ if (auto result = removeSampleRateLocked(clientId, *it); !result.ok()) {
+ return result;
+ }
+
+ auto& clients = mClientsByPropIdArea[*it];
clients.erase(clientId);
if (clients.empty()) {
- mClientsByPropIdArea.erase(it->first);
+ mClientsByPropIdArea.erase(*it);
+ mContSubConfigsByPropIdArea.erase(*it);
}
- it = subscriptions.erase(it);
+ it = propIdAreaIds.erase(it);
} else {
it++;
}
}
- if (subscriptions.empty()) {
- mSubscriptionsByClient.erase(clientId);
+ if (propIdAreaIds.empty()) {
+ mSubscribedPropsByClient.erase(clientId);
}
return {};
}
-Result<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId) {
+VhalResult<void> SubscriptionManager::unsubscribe(SubscriptionManager::ClientIdType clientId) {
std::scoped_lock<std::mutex> lockGuard(mLock);
- if (mSubscriptionsByClient.find(clientId) == mSubscriptionsByClient.end()) {
- return Error() << "No property was subscribed for this client";
+ if (mSubscribedPropsByClient.find(clientId) == mSubscribedPropsByClient.end()) {
+ return StatusError(StatusCode::INVALID_ARG) << "No property was subscribed for this client";
}
- auto& subscriptions = mSubscriptionsByClient[clientId];
- for (auto const& [propIdAreaId, _] : subscriptions) {
+ auto& subscriptions = mSubscribedPropsByClient[clientId];
+ for (auto const& propIdAreaId : subscriptions) {
+ if (auto result = removeSampleRateLocked(clientId, propIdAreaId); !result.ok()) {
+ return result;
+ }
+
auto& clients = mClientsByPropIdArea[propIdAreaId];
clients.erase(clientId);
if (clients.empty()) {
mClientsByPropIdArea.erase(propIdAreaId);
+ mContSubConfigsByPropIdArea.erase(propIdAreaId);
}
}
- mSubscriptionsByClient.erase(clientId);
+ mSubscribedPropsByClient.erase(clientId);
return {};
}
@@ -208,10 +273,8 @@
if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
continue;
}
- for (const auto& [clientId, client] : mClientsByPropIdArea[propIdAreaId]) {
- if (!mSubscriptionsByClient[clientId][propIdAreaId]->isOnChange()) {
- continue;
- }
+
+ for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
clients[client].push_back(&value);
}
}
@@ -220,25 +283,7 @@
bool SubscriptionManager::isEmpty() {
std::scoped_lock<std::mutex> lockGuard(mLock);
- return mSubscriptionsByClient.empty() && mClientsByPropIdArea.empty();
-}
-
-SubscriptionManager::RecurrentSubscription::RecurrentSubscription(
- std::shared_ptr<RecurrentTimer> timer, std::function<void()>&& action, int64_t interval)
- : mAction(std::make_shared<std::function<void()>>(action)), mTimer(timer) {
- mTimer->registerTimerCallback(interval, mAction);
-}
-
-SubscriptionManager::RecurrentSubscription::~RecurrentSubscription() {
- mTimer->unregisterTimerCallback(mAction);
-}
-
-bool SubscriptionManager::RecurrentSubscription::isOnChange() {
- return false;
-}
-
-bool SubscriptionManager::OnChangeSubscription::isOnChange() {
- return true;
+ return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
}
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 49f5b7e..f48b906 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -1308,25 +1308,7 @@
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 = {
{
@@ -1353,28 +1335,6 @@
}
TEST_F(DefaultVehicleHalTest, testSubscribeGlobalContinuousRateOutOfRange) {
- 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;
- });
-
// The maxSampleRate is 100, so the sample rate should be the default max 100.
std::vector<SubscribeOptions> options = {
{
@@ -1398,24 +1358,6 @@
}
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,
@@ -1436,6 +1378,8 @@
// Sleep for 1s, which should generate ~20 events.
std::this_thread::sleep_for(std::chrono::seconds(1));
+ getClient()->unsubscribe(getCallbackClient(), std::vector<int32_t>({AREA_CONTINUOUS_PROP}));
+
std::vector<VehiclePropValue> events;
while (true) {
auto maybeResults = getCallback()->nextOnPropertyEventResults();
@@ -1509,28 +1453,6 @@
}
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,
@@ -1621,12 +1543,6 @@
}
TEST_F(DefaultVehicleHalTest, testOnBinderDiedUnlinked) {
- // First subscribe to a continuous property so that we register a death recipient for our
- // client.
- 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,
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 66aef7c..4df4e1a 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -32,9 +32,14 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+MockVehicleHardware::MockVehicleHardware() {
+ mRecurrentTimer = std::make_unique<RecurrentTimer>();
+}
+
MockVehicleHardware::~MockVehicleHardware() {
std::unique_lock<std::mutex> lk(mLock);
mCv.wait(lk, [this] { return mThreadCount == 0; });
+ mRecurrentTimer.reset();
}
std::vector<VehiclePropConfig> MockVehicleHardware::getAllPropertyConfigs() const {
@@ -83,6 +88,42 @@
return StatusCode::OK;
}
+StatusCode MockVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId, float sampleRate) {
+ std::shared_ptr<std::function<void()>> action;
+
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ if (mRecurrentActions[propId][areaId] != nullptr) {
+ // Remove the previous action register for this [propId, areaId].
+ mRecurrentTimer->unregisterTimerCallback(mRecurrentActions[propId][areaId]);
+ }
+ if (sampleRate == 0) {
+ return StatusCode::OK;
+ }
+
+ // We are sure 'propertyChangeCallback' would be alive because we would unregister timer
+ // before destroying 'this' which owns mPropertyChangeCallback.
+ const PropertyChangeCallback* propertyChangeCallback = mPropertyChangeCallback.get();
+ action = std::make_shared<std::function<void()>>([propertyChangeCallback, propId, areaId] {
+ std::vector<VehiclePropValue> values = {
+ {
+ .prop = propId,
+ .areaId = areaId,
+ },
+ };
+ (*propertyChangeCallback)(values);
+ });
+ // Store the action in a map so that we could remove the action later.
+ mRecurrentActions[propId][areaId] = action;
+ }
+
+ // In mock implementation, we generate a new property change event for this property at sample
+ // rate.
+ int64_t interval = static_cast<int64_t>(1'000'000'000. / sampleRate);
+ mRecurrentTimer->registerTimerCallback(interval, action);
+ return StatusCode::OK;
+}
+
void MockVehicleHardware::registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) {
std::scoped_lock<std::mutex> lockGuard(mLock);
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index cb8b6a0..743841c 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -18,6 +18,7 @@
#define android_hardware_automotive_vehicle_aidl_impl_vhal_test_MockVehicleHardware_H_
#include <IVehicleHardware.h>
+#include <RecurrentTimer.h>
#include <VehicleHalTypes.h>
#include <android-base/thread_annotations.h>
@@ -38,6 +39,8 @@
class MockVehicleHardware final : public IVehicleHardware {
public:
+ MockVehicleHardware();
+
~MockVehicleHardware();
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
@@ -55,6 +58,8 @@
void registerOnPropertyChangeEvent(
std::unique_ptr<const PropertyChangeCallback> callback) override;
void registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback>) override;
+ aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate(
+ int32_t propId, int32_t areaId, float sampleRate) override;
// Test functions.
void setPropertyConfigs(
@@ -117,6 +122,11 @@
std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
DumpResult mDumpResult;
+
+ // RecurrentTimer is thread-safe.
+ std::shared_ptr<RecurrentTimer> mRecurrentTimer;
+ std::unordered_map<int32_t, std::unordered_map<int32_t, std::shared_ptr<std::function<void()>>>>
+ mRecurrentActions GUARDED_BY(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
index 2a468f6..3f59363 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -16,6 +16,7 @@
#include "SubscriptionManager.h"
+#include <MockVehicleHardware.h>
#include <VehicleHalTypes.h>
#include <aidl/android/hardware/automotive/vehicle/BnVehicleCallback.h>
@@ -86,19 +87,21 @@
class SubscriptionManagerTest : public testing::Test {
public:
void SetUp() override {
- mManager = std::make_unique<SubscriptionManager>(
- [](const std::shared_ptr<IVehicleCallback>& callback,
- const VehiclePropValue& value) {
- callback->onPropertyEvent(
- VehiclePropValues{
- .payloads = {value},
- },
- 0);
- });
+ mHardware = std::make_shared<MockVehicleHardware>();
+ mManager = std::make_unique<SubscriptionManager>(mHardware.get());
mCallback = ndk::SharedRefBase::make<PropertyCallback>();
// Keep the local binder alive.
mBinder = mCallback->asBinder();
mCallbackClient = IVehicleCallback::fromBinder(mBinder);
+ std::shared_ptr<IVehicleCallback> callbackClient = mCallbackClient;
+ mHardware->registerOnPropertyChangeEvent(
+ std::make_unique<IVehicleHardware::PropertyChangeCallback>(
+ [callbackClient](std::vector<VehiclePropValue> updatedValues) {
+ VehiclePropValues values = {
+ .payloads = std::move(updatedValues),
+ };
+ callbackClient->onPropertyEvent(values, 0);
+ }));
}
SubscriptionManager* getManager() { return mManager.get(); }
@@ -115,6 +118,7 @@
std::unique_ptr<SubscriptionManager> mManager;
std::shared_ptr<PropertyCallback> mCallback;
std::shared_ptr<IVehicleCallback> mCallbackClient;
+ std::shared_ptr<MockVehicleHardware> mHardware;
SpAIBinder mBinder;
};
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index c33f3e9..c431d85 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -30,6 +30,7 @@
#include <hidl/ServiceManagement.h>
#include <inttypes.h>
#include <utils/Log.h>
+#include <utils/SystemClock.h>
#include <chrono>
#include <mutex>
@@ -67,6 +68,7 @@
private:
std::mutex mLock;
std::unordered_map<int32_t, size_t> mEventsCount GUARDED_BY(mLock);
+ std::unordered_map<int32_t, std::vector<int64_t>> mEventTimestamps GUARDED_BY(mLock);
std::condition_variable mEventCond;
public:
@@ -74,7 +76,9 @@
{
std::lock_guard<std::mutex> lockGuard(mLock);
for (auto& value : values) {
- mEventsCount[value->getPropId()] += 1;
+ int32_t propId = value->getPropId();
+ mEventsCount[propId] += 1;
+ mEventTimestamps[propId].push_back(value->getTimestamp());
}
}
mEventCond.notify_one();
@@ -94,6 +98,13 @@
});
}
+ std::vector<int64_t> getEventTimestamps(int32_t propId) {
+ {
+ std::lock_guard<std::mutex> lockGuard(mLock);
+ return mEventTimestamps[propId];
+ }
+ }
+
void reset() {
std::lock_guard<std::mutex> lockGuard(mLock);
mEventsCount.clear();
@@ -285,19 +296,59 @@
int32_t propId = toInt(VehicleProperty::PERF_VEHICLE_SPEED);
- std::vector<SubscribeOptions> options = {
- SubscribeOptions{.propId = propId, .sampleRate = 10.0}};
+ auto propConfigsResult = mVhalClient->getPropConfigs({propId});
+
+ ASSERT_TRUE(propConfigsResult.ok()) << "Failed to get property config for PERF_VEHICLE_SPEED: "
+ << "error: " << propConfigsResult.error().message();
+ ASSERT_EQ(propConfigsResult.value().size(), 1u)
+ << "Expect to return 1 config for PERF_VEHICLE_SPEED";
+ auto& propConfig = propConfigsResult.value()[0];
+ float minSampleRate = propConfig->getMinSampleRate();
+ float maxSampleRate = propConfig->getMaxSampleRate();
+
+ if (minSampleRate < 1) {
+ GTEST_SKIP() << "Sample rate for vehicle speed < 1 times/sec, skip test since it would "
+ "take too long";
+ }
auto client = mVhalClient->getSubscriptionClient(mCallback);
ASSERT_NE(client, nullptr) << "Failed to get subscription client";
- auto result = client->subscribe(options);
+ auto result = client->subscribe({{.propId = propId, .sampleRate = minSampleRate}});
ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
", error: %s",
propId, result.error().message().c_str());
- ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, 10, std::chrono::seconds(10)))
- << "Didn't get enough events for subscription";
+
+ if (mVhalClient->isAidlVhal()) {
+ // Skip checking timestamp for HIDL because the behavior for sample rate and timestamp is
+ // only specified clearly for AIDL.
+
+ // Timeout is 2 seconds, which gives a 1 second buffer.
+ ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, std::floor(minSampleRate),
+ std::chrono::seconds(2)))
+ << "Didn't get enough events for subscribing to minSampleRate";
+ }
+
+ result = client->subscribe({{.propId = propId, .sampleRate = maxSampleRate}});
+
+ ASSERT_TRUE(result.ok()) << StringPrintf("Failed to subscribe to property: %" PRId32
+ ", error: %s",
+ propId, result.error().message().c_str());
+
+ if (mVhalClient->isAidlVhal()) {
+ ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, std::floor(maxSampleRate),
+ std::chrono::seconds(2)))
+ << "Didn't get enough events for subscribing to maxSampleRate";
+
+ std::unordered_set<int64_t> timestamps;
+ // Event event should have a different timestamp.
+ for (const int64_t& eventTimestamp : mCallback->getEventTimestamps(propId)) {
+ ASSERT_TRUE(timestamps.find(eventTimestamp) == timestamps.end())
+ << "two events for the same property must not have the same timestamp";
+ timestamps.insert(eventTimestamp);
+ }
+ }
result = client->unsubscribe({propId});
ASSERT_TRUE(result.ok()) << StringPrintf("Failed to unsubscribe to property: %" PRId32
@@ -325,6 +376,49 @@
kInvalidProp);
}
+// Test the timestamp returned in GetValues results is the timestamp when the value is retrieved.
+TEST_P(VtsHalAutomotiveVehicleTargetTest, testGetValuesTimestampAIDL) {
+ if (!mVhalClient->isAidlVhal()) {
+ GTEST_SKIP() << "Skip checking timestamp for HIDL because the behavior is only specified "
+ "for AIDL";
+ }
+
+ int32_t propId = toInt(VehicleProperty::PARKING_BRAKE_ON);
+ auto prop = mVhalClient->createHalPropValue(propId);
+
+ auto result = mVhalClient->getValueSync(*prop);
+
+ ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
+ ", error: %s",
+ propId, result.error().message().c_str());
+ ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
+ ASSERT_EQ(result.value()->getInt32Values().size(), 1u) << "Result must contain 1 int value";
+
+ bool parkBrakeOnValue1 = (result.value()->getInt32Values()[0] == 1);
+ int64_t timestampValue1 = result.value()->getTimestamp();
+
+ result = mVhalClient->getValueSync(*prop);
+
+ ASSERT_TRUE(result.ok()) << StringPrintf("Failed to get value for property: %" PRId32
+ ", error: %s",
+ propId, result.error().message().c_str());
+ ASSERT_NE(result.value(), nullptr) << "Result value must not be null";
+ ASSERT_EQ(result.value()->getInt32Values().size(), 1u) << "Result must contain 1 int value";
+
+ bool parkBarkeOnValue2 = (result.value()->getInt32Values()[0] == 1);
+ int64_t timestampValue2 = result.value()->getTimestamp();
+
+ if (parkBarkeOnValue2 == parkBrakeOnValue1) {
+ ASSERT_EQ(timestampValue2, timestampValue1)
+ << "getValue result must contain a timestamp updated when the value was updated, if"
+ "the value does not change, expect the same timestamp";
+ } else {
+ ASSERT_GT(timestampValue2, timestampValue1)
+ << "getValue result must contain a timestamp updated when the value was updated, if"
+ "the value changes, expect the newer value has a larger timestamp";
+ }
+}
+
std::vector<ServiceDescriptor> getDescriptors() {
std::vector<ServiceDescriptor> descriptors;
for (std::string name : getAidlHalInstanceNames(IVehicle::descriptor)) {
diff --git a/bluetooth/1.0/default/test/fuzzer/Android.bp b/bluetooth/1.0/default/test/fuzzer/Android.bp
index 81f328e..691136f 100644
--- a/bluetooth/1.0/default/test/fuzzer/Android.bp
+++ b/bluetooth/1.0/default/test/fuzzer/Android.bp
@@ -46,7 +46,6 @@
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
"libcutils",
- "libutils",
],
shared_libs: [
"android.hardware.bluetooth@1.0",
@@ -54,6 +53,7 @@
"libhidlbase",
"libbt-vendor-fuzz",
"liblog",
+ "libutils",
],
fuzz_config: {
cc: [
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
index 0dd8148..2a88959 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -45,6 +45,7 @@
latency_modes_ = latencyModes;
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
stack_iface_ = host_if;
+ is_binder_died = false;
AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
this);
@@ -59,8 +60,10 @@
if (stack_iface_ != nullptr) {
BluetoothAudioSessionReport::OnSessionEnded(session_type_);
- AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
- death_recipient_.get(), this);
+ if (!is_binder_died) {
+ AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
+ death_recipient_.get(), this);
+ }
} else {
LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
<< " has NO session";
@@ -147,6 +150,7 @@
LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
return;
}
+ provider->is_binder_died = true;
provider->endSession();
}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index a9f830a..dbfff7d 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -62,6 +62,7 @@
std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
SessionType session_type_;
std::vector<LatencyMode> latency_modes_;
+ bool is_binder_died = false;
};
} // namespace audio
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index ae17c51..1d81f7b 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -80,8 +80,9 @@
getDisplayCommand(display).colorTransformMatrix.emplace(std::move(matVec));
}
- void setDisplayBrightness(int64_t display, float brightness) {
- getDisplayCommand(display).brightness.emplace(DisplayBrightness{.brightness = brightness});
+ void setDisplayBrightness(int64_t display, float brightness, float brightnessNits) {
+ getDisplayCommand(display).brightness.emplace(
+ DisplayBrightness{.brightness = brightness, .brightnessNits = brightnessNits});
}
void setClientTarget(int64_t display, uint32_t slot, const native_handle_t* target,
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 147a9ee..c081199 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -974,7 +974,7 @@
// Preconditions to successfully run are knowing the max brightness and successfully applying
// the max brightness
ASSERT_GT(maxBrightnessNits, 0.f);
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f, maxBrightnessNits);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 2d08ac6..2cae5a2 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1374,7 +1374,7 @@
bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
DisplayCapability::BRIGHTNESS) != capabilities.end();
if (!brightnessSupport) {
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
execute();
const auto errors = mReader.takeErrors();
EXPECT_EQ(1, errors.size());
@@ -1383,23 +1383,23 @@
return;
}
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 0.5f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -1.0f, -1.f);
execute();
EXPECT_TRUE(mReader.takeErrors().empty());
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 2.0f, -1.f);
execute();
{
const auto errors = mReader.takeErrors();
@@ -1407,7 +1407,7 @@
EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, errors[0].errorCode);
}
- mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f);
+ mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ -2.0f, -1.f);
execute();
{
const auto errors = mReader.takeErrors();
diff --git a/graphics/mapper/3.0/utils/vts/MapperVts.cpp b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
index de886a9..c470a4a 100644
--- a/graphics/mapper/3.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/3.0/utils/vts/MapperVts.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <mapper-vts/3.0/MapperVts.h>
+#include "gtest/gtest.h"
namespace android {
namespace hardware {
@@ -94,23 +96,31 @@
std::vector<const native_handle_t*> bufferHandles;
bufferHandles.reserve(count);
mAllocator->allocate(
- descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
- ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
-
- for (uint32_t i = 0; i < count; i++) {
- if (import) {
- ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(importBuffer(tmpBuffers[i])));
- } else {
- ASSERT_NO_FATAL_FAILURE(bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+ descriptor, count,
+ [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+ if (tmpError != Error::NONE) {
+ if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0, INT_MAX) < 33) {
+ GTEST_SKIP() << "Old vendor grallocs may not support P010";
+ } else {
+ GTEST_FAIL() << "failed to allocate buffers";
+ }
}
- }
+ ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
- if (outStride) {
- *outStride = tmpStride;
- }
- });
+ for (uint32_t i = 0; i < count; i++) {
+ if (import) {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(importBuffer(tmpBuffers[i])));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+ }
+ }
+
+ if (outStride) {
+ *outStride = tmpStride;
+ }
+ });
if (::testing::Test::HasFatalFailure()) {
bufferHandles.clear();
@@ -127,7 +137,7 @@
}
auto buffers = allocate(descriptor, 1, import, outStride);
- if (::testing::Test::HasFatalFailure()) {
+ if (::testing::Test::HasFatalFailure() || ::testing::Test::IsSkipped()) {
return nullptr;
}
diff --git a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
index 6c90af4..3b1bfab 100644
--- a/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
+++ b/graphics/mapper/3.0/vts/functional/VtsHalGraphicsMapperV3_0TargetTest.cpp
@@ -337,6 +337,10 @@
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
+ if (::testing::Test::IsSkipped()) {
+ GTEST_SKIP();
+ }
+
ASSERT_NE(nullptr, bufferHandle);
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 901f0e3..4a6f68d 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <gralloctypes/Gralloc4.h>
#include <mapper-vts/4.0/MapperVts.h>
@@ -95,7 +96,14 @@
return;
}
- ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+ if (tmpError != Error::NONE) {
+ if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0,
+ INT_MAX) < 33) {
+ GTEST_SKIP() << "Old vendor grallocs may not support P010";
+ } else {
+ GTEST_FAIL() << "failed to allocate buffers";
+ }
+ }
ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
for (uint32_t i = 0; i < count; i++) {
@@ -133,11 +141,7 @@
}
auto buffers = allocate(descriptor, 1, import, tolerance, outStride);
- if (::testing::Test::HasFatalFailure()) {
- return nullptr;
- }
-
- if (buffers.size() != 1) {
+ if (::testing::Test::HasFatalFailure() || ::testing::Test::IsSkipped() || buffers.size() != 1) {
return nullptr;
}
return buffers[0];
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 463b565..8f440e4 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -999,10 +999,13 @@
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YCBCR_P010;
- const native_handle_t* bufferHandle;
uint32_t stride;
- ASSERT_NO_FATAL_FAILURE(
- bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+ const native_handle_t* bufferHandle =
+ mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride);
+
+ if (::testing::Test::IsSkipped()) {
+ GTEST_SKIP();
+ }
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
static_cast<int32_t>(info.height)};
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
index cd06415..fcad499 100644
--- a/health/aidl/OWNERS
+++ b/health/aidl/OWNERS
@@ -1,2 +1,4 @@
# Bug component: 30545
elsk@google.com
+smoreland@google.com
+stayfan@google.com
diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp
index 3a3f4d5..8bc681a 100644
--- a/keymaster/4.0/support/fuzzer/Android.bp
+++ b/keymaster/4.0/support/fuzzer/Android.bp
@@ -30,12 +30,12 @@
"libbase",
"liblog",
"libkeymaster4support",
- "libutils",
],
shared_libs: [
"android.hardware.keymaster@4.0",
"libcrypto",
"libhidlbase",
+ "libutils",
],
fuzz_config: {
cc: [
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 22aa0f9..bf56860 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -2866,8 +2866,8 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string plaintext;
- ErrorCode error = Finish(message, &plaintext);
- if (error == ErrorCode::INVALID_INPUT_LENGTH) {
+ ErrorCode error = Finish(ciphertext, &plaintext);
+ if (error == ErrorCode::INVALID_ARGUMENT) {
// This is the expected error, we can exit the test now.
return;
} else {
diff --git a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index d9a6363..5fa13e7 100644
--- a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -24,6 +24,7 @@
#include <android-base/strings.h>
#include <android/api-level.h>
+#include <VtsCoreUtil.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/omx/1.0/IOmxNode.h>
#include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -377,6 +378,10 @@
return android::base::GetIntProperty("ro.product.first_api_level", __ANDROID_API_T__);
}
+static bool isTV() {
+ return testing::deviceSupportsFeature("android.software.leanback");
+}
+
// list components and roles.
TEST_P(StoreHidlTest, OmxCodecAllowedTest) {
hidl_vec<IOmx::ComponentInfo> componentInfos = getComponentInfoList(omx);
@@ -384,9 +389,16 @@
for (std::string role : info.mRoles) {
if (role.find("video_decoder") != std::string::npos ||
role.find("video_encoder") != std::string::npos) {
- ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
- << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
- << " not allowed for devices launching with Android S and above";
+ // Codec2 is not mandatory on Android TV devices that launched with Android S
+ if (isTV()) {
+ ASSERT_LT(getFirstApiLevel(), __ANDROID_API_T__)
+ << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+ << " not allowed for devices launching with Android T and above";
+ } else {
+ ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
+ << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+ << " not allowed for devices launching with Android S and above";
+ }
}
if (role.find("audio_decoder") != std::string::npos ||
role.find("audio_encoder") != std::string::npos) {
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 5e1c811..258b172 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -59,6 +59,7 @@
serial = GetRandomSerialNumber();
ndk::ScopedAStatus res = radio_config->getHalDeviceCapabilities(serial);
ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
ALOGI("getHalDeviceCapabilities, rspInfo.error = %s\n",
toString(radioRsp_config->rspInfo.error).c_str());
}
@@ -70,6 +71,7 @@
serial = GetRandomSerialNumber();
ndk::ScopedAStatus res = radio_config->getSimSlotsStatus(serial);
ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
ALOGI("getSimSlotsStatus, rspInfo.error = %s\n",
toString(radioRsp_config->rspInfo.error).c_str());
}
@@ -166,31 +168,60 @@
* Test IRadioConfig.setSimSlotsMapping() for the response returned.
*/
TEST_P(RadioConfigTest, setSimSlotsMapping) {
- serial = GetRandomSerialNumber();
- SlotPortMapping slotPortMapping;
- slotPortMapping.physicalSlotId = 0;
- slotPortMapping.portId = 0;
- std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
- if (isDsDsEnabled()) {
- slotPortMapping.physicalSlotId = 1;
- slotPortMappingList.push_back(slotPortMapping);
- } else if (isTsTsEnabled()) {
- slotPortMapping.physicalSlotId = 1;
- slotPortMappingList.push_back(slotPortMapping);
- slotPortMapping.physicalSlotId = 2;
- slotPortMappingList.push_back(slotPortMapping);
- }
- ndk::ScopedAStatus res = radio_config->setSimSlotsMapping(serial, slotPortMappingList);
- ASSERT_OK(res);
- EXPECT_EQ(std::cv_status::no_timeout, wait());
- EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
- EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
- ALOGI("setSimSlotsMapping, rspInfo.error = %s\n",
- toString(radioRsp_config->rspInfo.error).c_str());
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_config->rspInfo.error, {RadioError::NONE}));
+ // get slot status and set SIM slots mapping based on the result.
+ updateSimSlotStatus();
+ if (radioRsp_config->rspInfo.error == RadioError::NONE) {
+ SlotPortMapping slotPortMapping;
+ // put invalid value at first and adjust by slotStatusResponse.
+ slotPortMapping.physicalSlotId = -1;
+ slotPortMapping.portId = -1;
+ std::vector<SlotPortMapping> slotPortMappingList = {slotPortMapping};
+ if (isDsDsEnabled()) {
+ slotPortMappingList.push_back(slotPortMapping);
+ } else if (isTsTsEnabled()) {
+ slotPortMappingList.push_back(slotPortMapping);
+ slotPortMappingList.push_back(slotPortMapping);
+ }
+ for (size_t i = 0; i < radioRsp_config->simSlotStatus.size(); i++) {
+ ASSERT_TRUE(radioRsp_config->simSlotStatus[i].portInfo.size() > 0);
+ for (size_t j = 0; j < radioRsp_config->simSlotStatus[i].portInfo.size(); j++) {
+ if (radioRsp_config->simSlotStatus[i].portInfo[j].portActive) {
+ int32_t logicalSlotId =
+ radioRsp_config->simSlotStatus[i].portInfo[j].logicalSlotId;
+ // logicalSlotId should be 0 or positive numbers if the port
+ // is active.
+ EXPECT_GE(logicalSlotId, 0);
+ // logicalSlotId should be less than the maximum number of
+ // supported SIM slots.
+ EXPECT_LT(logicalSlotId, slotPortMappingList.size());
+ if (logicalSlotId >= 0 && logicalSlotId < slotPortMappingList.size()) {
+ slotPortMappingList[logicalSlotId].physicalSlotId = i;
+ slotPortMappingList[logicalSlotId].portId = j;
+ }
+ }
+ }
+ }
- // Give some time for modem to fully switch SIM configuration
- sleep(MODEM_SET_SIM_SLOT_MAPPING_DELAY_IN_SECONDS);
+ // set SIM slots mapping
+ for (size_t i = 0; i < slotPortMappingList.size(); i++) {
+ // physicalSlotId and portId should be 0 or positive numbers for the
+ // input of setSimSlotsMapping.
+ EXPECT_GE(slotPortMappingList[i].physicalSlotId, 0);
+ EXPECT_GE(slotPortMappingList[i].portId, 0);
+ }
+ serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_config->setSimSlotsMapping(serial, slotPortMappingList);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
+ ALOGI("setSimSlotsMapping, rspInfo.error = %s\n",
+ toString(radioRsp_config->rspInfo.error).c_str());
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_config->rspInfo.error, {RadioError::NONE}));
+
+ // Give some time for modem to fully switch SIM configuration
+ sleep(MODEM_SET_SIM_SLOT_MAPPING_DELAY_IN_SECONDS);
+ }
}
/*
@@ -207,12 +238,24 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_config->rspInfo.type);
EXPECT_EQ(serial, radioRsp_config->rspInfo.serial);
if (radioRsp_config->rspInfo.error == RadioError::NONE) {
+ uint8_t simCount = 0;
// check if cardState is present, portInfo size should be more than 0
for (const SimSlotStatus& slotStatusResponse : radioRsp_config->simSlotStatus) {
if (slotStatusResponse.cardState == CardStatus::STATE_PRESENT) {
ASSERT_TRUE(slotStatusResponse.portInfo.size() > 0);
- ASSERT_TRUE(slotStatusResponse.portInfo[0].portActive);
+ for (const SimPortInfo& simPortInfo : slotStatusResponse.portInfo) {
+ if (simPortInfo.portActive) {
+ simCount++;
+ }
+ }
}
}
+ if (isSsSsEnabled()) {
+ EXPECT_EQ(1, simCount);
+ } else if (isDsDsEnabled()) {
+ EXPECT_EQ(2, simCount);
+ } else if (isTsTsEnabled()) {
+ EXPECT_EQ(3, simCount);
+ }
}
}
diff --git a/radio/aidl/vts/radio_modem_response.cpp b/radio/aidl/vts/radio_modem_response.cpp
index d2715a8..20b44c5 100644
--- a/radio/aidl/vts/radio_modem_response.cpp
+++ b/radio/aidl/vts/radio_modem_response.cpp
@@ -24,6 +24,7 @@
ndk::ScopedAStatus RadioModemResponse::enableModemResponse(const RadioResponseInfo& info) {
rspInfo = info;
+ enableModemResponseToggle = !enableModemResponseToggle;
parent_modem.notify(info.serial);
return ndk::ScopedAStatus::ok();
}
diff --git a/radio/aidl/vts/radio_modem_utils.h b/radio/aidl/vts/radio_modem_utils.h
index 8779e0c..49e1891 100644
--- a/radio/aidl/vts/radio_modem_utils.h
+++ b/radio/aidl/vts/radio_modem_utils.h
@@ -37,7 +37,7 @@
RadioResponseInfo rspInfo;
bool isModemEnabled;
- bool enableModemResponseToggle;
+ bool enableModemResponseToggle = false;
virtual ndk::ScopedAStatus acknowledgeRequest(int32_t serial) override;
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index e1d508d..0bae374 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -592,6 +592,89 @@
}
/*
+ * Test IRadioNetwork.setSignalStrengthReportingCriteria() for multi-RANs per request
+ */
+TEST_P(RadioNetworkTest, setSignalStrengthReportingCriteria_multiRansPerRequest) {
+ SignalThresholdInfo signalThresholdInfoGeran;
+ signalThresholdInfoGeran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
+ signalThresholdInfoGeran.hysteresisMs = 5000;
+ signalThresholdInfoGeran.hysteresisDb = 2;
+ signalThresholdInfoGeran.thresholds = {-109, -103, -97, -89};
+ signalThresholdInfoGeran.isEnabled = true;
+ signalThresholdInfoGeran.ran = AccessNetwork::GERAN;
+
+ SignalThresholdInfo signalThresholdInfoUtran;
+ signalThresholdInfoUtran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSCP;
+ signalThresholdInfoUtran.hysteresisMs = 5000;
+ signalThresholdInfoUtran.hysteresisDb = 2;
+ signalThresholdInfoUtran.thresholds = {-110, -97, -73, -49, -25};
+ signalThresholdInfoUtran.isEnabled = true;
+ signalThresholdInfoUtran.ran = AccessNetwork::UTRAN;
+
+ SignalThresholdInfo signalThresholdInfoEutran;
+ signalThresholdInfoEutran.signalMeasurement = SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSRP;
+ signalThresholdInfoEutran.hysteresisMs = 5000;
+ signalThresholdInfoEutran.hysteresisDb = 2;
+ signalThresholdInfoEutran.thresholds = {-128, -108, -88, -68};
+ signalThresholdInfoEutran.isEnabled = true;
+ signalThresholdInfoEutran.ran = AccessNetwork::EUTRAN;
+
+ SignalThresholdInfo signalThresholdInfoCdma2000;
+ signalThresholdInfoCdma2000.signalMeasurement =
+ SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_RSSI;
+ signalThresholdInfoCdma2000.hysteresisMs = 5000;
+ signalThresholdInfoCdma2000.hysteresisDb = 2;
+ signalThresholdInfoCdma2000.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfoCdma2000.isEnabled = true;
+ signalThresholdInfoCdma2000.ran = AccessNetwork::CDMA2000;
+
+ SignalThresholdInfo signalThresholdInfoNgran;
+ signalThresholdInfoNgran.signalMeasurement =
+ SignalThresholdInfo::SIGNAL_MEASUREMENT_TYPE_SSRSRP;
+ signalThresholdInfoNgran.hysteresisMs = 5000;
+ signalThresholdInfoNgran.hysteresisDb = 0;
+ signalThresholdInfoNgran.thresholds = {-105, -90, -75, -65};
+ signalThresholdInfoNgran.isEnabled = true;
+ signalThresholdInfoNgran.ran = AccessNetwork::NGRAN;
+
+ const static std::vector<SignalThresholdInfo> candidateSignalThresholdInfos = {
+ signalThresholdInfoGeran, signalThresholdInfoUtran, signalThresholdInfoEutran,
+ signalThresholdInfoCdma2000, signalThresholdInfoNgran};
+
+ std::vector<SignalThresholdInfo> supportedSignalThresholdInfos;
+ for (size_t i = 0; i < candidateSignalThresholdInfos.size(); i++) {
+ serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(
+ serial, {candidateSignalThresholdInfos[i]});
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+ supportedSignalThresholdInfos.push_back(signalThresholdInfoGeran);
+ } else {
+ // Refer to IRadioNetworkResponse#setSignalStrengthReportingCriteriaResponse
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_network->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+ }
+ }
+
+ ASSERT_FALSE(supportedSignalThresholdInfos.empty());
+
+ serial = GetRandomSerialNumber();
+ ndk::ScopedAStatus res = radio_network->setSignalStrengthReportingCriteria(
+ serial, supportedSignalThresholdInfos);
+ ASSERT_OK(res);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ALOGI("setSignalStrengthReportingCriteria_multiRansPerRequest, rspInfo.error = %s\n",
+ toString(radioRsp_network->rspInfo.error).c_str());
+
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::NONE}));
+}
+
+/*
* Test IRadioNetwork.setLinkCapacityReportingCriteria() invalid hysteresisDlKbps
*/
TEST_P(RadioNetworkTest, setLinkCapacityReportingCriteria_invalidHysteresisDlKbps) {
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
index ca89555..c30c183 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintOperation.aidl
@@ -242,7 +242,8 @@
* not a multiple of the AES block size, finish() must return
* ErrorCode::INVALID_INPUT_LENGTH. If padding is PaddingMode::PKCS7, pad the data per the
* PKCS#7 specification, including adding an additional padding block if the data is a
- * multiple of the block length.
+ * multiple of the block length. If padding is PaddingMode::PKCS7 and decryption does not
+ * result in valid padding, return ErrorCode::INVALID_ARGUMENT.
*
* o BlockMode::GCM. During encryption, after processing all plaintext, compute the tag
* (Tag::MAC_LENGTH bytes) and append it to the returned ciphertext. During decryption,
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index e73f46c..cbe4512 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -5481,18 +5481,45 @@
EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
string plaintext;
- ErrorCode error = Finish(message, &plaintext);
- if (error == ErrorCode::INVALID_INPUT_LENGTH) {
+ ErrorCode error = Finish(ciphertext, &plaintext);
+ if (error == ErrorCode::INVALID_ARGUMENT) {
// This is the expected error, we can exit the test now.
return;
} else {
// Very small chance we got valid decryption, so try again.
- ASSERT_EQ(error, ErrorCode::OK);
+ ASSERT_EQ(error, ErrorCode::OK)
+ << "Expected INVALID_ARGUMENT or (rarely) OK, got " << error;
}
}
FAIL() << "Corrupt ciphertext should have failed to decrypt by now.";
}
+/*
+ * EncryptionOperationsTest.AesEcbPkcs7CiphertextTooShort
+ *
+ * Verifies that AES decryption fails in the correct way when the padding is corrupted.
+ */
+TEST_P(EncryptionOperationsTest, AesEcbPkcs7CiphertextTooShort) {
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(128)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::ECB)
+ .Padding(PaddingMode::PKCS7)));
+
+ auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+
+ string message = "a";
+ string ciphertext = EncryptMessage(message, params);
+ EXPECT_EQ(16U, ciphertext.size());
+ EXPECT_NE(ciphertext, message);
+
+ // Shorten the ciphertext.
+ ciphertext.resize(ciphertext.size() - 1);
+ EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, params));
+ string plaintext;
+ EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(ciphertext, &plaintext));
+}
+
vector<uint8_t> CopyIv(const AuthorizationSet& set) {
auto iv = set.GetTagValue(TAG_NONCE);
EXPECT_TRUE(iv);
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
index 2ac1884..2c68489 100644
--- a/sensors/aidl/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -229,8 +229,7 @@
*
* @param mem shared memory info data structure.
* @param out channelHandle The registered channel handle.
- * @return The direct channel handle, which is positive if successfully registered, and -1
- * otherwise.
+ * @return The direct channel handle, which is positive if successfully registered.
* @return Status::ok on success
* EX_ILLEGAL_ARGUMENT if the shared memory information is not consistent.
* EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
@@ -245,7 +244,7 @@
* @see OperationMode
* @param mode The operation mode.
* @return Status::ok on success
- * EX_UNSUPPORTED_OPERATION if requested mode is not supported.
+ * EX_UNSUPPORTED_OPERATION or EX_ILLEGAL_ARGUMENT if requested mode is not supported.
* EX_SECURITY if the operation is not allowed.
*/
void setOperationMode(in OperationMode mode);
diff --git a/sensors/aidl/default/multihal/HalProxyAidl.cpp b/sensors/aidl/default/multihal/HalProxyAidl.cpp
index 64805e6..e6bcdad 100644
--- a/sensors/aidl/default/multihal/HalProxyAidl.cpp
+++ b/sensors/aidl/default/multihal/HalProxyAidl.cpp
@@ -29,6 +29,7 @@
using ::aidl::android::hardware::sensors::ISensors;
using ::aidl::android::hardware::sensors::ISensorsCallback;
using ::android::hardware::sensors::V2_1::implementation::convertToOldEvent;
+using ::ndk::ScopedAStatus;
namespace aidl {
namespace android {
@@ -36,19 +37,22 @@
namespace sensors {
namespace implementation {
-static binder_status_t resultToBinderStatus(::android::hardware::sensors::V1_0::Result result) {
- switch (result) {
- case ::android::hardware::sensors::V1_0::Result::OK:
- return STATUS_OK;
- case ::android::hardware::sensors::V1_0::Result::PERMISSION_DENIED:
- return STATUS_PERMISSION_DENIED;
- case ::android::hardware::sensors::V1_0::Result::NO_MEMORY:
- return STATUS_NO_MEMORY;
- case ::android::hardware::sensors::V1_0::Result::BAD_VALUE:
- return STATUS_BAD_VALUE;
- case ::android::hardware::sensors::V1_0::Result::INVALID_OPERATION:
- return STATUS_INVALID_OPERATION;
- }
+static ScopedAStatus
+resultToAStatus(::android::hardware::sensors::V1_0::Result result) {
+ switch (result) {
+ case ::android::hardware::sensors::V1_0::Result::OK:
+ return ScopedAStatus::ok();
+ case ::android::hardware::sensors::V1_0::Result::PERMISSION_DENIED:
+ return ScopedAStatus::fromExceptionCode(EX_SECURITY);
+ case ::android::hardware::sensors::V1_0::Result::NO_MEMORY:
+ return ScopedAStatus::fromServiceSpecificError(ISensors::ERROR_NO_MEMORY);
+ case ::android::hardware::sensors::V1_0::Result::BAD_VALUE:
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ case ::android::hardware::sensors::V1_0::Result::INVALID_OPERATION:
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ default:
+ return ScopedAStatus::fromExceptionCode(EX_TRANSACTION_FAILED);
+ }
}
static ::android::hardware::sensors::V1_0::RateLevel convertRateLevel(
@@ -62,6 +66,8 @@
return ::android::hardware::sensors::V1_0::RateLevel::FAST;
case ISensors::RateLevel::VERY_FAST:
return ::android::hardware::sensors::V1_0::RateLevel::VERY_FAST;
+ default:
+ assert(false);
}
}
@@ -72,6 +78,8 @@
return ::android::hardware::sensors::V1_0::OperationMode::NORMAL;
case ISensors::OperationMode::DATA_INJECTION:
return ::android::hardware::sensors::V1_0::OperationMode::DATA_INJECTION;
+ default:
+ assert(false);
}
}
@@ -82,6 +90,8 @@
return ::android::hardware::sensors::V1_0::SharedMemType::ASHMEM;
case ISensors::SharedMemInfo::SharedMemType::GRALLOC:
return ::android::hardware::sensors::V1_0::SharedMemType::GRALLOC;
+ default:
+ assert(false);
}
}
@@ -90,6 +100,8 @@
switch (sharedMemFormat) {
case ISensors::SharedMemInfo::SharedMemFormat::SENSORS_EVENT:
return ::android::hardware::sensors::V1_0::SharedMemFormat::SENSORS_EVENT;
+ default:
+ assert(false);
}
}
@@ -104,106 +116,125 @@
return v1SharedMemInfo;
}
-::ndk::ScopedAStatus HalProxyAidl::activate(int32_t in_sensorHandle, bool in_enabled) {
- return ndk::ScopedAStatus::fromStatus(
- resultToBinderStatus(HalProxy::activate(in_sensorHandle, in_enabled)));
+ScopedAStatus HalProxyAidl::activate(int32_t in_sensorHandle, bool in_enabled) {
+ return resultToAStatus(HalProxy::activate(in_sensorHandle, in_enabled));
}
-::ndk::ScopedAStatus HalProxyAidl::batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
- int64_t in_maxReportLatencyNs) {
- return ndk::ScopedAStatus::fromStatus(resultToBinderStatus(
- HalProxy::batch(in_sensorHandle, in_samplingPeriodNs, in_maxReportLatencyNs)));
+ScopedAStatus HalProxyAidl::batch(int32_t in_sensorHandle,
+ int64_t in_samplingPeriodNs,
+ int64_t in_maxReportLatencyNs) {
+ return resultToAStatus(HalProxy::batch(in_sensorHandle, in_samplingPeriodNs,
+ in_maxReportLatencyNs));
}
-::ndk::ScopedAStatus HalProxyAidl::configDirectReport(int32_t in_sensorHandle,
- int32_t in_channelHandle,
- ISensors::RateLevel in_rate,
- int32_t* _aidl_return) {
- binder_status_t binderStatus;
- HalProxy::configDirectReport(
- in_sensorHandle, in_channelHandle, convertRateLevel(in_rate),
- [&binderStatus, _aidl_return](::android::hardware::sensors::V1_0::Result result,
- int32_t reportToken) {
- binderStatus = resultToBinderStatus(result);
- *_aidl_return = reportToken;
- });
- return ndk::ScopedAStatus::fromStatus(binderStatus);
+ScopedAStatus HalProxyAidl::configDirectReport(int32_t in_sensorHandle,
+ int32_t in_channelHandle,
+ ISensors::RateLevel in_rate,
+ int32_t *_aidl_return) {
+ ScopedAStatus status =
+ ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ HalProxy::configDirectReport(
+ in_sensorHandle, in_channelHandle, convertRateLevel(in_rate),
+ [&status, _aidl_return](::android::hardware::sensors::V1_0::Result result,
+ int32_t reportToken) {
+ status = resultToAStatus(result);
+ *_aidl_return = reportToken;
+ });
+
+ return status;
}
-::ndk::ScopedAStatus HalProxyAidl::flush(int32_t in_sensorHandle) {
- return ndk::ScopedAStatus::fromStatus(resultToBinderStatus(HalProxy::flush(in_sensorHandle)));
+ScopedAStatus HalProxyAidl::flush(int32_t in_sensorHandle) {
+ return resultToAStatus(HalProxy::flush(in_sensorHandle));
}
-::ndk::ScopedAStatus HalProxyAidl::getSensorsList(
- std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) {
- for (const auto& sensor : HalProxy::getSensors()) {
- _aidl_return->push_back(convertSensorInfo(sensor.second));
- }
- return ndk::ScopedAStatus::ok();
+ScopedAStatus HalProxyAidl::getSensorsList(
+ std::vector<::aidl::android::hardware::sensors::SensorInfo> *_aidl_return) {
+ for (const auto &sensor : HalProxy::getSensors()) {
+ _aidl_return->push_back(convertSensorInfo(sensor.second));
+ }
+ return ScopedAStatus::ok();
}
-::ndk::ScopedAStatus HalProxyAidl::initialize(
- const MQDescriptor<::aidl::android::hardware::sensors::Event, SynchronizedReadWrite>&
- in_eventQueueDescriptor,
- const MQDescriptor<int32_t, SynchronizedReadWrite>& in_wakeLockDescriptor,
- const std::shared_ptr<ISensorsCallback>& in_sensorsCallback) {
- ::android::sp<::android::hardware::sensors::V2_1::implementation::ISensorsCallbackWrapperBase>
- dynamicCallback = new ISensorsCallbackWrapperAidl(in_sensorsCallback);
+ScopedAStatus HalProxyAidl::initialize(
+ const MQDescriptor<::aidl::android::hardware::sensors::Event,
+ SynchronizedReadWrite> &in_eventQueueDescriptor,
+ const MQDescriptor<int32_t, SynchronizedReadWrite> &in_wakeLockDescriptor,
+ const std::shared_ptr<ISensorsCallback> &in_sensorsCallback) {
+ ::android::sp<::android::hardware::sensors::V2_1::implementation::
+ ISensorsCallbackWrapperBase>
+ dynamicCallback = new ISensorsCallbackWrapperAidl(in_sensorsCallback);
- auto aidlEventQueue =
- std::make_unique<::android::AidlMessageQueue<::aidl::android::hardware::sensors::Event,
- SynchronizedReadWrite>>(
- in_eventQueueDescriptor, true /* resetPointers */);
- std::unique_ptr<
- ::android::hardware::sensors::V2_1::implementation::EventMessageQueueWrapperBase>
- eventQueue = std::make_unique<EventMessageQueueWrapperAidl>(aidlEventQueue);
+ auto aidlEventQueue = std::make_unique<::android::AidlMessageQueue<
+ ::aidl::android::hardware::sensors::Event, SynchronizedReadWrite>>(
+ in_eventQueueDescriptor, true /* resetPointers */);
+ std::unique_ptr<::android::hardware::sensors::V2_1::implementation::
+ EventMessageQueueWrapperBase>
+ eventQueue =
+ std::make_unique<EventMessageQueueWrapperAidl>(aidlEventQueue);
- auto aidlWakeLockQueue =
- std::make_unique<::android::AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
- in_wakeLockDescriptor, true /* resetPointers */);
- std::unique_ptr<
- ::android::hardware::sensors::V2_1::implementation::WakeLockMessageQueueWrapperBase>
- wakeLockQueue = std::make_unique<WakeLockMessageQueueWrapperAidl>(aidlWakeLockQueue);
+ auto aidlWakeLockQueue = std::make_unique<
+ ::android::AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
+ in_wakeLockDescriptor, true /* resetPointers */);
+ std::unique_ptr<::android::hardware::sensors::V2_1::implementation::
+ WakeLockMessageQueueWrapperBase>
+ wakeLockQueue =
+ std::make_unique<WakeLockMessageQueueWrapperAidl>(aidlWakeLockQueue);
- return ndk::ScopedAStatus::fromStatus(
- resultToBinderStatus(initializeCommon(eventQueue, wakeLockQueue, dynamicCallback)));
+ return resultToAStatus(
+ initializeCommon(eventQueue, wakeLockQueue, dynamicCallback));
}
-::ndk::ScopedAStatus HalProxyAidl::injectSensorData(
- const ::aidl::android::hardware::sensors::Event& in_event) {
- ::android::hardware::sensors::V2_1::Event hidlEvent;
- convertToHidlEvent(in_event, &hidlEvent);
- return ndk::ScopedAStatus::fromStatus(
- resultToBinderStatus(HalProxy::injectSensorData(convertToOldEvent(hidlEvent))));
+ScopedAStatus HalProxyAidl::injectSensorData(
+ const ::aidl::android::hardware::sensors::Event &in_event) {
+ ::android::hardware::sensors::V2_1::Event hidlEvent;
+ convertToHidlEvent(in_event, &hidlEvent);
+ return resultToAStatus(
+ HalProxy::injectSensorData(convertToOldEvent(hidlEvent)));
}
-::ndk::ScopedAStatus HalProxyAidl::registerDirectChannel(const ISensors::SharedMemInfo& in_mem,
- int32_t* _aidl_return) {
- binder_status_t binderStatus;
- ::android::hardware::sensors::V1_0::SharedMemInfo sharedMemInfo = convertSharedMemInfo(in_mem);
+ScopedAStatus
+HalProxyAidl::registerDirectChannel(const ISensors::SharedMemInfo &in_mem,
+ int32_t *_aidl_return) {
+ ScopedAStatus status =
+ ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ ::android::hardware::sensors::V1_0::SharedMemInfo sharedMemInfo =
+ convertSharedMemInfo(in_mem);
- HalProxy::registerDirectChannel(
- sharedMemInfo,
- [&binderStatus, _aidl_return](::android::hardware::sensors::V1_0::Result result,
- int32_t reportToken) {
- binderStatus = resultToBinderStatus(result);
- *_aidl_return = reportToken;
- });
+ HalProxy::registerDirectChannel(
+ sharedMemInfo,
+ [&status, _aidl_return](::android::hardware::sensors::V1_0::Result result,
+ int32_t reportToken) {
+ status = resultToAStatus(result);
+ *_aidl_return = reportToken;
+ });
- native_handle_delete(
- const_cast<native_handle_t*>(sharedMemInfo.memoryHandle.getNativeHandle()));
- return ndk::ScopedAStatus::fromStatus(binderStatus);
+ native_handle_delete(const_cast<native_handle_t *>(
+ sharedMemInfo.memoryHandle.getNativeHandle()));
+
+ return status;
}
-::ndk::ScopedAStatus HalProxyAidl::setOperationMode(
- ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) {
- return ndk::ScopedAStatus::fromStatus(
- resultToBinderStatus(HalProxy::setOperationMode(convertOperationMode(in_mode))));
+ScopedAStatus HalProxyAidl::setOperationMode(
+ ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) {
+ return resultToAStatus(
+ HalProxy::setOperationMode(convertOperationMode(in_mode)));
}
-::ndk::ScopedAStatus HalProxyAidl::unregisterDirectChannel(int32_t in_channelHandle) {
- return ndk::ScopedAStatus::fromStatus(
- resultToBinderStatus(HalProxy::unregisterDirectChannel(in_channelHandle)));
+ScopedAStatus HalProxyAidl::unregisterDirectChannel(int32_t in_channelHandle) {
+ return resultToAStatus(HalProxy::unregisterDirectChannel(in_channelHandle));
+}
+
+binder_status_t HalProxyAidl::dump(int fd, const char ** /* args */,
+ uint32_t /* numArgs */) {
+ native_handle_t *nativeHandle =
+ native_handle_create(1 /* numFds */, 0 /* numInts */);
+ nativeHandle->data[0] = fd;
+
+ HalProxy::debug(nativeHandle, {} /* args */);
+
+ native_handle_delete(nativeHandle);
+ return STATUS_OK;
}
} // namespace implementation
diff --git a/sensors/aidl/default/multihal/include/HalProxyAidl.h b/sensors/aidl/default/multihal/include/HalProxyAidl.h
index 7401726..5c81715 100644
--- a/sensors/aidl/default/multihal/include/HalProxyAidl.h
+++ b/sensors/aidl/default/multihal/include/HalProxyAidl.h
@@ -55,6 +55,8 @@
::ndk::ScopedAStatus setOperationMode(
::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) override;
::ndk::ScopedAStatus unregisterDirectChannel(int32_t in_channelHandle) override;
+
+ binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;
};
} // namespace implementation
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index 83d0dc9..d536e29 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -599,10 +599,12 @@
ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
} else {
- ASSERT_EQ(getSensors()
- ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
- .getExceptionCode(),
- EX_UNSUPPORTED_OPERATION);
+ int errorCode =
+ getSensors()
+ ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
+ .getExceptionCode();
+ ASSERT_TRUE((errorCode == EX_UNSUPPORTED_OPERATION) ||
+ (errorCode == EX_ILLEGAL_ARGUMENT));
}
}
@@ -938,10 +940,10 @@
if (isDirectReportRateSupported(sensor, rateLevel)) {
ASSERT_TRUE(status.isOk());
if (rateLevel != ISensors::RateLevel::STOP) {
- ASSERT_GT(*reportToken, 0);
- } else {
- ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ ASSERT_GT(*reportToken, 0);
}
+ } else {
+ ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
}
}
@@ -982,11 +984,15 @@
::ndk::ScopedAStatus status = registerDirectChannel(mem->getSharedMemInfo(), &channelHandle);
if (supportsSharedMemType) {
ASSERT_TRUE(status.isOk());
- ASSERT_EQ(channelHandle, 0);
+ ASSERT_GT(channelHandle, 0);
+
+ // Verify that the memory has been zeroed
+ for (size_t i = 0; i < mem->getSize(); i++) {
+ ASSERT_EQ(buffer[i], 0x00);
+ }
} else {
int32_t error = supportsAnyDirectChannel ? EX_ILLEGAL_ARGUMENT : EX_UNSUPPORTED_OPERATION;
ASSERT_EQ(status.getExceptionCode(), error);
- ASSERT_EQ(channelHandle, -1);
}
*directChannelHandle = channelHandle;
}
@@ -1038,7 +1044,7 @@
// Verify that a sensor handle of -1 is only acceptable when using RateLevel::STOP
ndk::ScopedAStatus status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
ISensors::RateLevel::NORMAL, &reportToken);
- ASSERT_EQ(status.getServiceSpecificError(), android::BAD_VALUE);
+ ASSERT_EQ(status.getExceptionCode(), EX_ILLEGAL_ARGUMENT);
status = configDirectReport(-1 /* sensorHandle */, directChannelHandle,
ISensors::RateLevel::STOP, &reportToken);
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 2cc1e6a..36cde9b 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -14,6 +14,7 @@
vendor_available: true,
srcs: ["android/hardware/uwb/*.aidl"],
stability: "vintf",
+ host_supported: true,
backend: {
java: {
sdk_version: "module_Tiramisu",
diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp
index acdbdcd..c4140be 100644
--- a/vibrator/aidl/default/Android.bp
+++ b/vibrator/aidl/default/Android.bp
@@ -63,7 +63,6 @@
"libbinder_random_parcel",
"libcutils",
"liblog",
- "libutils",
"libvibratorexampleimpl",
],
target: {
@@ -71,12 +70,14 @@
shared_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
host: {
static_libs: [
"libbinder_ndk",
"libbinder",
+ "libutils",
],
},
darwin: {
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
index 8a75fd8..bb8cf59 100644
--- a/wifi/1.6/default/wifi_legacy_hal.cpp
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -1549,13 +1549,14 @@
std::pair<wifi_error, wifi_radio_combination_matrix*>
WifiLegacyHal::getSupportedRadioCombinationsMatrix() {
- std::array<char, kMaxSupportedRadioCombinationsMatrixLength> buffer;
- buffer.fill(0);
+ char* buffer = new char[kMaxSupportedRadioCombinationsMatrixLength];
+ std::fill(buffer, buffer + kMaxSupportedRadioCombinationsMatrixLength, 0);
uint32_t size = 0;
wifi_radio_combination_matrix* radio_combination_matrix_ptr =
- reinterpret_cast<wifi_radio_combination_matrix*>(buffer.data());
+ reinterpret_cast<wifi_radio_combination_matrix*>(buffer);
wifi_error status = global_func_table_.wifi_get_supported_radio_combinations_matrix(
- global_handle_, buffer.size(), &size, radio_combination_matrix_ptr);
+ global_handle_, kMaxSupportedRadioCombinationsMatrixLength, &size,
+ radio_combination_matrix_ptr);
CHECK(size >= 0 && size <= kMaxSupportedRadioCombinationsMatrixLength);
return {status, radio_combination_matrix_ptr};
}