mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 05:49:27 +00:00
Merge "Merge 10952656" into aosp-main-future
This commit is contained in:
@@ -57,7 +57,7 @@ class LinearFakeValueGenerator : public FakeValueGenerator {
|
||||
float dispersion; // Defines minimum and maximum value based on initial value.
|
||||
float increment; // Value that we will be added to currentValue with each timer tick.
|
||||
int64_t interval;
|
||||
long lastEventTimestamp;
|
||||
int64_t lastEventTimestamp;
|
||||
};
|
||||
|
||||
GeneratorCfg mGenCfg;
|
||||
|
||||
@@ -86,7 +86,7 @@ std::optional<VehiclePropValue> LinearFakeValueGenerator::nextEvent() {
|
||||
if (mGenCfg.lastEventTimestamp == 0) {
|
||||
mGenCfg.lastEventTimestamp = elapsedRealtimeNano();
|
||||
} else {
|
||||
long nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval;
|
||||
int64_t nextEventTime = mGenCfg.lastEventTimestamp + mGenCfg.interval;
|
||||
// Prevent overflow.
|
||||
assert(nextEventTime > mGenCfg.lastEventTimestamp);
|
||||
mGenCfg.lastEventTimestamp = nextEventTime;
|
||||
|
||||
@@ -99,12 +99,17 @@ class FakeVehicleHardware : public IVehicleHardware {
|
||||
const std::shared_ptr<VehiclePropValuePool> mValuePool;
|
||||
const std::shared_ptr<VehiclePropertyStore> mServerSidePropStore;
|
||||
|
||||
const std::string mDefaultConfigDir;
|
||||
const std::string mOverrideConfigDir;
|
||||
|
||||
ValueResultType getValue(
|
||||
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
|
||||
|
||||
VhalResult<void> setValue(
|
||||
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
|
||||
|
||||
bool UseOverrideConfigDir();
|
||||
|
||||
private:
|
||||
// Expose private methods to unit test.
|
||||
friend class FakeVehicleHardwareTestHelper;
|
||||
@@ -156,8 +161,6 @@ class FakeVehicleHardware : public IVehicleHardware {
|
||||
aidl::android::hardware::automotive::vehicle::SetValueRequest>
|
||||
mPendingSetValueRequests;
|
||||
|
||||
const std::string mDefaultConfigDir;
|
||||
const std::string mOverrideConfigDir;
|
||||
const bool mForceOverride;
|
||||
bool mAddExtraTestVendorConfigs;
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#include <dirent.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
@@ -205,9 +204,10 @@ void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config)
|
||||
|
||||
// Create a separate instance for each individual zone
|
||||
VehiclePropValue prop = {
|
||||
.timestamp = elapsedRealtimeNano(),
|
||||
.areaId = curArea,
|
||||
.prop = propId,
|
||||
.timestamp = elapsedRealtimeNano(),
|
||||
.value = {},
|
||||
};
|
||||
|
||||
if (config.initialAreaValues.empty()) {
|
||||
@@ -240,6 +240,8 @@ FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
|
||||
std::string overrideConfigDir, bool forceOverride)
|
||||
: mValuePool(std::make_unique<VehiclePropValuePool>()),
|
||||
mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
|
||||
mDefaultConfigDir(defaultConfigDir),
|
||||
mOverrideConfigDir(overrideConfigDir),
|
||||
mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
|
||||
mFakeUserHal(new FakeUserHal(mValuePool)),
|
||||
mRecurrentTimer(new RecurrentTimer()),
|
||||
@@ -247,8 +249,6 @@ FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
|
||||
[this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
|
||||
mPendingGetValueRequests(this),
|
||||
mPendingSetValueRequests(this),
|
||||
mDefaultConfigDir(defaultConfigDir),
|
||||
mOverrideConfigDir(overrideConfigDir),
|
||||
mForceOverride(forceOverride) {
|
||||
init();
|
||||
}
|
||||
@@ -259,11 +259,15 @@ FakeVehicleHardware::~FakeVehicleHardware() {
|
||||
mGeneratorHub.reset();
|
||||
}
|
||||
|
||||
bool FakeVehicleHardware::UseOverrideConfigDir() {
|
||||
return mForceOverride ||
|
||||
android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false);
|
||||
}
|
||||
|
||||
std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
|
||||
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
|
||||
loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
|
||||
if (mForceOverride ||
|
||||
android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false)) {
|
||||
if (UseOverrideConfigDir()) {
|
||||
loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
|
||||
}
|
||||
return configsByPropId;
|
||||
@@ -938,7 +942,7 @@ FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
|
||||
<< StringPrintf("failed to get special value: %d, error: %s", value.prop,
|
||||
getErrorMsg(result).c_str());
|
||||
} else {
|
||||
return std::move(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,7 +957,7 @@ FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(readResult);
|
||||
return readResult;
|
||||
}
|
||||
|
||||
DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
|
||||
@@ -990,9 +994,11 @@ DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
|
||||
} else if (EqualsIgnoreCase(option, "--genTestVendorConfigs")) {
|
||||
mAddExtraTestVendorConfigs = true;
|
||||
result.refreshPropertyConfigs = true;
|
||||
result.buffer = "successfully generated vendor configs";
|
||||
} else if (EqualsIgnoreCase(option, "--restoreVendorConfigs")) {
|
||||
mAddExtraTestVendorConfigs = false;
|
||||
result.refreshPropertyConfigs = true;
|
||||
result.buffer = "successfully restored vendor configs";
|
||||
} else {
|
||||
result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
|
||||
}
|
||||
@@ -1328,9 +1334,9 @@ std::string FakeVehicleHardware::genFakeDataCommand(const std::vector<std::strin
|
||||
VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputAction action,
|
||||
int32_t keyCode, int32_t targetDisplay) {
|
||||
VehiclePropValue value = {
|
||||
.prop = toInt(VehicleProperty::HW_KEY_INPUT),
|
||||
.areaId = 0,
|
||||
.timestamp = elapsedRealtimeNano(),
|
||||
.areaId = 0,
|
||||
.prop = toInt(VehicleProperty::HW_KEY_INPUT),
|
||||
.status = VehiclePropertyStatus::AVAILABLE,
|
||||
.value.int32Values = {toInt(action), keyCode, targetDisplay},
|
||||
};
|
||||
@@ -1340,9 +1346,9 @@ VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputActi
|
||||
VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
|
||||
int32_t keyCode, int32_t action,
|
||||
int32_t repeatCount) {
|
||||
VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
|
||||
VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
|
||||
.areaId = area,
|
||||
.timestamp = elapsedRealtimeNano(),
|
||||
.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
|
||||
.status = VehiclePropertyStatus::AVAILABLE,
|
||||
.value.int32Values = {targetDisplay, keyCode, action, repeatCount},
|
||||
.value.int64Values = {elapsedRealtimeNano()}};
|
||||
@@ -1380,9 +1386,9 @@ VehiclePropValue FakeVehicleHardware::createHwMotionInputProp(
|
||||
floatValues.push_back(size[i]);
|
||||
}
|
||||
|
||||
VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
|
||||
VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
|
||||
.areaId = area,
|
||||
.timestamp = elapsedRealtimeNano(),
|
||||
.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
|
||||
.status = VehiclePropertyStatus::AVAILABLE,
|
||||
.value.int32Values = intValues,
|
||||
.value.floatValues = floatValues,
|
||||
@@ -1451,8 +1457,9 @@ std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
|
||||
|
||||
std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
|
||||
VehiclePropValue value = {
|
||||
.prop = propId,
|
||||
.areaId = areaId,
|
||||
.prop = propId,
|
||||
.value = {},
|
||||
};
|
||||
bool isSpecialValue = false;
|
||||
auto result = maybeGetSpecialValue(value, &isSpecialValue);
|
||||
@@ -1523,12 +1530,12 @@ std::vector<std::string> FakeVehicleHardware::getOptionValues(
|
||||
while (*index < options.size()) {
|
||||
std::string option = options[*index];
|
||||
if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
|
||||
return std::move(values);
|
||||
return values;
|
||||
}
|
||||
values.push_back(option);
|
||||
(*index)++;
|
||||
}
|
||||
return std::move(values);
|
||||
return values;
|
||||
}
|
||||
|
||||
Result<VehiclePropValue> FakeVehicleHardware::parsePropOptions(
|
||||
@@ -1808,6 +1815,7 @@ void FakeVehicleHardware::registerOnPropertyChangeEvent(
|
||||
|
||||
void FakeVehicleHardware::registerOnPropertySetErrorEvent(
|
||||
std::unique_ptr<const PropertySetErrorCallback> callback) {
|
||||
// In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback.
|
||||
if (mOnPropertySetErrorCallback != nullptr) {
|
||||
ALOGE("registerOnPropertySetErrorEvent must only be called once");
|
||||
return;
|
||||
@@ -1836,8 +1844,9 @@ StatusCode FakeVehicleHardware::updateSampleRate(int32_t propId, int32_t 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,
|
||||
.prop = propId,
|
||||
.value = {},
|
||||
});
|
||||
if (!result.ok()) {
|
||||
// Failed to read current value, skip refreshing.
|
||||
|
||||
@@ -82,6 +82,10 @@ class GRPCVehicleHardware : public IVehicleHardware {
|
||||
|
||||
bool waitForConnected(std::chrono::milliseconds waitTime);
|
||||
|
||||
protected:
|
||||
std::shared_mutex mCallbackMutex;
|
||||
std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
|
||||
|
||||
private:
|
||||
void ValuePollingLoop();
|
||||
|
||||
@@ -90,8 +94,6 @@ class GRPCVehicleHardware : public IVehicleHardware {
|
||||
std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
|
||||
std::thread mValuePollingThread;
|
||||
|
||||
std::shared_mutex mCallbackMutex;
|
||||
std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
|
||||
std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
|
||||
|
||||
std::mutex mShutdownMutex;
|
||||
|
||||
@@ -107,12 +107,18 @@ class SubscriptionClient final : public ConnectedClient {
|
||||
// Gets the callback to be called when the request for this client has finished.
|
||||
std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
|
||||
|
||||
// Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
|
||||
// Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
|
||||
// callback.
|
||||
static void sendUpdatedValues(
|
||||
CallbackType callback,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
|
||||
updatedValues);
|
||||
// Marshals the set property error events into largeParcelable and sends it through
|
||||
// {@code onPropertySetError} callback.
|
||||
static void sendPropertySetErrors(
|
||||
CallbackType callback,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
|
||||
vehiclePropErrors);
|
||||
|
||||
protected:
|
||||
// Gets the callback to be called when the request for this client has timeout.
|
||||
|
||||
@@ -249,10 +249,14 @@ class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehi
|
||||
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
|
||||
|
||||
static void onPropertyChangeEvent(
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager,
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
|
||||
updatedValues);
|
||||
|
||||
static void onPropertySetErrorEvent(
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
static void checkHealth(IVehicleHardware* hardware,
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager);
|
||||
|
||||
|
||||
@@ -99,6 +99,12 @@ class SubscriptionManager final {
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
|
||||
updatedValues);
|
||||
|
||||
// For a list of set property error events, returns a map that maps clients subscribing to the
|
||||
// properties to a list of errors for each client.
|
||||
std::unordered_map<CallbackType,
|
||||
std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
|
||||
getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
// Checks whether the sample rate is valid.
|
||||
static bool checkSampleRateHz(float sampleRateHz);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
|
||||
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
|
||||
using ::android::base::Result;
|
||||
@@ -300,7 +302,34 @@ void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> cal
|
||||
if (ScopedAStatus callbackStatus =
|
||||
callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
|
||||
!callbackStatus.isOk()) {
|
||||
ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
|
||||
ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
|
||||
"exception: %d, service specific error: %d",
|
||||
callback->asBinder().get(), callbackStatus.getMessage(),
|
||||
callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
|
||||
}
|
||||
}
|
||||
|
||||
void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
|
||||
std::vector<VehiclePropError>&& vehiclePropErrors) {
|
||||
if (vehiclePropErrors.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
VehiclePropErrors vehiclePropErrorsLargeParcelable;
|
||||
ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
|
||||
&vehiclePropErrorsLargeParcelable);
|
||||
if (!status.isOk()) {
|
||||
int statusCode = status.getServiceSpecificError();
|
||||
ALOGE("subscribe: failed to marshal result into large parcelable, error: "
|
||||
"%s, code: %d",
|
||||
status.getMessage(), statusCode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ScopedAStatus callbackStatus =
|
||||
callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
|
||||
!callbackStatus.isOk()) {
|
||||
ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
|
||||
"exception: %d, service specific error: %d",
|
||||
callback->asBinder().get(), callbackStatus.getMessage(),
|
||||
callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
|
||||
|
||||
@@ -144,6 +144,11 @@ DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHa
|
||||
[subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
|
||||
onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
|
||||
}));
|
||||
mVehicleHardware->registerOnPropertySetErrorEvent(
|
||||
std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
|
||||
[subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
|
||||
onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
|
||||
}));
|
||||
|
||||
// Register heartbeat event.
|
||||
mRecurrentAction = std::make_shared<std::function<void()>>(
|
||||
@@ -177,7 +182,7 @@ DefaultVehicleHal::~DefaultVehicleHal() {
|
||||
}
|
||||
|
||||
void DefaultVehicleHal::onPropertyChangeEvent(
|
||||
std::weak_ptr<SubscriptionManager> subscriptionManager,
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<VehiclePropValue>& updatedValues) {
|
||||
auto manager = subscriptionManager.lock();
|
||||
if (manager == nullptr) {
|
||||
@@ -194,6 +199,20 @@ void DefaultVehicleHal::onPropertyChangeEvent(
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultVehicleHal::onPropertySetErrorEvent(
|
||||
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
auto manager = subscriptionManager.lock();
|
||||
if (manager == nullptr) {
|
||||
ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
|
||||
return;
|
||||
}
|
||||
auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
|
||||
for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
|
||||
SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
|
||||
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
|
||||
@@ -692,15 +711,19 @@ ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType& callback,
|
||||
// Create a new SubscriptionClient if there isn't an existing one.
|
||||
mSubscriptionClients->maybeAddClient(callback);
|
||||
|
||||
// Since we have already check the sample rates, the following functions must succeed.
|
||||
if (!onChangeSubscriptions.empty()) {
|
||||
return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
|
||||
/*isContinuousProperty=*/false));
|
||||
auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
|
||||
/*isContinuousProperty=*/false);
|
||||
if (!result.ok()) {
|
||||
return toScopedAStatus(result);
|
||||
}
|
||||
}
|
||||
if (!continuousSubscriptions.empty()) {
|
||||
return toScopedAStatus(mSubscriptionManager->subscribe(callback,
|
||||
continuousSubscriptions,
|
||||
/*isContinuousProperty=*/true));
|
||||
auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
|
||||
/*isContinuousProperty=*/true);
|
||||
if (!result.ok()) {
|
||||
return toScopedAStatus(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ScopedAStatus::ok();
|
||||
|
||||
@@ -36,6 +36,7 @@ constexpr float ONE_SECOND_IN_NANO = 1'000'000'000.;
|
||||
using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
|
||||
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
|
||||
using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
|
||||
using ::android::base::Error;
|
||||
using ::android::base::Result;
|
||||
@@ -269,6 +270,32 @@ SubscriptionManager::getSubscribedClients(const std::vector<VehiclePropValue>& u
|
||||
return clients;
|
||||
}
|
||||
|
||||
std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
|
||||
SubscriptionManager::getSubscribedClientsForErrorEvents(
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
|
||||
|
||||
for (const auto& errorEvent : errorEvents) {
|
||||
PropIdAreaId propIdAreaId{
|
||||
.propId = errorEvent.propId,
|
||||
.areaId = errorEvent.areaId,
|
||||
};
|
||||
if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
|
||||
clients[client].push_back({
|
||||
.propId = errorEvent.propId,
|
||||
.areaId = errorEvent.areaId,
|
||||
.errorCode = errorEvent.errorCode,
|
||||
});
|
||||
}
|
||||
}
|
||||
return clients;
|
||||
}
|
||||
|
||||
bool SubscriptionManager::isEmpty() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
|
||||
|
||||
@@ -62,6 +62,7 @@ using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
|
||||
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
|
||||
@@ -1653,6 +1654,63 @@ TEST_F(DefaultVehicleHalTest, testDumpCallerShouldNotDump) {
|
||||
ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
|
||||
}
|
||||
|
||||
TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
|
||||
std::vector<SubscribeOptions> options = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaIds = {0},
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaIds = {0},
|
||||
.sampleRate = 1,
|
||||
},
|
||||
};
|
||||
auto status = getClient()->subscribe(getCallbackClient(), options, 0);
|
||||
ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
|
||||
std::vector<SetValueErrorEvent> errorEvents = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INTERNAL_ERROR,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::ACCESS_DENIED,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INVALID_ARG,
|
||||
},
|
||||
};
|
||||
std::vector<VehiclePropError> expectedResults = {
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INTERNAL_ERROR,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_ON_CHANGE_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::ACCESS_DENIED,
|
||||
},
|
||||
{
|
||||
.propId = GLOBAL_CONTINUOUS_PROP,
|
||||
.areaId = 0,
|
||||
.errorCode = StatusCode::INVALID_ARG,
|
||||
},
|
||||
};
|
||||
getHardware()->sendOnPropertySetErrorEvent(errorEvents);
|
||||
|
||||
ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
|
||||
auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
|
||||
ASSERT_TRUE(maybeVehiclePropErrors.has_value());
|
||||
const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
|
||||
ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -81,8 +81,14 @@ ScopedAStatus MockVehicleCallback::onPropertyEvent(const VehiclePropValues& resu
|
||||
return result;
|
||||
}
|
||||
|
||||
ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
|
||||
return ScopedAStatus::ok();
|
||||
ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
|
||||
ScopedAStatus result;
|
||||
{
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
result = storeResults(results, &mOnPropertySetErrorResults);
|
||||
}
|
||||
mCond.notify_all();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
|
||||
@@ -105,6 +111,16 @@ size_t MockVehicleCallback::countOnPropertyEventResults() {
|
||||
return mOnPropertyEventResults.size();
|
||||
}
|
||||
|
||||
std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return pop(mOnPropertySetErrorResults);
|
||||
}
|
||||
|
||||
size_t MockVehicleCallback::countOnPropertySetErrorResults() {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
return mOnPropertySetErrorResults.size();
|
||||
}
|
||||
|
||||
bool MockVehicleCallback::waitForSetValueResults(size_t size, size_t timeoutInNano) {
|
||||
std::unique_lock lk(mLock);
|
||||
return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
|
||||
|
||||
@@ -63,6 +63,9 @@ class MockVehicleCallback final
|
||||
nextSetValueResults();
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
|
||||
nextOnPropertyEventResults();
|
||||
size_t countOnPropertySetErrorResults();
|
||||
std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
|
||||
nextOnPropertySetErrorResults();
|
||||
size_t countOnPropertyEventResults();
|
||||
bool waitForSetValueResults(size_t size, size_t timeoutInNano);
|
||||
bool waitForGetValueResults(size_t size, size_t timeoutInNano);
|
||||
@@ -77,6 +80,8 @@ class MockVehicleCallback final
|
||||
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
|
||||
mOnPropertyEventResults GUARDED_BY(mLock);
|
||||
int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
|
||||
std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
|
||||
mOnPropertySetErrorResults GUARDED_BY(mLock);
|
||||
};
|
||||
|
||||
} // namespace vehicle
|
||||
|
||||
@@ -131,8 +131,9 @@ void MockVehicleHardware::registerOnPropertyChangeEvent(
|
||||
}
|
||||
|
||||
void MockVehicleHardware::registerOnPropertySetErrorEvent(
|
||||
std::unique_ptr<const PropertySetErrorCallback>) {
|
||||
// TODO(b/200737967): mock this.
|
||||
std::unique_ptr<const PropertySetErrorCallback> callback) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
mPropertySetErrorCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
|
||||
@@ -254,6 +255,12 @@ template StatusCode MockVehicleHardware::handleRequestsLocked<SetValueRequest, S
|
||||
std::list<std::vector<SetValueRequest>>* storedRequests,
|
||||
std::list<std::vector<SetValueResult>>* storedResponses) const;
|
||||
|
||||
void MockVehicleHardware::sendOnPropertySetErrorEvent(
|
||||
const std::vector<SetValueErrorEvent>& errorEvents) {
|
||||
std::scoped_lock<std::mutex> lockGuard(mLock);
|
||||
(*mPropertySetErrorCallback)(errorEvents);
|
||||
}
|
||||
|
||||
} // namespace vehicle
|
||||
} // namespace automotive
|
||||
} // namespace hardware
|
||||
|
||||
@@ -85,6 +85,7 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
aidl::android::hardware::automotive::vehicle::StatusCode status);
|
||||
void setSleepTime(int64_t timeInNano);
|
||||
void setDumpResult(DumpResult result);
|
||||
void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
|
||||
|
||||
private:
|
||||
mutable std::mutex mLock;
|
||||
@@ -104,6 +105,7 @@ class MockVehicleHardware final : public IVehicleHardware {
|
||||
mStatusByFunctions GUARDED_BY(mLock);
|
||||
int64_t mSleepTime GUARDED_BY(mLock) = 0;
|
||||
std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
|
||||
std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
|
||||
std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
|
||||
std::shared_ptr<const GetValuesCallback>,
|
||||
const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
|
||||
|
||||
@@ -27,6 +27,7 @@ cc_library_static {
|
||||
visibility: [
|
||||
"//hardware/interfaces/automotive/vehicle:__subpackages__",
|
||||
"//device/generic/car/emulator:__subpackages__",
|
||||
"//system/software_defined_vehicle/core_services:__subpackages__",
|
||||
],
|
||||
vendor: true,
|
||||
host_supported: true,
|
||||
|
||||
@@ -31,6 +31,9 @@ using ::android::base::ParseInt;
|
||||
|
||||
namespace aidl::android::hardware::biometrics::fingerprint {
|
||||
|
||||
FakeFingerprintEngine::FakeFingerprintEngine()
|
||||
: mRandom(std::mt19937::default_seed), mWorkMode(WorkMode::kIdle) {}
|
||||
|
||||
void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
|
||||
BEGIN_OP(0);
|
||||
std::uniform_int_distribution<int64_t> dist;
|
||||
@@ -48,7 +51,7 @@ void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t ch
|
||||
void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
|
||||
const keymaster::HardwareAuthToken& hat,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
|
||||
BEGIN_OP(0);
|
||||
|
||||
// Do proper HAT verification in the real implementation.
|
||||
if (hat.mac.empty()) {
|
||||
@@ -57,13 +60,77 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
|
||||
return;
|
||||
}
|
||||
|
||||
updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(0);
|
||||
updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
|
||||
keymaster::HardwareAuthToken());
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(0);
|
||||
|
||||
auto detectInteractionSupported =
|
||||
FingerprintHalProperties::detect_interaction().value_or(false);
|
||||
if (!detectInteractionSupported) {
|
||||
LOG(ERROR) << "Detect interaction is not supported";
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
|
||||
keymaster::HardwareAuthToken());
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb,
|
||||
std::future<void>& cancel, int64_t operationId,
|
||||
const keymaster::HardwareAuthToken& hat) {
|
||||
mCancel = std::move(cancel);
|
||||
mWorkMode = mode;
|
||||
mCb = cb;
|
||||
mOperationId = operationId;
|
||||
mHat = hat;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::fingerDownAction() {
|
||||
bool isTerminal = false;
|
||||
LOG(INFO) << __func__;
|
||||
switch (mWorkMode) {
|
||||
case WorkMode::kAuthenticate:
|
||||
isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel);
|
||||
break;
|
||||
case WorkMode::kEnroll:
|
||||
isTerminal = onEnrollFingerDown(mCb, mHat, mCancel);
|
||||
break;
|
||||
case WorkMode::kDetectInteract:
|
||||
isTerminal = onDetectInteractFingerDown(mCb, mCancel);
|
||||
break;
|
||||
default:
|
||||
LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isTerminal) {
|
||||
mWorkMode = WorkMode::kIdle;
|
||||
}
|
||||
}
|
||||
|
||||
bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
|
||||
const keymaster::HardwareAuthToken&,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
|
||||
|
||||
// Force error-out
|
||||
auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
|
||||
if (err != 0) {
|
||||
LOG(ERROR) << "Fail: operation_enroll_error";
|
||||
auto ec = convertError(err);
|
||||
cb->onError(ec.first, ec.second);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
|
||||
@@ -72,7 +139,7 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
|
||||
if (parts.size() != 3) {
|
||||
LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
|
||||
cb->onError(Error::VENDOR, 0 /* vendorError */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
auto enrollmentId = std::stoi(parts[0]);
|
||||
auto progress = parseEnrollmentCapture(parts[1]);
|
||||
@@ -88,7 +155,7 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
|
||||
if (shouldCancel(cancel)) {
|
||||
LOG(ERROR) << "Fail: cancel";
|
||||
cb->onError(Error::CANCELED, 0 /* vendorCode */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
auto ac = convertAcquiredInfo(acquired[j]);
|
||||
cb->onAcquired(ac.first, ac.second);
|
||||
@@ -114,10 +181,13 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
|
||||
cb->onEnrollmentProgress(enrollmentId, left);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
|
||||
const std::future<void>& cancel) {
|
||||
bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
|
||||
int64_t /* operationId */,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
|
||||
|
||||
int64_t now = Util::getSystemNanoTime();
|
||||
@@ -129,19 +199,12 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
|
||||
if (N == 0) {
|
||||
LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// got lockout?
|
||||
FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
|
||||
if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
|
||||
LOG(ERROR) << "Fail: lockout permanent";
|
||||
cb->onLockoutPermanent();
|
||||
return;
|
||||
} else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
|
||||
int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
|
||||
LOG(ERROR) << "Fail: lockout timed " << timeLeft;
|
||||
cb->onLockoutTimed(timeLeft);
|
||||
if (checkSensorLockout(cb)) {
|
||||
return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -150,7 +213,7 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
|
||||
LOG(ERROR) << "Fail: operation_authenticate_fails";
|
||||
mLockoutTracker.addFailedAttempt();
|
||||
cb->onAuthenticationFailed();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
|
||||
@@ -158,20 +221,21 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
|
||||
LOG(ERROR) << "Fail: operation_authenticate_error";
|
||||
auto ec = convertError(err);
|
||||
cb->onError(ec.first, ec.second);
|
||||
return;
|
||||
return true; /* simply terminating current operation for any user inserted error,
|
||||
revisit if tests need*/
|
||||
}
|
||||
|
||||
if (FingerprintHalProperties::lockout().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: lockout";
|
||||
cb->onLockoutPermanent();
|
||||
cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldCancel(cancel)) {
|
||||
LOG(ERROR) << "Fail: cancel";
|
||||
cb->onError(Error::CANCELED, 0 /* vendorCode */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i < N) {
|
||||
@@ -189,29 +253,23 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
|
||||
if (id > 0 && isEnrolled) {
|
||||
cb->onAuthenticationSucceeded(id, {} /* hat */);
|
||||
mLockoutTracker.reset();
|
||||
return;
|
||||
return true;
|
||||
} else {
|
||||
LOG(ERROR) << "Fail: fingerprint not enrolled";
|
||||
cb->onAuthenticationFailed();
|
||||
mLockoutTracker.addFailedAttempt();
|
||||
checkSensorLockout(cb);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
|
||||
const std::future<void>& cancel) {
|
||||
bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
|
||||
const std::future<void>& cancel) {
|
||||
BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
|
||||
|
||||
int64_t duration =
|
||||
FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
|
||||
|
||||
auto detectInteractionSupported =
|
||||
FingerprintHalProperties::detect_interaction().value_or(false);
|
||||
if (!detectInteractionSupported) {
|
||||
LOG(ERROR) << "Detect interaction is not supported";
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
|
||||
auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
|
||||
auto acquiredInfos = parseIntSequence(acquired);
|
||||
int N = acquiredInfos.size();
|
||||
@@ -220,7 +278,7 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
|
||||
if (N == 0) {
|
||||
LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
@@ -230,13 +288,13 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
|
||||
LOG(ERROR) << "Fail: operation_detect_interaction_error";
|
||||
auto ec = convertError(err);
|
||||
cb->onError(ec.first, ec.second);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shouldCancel(cancel)) {
|
||||
LOG(ERROR) << "Fail: cancel";
|
||||
cb->onError(Error::CANCELED, 0 /* vendorCode */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i < N) {
|
||||
@@ -253,21 +311,18 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
|
||||
if (id <= 0 || !isEnrolled) {
|
||||
LOG(ERROR) << "Fail: not enrolled";
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
cb->onInteractionDetected();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
|
||||
BEGIN_OP(0);
|
||||
|
||||
std::vector<int32_t> ids;
|
||||
// There are some enrollment sync issue with framework, which results in
|
||||
// a single template removal during the very firt sync command after reboot.
|
||||
// This is a workaround for now. TODO(b/243129174)
|
||||
ids.push_back(-1);
|
||||
|
||||
for (auto& enrollment : FingerprintHalProperties::enrollments()) {
|
||||
auto id = enrollment.value_or(0);
|
||||
if (id > 0) {
|
||||
@@ -330,6 +385,11 @@ void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
|
||||
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
|
||||
return;
|
||||
}
|
||||
clearLockout(cb);
|
||||
isLockoutTimerAborted = true;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
|
||||
FingerprintHalProperties::lockout(false);
|
||||
cb->onLockoutCleared();
|
||||
mLockoutTracker.reset();
|
||||
@@ -339,6 +399,7 @@ ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*
|
||||
int32_t /*y*/, float /*minor*/,
|
||||
float /*major*/) {
|
||||
BEGIN_OP(0);
|
||||
fingerDownAction();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -369,7 +430,8 @@ bool FakeFingerprintEngine::getSensorLocationConfig(SensorLocation& out) {
|
||||
if (dim.size() >= 4) {
|
||||
d = dim[3];
|
||||
}
|
||||
if (isValidStr) out = {0, x, y, r, d};
|
||||
if (isValidStr)
|
||||
out = {.sensorLocationX = x, .sensorLocationY = y, .sensorRadius = r, .display = d};
|
||||
|
||||
return isValidStr;
|
||||
}
|
||||
@@ -385,8 +447,7 @@ SensorLocation FakeFingerprintEngine::getSensorLocation() {
|
||||
}
|
||||
|
||||
SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
|
||||
return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */,
|
||||
0 /* sensorRadius */, "" /* display */};
|
||||
return SensorLocation();
|
||||
}
|
||||
|
||||
std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
|
||||
@@ -513,4 +574,39 @@ int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2)
|
||||
return dist(mRandom);
|
||||
}
|
||||
|
||||
bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) {
|
||||
FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
|
||||
if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
|
||||
LOG(ERROR) << "Fail: lockout permanent";
|
||||
cb->onLockoutPermanent();
|
||||
isLockoutTimerAborted = true;
|
||||
return true;
|
||||
} else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
|
||||
int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
|
||||
LOG(ERROR) << "Fail: lockout timed " << timeLeft;
|
||||
cb->onLockoutTimed(timeLeft);
|
||||
if (isLockoutTimerSupported && !isLockoutTimerStarted) startLockoutTimer(timeLeft, cb);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
|
||||
BEGIN_OP(0);
|
||||
std::function<void(ISessionCallback*)> action =
|
||||
std::bind(&FakeFingerprintEngine::lockoutTimerExpired, this, std::placeholders::_1);
|
||||
std::thread([timeout, action, cb]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
|
||||
action(cb);
|
||||
}).detach();
|
||||
|
||||
isLockoutTimerStarted = true;
|
||||
}
|
||||
void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
|
||||
if (!isLockoutTimerAborted) {
|
||||
clearLockout(cb);
|
||||
}
|
||||
isLockoutTimerStarted = false;
|
||||
isLockoutTimerAborted = false;
|
||||
}
|
||||
} // namespace aidl::android::hardware::biometrics::fingerprint
|
||||
|
||||
@@ -27,11 +27,13 @@ using namespace ::android::fingerprint::virt;
|
||||
|
||||
namespace aidl::android::hardware::biometrics::fingerprint {
|
||||
|
||||
SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() {
|
||||
SensorLocation location;
|
||||
FakeFingerprintEngineSide::FakeFingerprintEngineSide() : FakeFingerprintEngine() {
|
||||
isLockoutTimerSupported = true;
|
||||
}
|
||||
|
||||
return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
|
||||
defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
|
||||
"" /* display */};
|
||||
SensorLocation FakeFingerprintEngineSide::defaultSensorLocation() {
|
||||
return SensorLocation{.sensorLocationX = defaultSensorLocationX,
|
||||
.sensorLocationY = defaultSensorLocationY,
|
||||
.sensorRadius = defaultSensorRadius};
|
||||
}
|
||||
} // namespace aidl::android::hardware::biometrics::fingerprint
|
||||
|
||||
@@ -31,12 +31,12 @@ using namespace ::android::fingerprint::virt;
|
||||
namespace aidl::android::hardware::biometrics::fingerprint {
|
||||
|
||||
FakeFingerprintEngineUdfps::FakeFingerprintEngineUdfps()
|
||||
: FakeFingerprintEngine(), mWorkMode(WorkMode::kIdle), mPointerDownTime(0), mUiReadyTime(0) {}
|
||||
: FakeFingerprintEngine(), mPointerDownTime(0), mUiReadyTime(0) {}
|
||||
|
||||
SensorLocation FakeFingerprintEngineUdfps::defaultSensorLocation() {
|
||||
return {0 /* displayId (not used) */, defaultSensorLocationX /* sensorLocationX */,
|
||||
defaultSensorLocationY /* sensorLocationY */, defaultSensorRadius /* sensorRadius */,
|
||||
"" /* display */};
|
||||
return SensorLocation{.sensorLocationX = defaultSensorLocationX,
|
||||
.sensorLocationY = defaultSensorLocationY,
|
||||
.sensorRadius = defaultSensorRadius};
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus FakeFingerprintEngineUdfps::onPointerDownImpl(int32_t /*pointerId*/,
|
||||
@@ -70,68 +70,17 @@ ndk::ScopedAStatus FakeFingerprintEngineUdfps::onUiReadyImpl() {
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::fingerDownAction() {
|
||||
switch (mWorkMode) {
|
||||
case WorkMode::kAuthenticate:
|
||||
onAuthenticateFingerDown();
|
||||
break;
|
||||
case WorkMode::kEnroll:
|
||||
onEnrollFingerDown();
|
||||
break;
|
||||
case WorkMode::kDetectInteract:
|
||||
onDetectInteractFingerDown();
|
||||
break;
|
||||
default:
|
||||
LOG(WARNING) << "unexpected call: onUiReady()";
|
||||
break;
|
||||
}
|
||||
|
||||
FakeFingerprintEngine::fingerDownAction();
|
||||
mUiReadyTime = 0;
|
||||
mPointerDownTime = 0;
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::onAuthenticateFingerDown() {
|
||||
FakeFingerprintEngine::authenticateImpl(mCb, mOperationId, mCancelVec[0]);
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::onEnrollFingerDown() {
|
||||
// Any use case to emulate display touch for each capture during enrollment?
|
||||
FakeFingerprintEngine::enrollImpl(mCb, mHat, mCancelVec[0]);
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::onDetectInteractFingerDown() {
|
||||
FakeFingerprintEngine::detectInteractionImpl(mCb, mCancelVec[0]);
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::enrollImpl(ISessionCallback* cb,
|
||||
const keymaster::HardwareAuthToken& hat,
|
||||
const std::future<void>& cancel) {
|
||||
updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::authenticateImpl(ISessionCallback* cb, int64_t operationId,
|
||||
const std::future<void>& cancel) {
|
||||
updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
|
||||
keymaster::HardwareAuthToken());
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::detectInteractionImpl(ISessionCallback* cb,
|
||||
const std::future<void>& cancel) {
|
||||
updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
|
||||
keymaster::HardwareAuthToken());
|
||||
}
|
||||
|
||||
void FakeFingerprintEngineUdfps::updateContext(WorkMode mode, ISessionCallback* cb,
|
||||
std::future<void>& cancel, int64_t operationId,
|
||||
const keymaster::HardwareAuthToken& hat) {
|
||||
FakeFingerprintEngine::updateContext(mode, cb, cancel, operationId, hat);
|
||||
mPointerDownTime = 0;
|
||||
mUiReadyTime = 0;
|
||||
mCancelVec.clear();
|
||||
|
||||
mCancelVec.push_back(std::move(cancel));
|
||||
mWorkMode = mode;
|
||||
mCb = cb;
|
||||
mOperationId = operationId;
|
||||
mHat = hat;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::fingerprint
|
||||
|
||||
@@ -67,9 +67,13 @@ int64_t FakeLockoutTracker::getLockoutTimeLeft() {
|
||||
int64_t res = 0;
|
||||
|
||||
if (mLockoutTimedStart > 0) {
|
||||
int32_t lockoutTimedDuration =
|
||||
FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
|
||||
auto now = Util::getSystemNanoTime();
|
||||
auto left = now - mLockoutTimedStart;
|
||||
res = (left > 0) ? (left / 1000000LL) : 0;
|
||||
auto elapsed = (now - mLockoutTimedStart) / 1000000LL;
|
||||
res = lockoutTimedDuration - elapsed;
|
||||
LOG(INFO) << "xxxxxx: elapsed=" << elapsed << " now = " << now
|
||||
<< " mLockoutTimedStart=" << mLockoutTimedStart << " res=" << res;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "Fingerprint.h"
|
||||
#include "Session.h"
|
||||
|
||||
#include <android-base/properties.h>
|
||||
#include <fingerprint.sysprop.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
@@ -59,6 +60,7 @@ Fingerprint::Fingerprint() : mWorker(MAX_WORKER_QUEUE_SIZE) {
|
||||
<< sensorTypeProp;
|
||||
}
|
||||
LOG(INFO) << "sensorTypeProp:" << sensorTypeProp;
|
||||
LOG(INFO) << "ro.product.name=" << ::android::base::GetProperty("ro.product.name", "UNKNOWN");
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
|
||||
@@ -105,16 +107,16 @@ ndk::ScopedAStatus Fingerprint::createSession(int32_t sensorId, int32_t userId,
|
||||
|
||||
mSession->linkToDeath(cb->asBinder().get());
|
||||
|
||||
LOG(INFO) << "createSession: sensorId:" << sensorId << " userId:" << userId;
|
||||
LOG(INFO) << __func__ << ": sensorId:" << sensorId << " userId:" << userId;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArgs) {
|
||||
if (fd < 0) {
|
||||
LOG(ERROR) << "Fingerprint::dump fd invalid: " << fd;
|
||||
LOG(ERROR) << __func__ << "fd invalid: " << fd;
|
||||
return STATUS_BAD_VALUE;
|
||||
} else {
|
||||
LOG(INFO) << "Fingerprint::dump fd:" << fd << "numArgs:" << numArgs;
|
||||
LOG(INFO) << __func__ << " fd:" << fd << "numArgs:" << numArgs;
|
||||
}
|
||||
|
||||
dprintf(fd, "----- FingerprintVirtualHal::dump -----\n");
|
||||
@@ -131,11 +133,11 @@ binder_status_t Fingerprint::dump(int fd, const char** /*args*/, uint32_t numArg
|
||||
|
||||
binder_status_t Fingerprint::handleShellCommand(int in, int out, int err, const char** args,
|
||||
uint32_t numArgs) {
|
||||
LOG(INFO) << "Fingerprint::handleShellCommand in:" << in << " out:" << out << " err:" << err
|
||||
LOG(INFO) << __func__ << " in:" << in << " out:" << out << " err:" << err
|
||||
<< " numArgs:" << numArgs;
|
||||
|
||||
if (numArgs == 0) {
|
||||
LOG(INFO) << "Fingerprint::handleShellCommand: available commands";
|
||||
LOG(INFO) << __func__ << ": available commands";
|
||||
onHelp(out);
|
||||
return STATUS_OK;
|
||||
}
|
||||
@@ -163,7 +165,7 @@ void Fingerprint::onHelp(int fd) {
|
||||
}
|
||||
|
||||
void Fingerprint::resetConfigToDefault() {
|
||||
LOG(INFO) << "reset virtual HAL configuration to default";
|
||||
LOG(INFO) << __func__ << ": reset virtual HAL configuration to default";
|
||||
#define RESET_CONFIG_O(__NAME__) \
|
||||
if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt)
|
||||
#define RESET_CONFIG_V(__NAME__) \
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace aidl::android::hardware::biometrics::fingerprint {
|
||||
// A fake engine that is backed by system properties instead of hardware.
|
||||
class FakeFingerprintEngine {
|
||||
public:
|
||||
FakeFingerprintEngine() : mRandom(std::mt19937::default_seed) {}
|
||||
FakeFingerprintEngine();
|
||||
virtual ~FakeFingerprintEngine() {}
|
||||
|
||||
void generateChallengeImpl(ISessionCallback* cb);
|
||||
@@ -66,6 +66,8 @@ class FakeFingerprintEngine {
|
||||
|
||||
virtual SensorLocation defaultSensorLocation();
|
||||
|
||||
virtual void fingerDownAction();
|
||||
|
||||
std::vector<int32_t> parseIntSequence(const std::string& str, const std::string& sep = ",");
|
||||
|
||||
std::vector<std::vector<int32_t>> parseEnrollmentCapture(const std::string& str);
|
||||
@@ -74,15 +76,35 @@ class FakeFingerprintEngine {
|
||||
|
||||
std::mt19937 mRandom;
|
||||
|
||||
enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
|
||||
|
||||
WorkMode getWorkMode() { return mWorkMode; }
|
||||
|
||||
virtual std::string toString() const {
|
||||
std::ostringstream os;
|
||||
os << "----- FakeFingerprintEngine:: -----" << std::endl;
|
||||
os << "mWorkMode:" << (int)mWorkMode;
|
||||
os << "acquiredVendorInfoBase:" << FINGERPRINT_ACQUIRED_VENDOR_BASE;
|
||||
os << ", errorVendorBase:" << FINGERPRINT_ERROR_VENDOR_BASE << std::endl;
|
||||
os << mLockoutTracker.toString();
|
||||
return os.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
|
||||
int64_t operationId, const keymaster::HardwareAuthToken& hat);
|
||||
|
||||
bool onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
|
||||
const std::future<void>& cancel);
|
||||
bool onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future<void>& cancel);
|
||||
bool onDetectInteractFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
|
||||
|
||||
WorkMode mWorkMode;
|
||||
ISessionCallback* mCb;
|
||||
keymaster::HardwareAuthToken mHat;
|
||||
std::future<void> mCancel;
|
||||
int64_t mOperationId;
|
||||
|
||||
private:
|
||||
static constexpr int32_t FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
|
||||
static constexpr int32_t FINGERPRINT_ERROR_VENDOR_BASE = 1000;
|
||||
@@ -91,8 +113,21 @@ class FakeFingerprintEngine {
|
||||
bool parseEnrollmentCaptureSingle(const std::string& str,
|
||||
std::vector<std::vector<int32_t>>& res);
|
||||
int32_t getRandomInRange(int32_t bound1, int32_t bound2);
|
||||
bool checkSensorLockout(ISessionCallback*);
|
||||
void clearLockout(ISessionCallback* cb);
|
||||
|
||||
FakeLockoutTracker mLockoutTracker;
|
||||
|
||||
protected:
|
||||
// lockout timer
|
||||
void lockoutTimerExpired(ISessionCallback* cb);
|
||||
bool isLockoutTimerSupported;
|
||||
bool isLockoutTimerStarted;
|
||||
bool isLockoutTimerAborted;
|
||||
|
||||
public:
|
||||
void startLockoutTimer(int64_t timeout, ISessionCallback* cb);
|
||||
bool getLockoutTimerStarted() { return isLockoutTimerStarted; }
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::fingerprint
|
||||
|
||||
@@ -28,7 +28,7 @@ class FakeFingerprintEngineSide : public FakeFingerprintEngine {
|
||||
static constexpr int32_t defaultSensorLocationY = 600;
|
||||
static constexpr int32_t defaultSensorRadius = 150;
|
||||
|
||||
FakeFingerprintEngineSide() : FakeFingerprintEngine() {}
|
||||
FakeFingerprintEngineSide();
|
||||
~FakeFingerprintEngineSide() {}
|
||||
|
||||
virtual SensorLocation defaultSensorLocation() override;
|
||||
|
||||
@@ -42,39 +42,20 @@ class FakeFingerprintEngineUdfps : public FakeFingerprintEngine {
|
||||
|
||||
SensorLocation defaultSensorLocation() override;
|
||||
|
||||
void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
|
||||
const std::future<void>& cancel);
|
||||
void authenticateImpl(ISessionCallback* cb, int64_t operationId,
|
||||
const std::future<void>& cancel);
|
||||
void detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel);
|
||||
|
||||
enum class WorkMode : int8_t { kIdle = 0, kAuthenticate, kEnroll, kDetectInteract };
|
||||
|
||||
WorkMode getWorkMode() { return mWorkMode; }
|
||||
void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
|
||||
int64_t operationId, const keymaster::HardwareAuthToken& hat);
|
||||
void fingerDownAction();
|
||||
|
||||
std::string toString() const {
|
||||
std::ostringstream os;
|
||||
os << FakeFingerprintEngine::toString();
|
||||
os << "----- FakeFingerprintEngineUdfps -----" << std::endl;
|
||||
os << "mWorkMode:" << (int)mWorkMode;
|
||||
os << ", mUiReadyTime:" << mUiReadyTime;
|
||||
os << ", mPointerDownTime:" << mPointerDownTime << std::endl;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
private:
|
||||
void onAuthenticateFingerDown();
|
||||
void onEnrollFingerDown();
|
||||
void onDetectInteractFingerDown();
|
||||
void fingerDownAction();
|
||||
void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
|
||||
int64_t operationId, const keymaster::HardwareAuthToken& hat);
|
||||
|
||||
WorkMode mWorkMode;
|
||||
ISessionCallback* mCb;
|
||||
keymaster::HardwareAuthToken mHat;
|
||||
std::vector<std::future<void>> mCancelVec;
|
||||
int64_t mOperationId;
|
||||
int64_t mPointerDownTime;
|
||||
int64_t mUiReadyTime;
|
||||
};
|
||||
|
||||
@@ -43,6 +43,7 @@ class Fingerprint : public BnFingerprint {
|
||||
private:
|
||||
void resetConfigToDefault();
|
||||
void onHelp(int);
|
||||
void onSimFingerDown();
|
||||
|
||||
std::unique_ptr<FakeFingerprintEngine> mEngine;
|
||||
WorkerThread mWorker;
|
||||
|
||||
@@ -93,9 +93,13 @@ class TestSessionCallback : public BnSessionCallback {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
|
||||
mLockoutTimed = true;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
ndk::ScopedAStatus onLockoutCleared() override {
|
||||
mLockoutCleared = true;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
ndk::ScopedAStatus onLockoutCleared() override { return ndk::ScopedAStatus::ok(); }
|
||||
ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
|
||||
|
||||
Error mError = Error::UNKNOWN;
|
||||
@@ -110,6 +114,8 @@ class TestSessionCallback : public BnSessionCallback {
|
||||
bool mAuthenticateFailed = false;
|
||||
bool mAuthenticatorIdInvalidated = false;
|
||||
bool mLockoutPermanent = false;
|
||||
bool mLockoutTimed = false;
|
||||
bool mLockoutCleared = false;
|
||||
int mInteractionDetectedCount = 0;
|
||||
int32_t mLastAcquiredInfo = -1;
|
||||
int32_t mLastAcquiredVendorCode = -1;
|
||||
@@ -132,6 +138,8 @@ class FakeFingerprintEngineTest : public ::testing::Test {
|
||||
FingerprintHalProperties::operation_enroll_latency({});
|
||||
FingerprintHalProperties::operation_authenticate_latency({});
|
||||
FingerprintHalProperties::operation_detect_interaction_latency({});
|
||||
FingerprintHalProperties::operation_authenticate_fails(false);
|
||||
FingerprintHalProperties::operation_detect_interaction_latency({});
|
||||
}
|
||||
|
||||
FakeFingerprintEngine mEngine;
|
||||
@@ -178,11 +186,14 @@ TEST_F(FakeFingerprintEngineTest, Enroll) {
|
||||
FingerprintHalProperties::next_enrollment("4:0,0:true");
|
||||
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
|
||||
mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kEnroll);
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
|
||||
ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
|
||||
ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
|
||||
ASSERT_EQ(4, mCallback->mLastEnrolled);
|
||||
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
|
||||
@@ -192,6 +203,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
|
||||
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
|
||||
mCancel.set_value();
|
||||
mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(Error::CANCELED, mCallback->mError);
|
||||
ASSERT_EQ(-1, mCallback->mLastEnrolled);
|
||||
ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
|
||||
@@ -204,6 +216,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollFail) {
|
||||
FingerprintHalProperties::next_enrollment(next);
|
||||
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
|
||||
mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
|
||||
ASSERT_EQ(-1, mCallback->mLastEnrolled);
|
||||
ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
|
||||
@@ -216,6 +229,7 @@ TEST_F(FakeFingerprintEngineTest, EnrollAcquired) {
|
||||
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
|
||||
int32_t prevCnt = mCallback->mLastAcquiredCount;
|
||||
mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
|
||||
ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
|
||||
ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
|
||||
@@ -229,9 +243,12 @@ TEST_F(FakeFingerprintEngineTest, Authenticate) {
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
FingerprintHalProperties::enrollment_hit(2);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_FALSE(mCallback->mAuthenticateFailed);
|
||||
ASSERT_EQ(2, mCallback->mLastAuthenticated);
|
||||
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
|
||||
@@ -239,6 +256,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
|
||||
FingerprintHalProperties::enrollment_hit(2);
|
||||
mCancel.set_value();
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(Error::CANCELED, mCallback->mError);
|
||||
ASSERT_EQ(-1, mCallback->mLastAuthenticated);
|
||||
}
|
||||
@@ -247,6 +265,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateNotSet) {
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
FingerprintHalProperties::enrollment_hit({});
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_TRUE(mCallback->mAuthenticateFailed);
|
||||
}
|
||||
|
||||
@@ -254,7 +273,9 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) {
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
FingerprintHalProperties::enrollment_hit(3);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_TRUE(mCallback->mAuthenticateFailed);
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
|
||||
@@ -262,6 +283,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
|
||||
FingerprintHalProperties::enrollment_hit(2);
|
||||
FingerprintHalProperties::lockout(true);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_TRUE(mCallback->mLockoutPermanent);
|
||||
ASSERT_NE(mCallback->mError, Error::UNKNOWN);
|
||||
}
|
||||
@@ -269,6 +291,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
|
||||
FingerprintHalProperties::operation_authenticate_error(8);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(mCallback->mError, (Error)8);
|
||||
ASSERT_EQ(mCallback->mErrorVendorCode, 0);
|
||||
}
|
||||
@@ -276,10 +299,19 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateError9) {
|
||||
FingerprintHalProperties::operation_authenticate_error(1009);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(mCallback->mError, (Error)7);
|
||||
ASSERT_EQ(mCallback->mErrorVendorCode, 9);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateFails) {
|
||||
FingerprintHalProperties::operation_authenticate_fails(true);
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_TRUE(mCallback->mAuthenticateFailed);
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
|
||||
FingerprintHalProperties::lockout(false);
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
@@ -287,6 +319,7 @@ TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
|
||||
FingerprintHalProperties::operation_authenticate_acquired("4,1009");
|
||||
int32_t prevCount = mCallback->mLastAcquiredCount;
|
||||
mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_FALSE(mCallback->mAuthenticateFailed);
|
||||
ASSERT_EQ(2, mCallback->mLastAuthenticated);
|
||||
ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
|
||||
@@ -300,8 +333,11 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
|
||||
FingerprintHalProperties::enrollment_hit(2);
|
||||
FingerprintHalProperties::operation_detect_interaction_acquired("");
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kDetectInteract);
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
|
||||
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
|
||||
ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
|
||||
@@ -310,6 +346,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
|
||||
FingerprintHalProperties::enrollment_hit(2);
|
||||
mCancel.set_value();
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(Error::CANCELED, mCallback->mError);
|
||||
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
|
||||
}
|
||||
@@ -319,6 +356,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) {
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
FingerprintHalProperties::enrollment_hit({});
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
|
||||
}
|
||||
|
||||
@@ -326,6 +364,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectNotEnrolled) {
|
||||
FingerprintHalProperties::enrollments({1, 2});
|
||||
FingerprintHalProperties::enrollment_hit(25);
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
|
||||
}
|
||||
|
||||
@@ -333,6 +372,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
|
||||
FingerprintHalProperties::detect_interaction(true);
|
||||
FingerprintHalProperties::operation_detect_interaction_error(8);
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
|
||||
ASSERT_EQ(mCallback->mError, (Error)8);
|
||||
ASSERT_EQ(mCallback->mErrorVendorCode, 0);
|
||||
@@ -345,6 +385,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) {
|
||||
FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
|
||||
int32_t prevCount = mCallback->mLastAcquiredCount;
|
||||
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
|
||||
mEngine.fingerDownAction();
|
||||
ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
|
||||
ASSERT_EQ(prevCount + 2, mCallback->mLastAcquiredCount);
|
||||
ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
|
||||
@@ -354,9 +395,7 @@ TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) {
|
||||
TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) {
|
||||
FingerprintHalProperties::enrollments({2, 4, 8});
|
||||
mEngine.enumerateEnrollmentsImpl(mCallback.get());
|
||||
ASSERT_EQ(
|
||||
4,
|
||||
mCallback->mLastEnrollmentEnumerated.size()); // Due to workaround. TODO (b/243129174)
|
||||
ASSERT_EQ(3, mCallback->mLastEnrollmentEnumerated.size());
|
||||
for (auto id : FingerprintHalProperties::enrollments()) {
|
||||
ASSERT_TRUE(std::find(mCallback->mLastEnrollmentEnumerated.begin(),
|
||||
mCallback->mLastEnrollmentEnumerated.end(),
|
||||
@@ -464,9 +503,15 @@ TEST_F(FakeFingerprintEngineTest, randomLatency) {
|
||||
FingerprintHalProperties::operation_detect_interaction_latency()));
|
||||
}
|
||||
ASSERT_TRUE(latencySet.size() > 95);
|
||||
FingerprintHalProperties::operation_detect_interaction_latency({});
|
||||
}
|
||||
|
||||
TEST_F(FakeFingerprintEngineTest, lockoutTimer) {
|
||||
mEngine.startLockoutTimer(200, mCallback.get());
|
||||
ASSERT_TRUE(mEngine.getLockoutTimerStarted());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(210));
|
||||
ASSERT_FALSE(mEngine.getLockoutTimerStarted());
|
||||
ASSERT_TRUE(mCallback->mLockoutCleared);
|
||||
}
|
||||
} // namespace aidl::android::hardware::biometrics::fingerprint
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -65,11 +65,11 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
|
||||
// time left
|
||||
int N = 5;
|
||||
int64_t prevTimeLeft = INT_MIN;
|
||||
int64_t prevTimeLeft = INT_MAX;
|
||||
for (int i = 0; i < N; i++) {
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
|
||||
int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
|
||||
ASSERT_TRUE(currTimeLeft > prevTimeLeft);
|
||||
ASSERT_TRUE(currTimeLeft < prevTimeLeft);
|
||||
prevTimeLeft = currTimeLeft;
|
||||
}
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
|
||||
|
||||
@@ -70,9 +70,9 @@ union Metadata {
|
||||
/**
|
||||
* Station name.
|
||||
*
|
||||
* This is a generic field to cover any radio technology.
|
||||
* <p>This is a generic field to cover any radio technology.
|
||||
*
|
||||
* If the PROGRAM_NAME has the same content as DAB_*_NAME or RDS_PS,
|
||||
* <p>Note: If the program name has the same content as dab*Name or ({@link Metadata#rdsPs},
|
||||
* it may not be present, to preserve space - framework must repopulate
|
||||
* it on the client side.
|
||||
*/
|
||||
@@ -86,10 +86,10 @@ union Metadata {
|
||||
/**
|
||||
* DAB ensemble name abbreviated (string).
|
||||
*
|
||||
* The string must be up to 8 characters long.
|
||||
* <p>Note: The string must be up to 8 characters long.
|
||||
*
|
||||
* If the short variant is present, the long (DAB_ENSEMBLE_NAME) one must be
|
||||
* present as well.
|
||||
* <p>Note: If the short variant is present, the long ({@link Metadata#dabEnsembleName})
|
||||
* one must be present as well.
|
||||
*/
|
||||
String dabEnsembleNameShort;
|
||||
|
||||
@@ -99,7 +99,9 @@ union Metadata {
|
||||
String dabServiceName;
|
||||
|
||||
/**
|
||||
* DAB service name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
|
||||
* DAB service name abbreviated (string)
|
||||
*
|
||||
* <p>Note: The string must be up to 8 characters long.
|
||||
*/
|
||||
String dabServiceNameShort;
|
||||
|
||||
@@ -109,7 +111,9 @@ union Metadata {
|
||||
String dabComponentName;
|
||||
|
||||
/**
|
||||
* DAB component name abbreviated (see DAB_ENSEMBLE_NAME_SHORT) (string)
|
||||
* DAB component name abbreviated (string)
|
||||
*
|
||||
* <p>Note: The string must be up to 8 characters long.
|
||||
*/
|
||||
String dabComponentNameShort;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,10 @@ parcelable ProgramIdentifier {
|
||||
IdentifierType type = IdentifierType.INVALID;
|
||||
|
||||
/**
|
||||
* The uint64_t value field holds the value in format described in comments
|
||||
* for IdentifierType enum.
|
||||
* The value field holds the value in format described in comments for IdentifierType enum.
|
||||
*
|
||||
* The value should be 64-bit unsigned integer, but is represented as 64-bit signed integer
|
||||
* in AIDL.
|
||||
*/
|
||||
long value;
|
||||
}
|
||||
|
||||
@@ -53,18 +53,18 @@ const VirtualRadio& VirtualRadio::getAmFmRadio() {
|
||||
static VirtualRadio amFmRadioMock(
|
||||
"AM/FM radio mock",
|
||||
{
|
||||
{makeSelectorAmfm(/* frequency= */ 94900), "Wild 94.9", "Drake ft. Rihanna",
|
||||
{makeSelectorAmfm(/* frequency= */ 94900u), "Wild 94.9", "Drake ft. Rihanna",
|
||||
"Too Good"},
|
||||
{makeSelectorAmfm(/* frequency= */ 96500), "KOIT", "Celine Dion", "All By Myself"},
|
||||
{makeSelectorAmfm(/* frequency= */ 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
|
||||
{makeSelectorAmfm(/* frequency= */ 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
|
||||
{makeSelectorAmfm(/* frequency= */ 101300), "101-3 KISS-FM", "Justin Timberlake",
|
||||
{makeSelectorAmfm(/* frequency= */ 96500u), "KOIT", "Celine Dion", "All By Myself"},
|
||||
{makeSelectorAmfm(/* frequency= */ 97300u), "Alice@97.3", "Drops of Jupiter", "Train"},
|
||||
{makeSelectorAmfm(/* frequency= */ 99700u), "99.7 Now!", "The Chainsmokers", "Closer"},
|
||||
{makeSelectorAmfm(/* frequency= */ 101300u), "101-3 KISS-FM", "Justin Timberlake",
|
||||
"Rock Your Body"},
|
||||
{makeSelectorAmfm(/* frequency= */ 103700), "iHeart80s @ 103.7", "Michael Jackson",
|
||||
{makeSelectorAmfm(/* frequency= */ 103700u), "iHeart80s @ 103.7", "Michael Jackson",
|
||||
"Billie Jean"},
|
||||
{makeSelectorAmfm(/* frequency= */ 106100), "106 KMEL", "Drake", "Marvins Room"},
|
||||
{makeSelectorAmfm(/* frequency= */ 700), "700 AM", "Artist700", "Title700"},
|
||||
{makeSelectorAmfm(/* frequency= */ 1700), "1700 AM", "Artist1700", "Title1700"},
|
||||
{makeSelectorAmfm(/* frequency= */ 106100u), "106 KMEL", "Drake", "Marvins Room"},
|
||||
{makeSelectorAmfm(/* frequency= */ 700u), "700 AM", "Artist700", "Title700"},
|
||||
{makeSelectorAmfm(/* frequency= */ 1700u), "1700 AM", "Artist1700", "Title1700"},
|
||||
});
|
||||
// clang-format on
|
||||
return amFmRadioMock;
|
||||
@@ -77,13 +77,13 @@ const VirtualRadio& VirtualRadio::getDabRadio() {
|
||||
"DAB radio mock",
|
||||
{
|
||||
{makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u,
|
||||
/* freq= */ 225648), "BBC Radio 1", "Khalid", "Talk"},
|
||||
/* freq= */ 225648u), "BBC Radio 1", "Khalid", "Talk"},
|
||||
{makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u,
|
||||
/* freq= */ 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"},
|
||||
/* freq= */ 222064u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
|
||||
{makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
|
||||
/* freq= */ 227360), "Absolute Radio", "Coldplay", "Clocks"},
|
||||
/* freq= */ 227360u), "Absolute Radio", "Coldplay", "Clocks"},
|
||||
{makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
|
||||
/* freq= */ 222064), "Absolute Radio", "Coldplay", "Clocks"},
|
||||
/* freq= */ 222064u), "Absolute Radio", "Coldplay", "Clocks"},
|
||||
});
|
||||
// clang-format on
|
||||
return dabRadioMock;
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <broadcastradio-utils-aidl/Utils.h>
|
||||
#include <broadcastradio-vts-utils/mock-timeout.h>
|
||||
#include <cutils/bitops.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
|
||||
@@ -61,11 +61,6 @@ using ::testing::SaveArg;
|
||||
|
||||
namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
|
||||
|
||||
inline constexpr std::chrono::seconds kTuneTimeoutSec =
|
||||
std::chrono::seconds(IBroadcastRadio::TUNER_TIMEOUT_MS * 1000);
|
||||
inline constexpr std::chrono::seconds kProgramListScanTimeoutSec =
|
||||
std::chrono::seconds(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS * 1000);
|
||||
|
||||
const ConfigFlag kConfigFlagValues[] = {
|
||||
ConfigFlag::FORCE_MONO,
|
||||
ConfigFlag::FORCE_ANALOG,
|
||||
@@ -108,20 +103,68 @@ bool supportsFM(const AmFmRegionConfig& config) {
|
||||
|
||||
} // namespace
|
||||
|
||||
class TunerCallbackMock : public BnTunerCallback {
|
||||
class CallbackFlag final {
|
||||
public:
|
||||
TunerCallbackMock();
|
||||
CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
|
||||
/**
|
||||
* Notify that the callback is called.
|
||||
*/
|
||||
void notify() {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mCalled = true;
|
||||
lock.unlock();
|
||||
mCv.notify_all();
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for the timeout passed into the constructor.
|
||||
*/
|
||||
bool wait() {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
|
||||
[this] { return mCalled; });
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset the callback to not called.
|
||||
*/
|
||||
void reset() {
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mCalled = false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
bool mCalled GUARDED_BY(mMutex) = false;
|
||||
std::condition_variable mCv;
|
||||
int mTimeoutMs;
|
||||
};
|
||||
|
||||
class TunerCallbackImpl final : public BnTunerCallback {
|
||||
public:
|
||||
TunerCallbackImpl();
|
||||
ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
|
||||
MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&));
|
||||
ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
|
||||
ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
|
||||
MOCK_METHOD1(onAntennaStateChange, ScopedAStatus(bool connected));
|
||||
MOCK_METHOD1(onParametersUpdated, ScopedAStatus(const vector<VendorKeyValue>& parameters));
|
||||
MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value));
|
||||
MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
|
||||
ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
|
||||
ScopedAStatus onAntennaStateChange(bool connected) override;
|
||||
ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
|
||||
|
||||
bool waitOnCurrentProgramInfoChangedCallback();
|
||||
bool waitProgramReady();
|
||||
void reset();
|
||||
|
||||
bool getAntennaConnectionState();
|
||||
ProgramInfo getCurrentProgramInfo();
|
||||
bcutils::ProgramInfoSet getProgramList();
|
||||
|
||||
private:
|
||||
std::mutex mLock;
|
||||
bool mAntennaConnectionState GUARDED_BY(mLock);
|
||||
ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
|
||||
bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
|
||||
CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
|
||||
CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
|
||||
};
|
||||
|
||||
struct AnnouncementListenerMock : public BnAnnouncementListener {
|
||||
@@ -139,7 +182,7 @@ class BroadcastRadioHalTest : public testing::TestWithParam<string> {
|
||||
|
||||
std::shared_ptr<IBroadcastRadio> mModule;
|
||||
Properties mProperties;
|
||||
std::shared_ptr<TunerCallbackMock> mCallback = SharedRefBase::make<TunerCallbackMock>();
|
||||
std::shared_ptr<TunerCallbackImpl> mCallback;
|
||||
};
|
||||
|
||||
MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) {
|
||||
@@ -147,20 +190,18 @@ MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + "
|
||||
return ids.end() != find(ids.begin(), ids.end(), id.value);
|
||||
}
|
||||
|
||||
TunerCallbackMock::TunerCallbackMock() {
|
||||
EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
|
||||
|
||||
// we expect the antenna is connected through the whole test
|
||||
EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
|
||||
TunerCallbackImpl::TunerCallbackImpl() {
|
||||
mAntennaConnectionState = true;
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) {
|
||||
ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
|
||||
LOG(DEBUG) << "Tune failed for selector" << selector.toString();
|
||||
EXPECT_TRUE(result == Result::CANCELED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
|
||||
ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
|
||||
LOG(DEBUG) << "onCurrentProgramInfoChanged called";
|
||||
for (const auto& id : info.selector) {
|
||||
EXPECT_NE(id.type, IdentifierType::INVALID);
|
||||
}
|
||||
@@ -196,21 +237,75 @@ ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo&
|
||||
}
|
||||
}
|
||||
|
||||
return onCurrentProgramInfoChangedMock(info);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
mCurrentProgramInfo = info;
|
||||
}
|
||||
|
||||
mOnCurrentProgramInfoChangedFlag.notify();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
|
||||
updateProgramList(chunk, &mProgramList);
|
||||
ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
|
||||
LOG(DEBUG) << "onProgramListUpdated called";
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
updateProgramList(chunk, &mProgramList);
|
||||
}
|
||||
|
||||
if (chunk.complete) {
|
||||
onProgramListReady();
|
||||
mOnProgramListReadyFlag.notify();
|
||||
}
|
||||
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackImpl::onParametersUpdated(
|
||||
[[maybe_unused]] const vector<VendorKeyValue>& parameters) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
|
||||
if (!connected) {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
mAntennaConnectionState = false;
|
||||
}
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
|
||||
[[maybe_unused]] bool in_value) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
|
||||
return mOnCurrentProgramInfoChangedFlag.wait();
|
||||
}
|
||||
|
||||
bool TunerCallbackImpl::waitProgramReady() {
|
||||
return mOnProgramListReadyFlag.wait();
|
||||
}
|
||||
|
||||
void TunerCallbackImpl::reset() {
|
||||
mOnCurrentProgramInfoChangedFlag.reset();
|
||||
mOnProgramListReadyFlag.reset();
|
||||
}
|
||||
|
||||
bool TunerCallbackImpl::getAntennaConnectionState() {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
return mAntennaConnectionState;
|
||||
}
|
||||
|
||||
ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
return mCurrentProgramInfo;
|
||||
}
|
||||
|
||||
bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
|
||||
std::lock_guard<std::mutex> lk(mLock);
|
||||
return mProgramList;
|
||||
}
|
||||
|
||||
void BroadcastRadioHalTest::SetUp() {
|
||||
EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
|
||||
|
||||
@@ -228,6 +323,8 @@ void BroadcastRadioHalTest::SetUp() {
|
||||
EXPECT_FALSE(mProperties.product.empty());
|
||||
EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
|
||||
|
||||
mCallback = SharedRefBase::make<TunerCallbackImpl>();
|
||||
|
||||
// set callback
|
||||
EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
|
||||
}
|
||||
@@ -236,6 +333,11 @@ void BroadcastRadioHalTest::TearDown() {
|
||||
if (mModule) {
|
||||
ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
|
||||
}
|
||||
if (mCallback) {
|
||||
// we expect the antenna is connected through the whole test
|
||||
EXPECT_TRUE(mCallback->getAntennaConnectionState());
|
||||
mCallback = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
|
||||
@@ -256,7 +358,7 @@ std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList() {
|
||||
|
||||
std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
|
||||
const ProgramFilter& filter) {
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
|
||||
mCallback->reset();
|
||||
|
||||
auto startResult = mModule->startProgramListUpdates(filter);
|
||||
|
||||
@@ -268,13 +370,13 @@ std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
|
||||
if (!startResult.isOk()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, kProgramListScanTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitProgramReady());
|
||||
|
||||
auto stopResult = mModule->stopProgramListUpdates();
|
||||
|
||||
EXPECT_TRUE(stopResult.isOk());
|
||||
|
||||
return mCallback->mProgramList;
|
||||
return mCallback->getProgramList();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,7 +558,7 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithoutTunerCallback) {
|
||||
* - if it is supported, the test is ignored;
|
||||
*/
|
||||
TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
|
||||
LOG(DEBUG) << "TuneFailsWithInvalid Test";
|
||||
LOG(DEBUG) << "TuneFailsWithNotSupported Test";
|
||||
|
||||
vector<ProgramIdentifier> supportTestId = {
|
||||
makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid
|
||||
@@ -477,9 +579,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
|
||||
for (const auto& id : supportTestId) {
|
||||
ProgramSelector sel{id, {}};
|
||||
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
if (!bcutils::isSupported(mProperties, sel)) {
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
|
||||
}
|
||||
}
|
||||
@@ -508,9 +610,9 @@ TEST_P(BroadcastRadioHalTest, TuneFailsWithInvalid) {
|
||||
for (const auto& id : invalidId) {
|
||||
ProgramSelector sel{id, {}};
|
||||
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
if (bcutils::isSupported(mProperties, sel)) {
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
|
||||
}
|
||||
}
|
||||
@@ -549,13 +651,7 @@ TEST_P(BroadcastRadioHalTest, FmTune) {
|
||||
int64_t freq = 90900; // 90.9 FM
|
||||
ProgramSelector sel = makeSelectorAmfm(freq);
|
||||
// try tuning
|
||||
ProgramInfo infoCb = {};
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
|
||||
InfoHasId(makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq)))
|
||||
.Times(AnyNumber())
|
||||
.WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))))
|
||||
.WillRepeatedly(testing::InvokeWithoutArgs([] { return ndk::ScopedAStatus::ok(); }));
|
||||
|
||||
mCallback->reset();
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
// expect a failure if it's not supported
|
||||
@@ -566,7 +662,8 @@ TEST_P(BroadcastRadioHalTest, FmTune) {
|
||||
|
||||
// expect a callback if it succeeds
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
|
||||
|
||||
LOG(DEBUG) << "Current program info: " << infoCb.toString();
|
||||
|
||||
@@ -638,12 +735,6 @@ TEST_P(BroadcastRadioHalTest, DabTune) {
|
||||
}
|
||||
|
||||
// try tuning
|
||||
ProgramInfo infoCb = {};
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
|
||||
InfoHasId(makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)))
|
||||
.Times(AnyNumber())
|
||||
.WillOnce(
|
||||
DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))));
|
||||
|
||||
auto result = mModule->tune(sel);
|
||||
|
||||
@@ -655,7 +746,9 @@ TEST_P(BroadcastRadioHalTest, DabTune) {
|
||||
|
||||
// expect a callback if it succeeds
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
|
||||
|
||||
LOG(DEBUG) << "Current program info: " << infoCb.toString();
|
||||
|
||||
// it should tune exactly to what was requested
|
||||
@@ -669,13 +762,13 @@ TEST_P(BroadcastRadioHalTest, DabTune) {
|
||||
*
|
||||
* Verifies that:
|
||||
* - the method succeeds;
|
||||
* - the program info is changed within kTuneTimeoutSec;
|
||||
* - the program info is changed within kTuneTimeoutMs;
|
||||
* - works both directions and with or without skipping sub-channel.
|
||||
*/
|
||||
TEST_P(BroadcastRadioHalTest, Seek) {
|
||||
LOG(DEBUG) << "Seek Test";
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
|
||||
mCallback->reset();
|
||||
|
||||
auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
|
||||
|
||||
@@ -685,14 +778,14 @@ TEST_P(BroadcastRadioHalTest, Seek) {
|
||||
}
|
||||
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
|
||||
mCallback->reset();
|
||||
|
||||
result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
|
||||
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -720,13 +813,13 @@ TEST_P(BroadcastRadioHalTest, SeekFailsWithoutTunerCallback) {
|
||||
*
|
||||
* Verifies that:
|
||||
* - the method succeeds or returns NOT_SUPPORTED;
|
||||
* - the program info is changed within kTuneTimeoutSec if the method succeeded;
|
||||
* - the program info is changed within kTuneTimeoutMs if the method succeeded;
|
||||
* - works both directions.
|
||||
*/
|
||||
TEST_P(BroadcastRadioHalTest, Step) {
|
||||
LOG(DEBUG) << "Step Test";
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
|
||||
mCallback->reset();
|
||||
|
||||
auto result = mModule->step(/* in_directionUp= */ true);
|
||||
|
||||
@@ -735,14 +828,14 @@ TEST_P(BroadcastRadioHalTest, Step) {
|
||||
return;
|
||||
}
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
|
||||
EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
|
||||
mCallback->reset();
|
||||
|
||||
result = mModule->step(/* in_directionUp= */ false);
|
||||
|
||||
EXPECT_TRUE(result.isOk());
|
||||
EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
|
||||
EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -904,13 +997,12 @@ TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
|
||||
LOG(DEBUG) << "SetConfigFlags Test";
|
||||
|
||||
auto get = [&](ConfigFlag flag) -> bool {
|
||||
bool* gotValue = nullptr;
|
||||
bool gotValue;
|
||||
|
||||
auto halResult = mModule->isConfigFlagSet(flag, gotValue);
|
||||
auto halResult = mModule->isConfigFlagSet(flag, &gotValue);
|
||||
|
||||
EXPECT_FALSE(gotValue == nullptr);
|
||||
EXPECT_TRUE(halResult.isOk());
|
||||
return *gotValue;
|
||||
return gotValue;
|
||||
};
|
||||
|
||||
auto notSupportedError = resultToInt(Result::NOT_SUPPORTED);
|
||||
@@ -955,7 +1047,7 @@ TEST_P(BroadcastRadioHalTest, SetConfigFlags) {
|
||||
*
|
||||
* Verifies that:
|
||||
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutSec;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutMs;
|
||||
* - stopProgramListUpdates does not crash.
|
||||
*/
|
||||
TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
|
||||
@@ -969,7 +1061,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
|
||||
*
|
||||
* Verifies that:
|
||||
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutSec;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutMs;
|
||||
* - stopProgramListUpdates does not crash;
|
||||
* - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
|
||||
* AMFM program matches the expected result.
|
||||
@@ -1017,7 +1109,7 @@ TEST_P(BroadcastRadioHalTest, GetProgramListFromAmFmFilter) {
|
||||
*
|
||||
* Verifies that:
|
||||
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutSec;
|
||||
* - the complete list is fetched within kProgramListScanTimeoutMs;
|
||||
* - stopProgramListUpdates does not crash;
|
||||
* - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
|
||||
* program matches the expected result.
|
||||
|
||||
@@ -204,7 +204,7 @@ bool isSupported(const Properties& prop, const ProgramSelector& sel) {
|
||||
}
|
||||
|
||||
bool isValid(const ProgramIdentifier& id) {
|
||||
int64_t val = id.value;
|
||||
uint64_t val = static_cast<uint64_t>(id.value);
|
||||
bool valid = true;
|
||||
|
||||
auto expect = [&valid](bool condition, const string& message) {
|
||||
@@ -231,11 +231,11 @@ bool isValid(const ProgramIdentifier& id) {
|
||||
expect(val <= 0xFFFFu, "16bit id");
|
||||
break;
|
||||
case IdentifierType::HD_STATION_ID_EXT: {
|
||||
int64_t stationId = val & 0xFFFFFFFF; // 32bit
|
||||
uint64_t stationId = val & 0xFFFFFFFF; // 32bit
|
||||
val >>= 32;
|
||||
int64_t subchannel = val & 0xF; // 4bit
|
||||
uint64_t subchannel = val & 0xF; // 4bit
|
||||
val >>= 4;
|
||||
int64_t freq = val & 0x3FFFF; // 18bit
|
||||
uint64_t freq = val & 0x3FFFF; // 18bit
|
||||
expect(stationId != 0u, "HD station id != 0");
|
||||
expect(subchannel < 8u, "HD subch < 8");
|
||||
expect(freq > 100u, "f > 100kHz");
|
||||
@@ -252,9 +252,9 @@ bool isValid(const ProgramIdentifier& id) {
|
||||
break;
|
||||
}
|
||||
case IdentifierType::DAB_SID_EXT: {
|
||||
int64_t sid = val & 0xFFFFFFFF; // 32bit
|
||||
uint64_t sid = val & 0xFFFFFFFF; // 32bit
|
||||
val >>= 32;
|
||||
int64_t ecc = val & 0xFF; // 8bit
|
||||
uint64_t ecc = val & 0xFF; // 8bit
|
||||
expect(sid != 0u, "DAB SId != 0");
|
||||
expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
|
||||
break;
|
||||
@@ -305,19 +305,19 @@ ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
|
||||
return {type, value};
|
||||
}
|
||||
|
||||
ProgramSelector makeSelectorAmfm(int32_t frequency) {
|
||||
ProgramSelector makeSelectorAmfm(uint32_t frequency) {
|
||||
ProgramSelector sel = {};
|
||||
sel.primaryId = makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, frequency);
|
||||
return sel;
|
||||
}
|
||||
|
||||
ProgramSelector makeSelectorDab(int64_t sidExt) {
|
||||
ProgramSelector makeSelectorDab(uint64_t sidExt) {
|
||||
ProgramSelector sel = {};
|
||||
sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
|
||||
return sel;
|
||||
}
|
||||
|
||||
ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq) {
|
||||
ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq) {
|
||||
ProgramSelector sel = {};
|
||||
sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
|
||||
vector<ProgramIdentifier> secondaryIds = {
|
||||
|
||||
@@ -137,9 +137,9 @@ bool isValid(const ProgramIdentifier& id);
|
||||
bool isValid(const ProgramSelector& sel);
|
||||
|
||||
ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
|
||||
ProgramSelector makeSelectorAmfm(int32_t frequency);
|
||||
ProgramSelector makeSelectorDab(int64_t sidExt);
|
||||
ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq);
|
||||
ProgramSelector makeSelectorAmfm(uint32_t frequency);
|
||||
ProgramSelector makeSelectorDab(uint64_t sidExt);
|
||||
ProgramSelector makeSelectorDab(uint64_t sidExt, uint32_t ensemble, uint64_t freq);
|
||||
|
||||
bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
|
||||
|
||||
|
||||
@@ -552,6 +552,11 @@ TEST_P(CameraAidlTest, configureStreamsAvailableOutputs) {
|
||||
stream.rotation = StreamRotation::ROTATION_0;
|
||||
stream.dynamicRangeProfile = RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
|
||||
stream.useCase = ScalerAvailableStreamUseCases::
|
||||
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
|
||||
stream.colorSpace = static_cast<int>(
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
|
||||
|
||||
std::vector<Stream> streams = {stream};
|
||||
StreamConfiguration config;
|
||||
|
||||
@@ -45,8 +45,6 @@ using ::aidl::android::hardware::camera::common::TorchModeStatus;
|
||||
using ::aidl::android::hardware::camera::device::CameraMetadata;
|
||||
using ::aidl::android::hardware::camera::device::ICameraDevice;
|
||||
using ::aidl::android::hardware::camera::metadata::CameraMetadataTag;
|
||||
using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap;
|
||||
using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
|
||||
using ::aidl::android::hardware::camera::metadata::SensorInfoColorFilterArrangement;
|
||||
using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
|
||||
using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
|
||||
@@ -122,7 +120,7 @@ void CameraAidlTest::SetUp() {
|
||||
ABinderProcess_startThreadPool();
|
||||
|
||||
SpAIBinder cameraProviderBinder =
|
||||
SpAIBinder(AServiceManager_getService(serviceDescriptor.c_str()));
|
||||
SpAIBinder(AServiceManager_waitForService(serviceDescriptor.c_str()));
|
||||
ASSERT_NE(cameraProviderBinder.get(), nullptr);
|
||||
|
||||
std::shared_ptr<ICameraProvider> cameraProvider =
|
||||
@@ -2321,21 +2319,26 @@ void CameraAidlTest::configureStreamUseCaseInternal(const AvailableStream &thres
|
||||
}
|
||||
|
||||
std::vector<Stream> streams(1);
|
||||
streams[0] = {0,
|
||||
StreamType::OUTPUT,
|
||||
outputPreviewStreams[0].width,
|
||||
outputPreviewStreams[0].height,
|
||||
static_cast<PixelFormat>(outputPreviewStreams[0].format),
|
||||
static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_CPU_READ),
|
||||
Dataspace::UNKNOWN,
|
||||
StreamRotation::ROTATION_0,
|
||||
std::string(),
|
||||
0,
|
||||
-1,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
|
||||
streams[0] = {
|
||||
0,
|
||||
StreamType::OUTPUT,
|
||||
outputPreviewStreams[0].width,
|
||||
outputPreviewStreams[0].height,
|
||||
static_cast<PixelFormat>(outputPreviewStreams[0].format),
|
||||
static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_CPU_READ),
|
||||
Dataspace::UNKNOWN,
|
||||
StreamRotation::ROTATION_0,
|
||||
std::string(),
|
||||
0,
|
||||
-1,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
|
||||
ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
|
||||
static_cast<int>(
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)};
|
||||
|
||||
int32_t streamConfigCounter = 0;
|
||||
CameraMetadata req;
|
||||
@@ -2479,7 +2482,11 @@ void CameraAidlTest::configureSingleStream(
|
||||
/*groupId*/ -1,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
|
||||
ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
|
||||
static_cast<int>(
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)};
|
||||
|
||||
StreamConfiguration config;
|
||||
config.streams = streams;
|
||||
@@ -2810,21 +2817,26 @@ void CameraAidlTest::configurePreviewStreams(
|
||||
std::vector<Stream> streams(physicalIds.size());
|
||||
int32_t streamId = 0;
|
||||
for (auto const& physicalId : physicalIds) {
|
||||
streams[streamId] = {streamId,
|
||||
StreamType::OUTPUT,
|
||||
outputPreviewStreams[0].width,
|
||||
outputPreviewStreams[0].height,
|
||||
static_cast<PixelFormat>(outputPreviewStreams[0].format),
|
||||
static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
|
||||
Dataspace::UNKNOWN,
|
||||
StreamRotation::ROTATION_0,
|
||||
physicalId,
|
||||
0,
|
||||
-1,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
|
||||
streams[streamId] = {
|
||||
streamId,
|
||||
StreamType::OUTPUT,
|
||||
outputPreviewStreams[0].width,
|
||||
outputPreviewStreams[0].height,
|
||||
static_cast<PixelFormat>(outputPreviewStreams[0].format),
|
||||
static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER),
|
||||
Dataspace::UNKNOWN,
|
||||
StreamRotation::ROTATION_0,
|
||||
physicalId,
|
||||
0,
|
||||
-1,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
|
||||
ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
|
||||
static_cast<int>(
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)};
|
||||
streamId++;
|
||||
}
|
||||
|
||||
@@ -2883,7 +2895,8 @@ void CameraAidlTest::configureStreams(const std::string& name,
|
||||
bool* supportsPartialResults, int32_t* partialResultCount,
|
||||
bool* useHalBufManager, std::shared_ptr<DeviceCb>* outCb,
|
||||
uint32_t streamConfigCounter, bool maxResolution,
|
||||
RequestAvailableDynamicRangeProfilesMap prof) {
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProf,
|
||||
RequestAvailableColorSpaceProfilesMap colorSpaceProf) {
|
||||
ASSERT_NE(nullptr, session);
|
||||
ASSERT_NE(nullptr, halStreams);
|
||||
ASSERT_NE(nullptr, previewStream);
|
||||
@@ -2965,7 +2978,9 @@ void CameraAidlTest::configureStreams(const std::string& name,
|
||||
-1,
|
||||
{maxResolution ? SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION
|
||||
: SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
prof};
|
||||
dynamicRangeProf,
|
||||
ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
|
||||
static_cast<int>(colorSpaceProf)};
|
||||
|
||||
StreamConfiguration config;
|
||||
config.streams = streams;
|
||||
@@ -3416,7 +3431,11 @@ void CameraAidlTest::configureOfflineStillStream(
|
||||
/*groupId*/ 0,
|
||||
{SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
|
||||
ScalerAvailableStreamUseCases::ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
|
||||
static_cast<int>(
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)};
|
||||
|
||||
StreamConfiguration config = {streams, StreamConfigurationMode::NORMAL_MODE, CameraMetadata()};
|
||||
|
||||
@@ -3531,15 +3550,12 @@ void CameraAidlTest::processColorSpaceRequest(
|
||||
Stream previewStream;
|
||||
std::shared_ptr<DeviceCb> cb;
|
||||
|
||||
previewStream.usage =
|
||||
static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
|
||||
previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED);
|
||||
previewStream.colorSpace = static_cast<int32_t>(colorSpace);
|
||||
previewStream.usage = static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
|
||||
configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
|
||||
&previewStream, &halStreams, &supportsPartialResults,
|
||||
&partialResultCount, &useHalBufManager, &cb, 0,
|
||||
/*maxResolution*/ false, dynamicRangeProfile);
|
||||
&previewStream, &halStreams, &supportsPartialResults, &partialResultCount,
|
||||
&useHalBufManager, &cb, 0,
|
||||
/*maxResolution*/ false, dynamicRangeProfile, colorSpace);
|
||||
ASSERT_NE(mSession, nullptr);
|
||||
|
||||
::aidl::android::hardware::common::fmq::MQDescriptor<
|
||||
|
||||
@@ -77,6 +77,9 @@ using ::aidl::android::hardware::camera::device::StreamBuffer;
|
||||
using ::aidl::android::hardware::camera::device::StreamBufferRet;
|
||||
using ::aidl::android::hardware::camera::device::StreamConfiguration;
|
||||
using ::aidl::android::hardware::camera::device::StreamConfigurationMode;
|
||||
using ::aidl::android::hardware::camera::metadata::RequestAvailableColorSpaceProfilesMap;
|
||||
using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
|
||||
using ::aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases;
|
||||
using ::aidl::android::hardware::camera::provider::ConcurrentCameraIdCombination;
|
||||
using ::aidl::android::hardware::camera::provider::ICameraProvider;
|
||||
|
||||
@@ -205,10 +208,12 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
bool* supportsPartialResults /*out*/, int32_t* partialResultCount /*out*/,
|
||||
bool* useHalBufManager /*out*/, std::shared_ptr<DeviceCb>* outCb /*out*/,
|
||||
uint32_t streamConfigCounter, bool maxResolution,
|
||||
aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
|
||||
prof = ::aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProf =
|
||||
RequestAvailableDynamicRangeProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
|
||||
RequestAvailableColorSpaceProfilesMap colorSpaceProf =
|
||||
RequestAvailableColorSpaceProfilesMap::
|
||||
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
|
||||
|
||||
void configurePreviewStreams(
|
||||
const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
|
||||
@@ -379,8 +384,7 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
|
||||
static void get10BitDynamicRangeProfiles(
|
||||
const camera_metadata_t* staticMeta,
|
||||
std::vector<aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableDynamicRangeProfilesMap>* profiles);
|
||||
std::vector<RequestAvailableDynamicRangeProfilesMap>* profiles);
|
||||
|
||||
static bool reportsColorSpaces(const camera_metadata_t* staticMeta);
|
||||
|
||||
@@ -390,17 +394,13 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
RequestAvailableColorSpaceProfilesMap>* profiles);
|
||||
|
||||
static bool isColorSpaceCompatibleWithDynamicRangeAndPixelFormat(
|
||||
const camera_metadata_t* staticMeta,
|
||||
aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableColorSpaceProfilesMap colorSpace,
|
||||
aidl::android::hardware::camera::metadata::
|
||||
const camera_metadata_t* staticMeta, RequestAvailableColorSpaceProfilesMap colorSpace,
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile,
|
||||
aidl::android::hardware::graphics::common::PixelFormat pixelFormat);
|
||||
|
||||
static const char* getColorSpaceProfileString(aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableColorSpaceProfilesMap colorSpace);
|
||||
static const char* getColorSpaceProfileString(RequestAvailableColorSpaceProfilesMap colorSpace);
|
||||
|
||||
static const char* getDynamicRangeProfileString(aidl::android::hardware::camera::metadata::
|
||||
static const char* getDynamicRangeProfileString(
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
|
||||
|
||||
static int32_t halFormatToPublicFormat(
|
||||
@@ -411,10 +411,8 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
|
||||
static Size getMinSize(Size a, Size b);
|
||||
|
||||
void processColorSpaceRequest(aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableColorSpaceProfilesMap colorSpace,
|
||||
aidl::android::hardware::camera::metadata::
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
|
||||
void processColorSpaceRequest(RequestAvailableColorSpaceProfilesMap colorSpace,
|
||||
RequestAvailableDynamicRangeProfilesMap dynamicRangeProfile);
|
||||
|
||||
void processZoomSettingsOverrideRequests(
|
||||
int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
|
||||
@@ -574,10 +572,8 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
static bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
|
||||
std::string* deviceVersion, std::string* cameraId);
|
||||
|
||||
static void verify10BitMetadata(
|
||||
HandleImporter& importer, const InFlightRequest& request,
|
||||
aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
|
||||
profile);
|
||||
static void verify10BitMetadata(HandleImporter& importer, const InFlightRequest& request,
|
||||
RequestAvailableDynamicRangeProfilesMap profile);
|
||||
|
||||
static void waitForReleaseFence(
|
||||
std::vector<InFlightRequest::StreamBufferAndTimestamp>& resultOutputBuffers);
|
||||
|
||||
@@ -106,9 +106,15 @@ my_system_matrix_deps := \
|
||||
framework_compatibility_matrix.6.xml \
|
||||
framework_compatibility_matrix.7.xml \
|
||||
framework_compatibility_matrix.8.xml \
|
||||
framework_compatibility_matrix.9.xml \
|
||||
framework_compatibility_matrix.device.xml \
|
||||
|
||||
# Only allow the use of the unreleased compatibility matrix when we can use unfrozen
|
||||
# interfaces (in the `next` release configuration).
|
||||
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
|
||||
my_system_matrix_deps += \
|
||||
framework_compatibility_matrix.9.xml
|
||||
endif
|
||||
|
||||
my_framework_matrix_deps += \
|
||||
$(my_system_matrix_deps)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.authsecret</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
@@ -123,7 +123,7 @@
|
||||
<instance>virtual</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.biometrics.fingerprint</name>
|
||||
<version>3</version>
|
||||
<interface>
|
||||
@@ -314,7 +314,7 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.security.keymint</name>
|
||||
<version>1-3</version>
|
||||
<interface>
|
||||
@@ -323,7 +323,7 @@
|
||||
<instance>strongbox</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.security.keymint</name>
|
||||
<version>1-3</version>
|
||||
<interface>
|
||||
@@ -532,7 +532,7 @@
|
||||
<regex-instance>SIM[1-9][0-9]*</regex-instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.security.secureclock</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
@@ -540,7 +540,7 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.security.sharedsecret</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
@@ -692,7 +692,7 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<hal format="aidl" optional="true" updatable-via-apex="true">
|
||||
<name>android.hardware.uwb</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
|
||||
@@ -565,6 +565,14 @@
|
||||
<regex-instance>chip[0-9]+</regex-instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<name>android.hardware.threadnetwork</name>
|
||||
<version>1</version>
|
||||
<interface>
|
||||
<name>IThreadChip</name>
|
||||
<instance>chip0</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<name>android.hardware.tv.hdmi.cec</name>
|
||||
<version>1</version>
|
||||
|
||||
@@ -23,7 +23,7 @@ aidl_interface {
|
||||
sdk_version: "module_current",
|
||||
},
|
||||
ndk: {
|
||||
min_sdk_version: "UpsideDownCake",
|
||||
min_sdk_version: "34",
|
||||
},
|
||||
},
|
||||
double_loadable: true,
|
||||
|
||||
@@ -486,8 +486,6 @@ void GnssHalTest::collectSvInfoListTimestamps(const int numMeasurementEvents,
|
||||
|
||||
auto status = aidl_gnss_hal_->startSvStatus();
|
||||
EXPECT_TRUE(status.isOk());
|
||||
ASSERT_TRUE(aidl_gnss_cb_->sv_info_list_timestamps_millis_cbq_.size() ==
|
||||
aidl_gnss_cb_->sv_info_list_cbq_.size());
|
||||
long lastElapsedRealtimeMillis = 0;
|
||||
for (int i = 0; i < numMeasurementEvents; i++) {
|
||||
long timeStamp;
|
||||
|
||||
@@ -54,7 +54,6 @@ cc_test {
|
||||
"libgui",
|
||||
"libhidlbase",
|
||||
"libprocessgroup",
|
||||
"libtinyxml2",
|
||||
"android.hardware.graphics.mapper@2.0",
|
||||
"android.hardware.graphics.mapper@2.1",
|
||||
"android.hardware.graphics.mapper@3.0",
|
||||
|
||||
@@ -31,12 +31,6 @@
|
||||
#include "RenderEngineVts.h"
|
||||
#include "VtsComposerClient.h"
|
||||
|
||||
// tinyxml2 does implicit conversions >:(
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
#include <tinyxml2.h>
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
namespace aidl::android::hardware::graphics::composer3::vts {
|
||||
namespace {
|
||||
|
||||
@@ -129,76 +123,6 @@ class GraphicsCompositionTestBase : public ::testing::Test {
|
||||
return {false, graphicBuffer};
|
||||
}
|
||||
|
||||
uint64_t getStableDisplayId(int64_t display) {
|
||||
const auto& [status, identification] =
|
||||
mComposerClient->getDisplayIdentificationData(display);
|
||||
EXPECT_TRUE(status.isOk());
|
||||
|
||||
if (const auto info = ::android::parseDisplayIdentificationData(
|
||||
static_cast<uint8_t>(identification.port), identification.data)) {
|
||||
return info->id.value;
|
||||
}
|
||||
|
||||
return ::android::PhysicalDisplayId::fromPort(static_cast<uint8_t>(identification.port))
|
||||
.value;
|
||||
}
|
||||
|
||||
// Gets the per-display XML config
|
||||
std::unique_ptr<tinyxml2::XMLDocument> getDisplayConfigXml(int64_t display) {
|
||||
std::stringstream pathBuilder;
|
||||
pathBuilder << "/vendor/etc/displayconfig/display_id_" << getStableDisplayId(display)
|
||||
<< ".xml";
|
||||
const std::string path = pathBuilder.str();
|
||||
auto document = std::make_unique<tinyxml2::XMLDocument>();
|
||||
const tinyxml2::XMLError error = document->LoadFile(path.c_str());
|
||||
if (error == tinyxml2::XML_SUCCESS) {
|
||||
return document;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the max display brightness for this display.
|
||||
// If the display config xml does not exist, then assume that the display is not well-configured
|
||||
// enough to provide a display brightness, so return nullopt.
|
||||
std::optional<float> getMaxDisplayBrightnessNits(int64_t display) {
|
||||
const auto document = getDisplayConfigXml(display);
|
||||
if (!document) {
|
||||
// Assume the device doesn't support display brightness
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto root = document->RootElement();
|
||||
if (!root) {
|
||||
// If there's somehow no root element, then this isn't a valid config
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto screenBrightnessMap = root->FirstChildElement("screenBrightnessMap");
|
||||
if (!screenBrightnessMap) {
|
||||
// A valid display config must have a screen brightness map
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto point = screenBrightnessMap->FirstChildElement("point");
|
||||
float maxNits = -1.f;
|
||||
while (point != nullptr) {
|
||||
const auto nits = point->FirstChildElement("nits");
|
||||
if (nits) {
|
||||
maxNits = std::max(maxNits, nits->FloatText(-1.f));
|
||||
}
|
||||
point = point->NextSiblingElement("point");
|
||||
}
|
||||
|
||||
if (maxNits < 0.f) {
|
||||
// If we got here, then there were no point elements containing a nit value, so this
|
||||
// config isn't valid
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return maxNits;
|
||||
}
|
||||
|
||||
void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
|
||||
for (const auto& layer : layers) {
|
||||
layer->write(*mWriter);
|
||||
@@ -957,32 +881,6 @@ TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
|
||||
}
|
||||
|
||||
TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
|
||||
const auto& [status, capabilities] =
|
||||
mComposerClient->getDisplayCapabilities(getPrimaryDisplayId());
|
||||
ASSERT_TRUE(status.isOk());
|
||||
|
||||
const bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(),
|
||||
DisplayCapability::BRIGHTNESS) != capabilities.end();
|
||||
|
||||
if (!brightnessSupport) {
|
||||
GTEST_SUCCEED() << "Cannot verify dimming behavior without brightness support";
|
||||
return;
|
||||
}
|
||||
|
||||
const std::optional<float> maxBrightnessNitsOptional =
|
||||
getMaxDisplayBrightnessNits(getPrimaryDisplayId());
|
||||
|
||||
ASSERT_TRUE(maxBrightnessNitsOptional.has_value());
|
||||
|
||||
const float maxBrightnessNits = *maxBrightnessNitsOptional;
|
||||
|
||||
// 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, maxBrightnessNits);
|
||||
execute();
|
||||
ASSERT_TRUE(mReader.takeErrors().empty());
|
||||
|
||||
for (ColorMode mode : mTestColorModes) {
|
||||
EXPECT_TRUE(mComposerClient
|
||||
->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC)
|
||||
@@ -999,11 +897,14 @@ TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
|
||||
const common::Rect redRect = {0, 0, getDisplayWidth(), getDisplayHeight() / 2};
|
||||
const common::Rect dimmerRedRect = {0, getDisplayHeight() / 2, getDisplayWidth(),
|
||||
getDisplayHeight()};
|
||||
|
||||
static constexpr float kMaxBrightnessNits = 300.f;
|
||||
|
||||
const auto redLayer =
|
||||
std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId());
|
||||
redLayer->setColor(RED);
|
||||
redLayer->setDisplayFrame(redRect);
|
||||
redLayer->setWhitePointNits(maxBrightnessNits);
|
||||
redLayer->setWhitePointNits(kMaxBrightnessNits);
|
||||
redLayer->setBrightness(1.f);
|
||||
|
||||
const auto dimmerRedLayer =
|
||||
@@ -1013,7 +914,7 @@ TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
|
||||
// Intentionally use a small dimming ratio as some implementations may be more likely to
|
||||
// kick into GPU composition to apply dithering when the dimming ratio is high.
|
||||
static constexpr float kDimmingRatio = 0.9f;
|
||||
dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio);
|
||||
dimmerRedLayer->setWhitePointNits(kMaxBrightnessNits * kDimmingRatio);
|
||||
dimmerRedLayer->setBrightness(kDimmingRatio);
|
||||
|
||||
const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
|
||||
|
||||
@@ -214,7 +214,8 @@ TEST_P(RadioDataTest, setupDataCall_osAppId) {
|
||||
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_data->rspInfo.error,
|
||||
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
|
||||
RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
|
||||
if (radioRsp_data->setupDataCallResult.trafficDescriptors.size() <= 0) {
|
||||
if (radioRsp_data->setupDataCallResult.trafficDescriptors.size() <= 0 ||
|
||||
!radioRsp_data->setupDataCallResult.trafficDescriptors[0].osAppId.has_value()) {
|
||||
return;
|
||||
}
|
||||
EXPECT_EQ(trafficDescriptor.osAppId.value().osAppId,
|
||||
|
||||
@@ -119,7 +119,7 @@ TEST_P(RadioNetworkTest, setGetAllowedNetworkTypesBitmap) {
|
||||
RadioError::REQUEST_NOT_SUPPORTED, RadioError::NO_RESOURCES}));
|
||||
if (radioRsp_network->rspInfo.error == RadioError::NONE) {
|
||||
// verify we get the value we set
|
||||
ASSERT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap);
|
||||
EXPECT_EQ(radioRsp_network->networkTypeBitmapResponse, allowedNetworkTypesBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -887,6 +887,15 @@ bool convertLegacyLinkLayerRadioStatsToAidl(
|
||||
return true;
|
||||
}
|
||||
|
||||
StaLinkLayerLinkStats::StaLinkState convertLegacyMlLinkStateToAidl(wifi_link_state state) {
|
||||
if (state == wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE) {
|
||||
return StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE;
|
||||
} else if (state == wifi_link_state::WIFI_LINK_STATE_IN_USE) {
|
||||
return StaLinkLayerLinkStats::StaLinkState::IN_USE;
|
||||
}
|
||||
return StaLinkLayerLinkStats::StaLinkState::UNKNOWN;
|
||||
}
|
||||
|
||||
bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& legacy_ml_stats,
|
||||
StaLinkLayerStats* aidl_stats) {
|
||||
if (!aidl_stats) {
|
||||
@@ -898,6 +907,7 @@ bool convertLegacyLinkLayerMlStatsToAidl(const legacy_hal::LinkLayerMlStats& leg
|
||||
for (const auto& link : legacy_ml_stats.links) {
|
||||
StaLinkLayerLinkStats linkStats = {};
|
||||
linkStats.linkId = link.stat.link_id;
|
||||
linkStats.state = convertLegacyMlLinkStateToAidl(link.stat.state);
|
||||
linkStats.radioId = link.stat.radio;
|
||||
linkStats.frequencyMhz = link.stat.frequency;
|
||||
linkStats.beaconRx = link.stat.beacon_rx;
|
||||
|
||||
@@ -123,6 +123,9 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) {
|
||||
// Add two radio stats
|
||||
legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
|
||||
legacy_ml_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
|
||||
wifi_link_state states[sizeof(wifi_link_state)] = {wifi_link_state::WIFI_LINK_STATE_UNKNOWN,
|
||||
wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE,
|
||||
wifi_link_state::WIFI_LINK_STATE_IN_USE};
|
||||
// Add two links.
|
||||
legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
|
||||
legacy_ml_stats.links.push_back(legacy_hal::LinkStats{});
|
||||
@@ -133,6 +136,7 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) {
|
||||
link.stat.beacon_rx = rand();
|
||||
// MLO link id: 0 - 15
|
||||
link.stat.link_id = rand() % 16;
|
||||
link.stat.state = states[rand() % sizeof(states)];
|
||||
// Maximum number of radios is limited to 3 for testing.
|
||||
link.stat.radio = rand() % 4;
|
||||
link.stat.frequency = rand();
|
||||
@@ -241,6 +245,18 @@ TEST_F(AidlStructUtilTest, canConvertLegacyLinkLayerMlStatsToAidl) {
|
||||
int l = 0;
|
||||
for (legacy_hal::LinkStats& link : legacy_ml_stats.links) {
|
||||
EXPECT_EQ(link.stat.link_id, (uint8_t)converted.iface.links[l].linkId);
|
||||
StaLinkLayerLinkStats::StaLinkState expectedState;
|
||||
switch (link.stat.state) {
|
||||
case wifi_link_state::WIFI_LINK_STATE_NOT_IN_USE:
|
||||
expectedState = StaLinkLayerLinkStats::StaLinkState::NOT_IN_USE;
|
||||
break;
|
||||
case wifi_link_state::WIFI_LINK_STATE_IN_USE:
|
||||
expectedState = StaLinkLayerLinkStats::StaLinkState::IN_USE;
|
||||
break;
|
||||
default:
|
||||
expectedState = StaLinkLayerLinkStats::StaLinkState::UNKNOWN;
|
||||
}
|
||||
EXPECT_EQ(expectedState, converted.iface.links[l].state);
|
||||
EXPECT_EQ(link.stat.radio, converted.iface.links[l].radioId);
|
||||
EXPECT_EQ(link.stat.frequency, (uint32_t)converted.iface.links[l].frequencyMhz);
|
||||
EXPECT_EQ(link.stat.beacon_rx, (uint32_t)converted.iface.links[l].beaconRx);
|
||||
|
||||
@@ -1452,14 +1452,24 @@ WifiChip::getSupportedRadioCombinationsInternal() {
|
||||
if (legacy_status != legacy_hal::WIFI_SUCCESS) {
|
||||
LOG(ERROR) << "Failed to get SupportedRadioCombinations matrix from legacy HAL: "
|
||||
<< legacyErrorToString(legacy_status);
|
||||
if (legacy_matrix != nullptr) {
|
||||
free(legacy_matrix);
|
||||
}
|
||||
return {aidl_combinations, createWifiStatusFromLegacyError(legacy_status)};
|
||||
}
|
||||
|
||||
if (!aidl_struct_util::convertLegacyRadioCombinationsMatrixToAidl(legacy_matrix,
|
||||
&aidl_combinations)) {
|
||||
LOG(ERROR) << "Failed convertLegacyRadioCombinationsMatrixToAidl() ";
|
||||
if (legacy_matrix != nullptr) {
|
||||
free(legacy_matrix);
|
||||
}
|
||||
return {aidl_combinations, createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
|
||||
}
|
||||
|
||||
if (legacy_matrix != nullptr) {
|
||||
free(legacy_matrix);
|
||||
}
|
||||
return {aidl_combinations, ndk::ScopedAStatus::ok()};
|
||||
}
|
||||
|
||||
|
||||
@@ -76,18 +76,10 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
|
||||
|
||||
void TearDown() override { stopWifiService(getInstanceName()); }
|
||||
|
||||
// Used as a mechanism to inform the test about data/event callbacks.
|
||||
inline void notify() {
|
||||
std::unique_lock<std::mutex> lock(mtx_);
|
||||
count_++;
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
enum CallbackType {
|
||||
INVALID = -2,
|
||||
ANY_CALLBACK = -1,
|
||||
INVALID = 0,
|
||||
|
||||
NOTIFY_CAPABILITIES_RESPONSE = 0,
|
||||
NOTIFY_CAPABILITIES_RESPONSE = 1,
|
||||
NOTIFY_ENABLE_RESPONSE,
|
||||
NOTIFY_CONFIG_RESPONSE,
|
||||
NOTIFY_DISABLE_RESPONSE,
|
||||
@@ -128,310 +120,278 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
|
||||
EVENT_SUSPENSION_MODE_CHANGE,
|
||||
};
|
||||
|
||||
// Used as a mechanism to inform the test about data/event callbacks.
|
||||
inline void notify(CallbackType callbackType) {
|
||||
std::unique_lock<std::mutex> lock(mtx_);
|
||||
callback_event_bitmap_ |= (UINT64_C(0x1) << callbackType);
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
// Test code calls this function to wait for data/event callback.
|
||||
// Must set callbackType = INVALID before calling this function.
|
||||
// Must set callback_event_bitmap_ to 0 before calling this function.
|
||||
inline std::cv_status wait(CallbackType waitForCallbackType) {
|
||||
std::unique_lock<std::mutex> lock(mtx_);
|
||||
EXPECT_NE(INVALID, waitForCallbackType);
|
||||
|
||||
std::cv_status status = std::cv_status::no_timeout;
|
||||
auto now = std::chrono::system_clock::now();
|
||||
while (count_ == 0) {
|
||||
while (!(receivedCallback(waitForCallbackType))) {
|
||||
status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
|
||||
if (status == std::cv_status::timeout) return status;
|
||||
if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID &&
|
||||
callback_type_ != waitForCallbackType) {
|
||||
count_--;
|
||||
}
|
||||
}
|
||||
count_--;
|
||||
return status;
|
||||
}
|
||||
|
||||
inline bool receivedCallback(CallbackType waitForCallbackType) {
|
||||
return callback_event_bitmap_ & (UINT64_C(0x1) << waitForCallbackType);
|
||||
}
|
||||
|
||||
class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback {
|
||||
public:
|
||||
WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){};
|
||||
|
||||
::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override {
|
||||
parent_.callback_type_ = EVENT_CLUSTER_EVENT;
|
||||
parent_.nan_cluster_event_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_CLUSTER_EVENT);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override {
|
||||
parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM;
|
||||
parent_.nan_data_path_confirm_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_DATA_PATH_CONFIRM);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override {
|
||||
parent_.callback_type_ = EVENT_DATA_PATH_REQUEST;
|
||||
parent_.nan_data_path_request_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_DATA_PATH_REQUEST);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventDataPathScheduleUpdate(
|
||||
const NanDataPathScheduleUpdateInd& event) override {
|
||||
parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE;
|
||||
parent_.nan_data_path_schedule_update_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_DATA_PATH_SCHEDULE_UPDATE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override {
|
||||
parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED;
|
||||
parent_.ndp_instance_id_ = ndpInstanceId;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_DATA_PATH_TERMINATED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override {
|
||||
parent_.callback_type_ = EVENT_DISABLED;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_DISABLED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override {
|
||||
parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED;
|
||||
parent_.nan_followup_received_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_FOLLOWUP_RECEIVED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override {
|
||||
parent_.callback_type_ = EVENT_MATCH;
|
||||
parent_.nan_match_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_MATCH);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override {
|
||||
parent_.callback_type_ = EVENT_MATCH_EXPIRED;
|
||||
parent_.session_id_ = discoverySessionId;
|
||||
parent_.peer_id_ = peerId;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_MATCH_EXPIRED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = EVENT_PUBLISH_TERMINATED;
|
||||
parent_.session_id_ = sessionId;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_PUBLISH_TERMINATED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED;
|
||||
parent_.session_id_ = sessionId;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_SUBSCRIBE_TERMINATED);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_TRANSMIT_FOLLOWUP);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override {
|
||||
parent_.callback_type_ = EVENT_PAIRING_CONFIRM;
|
||||
parent_.nan_pairing_confirm_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_PAIRING_CONFIRM);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override {
|
||||
parent_.callback_type_ = EVENT_PAIRING_REQUEST;
|
||||
parent_.nan_pairing_request_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_PAIRING_REQUEST);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventBootstrappingConfirm(
|
||||
const NanBootstrappingConfirmInd& event) override {
|
||||
parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM;
|
||||
parent_.nan_bootstrapping_confirm_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_BOOTSTRAPPING_CONFIRM);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventBootstrappingRequest(
|
||||
const NanBootstrappingRequestInd& event) override {
|
||||
parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST;
|
||||
parent_.nan_bootstrapping_request_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_BOOTSTRAPPING_REQUEST);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus eventSuspensionModeChanged(
|
||||
const NanSuspensionModeChangeInd& event) override {
|
||||
parent_.callback_type_ = EVENT_SUSPENSION_MODE_CHANGE;
|
||||
parent_.nan_suspension_mode_change_ind_ = event;
|
||||
parent_.notify();
|
||||
parent_.notify(EVENT_SUSPENSION_MODE_CHANGE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyCapabilitiesResponse(
|
||||
char16_t id, const NanStatus& status,
|
||||
const NanCapabilities& capabilities) override {
|
||||
parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.capabilities_ = capabilities;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_CAPABILITIES_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_CONFIG_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_CREATE_DATA_INTERFACE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_DELETE_DATA_INTERFACE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_DISABLE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_ENABLE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status,
|
||||
int32_t ndpInstanceId) override {
|
||||
parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.ndp_instance_id_ = ndpInstanceId;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_INITIATE_DATA_PATH_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse(
|
||||
char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status,
|
||||
int8_t sessionId) override {
|
||||
parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.session_id_ = sessionId;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_START_PUBLISH_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status,
|
||||
int8_t sessionId) override {
|
||||
parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.session_id_ = sessionId;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_START_SUBSCRIBE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_STOP_PUBLISH_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_STOP_SUBSCRIBE_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_TERMINATE_DATA_PATH_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifySuspendResponse(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_SUSPEND_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_SUSPEND_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyResumeResponse(char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_RESUME_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_RESUME_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status,
|
||||
int32_t pairingInstanceId) override {
|
||||
parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.pairing_instance_id_ = pairingInstanceId;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_INITIATE_PAIRING_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse(
|
||||
char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyInitiateBootstrappingResponse(
|
||||
char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override {
|
||||
parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse(
|
||||
char16_t id, const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus notifyTerminatePairingResponse(char16_t id,
|
||||
const NanStatus& status) override {
|
||||
parent_.callback_type_ = NOTIFY_TERMINATE_PAIRING_RESPONSE;
|
||||
parent_.id_ = id;
|
||||
parent_.status_ = status;
|
||||
parent_.notify();
|
||||
parent_.notify(NOTIFY_TERMINATE_PAIRING_RESPONSE);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
@@ -441,7 +401,7 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
|
||||
|
||||
protected:
|
||||
std::shared_ptr<IWifiNanIface> wifi_nan_iface_;
|
||||
CallbackType callback_type_;
|
||||
uint64_t callback_event_bitmap_;
|
||||
uint16_t id_;
|
||||
uint8_t session_id_;
|
||||
uint32_t ndp_instance_id_;
|
||||
@@ -468,7 +428,6 @@ class WifiNanIfaceAidlTest : public testing::TestWithParam<std::string> {
|
||||
// synchronization objects
|
||||
std::mutex mtx_;
|
||||
std::condition_variable cv_;
|
||||
int count_ = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -488,7 +447,7 @@ TEST_P(WifiNanIfaceAidlTest, FailOnIfaceInvalid) {
|
||||
*/
|
||||
TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
|
||||
uint16_t inputCmdId = 10;
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
NanEnableRequest nanEnableRequest = {};
|
||||
NanConfigRequestSupplemental nanConfigRequestSupp = {};
|
||||
auto status =
|
||||
@@ -498,7 +457,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
|
||||
|
||||
// Wait for a callback.
|
||||
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
|
||||
ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
|
||||
ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
|
||||
ASSERT_EQ(id_, inputCmdId);
|
||||
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
|
||||
}
|
||||
@@ -509,7 +468,7 @@ TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
|
||||
*/
|
||||
TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
|
||||
uint16_t inputCmdId = 10;
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
NanConfigRequest nanConfigRequest = {};
|
||||
NanConfigRequestSupplemental nanConfigRequestSupp = {};
|
||||
auto status =
|
||||
@@ -520,7 +479,7 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
|
||||
|
||||
// Wait for a callback.
|
||||
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
|
||||
ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_);
|
||||
ASSERT_TRUE(receivedCallback(NOTIFY_CONFIG_RESPONSE));
|
||||
ASSERT_EQ(id_, inputCmdId);
|
||||
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
|
||||
}
|
||||
@@ -561,12 +520,12 @@ TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidShimArgs) {
|
||||
*/
|
||||
TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) {
|
||||
uint16_t inputCmdId = 10;
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk());
|
||||
|
||||
// Wait for a callback.
|
||||
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
|
||||
ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_);
|
||||
ASSERT_TRUE(receivedCallback(NOTIFY_CAPABILITIES_RESPONSE));
|
||||
ASSERT_EQ(id_, inputCmdId);
|
||||
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
|
||||
|
||||
@@ -654,14 +613,14 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) {
|
||||
nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0;
|
||||
nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false;
|
||||
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp);
|
||||
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
|
||||
ASSERT_TRUE(status.isOk());
|
||||
|
||||
// Wait for a callback.
|
||||
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
|
||||
ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
|
||||
ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
|
||||
ASSERT_EQ(id_, inputCmdId);
|
||||
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
|
||||
}
|
||||
@@ -688,7 +647,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) {
|
||||
|
||||
// Wait for a callback.
|
||||
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
|
||||
ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_);
|
||||
ASSERT_TRUE(receivedCallback(NOTIFY_START_PUBLISH_RESPONSE));
|
||||
ASSERT_EQ(id_, inputCmdId + 1);
|
||||
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
|
||||
}
|
||||
@@ -699,7 +658,7 @@ TEST_P(WifiNanIfaceAidlTest, StartPublishRequest) {
|
||||
*/
|
||||
TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
|
||||
uint16_t inputCmdId = 10;
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {};
|
||||
nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong";
|
||||
auto status = wifi_nan_iface_->respondToDataPathIndicationRequest(
|
||||
@@ -716,7 +675,7 @@ TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
|
||||
*/
|
||||
TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) {
|
||||
uint16_t inputCmdId = 10;
|
||||
callback_type_ = INVALID;
|
||||
callback_event_bitmap_ = 0;
|
||||
NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
|
||||
nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong";
|
||||
auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
#include <VtsCoreUtil.h>
|
||||
@@ -68,6 +69,50 @@ class WifiStaIfaceAidlTest : public testing::TestWithParam<std::string> {
|
||||
|
||||
std::shared_ptr<IWifiStaIface> wifi_sta_iface_;
|
||||
|
||||
// Checks if the MdnsOffloadManagerService is installed.
|
||||
bool isMdnsOffloadServicePresent() {
|
||||
int status =
|
||||
// --query-flags MATCH_SYSTEM_ONLY(1048576) will only return matched service
|
||||
// installed on system or system_ext partition. The MdnsOffloadManagerService should
|
||||
// be installed on system_ext partition.
|
||||
// NOLINTNEXTLINE(cert-env33-c)
|
||||
system("pm query-services --query-flags 1048576"
|
||||
" com.android.tv.mdnsoffloadmanager/"
|
||||
"com.android.tv.mdnsoffloadmanager.MdnsOffloadManagerService"
|
||||
" | egrep -q mdnsoffloadmanager");
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
// Detected panel TV device by using ro.oem.key1 property.
|
||||
// https://docs.partner.android.com/tv/build/platform/props-vars/ro-oem-key1
|
||||
bool isPanelTvDevice() {
|
||||
const std::string oem_key1 = getPropertyString("ro.oem.key1");
|
||||
if (oem_key1.size() < 9) {
|
||||
return false;
|
||||
}
|
||||
if (oem_key1.substr(0, 3) != "ATV") {
|
||||
return false;
|
||||
}
|
||||
const std::string psz_string = oem_key1.substr(6, 3);
|
||||
// If PSZ string contains non digit, then it is not a panel TV device.
|
||||
for (char ch : psz_string) {
|
||||
if (!isdigit(ch)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If PSZ is "000", then it is not a panel TV device.
|
||||
if (psz_string == "000") {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string getPropertyString(const char* property_name) {
|
||||
char property_string_raw_bytes[PROPERTY_VALUE_MAX] = {};
|
||||
int len = property_get(property_name, property_string_raw_bytes, "");
|
||||
return std::string(property_string_raw_bytes, len);
|
||||
}
|
||||
|
||||
private:
|
||||
const char* getInstanceName() { return GetParam().c_str(); }
|
||||
};
|
||||
@@ -99,6 +144,11 @@ TEST_P(WifiStaIfaceAidlTest, GetFeatureSet) {
|
||||
*/
|
||||
// @VsrTest = 5.3.12
|
||||
TEST_P(WifiStaIfaceAidlTest, CheckApfIsSupported) {
|
||||
// Flat panel TV devices that support MDNS offload do not have to implement APF if the WiFi
|
||||
// chipset does not have sufficient RAM to do so.
|
||||
if (isPanelTvDevice() && isMdnsOffloadServicePresent()) {
|
||||
GTEST_SKIP() << "Panel TV supports mDNS offload. It is not required to support APF";
|
||||
}
|
||||
int vendor_api_level = property_get_int32("ro.vendor.api_level", 0);
|
||||
// Before VSR 14, APF support is optional.
|
||||
if (vendor_api_level < __ANDROID_API_U__) {
|
||||
|
||||
@@ -41,10 +41,9 @@ using ::android::hardware::wifi::V1_0::IWifiChip;
|
||||
using ::android::wifi_system::HostapdManager;
|
||||
using ::android::wifi_system::SupplicantManager;
|
||||
|
||||
namespace {
|
||||
// Helper function to initialize the driver and firmware to AP mode
|
||||
// using the vendor HAL HIDL interface.
|
||||
void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
|
||||
void initializeDriverAndFirmware(const std::string& wifi_instance_name) {
|
||||
if (getWifi(wifi_instance_name) != nullptr) {
|
||||
sp<IWifiChip> wifi_chip = getWifiChip(wifi_instance_name);
|
||||
ChipModeId mode_id;
|
||||
@@ -57,21 +56,20 @@ void initilializeDriverAndFirmware(const std::string& wifi_instance_name) {
|
||||
|
||||
// Helper function to deinitialize the driver and firmware
|
||||
// using the vendor HAL HIDL interface.
|
||||
void deInitilializeDriverAndFirmware(const std::string& wifi_instance_name) {
|
||||
void deInitializeDriverAndFirmware(const std::string& wifi_instance_name) {
|
||||
if (getWifi(wifi_instance_name) != nullptr) {
|
||||
stopWifi(wifi_instance_name);
|
||||
} else {
|
||||
LOG(WARNING) << __func__ << ": Vendor HAL not supported";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void stopSupplicantIfNeeded(const std::string& instance_name) {
|
||||
SupplicantManager supplicant_manager;
|
||||
if (supplicant_manager.IsSupplicantRunning()) {
|
||||
LOG(INFO) << "Supplicant is running, stop supplicant first.";
|
||||
ASSERT_TRUE(supplicant_manager.StopSupplicant());
|
||||
deInitilializeDriverAndFirmware(instance_name);
|
||||
deInitializeDriverAndFirmware(instance_name);
|
||||
ASSERT_FALSE(supplicant_manager.IsSupplicantRunning());
|
||||
}
|
||||
}
|
||||
@@ -80,13 +78,13 @@ void stopHostapd(const std::string& instance_name) {
|
||||
HostapdManager hostapd_manager;
|
||||
|
||||
ASSERT_TRUE(hostapd_manager.StopHostapd());
|
||||
deInitilializeDriverAndFirmware(instance_name);
|
||||
deInitializeDriverAndFirmware(instance_name);
|
||||
}
|
||||
|
||||
void startHostapdAndWaitForHidlService(
|
||||
const std::string& wifi_instance_name,
|
||||
const std::string& hostapd_instance_name) {
|
||||
initilializeDriverAndFirmware(wifi_instance_name);
|
||||
initializeDriverAndFirmware(wifi_instance_name);
|
||||
|
||||
HostapdManager hostapd_manager;
|
||||
ASSERT_TRUE(hostapd_manager.StartHostapd());
|
||||
|
||||
@@ -36,5 +36,9 @@ void startHostapdAndWaitForHidlService(
|
||||
|
||||
bool is_1_1(const android::sp<android::hardware::wifi::hostapd::V1_0::IHostapd>&
|
||||
hostapd);
|
||||
// Used to initialize/deinitialize the driver and firmware at the
|
||||
// beginning and end of each test.
|
||||
void initializeDriverAndFirmware(const std::string& wifi_instance_name);
|
||||
void deInitializeDriverAndFirmware(const std::string& wifi_instance_name);
|
||||
|
||||
#endif /* HOSTAPD_HIDL_TEST_UTILS_H */
|
||||
|
||||
@@ -37,6 +37,7 @@ cc_test {
|
||||
"android.hardware.wifi@1.5",
|
||||
"android.hardware.wifi@1.6",
|
||||
"android.hardware.wifi-V1-ndk",
|
||||
"libwifi-system",
|
||||
"libwifi-system-iface",
|
||||
"VtsHalWifiTargetTestUtil",
|
||||
],
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <wifi_hidl_test_utils_1_5.h>
|
||||
#include <wifi_hidl_test_utils_1_6.h>
|
||||
|
||||
#include "hostapd_test_utils.h"
|
||||
#include "wifi_aidl_test_utils.h"
|
||||
|
||||
using aidl::android::hardware::wifi::hostapd::BandMask;
|
||||
@@ -56,10 +57,7 @@ const std::string kInvalidMaxPassphrase =
|
||||
const int kIfaceChannel = 6;
|
||||
const int kIfaceInvalidChannel = 567;
|
||||
const std::vector<uint8_t> kTestZeroMacAddr(6, 0x0);
|
||||
const Ieee80211ReasonCode kTestDisconnectReasonCode =
|
||||
Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
|
||||
const std::string kWifiAidlInstanceNameStr = std::string() + IWifi::descriptor + "/default";
|
||||
const char* kWifiAidlInstanceName = kWifiAidlInstanceNameStr.c_str();
|
||||
const Ieee80211ReasonCode kTestDisconnectReasonCode = Ieee80211ReasonCode::WLAN_REASON_UNSPECIFIED;
|
||||
|
||||
inline BandMask operator|(BandMask a, BandMask b) {
|
||||
return static_cast<BandMask>(static_cast<int32_t>(a) |
|
||||
@@ -70,10 +68,13 @@ inline BandMask operator|(BandMask a, BandMask b) {
|
||||
class HostapdAidl : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
hostapd = IHostapd::fromBinder(ndk::SpAIBinder(
|
||||
AServiceManager_waitForService(GetParam().c_str())));
|
||||
disableHalsAndFramework();
|
||||
initializeHostapdAndVendorHal(GetParam());
|
||||
|
||||
hostapd = getHostapd(GetParam());
|
||||
ASSERT_NE(hostapd, nullptr);
|
||||
EXPECT_TRUE(hostapd->setDebugParams(DebugLevel::EXCESSIVE).isOk());
|
||||
|
||||
isAcsSupport = testing::checkSubstringInCommandOutput(
|
||||
"/system/bin/cmd wifi get-softap-supported-features",
|
||||
"wifi_softap_acs_supported");
|
||||
@@ -81,81 +82,23 @@ class HostapdAidl : public testing::TestWithParam<std::string> {
|
||||
"/system/bin/cmd wifi get-softap-supported-features",
|
||||
"wifi_softap_wpa3_sae_supported");
|
||||
isBridgedSupport = testing::checkSubstringInCommandOutput(
|
||||
"/system/bin/cmd wifi get-softap-supported-features",
|
||||
"wifi_softap_bridged_ap_supported");
|
||||
if (!isAidlServiceAvailable(kWifiAidlInstanceName)) {
|
||||
const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
|
||||
::android::hardware::wifi::V1_0::IWifi::descriptor);
|
||||
EXPECT_NE(0, instances.size());
|
||||
wifiHidlInstanceName = instances[0];
|
||||
}
|
||||
"/system/bin/cmd wifi get-softap-supported-features",
|
||||
"wifi_softap_bridged_ap_supported");
|
||||
}
|
||||
|
||||
virtual void TearDown() override {
|
||||
stopVendorHal();
|
||||
hostapd->terminate();
|
||||
// Wait 3 seconds to allow terminate to complete
|
||||
sleep(3);
|
||||
stopHostapdAndVendorHal();
|
||||
startWifiFramework();
|
||||
}
|
||||
|
||||
std::shared_ptr<IHostapd> hostapd;
|
||||
std::string wifiHidlInstanceName;
|
||||
bool isAcsSupport;
|
||||
bool isWpa3SaeSupport;
|
||||
bool isBridgedSupport;
|
||||
|
||||
void stopVendorHal() {
|
||||
if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
|
||||
// HIDL and AIDL versions of getWifi() take different arguments
|
||||
// i.e. const char* vs string
|
||||
if (getWifi(kWifiAidlInstanceName) != nullptr) {
|
||||
stopWifiService(kWifiAidlInstanceName);
|
||||
}
|
||||
} else {
|
||||
if (getWifi(wifiHidlInstanceName) != nullptr) {
|
||||
stopWifi(wifiHidlInstanceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetName(bool isBridged) {
|
||||
if (isAidlServiceAvailable(kWifiAidlInstanceName)) {
|
||||
return setupApIfaceAndGetNameAidl(isBridged);
|
||||
} else {
|
||||
return setupApIfaceAndGetNameHidl(isBridged);
|
||||
}
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetNameAidl(bool isBridged) {
|
||||
std::shared_ptr<IWifiApIface> wifi_ap_iface;
|
||||
if (isBridged) {
|
||||
wifi_ap_iface = getBridgedWifiApIface(kWifiAidlInstanceName);
|
||||
} else {
|
||||
wifi_ap_iface = getWifiApIface(kWifiAidlInstanceName);
|
||||
}
|
||||
EXPECT_NE(nullptr, wifi_ap_iface.get());
|
||||
|
||||
std::string ap_iface_name;
|
||||
auto status = wifi_ap_iface->getName(&ap_iface_name);
|
||||
EXPECT_TRUE(status.isOk());
|
||||
return ap_iface_name;
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetNameHidl(bool isBridged) {
|
||||
android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface;
|
||||
if (isBridged) {
|
||||
wifi_ap_iface = getBridgedWifiApIface_1_6(wifiHidlInstanceName);
|
||||
} else {
|
||||
wifi_ap_iface = getWifiApIface_1_5(wifiHidlInstanceName);
|
||||
}
|
||||
EXPECT_NE(nullptr, wifi_ap_iface.get());
|
||||
|
||||
const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName);
|
||||
EXPECT_EQ(android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS,
|
||||
status_and_name.first.code);
|
||||
return status_and_name.second;
|
||||
}
|
||||
|
||||
IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
|
||||
IfaceParams iface_params;
|
||||
ChannelParams channelParams;
|
||||
|
||||
80
wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
Normal file
80
wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/wifi/IWifi.h>
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "wifi_aidl_test_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kWifiInstanceNameStr = std::string() + IWifi::descriptor + "/default";
|
||||
const char* kWifiInstanceName = kWifiInstanceNameStr.c_str();
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace HostapdAidlTestUtils {
|
||||
|
||||
bool useAidlService() {
|
||||
return isAidlServiceAvailable(kWifiInstanceName);
|
||||
}
|
||||
|
||||
void startAndConfigureVendorHal() {
|
||||
if (getWifi(kWifiInstanceName) != nullptr) {
|
||||
std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(kWifiInstanceName);
|
||||
int mode_id;
|
||||
EXPECT_TRUE(configureChipToSupportConcurrencyType(wifi_chip, IfaceConcurrencyType::AP,
|
||||
&mode_id));
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to initialize Vendor HAL";
|
||||
}
|
||||
}
|
||||
|
||||
void stopVendorHal() {
|
||||
if (getWifi(kWifiInstanceName) != nullptr) {
|
||||
stopWifiService(kWifiInstanceName);
|
||||
} else {
|
||||
LOG(ERROR) << "Unable to stop Vendor HAL";
|
||||
}
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetName(bool isBridged) {
|
||||
std::shared_ptr<IWifiApIface> wifi_ap_iface;
|
||||
if (isBridged) {
|
||||
wifi_ap_iface = getBridgedWifiApIface(kWifiInstanceName);
|
||||
} else {
|
||||
wifi_ap_iface = getWifiApIface(kWifiInstanceName);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(wifi_ap_iface.get() != nullptr);
|
||||
if (!wifi_ap_iface.get()) {
|
||||
LOG(ERROR) << "Unable to create iface. isBridged=" << isBridged;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string ap_iface_name;
|
||||
auto status = wifi_ap_iface->getName(&ap_iface_name);
|
||||
EXPECT_TRUE(status.isOk());
|
||||
if (!status.isOk()) {
|
||||
LOG(ERROR) << "Unable to retrieve iface name. isBridged=" << isBridged;
|
||||
return "";
|
||||
}
|
||||
return ap_iface_name;
|
||||
}
|
||||
|
||||
} // namespace HostapdAidlTestUtils
|
||||
71
wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h
Normal file
71
wifi/hostapd/aidl/vts/functional/hostapd_legacy_test_utils.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "hostapd_hidl_test_utils.h"
|
||||
#include "wifi_hidl_test_utils.h"
|
||||
|
||||
using ::android::hardware::wifi::V1_0::WifiStatus;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string getWifiInstanceName() {
|
||||
const std::vector<std::string> instances = android::hardware::getAllHalInstanceNames(
|
||||
::android::hardware::wifi::V1_0::IWifi::descriptor);
|
||||
EXPECT_NE(0, instances.size());
|
||||
return instances.size() != 0 ? instances[0] : "";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace HostapdLegacyTestUtils {
|
||||
|
||||
void startAndConfigureVendorHal() {
|
||||
initializeDriverAndFirmware(getWifiInstanceName());
|
||||
}
|
||||
|
||||
void stopVendorHal() {
|
||||
deInitializeDriverAndFirmware(getWifiInstanceName());
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetName(bool isBridged) {
|
||||
android::sp<::android::hardware::wifi::V1_0::IWifiApIface> wifi_ap_iface;
|
||||
if (isBridged) {
|
||||
wifi_ap_iface = getBridgedWifiApIface_1_6(getWifiInstanceName());
|
||||
} else {
|
||||
wifi_ap_iface = getWifiApIface_1_5(getWifiInstanceName());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(wifi_ap_iface.get() != nullptr);
|
||||
if (!wifi_ap_iface.get()) {
|
||||
LOG(ERROR) << "Unable to create iface. isBridged=" << isBridged;
|
||||
return "";
|
||||
}
|
||||
|
||||
const auto& status_and_name = HIDL_INVOKE(wifi_ap_iface, getName);
|
||||
EXPECT_TRUE(status_and_name.first.code ==
|
||||
android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS);
|
||||
if (status_and_name.first.code != android::hardware::wifi::V1_0::WifiStatusCode::SUCCESS) {
|
||||
LOG(ERROR) << "Unable to retrieve iface name. isBridged=" << isBridged;
|
||||
return "";
|
||||
}
|
||||
return status_and_name.second;
|
||||
}
|
||||
|
||||
} // namespace HostapdLegacyTestUtils
|
||||
122
wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h
Normal file
122
wifi/hostapd/aidl/vts/functional/hostapd_test_utils.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/wifi/hostapd/BnHostapd.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <wifi_system/hostapd_manager.h>
|
||||
#include <wifi_system/supplicant_manager.h>
|
||||
|
||||
#include "hostapd_aidl_test_utils.h"
|
||||
#include "hostapd_legacy_test_utils.h"
|
||||
|
||||
using aidl::android::hardware::wifi::hostapd::IHostapd;
|
||||
using android::wifi_system::HostapdManager;
|
||||
using android::wifi_system::SupplicantManager;
|
||||
|
||||
namespace {
|
||||
|
||||
void startAndConfigureVendorHal() {
|
||||
if (HostapdAidlTestUtils::useAidlService()) {
|
||||
HostapdAidlTestUtils::startAndConfigureVendorHal();
|
||||
} else {
|
||||
HostapdLegacyTestUtils::startAndConfigureVendorHal();
|
||||
}
|
||||
}
|
||||
|
||||
void stopVendorHal() {
|
||||
if (HostapdAidlTestUtils::useAidlService()) {
|
||||
HostapdAidlTestUtils::stopVendorHal();
|
||||
} else {
|
||||
HostapdLegacyTestUtils::stopVendorHal();
|
||||
}
|
||||
}
|
||||
|
||||
void stopHostapd() {
|
||||
HostapdManager hostapd_manager;
|
||||
ASSERT_TRUE(hostapd_manager.StopHostapd());
|
||||
}
|
||||
|
||||
void waitForSupplicantState(bool enable) {
|
||||
SupplicantManager supplicant_manager;
|
||||
int count = 50; // wait at most 5 seconds
|
||||
while (count-- > 0) {
|
||||
if (supplicant_manager.IsSupplicantRunning() == enable) {
|
||||
return;
|
||||
}
|
||||
usleep(100000); // 100 ms
|
||||
}
|
||||
LOG(ERROR) << "Unable to " << (enable ? "start" : "stop") << " supplicant";
|
||||
}
|
||||
|
||||
void toggleWifiFrameworkAndScan(bool enable) {
|
||||
if (enable) {
|
||||
std::system("svc wifi enable");
|
||||
std::system("cmd wifi set-scan-always-available enabled");
|
||||
waitForSupplicantState(true);
|
||||
} else {
|
||||
std::system("svc wifi disable");
|
||||
std::system("cmd wifi set-scan-always-available disabled");
|
||||
waitForSupplicantState(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<IHostapd> getHostapd(const std::string& hostapd_instance_name) {
|
||||
return IHostapd::fromBinder(
|
||||
ndk::SpAIBinder(AServiceManager_waitForService(hostapd_instance_name.c_str())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the Wifi framework, hostapd, and vendor HAL.
|
||||
*
|
||||
* Note: The framework should be disabled to avoid having
|
||||
* any other clients to the HALs during testing.
|
||||
*/
|
||||
void disableHalsAndFramework() {
|
||||
toggleWifiFrameworkAndScan(false);
|
||||
stopHostapd();
|
||||
stopVendorHal();
|
||||
|
||||
// Wait for the services to stop.
|
||||
sleep(3);
|
||||
}
|
||||
|
||||
void initializeHostapdAndVendorHal(const std::string& hostapd_instance_name) {
|
||||
startAndConfigureVendorHal();
|
||||
HostapdManager hostapd_manager;
|
||||
ASSERT_TRUE(hostapd_manager.StartHostapd());
|
||||
getHostapd(hostapd_instance_name);
|
||||
}
|
||||
|
||||
void stopHostapdAndVendorHal() {
|
||||
stopHostapd();
|
||||
stopVendorHal();
|
||||
}
|
||||
|
||||
void startWifiFramework() {
|
||||
toggleWifiFrameworkAndScan(true);
|
||||
}
|
||||
|
||||
std::string setupApIfaceAndGetName(bool isBridged) {
|
||||
if (HostapdAidlTestUtils::useAidlService()) {
|
||||
return HostapdAidlTestUtils::setupApIfaceAndGetName(isBridged);
|
||||
} else {
|
||||
return HostapdLegacyTestUtils::setupApIfaceAndGetName(isBridged);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user