diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl index 8addab7b5f..aa1a86f3aa 100644 --- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl +++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl @@ -55,6 +55,9 @@ union HapticGenerator { parcelable HapticScale { int id; android.hardware.audio.effect.HapticGenerator.VibratorScale scale = android.hardware.audio.effect.HapticGenerator.VibratorScale.MUTE; + float scaleFactor = (-1.0f) /* -1.000000f */; + float adaptiveScaleFactor = (-1.0f) /* -1.000000f */; + const float UNDEFINED_SCALE_FACTOR = (-1.0f) /* -1.000000f */; } @VintfStability parcelable VibratorInformation { diff --git a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl index 3cc5acb48c..f882d63ee2 100644 --- a/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl +++ b/audio/aidl/android/hardware/audio/effect/HapticGenerator.aidl @@ -55,14 +55,52 @@ union HapticGenerator { @VintfStability parcelable HapticScale { + /** + * Representation of undefined scale factor, applied by default for backwards compatibility. + */ + const float UNDEFINED_SCALE_FACTOR = -1.0f; + /** * Audio track ID. */ int id; + /** * Haptic intensity. + * + * This represents haptics scale as fixed levels defined by VibrationScale. If the field + * scaleFactor is defined then this will be ignored in favor of scaleFactor, otherwise this + * will be used to define the intensity for the haptics. */ VibratorScale scale = VibratorScale.MUTE; + + /** + * Haptic scale factor. + * + * This is a continuous scale representation of VibratorScale, allowing flexible number of + * scale levels. If this field is defined then it will be used to define the intensity of + * the haptics, instead of the old VibratorScale field. If this field is undefined then the + * old VibratorScale field will be used. + * + * The value zero represents the same as VibratorScale.MUTE and the value one represents + * VibratorScale.NONE. Values in (0,1) should scale down, and values > 1 should scale up + * within hardware bounds. Negative values will be ignored. + */ + float scaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR + + /** + * Haptic adaptive scale factor. + * + * This is an additional scale value that should be applied on top of the vibrator scale to + * adapt to the device current state. This should be applied to linearly scale the haptic + * data after scale/scaleFactor is applied. + * + * The value zero mutes the haptics, even if the scale/scaleFactor are not set to MUTE/zero. + * The value one will not scale the haptics, and can be used as a constant for no-op. + * Values in (0,1) should scale down. Values > 1 should scale up within hardware bounds. + * Negative values will be ignored. + */ + float adaptiveScaleFactor = -1.0f; // UNDEFINED_SCALE_FACTOR } /** diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp index cbd42c0610..85d400e586 100644 --- a/audio/aidl/vts/Android.bp +++ b/audio/aidl/vts/Android.bp @@ -136,6 +136,9 @@ cc_test { name: "VtsHalHapticGeneratorTargetTest", defaults: ["VtsHalAudioEffectTargetTestDefaults"], srcs: ["VtsHalHapticGeneratorTargetTest.cpp"], + shared_libs: [ + "libaudioutils", + ], } cc_test { diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h index d71697520b..e073ece73a 100644 --- a/audio/aidl/vts/EffectHelper.h +++ b/audio/aidl/vts/EffectHelper.h @@ -479,6 +479,17 @@ class EffectHelper { mOutputSamples = common.output.frameCount * mOutputFrameSize / sizeof(float); } + void generateInput(std::vector& input, float inputFrequency, float samplingFrequency, + size_t inputSize = 0) { + if (inputSize == 0 || inputSize > input.size()) { + inputSize = input.size(); + } + + for (size_t i = 0; i < inputSize; i++) { + input[i] = sin(2 * M_PI * inputFrequency * i / samplingFrequency); + } + } + bool mIsSpatializer; Descriptor mDescriptor; size_t mInputFrameSize, mOutputFrameSize; diff --git a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp index 2b6dc3d412..2802bf978f 100644 --- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp +++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp @@ -21,11 +21,13 @@ #define LOG_TAG "VtsHalHapticGeneratorTargetTest" #include #include +#include #include "EffectHelper.h" using namespace android; +using aidl::android::hardware::audio::common::getChannelCount; using aidl::android::hardware::audio::effect::Descriptor; using aidl::android::hardware::audio::effect::getEffectTypeUuidHapticGenerator; using aidl::android::hardware::audio::effect::HapticGenerator; @@ -34,406 +36,412 @@ using aidl::android::hardware::audio::effect::IFactory; using aidl::android::hardware::audio::effect::Parameter; using android::hardware::audio::common::testing::detail::TestExecutionTracer; -/** - * Here we focus on specific parameter checking, general IEffect interfaces testing performed in - * VtsAudioEffectTargetTest. - */ -enum ParamName { - PARAM_INSTANCE_NAME, - PARAM_HAPTIC_SCALE_ID, - PARAM_HAPTIC_SCALE_VIBRATOR_SCALE, - PARAM_VIBRATION_INFORMATION_RESONANT_FREQUENCY, - PARAM_VIBRATION_INFORMATION_Q_FACTOR, - PARAM_VIBRATION_INFORMATION_MAX_AMPLITUDE, -}; -using HapticGeneratorParamTestParam = - std::tuple, Descriptor>, int, - HapticGenerator::VibratorScale, float, float, float>; - -/* - * Testing parameter range, assuming the parameter supported by effect is in this range. - * Parameter should be within the valid range defined in the documentation, - * for any supported value test expects EX_NONE from IEffect.setParameter(), - * otherwise expect EX_ILLEGAL_ARGUMENT. - */ - -// TODO : Update the test values once range/capability is updated by implementation const int MIN_ID = std::numeric_limits::min(); const int MAX_ID = std::numeric_limits::max(); const float MIN_FLOAT = std::numeric_limits::min(); const float MAX_FLOAT = std::numeric_limits::max(); -const std::vector kHapticScaleIdValues = {MIN_ID, 0, MAX_ID}; -const std::vector kVibratorScaleValues = { +std::vector kScaleValues = { ndk::enum_range().begin(), ndk::enum_range().end()}; +const std::vector kScaleFactorValues = {HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, + 0.0f, 0.5f, 1.0f, MAX_FLOAT}; +const std::vector kAdaptiveScaleFactorValues = { + HapticGenerator::HapticScale::UNDEFINED_SCALE_FACTOR, 0.0f, 0.5f, 1.0f, MAX_FLOAT}; + const std::vector kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT}; const std::vector kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT}; const std::vector kMaxAmplitude = {MIN_FLOAT, 100, MAX_FLOAT}; -class HapticGeneratorParamTest : public ::testing::TestWithParam, - public EffectHelper { +constexpr int HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION = 3; + +static const std::vector kHapticOutputLayouts = { + AudioChannelLayout::LAYOUT_MONO_HAPTIC_A, AudioChannelLayout::LAYOUT_MONO_HAPTIC_AB, + AudioChannelLayout::LAYOUT_STEREO_HAPTIC_A, AudioChannelLayout::LAYOUT_STEREO_HAPTIC_AB}; + +class HapticGeneratorHelper : public EffectHelper { public: - HapticGeneratorParamTest() - : mParamHapticScaleId(std::get(GetParam())), - mParamVibratorScale(std::get(GetParam())), - mParamResonantFrequency( - std::get(GetParam())), - mParamQFactor(std::get(GetParam())), - mParamMaxAmplitude(std::get(GetParam())) { - std::tie(mFactory, mDescriptor) = std::get(GetParam()); - } - void SetUp() override { + void SetUpHapticGenerator(int32_t chMask = AudioChannelLayout::CHANNEL_HAPTIC_A) { ASSERT_NE(nullptr, mFactory); ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); + EXPECT_STATUS(EX_NONE, mEffect->getInterfaceVersion(&mEffectInterfaceVersion)); + + AudioChannelLayout layout = + AudioChannelLayout::make(chMask); Parameter::Common common = createParamCommon( - 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, - kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); - IEffect::OpenEffectReturn ret; + 0 /* session */, 1 /* ioHandle */, kSamplingFrequency /* iSampleRate */, + kSamplingFrequency /* oSampleRate */, kFrameCount /* iFrameCount */, + kFrameCount /* oFrameCount */, layout, layout); ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE)); ASSERT_NE(nullptr, mEffect); } - void TearDown() override { + void TearDownHapticGenerator() { ASSERT_NO_FATAL_FAILURE(close(mEffect)); ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); + ret = IEffect::OpenEffectReturn{}; } - static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; + Parameter createScaleParam(const std::vector& hapticScales) { + return Parameter::make( + Parameter::Specific::make( + HapticGenerator::make(hapticScales))); + } + + Parameter createVibratorParam(HapticGenerator::VibratorInformation vibrationInfo) { + return Parameter::make( + Parameter::Specific::make( + HapticGenerator::make(vibrationInfo))); + } + + void setAndVerifyParameter(Parameter hapticParameter, HapticGenerator::Tag tag, + binder_exception_t expected = EX_NONE) { + EXPECT_STATUS(expected, mEffect->setParameter(hapticParameter)) + << hapticParameter.toString(); + if (expected == EX_NONE) { + // get parameter + Parameter getParam; + auto second = Parameter::Id::make( + HapticGenerator::Id::make( + HapticGenerator::Tag(tag))); + // If the set is successful, get param should match + EXPECT_STATUS(expected, mEffect->getParameter(second, &getParam)); + EXPECT_EQ(hapticParameter, getParam) << "\nexpectedParam:" << hapticParameter.toString() + << "\ngetParam:" << getParam.toString(); + } + } + + HapticGenerator::VibratorInformation createVibratorInfo(float resonantFrequency, float qFactor, + float amplitude) { + return HapticGenerator::VibratorInformation(resonantFrequency, qFactor, amplitude); + } + + static const long kFrameCount = 10000; + static constexpr int kSamplingFrequency = 44100; + static constexpr int kDefaultScaleID = 0; + static constexpr float kDefaultMaxAmp = 1; + static constexpr float kDefaultResonantFrequency = 150; + static constexpr float kDefaultQfactor = 8; + static constexpr HapticGenerator::VibratorScale kDefaultScale = + HapticGenerator::VibratorScale::NONE; std::shared_ptr mFactory; std::shared_ptr mEffect; - Descriptor mDescriptor; - int mParamHapticScaleId = 0; - HapticGenerator::VibratorScale mParamVibratorScale = HapticGenerator::VibratorScale::MUTE; - float mParamResonantFrequency = 0; - float mParamQFactor = 0; - float mParamMaxAmplitude = 0; + IEffect::OpenEffectReturn ret; + Parameter mHapticSpecificParameter; + Parameter::Id mHapticIdParameter; + int mEffectInterfaceVersion; +}; - void SetAndGetHapticGeneratorParameters() { - for (auto& it : mTags) { - auto& tag = std::get(it); - auto& setHg = std::get(it); +/** + *Tests do the following: + * -Testing parameter range supported by the effect. + * -For any supported value test expects EX_NONE from IEffect.setParameter(), + * otherwise expect EX_ILLEGAL_ARGUMENT. + * -Validating the effect by comparing the output energies of the supported parameters. + **/ - // set parameter - Parameter expectParam; - Parameter::Specific specific; - specific.set(setHg); - expectParam.set(specific); +using EffectInstance = std::pair, Descriptor>; - const bool valid = - isParameterValid(setHg, mDescriptor); - const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT; - EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString(); +class HapticGeneratorScaleParamTest : public ::testing::TestWithParam, + public HapticGeneratorHelper { + public: + HapticGeneratorScaleParamTest() { std::tie(mFactory, mDescriptor) = GetParam(); } + void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); } + void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } +}; - // only get if parameter in range and set success - if (expected == EX_NONE) { - Parameter getParam; - Parameter::Id id; - HapticGenerator::Id hgId; - hgId.set(tag); - id.set(hgId); - EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam)); - EXPECT_EQ(expectParam, getParam) << expectParam.toString() << "\n" - << getParam.toString(); +TEST_P(HapticGeneratorScaleParamTest, SetAndGetScales) { + std::vector hapticScales; + for (int i = 0; i < static_cast(kScaleValues.size()); i++) { + hapticScales.push_back({.id = i, .scale = kScaleValues[i]}); + } + ASSERT_NO_FATAL_FAILURE( + setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); +} + +TEST_P(HapticGeneratorScaleParamTest, SetAndGetScaleFactors) { + if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) { + GTEST_SKIP() << "Skipping HapticGenerator ScaleFactors test for effect version " + << std::to_string(mEffectInterfaceVersion); + } + + std::vector hapticScales; + for (int i = 0; i < static_cast(kScaleFactorValues.size()); i++) { + hapticScales.push_back( + {.id = i, .scale = kScaleValues[0], .scaleFactor = kScaleFactorValues[i]}); + } + ASSERT_NO_FATAL_FAILURE( + setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); +} + +TEST_P(HapticGeneratorScaleParamTest, SetAndGetAdaptiveScaleFactors) { + if (mEffectInterfaceVersion < HAPTIC_SCALE_FACTORS_EFFECT_MIN_VERSION) { + GTEST_SKIP() << "Skipping HapticGenerator AdaptiveScaleFactors test for effect version " + << std::to_string(mEffectInterfaceVersion); + } + + std::vector hapticScales; + for (int i = 0; i < static_cast(kAdaptiveScaleFactorValues.size()); i++) { + hapticScales.push_back({.id = i, + .scale = kScaleValues[0], + .scaleFactor = kScaleFactorValues[3], + .adaptiveScaleFactor = kAdaptiveScaleFactorValues[i]}); + } + ASSERT_NO_FATAL_FAILURE( + setAndVerifyParameter(createScaleParam(hapticScales), HapticGenerator::hapticScales)); +} + +INSTANTIATE_TEST_SUITE_P( + HapticGeneratorValidTest, HapticGeneratorScaleParamTest, + testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, getEffectTypeUuidHapticGenerator())), + [](const testing::TestParamInfo& info) { + auto descriptor = info.param; + return getPrefix(descriptor.second); + }); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScaleParamTest); + +enum VibratorParamName { + VIBRATOR_PARAM_INSTANCE, + VIBRATOR_PARAM_RESONANT_FREQUENCY, + VIBRATOR_PARAM_Q_FACTOR, + VIBRATOR_PARAM_MAX_AMPLITUDE, +}; + +using HapticGeneratorVibratorInfoTestParam = std::tuple; + +class HapticGeneratorVibratorInfoParamTest + : public ::testing::TestWithParam, + public HapticGeneratorHelper { + public: + HapticGeneratorVibratorInfoParamTest() + : mParamResonantFrequency(std::get(GetParam())), + mParamQFactor(std::get(GetParam())), + mParamMaxAmplitude(std::get(GetParam())) { + std::tie(mFactory, mDescriptor) = std::get(GetParam()); + } + void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator()); } + void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } + + float mParamResonantFrequency = kDefaultResonantFrequency; + float mParamQFactor = kDefaultQfactor; + float mParamMaxAmplitude = kDefaultMaxAmp; +}; + +TEST_P(HapticGeneratorVibratorInfoParamTest, SetAndGetVibratorInformation) { + auto vibratorInfo = + createVibratorInfo(mParamResonantFrequency, mParamQFactor, mParamMaxAmplitude); + if (isParameterValid(vibratorInfo, mDescriptor)) { + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), + HapticGenerator::vibratorInfo)); + } else { + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), + HapticGenerator::vibratorInfo, + EX_ILLEGAL_ARGUMENT)); + } +} +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorVibratorInfoParamTest); + +INSTANTIATE_TEST_SUITE_P( + HapticGeneratorValidTest, HapticGeneratorVibratorInfoParamTest, + ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( + IFactory::descriptor, getEffectTypeUuidHapticGenerator())), + testing::ValuesIn(kResonantFrequencyValues), + testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string resonantFrequency = + std::to_string(std::get(info.param)); + std::string qFactor = std::to_string(std::get(info.param)); + std::string maxAmplitude = + std::to_string(std::get(info.param)); + std::string name = getPrefix(descriptor) + "_resonantFrequency" + resonantFrequency + + "_qFactor" + qFactor + "_maxAmplitude" + maxAmplitude; + std::replace_if( + name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + return name; + }); + +/** + * The data tests do the following + * -Generate test input. + * -Check if the parameters are supported. Skip the unsupported parameter values. + * -Validate increase in haptic output energy energy. + **/ + +enum DataTestParam { EFFECT_INSTANCE, LAYOUT }; +using HapticGeneratorDataTestParam = std::tuple; + +class HapticGeneratorDataTest : public ::testing::TestWithParam, + public HapticGeneratorHelper { + public: + HapticGeneratorDataTest() : mChMask(std::get(GetParam())) { + std::tie(mFactory, mDescriptor) = std::get(GetParam()); + mAudioChannelCount = + getChannelCount(AudioChannelLayout::make(mChMask), + ~AudioChannelLayout::LAYOUT_HAPTIC_AB); + mHapticChannelCount = + getChannelCount(AudioChannelLayout::make(mChMask), + AudioChannelLayout::LAYOUT_HAPTIC_AB); + + mAudioSamples = kFrameCount * mAudioChannelCount; + mHapticSamples = kFrameCount * mHapticChannelCount; + mInput.resize(mHapticSamples + mAudioSamples, 0); + mOutput.resize(mHapticSamples + mAudioSamples, 0); + } + + void SetUp() override { ASSERT_NO_FATAL_FAILURE(SetUpHapticGenerator(mChMask)); } + void TearDown() override { ASSERT_NO_FATAL_FAILURE(TearDownHapticGenerator()); } + + void generateSinePeriod() { + size_t cycleSize = kSamplingFrequency / kInputFrequency; + size_t startSize = 0; + while (startSize < mAudioSamples) { + for (size_t i = 0; i < cycleSize; i++) { + mInput[i + startSize] = sin(2 * M_PI * kInputFrequency * i / kSamplingFrequency); + } + startSize += mAudioSamples / 4; + } + } + + void setBaseVibratorParam() { + auto vibratorInfo = + createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, kDefaultMaxAmp); + if (isParameterValid(vibratorInfo, mDescriptor)) { + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), + HapticGenerator::vibratorInfo)); + } else { + GTEST_SKIP() << "Invalid base vibrator values, skipping the test\n"; + } + } + + void setBaseScaleParam() { + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter( + createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, kDefaultScale)}), + HapticGenerator::hapticScales)); + } + + void validateIncreasingEnergy(HapticGenerator::Tag tag) { + float baseEnergy = -1; + for (auto param : mHapticParam) { + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(param, tag)); + SCOPED_TRACE("Param: " + param.toString()); + ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret)); + float hapticOutputEnergy = audio_utils_compute_energy_mono( + mOutput.data() + mAudioSamples, AUDIO_FORMAT_PCM_FLOAT, mHapticSamples); + EXPECT_GT(hapticOutputEnergy, baseEnergy); + baseEnergy = hapticOutputEnergy; + } + } + + float findAbsMax(auto begin, auto end) { + return *std::max_element(begin, end, + [](float a, float b) { return std::abs(a) < std::abs(b); }); + } + + void findMaxAmplitude() { + for (float amp = 0.1; amp <= 1; amp += 0.1) { + auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amp); + if (!isParameterValid(vibratorInfo, + mDescriptor)) { + continue; + } + ASSERT_NO_FATAL_FAILURE(setAndVerifyParameter(createVibratorParam(vibratorInfo), + HapticGenerator::vibratorInfo)); + ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(mInput, mOutput, mEffect, &ret)); + float outAmplitude = findAbsMax(mOutput.begin() + mAudioSamples, mOutput.end()); + if (outAmplitude > mMaxAmplitude) { + mMaxAmplitude = outAmplitude; + } else { + break; } } } - void addHapticScaleParam(int id, HapticGenerator::VibratorScale scale) { - HapticGenerator setHg; - std::vector hapticScales = {{.id = id, .scale = scale}}; - setHg.set(hapticScales); - mTags.push_back({HapticGenerator::hapticScales, setHg}); - } - - void addVibratorInformationParam(float resonantFrequencyHz, float qFactor, float maxAmplitude) { - HapticGenerator hg; - HapticGenerator::VibratorInformation vibrationInfo = { - .resonantFrequencyHz = resonantFrequencyHz, - .qFactor = qFactor, - .maxAmplitude = maxAmplitude}; - hg.set(vibrationInfo); - mTags.push_back({HapticGenerator::vibratorInfo, hg}); - } - - private: - enum ParamTestEnum { PARAM_TEST_TAG, PARAM_TEST_TARGET }; - std::vector> mTags; - - void CleanUp() { mTags.clear(); } + const int kInputFrequency = 1000; + float mMaxAmplitude = 0; + size_t mHapticSamples; + int32_t mChMask; + int32_t mAudioChannelCount; + int32_t mHapticChannelCount; + size_t mAudioSamples; + float mBaseHapticOutputEnergy; + std::vector mHapticParam; + // both input and output buffer includes audio and haptic samples + std::vector mInput; + std::vector mOutput; }; -TEST_P(HapticGeneratorParamTest, SetAndGetHapticScale) { - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale)); - SetAndGetHapticGeneratorParameters(); +TEST_P(HapticGeneratorDataTest, IncreasingVibratorScaleTest) { + generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); + ASSERT_NO_FATAL_FAILURE(setBaseVibratorParam()); + for (HapticGenerator::VibratorScale scale : kScaleValues) { + mHapticParam.push_back( + createScaleParam({HapticGenerator::HapticScale(kDefaultScaleID, scale)})); + } + ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::hapticScales)); } -TEST_P(HapticGeneratorParamTest, SetAndGetMultipleHapticScales) { - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale)); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam(mParamHapticScaleId, mParamVibratorScale)); - SetAndGetHapticGeneratorParameters(); +TEST_P(HapticGeneratorDataTest, IncreasingMaxAmplitudeTest) { + generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); + ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); + findMaxAmplitude(); + std::vector increasingAmplitudeValues = {0.25f * mMaxAmplitude, 0.5f * mMaxAmplitude, + 0.75f * mMaxAmplitude, mMaxAmplitude}; + for (float amplitude : increasingAmplitudeValues) { + auto vibratorInfo = + createVibratorInfo(kDefaultResonantFrequency, kDefaultQfactor, amplitude); + if (!isParameterValid(vibratorInfo, mDescriptor)) { + continue; + } + mHapticParam.push_back(createVibratorParam(vibratorInfo)); + } + ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); } -TEST_P(HapticGeneratorParamTest, SetAndGetVibratorInformation) { - EXPECT_NO_FATAL_FAILURE(addVibratorInformationParam(mParamResonantFrequency, mParamQFactor, - mParamMaxAmplitude)); - SetAndGetHapticGeneratorParameters(); +TEST_P(HapticGeneratorDataTest, DescreasingResonantFrequencyTest) { + std::vector descreasingResonantFrequency = {800, 600, 400, 200}; + generateInput(mInput, kInputFrequency, kSamplingFrequency, mAudioSamples); + ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); + for (float resonantFrequency : descreasingResonantFrequency) { + auto vibratorInfo = createVibratorInfo(resonantFrequency, kDefaultQfactor, kDefaultMaxAmp); + if (!isParameterValid(vibratorInfo, mDescriptor)) { + continue; + } + mHapticParam.push_back(createVibratorParam(vibratorInfo)); + } + ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); +} + +TEST_P(HapticGeneratorDataTest, IncreasingQfactorTest) { + std::vector increasingQfactor = {16, 24, 32, 40}; + generateSinePeriod(); + ASSERT_NO_FATAL_FAILURE(setBaseScaleParam()); + for (float qFactor : increasingQfactor) { + auto vibratorInfo = createVibratorInfo(kDefaultResonantFrequency, qFactor, kDefaultMaxAmp); + if (!isParameterValid(vibratorInfo, mDescriptor)) { + continue; + } + mHapticParam.push_back(createVibratorParam(vibratorInfo)); + } + ASSERT_NO_FATAL_FAILURE(validateIncreasingEnergy(HapticGenerator::vibratorInfo)); } INSTANTIATE_TEST_SUITE_P( - HapticGeneratorValidTest, HapticGeneratorParamTest, + DataTest, HapticGeneratorDataTest, ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( IFactory::descriptor, getEffectTypeUuidHapticGenerator())), - testing::ValuesIn(kHapticScaleIdValues), - testing::ValuesIn(kVibratorScaleValues), - testing::ValuesIn(kResonantFrequencyValues), - testing::ValuesIn(kQFactorValues), testing::ValuesIn(kMaxAmplitude)), - [](const testing::TestParamInfo& info) { - auto descriptor = std::get(info.param).second; - std::string hapticScaleID = std::to_string(std::get(info.param)); - std::string hapticScaleVibScale = std::to_string( - static_cast(std::get(info.param))); - std::string resonantFrequency = std::to_string( - std::get(info.param)); - std::string qFactor = - std::to_string(std::get(info.param)); - std::string maxAmplitude = - std::to_string(std::get(info.param)); - std::string name = getPrefix(descriptor) + "_hapticScaleId" + hapticScaleID + - "_hapticScaleVibScale" + hapticScaleVibScale + "_resonantFrequency" + - resonantFrequency + "_qFactor" + qFactor + "_maxAmplitude" + - maxAmplitude; - std::replace_if( - name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); + testing::ValuesIn(kHapticOutputLayouts)), + [](const testing::TestParamInfo& info) { + auto descriptor = std::get(info.param).second; + std::string layout = "0x" + std::format("{:x}", std::get(info.param)); + std::string name = getPrefix(descriptor) + "_layout_" + layout; return name; }); - -INSTANTIATE_TEST_SUITE_P( - HapticGeneratorInvalidTest, HapticGeneratorParamTest, - ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( - IFactory::descriptor, getEffectTypeUuidHapticGenerator())), - testing::Values(MIN_ID), - testing::Values(HapticGenerator::VibratorScale::NONE), - testing::Values(MIN_FLOAT), testing::Values(MIN_FLOAT), - testing::Values(MIN_FLOAT)), - [](const testing::TestParamInfo& info) { - auto descriptor = std::get(info.param).second; - std::string hapticScaleID = std::to_string(std::get(info.param)); - std::string hapticScaleVibScale = std::to_string( - static_cast(std::get(info.param))); - std::string resonantFrequency = std::to_string( - std::get(info.param)); - std::string qFactor = - std::to_string(std::get(info.param)); - std::string maxAmplitude = - std::to_string(std::get(info.param)); - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - toString(descriptor.common.id.uuid) + "_hapticScaleId" + - hapticScaleID + "_hapticScaleVibScale" + hapticScaleVibScale + - "_resonantFrequency" + resonantFrequency + "_qFactor" + qFactor + - "_maxAmplitude" + maxAmplitude; - std::replace_if( - name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); - return name; - }); -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorParamTest); - -// Test HapticScale[] hapticScales parameter -using HapticGeneratorScalesTestParam = std::tuple, Descriptor>>; -class HapticGeneratorScalesTest : public ::testing::TestWithParam, - public EffectHelper { - public: - HapticGeneratorScalesTest() { - std::tie(mFactory, mDescriptor) = std::get(GetParam()); - } - - void SetUp() override { - ASSERT_NE(nullptr, mFactory); - ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor)); - - Parameter::Common common = createParamCommon( - 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */, - kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */); - IEffect::OpenEffectReturn ret; - ASSERT_NO_FATAL_FAILURE(open(mEffect, common, std::nullopt, &ret, EX_NONE)); - ASSERT_NE(nullptr, mEffect); - } - - void TearDown() override { - ASSERT_NO_FATAL_FAILURE(close(mEffect)); - ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect)); - CleanUp(); - } - - static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100; - std::shared_ptr mFactory; - std::shared_ptr mEffect; - Descriptor mDescriptor; - - void addHapticScaleParam(std::vector scales) { - mHapticScales.push_back(HapticGenerator::make(scales)); - for (const auto& scale : scales) { - expectMap.insert_or_assign(scale.id, scale.scale); - } - } - - void SetHapticScaleParameters() { - // std::unordered_set target; - for (auto& it : mHapticScales) { - Parameter::Specific specific = - Parameter::Specific::make(it); - Parameter param = Parameter::make(specific); - EXPECT_STATUS(EX_NONE, mEffect->setParameter(param)) << param.toString(); - } - } - - void checkHapticScaleParameter() { - // get parameter - Parameter targetParam; - HapticGenerator::Id hgId = HapticGenerator::Id::make( - HapticGenerator::hapticScales); - Parameter::Id id = Parameter::Id::make(hgId); - EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &targetParam)); - ASSERT_EQ(Parameter::specific, targetParam.getTag()); - Parameter::Specific specific = targetParam.get(); - ASSERT_EQ(Parameter::Specific::hapticGenerator, specific.getTag()); - HapticGenerator hg = specific.get(); - ASSERT_EQ(HapticGenerator::hapticScales, hg.getTag()); - std::vector scales = hg.get(); - ASSERT_EQ(scales.size(), expectMap.size()); - for (const auto& scale : scales) { - auto itor = expectMap.find(scale.id); - ASSERT_NE(expectMap.end(), itor); - ASSERT_EQ(scale.scale, itor->second); - expectMap.erase(scale.id); - } - ASSERT_EQ(0ul, expectMap.size()); - } - - const static HapticGenerator::HapticScale kHapticScaleWithMinId; - const static HapticGenerator::HapticScale kHapticScaleWithMinIdNew; - const static HapticGenerator::HapticScale kHapticScale; - const static HapticGenerator::HapticScale kHapticScaleNew; - const static HapticGenerator::HapticScale kHapticScaleWithMaxId; - const static HapticGenerator::HapticScale kHapticScaleWithMaxIdNew; - - std::vector mHapticScales; - - void CleanUp() { - mHapticScales.clear(); - expectMap.clear(); - } - - private: - std::map expectMap; -}; - -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinId = { - .id = MIN_ID, .scale = HapticGenerator::VibratorScale::MUTE}; -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMinIdNew = { - .id = MIN_ID, .scale = HapticGenerator::VibratorScale::VERY_LOW}; -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScale = { - .id = 1, .scale = HapticGenerator::VibratorScale::LOW}; -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleNew = { - .id = 1, .scale = HapticGenerator::VibratorScale::NONE}; -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxId = { - .id = MAX_ID, .scale = HapticGenerator::VibratorScale::VERY_HIGH}; -const HapticGenerator::HapticScale HapticGeneratorScalesTest::kHapticScaleWithMaxIdNew = { - .id = MAX_ID, .scale = HapticGenerator::VibratorScale::MUTE}; - -TEST_P(HapticGeneratorScalesTest, SetAndUpdateOne) { - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleNew})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMinIdNew})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxIdNew})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -TEST_P(HapticGeneratorScalesTest, SetAndUpdateVector) { - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam( - {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -TEST_P(HapticGeneratorScalesTest, SetAndUpdateMultipleVector) { - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam( - {kHapticScaleNew, kHapticScaleWithMaxIdNew, kHapticScaleWithMinIdNew})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScale, kHapticScaleWithMaxId, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -TEST_P(HapticGeneratorScalesTest, SetOneAndAddMoreVector) { - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -TEST_P(HapticGeneratorScalesTest, SetMultipleAndAddOneVector) { - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScaleWithMaxId, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE(addHapticScaleParam({kHapticScale})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -TEST_P(HapticGeneratorScalesTest, SetMultipleVectorRepeat) { - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - EXPECT_NO_FATAL_FAILURE( - addHapticScaleParam({kHapticScaleWithMaxId, kHapticScale, kHapticScaleWithMinId})); - EXPECT_NO_FATAL_FAILURE(SetHapticScaleParameters()); - - EXPECT_NO_FATAL_FAILURE(checkHapticScaleParameter()); -} - -INSTANTIATE_TEST_SUITE_P( - HapticGeneratorScalesTest, HapticGeneratorScalesTest, - ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors( - IFactory::descriptor, getEffectTypeUuidHapticGenerator()))), - [](const testing::TestParamInfo& info) { - auto descriptor = std::get(info.param).second; - std::string name = "Implementor_" + descriptor.common.implementor + "_name_" + - descriptor.common.name + "_UUID_" + - toString(descriptor.common.id.uuid); - std::replace_if( - name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); - return name; - }); -GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorScalesTest); +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HapticGeneratorDataTest); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/automotive/TEST_MAPPING b/automotive/TEST_MAPPING index c64c8805d6..483a85fd41 100644 --- a/automotive/TEST_MAPPING +++ b/automotive/TEST_MAPPING @@ -19,10 +19,58 @@ "name": "CtsCarBuiltinApiHostTestCases" }, { - "name": "CarServiceTest" + "name": "CarServiceAudioTest" + }, + { + "name": "CarServiceCarTest" + }, + { + "name": "CarServiceClusterTest" + }, + { + "name": "CarServiceDiagnosticTest" + }, + { + "name": "CarServiceDrivingStateTest" + }, + { + "name": "CarServiceEvsTest" + }, + { + "name": "CarServiceGarageModeTest" + }, + { + "name": "CarServiceInputTest" + }, + { + "name": "CarServiceOsTest" + }, + { + "name": "CarServicePmTest" + }, + { + "name": "CarServicePowerTest" + }, + { + "name": "CarServicePropertyTest" + }, + { + "name": "CarServiceRemoteAccessTest" + }, + { + "name": "CarServiceStorageMonitoringTest" + }, + { + "name": "CarServiceTelemetryTest" }, { "name": "CarServiceUnitTest" + }, + { + "name": "CarServiceVmsTest" + }, + { + "name": "CarServiceWatchdogTest" } ] } \ No newline at end of file diff --git a/automotive/evs/aidl/Android.bp b/automotive/evs/aidl/Android.bp index 9f5ab97a6d..75eb924899 100644 --- a/automotive/evs/aidl/Android.bp +++ b/automotive/evs/aidl/Android.bp @@ -46,6 +46,9 @@ aidl_interface { ndk: { min_sdk_version: "29", }, + rust: { + enabled: true, + }, }, versions_with_info: [ { diff --git a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml index 50692f7d5d..9ddc6ad3f4 100644 --- a/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml +++ b/automotive/evs/aidl/impl/default/manifest_evs-default-service.xml @@ -2,6 +2,6 @@ android.hardware.automotive.evs IEvsEnumerator/hw/0 - 1 + 2 diff --git a/automotive/evs/aidl/rust_impl/Android.bp b/automotive/evs/aidl/rust_impl/Android.bp new file mode 100644 index 0000000000..ac8b90f1b2 --- /dev/null +++ b/automotive/evs/aidl/rust_impl/Android.bp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 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. + */ + +rust_binary { + name: "android.hardware.automotive.evs-aidl-rust-service", + relative_install_path: "hw", + vendor: true, + srcs: ["src/*.rs"], + crate_root: "src/main.rs", + vintf_fragments: ["manifest_evs-rust-service.xml"], + init_rc: ["evs-rust-service.rc"], + rustlibs: [ + "android.hardware.automotive.evs-V2-rust", + "libbinder_rs", + "liblog_rust", + ], +} diff --git a/automotive/evs/aidl/rust_impl/README.md b/automotive/evs/aidl/rust_impl/README.md new file mode 100644 index 0000000000..bf00aede4f --- /dev/null +++ b/automotive/evs/aidl/rust_impl/README.md @@ -0,0 +1,21 @@ +# Rust Skeleton EVS HAL implementation. + +WARNING: This is not a reference EVS HAL implementation and therefore does not +provide any actual functionality. + +This folder contains a skeleton EVS HAL implementation in Rust to demonstrate +how vendors could implement their EVS HAL in Rust. To compile and run this +implementation, please include below package to the device build script: + +* `android.hardware.automotive.evs-aidl-rust-service` + +Please note that this service will attempt to register the service as +`IEvsEnumerator/rust/0` and therefore is also required to be declared in the +service context by adding below line to a proper `service_contexts` file: + +> android.hardware.automotive.evs.IEvsEnumerator/rust/0 u:object_r:hal_evs_service:s0 + +This implementation intentionally returns `binder::StatusCode::UNKNOWN_ERROR` +for any API call except deprecated API for ultrasonics; the process will be +panicked on these methods instead. Hence, this implementation does not comply +with VTS tests and vendors must replace each method with actual implementation. diff --git a/automotive/evs/aidl/rust_impl/evs-rust-service.rc b/automotive/evs/aidl/rust_impl/evs-rust-service.rc new file mode 100644 index 0000000000..3741b21abf --- /dev/null +++ b/automotive/evs/aidl/rust_impl/evs-rust-service.rc @@ -0,0 +1,8 @@ +service vendor.evs-hal-rust-default /vendor/bin/hw/android.hardware.automotive.evs-aidl-rust-service + class early_hal + priority -20 + user graphics + group automotive_evs camera + onrestart restart cardisplayproxyd + onrestart restart evsmanagerd + disabled diff --git a/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml new file mode 100644 index 0000000000..813cbb2109 --- /dev/null +++ b/automotive/evs/aidl/rust_impl/manifest_evs-rust-service.xml @@ -0,0 +1,7 @@ + + + android.hardware.automotive.evs + 2 + IEvsEnumerator/rust/0 + + diff --git a/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs new file mode 100644 index 0000000000..72b2d5358e --- /dev/null +++ b/automotive/evs/aidl/rust_impl/src/default_evs_hal.rs @@ -0,0 +1,113 @@ +// +// Copyright (C) 2024 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. +// + +use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::{ + CameraDesc::CameraDesc, DisplayState::DisplayState, IEvsCamera::IEvsCamera, + IEvsDisplay::IEvsDisplay, IEvsEnumerator::IEvsEnumerator, + IEvsEnumeratorStatusCallback::IEvsEnumeratorStatusCallback, + IEvsUltrasonicsArray::IEvsUltrasonicsArray, Stream::Stream, + UltrasonicsArrayDesc::UltrasonicsArrayDesc, +}; + +pub struct DefaultEvsHal {} + +impl binder::Interface for DefaultEvsHal {} + +impl IEvsEnumerator for DefaultEvsHal { + fn closeCamera( + &self, + _: &binder::Strong<(dyn IEvsCamera + 'static)>, + ) -> std::result::Result<(), binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn closeDisplay( + &self, + _: &binder::Strong<(dyn IEvsDisplay + 'static)>, + ) -> std::result::Result<(), binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn closeUltrasonicsArray( + &self, + _: &binder::Strong<(dyn IEvsUltrasonicsArray + 'static)>, + ) -> std::result::Result<(), binder::Status> { + unimplemented!() + } + + fn getCameraList(&self) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getDisplayIdList(&self) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getDisplayState(&self) -> std::result::Result { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getStreamList( + &self, + _: &CameraDesc, + ) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getUltrasonicsArrayList( + &self, + ) -> std::result::Result, binder::Status> { + unimplemented!() + } + + fn isHardware(&self) -> std::result::Result { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn openCamera( + &self, + _: &str, + _: &Stream, + ) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn openDisplay( + &self, + _: i32, + ) -> std::result::Result, binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn openUltrasonicsArray( + &self, + _: &str, + ) -> std::result::Result, binder::Status> + { + unimplemented!() + } + + fn registerStatusCallback( + &self, + _: &binder::Strong<(dyn IEvsEnumeratorStatusCallback + 'static)>, + ) -> std::result::Result<(), binder::Status> { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } + + fn getDisplayStateById(&self, _: i32) -> std::result::Result { + Err(binder::StatusCode::UNKNOWN_ERROR.into()) + } +} diff --git a/automotive/evs/aidl/rust_impl/src/main.rs b/automotive/evs/aidl/rust_impl/src/main.rs new file mode 100644 index 0000000000..df312c0024 --- /dev/null +++ b/automotive/evs/aidl/rust_impl/src/main.rs @@ -0,0 +1,42 @@ +// +// Copyright (C) 2024 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. +// + +mod default_evs_hal; + +use crate::default_evs_hal::DefaultEvsHal; + +use android_hardware_automotive_evs::aidl::android::hardware::automotive::evs::IEvsEnumerator::BnEvsEnumerator; + +use log::info; + +fn main() { + binder::ProcessState::start_thread_pool(); + + let service = DefaultEvsHal {}; + + // Register HAL implementation as rust/0 instance. + let service_name = "android.hardware.automotive.evs.IEvsEnumerator/rust/0"; + let service_binder = BnEvsEnumerator::new_binder(service, binder::BinderFeatures::default()); + + binder::add_service(service_name, service_binder.as_binder()) + .expect(format!("Failed to register {}.", service_name).as_str()); + info!("EVS Hardware Enumerator is ready"); + + binder::ProcessState::join_thread_pool(); + + // In normal operation, we don't expect the thread pool to exit. + info!("EVS Hardware Enumerator is shutting down"); +} diff --git a/automotive/vehicle/Android.bp b/automotive/vehicle/Android.bp index e6149378b0..606e108004 100644 --- a/automotive/vehicle/Android.bp +++ b/automotive/vehicle/Android.bp @@ -22,7 +22,7 @@ cc_defaults { name: "VehicleHalInterfaceDefaults", static_libs: [ "android.hardware.automotive.vehicle-V3-ndk", - "android.hardware.automotive.vehicle.property-V3-ndk", + "android.hardware.automotive.vehicle.property-V4-ndk", ], } @@ -30,6 +30,14 @@ rust_defaults { name: "VehicleHalInterfaceRustDefaults", rustlibs: [ "android.hardware.automotive.vehicle-V3-rust", - "android.hardware.automotive.vehicle.property-V3-rust", + "android.hardware.automotive.vehicle.property-V4-rust", + ], +} + +aidl_interface_defaults { + name: "android.hardware.automotive.vehicle-latest-defaults", + imports: [ + "android.hardware.automotive.vehicle-V3", + "android.hardware.automotive.vehicle.property-V4", ], } diff --git a/automotive/vehicle/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp index f517df8018..1e43070d0b 100644 --- a/automotive/vehicle/aidl/aidl_test/Android.bp +++ b/automotive/vehicle/aidl/aidl_test/Android.bp @@ -40,7 +40,7 @@ cc_test { cc_test { name: "VehiclePropertyAnnotationCppTest", srcs: ["VehiclePropertyAnnotationCppTest.cpp"], - header_libs: ["IVehicleGeneratedHeaders-V3"], + header_libs: ["IVehicleGeneratedHeaders-V4"], defaults: ["VehicleHalInterfaceDefaults"], test_suites: ["general-tests"], } @@ -49,11 +49,11 @@ android_test { name: "VehiclePropertyAnnotationJavaTest", srcs: [ "VehiclePropertyAnnotationJavaTest.java", - ":IVehicleGeneratedJavaFiles-V3", + ":IVehicleGeneratedJavaFiles-V4", ], static_libs: [ "android.hardware.automotive.vehicle-V3-java", - "android.hardware.automotive.vehicle.property-V3-java", + "android.hardware.automotive.vehicle.property-V4-java", "androidx.test.runner", "truth", ], diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h index 51a3025740..6f6c91c149 100644 --- a/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h +++ b/automotive/vehicle/aidl/generated_lib/3/cpp/AccessForVehicleProperty.h @@ -27,6 +27,10 @@ #include #include +// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. +#include +// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + #include namespace aidl { @@ -302,6 +306,9 @@ std::unordered_map AccessForVehiclePrope {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess::READ}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ}, + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess::READ}, + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. }; } // namespace vehicle diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h index 60e9a72138..88f2f88ac3 100644 --- a/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h +++ b/automotive/vehicle/aidl/generated_lib/3/cpp/ChangeModeForVehicleProperty.h @@ -27,6 +27,10 @@ #include #include +// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. +#include +// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + #include namespace aidl { @@ -302,6 +306,9 @@ std::unordered_map ChangeModeForVehi {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode::ON_CHANGE}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE}, + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + {PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode::STATIC}, + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. }; } // namespace vehicle diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h new file mode 100644 index 0000000000..2b50db3531 --- /dev/null +++ b/automotive/vehicle/aidl/generated_lib/3/cpp/PerDisplayMaxBrightness.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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 + +namespace aidl::android::hardware::automotive::vehicle { + +// Same as VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS as defined in v4. +static constexpr VehicleProperty PER_DISPLAY_MAX_BRIGHTNESS = (VehicleProperty)0x11410F4E; + +} // namespace aidl::android::hardware::automotive::vehicle diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h index 0e80bd85b2..0d242737d1 100644 --- a/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h +++ b/automotive/vehicle/aidl/generated_lib/3/cpp/VersionForVehicleProperty.h @@ -26,6 +26,10 @@ #include +// Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. +#include +// End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + #include namespace aidl { @@ -301,6 +305,9 @@ std::unordered_map VersionForVehicleProperty = { {VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE, 3}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 3}, {VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, 3}, + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + {PER_DISPLAY_MAX_BRIGHTNESS, 2}, + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. }; } // namespace vehicle diff --git a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java index afb6cab547..f899df84d7 100644 --- a/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java +++ b/automotive/vehicle/aidl/generated_lib/3/java/AccessForVehicleProperty.java @@ -28,6 +28,10 @@ import java.util.Map; public final class AccessForVehicleProperty { + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E; + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + public static final Map values = Map.ofEntries( Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyAccess.READ), Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyAccess.READ), @@ -294,7 +298,10 @@ public final class AccessForVehicleProperty { Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyAccess.READ_WRITE), Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyAccess.READ), Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE), - Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ) + Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ), + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess.READ) + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. ); } diff --git a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java index 12aff40b34..09989bf73b 100644 --- a/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java +++ b/automotive/vehicle/aidl/generated_lib/3/java/ChangeModeForVehicleProperty.java @@ -28,6 +28,10 @@ import java.util.Map; public final class ChangeModeForVehicleProperty { + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + private static final int PER_DISPLAY_MAX_BRIGHTNESS = 0x11410F4E; + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + public static final Map values = Map.ofEntries( Map.entry(VehicleProperty.INFO_VIN, VehiclePropertyChangeMode.STATIC), Map.entry(VehicleProperty.INFO_MAKE, VehiclePropertyChangeMode.STATIC), @@ -294,7 +298,10 @@ public final class ChangeModeForVehicleProperty { Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE), Map.entry(VehicleProperty.CROSS_TRAFFIC_MONITORING_WARNING_STATE, VehiclePropertyChangeMode.ON_CHANGE), Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE), - Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE) + Map.entry(VehicleProperty.LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE), + // Start manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. + Map.entry(PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode.STATIC) + // End manual edit: backport PER_DISPLAY_MAX_BRIGHTNESS. ); } diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp index 28c95cef85..aef2909e36 100644 --- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp +++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp @@ -27,7 +27,7 @@ cc_library { defaults: ["VehicleHalDefaults"], static_libs: ["VehicleHalUtils"], header_libs: [ - "IVehicleGeneratedHeaders-V3", + "IVehicleGeneratedHeaders-V4", ], shared_libs: ["libjsoncpp"], } @@ -44,7 +44,7 @@ cc_library { defaults: ["VehicleHalDefaults"], static_libs: ["VehicleHalUtils"], header_libs: [ - "IVehicleGeneratedHeaders-V3", + "IVehicleGeneratedHeaders-V4", "libbinder_headers", ], cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"], @@ -60,7 +60,7 @@ cc_library_headers { defaults: ["VehicleHalDefaults"], static_libs: ["VehicleHalUtils"], header_libs: [ - "IVehicleGeneratedHeaders-V3", + "IVehicleGeneratedHeaders-V4", ], shared_libs: ["libjsoncpp"], } diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp index abf15c5429..90ea02762e 100644 --- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp +++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/Android.bp @@ -27,8 +27,6 @@ cc_test { "VehicleHalJsonConfigLoader", "VehicleHalUtils", "libgtest", - ], - shared_libs: [ "libjsoncpp", ], defaults: ["VehicleHalDefaults"], @@ -43,8 +41,6 @@ cc_test { "VehicleHalJsonConfigLoaderEnableTestProperties", "VehicleHalUtils", "libgtest", - ], - shared_libs: [ "libjsoncpp", ], defaults: ["VehicleHalDefaults"], diff --git a/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING new file mode 100644 index 0000000000..15ac9cb6b6 --- /dev/null +++ b/automotive/vehicle/aidl/impl/default_config/TEST_MAPPING @@ -0,0 +1,8 @@ +{ + "ravenwood-presubmit": [ + { + "name": "CarServiceHostUnitTest", + "host": true + } + ] +} diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json index 2d1e9ab7fe..489d6387c3 100644 --- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json +++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json @@ -3195,19 +3195,22 @@ } }, { - "property": "VehicleProperty::DISPLAY_BRIGHTNESS", + "property": "VehicleProperty::PER_DISPLAY_BRIGHTNESS" + }, + { + "property": "VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS", "defaultValue": { "int32Values": [ + 0, + 100, + 1, + 100, + 2, + 100, + 3, 100 ] - }, - "areas": [ - { - "areaId": 0, - "minInt32Value": 0, - "maxInt32Value": 100 - } - ] + } }, { "property": "VehicleProperty::VALET_MODE_ENABLED", diff --git a/automotive/vehicle/aidl/impl/default_config/test/Android.bp b/automotive/vehicle/aidl/impl/default_config/test/Android.bp index 70933bee50..a88913e66a 100644 --- a/automotive/vehicle/aidl/impl/default_config/test/Android.bp +++ b/automotive/vehicle/aidl/impl/default_config/test/Android.bp @@ -29,12 +29,10 @@ cc_test { "VehicleHalUtils", "libgmock", "libgtest", + "libjsoncpp", ], header_libs: [ - "IVehicleGeneratedHeaders-V3", - ], - shared_libs: [ - "libjsoncpp", + "IVehicleGeneratedHeaders-V4", ], data: [ ":VehicleHalDefaultProperties_JSON", @@ -52,15 +50,13 @@ cc_test { "VehicleHalUtils", "libgmock", "libgtest", + "libjsoncpp", ], cflags: [ "-DENABLE_VEHICLE_HAL_TEST_PROPERTIES", ], header_libs: [ - "IVehicleGeneratedHeaders-V3", - ], - shared_libs: [ - "libjsoncpp", + "IVehicleGeneratedHeaders-V4", ], data: [ ":VehicleHalDefaultProperties_JSON", diff --git a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp index 4bc0b123de..0d814eafb9 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp +++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/test/Android.bp @@ -28,8 +28,6 @@ cc_test { "VehicleHalUtils", "FakeVehicleHalValueGenerators", "FakeObd2Frame", - ], - shared_libs: [ "libjsoncpp", ], data: [ diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp index b301557f06..a6247a70b7 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp @@ -1056,6 +1056,10 @@ VhalResult FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValu VhalResult isAdasPropertyAvailableResult; VhalResult isCruiseControlTypeStandardResult; switch (propId) { + case toInt(VehicleProperty::DISPLAY_BRIGHTNESS): + case toInt(VehicleProperty::PER_DISPLAY_BRIGHTNESS): + ALOGD("DISPLAY_BRIGHTNESS: %s", value.toString().c_str()); + return {}; case toInt(VehicleProperty::AP_POWER_STATE_REPORT): *isSpecialValue = true; return setApPowerStateReport(value); diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp index 9f002dd7cd..62c114780a 100644 --- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp +++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp @@ -40,10 +40,10 @@ cc_test { "FakeUserHal", "libgtest", "libgmock", + "libjsoncpp", ], shared_libs: [ "libgrpc++", - "libjsoncpp", "libprotobuf-cpp-full", ], data: [ diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp index 73bb521ddb..875037524d 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp @@ -83,6 +83,17 @@ std::vector GRPCVehicleHardware::getAllPropertyConf return configs; } +std::optional GRPCVehicleHardware::getPropertyConfig( + int32_t propId) const { + // TODO(b/354055835): Use GRPC call to get one config instead of getting all the configs. + for (const auto& config : getAllPropertyConfigs()) { + if (config.prop == propId) { + return config; + } + } + return std::nullopt; +} + aidlvhal::StatusCode GRPCVehicleHardware::setValues( std::shared_ptr callback, const std::vector& requests) { @@ -265,6 +276,7 @@ DumpResult GRPCVehicleHardware::dump(const std::vector& options) { return { .callerShouldDumpState = protoDumpResult.caller_should_dump_state(), .buffer = protoDumpResult.buffer(), + .refreshPropertyConfigs = protoDumpResult.refresh_property_configs(), }; } diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h index 1edf6580aa..15f473c0bd 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h @@ -50,6 +50,10 @@ class GRPCVehicleHardware : public IVehicleHardware { // Get all the property configs. std::vector getAllPropertyConfigs() const override; + // Get the config for the specified propId. + std::optional + getPropertyConfig(int32_t propId) const override; + // Set property values asynchronously. Server could return before the property set requests // are sent to vehicle bus or before property set confirmation is received. The callback is // safe to be called after the function returns and is safe to be called in a different thread. diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp index d7cbe1b017..7697c03d74 100644 --- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp +++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp @@ -226,6 +226,7 @@ GrpcVehicleProxyServer::GrpcVehicleProxyServer(std::vector serverAd auto dumpResult = mHardware->dump(dumpOptionStrings); result->set_caller_should_dump_state(dumpResult.callerShouldDumpState); result->set_buffer(dumpResult.buffer); + result->set_refresh_property_configs(dumpResult.refreshPropertyConfigs); return ::grpc::Status::OK; } diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h index f49d91b30c..06846553da 100644 --- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h @@ -20,6 +20,7 @@ #include #include +#include #include namespace android { @@ -46,33 +47,53 @@ struct SetValueErrorEvent { int32_t areaId; }; +namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle; + // An abstract interface to access vehicle hardware. // For virtualized VHAL, GrpcVehicleHardware would communicate with a VehicleHardware // implementation in another VM through GRPC. For non-virtualzied VHAL, VHAL directly communicates // with a VehicleHardware through this interface. class IVehicleHardware { public: - using SetValuesCallback = std::function)>; - using GetValuesCallback = std::function)>; - using PropertyChangeCallback = std::function)>; + using SetValuesCallback = std::function)>; + using GetValuesCallback = std::function)>; + using PropertyChangeCallback = std::function)>; using PropertySetErrorCallback = std::function)>; virtual ~IVehicleHardware() = default; // Get all the property configs. - virtual std::vector - getAllPropertyConfigs() const = 0; + virtual std::vector getAllPropertyConfigs() const = 0; + + // Get the property configs for the specified propId. This is used for early-boot + // native VHAL clients to access certain property configs when not all property configs are + // available. For example, a config discovery process might be required to determine the + // property config for HVAC. However, for early boot properties, e.g. VHAL_HEARTBEAT, it + // could return before the config discovery process. + // + // Currently Android system may try to access the following properties during early boot: + // STORAGE_ENCRYPTION_BINDING_SEED, WATCHDOG_ALIVE, WATCHDOG_TERMINATE_PROCESS, VHAL_HEARTBEAT, + // CURRENT_POWER_POLICY, POWER_POLICY_REQ, POWER_POLICY_GROUP_REQ. They should return + // quickly otherwise the whole bootup process might be blocked. + virtual std::optional getPropertyConfig(int32_t propId) const { + // The default implementation is to use getAllPropertyConfigs(). This should be + // overridden if getAllPropertyConfigs() takes a while to return for initial boot or + // relies on ethernet or other communication channel that is not available during early + // boot. + for (const auto& config : getAllPropertyConfigs()) { + if (config.prop == propId) { + return config; + } + } + return std::nullopt; + } // Set property values asynchronously. Server could return before the property set requests // are sent to vehicle bus or before property set confirmation is received. The callback is // safe to be called after the function returns and is safe to be called in a different thread. - virtual aidl::android::hardware::automotive::vehicle::StatusCode setValues( + virtual aidlvhal::StatusCode setValues( std::shared_ptr callback, - const std::vector& - requests) = 0; + const std::vector& requests) = 0; // Get property values asynchronously. Server could return before the property values are ready. // The callback is safe to be called after the function returns and is safe to be called in a @@ -86,7 +107,7 @@ class IVehicleHardware { virtual DumpResult dump(const std::vector& options) = 0; // Check whether the system is healthy, return {@code StatusCode::OK} for healthy. - virtual aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() = 0; + virtual aidlvhal::StatusCode checkHealth() = 0; // Register a callback that would be called when there is a property change event from vehicle. // This function must only be called once during initialization. @@ -179,16 +200,14 @@ class IVehicleHardware { // 5. The second subscriber is removed, 'unsubscribe' is called. // The impl can optionally disable the polling for vehicle speed. // - virtual aidl::android::hardware::automotive::vehicle::StatusCode subscribe( - [[maybe_unused]] aidl::android::hardware::automotive::vehicle::SubscribeOptions - options) { - return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + virtual aidlvhal::StatusCode subscribe([[maybe_unused]] aidlvhal::SubscribeOptions options) { + return aidlvhal::StatusCode::OK; } // A [propId, areaId] is unsubscribed. This applies for both continuous or on-change property. - virtual aidl::android::hardware::automotive::vehicle::StatusCode unsubscribe( - [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId) { - return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + virtual aidlvhal::StatusCode unsubscribe([[maybe_unused]] int32_t propId, + [[maybe_unused]] int32_t areaId) { + return aidlvhal::StatusCode::OK; } // This function is deprecated, subscribe/unsubscribe should be used instead. @@ -216,10 +235,10 @@ class IVehicleHardware { // // If the impl is always polling at {@code maxSampleRate} as specified in config, then this // function can be a no-op. - virtual aidl::android::hardware::automotive::vehicle::StatusCode updateSampleRate( - [[maybe_unused]] int32_t propId, [[maybe_unused]] int32_t areaId, - [[maybe_unused]] float sampleRate) { - return aidl::android::hardware::automotive::vehicle::StatusCode::OK; + virtual aidlvhal::StatusCode updateSampleRate([[maybe_unused]] int32_t propId, + [[maybe_unused]] int32_t areaId, + [[maybe_unused]] float sampleRate) { + return aidlvhal::StatusCode::OK; } }; diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp index b2edf753b8..0d3df49d46 100644 --- a/automotive/vehicle/aidl/impl/proto/Android.bp +++ b/automotive/vehicle/aidl/impl/proto/Android.bp @@ -106,3 +106,21 @@ cc_library_static { "-Wno-unused-parameter", ], } + +rust_protobuf { + name: "libvehicle_hal_property_protos", + crate_name: "vehicle_hal_property_protos", + protos: [":VehicleHalProtoFiles"], + source_stem: "vehicle_hal_property_protos", + host_supported: true, + vendor_available: true, + product_available: true, + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + exported_include_dirs: ["."], + proto_flags: [ + "-I external/protobuf/src", + ], +} diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto index 25bb7d4f77..fbfb505f51 100644 --- a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto +++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/DumpResult.proto @@ -25,4 +25,6 @@ message DumpResult { bool caller_should_dump_state = 1; /* The dumped information for the caller to print. */ string buffer = 2; + /* To pass if DefaultVehicleHal should refresh the property configs. */ + bool refresh_property_configs = 3; } diff --git a/automotive/vehicle/aidl/impl/vhal/Android.bp b/automotive/vehicle/aidl/impl/vhal/Android.bp index 5cc071d1ae..54d148e12d 100644 --- a/automotive/vehicle/aidl/impl/vhal/Android.bp +++ b/automotive/vehicle/aidl/impl/vhal/Android.bp @@ -66,7 +66,7 @@ cc_library { ], header_libs: [ "IVehicleHardware", - "IVehicleGeneratedHeaders-V3", + "IVehicleGeneratedHeaders-V4", ], shared_libs: [ "libbinder_ndk", diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h index b58d0f5302..932a2e21d0 100644 --- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h +++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h @@ -199,6 +199,8 @@ class DefaultVehicleHal final : public aidlvhal::BnVehicle { bool checkDumpPermission(); + bool isConfigSupportedForCurrentVhalVersion(const aidlvhal::VehiclePropConfig& config) const; + bool getAllPropConfigsFromHardwareLocked() const EXCLUDES(mConfigLock); // The looping handler function to process all onBinderDied or onBinderUnlinked events in diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp index e062a286b2..0ead81934c 100644 --- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp +++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp @@ -340,32 +340,37 @@ int32_t DefaultVehicleHal::getVhalInterfaceVersion() const { return myVersion; } +bool DefaultVehicleHal::isConfigSupportedForCurrentVhalVersion( + const VehiclePropConfig& config) const { + int32_t myVersion = getVhalInterfaceVersion(); + if (!isSystemProp(config.prop)) { + return true; + } + VehicleProperty property = static_cast(config.prop); + std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property); + auto it = VersionForVehicleProperty.find(property); + if (it == VersionForVehicleProperty.end()) { + ALOGE("The property: %s is not a supported system property, ignore", propertyName.c_str()); + return false; + } + int requiredVersion = it->second; + if (myVersion < requiredVersion) { + ALOGE("The property: %s is not supported for current client VHAL version, " + "require %d, current version: %d, ignore", + propertyName.c_str(), requiredVersion, myVersion); + return false; + } + return true; +} + bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const { ALOGD("Get all property configs from hardware"); auto configs = mVehicleHardware->getAllPropertyConfigs(); std::vector filteredConfigs; - int32_t myVersion = getVhalInterfaceVersion(); - for (auto& config : configs) { - if (!isSystemProp(config.prop)) { + for (const auto& config : configs) { + if (isConfigSupportedForCurrentVhalVersion(config)) { filteredConfigs.push_back(std::move(config)); - continue; } - VehicleProperty property = static_cast(config.prop); - std::string propertyName = aidl::android::hardware::automotive::vehicle::toString(property); - auto it = VersionForVehicleProperty.find(property); - if (it == VersionForVehicleProperty.end()) { - ALOGE("The property: %s is not a supported system property, ignore", - propertyName.c_str()); - continue; - } - int requiredVersion = it->second; - if (myVersion < requiredVersion) { - ALOGE("The property: %s is not supported for current client VHAL version, " - "require %d, current version: %d, ignore", - propertyName.c_str(), requiredVersion, myVersion); - continue; - } - filteredConfigs.push_back(std::move(config)); } { @@ -431,6 +436,19 @@ ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) { Result DefaultVehicleHal::getConfig(int32_t propId) const { Result result; + + if (!mConfigInit) { + std::optional config = mVehicleHardware->getPropertyConfig(propId); + if (!config.has_value()) { + return Error() << "no config for property, ID: " << propId; + } + if (!isConfigSupportedForCurrentVhalVersion(config.value())) { + return Error() << "property not supported for current VHAL interface, ID: " << propId; + } + + return config.value(); + } + getConfigsByPropId([this, &result, propId](const auto& configsByPropId) { SharedScopedLockAssertion lockAssertion(mConfigLock); @@ -685,6 +703,22 @@ ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback, ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector& props, VehiclePropConfigs* output) { std::vector configs; + + if (!mConfigInit) { + for (int32_t prop : props) { + auto maybeConfig = mVehicleHardware->getPropertyConfig(prop); + if (!maybeConfig.has_value() || + !isConfigSupportedForCurrentVhalVersion(maybeConfig.value())) { + return ScopedAStatus::fromServiceSpecificErrorWithMessage( + toInt(StatusCode::INVALID_ARG), + StringPrintf("no config for property, ID: %" PRId32, prop).c_str()); + } + configs.push_back(maybeConfig.value()); + } + + return vectorToStableLargeParcelable(std::move(configs), output); + } + ScopedAStatus status = ScopedAStatus::ok(); getConfigsByPropId([this, &configs, &status, &props](const auto& configsByPropId) { SharedScopedLockAssertion lockAssertion(mConfigLock); diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp index 11a8fc7ac1..4891bf56a9 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp @@ -650,6 +650,8 @@ TEST_F(DefaultVehicleHalTest, testGetPropConfigs) { auto hardware = std::make_unique(); hardware->setPropertyConfigs(testConfigs); + // Store the pointer for testing. We are sure it is valid. + MockVehicleHardware* hardwarePtr = hardware.get(); auto vhal = ndk::SharedRefBase::make(std::move(hardware)); std::shared_ptr client = IVehicle::fromBinder(vhal->asBinder()); @@ -658,6 +660,7 @@ TEST_F(DefaultVehicleHalTest, testGetPropConfigs) { ASSERT_TRUE(status.isOk()) << "getPropConfigs failed: " << status.getMessage(); ASSERT_EQ(output.payloads, testConfigs); + ASSERT_FALSE(hardwarePtr->getAllPropertyConfigsCalled()); } TEST_F(DefaultVehicleHalTest, testGetPropConfigsInvalidArg) { @@ -704,6 +707,34 @@ TEST_F(DefaultVehicleHalTest, testGetValuesSmall) { ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback"; EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch"; EXPECT_EQ(countClients(), static_cast(1)); + ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled()); +} + +TEST_F(DefaultVehicleHalTest, testGetValuesSmall_AfterGetAllPropConfigs) { + GetValueRequests requests; + std::vector expectedResults; + std::vector expectedHardwareRequests; + + // If we already called getAllPropConfigs, the configs will be cached. + VehiclePropConfigs output; + getClient()->getAllPropConfigs(&output); + + ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok()); + + getHardware()->addGetValueResponses(expectedResults); + + auto status = getClient()->getValues(getCallbackClient(), requests); + + ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage(); + + EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests) + << "requests to hardware mismatch"; + + auto maybeGetValueResults = getCallback()->nextGetValueResults(); + ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback"; + EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch"; + EXPECT_EQ(countClients(), static_cast(1)); + ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled()); } TEST_F(DefaultVehicleHalTest, testGetValuesLarge) { @@ -1016,6 +1047,34 @@ TEST_F(DefaultVehicleHalTest, testSetValuesSmall) { ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback"; ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch"; EXPECT_EQ(countClients(), static_cast(1)); + ASSERT_FALSE(getHardware()->getAllPropertyConfigsCalled()); +} + +TEST_F(DefaultVehicleHalTest, testSetValuesSmall_AfterGetAllPropConfigs) { + SetValueRequests requests; + std::vector expectedResults; + std::vector expectedHardwareRequests; + + // If we already called getAllPropConfigs, the configs will be cached. + VehiclePropConfigs output; + getClient()->getAllPropConfigs(&output); + + ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok()); + + getHardware()->addSetValueResponses(expectedResults); + + auto status = getClient()->setValues(getCallbackClient(), requests); + + ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage(); + + EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests) + << "requests to hardware mismatch"; + + auto maybeSetValueResults = getCallback()->nextSetValueResults(); + ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback"; + ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch"; + EXPECT_EQ(countClients(), static_cast(1)); + ASSERT_TRUE(getHardware()->getAllPropertyConfigsCalled()); } TEST_F(DefaultVehicleHalTest, testSetValuesLarge) { diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp index db15c8942f..e796ce56f5 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp @@ -45,9 +45,20 @@ MockVehicleHardware::~MockVehicleHardware() { std::vector MockVehicleHardware::getAllPropertyConfigs() const { std::scoped_lock lockGuard(mLock); + mGetAllPropertyConfigsCalled = true; return mPropertyConfigs; } +std::optional MockVehicleHardware::getPropertyConfig(int32_t propId) const { + std::scoped_lock lockGuard(mLock); + for (const auto& config : mPropertyConfigs) { + if (config.prop == propId) { + return config; + } + } + return std::nullopt; +} + StatusCode MockVehicleHardware::setValues(std::shared_ptr callback, const std::vector& requests) { std::scoped_lock lockGuard(mLock); @@ -336,6 +347,11 @@ void MockVehicleHardware::sendOnPropertySetErrorEvent( (*mPropertySetErrorCallback)(errorEvents); } +bool MockVehicleHardware::getAllPropertyConfigsCalled() { + std::scoped_lock lockGuard(mLock); + return mGetAllPropertyConfigsCalled; +} + } // namespace vehicle } // namespace automotive } // namespace hardware diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h index eeca582fa4..06e01a8ec0 100644 --- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h +++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h @@ -47,6 +47,8 @@ class MockVehicleHardware final : public IVehicleHardware { std::vector getAllPropertyConfigs() const override; + std::optional + getPropertyConfig(int32_t propId) const override; aidl::android::hardware::automotive::vehicle::StatusCode setValues( std::shared_ptr callback, const std::vector& @@ -98,6 +100,9 @@ class MockVehicleHardware final : public IVehicleHardware { std::vector getSubscribeOptions(); void clearSubscribeOptions(); + // Whether getAllPropertyConfigs() has been called, which blocks all all property configs + // being ready. + bool getAllPropertyConfigsCalled(); private: mutable std::mutex mLock; @@ -143,6 +148,8 @@ class MockVehicleHardware final : public IVehicleHardware { DumpResult mDumpResult; + mutable bool mGetAllPropertyConfigsCalled GUARDED_BY(mLock) = false; + // RecurrentTimer is thread-safe. std::shared_ptr mRecurrentTimer; std::unordered_map>>> diff --git a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java index bea5951bfb..7f4ceb8e66 100644 --- a/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java +++ b/automotive/vehicle/tools/generate_emu_metadata/src/com/android/car/tool/EmuMetadataGenerator.java @@ -79,17 +79,18 @@ public final class EmuMetadataGenerator { + "either this or input_files must be specified\n" + INPUT_FILES_OPTION + ": one or more Java files, this is used to decide the input " + "directory\n" + PACKAGE_NAME_OPTION - + ": the optional package name for the interface, by default is " + DEFAULT_PACKAGE_NAME - + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n" + OUTPUT_EMPTY_FILE_OPTION - + ": Only used for check_mode, this file will be created if " + + ": the optional package name for the interface, by default is " + + DEFAULT_PACKAGE_NAME + "\n" + OUTPUT_JSON_OPTION + ": The output JSON file\n" + + OUTPUT_EMPTY_FILE_OPTION + ": Only used for check_mode, this file will be created if " + "check passed\n" + CHECK_AGAINST_OPTION + ": An optional JSON file to check against. If specified, the " - + "generated output file will be checked against this file, if they are not the same, " + + ("generated output file will be checked against this file, if they are not the " + + "same, ") + "the script will fail, otherwise, the output_empty_file will be created\n" + "For example: \n" + "EnumMetadataGenerator --input_dir out/soong/.intermediates/hardware/" + "interfaces/automotive/vehicle/aidl_property/android.hardware.automotive.vehicle." - + "property-V3-java-source/gen/ --package_name android.hardware.automotive.vehicle " + + "property-V4-java-source/gen/ --package_name android.hardware.automotive.vehicle " + "--output_json /tmp/android.hardware.automotive.vehicle-types-meta.json"; private static final String VEHICLE_PROPERTY_FILE = "VehicleProperty.java"; private static final String CHECK_FILE_PATH = diff --git a/automotive/vehicle/vhal_static_cpp_lib.mk b/automotive/vehicle/vhal_static_cpp_lib.mk index 6b3d4866f8..9371453b37 100644 --- a/automotive/vehicle/vhal_static_cpp_lib.mk +++ b/automotive/vehicle/vhal_static_cpp_lib.mk @@ -17,4 +17,4 @@ LOCAL_STATIC_LIBRARIES += \ android.hardware.automotive.vehicle-V3-ndk \ - android.hardware.automotive.vehicle.property-V3-ndk + android.hardware.automotive.vehicle.property-V4-ndk diff --git a/automotive/vehicle/vts/Android.bp b/automotive/vehicle/vts/Android.bp index 303e5a6249..d55dc336fc 100644 --- a/automotive/vehicle/vts/Android.bp +++ b/automotive/vehicle/vts/Android.bp @@ -44,7 +44,7 @@ cc_test { "vhalclient_defaults", ], header_libs: [ - "IVehicleGeneratedHeaders-V3", + "IVehicleGeneratedHeaders-V4", ], test_suites: [ "general-tests", diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp index 4afecb4000..8c9a3572a9 100644 --- a/biometrics/common/aidl/Android.bp +++ b/biometrics/common/aidl/Android.bp @@ -22,6 +22,12 @@ aidl_interface { cpp: { enabled: false, }, + ndk: { + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], + }, rust: { enabled: true, }, diff --git a/biometrics/common/config/Android.bp b/biometrics/common/config/Android.bp index d38ffe861c..b86aafa513 100644 --- a/biometrics/common/config/Android.bp +++ b/biometrics/common/config/Android.bp @@ -22,7 +22,7 @@ cc_library { // SPDX-license-identifier-Apache-2.0 name: "android.hardware.biometrics.common.config", export_include_dirs: ["include"], - vendor: true, + vendor_available: true, srcs: [ "Config.cpp", ], @@ -30,6 +30,10 @@ cc_library { "libbase", "libbinder_ndk", ], + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], } cc_test_host { diff --git a/biometrics/common/config/include/config/Config.h b/biometrics/common/config/include/config/Config.h index 0367832f7d..b1affdc435 100644 --- a/biometrics/common/config/include/config/Config.h +++ b/biometrics/common/config/include/config/Config.h @@ -100,7 +100,11 @@ class Config { } else if (std::holds_alternative(v)) { for (auto x : std::get(v)) if (x.has_value()) os << x.value() << " "; + } else if (std::holds_alternative(v)) { + OptString ov = std::get(v); + if (ov.has_value()) os << ov.value(); } + return os.str(); } std::string toString() const { diff --git a/biometrics/common/thread/Android.bp b/biometrics/common/thread/Android.bp index e7a7e4c98a..c1ebe3b155 100644 --- a/biometrics/common/thread/Android.bp +++ b/biometrics/common/thread/Android.bp @@ -10,10 +10,14 @@ cc_library { // SPDX-license-identifier-Apache-2.0 name: "android.hardware.biometrics.common.thread", export_include_dirs: ["include"], - vendor: true, + vendor_available: true, srcs: [ "WorkerThread.cpp", ], + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], } cc_test_host { diff --git a/biometrics/common/util/Android.bp b/biometrics/common/util/Android.bp index 599c491772..a0bd211b87 100644 --- a/biometrics/common/util/Android.bp +++ b/biometrics/common/util/Android.bp @@ -6,7 +6,7 @@ cc_library { // SPDX-license-identifier-Apache-2.0 name: "android.hardware.biometrics.common.util", export_include_dirs: ["include"], - vendor: true, + vendor_available: true, srcs: [ "CancellationSignal.cpp", ], @@ -15,4 +15,8 @@ cc_library { "libbinder_ndk", "android.hardware.biometrics.common-V4-ndk", ], + apex_available: [ + "//apex_available:anyapex", + "//apex_available:platform", + ], } diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp index fadcde7892..54d01a7231 100644 --- a/biometrics/face/aidl/Android.bp +++ b/biometrics/face/aidl/Android.bp @@ -11,7 +11,7 @@ aidl_interface { name: "android.hardware.biometrics.face", vendor_available: true, srcs: [ - "android/hardware/biometrics/face/**/*.aidl", + "android/hardware/biometrics/face/*.aidl", ], imports: [ "android.hardware.biometrics.common-V4", @@ -36,6 +36,10 @@ aidl_interface { additional_shared_libraries: [ "libnativewindow", ], + apex_available: [ + "//apex_available:platform", + "com.android.hardware.biometrics.face.virtual", + ], }, }, versions_with_info: [ @@ -74,5 +78,39 @@ aidl_interface { ], frozen: true, - +} + +aidl_interface { + name: "android.hardware.biometrics.face.virtualhal", + srcs: [ + "android/hardware/biometrics/face/virtualhal/*.aidl", + ], + imports: [ + "android.hardware.biometrics.common-V4", + "android.hardware.keymaster-V4", + "android.hardware.biometrics.face-V4", + ], + vendor_available: true, + unstable: true, + backend: { + java: { + platform_apis: true, + }, + rust: { + enabled: false, + }, + cpp: { + enabled: false, + }, + ndk: { + additional_shared_libraries: [ + "libnativewindow", + ], + apex_available: [ + "com.android.hardware.biometrics.face.virtual", + "//apex_available:platform", + ], + }, + }, + frozen: false, } diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl index 26cb361482..0dbf0522f0 100644 --- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl +++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl @@ -73,7 +73,7 @@ interface ISession { * Note that this interface allows multiple in-flight challenges. Invoking generateChallenge * twice does not invalidate the first challenge. The challenge is invalidated only when: * 1) Its lifespan exceeds the challenge timeout defined in the TEE. - * 2) IFingerprint#revokeChallenge is invoked + * 2) IFace#revokeChallenge is invoked * * For example, the following is a possible table of valid challenges: * ---------------------------------------------- diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl new file mode 100644 index 0000000000..a25412043a --- /dev/null +++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.biometrics.face.virtualhal; + +import android.hardware.biometrics.face.AcquiredInfo; + +/** + * @hide + */ +union AcquiredInfoAndVendorCode { + /** + * Acquired info as specified in AcqauiredInfo.aidl + */ + AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN; + + /** + * Vendor specific code + */ + int vendorCode; +} diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl new file mode 100644 index 0000000000..7fbcf5d7bc --- /dev/null +++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.biometrics.face.virtualhal; + +import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode; + +/** + * @hide + */ +parcelable EnrollmentProgressStep { + /** + * The duration of the enrollment step in milli-seconds + */ + int durationMs; + + /** + * The sequence of acquired info and vendor code to be issued by HAL during the step. + * The codes are evenly spread over the duration + */ + AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes; +} diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl new file mode 100644 index 0000000000..1d3d934439 --- /dev/null +++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.biometrics.face.virtualhal; + +import android.hardware.biometrics.common.SensorStrength; +import android.hardware.biometrics.face.FaceSensorType; +import android.hardware.biometrics.face.IFace; +import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode; +import android.hardware.biometrics.face.virtualhal.NextEnrollment; + +/** + * @hide + */ +interface IVirtualHal { + /** + * The operation failed due to invalid input parameters, the error messages should + * gives more details + */ + const int STATUS_INVALID_PARAMETER = 1; + + /** + * Set Face Virtual HAL behavior parameters + */ + + /** + * setEnrollments + * + * Set the ids of the faces that were currently enrolled in the Virtual HAL, + * + * @param ids ids can contain 1 or more ids, each must be larger than 0 + */ + void setEnrollments(in int[] id); + + /** + * setEnrollmentHit + * + * Set current face enrollment ids in Face Virtual HAL, + * + * @param ids ids can contain 1 or more ids, each must be larger than 0 + */ + void setEnrollmentHit(in int hit_id); + + /** + * setNextEnrollment + * + * Set the next enrollment behavior + * + * @param next_enrollment specifies enrollment id, progress stages and final result + */ + void setNextEnrollment(in NextEnrollment next_enrollment); + + /** + * setAuthenticatorId + * + * Set authenticator id in virtual HAL, the id is returned in ISession#AuthenticatorId() call + * + * @param id authenticator id value, only applied to the sensor with SensorStrength::STRONG. + */ + void setAuthenticatorId(in long id); + + /** + * setChallenge + * + * Set the challenge generated by the virtual HAL, which is returned in + * ISessionCallback#onChallengeGenerated() + * + * @param challenge + */ + void setChallenge(in long challenge); + + /** + * setOperationAuthenticateFails + * + * Set whether to force authentication to fail. If true, the virtual hal will report failure on + * authentication attempt until it is set to false + * + * @param fail if true, then the next authentication will fail + */ + void setOperationAuthenticateFails(in boolean fail); + + /** + * setOperationAuthenticateLatency + * + * Set authentication latency in the virtual hal in a fixed value (single element) or random + * values (two elements representing the bound values) + * The latency simulates the delay from the time framework requesting HAL to authetication to + * the time when HAL is ready to perform authentication operations. + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of + * the following conditions + * 1. the array contains no element + * 2. the array contains more than two elements + * 3. the array contains any negative value + * The accompanying error message gives more detail + * + * @param latencyMs[] value(s) are in milli-seconds + */ + void setOperationAuthenticateLatency(in int[] latencyMs); + + /** + * setOperationAuthenticateDuration + * + * Set authentication duration covering the HAL authetication from start to end, including + * face capturing, and matching, acquired info reporting. In case a sequence of acquired + * info code are specified via setOperationAuthenticateAcquired(), the reporting is evenly + * distributed over the duration. + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative + * + * @param duration value is in milli-seconds + */ + void setOperationAuthenticateDuration(in int durationMs); + + /** + * setOperationAuthenticateError + * + * Force authentication to error out for non-zero error + * Check + * hardware/interfaces/biometrics/face/aidl/default/aidl/android/hardware/biometrics/face/Error.aidl + * for valid error codes + * + * @param error if error < 1000 + * non-vendor error + * else + * vendor error + */ + void setOperationAuthenticateError(in int error); + + /** + * setOperationAuthenticateAcquired + * + * Set one of more acquired info codes for the virtual hal to report during authentication + * Check + * hardware/interfaces/biometrics/face/aidl/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl + * for valid acquired info codes + * + * @param acquired[], one or more acquired info codes + */ + void setOperationAuthenticateAcquired(in AcquiredInfoAndVendorCode[] acquired); + + /** + * setOperationEnrollLatency + * + * Set enrollment latency in the virtual hal in a fixed value (single element) or random + * values (two elements representing the bound values) + * The latency simulates the delay from the time framework requesting HAL to enroll to the + * time when HAL is ready to perform enrollment operations. + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of + * the following conditions + * 1. the array contains no element + * 2. the array contains more than two elements + * 3. the array contains any negative value + * The accompanying error message gives more detail + * + * @param latencyMs[] value(s) are in milli-seconds + */ + void setOperationEnrollLatency(in int[] latencyMs); + + /** + * setOperationDetectInteractionLatency + * + * Set detect interaction latency in the virtual hal in a fixed value (single element) or random + * values (two elements representing the bound values) + * The latency simulates the delay from the time framework requesting HAL to detect interaction + * to the time when HAL is ready to perform detect interaction operations. + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of + * the following conditions + * 1. the array contains no element + * 2. the array contains more than two elements + * 3. the array contains any negative value + * The accompanying error message gives more detail + * + * @param latencyMs[] value(s) are in milli-seconds + */ + void setOperationDetectInteractionLatency(in int[] latencyMs); + + /** + * setOperationDetectInteractionFails + * + * Force detect interaction operation to fail + */ + void setOperationDetectInteractionFails(in boolean error); + + /** + * setLockout + * + * Whether to force to lockout on authentcation operation. If true, the virtual hal will report + * permanent lockout in processing authentication requrest, regardless of whether + * setLockoutEnable(true) is called or not. + * + * @param lockout, set to true if lockout is desired + */ + void setLockout(in boolean lockout); + + /** + * setLockoutEnable + * + * Whether to enable authentication-fail-based lockout tracking or not. The lock tracking + * includes both timed-based (aka temporary) lockout and permanent lockout. + * + * @param enable, set true to enable the lockout tracking + */ + void setLockoutEnable(in boolean enable); + + /** + * setLockoutTimedEnable + * + * Whether to enable authentication-fail-based time-based-lockout tracking or not. + * + * @param enable, set true to enable the time-basedlockout tracking + */ + void setLockoutTimedEnable(in boolean enable); + + /** + * setLockoutTimedThreshold + * + * Set the number of consecutive authentication failures that triggers the timed-based lock to + * occur + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative + * + * @param threshold, the number of consecutive failures + */ + void setLockoutTimedThreshold(in int threshold); + + /** + * setLockoutTimedDuration + * + * Set the duration to expire timed-based lock during which there is no authentication failure + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative + * + * @param duration, in milli-seconds + */ + void setLockoutTimedDuration(in int durationMs); + + /** + * setLockoutPermanentThreshold + * + * Set the number of consecutive authentication failures that triggers the permanent lock to + * occur + * + * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative + * + * @param threshold, the number of consecutive failures + */ + void setLockoutPermanentThreshold(in int threshold); + + /** + * resetConfigurations + * + * Reset all virtual hal configurations to default values + */ + void resetConfigurations(); + + /** + * setType + * + * Configure virtual face sensor type + * + * @param type, sensor type as specified in FaceSensorType.aidl + * + */ + void setType(in FaceSensorType type); + + /** + * setSensorStrength + * + * Configure virtual face sensor strength + * + * @param sensor strength as specified in common/SensorStrength.aidl + */ + void setSensorStrength(in SensorStrength strength); + + /** + * getFaceHal + * + * @return IFace interface associated with IVirtualHal instance + */ + IFace getFaceHal(); +} diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl similarity index 87% rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl rename to biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl index 4b50850696..d3547a8f74 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/NextEnrollment.aidl +++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl @@ -14,12 +14,11 @@ * limitations under the License. */ -package android.hardware.biometrics.fingerprint; +package android.hardware.biometrics.face.virtualhal; /** * @hide */ -@VintfStability parcelable NextEnrollment { /** * Identifier of the next enrollment if successful @@ -31,7 +30,7 @@ parcelable NextEnrollment { * and sequence of acquired info codes to be generated by HAL. * See EnrollmentProgressStep.aidl for more details */ - android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps; + android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep[] progressSteps; /** * Success or failure of the next enrollment diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md new file mode 100644 index 0000000000..bf1a4b18e4 --- /dev/null +++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md @@ -0,0 +1,3 @@ +The aidl files in this directory are used to control/configure face virtual hal +via IVirtualHal interface + diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp index 685639c15e..bed040569f 100644 --- a/biometrics/face/aidl/default/Android.bp +++ b/biometrics/face/aidl/default/Android.bp @@ -9,21 +9,13 @@ package { } filegroup { - name: "face-example.rc", - srcs: ["face-example.rc"], + name: "face-virtual.rc", + srcs: ["face-virtual.rc"], } -filegroup { - name: "face-example.xml", - srcs: ["face-example.xml"], -} - -cc_binary { - name: "android.hardware.biometrics.face-service.example", - relative_install_path: "hw", - init_rc: [":face-example.rc"], - vintf_fragments: [":face-example.xml"], - vendor: true, +cc_library_static { + name: "android.hardware.biometrics.face-service.lib", + vendor_available: true, shared_libs: [ "libbinder_ndk", @@ -32,32 +24,80 @@ cc_binary { ], srcs: [ "FakeLockoutTracker.cpp", - "main.cpp", "Face.cpp", "FakeFaceEngine.cpp", "Session.cpp", + "FaceConfig.cpp", + "VirtualHal.cpp", + "main.cpp", ], include_dirs: [ "frameworks/native/aidl/gui", ], stl: "c++_static", - static_libs: [ + whole_static_libs: [ "android.hardware.biometrics.common-V4-ndk", + "android.hardware.biometrics.common.config", "android.hardware.biometrics.common.thread", "android.hardware.biometrics.common.util", + "android.hardware.biometrics.face.virtualhal-ndk", "android.hardware.biometrics.face-V4-ndk", "android.hardware.common-V2-ndk", "android.hardware.keymaster-V4-ndk", "libandroid.hardware.biometrics.face.VirtualProps", "libbase", ], + apex_available: [ + "com.android.hardware.biometrics.face.virtual", + "//apex_available:platform", + ], +} + +cc_binary { + name: "android.hardware.biometrics.face-service.example", + system_ext_specific: true, + relative_install_path: "hw", + + shared_libs: [ + "libbinder_ndk", + "liblog", + "libnativewindow", + ], + whole_static_libs: [ + "android.hardware.biometrics.face-service.lib", + ], + installable: false, // install APEX instead + apex_available: [ + "com.android.hardware.biometrics.face.virtual", + "//apex_available:platform", + ], +} + +cc_binary { + name: "android.hardware.biometrics.face-service.default", + vendor: true, + relative_install_path: "hw", + init_rc: ["face-default.rc"], + vintf_fragments: ["face-default.xml"], + shared_libs: [ + "libbinder_ndk", + "liblog", + "libnativewindow", + ], + whole_static_libs: [ + "android.hardware.biometrics.face-service.lib", + ], } sysprop_library { name: "android.hardware.biometrics.face.VirtualProps", srcs: ["face.sysprop"], - property_owner: "Vendor", - vendor: true, + property_owner: "Platform", + vendor_available: true, + apex_available: [ + "//apex_available:platform", + "com.android.hardware.biometrics.face.virtual", + ], } cc_test { @@ -66,6 +106,7 @@ cc_test { "tests/FakeFaceEngineTest.cpp", "FakeFaceEngine.cpp", "FakeLockoutTracker.cpp", + "FaceConfig.cpp", ], shared_libs: [ "libbase", @@ -81,6 +122,8 @@ cc_test { "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", + "android.hardware.biometrics.common.config", + "android.hardware.biometrics.common.thread", ], vendor: true, test_suites: ["general-tests"], @@ -92,6 +135,7 @@ cc_test { srcs: [ "tests/FakeLockoutTrackerTest.cpp", "FakeLockoutTracker.cpp", + "FaceConfig.cpp", ], shared_libs: [ "libbase", @@ -107,8 +151,45 @@ cc_test { "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", + "android.hardware.biometrics.common.config", + "android.hardware.biometrics.common.thread", ], vendor: true, test_suites: ["general-tests"], require_root: true, } + +cc_test { + name: "android.hardware.biometrics.face.VirtualHalTest", + srcs: [ + "tests/VirtualHalTest.cpp", + "FakeLockoutTracker.cpp", + "Face.cpp", + "FakeFaceEngine.cpp", + "Session.cpp", + "VirtualHal.cpp", + "FaceConfig.cpp", + ], + shared_libs: [ + "libbase", + "libbinder_ndk", + "libnativewindow", + "liblog", + ], + include_dirs: [ + "frameworks/native/aidl/gui", + ], + static_libs: [ + "android.hardware.biometrics.common-V4-ndk", + "android.hardware.biometrics.common.config", + "android.hardware.biometrics.common.thread", + "android.hardware.biometrics.common.util", + "android.hardware.biometrics.face-V4-ndk", + "android.hardware.common-V2-ndk", + "android.hardware.keymaster-V4-ndk", + "libandroid.hardware.biometrics.face.VirtualProps", + "android.hardware.biometrics.face.virtualhal-ndk", + ], + test_suites: ["general-tests"], + require_root: true, +} diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp index 5ae0df6e56..154300759a 100644 --- a/biometrics/face/aidl/default/Face.cpp +++ b/biometrics/face/aidl/default/Face.cpp @@ -34,9 +34,7 @@ using namespace ::android::face::virt; namespace aidl::android::hardware::biometrics::face { const int kSensorId = 4; -const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength(); const int kMaxEnrollmentsPerUser = 5; -const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType(); const bool kHalControlsPreview = true; const std::string kHwComponentId = "faceSensor"; const std::string kHardwareVersion = "vendor/model/revision"; @@ -62,13 +60,13 @@ ndk::ScopedAStatus Face::getSensorProps(std::vector* return_val) { common::CommonProps commonProps; commonProps.sensorId = kSensorId; - commonProps.sensorStrength = kSensorStrength; + commonProps.sensorStrength = FakeFaceEngine::GetSensorStrength(); commonProps.maxEnrollmentsPerUser = kMaxEnrollmentsPerUser; commonProps.componentInfo = {std::move(hw_component_info), std::move(sw_component_info)}; SensorProps props; props.commonProps = std::move(commonProps); - props.sensorType = kSensorType; + props.sensorType = FakeFaceEngine::GetSensorType(); props.halControlsPreview = kHalControlsPreview; props.enrollPreviewWidth = 1080; props.enrollPreviewHeight = 1920; @@ -141,6 +139,30 @@ binder_status_t Face::handleShellCommand(int in, int out, int err, const char** return STATUS_OK; } +const char* Face::type2String(FaceSensorType type) { + switch (type) { + case FaceSensorType::RGB: + return "rgb"; + case FaceSensorType::IR: + return "ir"; + default: + return "unknown"; + } +} + +const char* Face::strength2String(common::SensorStrength strength) { + switch (strength) { + case common::SensorStrength::STRONG: + return "STRONG"; + case common::SensorStrength::WEAK: + return "WEAK"; + case common::SensorStrength::CONVENIENCE: + return "CONVENIENCE"; + default: + return "unknown"; + } +} + void Face::onHelp(int fd) { dprintf(fd, "Virtual Face HAL commands:\n"); dprintf(fd, " help: print this help\n"); @@ -167,7 +189,6 @@ void Face::resetConfigToDefault() { RESET_CONFIG_O(lockout); RESET_CONFIG_O(operation_authenticate_fails); RESET_CONFIG_O(operation_detect_interaction_fails); - RESET_CONFIG_O(operation_enroll_fails); RESET_CONFIG_V(operation_authenticate_latency); RESET_CONFIG_V(operation_detect_interaction_latency); RESET_CONFIG_V(operation_enroll_latency); diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h index 93fddb0474..dbe6341d05 100644 --- a/biometrics/face/aidl/default/Face.h +++ b/biometrics/face/aidl/default/Face.h @@ -17,6 +17,7 @@ #pragma once #include +#include "FaceConfig.h" #include "Session.h" namespace aidl::android::hardware::biometrics::face { @@ -33,9 +34,20 @@ class Face : public BnFace { binder_status_t dump(int fd, const char** args, uint32_t numArgs); binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc); + static FaceConfig& cfg() { + static FaceConfig* cfg = nullptr; + if (cfg == nullptr) { + cfg = new FaceConfig(); + cfg->init(); + } + return *cfg; + } + void resetConfigToDefault(); + static const char* type2String(FaceSensorType type); + static const char* strength2String(common::SensorStrength strength); + private: std::shared_ptr mSession; - void resetConfigToDefault(); void onHelp(int); }; diff --git a/biometrics/face/aidl/default/FaceConfig.cpp b/biometrics/face/aidl/default/FaceConfig.cpp new file mode 100644 index 0000000000..a91d7ccd64 --- /dev/null +++ b/biometrics/face/aidl/default/FaceConfig.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2024 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. + */ + +#define LOG_TAG "FaceConfig" + +#include "FaceConfig.h" + +#include + +#include + +using namespace ::android::face::virt; + +namespace aidl::android::hardware::biometrics::face { + +// Wrapper to system property access functions +#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_) \ + ConfigValue _NAME_##Getter() { \ + return FaceHalProperties::_NAME_(); \ + } \ + bool _NAME_##Setter(const ConfigValue& v) { \ + return FaceHalProperties::_NAME_(std::get<_T_>(v)); \ + } + +CREATE_GETTER_SETTER_WRAPPER(type, OptString) +CREATE_GETTER_SETTER_WRAPPER(enrollments, OptIntVec) +CREATE_GETTER_SETTER_WRAPPER(enrollment_hit, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(next_enrollment, OptString) +CREATE_GETTER_SETTER_WRAPPER(authenticator_id, OptInt64) +CREATE_GETTER_SETTER_WRAPPER(challenge, OptInt64) +CREATE_GETTER_SETTER_WRAPPER(strength, OptString) +CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_fails, OptBool) +CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_latency, OptIntVec) +CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_duration, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_error, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_acquired, OptString) +CREATE_GETTER_SETTER_WRAPPER(operation_enroll_latency, OptIntVec) +CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_fails, OptBool) +CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_latency, OptIntVec) +CREATE_GETTER_SETTER_WRAPPER(lockout, OptBool) +CREATE_GETTER_SETTER_WRAPPER(lockout_enable, OptBool) +CREATE_GETTER_SETTER_WRAPPER(lockout_timed_enable, OptBool) +CREATE_GETTER_SETTER_WRAPPER(lockout_timed_threshold, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(lockout_timed_duration, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(lockout_permanent_threshold, OptInt32) +CREATE_GETTER_SETTER_WRAPPER(features, OptIntVec) + +// Name, Getter, Setter, Parser and default value +#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter +static Config::Data configData[] = { + {NGS(type), &Config::parseString, "rgb"}, + {NGS(enrollments), &Config::parseIntVec, ""}, + {NGS(enrollment_hit), &Config::parseInt32, "0"}, + {NGS(next_enrollment), &Config::parseString, + "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"}, + {NGS(authenticator_id), &Config::parseInt64, "0"}, + {NGS(challenge), &Config::parseInt64, ""}, + {NGS(strength), &Config::parseString, "strong"}, + {NGS(operation_authenticate_fails), &Config::parseBool, "false"}, + {NGS(operation_authenticate_latency), &Config::parseIntVec, ""}, + {NGS(operation_authenticate_duration), &Config::parseInt32, "500"}, + {NGS(operation_authenticate_error), &Config::parseInt32, "0"}, + {NGS(operation_authenticate_acquired), &Config::parseString, ""}, + {NGS(operation_enroll_latency), &Config::parseIntVec, ""}, + {NGS(operation_detect_interaction_latency), &Config::parseIntVec, ""}, + {NGS(operation_detect_interaction_fails), &Config::parseBool, "false"}, + {NGS(lockout), &Config::parseBool, "false"}, + {NGS(lockout_enable), &Config::parseBool, "false"}, + {NGS(lockout_timed_enable), &Config::parseBool, "false"}, + {NGS(lockout_timed_threshold), &Config::parseInt32, "3"}, + {NGS(lockout_timed_duration), &Config::parseInt32, "10000"}, + {NGS(lockout_permanent_threshold), &Config::parseInt32, "5"}, + {NGS(features), &Config::parseIntVec, ""}}; + +Config::Data* FaceConfig::getConfigData(int* size) { + *size = sizeof(configData) / sizeof(configData[0]); + return configData; +} + +} // namespace aidl::android::hardware::biometrics::face diff --git a/biometrics/face/aidl/default/FaceConfig.h b/biometrics/face/aidl/default/FaceConfig.h new file mode 100644 index 0000000000..64b62e002d --- /dev/null +++ b/biometrics/face/aidl/default/FaceConfig.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 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 "config/Config.h" + +namespace aidl::android::hardware::biometrics::face { + +class FaceConfig : public Config { + Config::Data* getConfigData(int* size) override; +}; + +} // namespace aidl::android::hardware::biometrics::face diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp index bf75874aea..70d9f2df70 100644 --- a/biometrics/face/aidl/default/FakeFaceEngine.cpp +++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp @@ -23,6 +23,7 @@ #include +#include "Face.h" #include "util/CancellationSignal.h" #include "util/Util.h" @@ -31,23 +32,23 @@ using namespace ::android::face::virt; namespace aidl::android::hardware::biometrics::face { FaceSensorType FakeFaceEngine::GetSensorType() { - std::string type = FaceHalProperties::type().value_or(""); + std::string type = Face::cfg().get("type"); if (type == "IR") { return FaceSensorType::IR; } else { - FaceHalProperties::type("RGB"); + Face::cfg().set("type", "RGB"); return FaceSensorType::RGB; } } common::SensorStrength FakeFaceEngine::GetSensorStrength() { - std::string strength = FaceHalProperties::strength().value_or(""); + std::string strength = Face::cfg().get("strength"); if (strength == "convenience") { return common::SensorStrength::CONVENIENCE; } else if (strength == "weak") { return common::SensorStrength::WEAK; } else { - FaceHalProperties::strength("strong"); + // Face::cfg().set("strength", "strong"); return common::SensorStrength::STRONG; } } @@ -56,13 +57,13 @@ void FakeFaceEngine::generateChallengeImpl(ISessionCallback* cb) { BEGIN_OP(0); std::uniform_int_distribution dist; auto challenge = dist(mRandom); - FaceHalProperties::challenge(challenge); + Face::cfg().set("challenge", challenge); cb->onChallengeGenerated(challenge); } void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) { BEGIN_OP(0); - FaceHalProperties::challenge({}); + Face::cfg().set("challenge", 0); cb->onChallengeRevoked(challenge); } void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/, @@ -71,7 +72,7 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA EnrollmentType /*enrollmentType*/, const std::vector& /*features*/, const std::future& cancel) { - BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency())); + BEGIN_OP(getLatency(Face::cfg().getopt("operation_enroll_latency"))); // Do proper HAT verification in the real implementation. if (hat.mac.empty()) { @@ -80,18 +81,19 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA return; } - // Format: : - // ------:-----------------------------------------:-------------- - // | | |--->enrollment success (true/false) - // | |--> progress_steps + // Format: + // : + // -------:--------------------------------------------------:-------------- + // | | |--->enrollment + // success (true/false) | |--> progress_steps // | // |-->enrollment id // // - // progress_steps + // progress_steps: // -[acquiredInfo,...]+ // ---------------------------- --------------------- - // | |-> sequence of acquiredInfo code + // | |-> sequence of acquiredInfo code // | --> time duration of the step in ms // // E.g. 1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true @@ -101,7 +103,7 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA // std::string defaultNextEnrollment = "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"; - auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment); + auto nextEnroll = Face::cfg().get("next_enrollment"); auto parts = Util::split(nextEnroll, ":"); if (parts.size() != 3) { LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll; @@ -137,19 +139,19 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA if (left == 0 && !IS_TRUE(parts[2])) { // end and failed LOG(ERROR) << "Fail: requested by caller: " << nextEnroll; - FaceHalProperties::next_enrollment({}); + Face::cfg().setopt("next_enrollment", std::nullopt); cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */); } else { // progress and update props if last time LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left; if (left == 0) { - auto enrollments = FaceHalProperties::enrollments(); + auto enrollments = Face::cfg().getopt("enrollments"); enrollments.emplace_back(enrollmentId); - FaceHalProperties::enrollments(enrollments); - FaceHalProperties::next_enrollment({}); + Face::cfg().setopt("enrollments", enrollments); + Face::cfg().setopt("next_enrollment", std::nullopt); // change authenticatorId after new enrollment - auto id = FaceHalProperties::authenticator_id().value_or(0); + auto id = Face::cfg().get("authenticator_id"); auto newId = id + 1; - FaceHalProperties::authenticator_id(newId); + Face::cfg().set("authenticator_id", newId); LOG(INFO) << "Enrolled: " << enrollmentId; } cb->onEnrollmentProgress(enrollmentId, left); @@ -159,10 +161,12 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/, const std::future& cancel) { - BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency())); + BEGIN_OP(getLatency(Face::cfg().getopt("operation_authenticate_latency"))); - auto id = FaceHalProperties::enrollment_hit().value_or(0); - auto enrolls = FaceHalProperties::enrollments(); + // SLEEP_MS(3000); //emulate hw HAL + + auto id = Face::cfg().get("enrollment_hit"); + auto enrolls = Face::cfg().getopt("enrollments"); auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end(); auto vec2str = [](std::vector va) { @@ -192,10 +196,12 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI } int64_t now = Util::getSystemNanoTime(); - int64_t duration = - FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration); - auto acquired = - FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo); + int64_t duration = Face::cfg().get("operation_authenticate_duration"); + auto acquired = Face::cfg().get("operation_authenticate_acquired"); + if (acquired.empty()) { + Face::cfg().set("operation_authenticate_acquired", defaultAcquiredInfo); + acquired = defaultAcquiredInfo; + } auto acquiredInfos = Util::parseIntSequence(acquired); int N = acquiredInfos.size(); @@ -211,21 +217,21 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI int i = 0; do { - if (FaceHalProperties::lockout().value_or(false)) { + if (Face::cfg().get("lockout")) { LOG(ERROR) << "Fail: lockout"; cb->onLockoutPermanent(); cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */); return; } - if (FaceHalProperties::operation_authenticate_fails().value_or(false)) { + if (Face::cfg().get("operation_authenticate_fails")) { LOG(ERROR) << "Fail: operation_authenticate_fails"; mLockoutTracker.addFailedAttempt(cb); cb->onAuthenticationFailed(); return; } - auto err = FaceHalProperties::operation_authenticate_error().value_or(0); + auto err = Face::cfg().get("operation_authenticate_error"); if (err != 0) { LOG(ERROR) << "Fail: operation_authenticate_error"; auto ec = convertError(err); @@ -249,6 +255,15 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second << ")"; i++; + + // the captured face id may change during authentication period + auto idnew = Face::cfg().get("enrollment_hit"); + if (id != idnew) { + isEnrolled = std::find(enrolls.begin(), enrolls.end(), idnew) != enrolls.end(); + LOG(INFO) << "enrollment_hit changed from " << id << " to " << idnew; + id = idnew; + break; + } } SLEEP_MS(duration / N); @@ -292,9 +307,9 @@ std::pair FakeFaceEngine::convertError(int32_t code) { } void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future& cancel) { - BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency())); + BEGIN_OP(getLatency(Face::cfg().getopt("operation_detect_interaction_latency"))); - if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) { + if (Face::cfg().get("operation_detect_interaction_fails")) { LOG(ERROR) << "Fail: operation_detect_interaction_fails"; cb->onError(Error::VENDOR, 0 /* vendorError */); return; @@ -306,8 +321,8 @@ void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::futu return; } - auto id = FaceHalProperties::enrollment_hit().value_or(0); - auto enrolls = FaceHalProperties::enrollments(); + auto id = Face::cfg().get("enrollment_hit"); + auto enrolls = Face::cfg().getopt("enrollments"); auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end(); if (id <= 0 || !isEnrolled) { LOG(ERROR) << "Fail: not enrolled"; @@ -321,7 +336,7 @@ void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::futu void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) { BEGIN_OP(0); std::vector enrollments; - for (const auto& enrollmentId : FaceHalProperties::enrollments()) { + for (const auto& enrollmentId : Face::cfg().getopt("enrollments")) { if (enrollmentId) { enrollments.push_back(*enrollmentId); } @@ -334,20 +349,20 @@ void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb, BEGIN_OP(0); std::vector> newEnrollments; - for (const auto& enrollment : FaceHalProperties::enrollments()) { + for (const auto& enrollment : Face::cfg().getopt("enrollments")) { auto id = enrollment.value_or(0); if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) { newEnrollments.emplace_back(id); } } - FaceHalProperties::enrollments(newEnrollments); + Face::cfg().setopt("enrollments", newEnrollments); cb->onEnrollmentsRemoved(enrollmentIds); } void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) { BEGIN_OP(0); - if (FaceHalProperties::enrollments().empty()) { + if (Face::cfg().getopt("enrollments").empty()) { cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */); return; } @@ -365,7 +380,7 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw Feature feature, bool enabled) { BEGIN_OP(0); - if (FaceHalProperties::enrollments().empty()) { + if (Face::cfg().getopt("enrollments").empty()) { LOG(ERROR) << "Unable to set feature, enrollments are empty"; cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */); return; @@ -377,7 +392,7 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw return; } - auto features = FaceHalProperties::features(); + auto features = Face::cfg().getopt("features"); auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) { return *theFeature == (int)feature; @@ -389,7 +404,7 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw features.push_back((int)feature); } - FaceHalProperties::features(features); + Face::cfg().setopt("features", features); cb->onFeatureSet(feature); } @@ -399,22 +414,22 @@ void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) { if (GetSensorStrength() != common::SensorStrength::STRONG) { cb->onAuthenticatorIdRetrieved(0); } else { - cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0)); + cb->onAuthenticatorIdRetrieved(Face::cfg().get("authenticator_id")); } } void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) { BEGIN_OP(0); - int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0); + int64_t authenticatorId = Face::cfg().get("authenticator_id"); int64_t newId = authenticatorId + 1; - FaceHalProperties::authenticator_id(newId); + Face::cfg().set("authenticator_id", newId); cb->onAuthenticatorIdInvalidated(newId); } void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/) { BEGIN_OP(0); - FaceHalProperties::lockout(false); + Face::cfg().set("lockout", false); mLockoutTracker.reset(); cb->onLockoutCleared(); } diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.cpp b/biometrics/face/aidl/default/FakeLockoutTracker.cpp index 70bf08ee21..35d7c28393 100644 --- a/biometrics/face/aidl/default/FakeLockoutTracker.cpp +++ b/biometrics/face/aidl/default/FakeLockoutTracker.cpp @@ -19,6 +19,7 @@ #include "FakeLockoutTracker.h" #include #include +#include "Face.h" #include "util/Util.h" using namespace ::android::face::virt; @@ -36,15 +37,15 @@ void FakeLockoutTracker::reset(bool dueToTimerExpire) { } void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) { - bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false); - bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false); + bool lockoutEnabled = Face::cfg().get("lockout_enable"); + bool timedLockoutenabled = Face::cfg().get("lockout_timed_enable"); if (lockoutEnabled) { mFailedCount++; mTimedFailedCount++; mLastFailedTime = Util::getSystemNanoTime(); - int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3); + int32_t lockoutTimedThreshold = Face::cfg().get("lockout_timed_threshold"); int32_t lockoutPermanetThreshold = - FaceHalProperties::lockout_permanent_threshold().value_or(5); + Face::cfg().get("lockout_permanent_threshold"); if (mFailedCount >= lockoutPermanetThreshold) { mCurrentMode = LockoutMode::kPermanent; LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent"; @@ -68,7 +69,7 @@ FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() { } int32_t FakeLockoutTracker::getTimedLockoutDuration() { - return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000); + return Face::cfg().get("lockout_timed_duration"); } int64_t FakeLockoutTracker::getLockoutTimeLeft() { diff --git a/biometrics/face/aidl/default/VirtualHal.cpp b/biometrics/face/aidl/default/VirtualHal.cpp new file mode 100644 index 0000000000..52ac23bd59 --- /dev/null +++ b/biometrics/face/aidl/default/VirtualHal.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2024 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. + */ + +#include + +#include "VirtualHal.h" + +#include + +#include "util/CancellationSignal.h" + +#undef LOG_TAG +#define LOG_TAG "FaceVirtualHalAidl" + +namespace aidl::android::hardware::biometrics::face { +using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode; +using Tag = AcquiredInfoAndVendorCode::Tag; + +::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector& enrollments) { + Face::cfg().sourcedFromAidl(); + Face::cfg().setopt("enrollments", intVec2OptIntVec(enrollments)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setEnrollmentHit(int32_t enrollment_hit) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("enrollment_hit", enrollment_hit); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setNextEnrollment( + const ::aidl::android::hardware::biometrics::face::NextEnrollment& next_enrollment) { + Face::cfg().sourcedFromAidl(); + std::ostringstream os; + os << next_enrollment.id << ":"; + + int stepSize = next_enrollment.progressSteps.size(); + for (int i = 0; i < stepSize; i++) { + auto& step = next_enrollment.progressSteps[i]; + os << step.durationMs; + int acSize = step.acquiredInfoAndVendorCodes.size(); + for (int j = 0; j < acSize; j++) { + if (j == 0) os << "-["; + auto& acquiredInfoAndVendorCode = step.acquiredInfoAndVendorCodes[j]; + if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::vendorCode) + os << acquiredInfoAndVendorCode.get(); + else if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::acquiredInfo) + os << (int)acquiredInfoAndVendorCode.get(); + else + LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode union tag"; + if (j == acSize - 1) + os << "]"; + else + os << ","; + } + if (i == stepSize - 1) + os << ":"; + else + os << ","; + } + + os << (next_enrollment.result ? "true" : "false"); + Face::cfg().set("next_enrollment", os.str()); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setAuthenticatorId(int64_t in_id) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("authenticator_id", in_id); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setChallenge(int64_t in_challenge) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("challenge", in_challenge); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateFails(bool in_fail) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("operation_authenticate_fails", in_fail); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateLatency( + const std::vector& in_latency) { + ndk::ScopedAStatus status = sanityCheckLatency(in_latency); + if (!status.isOk()) { + return status; + } + + Face::cfg().sourcedFromAidl(); + Face::cfg().setopt("operation_authenticate_latency", intVec2OptIntVec(in_latency)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateDuration(int32_t in_duration) { + if (in_duration < 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative")); + } + Face::cfg().sourcedFromAidl(); + Face::cfg().set("operation_authenticate_duration", in_duration); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateError(int32_t in_error) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("operation_authenticate_error", in_error); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateAcquired( + const std::vector& in_acquired) { + Face::cfg().sourcedFromAidl(); + Face::cfg().setopt("operation_authenticate_acquired", + acquiredInfoVec2OptIntVec(in_acquired)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationEnrollLatency(const std::vector& in_latency) { + ndk::ScopedAStatus status = sanityCheckLatency(in_latency); + if (!status.isOk()) { + return status; + } + Face::cfg().sourcedFromAidl(); + Face::cfg().setopt("operation_enroll_latency", intVec2OptIntVec(in_latency)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionLatency( + const std::vector& in_latency) { + ndk::ScopedAStatus status = sanityCheckLatency(in_latency); + if (!status.isOk()) { + return status; + } + Face::cfg().sourcedFromAidl(); + Face::cfg().setopt("operation_detect_interact_latency", + intVec2OptIntVec(in_latency)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionFails(bool in_fails) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("operation_detect_interaction_fails", in_fails); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockout(bool in_lockout) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout", in_lockout); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockoutEnable(bool in_enable) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout_enable", in_enable); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockoutTimedEnable(bool in_enable) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout_timed_enable", in_enable); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockoutTimedThreshold(int32_t in_threshold) { + if (in_threshold < 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative")); + } + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout_timed_threshold", in_threshold); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockoutTimedDuration(int32_t in_duration) { + if (in_duration < 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative")); + } + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout_timed_duration", in_duration); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setLockoutPermanentThreshold(int32_t in_threshold) { + if (in_threshold < 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative")); + } + Face::cfg().sourcedFromAidl(); + Face::cfg().set("lockout_permanent_threshold", in_threshold); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::resetConfigurations() { + Face::cfg().sourcedFromAidl(); + Face::cfg().init(); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setType( + ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("type", Face::type2String(in_type)); + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::setSensorStrength(common::SensorStrength in_strength) { + Face::cfg().sourcedFromAidl(); + Face::cfg().set("strength", Face::strength2String(in_strength)); + return ndk::ScopedAStatus::ok(); +} + +OptIntVec VirtualHal::intVec2OptIntVec(const std::vector& in_vec) { + OptIntVec optIntVec; + std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec), + [](int value) { return std::optional(value); }); + return optIntVec; +} + +OptIntVec VirtualHal::acquiredInfoVec2OptIntVec( + const std::vector& in_vec) { + OptIntVec optIntVec; + std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec), + [](AcquiredInfoAndVendorCode ac) { + int value; + if (ac.getTag() == AcquiredInfoAndVendorCode::acquiredInfo) + value = (int)ac.get(); + else if (ac.getTag() == AcquiredInfoAndVendorCode::vendorCode) + value = ac.get(); + else + LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode tag"; + return std::optional(value); + }); + return optIntVec; +} + +::ndk::ScopedAStatus VirtualHal::sanityCheckLatency(const std::vector& in_latency) { + if (in_latency.size() == 0 || in_latency.size() > 2) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, + "Error: input input array must contain 1 or 2 elements")); + } + + for (auto x : in_latency) { + if (x < 0) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + IVirtualHal::STATUS_INVALID_PARAMETER, + "Error: input data must not be negative")); + } + } + + return ndk::ScopedAStatus::ok(); +} + +::ndk::ScopedAStatus VirtualHal::getFaceHal(std::shared_ptr* pFace) { + *pFace = mFp; + return ndk::ScopedAStatus::ok(); +} +} // namespace aidl::android::hardware::biometrics::face diff --git a/biometrics/face/aidl/default/VirtualHal.h b/biometrics/face/aidl/default/VirtualHal.h new file mode 100644 index 0000000000..f2ac552a93 --- /dev/null +++ b/biometrics/face/aidl/default/VirtualHal.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 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 + +#include "Face.h" + +namespace aidl::android::hardware::biometrics::face { +using namespace virtualhal; +class VirtualHal : public BnVirtualHal { + public: + VirtualHal(std::shared_ptr fp) : mFp(fp) {} + + ::ndk::ScopedAStatus setEnrollments(const std::vector& in_id) override; + ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override; + ::ndk::ScopedAStatus setNextEnrollment( + const ::aidl::android::hardware::biometrics::face::NextEnrollment& in_next_enrollment) + override; + ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override; + ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override; + ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override; + ::ndk::ScopedAStatus setOperationAuthenticateLatency( + const std::vector& in_latency) override; + ::ndk::ScopedAStatus setOperationAuthenticateDuration(int32_t in_duration) override; + ::ndk::ScopedAStatus setOperationAuthenticateError(int32_t in_error) override; + ::ndk::ScopedAStatus setOperationAuthenticateAcquired( + const std::vector& in_acquired) override; + ::ndk::ScopedAStatus setOperationEnrollLatency(const std::vector& in_latency) override; + ::ndk::ScopedAStatus setOperationDetectInteractionLatency( + const std::vector& in_latency) override; + ::ndk::ScopedAStatus setOperationDetectInteractionFails(bool in_fails) override; + ::ndk::ScopedAStatus setLockout(bool in_lockout) override; + ::ndk::ScopedAStatus setLockoutEnable(bool in_enable) override; + ::ndk::ScopedAStatus setLockoutTimedEnable(bool in_enable) override; + ::ndk::ScopedAStatus setLockoutTimedThreshold(int32_t in_threshold) override; + ::ndk::ScopedAStatus setLockoutTimedDuration(int32_t in_duration) override; + ::ndk::ScopedAStatus setLockoutPermanentThreshold(int32_t in_threshold) override; + ::ndk::ScopedAStatus resetConfigurations() override; + ::ndk::ScopedAStatus setType( + ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) override; + ::ndk::ScopedAStatus setSensorStrength(common::SensorStrength in_strength) override; + ::ndk::ScopedAStatus getFaceHal(std::shared_ptr* _aidl_return); + + private: + OptIntVec intVec2OptIntVec(const std::vector& intVec); + OptIntVec acquiredInfoVec2OptIntVec(const std::vector& intVec); + ::ndk::ScopedAStatus sanityCheckLatency(const std::vector& in_latency); + std::shared_ptr mFp; +}; + +} // namespace aidl::android::hardware::biometrics::face diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp index 86c4e12435..c4632d4404 100644 --- a/biometrics/face/aidl/default/apex/Android.bp +++ b/biometrics/face/aidl/default/apex/Android.bp @@ -23,7 +23,7 @@ apex { key: "com.android.hardware.key", certificate: ":com.android.hardware.certificate", updatable: false, - vendor: true, + system_ext_specific: true, binaries: [ // hal @@ -31,9 +31,7 @@ apex { ], prebuilts: [ // init_rc - "face-example-apex.rc", - // vintf_fragment - "face-example-apex.xml", + "face-virtual-apex.rc", ], overrides: [ @@ -42,21 +40,7 @@ apex { } prebuilt_etc { - name: "face-example-apex.rc", - src: ":gen-face-example-apex.rc", - installable: false, -} - -genrule { - name: "gen-face-example-apex.rc", - srcs: [":face-example.rc"], - out: ["face-example-apex.rc"], - cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face.virtual/bin/@' $(in) > $(out)", -} - -prebuilt_etc { - name: "face-example-apex.xml", - src: ":face-example.xml", - sub_dir: "vintf", + name: "face-virtual-apex.rc", + src: ":face-virtual.rc", installable: false, } diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt index e69de29bb2..6ad579c6ad 100644 --- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt +++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt @@ -0,0 +1,133 @@ +props { + owner: Vendor + module: "android.face.virt.FaceHalProperties" + prop { + api_name: "authenticator_id" + type: Long + access: ReadWrite + prop_name: "vendor.face.virtual.authenticator_id" + } + prop { + api_name: "challenge" + type: Long + access: ReadWrite + prop_name: "vendor.face.virtual.challenge" + } + prop { + api_name: "enrollment_hit" + type: Integer + access: ReadWrite + prop_name: "vendor.face.virtual.enrollment_hit" + } + prop { + api_name: "enrollments" + type: IntegerList + access: ReadWrite + prop_name: "persist.vendor.face.virtual.enrollments" + } + prop { + api_name: "features" + type: IntegerList + access: ReadWrite + prop_name: "persist.vendor.face.virtual.features" + } + prop { + api_name: "lockout" + access: ReadWrite + prop_name: "vendor.face.virtual.lockout" + } + prop { + api_name: "lockout_enable" + access: ReadWrite + prop_name: "persist.vendor.face.virtual.lockout_enable" + } + prop { + api_name: "lockout_permanent_threshold" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold" + } + prop { + api_name: "lockout_timed_duration" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.face.virtual.lockout_timed_duration" + } + prop { + api_name: "lockout_timed_enable" + access: ReadWrite + prop_name: "persist.vendor.face.virtual.lockout_timed_enable" + } + prop { + api_name: "lockout_timed_threshold" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.face.virtual.lockout_timed_threshold" + } + prop { + api_name: "next_enrollment" + type: String + access: ReadWrite + prop_name: "vendor.face.virtual.next_enrollment" + } + prop { + api_name: "operation_authenticate_acquired" + type: String + access: ReadWrite + prop_name: "vendor.face.virtual.operation_authenticate_acquired" + } + prop { + api_name: "operation_authenticate_duration" + type: Integer + access: ReadWrite + prop_name: "vendor.face.virtual.operation_authenticate_duration" + } + prop { + api_name: "operation_authenticate_error" + type: Integer + access: ReadWrite + prop_name: "vendor.face.virtual.operation_authenticate_error" + } + prop { + api_name: "operation_authenticate_fails" + access: ReadWrite + prop_name: "vendor.face.virtual.operation_authenticate_fails" + } + prop { + api_name: "operation_authenticate_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.face.virtual.operation_authenticate_latency" + } + prop { + api_name: "operation_detect_interaction_fails" + access: ReadWrite + prop_name: "vendor.face.virtual.operation_detect_interaction_fails" + } + prop { + api_name: "operation_detect_interaction_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.face.virtual.operation_detect_interaction_latency" + } + prop { + api_name: "operation_enroll_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.face.virtual.operation_enroll_latency" + } + prop { + api_name: "strength" + type: String + access: ReadWrite + prop_name: "persist.vendor.face.virtual.strength" + enum_values: "convenience|weak|strong" + } + prop { + api_name: "type" + type: String + access: ReadWrite + prop_name: "persist.vendor.face.virtual.type" + enum_values: "IR|RGB" + } +} diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc new file mode 100644 index 0000000000..7ce4249f48 --- /dev/null +++ b/biometrics/face/aidl/default/face-default.rc @@ -0,0 +1,8 @@ +service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.default default + class hal + user nobody + group nobody + interface aidl android.hardware.biometrics.face.IFace/default + oneshot + disabled + diff --git a/biometrics/face/aidl/default/face-example.xml b/biometrics/face/aidl/default/face-default.xml similarity index 81% rename from biometrics/face/aidl/default/face-example.xml rename to biometrics/face/aidl/default/face-default.xml index 2b39b3d783..94569de254 100644 --- a/biometrics/face/aidl/default/face-example.xml +++ b/biometrics/face/aidl/default/face-default.xml @@ -2,6 +2,6 @@ android.hardware.biometrics.face 4 - IFace/virtual + IFace/default diff --git a/biometrics/face/aidl/default/face-example.rc b/biometrics/face/aidl/default/face-example.rc deleted file mode 100644 index b0d82c60c5..0000000000 --- a/biometrics/face/aidl/default/face-example.rc +++ /dev/null @@ -1,8 +0,0 @@ -service vendor.face-example /vendor/bin/hw/android.hardware.biometrics.face-service.example - class hal - user nobody - group nobody - interface aidl android.hardware.biometrics.face.IFace/virtual - oneshot - disabled - diff --git a/biometrics/face/aidl/default/face-virtual.rc b/biometrics/face/aidl/default/face-virtual.rc new file mode 100644 index 0000000000..8fb0a7b58f --- /dev/null +++ b/biometrics/face/aidl/default/face-virtual.rc @@ -0,0 +1,8 @@ +service face-virtual /apex/com.android.hardware.biometrics.face.virtual/bin/hw/android.hardware.biometrics.face-service.example virtual + class hal + user nobody + group nobody + interface aidl android.hardware.biometrics.face.virtualhal.IVirtualHal/virtual + oneshot + disabled + diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop index 997fd671ac..ec2b92bf7e 100644 --- a/biometrics/face/aidl/default/face.sysprop +++ b/biometrics/face/aidl/default/face.sysprop @@ -7,7 +7,7 @@ owner: Vendor prop { prop_name: "persist.vendor.face.virtual.type" type: String - scope: Internal + scope: Public access: ReadWrite enum_values: "IR|RGB" api_name: "type" @@ -17,7 +17,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.strength" type: String - scope: Internal + scope: Public access: ReadWrite enum_values: "convenience|weak|strong" api_name: "strength" @@ -27,7 +27,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.enrollments" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "enrollments" } @@ -36,7 +36,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.features" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "features" } @@ -46,7 +46,7 @@ prop { prop { prop_name: "vendor.face.virtual.enrollment_hit" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "enrollment_hit" } @@ -60,7 +60,7 @@ prop { prop { prop_name: "vendor.face.virtual.next_enrollment" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "next_enrollment" } @@ -69,7 +69,7 @@ prop { prop { prop_name: "vendor.face.virtual.authenticator_id" type: Long - scope: Internal + scope: Public access: ReadWrite api_name: "authenticator_id" } @@ -78,7 +78,7 @@ prop { prop { prop_name: "vendor.face.virtual.challenge" type: Long - scope: Internal + scope: Public access: ReadWrite api_name: "challenge" } @@ -87,7 +87,7 @@ prop { prop { prop_name: "vendor.face.virtual.lockout" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "lockout" } @@ -96,7 +96,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_authenticate_fails" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_fails" } @@ -105,27 +105,18 @@ prop { prop { prop_name: "vendor.face.virtual.operation_detect_interaction_fails" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_fails" } -# force all enroll operations to fail -prop { - prop_name: "vendor.face.virtual.operation_enroll_fails" - type: Boolean - scope: Internal - access: ReadWrite - api_name: "operation_enroll_fails" -} - # add a latency to authentication operations # Note that this latency is the initial authentication latency that occurs before # the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED prop { prop_name: "vendor.face.virtual.operation_authenticate_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_latency" } @@ -134,7 +125,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_detect_interaction_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_latency" } @@ -143,7 +134,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_enroll_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_enroll_latency" } @@ -153,7 +144,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_authenticate_duration" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_duration" } @@ -162,7 +153,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_authenticate_error" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_error" } @@ -171,7 +162,7 @@ prop { prop { prop_name: "vendor.face.virtual.operation_authenticate_acquired" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_acquired" } @@ -180,7 +171,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.lockout_enable" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_enable" } @@ -189,7 +180,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.lockout_timed_enable" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_timed_enable" } @@ -198,7 +189,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.lockout_timed_threshold" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_timed_threshold" } @@ -207,7 +198,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.lockout_timed_duration" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_timed_duration" } @@ -216,7 +207,7 @@ prop { prop { prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_permanent_threshold" } diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp index 38e1c6311d..75a4479e77 100644 --- a/biometrics/face/aidl/default/main.cpp +++ b/biometrics/face/aidl/default/main.cpp @@ -14,25 +14,49 @@ * limitations under the License. */ +#undef LOG_TAG +#define LOG_TAG "FaceVirtualHal" + #include "Face.h" +#include "VirtualHal.h" #include #include #include using aidl::android::hardware::biometrics::face::Face; +using aidl::android::hardware::biometrics::face::VirtualHal; -int main() { - LOG(INFO) << "Face HAL started"; +int main(int argc, char** argv) { + if (argc < 2) { + LOG(ERROR) << "Missing argument -> exiting, Valid arguments:[default|virtual]"; + return EXIT_FAILURE; + } + LOG(INFO) << "Face HAL started: " << argv[1]; ABinderProcess_setThreadPoolMaxThreadCount(0); std::shared_ptr hal = ndk::SharedRefBase::make(); + std::shared_ptr hal_vhal = ndk::SharedRefBase::make(hal); - const std::string instance = std::string(Face::descriptor) + "/virtual"; - binder_status_t status = - AServiceManager_registerLazyService(hal->asBinder().get(), instance.c_str()); - CHECK_EQ(status, STATUS_OK); + if (strcmp(argv[1], "default") == 0) { + const std::string instance = std::string(Face::descriptor) + "/default"; + auto binder = hal->asBinder(); + binder_status_t status = + AServiceManager_registerLazyService(binder.get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + LOG(INFO) << "started IFace/default"; + } else if (strcmp(argv[1], "virtual") == 0) { + const std::string instance = std::string(VirtualHal::descriptor) + "/virtual"; + auto binder = hal_vhal->asBinder(); + binder_status_t status = + AServiceManager_registerLazyService(binder.get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + LOG(INFO) << "started IVirtualHal/virtual"; + } else { + LOG(ERROR) << "Unexpected argument: " << argv[1]; + return EXIT_FAILURE; + } AServiceManager_forceLazyServicesPersist(true); ABinderProcess_joinThreadPool(); - return EXIT_FAILURE; // should not reach + return EXIT_FAILURE; // should not reach here } diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp index 8c39b589af..d448532a8d 100644 --- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp +++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp @@ -21,6 +21,7 @@ #include #include +#include "Face.h" #include "FakeFaceEngine.h" #include "util/Util.h" @@ -141,12 +142,12 @@ class FakeFaceEngineTest : public ::testing::Test { } void TearDown() override { - FaceHalProperties::enrollments({}); - FaceHalProperties::challenge({}); - FaceHalProperties::features({}); - FaceHalProperties::authenticator_id({}); - FaceHalProperties::strength(""); - FaceHalProperties::operation_detect_interaction_latency({}); + Face::cfg().setopt("enrollments", {}); + Face::cfg().set("challenge", 0); + Face::cfg().setopt("features", {}); + Face::cfg().set("authenticator_id", 0); + Face::cfg().set("strength", ""); + Face::cfg().setopt("operation_detect_interaction_latency", {}); } FakeFaceEngine mEngine; @@ -160,81 +161,83 @@ TEST_F(FakeFaceEngineTest, one_eq_one) { TEST_F(FakeFaceEngineTest, GenerateChallenge) { mEngine.generateChallengeImpl(mCallback.get()); - ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge); + ASSERT_EQ(Face::cfg().get("challenge"), mCallback->mLastChallenge); } TEST_F(FakeFaceEngineTest, RevokeChallenge) { - auto challenge = FaceHalProperties::challenge().value_or(10); + auto challenge = Face::cfg().get("challenge"); mEngine.revokeChallengeImpl(mCallback.get(), challenge); - ASSERT_FALSE(FaceHalProperties::challenge().has_value()); + ASSERT_FALSE(Face::cfg().get("challenge")); ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked); } TEST_F(FakeFaceEngineTest, ResetLockout) { - FaceHalProperties::lockout(true); + Face::cfg().set("lockout", true); mEngine.resetLockoutImpl(mCallback.get(), {}); ASSERT_FALSE(mCallback->mLockoutPermanent); - ASSERT_FALSE(FaceHalProperties::lockout().value_or(true)); + ASSERT_FALSE(Face::cfg().get("lockout")); } TEST_F(FakeFaceEngineTest, AuthenticatorId) { - FaceHalProperties::authenticator_id(50); + Face::cfg().set("authenticator_id", 50); mEngine.getAuthenticatorIdImpl(mCallback.get()); ASSERT_EQ(50, mCallback->mLastAuthenticatorId); ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated); } TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) { - FaceHalProperties::strength("weak"); - FaceHalProperties::authenticator_id(500); + Face::cfg().set("strength", "weak"); + Face::cfg().set("authenticator_id", 500); mEngine.getAuthenticatorIdImpl(mCallback.get()); ASSERT_EQ(0, mCallback->mLastAuthenticatorId); ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated); } TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) { - FaceHalProperties::authenticator_id(500); + Face::cfg().set("authenticator_id", 500); mEngine.invalidateAuthenticatorIdImpl(mCallback.get()); - ASSERT_NE(500, FaceHalProperties::authenticator_id().value()); + ASSERT_NE(500, Face::cfg().get("authenticator_id")); ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated); } TEST_F(FakeFaceEngineTest, Enroll) { - FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true"); + Face::cfg().set("next_enrollment", + "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true"); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/, mCancel.get_future()); - ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value()); - ASSERT_EQ(1, FaceHalProperties::enrollments().size()); - ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value()); + ASSERT_FALSE(Face::cfg().getopt("next_enrollment").has_value()); + ASSERT_EQ(1, Face::cfg().getopt("enrollments").size()); + ASSERT_EQ(1, Face::cfg().getopt("enrollments")[0].value()); ASSERT_EQ(1, mCallback->mLastEnrolled); ASSERT_EQ(0, mCallback->mRemaining); } TEST_F(FakeFaceEngineTest, EnrollFails) { - FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false"); + Face::cfg().set("next_enrollment", + "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false"); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/, mCancel.get_future()); - ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value()); - ASSERT_EQ(0, FaceHalProperties::enrollments().size()); + ASSERT_FALSE(Face::cfg().getopt("next_enrollment").has_value()); + ASSERT_EQ(0, Face::cfg().getopt("enrollments").size()); } TEST_F(FakeFaceEngineTest, EnrollCancel) { - FaceHalProperties::next_enrollment("1:2000-[21,8,9],300:false"); + Face::cfg().set("next_enrollment", "1:2000-[21,8,9],300:false"); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mCancel.set_value(); mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/, mCancel.get_future()); ASSERT_EQ(Error::CANCELED, mCallback->mError); ASSERT_EQ(-1, mCallback->mLastEnrolled); - ASSERT_EQ(0, FaceHalProperties::enrollments().size()); - ASSERT_TRUE(FaceHalProperties::next_enrollment().has_value()); + ASSERT_EQ(0, Face::cfg().getopt("enrollments").size()); + ASSERT_FALSE(Face::cfg().get("next_enrollment").empty()); } TEST_F(FakeFaceEngineTest, Authenticate) { - FaceHalProperties::enrollments({100}); - FaceHalProperties::enrollment_hit(100); + Face::cfg().setopt("enrollments", {100}); + Face::cfg().set("enrollment_hit", 100); mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future()); ASSERT_EQ(100, mCallback->mLastAuthenticated); @@ -242,32 +245,32 @@ TEST_F(FakeFaceEngineTest, Authenticate) { } TEST_F(FakeFaceEngineTest, AuthenticateCancel) { - FaceHalProperties::enrollments({100}); - FaceHalProperties::enrollment_hit(100); + Face::cfg().setopt("enrollments", {100}); + Face::cfg().set("enrollment_hit", 100); mCancel.set_value(); mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future()); ASSERT_EQ(Error::CANCELED, mCallback->mError); } TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) { - FaceHalProperties::enrollments({3}); - FaceHalProperties::enrollment_hit(100); + Face::cfg().setopt("enrollments", {3}); + Face::cfg().set("enrollment_hit", 100); mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future()); ASSERT_EQ(Error::TIMEOUT, mCallback->mError); ASSERT_TRUE(mCallback->mAuthenticateFailed); } TEST_F(FakeFaceEngineTest, DetectInteraction) { - FaceHalProperties::enrollments({100}); - FaceHalProperties::enrollment_hit(100); + Face::cfg().setopt("enrollments", {100}); + Face::cfg().set("enrollment_hit", 100); ASSERT_EQ(0, mCallback->mInteractionDetectedCount); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); ASSERT_EQ(1, mCallback->mInteractionDetectedCount); } TEST_F(FakeFaceEngineTest, DetectInteractionCancel) { - FaceHalProperties::enrollments({100}); - FaceHalProperties::enrollment_hit(100); + Face::cfg().setopt("enrollments", {100}); + Face::cfg().set("enrollment_hit", 100); mCancel.set_value(); mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future()); ASSERT_EQ(Error::CANCELED, mCallback->mError); @@ -279,7 +282,7 @@ TEST_F(FakeFaceEngineTest, GetFeatureEmpty) { } TEST_F(FakeFaceEngineTest, SetFeature) { - FaceHalProperties::enrollments({1}); + Face::cfg().setopt("enrollments", {1}); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true); auto features = mCallback->mFeatures; @@ -294,7 +297,7 @@ TEST_F(FakeFaceEngineTest, SetFeature) { } TEST_F(FakeFaceEngineTest, ToggleFeature) { - FaceHalProperties::enrollments({1}); + Face::cfg().setopt("enrollments", {1}); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true); mEngine.getFeaturesImpl(mCallback.get()); @@ -310,7 +313,7 @@ TEST_F(FakeFaceEngineTest, ToggleFeature) { } TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) { - FaceHalProperties::enrollments({1}); + Face::cfg().setopt("enrollments", {1}); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false); mEngine.getFeaturesImpl(mCallback.get()); @@ -319,7 +322,7 @@ TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) { } TEST_F(FakeFaceEngineTest, SetMultipleFeatures) { - FaceHalProperties::enrollments({1}); + Face::cfg().setopt("enrollments", {1}); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true); mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true); @@ -335,7 +338,7 @@ TEST_F(FakeFaceEngineTest, SetMultipleFeatures) { } TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) { - FaceHalProperties::enrollments({1}); + Face::cfg().setopt("enrollments", {1}); keymaster::HardwareAuthToken hat{.mac = {2, 4}}; mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true); mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true); @@ -352,7 +355,7 @@ TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) { } TEST_F(FakeFaceEngineTest, Enumerate) { - FaceHalProperties::enrollments({120, 3}); + Face::cfg().setopt("enrollments", {120, 3}); mEngine.enumerateEnrollmentsImpl(mCallback.get()); auto enrolls = mCallback->mLastEnrollmentsEnumerated; ASSERT_FALSE(enrolls.empty()); @@ -361,7 +364,7 @@ TEST_F(FakeFaceEngineTest, Enumerate) { } TEST_F(FakeFaceEngineTest, RemoveEnrollments) { - FaceHalProperties::enrollments({120, 3, 100}); + Face::cfg().setopt("enrollments", {120, 3, 100}); mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100}); mEngine.enumerateEnrollmentsImpl(mCallback.get()); auto enrolls = mCallback->mLastEnrollmentsEnumerated; @@ -372,9 +375,9 @@ TEST_F(FakeFaceEngineTest, RemoveEnrollments) { } TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) { - FaceHalProperties::lockout(true); - FaceHalProperties::enrollments({33}); - FaceHalProperties::enrollment_hit(33); + Face::cfg().set("lockout", true); + Face::cfg().setopt("enrollments", {33}); + Face::cfg().set("enrollment_hit", 33); auto cancelFuture = mCancel.get_future(); mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture); @@ -382,28 +385,30 @@ TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) { mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */); ASSERT_FALSE(mCallback->mLockoutPermanent); - FaceHalProperties::enrollment_hit(33); + Face::cfg().set("enrollment_hit", 33); mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture); ASSERT_EQ(33, mCallback->mLastAuthenticated); ASSERT_FALSE(mCallback->mAuthenticateFailed); } TEST_F(FakeFaceEngineTest, LatencyDefault) { - FaceHalProperties::operation_detect_interaction_latency({}); - ASSERT_EQ(DEFAULT_LATENCY, - mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency())); + Face::cfg().setopt("operation_detect_interaction_latency", {}); + ASSERT_EQ(DEFAULT_LATENCY, mEngine.getLatency(Face::cfg().getopt( + "operation_detect_interaction_latency"))); } TEST_F(FakeFaceEngineTest, LatencyFixed) { - FaceHalProperties::operation_detect_interaction_latency({10}); - ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency())); + Face::cfg().setopt("operation_detect_interaction_latency", {10}); + ASSERT_EQ(10, mEngine.getLatency( + Face::cfg().getopt("operation_detect_interaction_latency"))); } TEST_F(FakeFaceEngineTest, LatencyRandom) { - FaceHalProperties::operation_detect_interaction_latency({1, 1000}); + Face::cfg().setopt("operation_detect_interaction_latency", {1, 1000}); std::set latencySet; for (int i = 0; i < 100; i++) { - auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()); + auto x = mEngine.getLatency( + Face::cfg().getopt("operation_detect_interaction_latency")); ASSERT_TRUE(x >= 1 && x <= 1000); latencySet.insert(x); } diff --git a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp index fa07d1dfeb..8564f6b8e2 100644 --- a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp +++ b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp @@ -21,6 +21,7 @@ #include +#include "Face.h" #include "FakeLockoutTracker.h" #include "util/Util.h" @@ -103,19 +104,21 @@ class FakeLockoutTrackerTest : public ::testing::Test { static constexpr int32_t LOCKOUT_TIMED_DURATION = 100; void SetUp() override { - FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD); - FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION); - FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD); + Face::cfg().set("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD); + Face::cfg().set("lockout_timed_duration", LOCKOUT_TIMED_DURATION); + Face::cfg().set("lockout_permanent_threshold", LOCKOUT_PERMANENT_THRESHOLD); + Face::cfg().set("lockout_enable", false); + Face::cfg().set("lockout", false); mCallback = ndk::SharedRefBase::make(); } void TearDown() override { // reset to default - FaceHalProperties::lockout_timed_threshold(5); - FaceHalProperties::lockout_timed_duration(20); - FaceHalProperties::lockout_permanent_threshold(10000); - FaceHalProperties::lockout_enable(false); - FaceHalProperties::lockout(false); + Face::cfg().set("lockout_timed_threshold", 5); + Face::cfg().set("lockout_timed_duration", 20); + Face::cfg().set("lockout_permanent_threshold", 10000); + Face::cfg().set("lockout_enable", false); + Face::cfg().set("lockout", false); } FakeLockoutTracker mLockoutTracker; @@ -123,7 +126,7 @@ class FakeLockoutTrackerTest : public ::testing::Test { }; TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) { - FaceHalProperties::lockout_enable(false); + Face::cfg().set("lockout_enable", false); for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++) mLockoutTracker.addFailedAttempt(mCallback.get()); ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone); @@ -131,7 +134,7 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) { } TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) { - FaceHalProperties::lockout_enable(true); + Face::cfg().set("lockout_enable", true); ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get())); for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++) mLockoutTracker.addFailedAttempt(mCallback.get()); @@ -145,8 +148,8 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) { } TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) { - FaceHalProperties::lockout_enable(true); - FaceHalProperties::lockout_timed_enable(true); + Face::cfg().set("lockout_enable", true); + Face::cfg().set("lockout_timed_enable", true); ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get())); for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) mLockoutTracker.addFailedAttempt(mCallback.get()); @@ -168,8 +171,8 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) { } TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) { - FaceHalProperties::lockout_enable(true); - FaceHalProperties::lockout_timed_enable(true); + Face::cfg().set("lockout_enable", true); + Face::cfg().set("lockout_timed_enable", true); ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get())); for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) mLockoutTracker.addFailedAttempt(mCallback.get()); @@ -182,8 +185,8 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) { } TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) { - FaceHalProperties::lockout_enable(true); - FaceHalProperties::lockout_timed_enable(true); + Face::cfg().set("lockout_enable", true); + Face::cfg().set("lockout_timed_enable", true); ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get())); ASSERT_EQ(0, mCallback->mLockoutTimed); for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) @@ -198,7 +201,7 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) { } TEST_F(FakeLockoutTrackerTest, resetLockout) { - FaceHalProperties::lockout_enable(true); + Face::cfg().set("lockout_enable", true); ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone); for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++) mLockoutTracker.addFailedAttempt(mCallback.get()); diff --git a/biometrics/face/aidl/default/tests/VirtualHalTest.cpp b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp new file mode 100644 index 0000000000..2f19805de8 --- /dev/null +++ b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2024 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. + */ + +#include +#include +#include + +#include + +#include "Face.h" +#include "VirtualHal.h" + +using namespace ::android::face::virt; +using namespace ::aidl::android::hardware::biometrics::face; + +namespace aidl::android::hardware::biometrics::face { + +class VirtualHalTest : public ::testing::Test { + public: + static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2; + + protected: + void SetUp() override { + mHal = ndk::SharedRefBase::make(); + mVhal = ndk::SharedRefBase::make(mHal); + ASSERT_TRUE(mVhal != nullptr); + mHal->resetConfigToDefault(); + } + + void TearDown() override { mHal->resetConfigToDefault(); } + + std::shared_ptr mVhal; + + ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name, + ndk::ScopedAStatus (VirtualHal::*f)(int32_t), + const std::vector& in_good); + + private: + std::shared_ptr mHal; +}; + +ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32( + const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t), + const std::vector& in_params_good) { + ndk::ScopedAStatus status; + for (auto& param : in_params_good) { + status = (*mVhal.*f)(param); + if (!status.isOk()) return status; + if (Face::cfg().get(name) != param) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, + "Error: fail to set non-negative parameter")); + } + } + + int32_t old_param = Face::cfg().get(name); + status = (*mVhal.*f)(-1); + if (status.isOk()) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK")); + } + if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, + "Error: unexpected return error code")); + } + if (Face::cfg().get(name) != old_param) { + return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage( + VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, + "Error: unexpected parameter change on failed attempt")); + } + return ndk::ScopedAStatus::ok(); +} + +TEST_F(VirtualHalTest, init) { + mVhal->setLockout(false); + ASSERT_TRUE(Face::cfg().get("lockout") == false); + ASSERT_TRUE(Face::cfg().get("type") == "rgb"); + ASSERT_TRUE(Face::cfg().get("strength") == "strong"); + std::int64_t id = Face::cfg().get("authenticator_id"); + ASSERT_TRUE(Face::cfg().get("authenticator_id") == 0); + ASSERT_TRUE(Face::cfg().getopt("enrollments") == OptIntVec()); +} + +TEST_F(VirtualHalTest, enrollment_hit_int32) { + mVhal->setEnrollmentHit(11); + ASSERT_TRUE(Face::cfg().get("enrollment_hit") == 11); +} + +TEST_F(VirtualHalTest, next_enrollment) { + struct { + std::string nextEnrollmentStr; + face::NextEnrollment nextEnrollment; + } testData[] = { + {"1:20:true", {1, {{20}}, true}}, + {"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}}, + {"2:50-[21],60,70-[4,1002,1]:false", + {2, + {{50, {{AcquiredInfo::START}}}, + {60}, + {70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}}, + false}}, + }; + + for (auto& d : testData) { + mVhal->setNextEnrollment(d.nextEnrollment); + ASSERT_TRUE(Face::cfg().get("next_enrollment") == d.nextEnrollmentStr); + } +} + +TEST_F(VirtualHalTest, authenticator_id_int64) { + mVhal->setAuthenticatorId(12345678900); + ASSERT_TRUE(Face::cfg().get("authenticator_id") == 12345678900); +} + +TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) { + mVhal->setOperationAuthenticateFails(true); + ASSERT_TRUE(Face::cfg().get("operation_authenticate_fails")); +} + +TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) { + using Tag = AcquiredInfoAndVendorCode::Tag; + std::vector ac{ + {AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}}; + mVhal->setOperationAuthenticateAcquired(ac); + OptIntVec ac_get = Face::cfg().getopt("operation_authenticate_acquired"); + ASSERT_TRUE(ac_get.size() == ac.size()); + for (int i = 0; i < ac.size(); i++) { + int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get() + : ac[i].get(); + ASSERT_TRUE(acCode == ac_get[i]); + } +} + +TEST_F(VirtualHalTest, type) { + struct { + FaceSensorType type; + const char* typeStr; + } typeMap[] = {{FaceSensorType::RGB, "rgb"}, + {FaceSensorType::IR, "ir"}, + {FaceSensorType::UNKNOWN, "unknown"}}; + for (auto const& x : typeMap) { + mVhal->setType(x.type); + ASSERT_TRUE(Face::cfg().get("type") == x.typeStr); + } +} + +TEST_F(VirtualHalTest, sensorStrength) { + struct { + common::SensorStrength strength; + const char* strengthStr; + } strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"}, + {common::SensorStrength::WEAK, "WEAK"}, + {common::SensorStrength::STRONG, "STRONG"}}; + + for (auto const& x : strengths) { + mVhal->setSensorStrength(x.strength); + ASSERT_TRUE(Face::cfg().get("strength") == x.strengthStr); + } +} + +TEST_F(VirtualHalTest, setLatency) { + ndk::ScopedAStatus status; + std::vector in_lats[] = {{1}, {2, 3}, {5, 4}}; + for (auto const& in_lat : in_lats) { + status = mVhal->setOperationAuthenticateLatency(in_lat); + ASSERT_TRUE(status.isOk()); + OptIntVec out_lat = Face::cfg().getopt("operation_authenticate_latency"); + ASSERT_TRUE(in_lat.size() == out_lat.size()); + for (int i = 0; i < in_lat.size(); i++) { + ASSERT_TRUE(in_lat[i] == out_lat[i]); + } + } + + std::vector bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}}; + for (auto const& in_lat : bad_in_lats) { + status = mVhal->setOperationAuthenticateLatency(in_lat); + ASSERT_TRUE(!status.isOk()); + ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER); + } +} + +TEST_F(VirtualHalTest, setOperationAuthenticateDuration) { + ndk::ScopedAStatus status = validateNonNegativeInputOfInt32( + "operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration, + {0, 33}); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(VirtualHalTest, setLockoutTimedDuration) { + ndk::ScopedAStatus status = validateNonNegativeInputOfInt32( + "lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35}); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(VirtualHalTest, setLockoutTimedThreshold) { + ndk::ScopedAStatus status = validateNonNegativeInputOfInt32( + "lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36}); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(VirtualHalTest, setLockoutPermanentThreshold) { + ndk::ScopedAStatus status = validateNonNegativeInputOfInt32( + "lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37}); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(VirtualHalTest, setOthers) { + // Verify that there is no CHECK() failures + mVhal->setEnrollments({7, 6, 5}); + mVhal->setChallenge(111222333444555666); + mVhal->setOperationAuthenticateError(4); + mVhal->setOperationEnrollLatency({4, 5}); + mVhal->setLockout(false); + mVhal->setLockoutEnable(false); +} + +} // namespace aidl::android::hardware::biometrics::face + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + ABinderProcess_startThreadPool(); + return RUN_ALL_TESTS(); +} diff --git a/biometrics/fingerprint/aidl/Android.bp b/biometrics/fingerprint/aidl/Android.bp index d0c1b8b054..9f9e7237b4 100644 --- a/biometrics/fingerprint/aidl/Android.bp +++ b/biometrics/fingerprint/aidl/Android.bp @@ -11,7 +11,7 @@ aidl_interface { name: "android.hardware.biometrics.fingerprint", vendor_available: true, srcs: [ - "android/hardware/biometrics/fingerprint/**/*.aidl", + "android/hardware/biometrics/fingerprint/*.aidl", ], imports: [ "android.hardware.biometrics.common-V4", @@ -25,6 +25,12 @@ aidl_interface { cpp: { enabled: false, }, + ndk: { + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + }, rust: { enabled: true, }, @@ -60,5 +66,34 @@ aidl_interface { }, ], + frozen: true, +} + +aidl_interface { + name: "android.hardware.biometrics.fingerprint.virtualhal", + srcs: [ + "android/hardware/biometrics/fingerprint/virtualhal/*.aidl", + ], + imports: [ + "android.hardware.biometrics.common-V4", + "android.hardware.keymaster-V4", + "android.hardware.biometrics.fingerprint-V4", + ], + vendor_available: true, + unstable: true, + backend: { + java: { + platform_apis: true, + }, + cpp: { + enabled: false, + }, + ndk: { + apex_available: [ + "com.android.hardware.biometrics.fingerprint.virtual", + "//apex_available:platform", + ], + }, + }, frozen: false, } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl deleted file mode 100644 index 33ae83c340..0000000000 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IVirtualHal.aidl +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2024 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. - */ -/////////////////////////////////////////////////////////////////////////////// -// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // -/////////////////////////////////////////////////////////////////////////////// - -// This file is a snapshot of an AIDL file. Do not edit it manually. There are -// two cases: -// 1). this is a frozen version file - do not edit this in any case. -// 2). this is a 'current' file. If you make a backwards compatible change to -// the interface (from the latest frozen version), the build system will -// prompt you to update this file with `m -update-api`. -// -// You must not make a backward incompatible change to any AIDL file built -// with the aidl_interface module type with versions property set. The module -// type is used to build AIDL files in a way that they can be used across -// independently updatable components of the system. If a device is shipped -// with such a backward incompatible change, it has a high risk of breaking -// later when a module using the interface is updated, e.g., Mainline modules. - -package android.hardware.biometrics.fingerprint; -/* @hide */ -@VintfStability -interface IVirtualHal { - oneway void setEnrollments(in int[] id); - oneway void setEnrollmentHit(in int hit_id); - oneway void setNextEnrollment(in android.hardware.biometrics.fingerprint.NextEnrollment next_enrollment); - oneway void setAuthenticatorId(in long id); - oneway void setChallenge(in long challenge); - oneway void setOperationAuthenticateFails(in boolean fail); - oneway void setOperationAuthenticateLatency(in int[] latencyMs); - oneway void setOperationAuthenticateDuration(in int durationMs); - oneway void setOperationAuthenticateError(in int error); - oneway void setOperationAuthenticateAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired); - oneway void setOperationEnrollError(in int error); - oneway void setOperationEnrollLatency(in int[] latencyMs); - oneway void setOperationDetectInteractionLatency(in int[] latencyMs); - oneway void setOperationDetectInteractionError(in int error); - oneway void setOperationDetectInteractionDuration(in int durationMs); - oneway void setOperationDetectInteractionAcquired(in android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquired); - oneway void setLockout(in boolean lockout); - oneway void setLockoutEnable(in boolean enable); - oneway void setLockoutTimedThreshold(in int threshold); - oneway void setLockoutTimedDuration(in int durationMs); - oneway void setLockoutPermanentThreshold(in int threshold); - oneway void resetConfigurations(); - oneway void setType(in android.hardware.biometrics.fingerprint.FingerprintSensorType type); - oneway void setSensorId(in int id); - oneway void setSensorStrength(in android.hardware.biometrics.common.SensorStrength strength); - oneway void setMaxEnrollmentPerUser(in int max); - oneway void setSensorLocation(in android.hardware.biometrics.fingerprint.SensorLocation loc); - oneway void setNavigationGuesture(in boolean v); - oneway void setDetectInteraction(in boolean v); - oneway void setDisplayTouch(in boolean v); - oneway void setControlIllumination(in boolean v); - const int STATUS_INVALID_PARAMETER = 1; -} diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl similarity index 93% rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl index c7be950b8b..1fc72219fe 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/AcquiredInfoAndVendorCode.aidl @@ -14,14 +14,13 @@ * limitations under the License. */ -package android.hardware.biometrics.fingerprint; +package android.hardware.biometrics.fingerprint.virtualhal; import android.hardware.biometrics.fingerprint.AcquiredInfo; /** * @hide */ -@VintfStability union AcquiredInfoAndVendorCode { /** * Acquired info as specified in AcqauiredInfo.aidl diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl similarity index 87% rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl index bf038f6fb6..b0b2926f6b 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/EnrollmentProgressStep.aidl @@ -14,14 +14,13 @@ * limitations under the License. */ -package android.hardware.biometrics.fingerprint; +package android.hardware.biometrics.fingerprint.virtualhal; -import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode; +import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode; /** * @hide */ -@VintfStability parcelable EnrollmentProgressStep { /** * The duration of the enrollment step in milli-seconds diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl similarity index 97% rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl rename to biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl index cb9135e6ab..5af84ed9b1 100644 --- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IVirtualHal.aidl +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/IVirtualHal.aidl @@ -14,19 +14,19 @@ * limitations under the License. */ -package android.hardware.biometrics.fingerprint; +package android.hardware.biometrics.fingerprint.virtualhal; import android.hardware.biometrics.common.SensorStrength; -import android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode; import android.hardware.biometrics.fingerprint.FingerprintSensorType; -import android.hardware.biometrics.fingerprint.NextEnrollment; +import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.SensorLocation; +import android.hardware.biometrics.fingerprint.virtualhal.AcquiredInfoAndVendorCode; +import android.hardware.biometrics.fingerprint.virtualhal.NextEnrollment; /** * @hide */ -@VintfStability -oneway interface IVirtualHal { +interface IVirtualHal { /** * The operation failed due to invalid input parameters, the error messages should * gives more details @@ -315,4 +315,5 @@ oneway interface IVirtualHal { void setDetectInteraction(in boolean v); void setDisplayTouch(in boolean v); void setControlIllumination(in boolean v); + IFingerprint getFingerprintHal(); } diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl new file mode 100644 index 0000000000..2d704f1166 --- /dev/null +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/NextEnrollment.aidl @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.biometrics.fingerprint.virtualhal; + +import android.hardware.biometrics.fingerprint.virtualhal.EnrollmentProgressStep; + +/** + * @hide + */ +parcelable NextEnrollment { + /** + * Identifier of the next enrollment if successful + */ + int id; + + /** + * Specification of the progress steps of the next enrollment, each step consists of duration + * and sequence of acquired info codes to be generated by HAL. + * See EnrollmentProgressStep.aidl for more details + */ + EnrollmentProgressStep[] progressSteps; + + /** + * Success or failure of the next enrollment + */ + boolean result = true; +} diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md new file mode 100644 index 0000000000..eaf23363bb --- /dev/null +++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/virtualhal/README.md @@ -0,0 +1,2 @@ +The aidl files in this directory are used only by fingerprint virtual hal +which is controlled/configured via IVirtualHal interface diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp index 9b72c872c9..faaa9c63fd 100644 --- a/biometrics/fingerprint/aidl/default/Android.bp +++ b/biometrics/fingerprint/aidl/default/Android.bp @@ -8,10 +8,9 @@ package { default_applicable_licenses: ["hardware_interfaces_license"], } -cc_binary { - name: "android.hardware.biometrics.fingerprint-service.example", - vendor: true, - relative_install_path: "hw", +cc_library_static { + name: "android.hardware.biometrics.fingerprint-service.lib", + vendor_available: true, local_include_dirs: ["include"], srcs: [ "FakeLockoutTracker.cpp", @@ -30,22 +29,80 @@ cc_binary { "libbinder_ndk", "liblog", ], - static_libs: [ + whole_static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", "libbase", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint.virtualhal-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.biometrics.common.thread", "android.hardware.biometrics.common.util", "android.hardware.biometrics.common.config", "android.hardware.keymaster-V4-ndk", ], + product_variables: { + debuggable: { + cflags: ["-DFPS_DEBUGGABLE"], + }, + }, + apex_available: [ + "com.android.hardware.biometrics.fingerprint.virtual", + "//apex_available:platform", + ], +} + +cc_binary { + name: "android.hardware.biometrics.fingerprint-service.example", + system_ext_specific: true, + relative_install_path: "hw", + local_include_dirs: ["include"], + srcs: [ + ], + stl: "c++_static", + shared_libs: [ + "libbinder_ndk", + "liblog", + ], + whole_static_libs: [ + "android.hardware.biometrics.fingerprint-service.lib", + ], installable: false, // install APEX instead product_variables: { debuggable: { cflags: ["-DFPS_DEBUGGABLE"], }, }, + apex_available: [ + "com.android.hardware.biometrics.fingerprint.virtual", + ], +} + +cc_binary { + name: "android.hardware.biometrics.fingerprint-service.default", + //system_ext_specific: true, + vendor: true, + relative_install_path: "hw", + init_rc: ["fingerprint-default.rc"], + vintf_fragments: ["fingerprint-default.xml"], + local_include_dirs: ["include"], + srcs: [ + ], + stl: "c++_static", + shared_libs: [ + "libbinder_ndk", + "liblog", + ], + whole_static_libs: [ + "android.hardware.biometrics.fingerprint-service.lib", + ], + product_variables: { + debuggable: { + cflags: ["-DFPS_DEBUGGABLE"], + }, + }, + apex_available: [ + "//apex_available:platform", + ], } cc_test { @@ -63,14 +120,13 @@ cc_test { ], static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", "android.hardware.biometrics.common.config", "android.hardware.biometrics.common.thread", ], - vendor: true, test_suites: ["general-tests"], require_root: true, } @@ -91,14 +147,13 @@ cc_test { ], static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", "android.hardware.biometrics.common.config", "android.hardware.biometrics.common.thread", ], - vendor: true, test_suites: ["general-tests"], require_root: true, } @@ -117,14 +172,13 @@ cc_test { ], static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", "android.hardware.biometrics.common.thread", "android.hardware.biometrics.common.config", ], - vendor: true, test_suites: ["general-tests"], require_root: true, } @@ -145,14 +199,13 @@ cc_test { ], static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", "android.hardware.biometrics.common.thread", "android.hardware.biometrics.common.config", ], - vendor: true, test_suites: ["general-tests"], require_root: true, } @@ -178,7 +231,8 @@ cc_test { ], static_libs: [ "libandroid.hardware.biometrics.fingerprint.VirtualProps", - "android.hardware.biometrics.fingerprint-V5-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", + "android.hardware.biometrics.fingerprint.virtualhal-ndk", "android.hardware.biometrics.common-V4-ndk", "android.hardware.keymaster-V4-ndk", "android.hardware.biometrics.common.util", @@ -190,7 +244,6 @@ cc_test { cflags: ["-DFPS_DEBUGGABLE"], }, }, - vendor: true, test_suites: ["general-tests"], require_root: true, } @@ -198,39 +251,34 @@ cc_test { sysprop_library { name: "android.hardware.biometrics.fingerprint.VirtualProps", srcs: ["fingerprint.sysprop"], - property_owner: "Vendor", - vendor: true, + property_owner: "Platform", + vendor_available: true, + apex_available: [ + "com.android.hardware.biometrics.fingerprint.virtual", + "//apex_available:platform", + ], } prebuilt_etc { - name: "fingerprint-example.rc", - src: "fingerprint-example.rc", - installable: false, -} - -prebuilt_etc { - name: "fingerprint-example.xml", - src: "fingerprint-example.xml", - sub_dir: "vintf", + name: "fingerprint-virtual.rc", + src: "fingerprint-virtual.rc", installable: false, } apex { name: "com.android.hardware.biometrics.fingerprint.virtual", manifest: "apex_manifest.json", - file_contexts: "apex_file_contexts", + file_contexts: ":com.android.biometrics.virtual.fingerprint-file_contexts", key: "com.android.hardware.key", certificate: ":com.android.hardware.certificate", updatable: false, - vendor: true, + system_ext_specific: true, binaries: [ "android.hardware.biometrics.fingerprint-service.example", ], prebuilts: [ // init_rc - "fingerprint-example.rc", - // vintf_fragment - "fingerprint-example.xml", + "fingerprint-virtual.rc", ], } diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp index 67eb8378cb..7a43d7b319 100644 --- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp +++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp @@ -389,10 +389,10 @@ void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb, if (isLockoutTimerStarted) isLockoutTimerAborted = true; } -void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) { +void FakeFingerprintEngine::clearLockout(ISessionCallback* cb, bool dueToTimeout) { Fingerprint::cfg().set("lockout", false); cb->onLockoutCleared(); - mLockoutTracker.reset(); + mLockoutTracker.reset(dueToTimeout); } ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/, @@ -536,7 +536,7 @@ void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) { BEGIN_OP(0); if (!isLockoutTimerAborted) { - clearLockout(cb); + clearLockout(cb, true); } isLockoutTimerStarted = false; isLockoutTimerAborted = false; diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp index a056db50d0..7d468452c3 100644 --- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp +++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp @@ -23,8 +23,11 @@ using namespace ::android::fingerprint::virt; namespace aidl::android::hardware::biometrics::fingerprint { -void FakeLockoutTracker::reset() { - mFailedCount = 0; +void FakeLockoutTracker::reset(bool dueToTimeout) { + if (!dueToTimeout) { + mFailedCount = 0; + } + mFailedCountTimed = 0; mLockoutTimedStart = 0; mCurrentMode = LockoutMode::kNone; } @@ -33,6 +36,7 @@ void FakeLockoutTracker::addFailedAttempt() { bool enabled = Fingerprint::cfg().get("lockout_enable"); if (enabled) { mFailedCount++; + mFailedCountTimed++; int32_t lockoutTimedThreshold = Fingerprint::cfg().get("lockout_timed_threshold"); int32_t lockoutPermanetThreshold = @@ -40,7 +44,7 @@ void FakeLockoutTracker::addFailedAttempt() { if (mFailedCount >= lockoutPermanetThreshold) { mCurrentMode = LockoutMode::kPermanent; Fingerprint::cfg().set("lockout", true); - } else if (mFailedCount >= lockoutTimedThreshold) { + } else if (mFailedCountTimed >= lockoutTimedThreshold) { if (mCurrentMode == LockoutMode::kNone) { mCurrentMode = LockoutMode::kTimed; mLockoutTimedStart = Util::getSystemNanoTime(); diff --git a/biometrics/fingerprint/aidl/default/VirtualHal.cpp b/biometrics/fingerprint/aidl/default/VirtualHal.cpp index e107d2f7ed..d1617652a9 100644 --- a/biometrics/fingerprint/aidl/default/VirtualHal.cpp +++ b/biometrics/fingerprint/aidl/default/VirtualHal.cpp @@ -26,7 +26,7 @@ #define LOG_TAG "FingerprintVirtualHalAidl" namespace aidl::android::hardware::biometrics::fingerprint { - +using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode; using Tag = AcquiredInfoAndVendorCode::Tag; ::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector& enrollments) { @@ -41,8 +41,7 @@ using Tag = AcquiredInfoAndVendorCode::Tag; return ndk::ScopedAStatus::ok(); } -::ndk::ScopedAStatus VirtualHal::setNextEnrollment( - const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment& next_enrollment) { +::ndk::ScopedAStatus VirtualHal::setNextEnrollment(const NextEnrollment& next_enrollment) { Fingerprint::cfg().sourcedFromAidl(); std::ostringstream os; os << next_enrollment.id << ":"; @@ -333,4 +332,10 @@ OptIntVec VirtualHal::acquiredInfoVec2OptIntVec( return ndk::ScopedAStatus::ok(); } +::ndk::ScopedAStatus VirtualHal::getFingerprintHal( + std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>* pFp) { + LOG(INFO) << " calling getFingerprintHal in VirtualHal.cpp"; + *pFp = mFp; + return ndk::ScopedAStatus::ok(); +} } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt index e69de29bb2..8c02a686d0 100644 --- a/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt +++ b/biometrics/fingerprint/aidl/default/api/android.hardware.biometrics.fingerprint.VirtualProps-current.txt @@ -0,0 +1,178 @@ +props { + owner: Vendor + module: "android.fingerprint.virt.FingerprintHalProperties" + prop { + api_name: "authenticator_id" + type: Long + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.authenticator_id" + } + prop { + api_name: "challenge" + type: Long + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.challenge" + } + prop { + api_name: "control_illumination" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination" + } + prop { + api_name: "detect_interaction" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.detect_interaction" + } + prop { + api_name: "display_touch" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch" + } + prop { + api_name: "enrollment_hit" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.enrollment_hit" + } + prop { + api_name: "enrollments" + type: IntegerList + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.enrollments" + } + prop { + api_name: "lockout" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.lockout" + } + prop { + api_name: "lockout_enable" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.lockout_enable" + } + prop { + api_name: "lockout_permanent_threshold" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold" + } + prop { + api_name: "lockout_timed_duration" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration" + } + prop { + api_name: "lockout_timed_threshold" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold" + } + prop { + api_name: "max_enrollments" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.max_enrollments" + } + prop { + api_name: "navigation_guesture" + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture" + } + prop { + api_name: "next_enrollment" + type: String + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.next_enrollment" + } + prop { + api_name: "operation_authenticate_acquired" + type: String + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired" + } + prop { + api_name: "operation_authenticate_duration" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration" + } + prop { + api_name: "operation_authenticate_error" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_authenticate_error" + } + prop { + api_name: "operation_authenticate_fails" + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails" + } + prop { + api_name: "operation_authenticate_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency" + } + prop { + api_name: "operation_detect_interaction_acquired" + type: String + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired" + } + prop { + api_name: "operation_detect_interaction_duration" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration" + } + prop { + api_name: "operation_detect_interaction_error" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error" + } + prop { + api_name: "operation_detect_interaction_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency" + } + prop { + api_name: "operation_enroll_error" + type: Integer + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_enroll_error" + } + prop { + api_name: "operation_enroll_latency" + type: IntegerList + access: ReadWrite + prop_name: "vendor.fingerprint.virtual.operation_enroll_latency" + } + prop { + api_name: "sensor_id" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.sensor_id" + } + prop { + api_name: "sensor_location" + type: String + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.sensor_location" + } + prop { + api_name: "sensor_strength" + type: Integer + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.sensor_strength" + } + prop { + api_name: "type" + type: String + access: ReadWrite + prop_name: "persist.vendor.fingerprint.virtual.type" + enum_values: "default|rear|udfps|side" + } +} diff --git a/biometrics/fingerprint/aidl/default/fingerprint-default.rc b/biometrics/fingerprint/aidl/default/fingerprint-default.rc new file mode 100644 index 0000000000..7e46bc1a21 --- /dev/null +++ b/biometrics/fingerprint/aidl/default/fingerprint-default.rc @@ -0,0 +1,7 @@ +service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.default default + class hal + user nobody + group nobody + interface aidl android.hardware.biometrics.fingerprint.IFingerprint/default + oneshot + disabled diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.xml b/biometrics/fingerprint/aidl/default/fingerprint-default.xml similarity index 50% rename from biometrics/fingerprint/aidl/default/fingerprint-example.xml rename to biometrics/fingerprint/aidl/default/fingerprint-default.xml index ee529e9875..d1404590b6 100644 --- a/biometrics/fingerprint/aidl/default/fingerprint-example.xml +++ b/biometrics/fingerprint/aidl/default/fingerprint-default.xml @@ -1,7 +1,10 @@ android.hardware.biometrics.fingerprint - 5 - IFingerprint/virtual + 4 + + IFingerprint + default + diff --git a/biometrics/fingerprint/aidl/default/fingerprint-example.rc b/biometrics/fingerprint/aidl/default/fingerprint-example.rc deleted file mode 100644 index da4ea45696..0000000000 --- a/biometrics/fingerprint/aidl/default/fingerprint-example.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.fingerprint-example /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example - class hal - user nobody - group nobody - interface aidl android.hardware.biometrics.fingerprint.IFingerprint/virtual - oneshot - disabled diff --git a/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc new file mode 100644 index 0000000000..5d1506c92d --- /dev/null +++ b/biometrics/fingerprint/aidl/default/fingerprint-virtual.rc @@ -0,0 +1,7 @@ +service fingerprint-virtual /apex/com.android.hardware.biometrics.fingerprint.virtual/bin/hw/android.hardware.biometrics.fingerprint-service.example virtual + class hal + user nobody + group nobody + interface aidl android.hardware.biometrics.fingerprint.virtualhal.IVirtualHal/virtual + oneshot + disabled diff --git a/biometrics/fingerprint/aidl/default/fingerprint.sysprop b/biometrics/fingerprint/aidl/default/fingerprint.sysprop index 6a6c29728b..eb334326f7 100644 --- a/biometrics/fingerprint/aidl/default/fingerprint.sysprop +++ b/biometrics/fingerprint/aidl/default/fingerprint.sysprop @@ -7,7 +7,7 @@ owner: Vendor prop { prop_name: "persist.vendor.fingerprint.virtual.type" type: String - scope: Internal + scope: Public access: ReadWrite enum_values: "default|rear|udfps|side" api_name: "type" @@ -17,7 +17,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.enrollments" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "enrollments" } @@ -27,7 +27,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.enrollment_hit" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "enrollment_hit" } @@ -42,7 +42,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.next_enrollment" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "next_enrollment" } @@ -51,7 +51,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.authenticator_id" type: Long - scope: Internal + scope: Public access: ReadWrite api_name: "authenticator_id" } @@ -60,7 +60,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.challenge" type: Long - scope: Internal + scope: Public access: ReadWrite api_name: "challenge" } @@ -69,7 +69,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_authenticate_fails" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_fails" } @@ -82,7 +82,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_error" } @@ -91,7 +91,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_enroll_error" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_enroll_error" } @@ -104,7 +104,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_latency" } @@ -114,7 +114,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_latency" } @@ -124,7 +124,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_enroll_latency" type: IntegerList - scope: Internal + scope: Public access: ReadWrite api_name: "operation_enroll_latency" } @@ -134,7 +134,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_duration" } @@ -143,7 +143,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_authenticate_error" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_error" } @@ -153,7 +153,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.sensor_location" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "sensor_location" } @@ -162,7 +162,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "operation_authenticate_acquired" } @@ -172,7 +172,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_duration" } @@ -184,7 +184,7 @@ prop { prop { prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired" type: String - scope: Internal + scope: Public access: ReadWrite api_name: "operation_detect_interaction_acquired" } @@ -193,7 +193,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.sensor_id" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "sensor_id" } @@ -203,7 +203,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.sensor_strength" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "sensor_strength" } @@ -213,7 +213,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.max_enrollments" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "max_enrollments" } @@ -222,7 +222,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "navigation_guesture" } @@ -231,7 +231,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.detect_interaction" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "detect_interaction" } @@ -240,7 +240,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "display_touch" } @@ -249,7 +249,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "control_illumination" } @@ -258,7 +258,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.lockout" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "lockout" } @@ -267,7 +267,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.lockout_enable" type: Boolean - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_enable" } @@ -276,7 +276,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_threshold" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_timed_threshold" } @@ -285,7 +285,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.lockout_timed_duration" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_timed_duration" } @@ -294,7 +294,7 @@ prop { prop { prop_name: "persist.vendor.fingerprint.virtual.lockout_permanent_threshold" type: Integer - scope: Internal + scope: Public access: ReadWrite api_name: "lockout_permanent_threshold" } diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h index 0d5357529d..362d0df3c8 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h +++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h @@ -110,7 +110,7 @@ class FakeFingerprintEngine { std::pair convertError(int32_t code); int32_t getRandomInRange(int32_t bound1, int32_t bound2); bool checkSensorLockout(ISessionCallback*); - void clearLockout(ISessionCallback* cb); + void clearLockout(ISessionCallback* cb, bool dueToTimeout = false); void waitForFingerDown(ISessionCallback* cb, const std::future& cancel); FakeLockoutTracker mLockoutTracker; diff --git a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h index a1b6128a9e..a7f2f8e294 100644 --- a/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h +++ b/biometrics/fingerprint/aidl/default/include/FakeLockoutTracker.h @@ -24,12 +24,12 @@ namespace aidl::android::hardware::biometrics::fingerprint { class FakeLockoutTracker { public: - FakeLockoutTracker() : mFailedCount(0) {} + FakeLockoutTracker() : mFailedCount(0), mFailedCountTimed(0) {} ~FakeLockoutTracker() {} enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent }; - void reset(); + void reset(bool dueToTimeout = false); LockoutMode getMode(); void addFailedAttempt(); int64_t getLockoutTimeLeft(); @@ -44,6 +44,7 @@ class FakeLockoutTracker { private: int32_t mFailedCount; + int32_t mFailedCountTimed; int64_t mLockoutTimedStart; LockoutMode mCurrentMode; }; diff --git a/biometrics/fingerprint/aidl/default/include/VirtualHal.h b/biometrics/fingerprint/aidl/default/include/VirtualHal.h index e5f62fc1c0..5488383a69 100644 --- a/biometrics/fingerprint/aidl/default/include/VirtualHal.h +++ b/biometrics/fingerprint/aidl/default/include/VirtualHal.h @@ -16,21 +16,21 @@ #pragma once -#include +#include #include "Fingerprint.h" namespace aidl::android::hardware::biometrics::fingerprint { +using namespace virtualhal; + class VirtualHal : public BnVirtualHal { public: - VirtualHal(Fingerprint* fp) : mFp(fp) {} + VirtualHal(std::shared_ptr fp) : mFp(fp) {} ::ndk::ScopedAStatus setEnrollments(const std::vector& in_id) override; ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override; - ::ndk::ScopedAStatus setNextEnrollment( - const ::aidl::android::hardware::biometrics::fingerprint::NextEnrollment& - in_next_enrollment) override; + ::ndk::ScopedAStatus setNextEnrollment(const NextEnrollment& in_next_enrollment) override; ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override; ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override; ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override; @@ -67,12 +67,15 @@ class VirtualHal : public BnVirtualHal { ::ndk::ScopedAStatus setDetectInteraction(bool in_v) override; ::ndk::ScopedAStatus setDisplayTouch(bool in_v) override; ::ndk::ScopedAStatus setControlIllumination(bool in_v) override; + ::ndk::ScopedAStatus getFingerprintHal( + std::shared_ptr<::aidl::android::hardware::biometrics::fingerprint::IFingerprint>* + _aidl_return); private: OptIntVec intVec2OptIntVec(const std::vector& intVec); OptIntVec acquiredInfoVec2OptIntVec(const std::vector& intVec); ::ndk::ScopedAStatus sanityCheckLatency(const std::vector& in_latency); - Fingerprint* mFp; + std::shared_ptr mFp; }; } // namespace aidl::android::hardware::biometrics::fingerprint diff --git a/biometrics/fingerprint/aidl/default/main.cpp b/biometrics/fingerprint/aidl/default/main.cpp index ba0c8ecadb..8ca44d6bbc 100644 --- a/biometrics/fingerprint/aidl/default/main.cpp +++ b/biometrics/fingerprint/aidl/default/main.cpp @@ -24,21 +24,38 @@ using aidl::android::hardware::biometrics::fingerprint::Fingerprint; using aidl::android::hardware::biometrics::fingerprint::VirtualHal; -int main() { - LOG(INFO) << "Fingerprint HAL started"; +int main(int argc, char** argv) { + if (argc < 2) { + LOG(ERROR) << "Missing argument -> exiting"; + return EXIT_FAILURE; + } + + LOG(INFO) << "Fingerprint HAL started: " << argv[1]; ABinderProcess_setThreadPoolMaxThreadCount(0); std::shared_ptr hal = ndk::SharedRefBase::make(); - auto binder = hal->asBinder(); - - std::shared_ptr hal_ext = ndk::SharedRefBase::make(hal.get()); - auto binder_ext = hal_ext->asBinder(); + std::shared_ptr hal_vhal = ndk::SharedRefBase::make(hal); if (hal->connected()) { - CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get())); - const std::string instance = std::string(Fingerprint::descriptor) + "/virtual"; - binder_status_t status = - AServiceManager_registerLazyService(binder.get(), instance.c_str()); - CHECK_EQ(status, STATUS_OK); + if (strcmp(argv[1], "default") == 0) { + const std::string instance = std::string(Fingerprint::descriptor) + "/default"; + auto binder = hal->asBinder(); + auto binder_ext = hal_vhal->asBinder(); + CHECK(STATUS_OK == AIBinder_setExtension(binder.get(), binder_ext.get())); + binder_status_t status = + AServiceManager_registerLazyService(binder.get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + LOG(INFO) << "started IFingerprint/default"; + } else if (strcmp(argv[1], "virtual") == 0) { + const std::string instance = std::string(VirtualHal::descriptor) + "/virtual"; + auto binder = hal_vhal->asBinder(); + binder_status_t status = + AServiceManager_registerLazyService(binder.get(), instance.c_str()); + CHECK_EQ(status, STATUS_OK); + LOG(INFO) << "started IVirtualHal/virtual"; + } else { + LOG(ERROR) << "Unexpected argument: " << argv[1]; + return EXIT_FAILURE; + } AServiceManager_forceLazyServicesPersist(true); } else { LOG(ERROR) << "Fingerprint HAL is not connected"; diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp index 3c12b6d97f..4c1277b5cb 100644 --- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp @@ -75,7 +75,7 @@ TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) { prevTimeLeft = currTimeLeft; } ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone); - mLockoutTracker.reset(); + mLockoutTracker.reset(true); } TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) { diff --git a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp index 3fe0b2a33e..8ffc96b13f 100644 --- a/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp +++ b/biometrics/fingerprint/aidl/default/tests/VirtualHalTest.cpp @@ -35,7 +35,7 @@ class VirtualHalTest : public ::testing::Test { protected: void SetUp() override { mHal = ndk::SharedRefBase::make(); - mVhal = ndk::SharedRefBase::make(mHal.get()); + mVhal = ndk::SharedRefBase::make(mHal); ASSERT_TRUE(mVhal != nullptr); mHal->resetConfigToDefault(); } diff --git a/biometrics/fingerprint/aidl/vts/Android.bp b/biometrics/fingerprint/aidl/vts/Android.bp index fc32fe6cad..628f03fe45 100644 --- a/biometrics/fingerprint/aidl/vts/Android.bp +++ b/biometrics/fingerprint/aidl/vts/Android.bp @@ -16,8 +16,8 @@ cc_test { ], srcs: ["VtsHalBiometricsFingerprintTargetTest.cpp"], static_libs: [ - "android.hardware.biometrics.common-V3-ndk", - "android.hardware.biometrics.fingerprint-V3-ndk", + "android.hardware.biometrics.common-V4-ndk", + "android.hardware.biometrics.fingerprint-V4-ndk", "android.hardware.keymaster-V4-ndk", ], shared_libs: [ diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp index 8f7d19dc46..b59c92e905 100644 --- a/camera/common/aidl/Android.bp +++ b/camera/common/aidl/Android.bp @@ -10,6 +10,7 @@ package { aidl_interface { name: "android.hardware.camera.common", + host_supported: true, vendor_available: true, srcs: ["android/hardware/camera/common/*.aidl"], frozen: true, diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp index 31c2dbeb4b..48ae34e74a 100644 --- a/camera/device/aidl/Android.bp +++ b/camera/device/aidl/Android.bp @@ -10,6 +10,7 @@ package { aidl_interface { name: "android.hardware.camera.device", + host_supported: true, vendor_available: true, srcs: ["android/hardware/camera/device/*.aidl"], frozen: true, @@ -31,6 +32,9 @@ aidl_interface { sdk_version: "module_current", enabled: false, }, + rust: { + enabled: true, + }, }, versions_with_info: [ { diff --git a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl index 62a19cff93..63ae320dd3 100644 --- a/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl +++ b/camera/device/aidl/android/hardware/camera/device/ICameraDeviceSession.aidl @@ -575,6 +575,11 @@ interface ICameraDeviceSession { * This can be called at any point after 'processCaptureRequest' in response * to camera clients disabling an active repeating request. * + * Note: The frame number parameter is the latest possible frame number at which the + * ongoing repeating request will end. It is possible that the repeating request may end + * before the specified frame number due to reasons such as the camera client abandoning + * buffers, which is timing dependent. + * * Performance requirements: * The call must not be blocked for extensive periods and should be extremely lightweight. There * must be no frame rate degradation or frame jitter introduced. diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp index ae8ba14256..a9c1a1a195 100644 --- a/camera/metadata/aidl/Android.bp +++ b/camera/metadata/aidl/Android.bp @@ -10,6 +10,7 @@ package { aidl_interface { name: "android.hardware.camera.metadata", + host_supported: true, vendor_available: true, srcs: ["android/hardware/camera/metadata/*.aidl"], frozen: true, diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 82666ae3df..49c8410d78 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -8714,16 +8715,25 @@ void CameraHidlTest::setupPreviewWindow( ASSERT_NE(nullptr, bufferItemConsumer); ASSERT_NE(nullptr, bufferHandler); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + *bufferItemConsumer = new BufferItemConsumer( + GraphicBuffer::USAGE_HW_TEXTURE); // Use GLConsumer default usage flags +#else sp producer; sp consumer; BufferQueue::createBufferQueue(&producer, &consumer); *bufferItemConsumer = new BufferItemConsumer(consumer, GraphicBuffer::USAGE_HW_TEXTURE); //Use GLConsumer default usage flags +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) ASSERT_NE(nullptr, (*bufferItemConsumer).get()); *bufferHandler = new BufferItemHander(*bufferItemConsumer); ASSERT_NE(nullptr, (*bufferHandler).get()); (*bufferItemConsumer)->setFrameAvailableListener(*bufferHandler); +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) + sp surface = (*bufferItemConsumer)->getSurface(); +#else sp surface = new Surface(producer); +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) sp previewCb = new PreviewWindowCb(surface); auto rc = device->setPreviewWindow(previewCb); diff --git a/camera/provider/aidl/Android.bp b/camera/provider/aidl/Android.bp index 38a8936001..faad35a918 100644 --- a/camera/provider/aidl/Android.bp +++ b/camera/provider/aidl/Android.bp @@ -10,6 +10,7 @@ package { aidl_interface { name: "android.hardware.camera.provider", + host_supported: true, vendor_available: true, srcs: [ "android/hardware/camera/provider/*.aidl", @@ -27,6 +28,9 @@ aidl_interface { cpp: { enabled: false, }, + rust: { + enabled: true, + }, }, versions_with_info: [ { diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp index ad8d4c877f..9fa4df2cf4 100644 --- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp +++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp @@ -165,26 +165,21 @@ TEST_P(CameraAidlTest, getResourceCost) { // Validate the integrity of manual flash strength control metadata TEST_P(CameraAidlTest, validateManualFlashStrengthControlKeys) { - if (flags::camera_manual_flash_strength_control()) { - std::vector cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str()); - CameraMetadata meta; - std::shared_ptr cameraDevice; - openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, - &cameraDevice /*out*/); - ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta); - ASSERT_TRUE(ret.isOk()); - const camera_metadata_t* staticMeta = - reinterpret_cast(meta.metadata.data()); - verifyManualFlashStrengthControlCharacteristics(staticMeta); - ret = mSession->close(); - mSession = nullptr; - ASSERT_TRUE(ret.isOk()); - } - } else { - ALOGI("validateManualFlashStrengthControlKeys: Test skipped.\n"); - GTEST_SKIP(); + std::vector cameraDeviceNames = getCameraDeviceNames(mProvider); + for (const auto& name : cameraDeviceNames) { + ALOGI("validateManualFlashStrengthControlKeys: Testing camera device %s", name.c_str()); + CameraMetadata meta; + std::shared_ptr cameraDevice; + openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, + &cameraDevice /*out*/); + ndk::ScopedAStatus ret = cameraDevice->getCameraCharacteristics(&meta); + ASSERT_TRUE(ret.isOk()); + const camera_metadata_t* staticMeta = + reinterpret_cast(meta.metadata.data()); + verifyManualFlashStrengthControlCharacteristics(staticMeta); + ret = mSession->close(); + mSession = nullptr; + ASSERT_TRUE(ret.isOk()); } } @@ -288,77 +283,70 @@ TEST_P(CameraAidlTest, getCameraCharacteristics) { } TEST_P(CameraAidlTest, getSessionCharacteristics) { - if (flags::feature_combination_query()) { - std::vector cameraDeviceNames = getCameraDeviceNames(mProvider); + std::vector cameraDeviceNames = getCameraDeviceNames(mProvider); - for (const auto& name : cameraDeviceNames) { - std::shared_ptr device; - ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str()); - ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device); - ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(), - ret.getServiceSpecificError()); - ASSERT_TRUE(ret.isOk()); - ASSERT_NE(device, nullptr); + for (const auto& name : cameraDeviceNames) { + std::shared_ptr device; + ALOGI("getSessionCharacteristics: Testing camera device %s", name.c_str()); + ndk::ScopedAStatus ret = mProvider->getCameraDeviceInterface(name, &device); + ALOGI("getCameraDeviceInterface returns: %d:%d", ret.getExceptionCode(), + ret.getServiceSpecificError()); + ASSERT_TRUE(ret.isOk()); + ASSERT_NE(device, nullptr); - int32_t interfaceVersion = -1; - ret = device->getInterfaceVersion(&interfaceVersion); - ASSERT_TRUE(ret.isOk()); - bool supportSessionCharacteristics = - (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3); - if (!supportSessionCharacteristics) { - continue; - } - - CameraMetadata meta; - openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, - &device /*out*/); - - std::vector outputStreams; - camera_metadata_t* staticMeta = - reinterpret_cast(meta.metadata.data()); - outputStreams.clear(); - ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); - ASSERT_NE(0u, outputStreams.size()); - - AvailableStream sampleStream = outputStreams[0]; - - int32_t streamId = 0; - Stream stream = {streamId, - StreamType::OUTPUT, - sampleStream.width, - sampleStream.height, - static_cast(sampleStream.format), - static_cast( - GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER), - Dataspace::UNKNOWN, - StreamRotation::ROTATION_0, - std::string(), - /*bufferSize*/ 0, - /*groupId*/ -1, - {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, - RequestAvailableDynamicRangeProfilesMap:: - ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; - - std::vector streams = {stream}; - StreamConfiguration config; - createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config); - - CameraMetadata camera_chars; - ret = device->getCameraCharacteristics(&camera_chars); - ASSERT_TRUE(ret.isOk()); - - CameraMetadata session_chars; - ret = device->getSessionCharacteristics(config, &session_chars); - ASSERT_TRUE(ret.isOk()); - verifySessionCharacteristics(session_chars, camera_chars); - - ret = mSession->close(); - mSession = nullptr; - ASSERT_TRUE(ret.isOk()); + int32_t interfaceVersion = -1; + ret = device->getInterfaceVersion(&interfaceVersion); + ASSERT_TRUE(ret.isOk()); + bool supportSessionCharacteristics = + (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3); + if (!supportSessionCharacteristics) { + continue; } - } else { - ALOGI("getSessionCharacteristics: Test skipped.\n"); - GTEST_SKIP(); + + CameraMetadata meta; + openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/, &device /*out*/); + + std::vector outputStreams; + camera_metadata_t* staticMeta = reinterpret_cast(meta.metadata.data()); + outputStreams.clear(); + ASSERT_EQ(Status::OK, getAvailableOutputStreams(staticMeta, outputStreams)); + ASSERT_NE(0u, outputStreams.size()); + + AvailableStream sampleStream = outputStreams[0]; + + int32_t streamId = 0; + Stream stream = {streamId, + StreamType::OUTPUT, + sampleStream.width, + sampleStream.height, + static_cast(sampleStream.format), + static_cast( + GRALLOC1_CONSUMER_USAGE_VIDEO_ENCODER), + Dataspace::UNKNOWN, + StreamRotation::ROTATION_0, + std::string(), + /*bufferSize*/ 0, + /*groupId*/ -1, + {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT}, + RequestAvailableDynamicRangeProfilesMap:: + ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD}; + + std::vector streams = {stream}; + StreamConfiguration config; + createStreamConfiguration(streams, StreamConfigurationMode::NORMAL_MODE, &config); + + CameraMetadata camera_chars; + ret = device->getCameraCharacteristics(&camera_chars); + ASSERT_TRUE(ret.isOk()); + + CameraMetadata session_chars; + ret = device->getSessionCharacteristics(config, &session_chars); + ASSERT_TRUE(ret.isOk()); + verifySessionCharacteristics(session_chars, camera_chars); + + ret = mSession->close(); + mSession = nullptr; + ASSERT_TRUE(ret.isOk()); } } @@ -615,19 +603,17 @@ TEST_P(CameraAidlTest, constructDefaultRequestSettings) { ASSERT_EQ(0u, rawMetadata.metadata.size()); } - if (flags::feature_combination_query()) { - if (supportFeatureCombinationQuery) { - CameraMetadata rawMetadata2; - ndk::ScopedAStatus ret2 = - device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2); + if (supportFeatureCombinationQuery) { + CameraMetadata rawMetadata2; + ndk::ScopedAStatus ret2 = + device->constructDefaultRequestSettings(reqTemplate, &rawMetadata2); - ASSERT_EQ(ret.isOk(), ret2.isOk()); - ASSERT_EQ(ret.getStatus(), ret2.getStatus()); + ASSERT_EQ(ret.isOk(), ret2.isOk()); + ASSERT_EQ(ret.getStatus(), ret2.getStatus()); - ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size()); - if (ret2.isOk()) { - validateDefaultRequestMetadata(reqTemplate, rawMetadata2); - } + ASSERT_EQ(rawMetadata.metadata.size(), rawMetadata2.metadata.size()); + if (ret2.isOk()) { + validateDefaultRequestMetadata(reqTemplate, rawMetadata2); } } } diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp index f905011806..6ecd45186c 100644 --- a/camera/provider/aidl/vts/camera_aidl_test.cpp +++ b/camera/provider/aidl/vts/camera_aidl_test.cpp @@ -1920,28 +1920,22 @@ void CameraAidlTest::verifyStreamCombination(const std::shared_ptrgetInterfaceVersion(&interfaceVersion); + int32_t interfaceVersion; + ret = device->getInterfaceVersion(&interfaceVersion); + ASSERT_TRUE(ret.isOk()); + bool supportFeatureCombinationQuery = + (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3); + if (supportFeatureCombinationQuery) { + ret = device->isStreamCombinationWithSettingsSupported(config, + &streamCombinationSupported); ASSERT_TRUE(ret.isOk()); - bool supportFeatureCombinationQuery = - (interfaceVersion >= CAMERA_DEVICE_API_MINOR_VERSION_3); - if (supportFeatureCombinationQuery) { - ret = device->isStreamCombinationWithSettingsSupported(config, - &streamCombinationSupported); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(expectedStatus, streamCombinationSupported); - } + ASSERT_EQ(expectedStatus, streamCombinationSupported); } } } void CameraAidlTest::verifySessionCharacteristics(const CameraMetadata& session_chars, const CameraMetadata& camera_chars) { - if (!flags::feature_combination_query()) { - return; - } - const camera_metadata_t* session_metadata = reinterpret_cast(session_chars.metadata.data()); diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml index e019902e9f..4a1a13ace2 100644 --- a/compatibility_matrices/compatibility_matrix.202504.xml +++ b/compatibility_matrices/compatibility_matrix.202504.xml @@ -241,7 +241,7 @@ android.hardware.graphics.composer3 - 3 + 4 IComposer default @@ -622,7 +622,7 @@ android.hardware.vibrator - 1-2 + 1-3 IVibrator default @@ -630,7 +630,7 @@ android.hardware.vibrator - 1-2 + 1-3 IVibratorManager default @@ -662,7 +662,7 @@ android.hardware.wifi.hostapd - 1-2 + 2-3 IHostapd default @@ -670,7 +670,7 @@ android.hardware.wifi.supplicant - 2-3 + 3-4 ISupplicant default diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp index b86f399afc..e7a31e626a 100644 --- a/compatibility_matrices/exclude/fcm_exclude.cpp +++ b/compatibility_matrices/exclude/fcm_exclude.cpp @@ -149,6 +149,7 @@ bool ShouldCheckMissingAidlHalsInFcm(const std::string& packageAndVersion) { "android.hardware.radio@", "android.hardware.uwb.fira_android@", "android.hardware.wifi.common@", + "android.hardware.biometrics.fingerprint.virtualhal@", // Test packages are exempted. "android.hardware.tests.", diff --git a/drm/aidl/Android.bp b/drm/aidl/Android.bp index c42e7236b4..827621c804 100644 --- a/drm/aidl/Android.bp +++ b/drm/aidl/Android.bp @@ -15,6 +15,7 @@ aidl_interface { frozen: true, imports: [ "android.hardware.common-V2", + "android.hardware.drm.common-V1", ], backend: { cpp: { @@ -31,7 +32,10 @@ aidl_interface { versions_with_info: [ { version: "1", - imports: ["android.hardware.common-V2"], + imports: [ + "android.hardware.common-V2", + "android.hardware.drm.common-V1", + ], }, ], diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/.hash b/drm/aidl/aidl_api/android.hardware.drm/1/.hash index 886e28c0cb..9a735e93d6 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/1/.hash +++ b/drm/aidl/aidl_api/android.hardware.drm/1/.hash @@ -1 +1,2 @@ 7b4b0a0f36a7a6bb22d2016375e4a9d4a033592f +3a0197fb44863256da9034c26e721b1eee12d1be diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl index 80ebb285ae..f09eadd127 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/EventType.aidl @@ -34,9 +34,9 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum EventType { - PROVISION_REQUIRED = 0, - KEY_NEEDED = 1, - KEY_EXPIRED = 2, - VENDOR_DEFINED = 3, - SESSION_RECLAIMED = 4, + PROVISION_REQUIRED, + KEY_NEEDED, + KEY_EXPIRED, + VENDOR_DEFINED, + SESSION_RECLAIMED, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl index 34b9615c55..556ee3863f 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyRequestType.aidl @@ -34,10 +34,10 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum KeyRequestType { - INITIAL = 0, - RENEWAL = 1, - RELEASE = 2, - UNKNOWN = 3, - NONE = 4, - UPDATE = 5, + INITIAL, + RENEWAL, + RELEASE, + UNKNOWN, + NONE, + UPDATE, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl index 261516f8ef..5a46552541 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyStatusType.aidl @@ -34,10 +34,10 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum KeyStatusType { - USABLE = 0, - EXPIRED = 1, - OUTPUT_NOT_ALLOWED = 2, - STATUS_PENDING = 3, - INTERNAL_ERROR = 4, - USABLE_IN_FUTURE = 5, + USABLE, + EXPIRED, + OUTPUT_NOT_ALLOWED, + STATUS_PENDING, + INTERNAL_ERROR, + USABLE_IN_FUTURE, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl index 7a9d633578..e677c8692f 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/KeyType.aidl @@ -34,7 +34,7 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum KeyType { - OFFLINE = 0, - STREAMING = 1, - RELEASE = 2, + OFFLINE, + STREAMING, + RELEASE, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl index 83362c359f..b77ddf6134 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/LogPriority.aidl @@ -34,12 +34,12 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum LogPriority { - UNKNOWN = 0, - DEFAULT = 1, - VERBOSE = 2, - DEBUG = 3, - INFO = 4, - WARN = 5, - ERROR = 6, - FATAL = 7, + UNKNOWN, + DEFAULT, + VERBOSE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl index 629564d706..be0e822720 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/OfflineLicenseState.aidl @@ -34,7 +34,7 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum OfflineLicenseState { - UNKNOWN = 0, - USABLE = 1, - INACTIVE = 2, + UNKNOWN, + USABLE, + INACTIVE, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl index 65b2b9d2ae..87b3641909 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/SecurityLevel.aidl @@ -34,11 +34,11 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum SecurityLevel { - UNKNOWN = 0, - SW_SECURE_CRYPTO = 1, - SW_SECURE_DECODE = 2, - HW_SECURE_CRYPTO = 3, - HW_SECURE_DECODE = 4, - HW_SECURE_ALL = 5, - DEFAULT = 6, + UNKNOWN, + SW_SECURE_CRYPTO, + SW_SECURE_DECODE, + HW_SECURE_CRYPTO, + HW_SECURE_DECODE, + HW_SECURE_ALL, + DEFAULT, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl index c64068958f..a3ba6c3e7d 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl +++ b/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/Status.aidl @@ -34,44 +34,44 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum Status { - OK = 0, - ERROR_DRM_NO_LICENSE = 1, - ERROR_DRM_LICENSE_EXPIRED = 2, - ERROR_DRM_SESSION_NOT_OPENED = 3, - ERROR_DRM_CANNOT_HANDLE = 4, - ERROR_DRM_INVALID_STATE = 5, - BAD_VALUE = 6, - ERROR_DRM_NOT_PROVISIONED = 7, - ERROR_DRM_RESOURCE_BUSY = 8, - ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 9, - ERROR_DRM_DEVICE_REVOKED = 10, - ERROR_DRM_DECRYPT = 11, - ERROR_DRM_UNKNOWN = 12, - ERROR_DRM_INSUFFICIENT_SECURITY = 13, - ERROR_DRM_FRAME_TOO_LARGE = 14, - ERROR_DRM_SESSION_LOST_STATE = 15, - ERROR_DRM_RESOURCE_CONTENTION = 16, - CANNOT_DECRYPT_ZERO_SUBSAMPLES = 17, - CRYPTO_LIBRARY_ERROR = 18, - GENERAL_OEM_ERROR = 19, - GENERAL_PLUGIN_ERROR = 20, - INIT_DATA_INVALID = 21, - KEY_NOT_LOADED = 22, - LICENSE_PARSE_ERROR = 23, - LICENSE_POLICY_ERROR = 24, - LICENSE_RELEASE_ERROR = 25, - LICENSE_REQUEST_REJECTED = 26, - LICENSE_RESTORE_ERROR = 27, - LICENSE_STATE_ERROR = 28, - MALFORMED_CERTIFICATE = 29, - MEDIA_FRAMEWORK_ERROR = 30, - MISSING_CERTIFICATE = 31, - PROVISIONING_CERTIFICATE_ERROR = 32, - PROVISIONING_CONFIGURATION_ERROR = 33, - PROVISIONING_PARSE_ERROR = 34, - PROVISIONING_REQUEST_REJECTED = 35, - RETRYABLE_PROVISIONING_ERROR = 36, - SECURE_STOP_RELEASE_ERROR = 37, - STORAGE_READ_FAILURE = 38, - STORAGE_WRITE_FAILURE = 39, + OK, + ERROR_DRM_NO_LICENSE, + ERROR_DRM_LICENSE_EXPIRED, + ERROR_DRM_SESSION_NOT_OPENED, + ERROR_DRM_CANNOT_HANDLE, + ERROR_DRM_INVALID_STATE, + BAD_VALUE, + ERROR_DRM_NOT_PROVISIONED, + ERROR_DRM_RESOURCE_BUSY, + ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION, + ERROR_DRM_DEVICE_REVOKED, + ERROR_DRM_DECRYPT, + ERROR_DRM_UNKNOWN, + ERROR_DRM_INSUFFICIENT_SECURITY, + ERROR_DRM_FRAME_TOO_LARGE, + ERROR_DRM_SESSION_LOST_STATE, + ERROR_DRM_RESOURCE_CONTENTION, + CANNOT_DECRYPT_ZERO_SUBSAMPLES, + CRYPTO_LIBRARY_ERROR, + GENERAL_OEM_ERROR, + GENERAL_PLUGIN_ERROR, + INIT_DATA_INVALID, + KEY_NOT_LOADED, + LICENSE_PARSE_ERROR, + LICENSE_POLICY_ERROR, + LICENSE_RELEASE_ERROR, + LICENSE_REQUEST_REJECTED, + LICENSE_RESTORE_ERROR, + LICENSE_STATE_ERROR, + MALFORMED_CERTIFICATE, + MEDIA_FRAMEWORK_ERROR, + MISSING_CERTIFICATE, + PROVISIONING_CERTIFICATE_ERROR, + PROVISIONING_CONFIGURATION_ERROR, + PROVISIONING_PARSE_ERROR, + PROVISIONING_REQUEST_REJECTED, + RETRYABLE_PROVISIONING_ERROR, + SECURE_STOP_RELEASE_ERROR, + STORAGE_READ_FAILURE, + STORAGE_WRITE_FAILURE, } diff --git a/drm/aidl/vts/Android.bp b/drm/aidl/vts/Android.bp index e813bd132e..1fe0972a78 100644 --- a/drm/aidl/vts/Android.bp +++ b/drm/aidl/vts/Android.bp @@ -48,6 +48,7 @@ cc_test { ], static_libs: [ "android.hardware.drm@1.0-helper", + "android.hardware.drm.common-V1-ndk", "android.hardware.drm-V1-ndk", "android.hardware.common-V2-ndk", "libaidlcommonsupport", @@ -60,13 +61,19 @@ cc_test { data: [":libvtswidevine-arm-prebuilts"], }, arm64: { - data: [":libvtswidevine-arm64-prebuilts", ":libvtswidevine-arm-prebuilts"], + data: [ + ":libvtswidevine-arm64-prebuilts", + ":libvtswidevine-arm-prebuilts", + ], }, x86: { data: [":libvtswidevine-x86-prebuilts"], }, x86_64: { - data: [":libvtswidevine-x86_64-prebuilts", ":libvtswidevine-x86-prebuilts"], + data: [ + ":libvtswidevine-x86_64-prebuilts", + ":libvtswidevine-x86-prebuilts", + ], }, }, test_suites: [ diff --git a/drm/common/aidl/Android.bp b/drm/common/aidl/Android.bp new file mode 100644 index 0000000000..c5cb441085 --- /dev/null +++ b/drm/common/aidl/Android.bp @@ -0,0 +1,39 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "hardware_interfaces_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["hardware_interfaces_license"], +} + +aidl_interface { + name: "android.hardware.drm.common", + host_supported: true, + vendor_available: true, + srcs: ["android/hardware/drm/*.aidl"], + stability: "vintf", + backend: { + cpp: { + enabled: false, + }, + java: { + sdk_version: "module_current", + }, + ndk: { + min_sdk_version: "34", + }, + rust: { + enabled: true, + }, + }, + double_loadable: true, + versions_with_info: [ + { + version: "1", + imports: [], + }, + ], + frozen: true, + +} diff --git a/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash new file mode 100644 index 0000000000..66690e1a7e --- /dev/null +++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/.hash @@ -0,0 +1 @@ +1b5e9159609b3aa05e2c7158f3a1488fda2250d1 diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl similarity index 92% rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl index 5704fb0726..118bef68c3 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevel.aidl +++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevel.aidl @@ -34,12 +34,12 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum HdcpLevel { - HDCP_UNKNOWN = 0, - HDCP_NONE = 1, - HDCP_V1 = 2, - HDCP_V2 = 3, - HDCP_V2_1 = 4, - HDCP_V2_2 = 5, - HDCP_NO_OUTPUT = 6, - HDCP_V2_3 = 7, + HDCP_UNKNOWN, + HDCP_NONE, + HDCP_V1, + HDCP_V2, + HDCP_V2_1, + HDCP_V2_2, + HDCP_NO_OUTPUT, + HDCP_V2_3, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl similarity index 100% rename from drm/aidl/aidl_api/android.hardware.drm/1/android/hardware/drm/HdcpLevels.aidl rename to drm/common/aidl/aidl_api/android.hardware.drm.common/1/android/hardware/drm/HdcpLevels.aidl diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl similarity index 92% rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl rename to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl index 5704fb0726..118bef68c3 100644 --- a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevel.aidl +++ b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevel.aidl @@ -34,12 +34,12 @@ package android.hardware.drm; @Backing(type="int") @VintfStability enum HdcpLevel { - HDCP_UNKNOWN = 0, - HDCP_NONE = 1, - HDCP_V1 = 2, - HDCP_V2 = 3, - HDCP_V2_1 = 4, - HDCP_V2_2 = 5, - HDCP_NO_OUTPUT = 6, - HDCP_V2_3 = 7, + HDCP_UNKNOWN, + HDCP_NONE, + HDCP_V1, + HDCP_V2, + HDCP_V2_1, + HDCP_V2_2, + HDCP_NO_OUTPUT, + HDCP_V2_3, } diff --git a/drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl similarity index 100% rename from drm/aidl/aidl_api/android.hardware.drm/current/android/hardware/drm/HdcpLevels.aidl rename to drm/common/aidl/aidl_api/android.hardware.drm.common/current/android/hardware/drm/HdcpLevels.aidl diff --git a/drm/aidl/android/hardware/drm/HdcpLevel.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevel.aidl similarity index 100% rename from drm/aidl/android/hardware/drm/HdcpLevel.aidl rename to drm/common/aidl/android/hardware/drm/HdcpLevel.aidl diff --git a/drm/aidl/android/hardware/drm/HdcpLevels.aidl b/drm/common/aidl/android/hardware/drm/HdcpLevels.aidl similarity index 100% rename from drm/aidl/android/hardware/drm/HdcpLevels.aidl rename to drm/common/aidl/android/hardware/drm/HdcpLevels.aidl diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl index 8a22d6e67f..aaafe7f583 100644 --- a/gnss/aidl/android/hardware/gnss/IGnss.aidl +++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl @@ -217,10 +217,6 @@ interface IGnss { * Starts a location output stream using the IGnssCallback gnssLocationCb(), following the * settings from the most recent call to setPositionMode(). * - * When a location output stream is in progress, calling setPositionMode() does not change the - * settings of the current location output stream. stop() and start() must be called to make the - * new settings effective. - * * This output must operate independently of any GNSS location batching operations, * see the IGnssBatching for details. */ @@ -310,10 +306,6 @@ interface IGnss { /** * Sets the GnssPositionMode parameter, its associated recurrence value, the time between fixes, * requested fix accuracy, time to first fix. - * - * If a location output stream is in progress, calling this method does not affect the settings - * of current location output stream. stop() and start() must be called to make the new settings - * effective. */ void setPositionMode(in PositionModeOptions options); diff --git a/graphics/Android.bp b/graphics/Android.bp index ac5c17f156..0ad385260a 100644 --- a/graphics/Android.bp +++ b/graphics/Android.bp @@ -91,13 +91,15 @@ aidl_interface_defaults { cc_defaults { name: "android.hardware.graphics.composer3-ndk_static", static_libs: [ - "android.hardware.graphics.composer3-V3-ndk", + "android.hardware.drm.common-V1-ndk", + "android.hardware.graphics.composer3-V4-ndk", ], } cc_defaults { name: "android.hardware.graphics.composer3-ndk_shared", shared_libs: [ - "android.hardware.graphics.composer3-V3-ndk", + "android.hardware.drm.common-V1-ndk", + "android.hardware.graphics.composer3-V4-ndk", ], } diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp index 7157862884..3b0a5979d2 100644 --- a/graphics/composer/2.2/utils/vts/Android.bp +++ b/graphics/composer/2.2/utils/vts/Android.bp @@ -39,6 +39,7 @@ cc_library_static { shared_libs: [ "libui", "server_configurable_flags", + "libtracing_perfetto", ], static_libs: [ "android.hardware.graphics.composer@2.1-vts", diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp index bda41981ad..431b1b6fcc 100644 --- a/graphics/composer/2.2/vts/functional/Android.bp +++ b/graphics/composer/2.2/vts/functional/Android.bp @@ -55,6 +55,7 @@ cc_test { "libui", "android.hardware.common-V2-ndk", "server_configurable_flags", + "libtracing_perfetto", ], static_libs: [ "android.hardware.graphics.common@1.1", diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp index ace940a875..bba41daf38 100644 --- a/graphics/composer/aidl/Android.bp +++ b/graphics/composer/aidl/Android.bp @@ -29,7 +29,7 @@ aidl_interface { host_supported: true, vendor_available: true, double_loadable: true, - frozen: true, + frozen: false, srcs: [ "android/hardware/graphics/composer3/*.aidl", ], @@ -39,6 +39,7 @@ aidl_interface { ], imports: [ "android.hardware.common-V2", + "android.hardware.drm.common-V1", ], backend: { cpp: { diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl index 6892f06180..0fff52325b 100644 --- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/CommandResultPayload.aidl @@ -41,4 +41,5 @@ union CommandResultPayload { android.hardware.graphics.composer3.ReleaseFences releaseFences; android.hardware.graphics.composer3.PresentOrValidate presentOrValidateResult; android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness clientTargetProperty; + android.hardware.graphics.composer3.DisplayLuts displayLuts; } diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl new file mode 100644 index 0000000000..327e84c1d7 --- /dev/null +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayLuts.aidl @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.composer3; +@VintfStability +parcelable DisplayLuts { + long display; + android.hardware.graphics.composer3.DisplayLuts.LayerLut[] layerLuts; + parcelable LayerLut { + long layer; + android.hardware.graphics.composer3.Lut lut; + } +} diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl index e64bd5273e..cd27360655 100644 --- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl @@ -45,4 +45,5 @@ interface IComposerCallback { oneway void onVsyncIdle(long display); oneway void onRefreshRateChangedDebug(in android.hardware.graphics.composer3.RefreshRateChangedDebugData data); void onHotplugEvent(long display, android.hardware.graphics.common.DisplayHotplugEvent event); + oneway void onHdcpLevelsChanged(long display, in android.hardware.drm.HdcpLevels levels); } diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl index 87c8c18443..8b2b13caa1 100644 --- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LayerCommand.aidl @@ -57,4 +57,5 @@ parcelable LayerCommand { @nullable int[] bufferSlotsToClear; android.hardware.graphics.composer3.LayerLifecycleBatchCommandType layerLifecycleBatchCommandType; int newBufferSlotCount; + @nullable android.hardware.graphics.composer3.Lut[] luts; } diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl new file mode 100644 index 0000000000..5fae35be9d --- /dev/null +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Lut.aidl @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.composer3; +@VintfStability +parcelable Lut { + @nullable ParcelFileDescriptor pfd; + android.hardware.graphics.composer3.LutProperties lutProperties; +} diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl new file mode 100644 index 0000000000..5edceb5c35 --- /dev/null +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/LutProperties.aidl @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 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. + */ +/////////////////////////////////////////////////////////////////////////////// +// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. // +/////////////////////////////////////////////////////////////////////////////// + +// This file is a snapshot of an AIDL file. Do not edit it manually. There are +// two cases: +// 1). this is a frozen version file - do not edit this in any case. +// 2). this is a 'current' file. If you make a backwards compatible change to +// the interface (from the latest frozen version), the build system will +// prompt you to update this file with `m -update-api`. +// +// You must not make a backward incompatible change to any AIDL file built +// with the aidl_interface module type with versions property set. The module +// type is used to build AIDL files in a way that they can be used across +// independently updatable components of the system. If a device is shipped +// with such a backward incompatible change, it has a high risk of breaking +// later when a module using the interface is updated, e.g., Mainline modules. + +package android.hardware.graphics.composer3; +@VintfStability +parcelable LutProperties { + android.hardware.graphics.composer3.LutProperties.Dimension dimension; + long size; + android.hardware.graphics.composer3.LutProperties.SamplingKey[] samplingKeys; + @VintfStability + enum Dimension { + ONE_D = 1, + THREE_D = 3, + } + @VintfStability + enum SamplingKey { + RGB, + MAX_RGB, + } +} diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl index 7d31ea3b1e..dae78fd88b 100644 --- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl +++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/OverlayProperties.aidl @@ -36,6 +36,7 @@ package android.hardware.graphics.composer3; parcelable OverlayProperties { android.hardware.graphics.composer3.OverlayProperties.SupportedBufferCombinations[] combinations; boolean supportMixedColorSpaces; + @nullable android.hardware.graphics.composer3.LutProperties[] lutProperties; parcelable SupportedBufferCombinations { android.hardware.graphics.common.PixelFormat[] pixelFormats; android.hardware.graphics.common.Dataspace[] standards; diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl index 99c91aa32e..94fc3d05f7 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/CommandResultPayload.aidl @@ -19,6 +19,7 @@ package android.hardware.graphics.composer3; import android.hardware.graphics.composer3.ChangedCompositionTypes; import android.hardware.graphics.composer3.ClientTargetPropertyWithBrightness; import android.hardware.graphics.composer3.CommandError; +import android.hardware.graphics.composer3.DisplayLuts; import android.hardware.graphics.composer3.DisplayRequest; import android.hardware.graphics.composer3.PresentFence; import android.hardware.graphics.composer3.PresentOrValidate; @@ -96,4 +97,13 @@ union CommandResultPayload { * the SDR buffers when an HDR layer is simultaneously device-composited. */ ClientTargetPropertyWithBrightness clientTargetProperty; + + /** + * Sets the Lut(s) for the layers. + * + * HWC should only request Lut(s) if SurfaceFlinger does not send the Lut(s) to the HWC. + * The main use-case is like HDR10+ or Dolby Vision where there is no Lut to send from + * SurfaceFlinger. + */ + DisplayLuts displayLuts; } diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl new file mode 100644 index 0000000000..ac0a60634a --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayLuts.aidl @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.graphics.composer3; + +import android.hardware.graphics.composer3.Lut; + +/** + * LUT (Look-Up Table) Interface for Color Transformation. + * + * This interface allows the HWC (Hardware Composer) to define and communicate Luts + * to SurfaceFlinger. + */ +@VintfStability +parcelable DisplayLuts { + /** + * The display which the layerLuts list is for. + */ + long display; + + parcelable LayerLut { + /** + * The layer that the HWC is requesting a LUT to be applied during GPU composition. + */ + long layer; + /** + * A Lut specified by the HWC for given HDR layers that don't have Luts provided. + */ + Lut lut; + } + + LayerLut[] layerLuts; +} diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl index 96eccd79bd..a1d61fddd7 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl @@ -16,6 +16,7 @@ package android.hardware.graphics.composer3; +import android.hardware.drm.HdcpLevels; import android.hardware.graphics.common.DisplayHotplugEvent; import android.hardware.graphics.composer3.RefreshRateChangedDebugData; import android.hardware.graphics.composer3.VsyncPeriodChangeTimeline; @@ -139,4 +140,12 @@ interface IComposerCallback { * @param event is the type of event that occurred. */ void onHotplugEvent(long display, DisplayHotplugEvent event); + + /** + * Notify the client the HDCP levels of the display changed. + * + * @param display is the display whose HDCP levels have changed. + * @param levels is the new HDCP levels. + */ + oneway void onHdcpLevelsChanged(long display, in HdcpLevels levels); } diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl index e961c48700..bf4f504d01 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LayerCommand.aidl @@ -24,6 +24,7 @@ import android.hardware.graphics.composer3.Buffer; import android.hardware.graphics.composer3.Color; import android.hardware.graphics.composer3.LayerBrightness; import android.hardware.graphics.composer3.LayerLifecycleBatchCommandType; +import android.hardware.graphics.composer3.Lut; import android.hardware.graphics.composer3.ParcelableBlendMode; import android.hardware.graphics.composer3.ParcelableComposition; import android.hardware.graphics.composer3.ParcelableDataspace; @@ -279,4 +280,9 @@ parcelable LayerCommand { * Specifies the number of buffer slot to be reserved. */ int newBufferSlotCount; + + /** + * Sets the lut(s) for the layer. + */ + @nullable Lut[] luts; } diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl new file mode 100644 index 0000000000..abfeb148e6 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Lut.aidl @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.graphics.composer3; + +import android.hardware.graphics.composer3.LutProperties; + +/** + * LUT (Look-Up Table) Interface for Color Transformation. + * + * This interface allows the HWC (Hardware Composer) to define and communicate LUTs + * with SurfaceFlinger. + */ + +@VintfStability +parcelable Lut { + /** + * A handle to a memory region. + * If the file descriptor is not set, this means that the HWC doesn't specify a Lut. + * + * When specifying a Lut, the HWC is required to follow the instructions as below: + * 1. use `memfd_create` to create a shared memory segment + * with the size specified in lutProperties. + * 2. use `mmap` to map the shared memory segment into its own virtual address space. + * PROT_READ/PROT_WRITE recommended for prot argument. + * + * For data precision, 32-bit float is used to specify a Lut by both the HWC and + * the platform. + * + * For unflattening/flattening 3D Lut(s), the algorithm below should be observed + * by both the HWC and the platform. + * Assuming that we have a 3D array `ORIGINAL[WIDTH, HEIGHT, DEPTH]`, we would turn it into + * `FLAT[WIDTH * HEIGHT * DEPTH]` by + * + * `FLAT[z + DEPTH * (y + HEIGHT * x)] = ORIGINAL[x, y, z]` + */ + @nullable ParcelFileDescriptor pfd; + + /** + * The properties of the Lut. + */ + LutProperties lutProperties; +} diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl new file mode 100644 index 0000000000..47ec390670 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/LutProperties.aidl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.graphics.composer3; + +/** + * The properties of the LUT (Look-Up Table). + */ +@VintfStability +parcelable LutProperties { + /** + * The dimension of the Lut. + * Either 1d or 3d. + */ + @VintfStability enum Dimension { ONE_D = 1, THREE_D = 3 } + Dimension dimension; + + /** + * The size of the Lut. + * This refers to the length of a 1D Lut, or the grid size of a 3D one. + */ + long size; + + /** + * SamplingKey is about how a Lut can be sampled. + * A Lut can be sampled in more than one way, + * but only one sampling method is used at one time. + * + * The implementations should use a sampling strategy + * at least as good as linear sampling. + */ + // TODO(b/358422255): add sampling ways + @VintfStability enum SamplingKey { RGB, MAX_RGB } + SamplingKey[] samplingKeys; +} diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl index c25eea484f..b97cdcc998 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/OverlayProperties.aidl @@ -16,6 +16,8 @@ package android.hardware.graphics.composer3; +import android.hardware.graphics.composer3.LutProperties; + @VintfStability parcelable OverlayProperties { parcelable SupportedBufferCombinations { @@ -42,4 +44,8 @@ parcelable OverlayProperties { // True if the DPU is able to color manage at least two overlays // with different input colorspaces, false otherwise. boolean supportMixedColorSpaces; + + // Array of lut properties in order that the HWC supports. + // The list accepts 1D lut(s) and 3D lut(s). + @nullable LutProperties[] lutProperties; } diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h index 76ba24b0b2..331d717356 100644 --- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h +++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientReader.h @@ -27,9 +27,8 @@ #include #include -#include #include - +#include #include #include @@ -84,6 +83,10 @@ class ComposerClientReader { parseSetClientTargetProperty(std::move( result.get())); break; + case CommandResultPayload::Tag::displayLuts: + parseSetDisplayLuts( + std::move(result.get())); + break; } } } @@ -182,6 +185,20 @@ class ComposerClientReader { return std::move(data.clientTargetProperty); } + // Get the lut(s) requested by hardware composer. + std::vector takeDisplayLuts(int64_t display) { + LOG_ALWAYS_FATAL_IF(mDisplay && display != *mDisplay); + auto found = mReturnData.find(display); + + // If not found, return the empty vector + if (found == mReturnData.end()) { + return {}; + } + + ReturnData& data = found->second; + return std::move(data.layerLuts); + } + private: void resetData() { mErrors.clear(); @@ -227,6 +244,18 @@ class ComposerClientReader { data.clientTargetProperty = std::move(clientTargetProperty); } + void parseSetDisplayLuts(DisplayLuts&& displayLuts) { + LOG_ALWAYS_FATAL_IF(mDisplay && displayLuts.display != *mDisplay); + auto& data = mReturnData[displayLuts.display]; + for (auto& layerLut : displayLuts.layerLuts) { + if (layerLut.lut.pfd.get() >= 0) { + data.layerLuts.push_back( + {layerLut.layer, Lut{ndk::ScopedFileDescriptor(layerLut.lut.pfd.release()), + layerLut.lut.lutProperties}}); + } + } + } + struct ReturnData { DisplayRequest displayRequests; std::vector changedLayers; @@ -238,6 +267,7 @@ class ComposerClientReader { .clientTargetProperty = {common::PixelFormat::RGBA_8888, Dataspace::UNKNOWN}, .brightness = 1.f, }; + std::vector layerLuts; }; std::vector mErrors; diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h index a1ccbfe047..02fb3aab28 100644 --- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h +++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -245,6 +246,15 @@ class ComposerClientWriter final { getLayerCommand(display, layer).blockingRegion.emplace(blocking.begin(), blocking.end()); } + void setLayerLuts(int64_t display, int64_t layer, std::vector& luts) { + std::vector> currentLuts; + for (auto& lut : luts) { + currentLuts.push_back(std::make_optional( + {ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties})); + } + getLayerCommand(display, layer).luts.emplace(std::move(currentLuts)); + } + std::vector takePendingCommands() { flushLayerCommand(); flushDisplayCommand(); diff --git a/graphics/composer/aidl/vts/Android.bp b/graphics/composer/aidl/vts/Android.bp index 3464fe998b..894ca52452 100644 --- a/graphics/composer/aidl/vts/Android.bp +++ b/graphics/composer/aidl/vts/Android.bp @@ -57,6 +57,7 @@ cc_test { "libprocessgroup", "libvndksupport", "server_configurable_flags", + "libtracing_perfetto", ], header_libs: [ "android.hardware.graphics.composer3-command-buffer", @@ -65,6 +66,7 @@ cc_test { "android.hardware.graphics.common@1.2", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", + "android.hardware.drm.common-V1-ndk", "libaidlcommonsupport", "libarect", "libbase", diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp index 544f69297a..1f7972cb72 100644 --- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp +++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp @@ -208,4 +208,15 @@ int32_t GraphicsComposerCallback::getInvalidRefreshRateDebugEnabledCallbackCount } } +::ndk::ScopedAStatus GraphicsComposerCallback::onHdcpLevelsChanged( + int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) { + std::scoped_lock lock(mMutex); + + const auto it = std::find(mDisplays.begin(), mDisplays.end(), in_display); + if (it != mDisplays.end()) { + mHdcpLevelChangedCount++; + } + return ::ndk::ScopedAStatus::ok(); +} + } // namespace aidl::android::hardware::graphics::composer3::vts diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h index 7a8d4a35b8..97f8e2bd0e 100644 --- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h +++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h @@ -65,6 +65,8 @@ class GraphicsComposerCallback : public BnComposerCallback { const RefreshRateChangedDebugData&) override; virtual ::ndk::ScopedAStatus onHotplugEvent(int64_t in_display, common::DisplayHotplugEvent) override; + virtual ::ndk::ScopedAStatus onHdcpLevelsChanged( + int64_t in_display, const ::aidl::android::hardware::drm::HdcpLevels&) override; mutable std::mutex mMutex; // the set of all currently connected displays @@ -88,6 +90,7 @@ class GraphicsComposerCallback : public BnComposerCallback { int32_t mInvalidVsyncPeriodChangeCount GUARDED_BY(mMutex) = 0; int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0; int32_t mInvalidRefreshRateDebugEnabledCallbackCount GUARDED_BY(mMutex) = 0; + int32_t mHdcpLevelChangedCount GUARDED_BY(mMutex) = 0; }; } // namespace aidl::android::hardware::graphics::composer3::vts diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp index 283b8ce2e4..9d5928d896 100644 --- a/graphics/composer/aidl/vts/ReadbackVts.cpp +++ b/graphics/composer/aidl/vts/ReadbackVts.cpp @@ -16,6 +16,7 @@ #include "ReadbackVts.h" #include +#include #include "RenderEngineVts.h" #include "renderengine/ExternalTexture.h" #include "renderengine/impl/ExternalTexture.h" @@ -106,37 +107,72 @@ LayerSettings TestLayer::toRenderEngineLayerSettings() { return layerSettings; } -int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) { +int32_t ReadbackHelper::GetBitsPerChannel(common::PixelFormat pixelFormat) { switch (pixelFormat) { + case common::PixelFormat::RGBA_1010102: + return 10; case common::PixelFormat::RGBA_8888: - return 4; case common::PixelFormat::RGB_888: - return 3; + return 8; default: return -1; } } -void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData, +int32_t ReadbackHelper::GetAlphaBits(common::PixelFormat pixelFormat) { + switch (pixelFormat) { + case common::PixelFormat::RGBA_8888: + return 8; + case common::PixelFormat::RGBA_1010102: + return 2; + case common::PixelFormat::RGB_888: + return 0; + default: + return -1; + } +} + +void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, + int32_t bytesPerPixel, void* bufferData, common::PixelFormat pixelFormat, std::vector desiredPixelColors) { ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 || - pixelFormat == common::PixelFormat::RGBA_8888); - int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat); + pixelFormat == common::PixelFormat::RGBA_8888 || + pixelFormat == common::PixelFormat::RGBA_1010102); + int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat); + int32_t alphaBits = GetAlphaBits(pixelFormat); + ASSERT_NE(-1, alphaBits); + ASSERT_NE(-1, bitsPerChannel); ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - auto pixel = row * static_cast(width) + col; + + uint32_t maxValue = (1 << bitsPerChannel) - 1; + uint32_t maxAlphaValue = (1 << alphaBits) - 1; + for (uint32_t row = 0; row < height; row++) { + for (uint32_t col = 0; col < width; col++) { + auto pixel = row * width + col; Color srcColor = desiredPixelColors[static_cast(pixel)]; - int offset = (row * static_cast(stride) + col) * bytesPerPixel; - uint8_t* pixelColor = (uint8_t*)bufferData + offset; - pixelColor[0] = static_cast(std::round(255.0f * srcColor.r)); - pixelColor[1] = static_cast(std::round(255.0f * srcColor.g)); - pixelColor[2] = static_cast(std::round(255.0f * srcColor.b)); + uint32_t offset = (row * stride + col) * static_cast(bytesPerPixel); - if (bytesPerPixel == 4) { - pixelColor[3] = static_cast(std::round(255.0f * srcColor.a)); + uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset); + + uint32_t red = static_cast(std::round(maxValue * srcColor.r)); + uint32_t green = static_cast(std::round(maxValue * srcColor.g)); + uint32_t blue = static_cast(std::round(maxValue * srcColor.b)); + + // Boo we're not word aligned so special case this. + if (pixelFormat == common::PixelFormat::RGB_888) { + uint8_t* pixelColor = (uint8_t*)pixelStart; + pixelColor[0] = static_cast(red); + pixelColor[1] = static_cast(green); + pixelColor[2] = static_cast(blue); + } else { + uint32_t alpha = static_cast(std::round(maxAlphaValue * srcColor.a)); + uint32_t color = (alpha << (32 - alphaBits)) | + (blue << (32 - alphaBits - bitsPerChannel)) | + (green << (32 - alphaBits - bitsPerChannel * 2)) | + (red << (32 - alphaBits - bitsPerChannel * 3)); + *pixelStart = color; } } } @@ -165,7 +201,8 @@ void ReadbackHelper::fillColorsArea(std::vector& expectedColors, int32_t bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat, const common::Dataspace& dataspace) { if (pixelFormat != common::PixelFormat::RGB_888 && - pixelFormat != common::PixelFormat::RGBA_8888) { + pixelFormat != common::PixelFormat::RGBA_8888 && + pixelFormat != common::PixelFormat::RGBA_1010102) { return false; } if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) { @@ -175,36 +212,110 @@ bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat, } void ReadbackHelper::compareColorBuffers(const std::vector& expectedColors, void* bufferData, - const uint32_t stride, const uint32_t width, - const uint32_t height, common::PixelFormat pixelFormat) { - const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat); - ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - auto pixel = row * static_cast(width) + col; - int offset = (row * static_cast(stride) + col) * bytesPerPixel; - uint8_t* pixelColor = (uint8_t*)bufferData + offset; + const uint32_t stride, int32_t bytesPerPixel, + const uint32_t width, const uint32_t height, + common::PixelFormat pixelFormat) { + int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat); + int32_t alphaBits = GetAlphaBits(pixelFormat); + ASSERT_GT(bytesPerPixel, 0); + ASSERT_NE(-1, alphaBits); + ASSERT_NE(-1, bitsPerChannel); + uint32_t maxValue = (1 << bitsPerChannel) - 1; + uint32_t maxAlphaValue = (1 << alphaBits) - 1; + for (uint32_t row = 0; row < height; row++) { + for (uint32_t col = 0; col < width; col++) { + auto pixel = row * width + col; const Color expectedColor = expectedColors[static_cast(pixel)]; - ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]); - ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]); - ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]); + + uint32_t offset = (row * stride + col) * static_cast(bytesPerPixel); + uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset); + + uint32_t expectedRed = static_cast(std::round(maxValue * expectedColor.r)); + uint32_t expectedGreen = static_cast(std::round(maxValue * expectedColor.g)); + uint32_t expectedBlue = static_cast(std::round(maxValue * expectedColor.b)); + + // Boo we're not word aligned so special case this. + if (pixelFormat == common::PixelFormat::RGB_888) { + uint8_t* pixelColor = (uint8_t*)pixelStart; + ASSERT_EQ(pixelColor[0], static_cast(expectedRed)) + << "Red channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(pixelColor[1], static_cast(expectedGreen)) + << "Green channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(pixelColor[2], static_cast(expectedBlue)) + << "Blue channel mismatch at (" << row << ", " << col << ")"; + } else { + uint32_t expectedAlpha = + static_cast(std::round(maxAlphaValue * expectedColor.a)); + + uint32_t actualRed = + (*pixelStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue; + uint32_t actualGreen = + (*pixelStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue; + uint32_t actualBlue = (*pixelStart >> (32 - alphaBits - bitsPerChannel)) & maxValue; + uint32_t actualAlpha = (*pixelStart >> (32 - alphaBits)) & maxAlphaValue; + + ASSERT_EQ(expectedRed, actualRed) + << "Red channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(expectedGreen, actualGreen) + << "Green channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(expectedBlue, actualBlue) + << "Blue channel mismatch at (" << row << ", " << col << ")"; + } } } } void ReadbackHelper::compareColorBuffers(void* expectedBuffer, void* actualBuffer, - const uint32_t stride, const uint32_t width, - const uint32_t height, common::PixelFormat pixelFormat) { - const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat); - ASSERT_NE(-1, bytesPerPixel); - for (int row = 0; row < height; row++) { - for (int col = 0; col < width; col++) { - int offset = (row * static_cast(stride) + col) * bytesPerPixel; - uint8_t* expectedColor = (uint8_t*)expectedBuffer + offset; - uint8_t* actualColor = (uint8_t*)actualBuffer + offset; - ASSERT_EQ(expectedColor[0], actualColor[0]); - ASSERT_EQ(expectedColor[1], actualColor[1]); - ASSERT_EQ(expectedColor[2], actualColor[2]); + const uint32_t stride, int32_t bytesPerPixel, + const uint32_t width, const uint32_t height, + common::PixelFormat pixelFormat) { + int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat); + int32_t alphaBits = GetAlphaBits(pixelFormat); + ASSERT_GT(bytesPerPixel, 0); + ASSERT_NE(-1, alphaBits); + ASSERT_NE(-1, bitsPerChannel); + uint32_t maxValue = (1 << bitsPerChannel) - 1; + uint32_t maxAlphaValue = (1 << alphaBits) - 1; + for (uint32_t row = 0; row < height; row++) { + for (uint32_t col = 0; col < width; col++) { + uint32_t offset = (row * stride + col) * static_cast(bytesPerPixel); + uint32_t* expectedStart = (uint32_t*)((uint8_t*)expectedBuffer + offset); + uint32_t* actualStart = (uint32_t*)((uint8_t*)actualBuffer + offset); + + // Boo we're not word aligned so special case this. + if (pixelFormat == common::PixelFormat::RGB_888) { + uint8_t* expectedPixel = (uint8_t*)expectedStart; + uint8_t* actualPixel = (uint8_t*)actualStart; + ASSERT_EQ(actualPixel[0], expectedPixel[0]) + << "Red channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(actualPixel[1], expectedPixel[1]) + << "Green channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(actualPixel[2], expectedPixel[2]) + << "Blue channel mismatch at (" << row << ", " << col << ")"; + } else { + uint32_t expectedRed = + (*expectedStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue; + uint32_t expectedGreen = + (*expectedStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue; + uint32_t expectedBlue = + (*expectedStart >> (32 - alphaBits - bitsPerChannel)) & maxValue; + uint32_t expectedAlpha = (*expectedStart >> (32 - alphaBits)) & maxAlphaValue; + + uint32_t actualRed = + (*actualStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue; + uint32_t actualGreen = + (*actualStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue; + uint32_t actualBlue = + (*actualStart >> (32 - alphaBits - bitsPerChannel)) & maxValue; + uint32_t actualAlpha = (*actualStart >> (32 - alphaBits)) & maxAlphaValue; + + ASSERT_EQ(expectedRed, actualRed) + << "Red channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(expectedGreen, actualGreen) + << "Green channel mismatch at (" << row << ", " << col << ")"; + ASSERT_EQ(expectedBlue, actualBlue) + << "Blue channel mismatch at (" << row << ", " << col << ")"; + } } } } @@ -258,12 +369,13 @@ void ReadbackBuffer::checkReadbackBuffer(const std::vector& expectedColor auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()), &bytesPerPixel, &bytesPerStride); EXPECT_EQ(::android::OK, status); - ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888); + ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888 || + mPixelFormat == PixelFormat::RGBA_1010102); const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0) ? static_cast(bytesPerStride / bytesPerPixel) : mGraphicBuffer->getStride(); - ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight, - mPixelFormat); + ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, bytesPerPixel, mWidth, + mHeight, mPixelFormat); status = mGraphicBuffer->unlock(); EXPECT_EQ(::android::OK, status); } @@ -353,8 +465,8 @@ void TestBufferLayer::fillBuffer(std::vector& expectedColors) { ? static_cast(bytesPerStride / bytesPerPixel) : mGraphicBuffer->getStride(); EXPECT_EQ(::android::OK, status); - ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData, - mPixelFormat, expectedColors)); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bytesPerPixel, + bufData, mPixelFormat, expectedColors)); const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence); ASSERT_EQ(::android::OK, unlockStatus); diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h index 8ac0f4bb99..e3b2384f5c 100644 --- a/graphics/composer/aidl/vts/ReadbackVts.h +++ b/graphics/composer/aidl/vts/ReadbackVts.h @@ -172,10 +172,12 @@ class ReadbackHelper { static Dataspace getDataspaceForColorMode(ColorMode mode); - static int32_t GetBytesPerPixel(PixelFormat pixelFormat); + static int32_t GetBitsPerChannel(PixelFormat pixelFormat); + static int32_t GetAlphaBits(PixelFormat pixelFormat); - static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData, - PixelFormat pixelFormat, std::vector desiredPixelColors); + static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, int32_t bytesPerPixel, + void* bufferData, PixelFormat pixelFormat, + std::vector desiredPixelColors); static void clearColors(std::vector& expectedColors, int32_t width, int32_t height, int32_t displayWidth); @@ -189,11 +191,12 @@ class ReadbackHelper { static const std::vector dataspaces; static void compareColorBuffers(const std::vector& expectedColors, void* bufferData, - const uint32_t stride, const uint32_t width, - const uint32_t height, PixelFormat pixelFormat); - static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride, + const uint32_t stride, int32_t bytesPerPixel, const uint32_t width, const uint32_t height, PixelFormat pixelFormat); + static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride, + int32_t bytesPerPixel, const uint32_t width, + const uint32_t height, PixelFormat pixelFormat); }; class ReadbackBuffer { diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp index bc5eb6f77d..8f8b5fd828 100644 --- a/graphics/composer/aidl/vts/RenderEngineVts.cpp +++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp @@ -81,7 +81,7 @@ void TestRenderEngine::checkColorBuffer(const std::vector& expectedColors const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0) ? static_cast(bytesPerStride / bytesPerPixel) : mGraphicBuffer->getStride(); - ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride, + ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride, bytesPerPixel, mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(), mFormat); ASSERT_EQ(::android::OK, mGraphicBuffer->unlock()); @@ -108,7 +108,7 @@ void TestRenderEngine::checkColorBuffer(const ::android::sp<::android::GraphicBu ASSERT_EQ(renderedStride, bufferStride); - ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride, + ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride, bytesPerPixel, mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(), mFormat); ASSERT_EQ(::android::OK, buffer->unlock()); diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp index 3d9253f917..9db8794fd6 100644 --- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp +++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp @@ -496,11 +496,14 @@ TEST_P(GraphicsCompositionTest, ClientComposition) { const auto& buffer = graphicBuffer->handle; void* clientBufData; const auto stride = static_cast(graphicBuffer->stride); - graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData); + int bytesPerPixel = -1; + int bytesPerStride = -1; + graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData, + &bytesPerPixel, &bytesPerStride); - ASSERT_NO_FATAL_FAILURE( - ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride, - clientBufData, clientFormat, expectedColors)); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer( + layer->getWidth(), layer->getHeight(), stride, bytesPerPixel, clientBufData, + clientFormat, expectedColors)); int32_t clientFence; const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence); ASSERT_EQ(::android::OK, unlockStatus); @@ -677,15 +680,18 @@ TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) { const auto& buffer = graphicBuffer->handle; void* clientBufData; + int bytesPerPixel = -1; + int bytesPerStride = -1; graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()}, - &clientBufData); + &clientBufData, &bytesPerPixel, &bytesPerStride); std::vector clientColors( static_cast(getDisplayWidth() * getDisplayHeight())); ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED); ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer( static_cast(getDisplayWidth()), static_cast(getDisplayHeight()), - graphicBuffer->getStride(), clientBufData, clientFormat, clientColors)); + graphicBuffer->getStride(), bytesPerPixel, clientBufData, clientFormat, + clientColors)); int32_t clientFence; const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence); ASSERT_EQ(::android::OK, unlockStatus); diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp index bae362f04e..f398c53f62 100644 --- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp +++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp @@ -718,6 +718,38 @@ TEST_P(GraphicsMapperHidlTest, LockUnlockBasic) { ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle))); } +/** + * Test IMapper::lock and IMapper::unlock with no CPU usage requested. + */ +TEST_P(GraphicsMapperHidlTest, LockUnlockNoCPUUsage) { + const auto& info = mDummyDescriptorInfo; + + const native_handle_t* bufferHandle; + uint32_t stride; + ASSERT_NO_FATAL_FAILURE( + bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride)); + + // lock buffer with 0 usage + const IMapper::Rect region{0, 0, static_cast(info.width), + static_cast(info.height)}; + + hidl_handle acquireFenceHandle; + + auto buffer = const_cast(bufferHandle); + mGralloc->getMapper()->lock(buffer, 0, region, acquireFenceHandle, + [&](const auto& tmpError, const auto& /*tmpData*/) { + EXPECT_EQ(Error::BAD_VALUE, tmpError) + << "Locking with 0 access succeeded"; + }); + + mGralloc->getMapper()->unlock(buffer, [&](const auto& tmpError, const auto&) { + EXPECT_EQ(Error::BAD_BUFFER, tmpError) + << "Unlocking not locked buffer succeeded"; + }); + + mGralloc->freeBuffer(bufferHandle); +} + /** * Test multiple operations associated with different color formats */ diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp index 1e0c427715..bdbe4d06b8 100644 --- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp +++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp @@ -749,6 +749,42 @@ TEST_P(GraphicsMapperStableCTests, LockUnlockBasic) { } } +/** + * Test IMapper::lock and IMapper::unlock with no CPU usage requested. + */ +TEST_P(GraphicsMapperStableCTests, LockUnlockNoCPUUsage) { + constexpr auto usage = BufferUsage::CPU_READ_NEVER | BufferUsage::CPU_WRITE_NEVER; + auto buffer = allocate({ + .name = {"VTS_TEMP"}, + .width = 64, + .height = 64, + .layerCount = 1, + .format = PixelFormat::RGBA_8888, + .usage = usage, + .reservedSize = 0, + }); + ASSERT_NE(nullptr, buffer.get()); + + // lock buffer for writing + const auto& info = buffer->info(); + const ARect region{0, 0, info.width, info.height}; + auto handle = buffer->import(); + uint8_t* data = nullptr; + + EXPECT_EQ(AIMAPPER_ERROR_BAD_VALUE, + mapper()->v5.lock(*handle, static_cast(info.usage), + region, -1,(void**)&data)) + << "Locking with 0 access succeeded"; + + int releaseFence = -1; + EXPECT_EQ(AIMAPPER_ERROR_BAD_BUFFER, + mapper()->v5.unlock(*handle, &releaseFence)) + << "Unlocking not locked buffer succeeded"; + if (releaseFence != -1) { + close(releaseFence); + } +} + /** * Test multiple operations associated with different color formats */ diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp index 56997a975d..c101f56059 100644 --- a/keymaster/aidl/Android.bp +++ b/keymaster/aidl/Android.bp @@ -18,6 +18,13 @@ aidl_interface { java: { platform_apis: true, }, + ndk: { + apex_available: [ + "com.android.hardware.biometrics.face.virtual", + "com.android.hardware.biometrics.fingerprint.virtual", + "//apex_available:platform", + ], + }, rust: { enabled: true, }, diff --git a/radio/aidl/vts/radio_sim_test.cpp b/radio/aidl/vts/radio_sim_test.cpp index ec1facc085..2823977c3b 100644 --- a/radio/aidl/vts/radio_sim_test.cpp +++ b/radio/aidl/vts/radio_sim_test.cpp @@ -533,7 +533,7 @@ TEST_P(RadioSimTest, setAllowedCarriers) { EXPECT_EQ(RadioError::NONE, radioRsp_sim->rspInfo.error); if (aidl_version <= 2) { - EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size()); + ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarriers.size()); EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarriers.size()); ASSERT_TRUE(std::string("123") == @@ -545,7 +545,7 @@ TEST_P(RadioSimTest, setAllowedCarriers) { ASSERT_TRUE(radioRsp_sim->carrierRestrictionsResp.allowedCarriersPrioritized); EXPECT_EQ(SimLockMultiSimPolicy::NO_MULTISIM_POLICY, radioRsp_sim->multiSimPolicyResp); } else { - EXPECT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size()); + ASSERT_EQ(1, radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList.size()); EXPECT_EQ(0, radioRsp_sim->carrierRestrictionsResp.excludedCarrierInfoList.size()); ASSERT_EQ(std::string("123"), radioRsp_sim->carrierRestrictionsResp.allowedCarrierInfoList[0].mcc); diff --git a/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl index 9098894cc7..4904c3f65d 100644 --- a/sensors/aidl/android/hardware/sensors/SensorType.aidl +++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl @@ -718,8 +718,8 @@ enum SensorType { HEADING = 42, /** - * Base for device manufacturers private sensor types. - * These sensor types can't be exposed in the SDK. + * Base of the range reserved for device manufacturers' private sensor + * types. These sensor types aren't documented in the SDK. */ DEVICE_PRIVATE_BASE = 0x10000, } diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h index 2adbc9dfb4..c90db69514 100644 --- a/sensors/aidl/default/include/sensors-impl/Sensors.h +++ b/sensors/aidl/default/include/sensors-impl/Sensors.h @@ -97,9 +97,13 @@ class Sensors : public BnSensors, public ISensorsEventCallback { return; } if (mEventQueue->write(&events.front(), events.size())) { + if (mEventQueueFlag == nullptr) { + // Don't take the wake lock if we can't wake the receiver to avoid holding it + // indefinitely. + return; + } mEventQueueFlag->wake( static_cast(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS)); - if (wakeup) { // Keep track of the number of outstanding WAKE_UP events in order to properly hold // a wake lock until the framework has secured a wake lock diff --git a/tests/extension/vibrator/aidl/Android.bp b/tests/extension/vibrator/aidl/Android.bp index 0306dca626..3ef8749caf 100644 --- a/tests/extension/vibrator/aidl/Android.bp +++ b/tests/extension/vibrator/aidl/Android.bp @@ -37,6 +37,15 @@ aidl_interface { java: { enabled: false, }, + ndk: { + enabled: true, + }, + cpp: { + enabled: false, + }, + rust: { + enabled: false, + }, }, frozen: true, versions_with_info: [ diff --git a/tests/extension/vibrator/aidl/client/Android.bp b/tests/extension/vibrator/aidl/client/Android.bp index 284ac7459b..00510b7443 100644 --- a/tests/extension/vibrator/aidl/client/Android.bp +++ b/tests/extension/vibrator/aidl/client/Android.bp @@ -16,16 +16,10 @@ cc_test { srcs: [ // system code has the option to use the unstable C++ libbinder API // or the NDK one. For maximum code portability, using the ndk client - // makes the most sense, but both are provided here as an example. - "test-cpp-client.cpp", + // makes the most sense. "test-ndk-client.cpp", ], shared_libs: [ - "libbinder", - "libutils", - "android.hardware.vibrator-V2-cpp", - "android.hardware.tests.extension.vibrator-V1-cpp", - "libbinder_ndk", "android.hardware.vibrator-V2-ndk", "android.hardware.tests.extension.vibrator-V1-ndk", diff --git a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp b/tests/extension/vibrator/aidl/client/test-cpp-client.cpp deleted file mode 100644 index 015a3453cb..0000000000 --- a/tests/extension/vibrator/aidl/client/test-cpp-client.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -#include -#include -#include -#include -#include - -using android::checked_interface_cast; -using android::IBinder; -using android::IInterface; -using android::OK; -using android::sp; -using android::waitForVintfService; -using android::hardware::tests::extension::vibrator::Directionality; -using android::hardware::tests::extension::vibrator::ICustomVibrator; -using android::hardware::vibrator::IVibrator; - -TEST(Cpp, CallRootMethod) { - sp vib = waitForVintfService(); - ASSERT_NE(nullptr, vib.get()); - ASSERT_TRUE(vib->off().isOk()); -} - -TEST(Cpp, CallExtMethod) { - // normally you would want to cache this - sp vib = waitForVintfService(); - ASSERT_NE(nullptr, vib.get()); - - // getting the extension - sp ext; - ASSERT_EQ(OK, IInterface::asBinder(vib)->getExtension(&ext)); - sp cvib = checked_interface_cast(ext); - ASSERT_NE(nullptr, cvib.get()); - - // calling extension method - ASSERT_TRUE(cvib->setDirectionality(Directionality::TRANSVERSE).isOk()); -} diff --git a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp index c846495984..4dd86e8c5d 100644 --- a/tests/extension/vibrator/aidl/client/test-ndk-client.cpp +++ b/tests/extension/vibrator/aidl/client/test-ndk-client.cpp @@ -28,7 +28,7 @@ using ndk::SpAIBinder; static const std::string kInstance = std::string() + IVibrator::descriptor + "/default"; TEST(Ndk, CallRootMethod) { - SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str())); + SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str())); ASSERT_NE(nullptr, vibBinder.get()); std::shared_ptr vib = IVibrator::fromBinder(vibBinder); ASSERT_NE(nullptr, vib.get()); @@ -38,7 +38,7 @@ TEST(Ndk, CallRootMethod) { TEST(Ndk, CallExtMethod) { // normally you would want to cache this // - SpAIBinder vibBinder = SpAIBinder(AServiceManager_getService(kInstance.c_str())); + SpAIBinder vibBinder = SpAIBinder(AServiceManager_waitForService(kInstance.c_str())); ASSERT_NE(nullptr, vibBinder.get()); std::shared_ptr vib = IVibrator::fromBinder(vibBinder); ASSERT_NE(nullptr, vib.get()); diff --git a/tests/extension/vibrator/aidl/default/Android.bp b/tests/extension/vibrator/aidl/default/Android.bp index 5e156af645..479b4fd8dc 100644 --- a/tests/extension/vibrator/aidl/default/Android.bp +++ b/tests/extension/vibrator/aidl/default/Android.bp @@ -10,11 +10,6 @@ package { cc_binary { name: "android.hardware.tests.extension.vibrator-service.example", relative_install_path: "hw", - // normally you implement a service directly, but we are using an implementation - // from a library to attach our extension to. - static_libs: [ - "libvibratorexampleimpl", - ], // need to add this in the manifest and to init as well to use, see // android.hardware.vibrator-service.example. This binary is being tested @@ -23,6 +18,7 @@ cc_binary { vendor: true, srcs: [ "service.cpp", + "Vibrator.cpp", "CustomVibrator.cpp", ], shared_libs: [ diff --git a/tests/extension/vibrator/aidl/default/Vibrator.cpp b/tests/extension/vibrator/aidl/default/Vibrator.cpp new file mode 100644 index 0000000000..50840960d3 --- /dev/null +++ b/tests/extension/vibrator/aidl/default/Vibrator.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 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. + */ + +#include "Vibrator.h" + +#include + +namespace aidl::android::hardware::vibrator { + +ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { + // basic example with only amplitude control capability + *_aidl_return = IVibrator::CAP_AMPLITUDE_CONTROL; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::off() { + LOG(INFO) << "Vibrator off"; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, const std::shared_ptr&) { + LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) { + LOG(INFO) << "Vibrator set amplitude: " << amplitude; + if (amplitude <= 0.0f || amplitude > 1.0f) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::perform(Effect, EffectStrength, + const std::shared_ptr&, int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector* _aidl_return) { + *_aidl_return = {}; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::setExternalControl(bool) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive, int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::compose(const std::vector&, + const std::shared_ptr&) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t, Effect, EffectStrength) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getResonantFrequency(float*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getQFactor(float*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getFrequencyResolution(float*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector*) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +ndk::ScopedAStatus Vibrator::composePwle(const std::vector&, + const std::shared_ptr&) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); +} + +} // namespace aidl::android::hardware::vibrator diff --git a/tests/extension/vibrator/aidl/default/Vibrator.h b/tests/extension/vibrator/aidl/default/Vibrator.h new file mode 100644 index 0000000000..80916ae8e2 --- /dev/null +++ b/tests/extension/vibrator/aidl/default/Vibrator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 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 + +namespace aidl::android::hardware::vibrator { + +class Vibrator : public BnVibrator { + ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override; + ndk::ScopedAStatus off() override; + ndk::ScopedAStatus on(int32_t timeoutMs, + const std::shared_ptr& callback) override; + ndk::ScopedAStatus perform(Effect effect, EffectStrength strength, + const std::shared_ptr& callback, + int32_t* _aidl_return) override; + ndk::ScopedAStatus getSupportedEffects(std::vector* _aidl_return) override; + ndk::ScopedAStatus setAmplitude(float amplitude) override; + ndk::ScopedAStatus setExternalControl(bool enabled) override; + ndk::ScopedAStatus getCompositionDelayMax(int32_t* maxDelayMs); + ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize); + ndk::ScopedAStatus getSupportedPrimitives(std::vector* supported) override; + ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive, + int32_t* durationMs) override; + ndk::ScopedAStatus compose(const std::vector& composite, + const std::shared_ptr& callback) override; + ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector* _aidl_return) override; + ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override; + ndk::ScopedAStatus alwaysOnDisable(int32_t id) override; + ndk::ScopedAStatus getResonantFrequency(float* resonantFreqHz) override; + ndk::ScopedAStatus getQFactor(float* qFactor) override; + ndk::ScopedAStatus getFrequencyResolution(float* freqResolutionHz) override; + ndk::ScopedAStatus getFrequencyMinimum(float* freqMinimumHz) override; + ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector* _aidl_return) override; + ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t* durationMs) override; + ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t* maxSize) override; + ndk::ScopedAStatus getSupportedBraking(std::vector* supported) override; + ndk::ScopedAStatus composePwle(const std::vector& composite, + const std::shared_ptr& callback) override; +}; + +} // namespace aidl::android::hardware::vibrator diff --git a/tests/extension/vibrator/aidl/default/service.cpp b/tests/extension/vibrator/aidl/default/service.cpp index 16290df826..5917d0fb6f 100644 --- a/tests/extension/vibrator/aidl/default/service.cpp +++ b/tests/extension/vibrator/aidl/default/service.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include #include "CustomVibrator.h" +#include "Vibrator.h" #include #include diff --git a/tv/tuner/aidl/Android.bp b/tv/tuner/aidl/Android.bp index 6cbf362f53..efcc327734 100644 --- a/tv/tuner/aidl/Android.bp +++ b/tv/tuner/aidl/Android.bp @@ -41,6 +41,5 @@ aidl_interface { }, ], - frozen: true, } diff --git a/tv/tuner/aidl/default/Android.bp b/tv/tuner/aidl/default/Android.bp index 4f0d04bfa2..a76a65306a 100644 --- a/tv/tuner/aidl/default/Android.bp +++ b/tv/tuner/aidl/default/Android.bp @@ -29,7 +29,7 @@ cc_defaults { ], shared_libs: [ "android.hardware.common.fmq-V1-ndk", - "android.hardware.tv.tuner-V2-ndk", + "android.hardware.tv.tuner-V3-ndk", "libbase", "libbinder_ndk", "libcutils", diff --git a/tv/tuner/aidl/vts/functional/Android.bp b/tv/tuner/aidl/vts/functional/Android.bp index ae4f598493..4c961ad9b0 100644 --- a/tv/tuner/aidl/vts/functional/Android.bp +++ b/tv/tuner/aidl/vts/functional/Android.bp @@ -56,7 +56,7 @@ cc_test { "android.hardware.cas-V1-ndk", "android.hardware.common-V2-ndk", "android.hardware.common.fmq-V1-ndk", - "android.hardware.tv.tuner-V2-ndk", + "android.hardware.tv.tuner-V3-ndk", "libaidlcommonsupport", "libfmq", "libcutils", diff --git a/vibrator/aidl/Android.bp b/vibrator/aidl/Android.bp index d3b72ee070..b2d98f5b2f 100644 --- a/vibrator/aidl/Android.bp +++ b/vibrator/aidl/Android.bp @@ -15,15 +15,33 @@ aidl_interface { srcs: [ "android/hardware/vibrator/*.aidl", ], + headers: [ + "PersistableBundle_aidl", + ], stability: "vintf", backend: { java: { sdk_version: "system_current", }, + ndk: { + enabled: true, + }, + cpp: { + enabled: false, + }, + rust: { + enabled: false, + }, }, - versions: [ - "1", - "2", + versions_with_info: [ + { + version: "1", + imports: [], + }, + { + version: "2", + imports: [], + }, ], - frozen: true, + frozen: false, } diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl index b7afb663cf..0dcc657955 100644 --- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibrator.aidl @@ -58,15 +58,23 @@ interface IVibrator { int getPwleCompositionSizeMax(); android.hardware.vibrator.Braking[] getSupportedBraking(); void composePwle(in android.hardware.vibrator.PrimitivePwle[] composite, in android.hardware.vibrator.IVibratorCallback callback); - const int CAP_ON_CALLBACK = 1; - const int CAP_PERFORM_CALLBACK = 2; - const int CAP_AMPLITUDE_CONTROL = 4; - const int CAP_EXTERNAL_CONTROL = 8; - const int CAP_EXTERNAL_AMPLITUDE_CONTROL = 16; - const int CAP_COMPOSE_EFFECTS = 32; - const int CAP_ALWAYS_ON_CONTROL = 64; - const int CAP_GET_RESONANT_FREQUENCY = 128; - const int CAP_GET_Q_FACTOR = 256; - const int CAP_FREQUENCY_CONTROL = 512; - const int CAP_COMPOSE_PWLE_EFFECTS = 1024; + void performVendorEffect(in android.hardware.vibrator.VendorEffect vendorEffect, in android.hardware.vibrator.IVibratorCallback callback); + List getPwleV2FrequencyToOutputAccelerationMap(); + int getPwleV2PrimitiveDurationMaxMillis(); + int getPwleV2CompositionSizeMax(); + int getPwleV2PrimitiveDurationMinMillis(); + void composePwleV2(in android.hardware.vibrator.PwleV2Primitive[] composite, in android.hardware.vibrator.IVibratorCallback callback); + const int CAP_ON_CALLBACK = (1 << 0) /* 1 */; + const int CAP_PERFORM_CALLBACK = (1 << 1) /* 2 */; + const int CAP_AMPLITUDE_CONTROL = (1 << 2) /* 4 */; + const int CAP_EXTERNAL_CONTROL = (1 << 3) /* 8 */; + const int CAP_EXTERNAL_AMPLITUDE_CONTROL = (1 << 4) /* 16 */; + const int CAP_COMPOSE_EFFECTS = (1 << 5) /* 32 */; + const int CAP_ALWAYS_ON_CONTROL = (1 << 6) /* 64 */; + const int CAP_GET_RESONANT_FREQUENCY = (1 << 7) /* 128 */; + const int CAP_GET_Q_FACTOR = (1 << 8) /* 256 */; + const int CAP_FREQUENCY_CONTROL = (1 << 9) /* 512 */; + const int CAP_COMPOSE_PWLE_EFFECTS = (1 << 10) /* 1024 */; + const int CAP_PERFORM_VENDOR_EFFECTS = (1 << 11) /* 2048 */; + const int CAP_COMPOSE_PWLE_EFFECTS_V2 = (1 << 12) /* 4096 */; } diff --git a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl index 290c68d877..ef5794c644 100644 --- a/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/IVibratorManager.aidl @@ -40,12 +40,12 @@ interface IVibratorManager { void prepareSynced(in int[] vibratorIds); void triggerSynced(in android.hardware.vibrator.IVibratorCallback callback); void cancelSynced(); - const int CAP_SYNC = 1; - const int CAP_PREPARE_ON = 2; - const int CAP_PREPARE_PERFORM = 4; - const int CAP_PREPARE_COMPOSE = 8; - const int CAP_MIXED_TRIGGER_ON = 16; - const int CAP_MIXED_TRIGGER_PERFORM = 32; - const int CAP_MIXED_TRIGGER_COMPOSE = 64; - const int CAP_TRIGGER_CALLBACK = 128; + const int CAP_SYNC = (1 << 0) /* 1 */; + const int CAP_PREPARE_ON = (1 << 1) /* 2 */; + const int CAP_PREPARE_PERFORM = (1 << 2) /* 4 */; + const int CAP_PREPARE_COMPOSE = (1 << 3) /* 8 */; + const int CAP_MIXED_TRIGGER_ON = (1 << 4) /* 16 */; + const int CAP_MIXED_TRIGGER_PERFORM = (1 << 5) /* 32 */; + const int CAP_MIXED_TRIGGER_COMPOSE = (1 << 6) /* 64 */; + const int CAP_TRIGGER_CALLBACK = (1 << 7) /* 128 */; } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl similarity index 89% rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl index 75ed0700be..a5eda52bc7 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/NextEnrollment.aidl +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2OutputMapEntry.aidl @@ -31,11 +31,9 @@ // with such a backward incompatible change, it has a high risk of breaking // later when a module using the interface is updated, e.g., Mainline modules. -package android.hardware.biometrics.fingerprint; -/* @hide */ +package android.hardware.vibrator; @VintfStability -parcelable NextEnrollment { - int id; - android.hardware.biometrics.fingerprint.EnrollmentProgressStep[] progressSteps; - boolean result = true; +parcelable PwleV2OutputMapEntry { + float frequencyHz; + float maxOutputAccelerationGs; } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl similarity index 89% rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl index 173ac1706d..c4f3ea955a 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/EnrollmentProgressStep.aidl +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/PwleV2Primitive.aidl @@ -31,10 +31,10 @@ // with such a backward incompatible change, it has a high risk of breaking // later when a module using the interface is updated, e.g., Mainline modules. -package android.hardware.biometrics.fingerprint; -/* @hide */ +package android.hardware.vibrator; @VintfStability -parcelable EnrollmentProgressStep { - int durationMs; - android.hardware.biometrics.fingerprint.AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes; +parcelable PwleV2Primitive { + float amplitude; + float frequencyHz; + int timeMillis; } diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl similarity index 87% rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl rename to vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl index c1dc51c21d..62a738076c 100644 --- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/AcquiredInfoAndVendorCode.aidl +++ b/vibrator/aidl/aidl_api/android.hardware.vibrator/current/android/hardware/vibrator/VendorEffect.aidl @@ -31,10 +31,11 @@ // with such a backward incompatible change, it has a high risk of breaking // later when a module using the interface is updated, e.g., Mainline modules. -package android.hardware.biometrics.fingerprint; -/* @hide */ +package android.hardware.vibrator; @VintfStability -union AcquiredInfoAndVendorCode { - android.hardware.biometrics.fingerprint.AcquiredInfo acquiredInfo = android.hardware.biometrics.fingerprint.AcquiredInfo.UNKNOWN; - int vendorCode; +parcelable VendorEffect { + android.os.PersistableBundle vendorData; + android.hardware.vibrator.EffectStrength strength = android.hardware.vibrator.EffectStrength.MEDIUM; + float scale; + float vendorScale; } diff --git a/vibrator/aidl/android/hardware/vibrator/Braking.aidl b/vibrator/aidl/android/hardware/vibrator/Braking.aidl index 2bc51db3f6..f934ff2474 100644 --- a/vibrator/aidl/android/hardware/vibrator/Braking.aidl +++ b/vibrator/aidl/android/hardware/vibrator/Braking.aidl @@ -23,12 +23,12 @@ enum Braking { * No braking mechanism used. * This is the default if the hardware does not support any braking mechanism. */ - NONE, + NONE = 0, /** * Closed-loop active braking. * * This effect should produce a sharp, crisp end to the waveform * Support is optional. */ - CLAB, + CLAB = 1, } diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl index 531489824b..5f8ee8dacc 100644 --- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl +++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl @@ -24,13 +24,13 @@ enum CompositePrimitive { * * Support is required. */ - NOOP, + NOOP = 0, /** * This effect should produce a sharp, crisp click sensation. * * Support is required. */ - CLICK, + CLICK = 1, /** * A haptic effect that simulates downwards movement with gravity. Often * followed by extra energy of hitting and reverberation to augment @@ -38,43 +38,43 @@ enum CompositePrimitive { * * Support is optional. */ - THUD, + THUD = 2, /** * A haptic effect that simulates spinning momentum. * * Support is optional. */ - SPIN, + SPIN = 3, /** * A haptic effect that simulates quick upward movement against gravity. * * Support is required. */ - QUICK_RISE, + QUICK_RISE = 4, /** * A haptic effect that simulates slow upward movement against gravity. * * Support is required. */ - SLOW_RISE, + SLOW_RISE = 5, /** * A haptic effect that simulates quick downwards movement with gravity. * * Support is required. */ - QUICK_FALL, + QUICK_FALL = 6, /** * This very short effect should produce a light crisp sensation intended * to be used repetitively for dynamic feedback. * * Support is required. */ - LIGHT_TICK, + LIGHT_TICK = 7, /** * This very short low frequency effect should produce a light crisp sensation intended * to be used repetitively for dynamic feedback. * * Support is required. */ - LOW_TICK, + LOW_TICK = 8, } diff --git a/vibrator/aidl/android/hardware/vibrator/Effect.aidl b/vibrator/aidl/android/hardware/vibrator/Effect.aidl index c60bfe98dc..f5cf9e392c 100644 --- a/vibrator/aidl/android/hardware/vibrator/Effect.aidl +++ b/vibrator/aidl/android/hardware/vibrator/Effect.aidl @@ -24,57 +24,57 @@ enum Effect { * * This effect should produce a sharp, crisp click sensation. */ - CLICK, + CLICK = 0, /** * A double click effect. * * This effect should produce two sequential sharp, crisp click sensations with a minimal * amount of time between them. */ - DOUBLE_CLICK, + DOUBLE_CLICK = 1, /** * A tick effect. * * This effect should produce a soft, short sensation, like the tick of a clock. */ - TICK, + TICK = 2, /** * A thud effect. * * This effect should solid feeling bump, like the depression of a heavy mechanical button. */ - THUD, + THUD = 3, /** * A pop effect. * * A short, quick burst effect. */ - POP, + POP = 4, /** * A heavy click effect. * * This should produce a sharp striking sensation, like a click but stronger. */ - HEAVY_CLICK, + HEAVY_CLICK = 5, /** * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a * pattern that can be played as a ringtone with any audio, depending on the device. */ - RINGTONE_1, - RINGTONE_2, - RINGTONE_3, - RINGTONE_4, - RINGTONE_5, - RINGTONE_6, - RINGTONE_7, - RINGTONE_8, - RINGTONE_9, - RINGTONE_10, - RINGTONE_11, - RINGTONE_12, - RINGTONE_13, - RINGTONE_14, - RINGTONE_15, + RINGTONE_1 = 6, + RINGTONE_2 = 7, + RINGTONE_3 = 8, + RINGTONE_4 = 9, + RINGTONE_5 = 10, + RINGTONE_6 = 11, + RINGTONE_7 = 12, + RINGTONE_8 = 13, + RINGTONE_9 = 14, + RINGTONE_10 = 15, + RINGTONE_11 = 16, + RINGTONE_12 = 17, + RINGTONE_13 = 18, + RINGTONE_14 = 19, + RINGTONE_15 = 20, /** * A soft tick effect meant to be played as a texture. * @@ -82,5 +82,5 @@ enum Effect { * are expected to be played multiple times in quick succession, replicating a specific * texture to the user as a form of haptic feedback. */ - TEXTURE_TICK, + TEXTURE_TICK = 21, } diff --git a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl index 66f70e57f3..c6a78d407c 100644 --- a/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl +++ b/vibrator/aidl/android/hardware/vibrator/EffectStrength.aidl @@ -19,7 +19,7 @@ package android.hardware.vibrator; @VintfStability @Backing(type="byte") enum EffectStrength { - LIGHT, - MEDIUM, - STRONG, + LIGHT = 0, + MEDIUM = 1, + STRONG = 2, } diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl index b4e7e44fe0..11f36baf2c 100644 --- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl +++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl @@ -16,13 +16,16 @@ package android.hardware.vibrator; -import android.hardware.vibrator.IVibratorCallback; import android.hardware.vibrator.Braking; -import android.hardware.vibrator.Effect; -import android.hardware.vibrator.EffectStrength; import android.hardware.vibrator.CompositeEffect; import android.hardware.vibrator.CompositePrimitive; +import android.hardware.vibrator.Effect; +import android.hardware.vibrator.EffectStrength; +import android.hardware.vibrator.IVibratorCallback; import android.hardware.vibrator.PrimitivePwle; +import android.hardware.vibrator.PwleV2OutputMapEntry; +import android.hardware.vibrator.PwleV2Primitive; +import android.hardware.vibrator.VendorEffect; @VintfStability interface IVibrator { @@ -70,6 +73,14 @@ interface IVibrator { * Whether composePwle is supported. */ const int CAP_COMPOSE_PWLE_EFFECTS = 1 << 10; + /** + * Whether perform w/ vendor effect is supported. + */ + const int CAP_PERFORM_VENDOR_EFFECTS = 1 << 11; + /** + * Whether composePwleV2 for PwlePrimitives is supported. + */ + const int CAP_COMPOSE_PWLE_EFFECTS_V2 = 1 << 12; /** * Determine capabilities of the vibrator HAL (CAP_* mask) @@ -359,4 +370,103 @@ interface IVibrator { * @param composite Array of PWLEs. */ void composePwle(in PrimitivePwle[] composite, in IVibratorCallback callback); + + /** + * Fire off a vendor-defined haptic event. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_PERFORM_VENDOR_EFFECTS). + * + * The duration of the effect is unknown and can be undefined for looping effects. + * IVibratorCallback.onComplete() support is required for this API. + * + * Doing this operation while the vibrator is already on is undefined behavior. Clients should + * explicitly call off. + * + * @param effect The vendor data representing the effect to be performed. + * @param callback A callback used to inform Frameworks of state change. + * @throws : + * - EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities. + * - EX_ILLEGAL_ARGUMENT for bad framework parameters, e.g. scale or effect strength. + * - EX_SERVICE_SPECIFIC for bad vendor data, vibration is not triggered. + */ + void performVendorEffect(in VendorEffect vendorEffect, in IVibratorCallback callback); + + /** + * Retrieves a mapping of vibration frequency (Hz) to the maximum achievable output + * acceleration (Gs) the device can reach at that frequency. + * + * The map, represented as a list of `PwleV2OutputMapEntry` (frequency, output acceleration) + * pairs, defines the device's frequency response. The platform uses the minimum and maximum + * frequency values to determine the supported input range for `IVibrator.composePwleV2`. + * Output acceleration values are used to identify a frequency range suitable to safely play + * perceivable vibrations with a simple API. The map is also exposed for developers using an + * advanced API. + * + * The platform does not impose specific requirements on map resolution which can vary + * depending on the shape of device output curve. The values will be linearly interpolated + * during lookups. The platform will provide a simple API, defined by the first frequency range + * where output acceleration consistently exceeds a minimum threshold of 10 db SL. + * + * + * This may not be supported and this support is reflected in getCapabilities + * (CAP_COMPOSE_PWLE_EFFECTS_V2). If this is supported, it's expected to be non-empty and + * describe a valid non-empty frequency range where the simple API can be defined + * (i.e. a range where the output acceleration is always above 10 db SL). + * + * @return A list of map entries representing the frequency to max acceleration + * mapping. + * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities. + */ + List getPwleV2FrequencyToOutputAccelerationMap(); + + /** + * Retrieve the maximum duration allowed for any primitive PWLE in units of + * milliseconds. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). + * + * @return The maximum duration allowed for a single PrimitivePwle. Non-zero value if supported. + * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities. + */ + int getPwleV2PrimitiveDurationMaxMillis(); + + /** + * Retrieve the maximum number of PWLE primitives input supported by IVibrator.composePwleV2. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). Devices supporting PWLE effects must + * support effects with at least 16 PwleV2Primitive. + * + * @return The maximum count allowed. Non-zero value if supported. + * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities. + */ + int getPwleV2CompositionSizeMax(); + + /** + * Retrieves the minimum duration (in milliseconds) of any segment within a + * PWLE effect. Devices supporting PWLE effects must support a minimum ramp + * time of 20 milliseconds. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). + * + * @return The minimum duration allowed for a single PrimitivePwle. Non-zero value if supported. + * @throws EX_UNSUPPORTED_OPERATION if unsupported, as reflected by getCapabilities. + */ + int getPwleV2PrimitiveDurationMinMillis(); + + /** + * Play composed sequence of chirps with optional callback upon completion. + * + * This may not be supported and this support is reflected in + * getCapabilities (CAP_COMPOSE_PWLE_EFFECTS_V2). + * + * Doing this operation while the vibrator is already on is undefined behavior. Clients should + * explicitly call off. IVibratorCallback.onComplete() support is required for this API. + * + * @param composite An array of primitives that represents a PWLE (Piecewise-Linear Envelope). + */ + void composePwleV2(in PwleV2Primitive[] composite, in IVibratorCallback callback); } diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl new file mode 100644 index 0000000000..a8db87cd25 --- /dev/null +++ b/vibrator/aidl/android/hardware/vibrator/PwleV2OutputMapEntry.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.vibrator; + +@VintfStability +parcelable PwleV2OutputMapEntry { + /** + * Absolute frequency point in the units of hertz + * + */ + float frequencyHz; + + /** + * Max output acceleration for the specified frequency in units of Gs. + * + * This value represents the maximum safe output acceleration (in Gs) achievable at the + * specified frequency, typically determined during calibration. The actual output acceleration + * is assumed to scale linearly with the input amplitude within the range of [0, 1]. + */ + float maxOutputAccelerationGs; +} diff --git a/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl new file mode 100644 index 0000000000..bd7bec6036 --- /dev/null +++ b/vibrator/aidl/android/hardware/vibrator/PwleV2Primitive.aidl @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.vibrator; + +@VintfStability +parcelable PwleV2Primitive { + /** + * Input amplitude ranges from 0.0 (inclusive) to 1.0 (inclusive), representing the relative + * input value. Actual output acceleration depends on frequency and device response curve + * (see IVibrator.getPwleV2FrequencyToOutputAccelerationMap for max values). + * + * Input amplitude linearly maps to output acceleration (e.g., 0.5 amplitude yields half the + * max acceleration for that frequency). + * + * 0.0 represents no output acceleration amplitude + * 1.0 represents the maximum achievable strength for each frequency, as determined by the + * actuator response curve + */ + float amplitude; + + /** + * Absolute frequency point in the units of hertz + * + * Values are within the continuous inclusive frequency range defined by + * IVibrator#getPwleV2FrequencyToOutputAccelerationMap. + */ + float frequencyHz; + + /* Total time from the previous PWLE point to the current one in units of milliseconds. */ + int timeMillis; +} diff --git a/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl new file mode 100644 index 0000000000..6b1af534c9 --- /dev/null +++ b/vibrator/aidl/android/hardware/vibrator/VendorEffect.aidl @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 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. + */ + +package android.hardware.vibrator; + +import android.hardware.vibrator.EffectStrength; +import android.os.PersistableBundle; + +@VintfStability +parcelable VendorEffect { + /** + * Vendor data describing the haptic effect. Expected fields should be defined by the vendor. + * + * Vendors can use this as a platform extension point for experimental hardware capabilities, + * but they are strongly discouraged from using it as an alternative to the AOSP support for + * stable vibrator APIs. Implemenitng vendor-specific custom effects outside the platform APIs + * will hinder portability for the code and overall user experience. + * + * Vendors are encouraged to upstream new capabilities to the IVibrator surface once it has + * matured into a stable interface. + */ + PersistableBundle vendorData; + + /** + * The intensity of the haptic effect. + * + * This value is defined by discrete scale levels that represents the intensity of this haptic + * effect. This is a discrete representation of the scale parameter below. + */ + EffectStrength strength = EffectStrength.MEDIUM; + + /** + * The intensity of the haptic effect. + * + * This value is defined by continuous scale that represents the intensity of this haptic + * effect. The vendor implementation can follow the platform scaling function or customize the + * implementation to their needs. This is a continuous representation of the strength parameter + * above. + * + * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds. + */ + float scale; + + /** + * The dynamic scale parameter provided by the vendor vibrator controller. + * + * This value is the same provided by the vendor to the platform IVibratorControlService and + * should be applied on top of the effect intensity provided by the strength/scale fields. + * The vendor can use this to dynamically adapt the haptic effect intensity to the device state. + * + * See frameworks/hardware/interfaces/vibrator for more documentation on vendor vibrator + * controller, and ScaleParam for more about this scale parameter. + * + * Values in [0,1) should scale down. Values > 1 should scale up within hardware bounds. + */ + float vendorScale; +} diff --git a/vibrator/aidl/default/Android.bp b/vibrator/aidl/default/Android.bp index 596c1a660c..b25a5ba752 100644 --- a/vibrator/aidl/default/Android.bp +++ b/vibrator/aidl/default/Android.bp @@ -15,7 +15,7 @@ cc_library_static { shared_libs: [ "libbase", "libbinder_ndk", - "android.hardware.vibrator-V2-ndk", + "android.hardware.vibrator-V3-ndk", ], export_include_dirs: ["include"], srcs: [ @@ -49,7 +49,7 @@ cc_binary { shared_libs: [ "libbase", "libbinder_ndk", - "android.hardware.vibrator-V2-ndk", + "android.hardware.vibrator-V3-ndk", ], static_libs: [ "libvibratorexampleimpl", @@ -62,7 +62,7 @@ cc_fuzz { host_supported: true, defaults: ["service_fuzzer_defaults"], static_libs: [ - "android.hardware.vibrator-V2-ndk", + "android.hardware.vibrator-V3-ndk", "liblog", "libvibratorexampleimpl", ], diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp index 01602abffb..4f8c2b84f0 100644 --- a/vibrator/aidl/default/Vibrator.cpp +++ b/vibrator/aidl/default/Vibrator.cpp @@ -27,9 +27,12 @@ namespace vibrator { static constexpr int32_t COMPOSE_DELAY_MAX_MS = 1000; static constexpr int32_t COMPOSE_SIZE_MAX = 256; static constexpr int32_t COMPOSE_PWLE_SIZE_MAX = 127; +static constexpr int32_t COMPOSE_PWLE_V2_SIZE_MAX = 16; static constexpr float Q_FACTOR = 11.0; static constexpr int32_t COMPOSE_PWLE_PRIMITIVE_DURATION_MAX_MS = 16383; +static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS = 1000; +static constexpr int32_t COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS = 20; static constexpr float PWLE_LEVEL_MIN = 0.0; static constexpr float PWLE_LEVEL_MAX = 1.0; static constexpr float PWLE_FREQUENCY_RESOLUTION_HZ = 1.0; @@ -39,14 +42,30 @@ static constexpr float PWLE_FREQUENCY_MAX_HZ = 160.0; static constexpr float PWLE_BW_MAP_SIZE = 1 + ((PWLE_FREQUENCY_MAX_HZ - PWLE_FREQUENCY_MIN_HZ) / PWLE_FREQUENCY_RESOLUTION_HZ); +// Service specific error code used for vendor vibration effects. +static constexpr int32_t ERROR_CODE_INVALID_DURATION = 1; + ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { LOG(VERBOSE) << "Vibrator reporting capabilities"; - *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | - IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL | - IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS | - IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY | - IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL | - IVibrator::CAP_COMPOSE_PWLE_EFFECTS; + std::lock_guard lock(mMutex); + if (mCapabilities == 0) { + if (!getInterfaceVersion(&mVersion).isOk()) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE)); + } + mCapabilities = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK | + IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL | + IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS | + IVibrator::CAP_ALWAYS_ON_CONTROL | IVibrator::CAP_GET_RESONANT_FREQUENCY | + IVibrator::CAP_GET_Q_FACTOR | IVibrator::CAP_FREQUENCY_CONTROL | + IVibrator::CAP_COMPOSE_PWLE_EFFECTS; + + if (mVersion >= 3) { + mCapabilities |= (IVibrator::CAP_PERFORM_VENDOR_EFFECTS | + IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2); + } + } + + *_aidl_return = mCapabilities; return ndk::ScopedAStatus::ok(); } @@ -102,6 +121,47 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Vibrator::performVendorEffect( + const VendorEffect& effect, const std::shared_ptr& callback) { + LOG(VERBOSE) << "Vibrator perform vendor effect"; + int32_t capabilities = 0; + if (!getCapabilities(&capabilities).isOk()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + EffectStrength strength = effect.strength; + if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM && + strength != EffectStrength::STRONG) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); + } + float scale = effect.scale; + if (scale <= 0) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + float vendorScale = effect.vendorScale; + if (vendorScale <= 0) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + int32_t durationMs = 0; + if (!effect.vendorData.getInt("DURATION_MS", &durationMs) || durationMs <= 0) { + return ndk::ScopedAStatus::fromServiceSpecificError(ERROR_CODE_INVALID_DURATION); + } + + if (callback != nullptr) { + std::thread([callback, durationMs] { + LOG(VERBOSE) << "Starting perform on another thread for durationMs:" << durationMs; + usleep(durationMs * 1000); + LOG(VERBOSE) << "Notifying perform vendor effect complete"; + callback->onComplete(); + }).detach(); + } + + return ndk::ScopedAStatus::ok(); +} + ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector* _aidl_return) { *_aidl_return = {Effect::CLICK, Effect::TICK}; return ndk::ScopedAStatus::ok(); @@ -412,6 +472,122 @@ ndk::ScopedAStatus Vibrator::composePwle(const std::vector &compo return ndk::ScopedAStatus::ok(); } +ndk::ScopedAStatus Vibrator::getPwleV2FrequencyToOutputAccelerationMap( + std::vector* _aidl_return) { + std::vector frequencyToOutputAccelerationMap; + + std::vector> frequencyToOutputAccelerationData = { + {30.0f, 0.01f}, {46.0f, 0.09f}, {50.0f, 0.1f}, {55.0f, 0.12f}, {62.0f, 0.66f}, + {83.0f, 0.82f}, {85.0f, 0.85f}, {92.0f, 1.05f}, {107.0f, 1.63f}, {115.0f, 1.72f}, + {123.0f, 1.81f}, {135.0f, 2.23f}, {144.0f, 2.47f}, {145.0f, 2.5f}, {150.0f, 3.0f}, + {175.0f, 2.51f}, {181.0f, 2.41f}, {190.0f, 2.28f}, {200.0f, 2.08f}, {204.0f, 1.96f}, + {205.0f, 1.9f}, {224.0f, 1.7f}, {235.0f, 1.5f}, {242.0f, 1.46f}, {253.0f, 1.41f}, + {263.0f, 1.39f}, {65.0f, 1.38f}, {278.0f, 1.37f}, {294.0f, 1.35f}, {300.0f, 1.34f}}; + for (const auto& entry : frequencyToOutputAccelerationData) { + frequencyToOutputAccelerationMap.push_back( + PwleV2OutputMapEntry(/*frequency=*/entry.first, + /*maxOutputAcceleration=*/entry.second)); + } + + *_aidl_return = frequencyToOutputAccelerationMap; + + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) { + *maxDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getPwleV2CompositionSizeMax(int32_t* maxSize) { + *maxSize = COMPOSE_PWLE_V2_SIZE_MAX; + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus Vibrator::getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) { + *minDurationMs = COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MIN_MS; + return ndk::ScopedAStatus::ok(); +} + +float getPwleV2FrequencyMinHz(std::vector frequencyToOutputAccelerationMap) { + if (frequencyToOutputAccelerationMap.empty()) { + return 0.0f; + } + + float minFrequency = frequencyToOutputAccelerationMap[0].frequencyHz; + + for (const auto& entry : frequencyToOutputAccelerationMap) { + if (entry.frequencyHz < minFrequency) { + minFrequency = entry.frequencyHz; + } + } + + return minFrequency; +} + +float getPwleV2FrequencyMaxHz(std::vector frequencyToOutputAccelerationMap) { + if (frequencyToOutputAccelerationMap.empty()) { + return 0.0f; + } + + float maxFrequency = frequencyToOutputAccelerationMap[0].frequencyHz; + + for (const auto& entry : frequencyToOutputAccelerationMap) { + if (entry.frequencyHz > maxFrequency) { + maxFrequency = entry.frequencyHz; + } + } + + return maxFrequency; +} + +ndk::ScopedAStatus Vibrator::composePwleV2(const std::vector& composite, + const std::shared_ptr& callback) { + int32_t capabilities = 0; + if (!getCapabilities(&capabilities).isOk()) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); + } + if ((capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) == 0) { + return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); + } + + int compositionSizeMax; + getPwleV2CompositionSizeMax(&compositionSizeMax); + if (composite.size() <= 0 || composite.size() > compositionSizeMax) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + + int32_t totalEffectDuration = 0; + std::vector frequencyToOutputAccelerationMap; + getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap); + float minFrequency = getPwleV2FrequencyMinHz(frequencyToOutputAccelerationMap); + float maxFrequency = getPwleV2FrequencyMaxHz(frequencyToOutputAccelerationMap); + + for (auto& e : composite) { + if (e.timeMillis < 0.0f || e.timeMillis > COMPOSE_PWLE_V2_PRIMITIVE_DURATION_MAX_MS) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (e.amplitude < 0.0f || e.amplitude > 1.0f) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + if (e.frequencyHz < minFrequency || e.frequencyHz > maxFrequency) { + return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT); + } + totalEffectDuration += e.timeMillis; + } + + std::thread([totalEffectDuration, callback] { + LOG(VERBOSE) << "Starting composePwleV2 on another thread"; + usleep(totalEffectDuration * 1000); + if (callback != nullptr) { + LOG(VERBOSE) << "Notifying compose PWLE V2 complete"; + callback->onComplete(); + } + }).detach(); + + return ndk::ScopedAStatus::ok(); +} + } // namespace vibrator } // namespace hardware } // namespace android diff --git a/vibrator/aidl/default/android.hardware.vibrator.xml b/vibrator/aidl/default/android.hardware.vibrator.xml index b5bd3ddd1e..b7300460c2 100644 --- a/vibrator/aidl/default/android.hardware.vibrator.xml +++ b/vibrator/aidl/default/android.hardware.vibrator.xml @@ -1,12 +1,12 @@ android.hardware.vibrator - 2 + 3 IVibrator/default android.hardware.vibrator - 2 + 3 IVibratorManager/default diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h index 4203bf212c..28bc763ffb 100644 --- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h +++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h @@ -17,6 +17,7 @@ #pragma once #include +#include namespace aidl { namespace android { @@ -31,6 +32,9 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus perform(Effect effect, EffectStrength strength, const std::shared_ptr& callback, int32_t* _aidl_return) override; + ndk::ScopedAStatus performVendorEffect( + const VendorEffect& effect, + const std::shared_ptr& callback) override; ndk::ScopedAStatus getSupportedEffects(std::vector* _aidl_return) override; ndk::ScopedAStatus setAmplitude(float amplitude) override; ndk::ScopedAStatus setExternalControl(bool enabled) override; @@ -54,7 +58,18 @@ class Vibrator : public BnVibrator { ndk::ScopedAStatus getSupportedBraking(std::vector* supported) override; ndk::ScopedAStatus composePwle(const std::vector &composite, const std::shared_ptr &callback) override; + ndk::ScopedAStatus getPwleV2FrequencyToOutputAccelerationMap( + std::vector* _aidl_return) override; + ndk::ScopedAStatus getPwleV2PrimitiveDurationMaxMillis(int32_t* maxDurationMs) override; + ndk::ScopedAStatus getPwleV2PrimitiveDurationMinMillis(int32_t* minDurationMs) override; + ndk::ScopedAStatus getPwleV2CompositionSizeMax(int32_t* maxSize) override; + ndk::ScopedAStatus composePwleV2(const std::vector& composite, + const std::shared_ptr& callback) override; + private: + mutable std::mutex mMutex; + int32_t mVersion GUARDED_BY(mMutex) = 0; // current Hal version + int32_t mCapabilities GUARDED_BY(mMutex) = 0; }; } // namespace vibrator diff --git a/vibrator/aidl/vts/Android.bp b/vibrator/aidl/vts/Android.bp index b6d2fb27da..a48bb2e89f 100644 --- a/vibrator/aidl/vts/Android.bp +++ b/vibrator/aidl/vts/Android.bp @@ -17,10 +17,10 @@ cc_test { tidy_timeout_srcs: ["VtsHalVibratorTargetTest.cpp"], srcs: ["VtsHalVibratorTargetTest.cpp"], shared_libs: [ - "libbinder", + "libbinder_ndk", ], static_libs: [ - "android.hardware.vibrator-V2-cpp", + "android.hardware.vibrator-V3-ndk", ], test_suites: [ "general-tests", @@ -36,10 +36,10 @@ cc_test { ], srcs: ["VtsHalVibratorManagerTargetTest.cpp"], shared_libs: [ - "libbinder", + "libbinder_ndk", ], static_libs: [ - "android.hardware.vibrator-V2-cpp", + "android.hardware.vibrator-V3-ndk", ], test_suites: [ "general-tests", diff --git a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp index e8ed26ab69..3c2a3607b1 100644 --- a/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorManagerTargetTest.cpp @@ -15,42 +15,40 @@ */ #include #include +#include +#include +#include -#include -#include -#include -#include -#include +#include +#include #include #include -using android::ProcessState; -using android::sp; -using android::String16; -using android::binder::Status; -using android::hardware::vibrator::BnVibratorCallback; -using android::hardware::vibrator::CompositeEffect; -using android::hardware::vibrator::CompositePrimitive; -using android::hardware::vibrator::Effect; -using android::hardware::vibrator::EffectStrength; -using android::hardware::vibrator::IVibrator; -using android::hardware::vibrator::IVibratorManager; +#include "test_utils.h" + +using aidl::android::hardware::vibrator::BnVibratorCallback; +using aidl::android::hardware::vibrator::CompositeEffect; +using aidl::android::hardware::vibrator::CompositePrimitive; +using aidl::android::hardware::vibrator::Effect; +using aidl::android::hardware::vibrator::EffectStrength; +using aidl::android::hardware::vibrator::IVibrator; +using aidl::android::hardware::vibrator::IVibratorManager; using std::chrono::high_resolution_clock; -const std::vector kEffects{android::enum_range().begin(), - android::enum_range().end()}; -const std::vector kEffectStrengths{android::enum_range().begin(), - android::enum_range().end()}; -const std::vector kPrimitives{android::enum_range().begin(), - android::enum_range().end()}; +const std::vector kEffects{ndk::enum_range().begin(), + ndk::enum_range().end()}; +const std::vector kEffectStrengths{ndk::enum_range().begin(), + ndk::enum_range().end()}; +const std::vector kPrimitives{ndk::enum_range().begin(), + ndk::enum_range().end()}; class CompletionCallback : public BnVibratorCallback { public: CompletionCallback(const std::function& callback) : mCallback(callback) {} - Status onComplete() override { + ndk::ScopedAStatus onComplete() override { mCallback(); - return Status::ok(); + return ndk::ScopedAStatus::ok(); } private: @@ -60,55 +58,50 @@ class CompletionCallback : public BnVibratorCallback { class VibratorAidl : public testing::TestWithParam { public: virtual void SetUp() override { - manager = android::waitForDeclaredService(String16(GetParam().c_str())); + auto serviceName = GetParam().c_str(); + manager = IVibratorManager::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(serviceName))); ASSERT_NE(manager, nullptr); - ASSERT_TRUE(manager->getCapabilities(&capabilities).isOk()); - EXPECT_TRUE(manager->getVibratorIds(&vibratorIds).isOk()); + EXPECT_OK(manager->getCapabilities(&capabilities)); + EXPECT_OK(manager->getVibratorIds(&vibratorIds)); } - sp manager; + std::shared_ptr manager; int32_t capabilities; std::vector vibratorIds; }; -inline bool isUnknownOrUnsupported(Status status) { - return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION || - status.transactionError() == android::UNKNOWN_TRANSACTION; -} - TEST_P(VibratorAidl, ValidateExistingVibrators) { - sp vibrator; - for (auto& id : vibratorIds) { - EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk()); + std::shared_ptr vibrator; + for (int32_t id : vibratorIds) { + EXPECT_OK(manager->getVibrator(id, &vibrator)); ASSERT_NE(vibrator, nullptr); } } TEST_P(VibratorAidl, GetVibratorWithInvalidId) { int32_t invalidId = *max_element(vibratorIds.begin(), vibratorIds.end()) + 1; - sp vibrator; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - manager->getVibrator(invalidId, &vibrator).exceptionCode()); + std::shared_ptr vibrator; + EXPECT_ILLEGAL_ARGUMENT(manager->getVibrator(invalidId, &vibrator)); ASSERT_EQ(vibrator, nullptr); } TEST_P(VibratorAidl, ValidatePrepareSyncedExistingVibrators) { if (!(capabilities & IVibratorManager::CAP_SYNC)) return; if (vibratorIds.empty()) return; - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - EXPECT_TRUE(manager->cancelSynced().isOk()); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + EXPECT_OK(manager->cancelSynced()); } TEST_P(VibratorAidl, PrepareSyncedEmptySetIsInvalid) { if (!(capabilities & IVibratorManager::CAP_SYNC)) return; std::vector emptyIds; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, manager->prepareSynced(emptyIds).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(manager->prepareSynced(emptyIds)); } TEST_P(VibratorAidl, PrepareSyncedNotSupported) { if (!(capabilities & IVibratorManager::CAP_SYNC)) { - Status status = manager->prepareSynced(vibratorIds); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->prepareSynced(vibratorIds)); } } @@ -117,15 +110,14 @@ TEST_P(VibratorAidl, PrepareOnNotSupported) { if (!(capabilities & IVibratorManager::CAP_SYNC)) return; if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) { uint32_t durationMs = 250; - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - sp vibrator; - for (auto& id : vibratorIds) { - EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk()); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + std::shared_ptr vibrator; + for (int32_t id : vibratorIds) { + EXPECT_OK(manager->getVibrator(id, &vibrator)); ASSERT_NE(vibrator, nullptr); - Status status = vibrator->on(durationMs, nullptr); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(durationMs, nullptr)); } - EXPECT_TRUE(manager->cancelSynced().isOk()); + EXPECT_OK(manager->cancelSynced()); } } @@ -133,16 +125,16 @@ TEST_P(VibratorAidl, PreparePerformNotSupported) { if (vibratorIds.empty()) return; if (!(capabilities & IVibratorManager::CAP_SYNC)) return; if (!(capabilities & IVibratorManager::CAP_PREPARE_ON)) { - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - sp vibrator; - for (auto& id : vibratorIds) { - EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk()); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + std::shared_ptr vibrator; + for (int32_t id : vibratorIds) { + EXPECT_OK(manager->getVibrator(id, &vibrator)); ASSERT_NE(vibrator, nullptr); int32_t lengthMs = 0; - Status status = vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED( + vibrator->perform(kEffects[0], kEffectStrengths[0], nullptr, &lengthMs)); } - EXPECT_TRUE(manager->cancelSynced().isOk()); + EXPECT_OK(manager->cancelSynced()); } } @@ -157,15 +149,14 @@ TEST_P(VibratorAidl, PrepareComposeNotSupported) { effect.scale = 1.0f; composite.emplace_back(effect); - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - sp vibrator; - for (auto& id : vibratorIds) { - EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk()); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + std::shared_ptr vibrator; + for (int32_t id : vibratorIds) { + EXPECT_OK(manager->getVibrator(id, &vibrator)); ASSERT_NE(vibrator, nullptr); - Status status = vibrator->compose(composite, nullptr); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr)); } - EXPECT_TRUE(manager->cancelSynced().isOk()); + EXPECT_OK(manager->cancelSynced()); } } @@ -177,51 +168,58 @@ TEST_P(VibratorAidl, TriggerWithCallback) { std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; - sp callback = - new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); uint32_t durationMs = 250; std::chrono::milliseconds timeout{durationMs * 2}; - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - sp vibrator; - for (auto& id : vibratorIds) { - EXPECT_TRUE(manager->getVibrator(id, &vibrator).isOk()); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + std::shared_ptr vibrator; + for (int32_t id : vibratorIds) { + EXPECT_OK(manager->getVibrator(id, &vibrator)); ASSERT_NE(vibrator, nullptr); - EXPECT_TRUE(vibrator->on(durationMs, nullptr).isOk()); + EXPECT_OK(vibrator->on(durationMs, nullptr)); } - EXPECT_TRUE(manager->triggerSynced(callback).isOk()); + EXPECT_OK(manager->triggerSynced(callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); - EXPECT_TRUE(manager->cancelSynced().isOk()); + EXPECT_OK(manager->cancelSynced()); } TEST_P(VibratorAidl, TriggerSyncNotSupported) { if (!(capabilities & IVibratorManager::CAP_SYNC)) { - Status status = manager->triggerSynced(nullptr); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(nullptr)); } } TEST_P(VibratorAidl, TriggerCallbackNotSupported) { if (!(capabilities & IVibratorManager::CAP_SYNC)) return; if (!(capabilities & IVibratorManager::CAP_TRIGGER_CALLBACK)) { - sp callback = new CompletionCallback([] {}); - EXPECT_TRUE(manager->prepareSynced(vibratorIds).isOk()); - Status status = manager->triggerSynced(callback); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; - EXPECT_TRUE(manager->cancelSynced().isOk()); + auto callback = ndk::SharedRefBase::make([] {}); + EXPECT_OK(manager->prepareSynced(vibratorIds)); + EXPECT_UNKNOWN_OR_UNSUPPORTED(manager->triggerSynced(callback)); + EXPECT_OK(manager->cancelSynced()); } } +std::vector FindVibratorManagerNames() { + std::vector names; + constexpr auto callback = [](const char* instance, void* context) { + std::string fullName = std::string(IVibratorManager::descriptor) + "/" + instance; + static_cast*>(context)->emplace_back(fullName); + }; + AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor, + static_cast(&names), callback); + return names; +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VibratorAidl); -INSTANTIATE_TEST_SUITE_P( - Vibrator, VibratorAidl, - testing::ValuesIn(android::getAidlHalInstanceNames(IVibratorManager::descriptor)), - android::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(FindVibratorManagerNames()), + android::PrintInstanceNameToString); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); } diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp index db474d6920..bc017ae3b5 100644 --- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp +++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp @@ -15,38 +15,51 @@ */ #include #include -#include -#include -#include -#include -#include +#include +#include +#include + +#include +#include +#include #include +#include +#include #include +#include +#include +#include -using android::ProcessState; -using android::sp; -using android::String16; -using android::binder::Status; -using android::hardware::vibrator::ActivePwle; -using android::hardware::vibrator::BnVibratorCallback; -using android::hardware::vibrator::Braking; -using android::hardware::vibrator::BrakingPwle; -using android::hardware::vibrator::CompositeEffect; -using android::hardware::vibrator::CompositePrimitive; -using android::hardware::vibrator::Effect; -using android::hardware::vibrator::EffectStrength; -using android::hardware::vibrator::IVibrator; -using android::hardware::vibrator::IVibratorManager; -using android::hardware::vibrator::PrimitivePwle; +#include "persistable_bundle_utils.h" +#include "pwle_v2_utils.h" +#include "test_utils.h" + +using aidl::android::hardware::vibrator::ActivePwle; +using aidl::android::hardware::vibrator::BnVibratorCallback; +using aidl::android::hardware::vibrator::Braking; +using aidl::android::hardware::vibrator::BrakingPwle; +using aidl::android::hardware::vibrator::CompositeEffect; +using aidl::android::hardware::vibrator::CompositePrimitive; +using aidl::android::hardware::vibrator::Effect; +using aidl::android::hardware::vibrator::EffectStrength; +using aidl::android::hardware::vibrator::IVibrator; +using aidl::android::hardware::vibrator::IVibratorManager; +using aidl::android::hardware::vibrator::PrimitivePwle; +using aidl::android::hardware::vibrator::PwleV2OutputMapEntry; +using aidl::android::hardware::vibrator::PwleV2Primitive; +using aidl::android::hardware::vibrator::VendorEffect; +using aidl::android::os::PersistableBundle; using std::chrono::high_resolution_clock; using namespace ::std::chrono_literals; -const std::vector kEffects{android::enum_range().begin(), - android::enum_range().end()}; -const std::vector kEffectStrengths{android::enum_range().begin(), - android::enum_range().end()}; +namespace pwle_v2_utils = aidl::android::hardware::vibrator::testing::pwlev2; + +const std::vector kEffects{ndk::enum_range().begin(), + ndk::enum_range().end()}; +const std::vector kEffectStrengths{ndk::enum_range().begin(), + ndk::enum_range().end()}; const std::vector kInvalidEffects = { static_cast(static_cast(kEffects.front()) - 1), @@ -59,8 +72,7 @@ const std::vector kInvalidEffectStrengths = { }; const std::vector kCompositePrimitives{ - android::enum_range().begin(), - android::enum_range().end()}; + ndk::enum_range().begin(), ndk::enum_range().end()}; const std::vector kRequiredPrimitives = { CompositePrimitive::CLICK, CompositePrimitive::LIGHT_TICK, @@ -74,14 +86,39 @@ const std::vector kInvalidPrimitives = { }; // Timeout to wait for vibration callback completion. -static constexpr auto VIBRATION_CALLBACK_TIMEOUT = 100ms; +static constexpr std::chrono::milliseconds VIBRATION_CALLBACK_TIMEOUT = 100ms; + +static constexpr int32_t VENDOR_EFFECTS_MIN_VERSION = 3; +static constexpr int32_t PWLE_V2_MIN_VERSION = 3; + +static std::vector findVibratorManagerNames() { + std::vector names; + constexpr auto callback = [](const char* instance, void* context) { + auto fullName = std::string(IVibratorManager::descriptor) + "/" + instance; + static_cast*>(context)->emplace_back(fullName); + }; + AServiceManager_forEachDeclaredInstance(IVibratorManager::descriptor, + static_cast(&names), callback); + return names; +} + +static std::vector findUnmanagedVibratorNames() { + std::vector names; + constexpr auto callback = [](const char* instance, void* context) { + auto fullName = std::string(IVibrator::descriptor) + "/" + instance; + static_cast*>(context)->emplace_back(fullName); + }; + AServiceManager_forEachDeclaredInstance(IVibrator::descriptor, static_cast(&names), + callback); + return names; +} class CompletionCallback : public BnVibratorCallback { public: CompletionCallback(const std::function &callback) : mCallback(callback) {} - Status onComplete() override { + ndk::ScopedAStatus onComplete() override { mCallback(); - return Status::ok(); + return ndk::ScopedAStatus::ok(); } private: @@ -93,88 +130,89 @@ class VibratorAidl : public testing::TestWithParam> virtual void SetUp() override { int32_t managerIdx = std::get<0>(GetParam()); int32_t vibratorId = std::get<1>(GetParam()); - auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor); if (managerIdx < 0) { // Testing a unmanaged vibrator, using vibratorId as index from registered HALs - auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor); - ASSERT_LT(vibratorId, vibratorAidlNames.size()); - auto vibratorName = String16(vibratorAidlNames[vibratorId].c_str()); - vibrator = android::waitForDeclaredService(vibratorName); + std::vector vibratorNames = findUnmanagedVibratorNames(); + ASSERT_LT(vibratorId, vibratorNames.size()); + vibrator = IVibrator::fromBinder(ndk::SpAIBinder( + AServiceManager_waitForService(vibratorNames[vibratorId].c_str()))); } else { // Testing a managed vibrator, using vibratorId to retrieve it from the manager - ASSERT_LT(managerIdx, managerAidlNames.size()); - auto managerName = String16(managerAidlNames[managerIdx].c_str()); - auto vibratorManager = android::waitForDeclaredService(managerName); - auto vibratorResult = vibratorManager->getVibrator(vibratorId, &vibrator); - ASSERT_TRUE(vibratorResult.isOk()); + std::vector managerNames = findVibratorManagerNames(); + ASSERT_LT(managerIdx, managerNames.size()); + auto vibratorManager = IVibratorManager::fromBinder(ndk::SpAIBinder( + AServiceManager_waitForService(managerNames[managerIdx].c_str()))); + EXPECT_OK(vibratorManager->getVibrator(vibratorId, &vibrator)) + << "\n For vibrator id: " << vibratorId; } ASSERT_NE(vibrator, nullptr); - ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk()); + EXPECT_OK(vibrator->getInterfaceVersion(&version)); + EXPECT_OK(vibrator->getCapabilities(&capabilities)); } virtual void TearDown() override { // Reset vibrator state between tests. - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } - sp vibrator; + std::shared_ptr vibrator; + int32_t version; int32_t capabilities; }; -inline bool isUnknownOrUnsupported(Status status) { - return status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION || - status.transactionError() == android::UNKNOWN_TRANSACTION; -} - -static float getResonantFrequencyHz(sp vibrator, int32_t capabilities) { +static float getResonantFrequencyHz(const std::shared_ptr& vibrator, + int32_t capabilities) { float resonantFrequencyHz; - Status status = vibrator->getResonantFrequency(&resonantFrequencyHz); + ndk::ScopedAStatus status = vibrator->getResonantFrequency(&resonantFrequencyHz); if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) { + EXPECT_OK(std::move(status)); EXPECT_GT(resonantFrequencyHz, 0); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return resonantFrequencyHz; } -static float getFrequencyResolutionHz(sp vibrator, int32_t capabilities) { +static float getFrequencyResolutionHz(const std::shared_ptr& vibrator, + int32_t capabilities) { float freqResolutionHz; - Status status = vibrator->getFrequencyResolution(&freqResolutionHz); + ndk::ScopedAStatus status = vibrator->getFrequencyResolution(&freqResolutionHz); if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { + EXPECT_OK(std::move(status)); EXPECT_GT(freqResolutionHz, 0); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return freqResolutionHz; } -static float getFrequencyMinimumHz(sp vibrator, int32_t capabilities) { +static float getFrequencyMinimumHz(const std::shared_ptr& vibrator, + int32_t capabilities) { float freqMinimumHz; - Status status = vibrator->getFrequencyMinimum(&freqMinimumHz); + ndk::ScopedAStatus status = vibrator->getFrequencyMinimum(&freqMinimumHz); if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); + EXPECT_OK(std::move(status)); float resonantFrequencyHz = getResonantFrequencyHz(vibrator, capabilities); EXPECT_GT(freqMinimumHz, 0); EXPECT_LE(freqMinimumHz, resonantFrequencyHz); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } return freqMinimumHz; } -static float getFrequencyMaximumHz(sp vibrator, int32_t capabilities) { +static float getFrequencyMaximumHz(const std::shared_ptr& vibrator, + int32_t capabilities) { std::vector bandwidthAmplitudeMap; - Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); + ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); + EXPECT_OK(std::move(status)); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } float freqMaximumHz = ((bandwidthAmplitudeMap.size() - 1) * @@ -191,7 +229,8 @@ static float getAmplitudeMax() { return 1.0; } -static ActivePwle composeValidActivePwle(sp vibrator, int32_t capabilities) { +static ActivePwle composeValidActivePwle(const std::shared_ptr& vibrator, + int32_t capabilities) { float frequencyHz; if (capabilities & IVibrator::CAP_GET_RESONANT_FREQUENCY) { frequencyHz = getResonantFrequencyHz(vibrator, capabilities); @@ -212,9 +251,9 @@ static ActivePwle composeValidActivePwle(sp vibrator, int32_t capabil } TEST_P(VibratorAidl, OnThenOffBeforeTimeout) { - EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk()); + EXPECT_OK(vibrator->on(2000, nullptr /*callback*/)); sleep(1); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, OnWithCallback) { @@ -223,26 +262,25 @@ TEST_P(VibratorAidl, OnWithCallback) { std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; - sp callback = - new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); uint32_t durationMs = 250; auto timeout = std::chrono::milliseconds(durationMs) + VIBRATION_CALLBACK_TIMEOUT; - EXPECT_TRUE(vibrator->on(durationMs, callback).isOk()); + EXPECT_OK(vibrator->on(durationMs, callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, OnCallbackNotSupported) { if (!(capabilities & IVibrator::CAP_ON_CALLBACK)) { - sp callback = new CompletionCallback([] {}); - Status status = vibrator->on(250, callback); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + auto callback = ndk::SharedRefBase::make([] {}); + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->on(250, callback)); } } TEST_P(VibratorAidl, ValidateEffect) { std::vector supported; - ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = @@ -250,15 +288,18 @@ TEST_P(VibratorAidl, ValidateEffect) { for (EffectStrength strength : kEffectStrengths) { int32_t lengthMs = 0; - Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); + ndk::ScopedAStatus status = + vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); if (isEffectSupported) { - EXPECT_TRUE(status.isOk()) << toString(effect) << " " << toString(strength); + EXPECT_OK(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); EXPECT_GT(lengthMs, 0); usleep(lengthMs * 1000); + EXPECT_OK(vibrator->off()); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) - << status << " " << toString(effect) << " " << toString(strength); + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } } } @@ -269,7 +310,7 @@ TEST_P(VibratorAidl, ValidateEffectWithCallback) { return; std::vector supported; - ASSERT_TRUE(vibrator->getSupportedEffects(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = @@ -278,25 +319,26 @@ TEST_P(VibratorAidl, ValidateEffectWithCallback) { for (EffectStrength strength : kEffectStrengths) { std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; - sp callback = - new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); int lengthMs = 0; - Status status = vibrator->perform(effect, strength, callback, &lengthMs); + ndk::ScopedAStatus status = vibrator->perform(effect, strength, callback, &lengthMs); if (isEffectSupported) { - EXPECT_TRUE(status.isOk()); + EXPECT_OK(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); EXPECT_GT(lengthMs, 0); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } - if (!status.isOk()) - continue; + if (lengthMs <= 0) continue; auto timeout = std::chrono::milliseconds(lengthMs) + VIBRATION_CALLBACK_TIMEOUT; EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } } } @@ -307,10 +349,10 @@ TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) { for (Effect effect : kEffects) { for (EffectStrength strength : kEffectStrengths) { - sp callback = new CompletionCallback([] {}); + auto callback = ndk::SharedRefBase::make([] {}); int lengthMs; - Status status = vibrator->perform(effect, strength, callback, &lengthMs); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->perform(effect, strength, callback, &lengthMs)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } } } @@ -319,53 +361,182 @@ TEST_P(VibratorAidl, InvalidEffectsUnsupported) { for (Effect effect : kInvalidEffects) { for (EffectStrength strength : kEffectStrengths) { int32_t lengthMs; - Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); - EXPECT_TRUE(isUnknownOrUnsupported(status)) - << status << toString(effect) << " " << toString(strength); + EXPECT_UNKNOWN_OR_UNSUPPORTED( + vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } } for (Effect effect : kEffects) { for (EffectStrength strength : kInvalidEffectStrengths) { int32_t lengthMs; - Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs); - EXPECT_TRUE(isUnknownOrUnsupported(status)) - << status << " " << toString(effect) << " " << toString(strength); + EXPECT_UNKNOWN_OR_UNSUPPORTED( + vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } } } +TEST_P(VibratorAidl, PerformVendorEffectSupported) { + if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; + + float scale = 0.0f; + float vendorScale = 0.0f; + for (EffectStrength strength : kEffectStrengths) { + PersistableBundle vendorData; + ::aidl::android::hardware::vibrator::testing::fillBasicData(&vendorData); + + PersistableBundle nestedData; + ::aidl::android::hardware::vibrator::testing::fillBasicData(&nestedData); + vendorData.putPersistableBundle("test_nested_bundle", nestedData); + + VendorEffect effect; + effect.vendorData = vendorData; + effect.strength = strength; + effect.scale = scale; + effect.vendorScale = vendorScale; + scale += 0.5f; + vendorScale += 0.2f; + + auto callback = ndk::SharedRefBase::make([] {}); + ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback); + + // No expectations on the actual status, the effect might be refused with illegal argument + // or the vendor might return a service-specific error code. + EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION && + status.getStatus() != STATUS_UNKNOWN_TRANSACTION) + << status << "\n For vendor effect with strength" << toString(strength) + << " and scale " << effect.scale; + + if (status.isOk()) { + // Generic vendor data should not trigger vibrations, but if it does trigger one + // then we make sure the vibrator is reset by triggering off(). + EXPECT_OK(vibrator->off()); + } + } +} + +TEST_P(VibratorAidl, PerformVendorEffectStability) { + if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; + + // Run some iterations of performVendorEffect with randomized vendor data to check basic + // stability of the implementation. + uint8_t iterations = 200; + + for (EffectStrength strength : kEffectStrengths) { + float scale = 0.5f; + float vendorScale = 0.2f; + for (uint8_t i = 0; i < iterations; i++) { + PersistableBundle vendorData; + ::aidl::android::hardware::vibrator::testing::fillRandomData(&vendorData); + + VendorEffect effect; + effect.vendorData = vendorData; + effect.strength = strength; + effect.scale = scale; + effect.vendorScale = vendorScale; + scale *= 2; + vendorScale *= 1.5f; + + auto callback = ndk::SharedRefBase::make([] {}); + ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, callback); + + // No expectations on the actual status, the effect might be refused with illegal + // argument or the vendor might return a service-specific error code. + EXPECT_TRUE(status.getExceptionCode() != EX_UNSUPPORTED_OPERATION && + status.getStatus() != STATUS_UNKNOWN_TRANSACTION) + << status << "\n For random vendor effect with strength " << toString(strength) + << " and scale " << effect.scale; + + if (status.isOk()) { + // Random vendor data should not trigger vibrations, but if it does trigger one + // then we make sure the vibrator is reset by triggering off(). + EXPECT_OK(vibrator->off()); + } + } + } +} + +TEST_P(VibratorAidl, PerformVendorEffectEmptyVendorData) { + if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; + + for (EffectStrength strength : kEffectStrengths) { + VendorEffect effect; + effect.strength = strength; + effect.scale = 1.0f; + effect.vendorScale = 1.0f; + + ndk::ScopedAStatus status = vibrator->performVendorEffect(effect, nullptr /*callback*/); + + EXPECT_TRUE(status.getExceptionCode() == EX_SERVICE_SPECIFIC) + << status << "\n For vendor effect with strength " << toString(strength) + << " and scale " << effect.scale; + } +} + +TEST_P(VibratorAidl, PerformVendorEffectInvalidScale) { + if ((capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) == 0) return; + + VendorEffect effect; + effect.strength = EffectStrength::MEDIUM; + + effect.scale = -1.0f; + effect.vendorScale = 1.0f; + EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/)); + + effect.scale = 1.0f; + effect.vendorScale = -1.0f; + EXPECT_ILLEGAL_ARGUMENT(vibrator->performVendorEffect(effect, nullptr /*callback*/)); +} + +TEST_P(VibratorAidl, PerformVendorEffectUnsupported) { + if (version < VENDOR_EFFECTS_MIN_VERSION) { + EXPECT_EQ(capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS, 0) + << "Vibrator version " << version << " should not report vendor effects capability"; + } + if (capabilities & IVibrator::CAP_PERFORM_VENDOR_EFFECTS) return; + + for (EffectStrength strength : kEffectStrengths) { + VendorEffect effect; + effect.strength = strength; + effect.scale = 1.0f; + effect.vendorScale = 1.0f; + + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->performVendorEffect(effect, nullptr /*callback*/)) + << "\n For vendor effect with strength " << toString(strength); + } +} + TEST_P(VibratorAidl, ChangeVibrationAmplitude) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { - EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.1f).exceptionCode()); - EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk()); - EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(0.5f).exceptionCode()); + EXPECT_OK(vibrator->setAmplitude(0.1f)); + EXPECT_OK(vibrator->on(2000, nullptr /*callback*/)); + EXPECT_OK(vibrator->setAmplitude(0.5f)); sleep(1); - EXPECT_EQ(Status::EX_NONE, vibrator->setAmplitude(1.0f).exceptionCode()); + EXPECT_OK(vibrator->setAmplitude(1.0f)); sleep(1); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } } TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) { if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) { - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode()); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode()); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(1.1).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(-1)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(0)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->setAmplitude(1.1)); } } TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) { if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) { - Status status = vibrator->setAmplitude(1); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(1)); } } TEST_P(VibratorAidl, ChangeVibrationExternalControl) { if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { - EXPECT_TRUE(vibrator->setExternalControl(true).isOk()); + EXPECT_OK(vibrator->setExternalControl(true)); sleep(1); - EXPECT_TRUE(vibrator->setExternalControl(false).isOk()); + EXPECT_OK(vibrator->setExternalControl(false)); sleep(1); } } @@ -375,15 +546,15 @@ TEST_P(VibratorAidl, ExternalAmplitudeControl) { (capabilities & IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0; if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) { - EXPECT_TRUE(vibrator->setExternalControl(true).isOk()); + EXPECT_OK(vibrator->setExternalControl(true)); - Status amplitudeStatus = vibrator->setAmplitude(0.5); if (supportsExternalAmplitudeControl) { - EXPECT_TRUE(amplitudeStatus.isOk()); + EXPECT_OK(vibrator->setAmplitude(0.5)); } else { - EXPECT_TRUE(isUnknownOrUnsupported(amplitudeStatus)) << amplitudeStatus; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setAmplitude(0.5)); } - EXPECT_TRUE(vibrator->setExternalControl(false).isOk()); + + EXPECT_OK(vibrator->setExternalControl(false)); } else { EXPECT_FALSE(supportsExternalAmplitudeControl); } @@ -391,18 +562,16 @@ TEST_P(VibratorAidl, ExternalAmplitudeControl) { TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) { if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) { - Status status = vibrator->setExternalControl(true); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->setExternalControl(true)); } } TEST_P(VibratorAidl, GetSupportedPrimitives) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector supported; + EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); - EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode()); - - for (auto primitive : kCompositePrimitives) { + for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); bool isPrimitiveRequired = @@ -417,22 +586,23 @@ TEST_P(VibratorAidl, GetSupportedPrimitives) { TEST_P(VibratorAidl, GetPrimitiveDuration) { if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) { std::vector supported; - ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); - for (auto primitive : kCompositePrimitives) { + for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); int32_t duration; - Status status = vibrator->getPrimitiveDuration(primitive, &duration); - if (isPrimitiveSupported) { - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()); + EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &duration)) + << "\n For primitive: " << toString(primitive) << " " << duration; if (primitive != CompositePrimitive::NOOP) { - ASSERT_GT(duration, 0) << toString(primitive) << " " << duration; + ASSERT_GT(duration, 0) + << "\n For primitive: " << toString(primitive) << " " << duration; } } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->getPrimitiveDuration(primitive, &duration)) + << "\n For primitive: " << toString(primitive); } } } @@ -446,14 +616,14 @@ TEST_P(VibratorAidl, ComposeValidPrimitives) { std::vector supported; int32_t maxDelay, maxSize; - ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); - EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode()); - EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode()); + EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); + EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay)); + EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize)); std::vector composite; for (int i = 0; i < supported.size(); i++) { - auto primitive = supported[i]; + CompositePrimitive primitive = supported[i]; float t = static_cast(i + 1) / supported.size(); CompositeEffect effect; @@ -467,8 +637,8 @@ TEST_P(VibratorAidl, ComposeValidPrimitives) { } if (composite.size() != 0) { - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); } } @@ -477,12 +647,12 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { GTEST_SKIP() << "CAP_COMPOSE_EFFECTS not supported"; } - auto unsupported = kInvalidPrimitives; + std::vector unsupported(kInvalidPrimitives); std::vector supported; - ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); - for (auto primitive : kCompositePrimitives) { + for (CompositePrimitive primitive : kCompositePrimitives) { bool isPrimitiveSupported = std::find(supported.begin(), supported.end(), primitive) != supported.end(); @@ -491,16 +661,15 @@ TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) { } } - for (auto primitive : unsupported) { + for (CompositePrimitive primitive : unsupported) { std::vector composite(1); - for (auto& effect : composite) { + for (CompositeEffect& effect : composite) { effect.delayMs = 0; effect.primitive = primitive; effect.scale = 1.0f; } - Status status = vibrator->compose(composite, nullptr); - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->compose(composite, nullptr)); } } @@ -516,18 +685,18 @@ TEST_P(VibratorAidl, ComposeScaleBoundary) { effect.primitive = CompositePrimitive::CLICK; effect.scale = std::nextafter(0.0f, -1.0f); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); effect.scale = 0.0f; - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); effect.scale = 1.0f; - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); effect.scale = std::nextafter(1.0f, 2.0f); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeDelayBoundary) { @@ -537,7 +706,7 @@ TEST_P(VibratorAidl, ComposeDelayBoundary) { int32_t maxDelay; - EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode()); + EXPECT_OK(vibrator->getCompositionDelayMax(&maxDelay)); std::vector composite(1); CompositeEffect& effect = composite[0]; @@ -546,19 +715,19 @@ TEST_P(VibratorAidl, ComposeDelayBoundary) { effect.scale = 1.0f; effect.delayMs = 0; - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); effect.delayMs = 1; - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); effect.delayMs = maxDelay; - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); effect.delayMs = maxDelay + 1; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeSizeBoundary) { @@ -568,7 +737,7 @@ TEST_P(VibratorAidl, ComposeSizeBoundary) { int32_t maxSize; - EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode()); + EXPECT_OK(vibrator->getCompositionSizeMax(&maxSize)); std::vector composite(maxSize); CompositeEffect effect; @@ -578,11 +747,11 @@ TEST_P(VibratorAidl, ComposeSizeBoundary) { effect.scale = 1.0f; std::fill(composite.begin(), composite.end(), effect); - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->compose(composite, nullptr)); + EXPECT_OK(vibrator->off()); composite.emplace_back(effect); - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->compose(composite, nullptr).exceptionCode()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->compose(composite, nullptr)); } TEST_P(VibratorAidl, ComposeCallback) { @@ -591,18 +760,17 @@ TEST_P(VibratorAidl, ComposeCallback) { } std::vector supported; + EXPECT_OK(vibrator->getSupportedPrimitives(&supported)); - ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk()); - - for (auto primitive : supported) { + for (CompositePrimitive primitive : supported) { if (primitive == CompositePrimitive::NOOP) { continue; } std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; - sp callback = - new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); CompositeEffect effect; std::vector composite; int32_t durationMs; @@ -615,50 +783,50 @@ TEST_P(VibratorAidl, ComposeCallback) { effect.scale = 1.0f; composite.emplace_back(effect); - EXPECT_EQ(Status::EX_NONE, - vibrator->getPrimitiveDuration(primitive, &durationMs).exceptionCode()) - << toString(primitive); + EXPECT_OK(vibrator->getPrimitiveDuration(primitive, &durationMs)) + << "\n For primitive: " << toString(primitive); duration = std::chrono::milliseconds(durationMs); start = high_resolution_clock::now(); - EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode()) - << toString(primitive); + EXPECT_OK(vibrator->compose(composite, callback)) + << "\n For primitive: " << toString(primitive); EXPECT_EQ(completionFuture.wait_for(duration + VIBRATION_CALLBACK_TIMEOUT), std::future_status::ready) - << toString(primitive); + << "\n For primitive: " << toString(primitive); end = high_resolution_clock::now(); elapsed = std::chrono::duration_cast(end - start); - EXPECT_GE(elapsed.count(), duration.count()) << toString(primitive); + EXPECT_GE(elapsed.count(), duration.count()) + << "\n For primitive: " << toString(primitive); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()) << "\n For primitive: " << toString(primitive); } } TEST_P(VibratorAidl, AlwaysOn) { if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) { std::vector supported; - ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedAlwaysOnEffects(&supported)); for (Effect effect : kEffects) { bool isEffectSupported = std::find(supported.begin(), supported.end(), effect) != supported.end(); for (EffectStrength strength : kEffectStrengths) { - Status status = vibrator->alwaysOnEnable(0, effect, strength); + ndk::ScopedAStatus status = vibrator->alwaysOnEnable(0, effect, strength); if (isEffectSupported) { - EXPECT_EQ(Status::EX_NONE, status.exceptionCode()) - << toString(effect) << " " << toString(strength); + EXPECT_OK(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) - << status << " " << toString(effect) << " " << toString(strength); + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)) + << "\n For effect: " << toString(effect) << " " << toString(strength); } } } - EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode()); + EXPECT_OK(vibrator->alwaysOnDisable(0)); } } @@ -668,12 +836,12 @@ TEST_P(VibratorAidl, GetResonantFrequency) { TEST_P(VibratorAidl, GetQFactor) { float qFactor; - Status status = vibrator->getQFactor(&qFactor); + ndk::ScopedAStatus status = vibrator->getQFactor(&qFactor); if (capabilities & IVibrator::CAP_GET_Q_FACTOR) { + EXPECT_OK(std::move(status)); ASSERT_GT(qFactor, 0); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } @@ -687,9 +855,9 @@ TEST_P(VibratorAidl, GetFrequencyMinimum) { TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) { std::vector bandwidthAmplitudeMap; - Status status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); + ndk::ScopedAStatus status = vibrator->getBandwidthAmplitudeMap(&bandwidthAmplitudeMap); if (capabilities & IVibrator::CAP_FREQUENCY_CONTROL) { - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); + EXPECT_OK(std::move(status)); ASSERT_FALSE(bandwidthAmplitudeMap.empty()); int minMapSize = (getResonantFrequencyHz(vibrator, capabilities) - @@ -702,42 +870,42 @@ TEST_P(VibratorAidl, GetBandwidthAmplitudeMap) { ASSERT_LE(e, 1.0); } } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetPwlePrimitiveDurationMax) { int32_t durationMs; - Status status = vibrator->getPwlePrimitiveDurationMax(&durationMs); + ndk::ScopedAStatus status = vibrator->getPwlePrimitiveDurationMax(&durationMs); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { + EXPECT_OK(std::move(status)); ASSERT_NE(durationMs, 0); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetPwleCompositionSizeMax) { int32_t maxSize; - Status status = vibrator->getPwleCompositionSizeMax(&maxSize); + ndk::ScopedAStatus status = vibrator->getPwleCompositionSizeMax(&maxSize); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { + EXPECT_OK(std::move(status)); ASSERT_NE(maxSize, 0); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } TEST_P(VibratorAidl, GetSupportedBraking) { std::vector supported; - Status status = vibrator->getSupportedBraking(&supported); + ndk::ScopedAStatus status = vibrator->getSupportedBraking(&supported); if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { bool isDefaultNoneSupported = std::find(supported.begin(), supported.end(), Braking::NONE) != supported.end(); + EXPECT_OK(std::move(status)); ASSERT_TRUE(isDefaultNoneSupported); - EXPECT_EQ(status.exceptionCode(), Status::EX_NONE); } else { - EXPECT_TRUE(isUnknownOrUnsupported(status)) << status; + EXPECT_UNKNOWN_OR_UNSUPPORTED(std::move(status)); } } @@ -746,7 +914,7 @@ TEST_P(VibratorAidl, ComposeValidPwle) { ActivePwle firstActive = composeValidActivePwle(vibrator, capabilities); std::vector supported; - ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedBraking(&supported)); bool isClabSupported = std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end(); BrakingPwle firstBraking; @@ -765,11 +933,11 @@ TEST_P(VibratorAidl, ComposeValidPwle) { secondBraking.braking = Braking::NONE; secondBraking.duration = 10; - auto pwleQueue = - std::vector{firstActive, firstBraking, secondActive, secondBraking}; + std::vector pwleQueue = {firstActive, firstBraking, secondActive, + secondBraking}; - EXPECT_EQ(Status::EX_NONE, vibrator->composePwle(pwleQueue, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->composePwle(pwleQueue, nullptr)); + EXPECT_OK(vibrator->off()); } } @@ -780,8 +948,8 @@ TEST_P(VibratorAidl, ComposeValidPwleWithCallback) { std::promise completionPromise; std::future completionFuture{completionPromise.get_future()}; - sp callback = - new CompletionCallback([&completionPromise] { completionPromise.set_value(); }); + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); int32_t segmentDurationMaxMs; vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs); uint32_t durationMs = segmentDurationMaxMs * 2 + 100; // Sum of 2 active and 1 braking below @@ -790,27 +958,25 @@ TEST_P(VibratorAidl, ComposeValidPwleWithCallback) { ActivePwle active = composeValidActivePwle(vibrator, capabilities); std::vector supported; - ASSERT_TRUE(vibrator->getSupportedBraking(&supported).isOk()); + EXPECT_OK(vibrator->getSupportedBraking(&supported)); bool isClabSupported = std::find(supported.begin(), supported.end(), Braking::CLAB) != supported.end(); BrakingPwle braking; braking.braking = isClabSupported ? Braking::CLAB : Braking::NONE; braking.duration = 100; - auto pwleQueue = std::vector{active, braking, active}; + std::vector pwleQueue = {active, braking, active}; - EXPECT_TRUE(vibrator->composePwle(pwleQueue, callback).isOk()); + EXPECT_OK(vibrator->composePwle(pwleQueue, callback)); EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_OK(vibrator->off()); } TEST_P(VibratorAidl, ComposePwleSegmentBoundary) { if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS) { std::vector pwleQueue; // test empty queue - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueue, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); ActivePwle active = composeValidActivePwle(vibrator, capabilities); @@ -824,9 +990,7 @@ TEST_P(VibratorAidl, ComposePwleSegmentBoundary) { pwleQueue.emplace_back(std::move(pwle)); } - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueue, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); } } @@ -836,20 +1000,16 @@ TEST_P(VibratorAidl, ComposePwleAmplitudeParameterBoundary) { active.startAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed active.endAmplitude = getAmplitudeMax() + 1.0; // Amplitude greater than allowed - auto pwleQueueGreater = std::vector{active}; + std::vector pwleQueueGreater = {active}; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr)); active.startAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed active.endAmplitude = getAmplitudeMin() - 1.0; // Amplitude less than allowed - auto pwleQueueLess = std::vector{active}; + std::vector pwleQueueLess = {active}; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr)); } } @@ -865,20 +1025,16 @@ TEST_P(VibratorAidl, ComposePwleFrequencyParameterBoundary) { freqMaximumHz + freqResolutionHz; // Frequency greater than allowed active.endFrequency = freqMaximumHz + freqResolutionHz; // Frequency greater than allowed - auto pwleQueueGreater = std::vector{active}; + std::vector pwleQueueGreater = {active}; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueueGreater, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueGreater, nullptr)); active.startFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed active.endFrequency = freqMinimumHz - freqResolutionHz; // Frequency less than allowed - auto pwleQueueLess = std::vector{active}; + std::vector pwleQueueLess = {active}; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueueLess, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueueLess, nullptr)); } } @@ -890,32 +1046,196 @@ TEST_P(VibratorAidl, ComposePwleSegmentDurationBoundary) { vibrator->getPwlePrimitiveDurationMax(&segmentDurationMaxMs); active.duration = segmentDurationMaxMs + 10; // Segment duration greater than allowed - auto pwleQueue = std::vector{active}; + std::vector pwleQueue = {active}; - EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, - vibrator->composePwle(pwleQueue, nullptr).exceptionCode()); - EXPECT_TRUE(vibrator->off().isOk()); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwle(pwleQueue, nullptr)); } } +TEST_P(VibratorAidl, PwleV2FrequencyToOutputAccelerationMapHasValidFrequencyRange) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + std::vector frequencyToOutputAccelerationMap; + ndk::ScopedAStatus status = + vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap); + EXPECT_OK(std::move(status)); + ASSERT_FALSE(frequencyToOutputAccelerationMap.empty()); + auto sharpnessRange = + pwle_v2_utils::getPwleV2SharpnessRange(vibrator, frequencyToOutputAccelerationMap); + // Validate the curve provides a usable sharpness range, which is a range of frequencies + // that are supported by the device. + ASSERT_TRUE(sharpnessRange.first >= 0); + // Validate that the sharpness range is a valid interval, not a single point. + ASSERT_TRUE(sharpnessRange.first < sharpnessRange.second); +} + +TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMaxMillis) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + int32_t durationMs; + ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMaxMillis(&durationMs); + EXPECT_OK(std::move(status)); + ASSERT_GT(durationMs, 0); // Ensure greater than zero + ASSERT_GE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS); +} + +TEST_P(VibratorAidl, GetPwleV2CompositionSizeMax) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + int32_t maxSize; + ndk::ScopedAStatus status = vibrator->getPwleV2CompositionSizeMax(&maxSize); + EXPECT_OK(std::move(status)); + ASSERT_GT(maxSize, 0); // Ensure greater than zero + ASSERT_GE(maxSize, pwle_v2_utils::COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE); +} + +TEST_P(VibratorAidl, GetPwleV2PrimitiveDurationMinMillis) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + int32_t durationMs; + ndk::ScopedAStatus status = vibrator->getPwleV2PrimitiveDurationMinMillis(&durationMs); + EXPECT_OK(std::move(status)); + ASSERT_GT(durationMs, 0); // Ensure greater than zero + ASSERT_LE(durationMs, pwle_v2_utils::COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS); +} + +TEST_P(VibratorAidl, ComposeValidPwleV2Effect) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + EXPECT_OK(vibrator->composePwleV2(pwle_v2_utils::composeValidPwleV2Effect(vibrator), nullptr)); + EXPECT_OK(vibrator->off()); +} + +TEST_P(VibratorAidl, ComposePwleV2Unsupported) { + if (version < PWLE_V2_MIN_VERSION) { + EXPECT_EQ(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2, 0) + << "Vibrator version " << version << " should not report PWLE V2 capability."; + } + if (capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2) return; + + std::vector pwleEffect{ + PwleV2Primitive(/*amplitude=*/1.0f, /*frequencyHz=*/100.0f, /*timeMillis=*/50)}; + + EXPECT_UNKNOWN_OR_UNSUPPORTED(vibrator->composePwleV2(pwleEffect, nullptr)); +} + +TEST_P(VibratorAidl, ComposeValidPwleV2EffectWithCallback) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + std::promise completionPromise; + std::future completionFuture{completionPromise.get_future()}; + auto callback = ndk::SharedRefBase::make( + [&completionPromise] { completionPromise.set_value(); }); + + int32_t minDuration; + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDuration)); + auto timeout = std::chrono::milliseconds(minDuration) + VIBRATION_CALLBACK_TIMEOUT; + float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator); + + EXPECT_OK(vibrator->composePwleV2( + {PwleV2Primitive(/*amplitude=*/0.5, minFrequency, minDuration)}, callback)); + EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready); + EXPECT_OK(vibrator->off()); +} + +TEST_P(VibratorAidl, composePwleV2EffectWithTooManyPoints) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2( + pwle_v2_utils::composePwleV2EffectWithTooManyPoints(vibrator), nullptr)); +} + +TEST_P(VibratorAidl, composeInvalidPwleV2Effect) { + if (!(capabilities & IVibrator::CAP_COMPOSE_PWLE_EFFECTS_V2)) { + GTEST_SKIP() << "PWLE V2 not supported, skipping test"; + return; + } + + // Retrieve min and max durations + int32_t minDurationMs, maxDurationMs; + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs)); + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs)); + + std::vector composePwle; + + // Negative amplitude + composePwle.push_back(PwleV2Primitive(/*amplitude=*/-0.8f, /*frequency=*/100, minDurationMs)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with negative amplitude should fail"; + composePwle.clear(); + + // Amplitude exceeding 1.0 + composePwle.push_back(PwleV2Primitive(/*amplitude=*/1.2f, /*frequency=*/100, minDurationMs)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with amplitude greater than 1.0 should fail"; + composePwle.clear(); + + // Duration exceeding maximum + composePwle.push_back( + PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, maxDurationMs + 10)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with duration exceeding maximum should fail"; + composePwle.clear(); + + // Negative duration + composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, /*frequency=*/100, /*time=*/-1)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with negative duration should fail"; + composePwle.clear(); + + // Frequency below minimum + float minFrequency = pwle_v2_utils::getPwleV2FrequencyMinHz(vibrator); + composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, minFrequency - 1, minDurationMs)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with frequency below minimum should fail"; + composePwle.clear(); + + // Frequency above maximum + float maxFrequency = pwle_v2_utils::getPwleV2FrequencyMaxHz(vibrator); + composePwle.push_back(PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency + 1, minDurationMs)); + EXPECT_ILLEGAL_ARGUMENT(vibrator->composePwleV2(composePwle, nullptr)) + << "Composing PWLE V2 effect with frequency above maximum should fail"; +} + std::vector> GenerateVibratorMapping() { std::vector> tuples; - auto managerAidlNames = android::getAidlHalInstanceNames(IVibratorManager::descriptor); - std::vector vibratorIds; - for (int i = 0; i < managerAidlNames.size(); i++) { - auto managerName = String16(managerAidlNames[i].c_str()); - auto vibratorManager = android::waitForDeclaredService(managerName); + std::vector managerNames = findVibratorManagerNames(); + std::vector vibratorIds; + for (int i = 0; i < managerNames.size(); i++) { + auto vibratorManager = IVibratorManager::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(managerNames[i].c_str()))); if (vibratorManager->getVibratorIds(&vibratorIds).isOk()) { - for (auto &vibratorId : vibratorIds) { - tuples.push_back(std::make_tuple(i, vibratorId)); + for (int32_t vibratorId : vibratorIds) { + tuples.emplace_back(i, vibratorId); } } } - auto vibratorAidlNames = android::getAidlHalInstanceNames(IVibrator::descriptor); - for (int i = 0; i < vibratorAidlNames.size(); i++) { - tuples.push_back(std::make_tuple(-1, i)); + std::vector vibratorNames = findUnmanagedVibratorNames(); + for (int i = 0; i < vibratorNames.size(); i++) { + tuples.emplace_back(-1, i); } return tuples; @@ -935,8 +1255,11 @@ INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl, testing::ValuesIn(GenerateVibra PrintGeneratedTest); int main(int argc, char **argv) { + // Random values are used in the implementation. + std::srand(std::time(nullptr)); + ::testing::InitGoogleTest(&argc, argv); - ProcessState::self()->setThreadPoolMaxThreadCount(1); - ProcessState::self()->startThreadPool(); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); return RUN_ALL_TESTS(); } diff --git a/vibrator/aidl/vts/persistable_bundle_utils.h b/vibrator/aidl/vts/persistable_bundle_utils.h new file mode 100644 index 0000000000..a765a4992e --- /dev/null +++ b/vibrator/aidl/vts/persistable_bundle_utils.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2024 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. + */ +#ifndef VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H +#define VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H + +#include + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { +namespace testing { + +using aidl::android::os::PersistableBundle; + +namespace { + +template +T nextValue() { + return static_cast(std::rand()); +} + +template <> +std::string nextValue() { + std::string str; + uint8_t entryCount = nextValue(); + for (uint8_t i = 0; i < entryCount; i++) { + str.push_back(nextValue()); + } + return str; +} + +template +T nextValue(T limit) { + assert(limit > 0); + return static_cast(std::rand()) / (static_cast(RAND_MAX / limit)); +} + +template +void fillVector(std::vector* values) { + uint8_t entryCount = nextValue(); + for (uint8_t i = 0; i < entryCount; i++) { + values->push_back(nextValue()); + } +} + +const std::vector> + sPersistableBundleSetters = {[](PersistableBundle* bundle, const std::string& key) -> void { + bundle->putBoolean(key, nextValue()); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + bundle->putInt(key, nextValue()); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + bundle->putLong(key, nextValue()); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + bundle->putDouble(key, nextValue()); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + bundle->putString(key, nextValue()); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + std::vector value; + fillVector(&value); + bundle->putBooleanVector(key, value); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + std::vector value; + fillVector(&value); + bundle->putIntVector(key, value); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + std::vector value; + fillVector(&value); + bundle->putLongVector(key, value); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + std::vector value; + fillVector(&value); + bundle->putDoubleVector(key, value); + }, + [](PersistableBundle* bundle, const std::string& key) -> void { + std::vector value; + fillVector(&value); + bundle->putStringVector(key, value); + }}; + +} // namespace + +void fillBasicData(PersistableBundle* bundle) { + bundle->putBoolean("test_bool", true); + bundle->putInt("test_int", 2147483647); + bundle->putLong("test_long", 2147483647L); + bundle->putDouble("test_double", 1.23); + bundle->putString("test_string", "test data"); + bundle->putBooleanVector("test_bool_vector", {true, false, false}); + bundle->putIntVector("test_int_vector", {1, 2, 3, 4}); + bundle->putLongVector("test_long_vector", {100L, 200L, 300L}); + bundle->putDoubleVector("test_double_vector", {1.1, 2.2}); + bundle->putStringVector("test_string_vector", {"test", "val"}); +} + +void fillRandomData(PersistableBundle* bundle) { + uint8_t entryCount = nextValue(); + for (uint8_t i = 0; i < entryCount; i++) { + std::string key(nextValue()); + uint8_t setterIdx = nextValue(sPersistableBundleSetters.size() - 1); + sPersistableBundleSetters[setterIdx](bundle, key); + } +} + +} // namespace testing +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl + +#endif // VIBRATOR_HAL_PERSISTABLE_BUNDLE_UTILS_H diff --git a/vibrator/aidl/vts/pwle_v2_utils.h b/vibrator/aidl/vts/pwle_v2_utils.h new file mode 100644 index 0000000000..2163908e2a --- /dev/null +++ b/vibrator/aidl/vts/pwle_v2_utils.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2024 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. + */ + +#ifndef VIBRATOR_HAL_PWLE_V2_UTILS_H +#define VIBRATOR_HAL_PWLE_V2_UTILS_H + +#include +#include "test_utils.h" + +using aidl::android::hardware::vibrator::IVibrator; +using aidl::android::hardware::vibrator::PwleV2OutputMapEntry; +using aidl::android::hardware::vibrator::PwleV2Primitive; + +namespace aidl { +namespace android { +namespace hardware { +namespace vibrator { +namespace testing { +namespace pwlev2 { + +static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SIZE = 16; +static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_PRIMITIVE_MAX_DURATION_MS = 1000; +static constexpr int32_t COMPOSE_PWLE_V2_MAX_ALLOWED_PRIMITIVE_MIN_DURATION_MS = 20; +static constexpr int32_t COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL = 10; + +namespace { +/** + * Returns a vector of (frequency in Hz, acceleration in dB) pairs, where the acceleration + * value denotes the minimum output required at the corresponding frequency to be perceptible + * by a human. + */ +static std::vector> getMinPerceptibleLevel() { + return {{0.4f, -97.81f}, {2.0f, -69.86f}, {3.0f, -62.81f}, {4.0f, -58.81f}, + {5.0f, -56.69f}, {6.0f, -54.77f}, {7.2f, -52.85f}, {8.0f, -51.77f}, + {8.64f, -50.84f}, {10.0f, -48.90f}, {10.37f, -48.52f}, {12.44f, -46.50f}, + {14.93f, -44.43f}, {15.0f, -44.35f}, {17.92f, -41.96f}, {20.0f, -40.36f}, + {21.5f, -39.60f}, {25.0f, -37.48f}, {25.8f, -36.93f}, {30.0f, -34.31f}, + {35.0f, -33.13f}, {40.0f, -32.81f}, {50.0f, -31.94f}, {60.0f, -31.77f}, + {70.0f, -31.59f}, {72.0f, -31.55f}, {80.0f, -31.77f}, {86.4f, -31.94f}, + {90.0f, -31.73f}, {100.0f, -31.90f}, {103.68f, -31.77f}, {124.42f, -31.70f}, + {149.3f, -31.38f}, {150.0f, -31.35f}, {179.16f, -31.02f}, {200.0f, -30.86f}, + {215.0f, -30.35f}, {250.0f, -28.98f}, {258.0f, -28.68f}, {300.0f, -26.81f}, + {400.0f, -19.81f}}; +} + +static float interpolateLinearly(const std::vector& xAxis, const std::vector& yAxis, + float x) { + EXPECT_TRUE(!xAxis.empty()); + EXPECT_TRUE(xAxis.size() == yAxis.size()); + + if (x <= xAxis.front()) return yAxis.front(); + if (x >= xAxis.back()) return yAxis.back(); + + auto it = std::upper_bound(xAxis.begin(), xAxis.end(), x); + int i = std::distance(xAxis.begin(), it) - 1; // Index of the lower bound + + const float& x0 = xAxis[i]; + const float& y0 = yAxis[i]; + const float& x1 = xAxis[i + 1]; + const float& y1 = yAxis[i + 1]; + + return y0 + (x - x0) * (y1 - y0) / (x1 - x0); +} + +static float minPerceptibleDbCurve(float frequency) { + // Initialize minPerceptibleMap only once + static auto minPerceptibleMap = []() -> std::function { + static std::vector minPerceptibleFrequencies; + static std::vector minPerceptibleAccelerations; + + auto minPerceptibleLevel = getMinPerceptibleLevel(); + // Sort the 'minPerceptibleLevel' data in ascending order based on the + // frequency values (first element of each pair). + std::sort(minPerceptibleLevel.begin(), minPerceptibleLevel.end(), + [](const auto& a, const auto& b) { return a.first < b.first; }); + + for (const auto& entry : minPerceptibleLevel) { + minPerceptibleFrequencies.push_back(entry.first); + minPerceptibleAccelerations.push_back(entry.second); + } + + return [&](float freq) { + return interpolateLinearly(minPerceptibleFrequencies, minPerceptibleAccelerations, + freq); + }; + }(); + + return minPerceptibleMap(frequency); +} + +static float convertSensitivityLevelToDecibel(int sl, float frequency) { + return sl + minPerceptibleDbCurve(frequency); +} + +static float convertDecibelToAcceleration(float db) { + return std::pow(10.0f, db / 20.0f); +} +} // namespace + +static float convertSensitivityLevelToAcceleration(int sl, float frequency) { + return pwlev2::convertDecibelToAcceleration( + pwlev2::convertSensitivityLevelToDecibel(sl, frequency)); +} + +static float getPwleV2FrequencyMinHz(const std::shared_ptr& vibrator) { + std::vector frequencyToOutputAccelerationMap; + EXPECT_OK( + vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap)); + EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty()); + // We can't use ASSERT_TRUE() above because this is a non-void function, + // but we need to return to assure we don't crash from a null dereference. + if (frequencyToOutputAccelerationMap.empty()) { + return std::numeric_limits::quiet_NaN(); + } + + auto entry = std::min_element( + frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(), + [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; }); + + return entry->frequencyHz; +} + +static float getPwleV2FrequencyMaxHz(const std::shared_ptr& vibrator) { + std::vector frequencyToOutputAccelerationMap; + EXPECT_OK( + vibrator->getPwleV2FrequencyToOutputAccelerationMap(&frequencyToOutputAccelerationMap)); + EXPECT_TRUE(!frequencyToOutputAccelerationMap.empty()); + // We can't use ASSERT_TRUE() above because this is a non-void function, + // but we need to return to assure we don't crash from a null dereference. + if (frequencyToOutputAccelerationMap.empty()) { + return std::numeric_limits::quiet_NaN(); + } + + auto entry = std::max_element( + frequencyToOutputAccelerationMap.begin(), frequencyToOutputAccelerationMap.end(), + [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; }); + + return entry->frequencyHz; +} + +static std::vector composeValidPwleV2Effect( + const std::shared_ptr& vibrator) { + int32_t minDurationMs; + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs)); + int32_t maxDurationMs; + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMaxMillis(&maxDurationMs)); + float minFrequency = getPwleV2FrequencyMinHz(vibrator); + float maxFrequency = getPwleV2FrequencyMaxHz(vibrator); + int32_t maxCompositionSize; + EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize)); + + std::vector pwleEffect; + + pwleEffect.emplace_back(0.1f, minFrequency, minDurationMs); + pwleEffect.emplace_back(0.5f, maxFrequency, maxDurationMs); + + float variedFrequency = (minFrequency + maxFrequency) / 2.0f; + for (int i = 0; i < maxCompositionSize - 2; i++) { + pwleEffect.emplace_back(0.7f, variedFrequency, minDurationMs); + } + + return pwleEffect; +} + +static std::vector composePwleV2EffectWithTooManyPoints( + const std::shared_ptr& vibrator) { + int32_t minDurationMs, maxCompositionSize; + EXPECT_OK(vibrator->getPwleV2PrimitiveDurationMinMillis(&minDurationMs)); + EXPECT_OK(vibrator->getPwleV2CompositionSizeMax(&maxCompositionSize)); + float maxFrequency = getPwleV2FrequencyMaxHz(vibrator); + + std::vector pwleEffect(maxCompositionSize + 1); // +1 to exceed the limit + + std::fill(pwleEffect.begin(), pwleEffect.end(), + PwleV2Primitive(/*amplitude=*/0.2f, maxFrequency, minDurationMs)); + + return pwleEffect; +} + +static std::pair getPwleV2SharpnessRange( + const std::shared_ptr& vibrator, + std::vector freqToOutputAccelerationMap) { + std::pair sharpnessRange = {-1, -1}; + + // Sort the entries by frequency in ascending order + std::sort(freqToOutputAccelerationMap.begin(), freqToOutputAccelerationMap.end(), + [](const auto& a, const auto& b) { return a.frequencyHz < b.frequencyHz; }); + + for (const auto& entry : freqToOutputAccelerationMap) { + float minAcceptableOutputAcceleration = convertSensitivityLevelToAcceleration( + pwlev2::COMPOSE_PWLE_V2_MIN_REQUIRED_SENSITIVITY_DB_SL, entry.frequencyHz); + + if (sharpnessRange.first < 0 && + minAcceptableOutputAcceleration <= entry.maxOutputAccelerationGs) { + sharpnessRange.first = entry.frequencyHz; // Found the lower bound + } else if (sharpnessRange.first >= 0 && + minAcceptableOutputAcceleration >= entry.maxOutputAccelerationGs) { + sharpnessRange.second = entry.frequencyHz; // Found the upper bound + return sharpnessRange; + } + } + + if (sharpnessRange.first >= 0) { + // If only the lower bound was found, set the upper bound to the max frequency. + sharpnessRange.second = getPwleV2FrequencyMaxHz(vibrator); + } + + return sharpnessRange; +} +} // namespace pwlev2 +} // namespace testing +} // namespace vibrator +} // namespace hardware +} // namespace android +} // namespace aidl +#endif // VIBRATOR_HAL_PWLE_V2_UTILS_H diff --git a/vibrator/aidl/vts/test_utils.h b/vibrator/aidl/vts/test_utils.h new file mode 100644 index 0000000000..aaf3211bd4 --- /dev/null +++ b/vibrator/aidl/vts/test_utils.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2024 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. + */ +#ifndef VIBRATOR_HAL_TEST_UTILS_H +#define VIBRATOR_HAL_TEST_UTILS_H + +#include +#include + +#if !defined(EXPECT_OK) +#define EXPECT_OK(expression) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::ndk::ScopedAStatus&& _status = (expression); _status.isOk()) \ + ; \ + else \ + ADD_FAILURE() << "Expected STATUS_OK for: " << #expression << "\n Actual: " << _status +#else +#error Macro EXPECT_OK already defined unexpectedly +#endif + +#if !defined(EXPECT_UNKNOWN_OR_UNSUPPORTED) +#define EXPECT_UNKNOWN_OR_UNSUPPORTED(expression) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::ndk::ScopedAStatus&& _status = (expression); \ + _status.getExceptionCode() == EX_UNSUPPORTED_OPERATION || \ + _status.getStatus() == STATUS_UNKNOWN_TRANSACTION) \ + ; \ + else \ + ADD_FAILURE() << "Expected STATUS_UNKNOWN_TRANSACTION or EX_UNSUPPORTED_OPERATION for: " \ + << #expression << "\n Actual: " << _status +#else +#error Macro EXPECT_UNKNOWN_OR_UNSUPPORTED already defined unexpectedly +#endif + +#if !defined(EXPECT_ILLEGAL_ARGUMENT) +#define EXPECT_ILLEGAL_ARGUMENT(expression) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::ndk::ScopedAStatus&& _status = (expression); \ + _status.getExceptionCode() == EX_ILLEGAL_ARGUMENT) \ + ; \ + else \ + ADD_FAILURE() << "Expected EX_ILLEGAL_ARGUMENT for: " << #expression \ + << "\n Actual: " << _status +#else +#error Macro EXPECT_ILLEGAL_ARGUMENT already defined unexpectedly +#endif + +#endif // VIBRATOR_HAL_TEST_UTILS_H diff --git a/vibrator/bench/Android.bp b/vibrator/bench/Android.bp index 87bdab4215..cd56516eed 100644 --- a/vibrator/bench/Android.bp +++ b/vibrator/bench/Android.bp @@ -30,12 +30,12 @@ cc_benchmark { "benchmark.cpp", ], shared_libs: [ - "android.hardware.vibrator-V2-cpp", + "android.hardware.vibrator-V3-ndk", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", - "libbinder", + "libbinder_ndk", "libhardware", "libhidlbase", "libutils", diff --git a/vibrator/bench/benchmark.cpp b/vibrator/bench/benchmark.cpp index deaa6f2c55..8fe9cf7a54 100644 --- a/vibrator/bench/benchmark.cpp +++ b/vibrator/bench/benchmark.cpp @@ -16,15 +16,14 @@ #include "benchmark/benchmark.h" +#include +#include + +#include +#include #include -#include -#include -#include -#include #include -using ::android::enum_range; -using ::android::sp; using ::android::hardware::hidl_enum_range; using ::android::hardware::Return; using ::android::hardware::details::hidl_enum_values; @@ -33,10 +32,11 @@ using ::benchmark::Fixture; using ::benchmark::kMicrosecond; using ::benchmark::State; using ::benchmark::internal::Benchmark; +using ::ndk::enum_range; using namespace ::std::chrono_literals; -namespace Aidl = ::android::hardware::vibrator; +namespace Aidl = ::aidl::android::hardware::vibrator; namespace V1_0 = ::android::hardware::vibrator::V1_0; namespace V1_1 = ::android::hardware::vibrator::V1_1; namespace V1_2 = ::android::hardware::vibrator::V1_2; @@ -56,8 +56,8 @@ template class BaseBench : public Fixture { public: void SetUp(State& /*state*/) override { - android::ProcessState::self()->setThreadPoolMaxThreadCount(1); - android::ProcessState::self()->startThreadPool(); + ABinderProcess_setThreadPoolMaxThreadCount(1); + ABinderProcess_startThreadPool(); } void TearDown(State& /*state*/) override { @@ -75,7 +75,7 @@ class BaseBench : public Fixture { auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); } protected: - sp mVibrator; + std::shared_ptr mVibrator; }; template @@ -83,7 +83,12 @@ class VibratorBench : public BaseBench { public: void SetUp(State& state) override { BaseBench::SetUp(state); - this->mVibrator = I::getService(); + auto service = I::getService(); + if (service) { + this->mVibrator = std::shared_ptr(service.release()); + } else { + this->mVibrator = nullptr; + } } protected: @@ -356,7 +361,9 @@ class VibratorBench_Aidl : public BaseBench { public: void SetUp(State& state) override { BaseBench::SetUp(state); - this->mVibrator = android::waitForVintfService(); + auto serviceName = std::string(Aidl::IVibrator::descriptor) + "/default"; + this->mVibrator = Aidl::IVibrator::fromBinder( + ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str()))); } void TearDown(State& state) override { @@ -373,14 +380,24 @@ class VibratorBench_Aidl : public BaseBench { return (deviceCapabilities & capabilities) == capabilities; } - bool shouldSkipWithError(State& state, const android::binder::Status&& status) { + bool shouldSkipWithError(State& state, const ndk::ScopedAStatus&& status) { if (!status.isOk()) { - state.SkipWithError(status.toString8().c_str()); + state.SkipWithError(status.getMessage()); return true; } return false; } + void waitForComplete(std::future& callbackFuture) { + // Wait until the HAL has finished processing previous vibration before starting a new one, + // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest + // HAL implementations are waiting on previous vibration cleanup and might be significantly + // slower, so make sure we measure vibrations on a clean slate. + if (callbackFuture.valid()) { + callbackFuture.wait_for(VIBRATION_CALLBACK_TIMEOUT); + } + } + static void SlowBenchConfig(Benchmark* b) { b->Iterations(VIBRATION_ITERATIONS); } }; @@ -397,18 +414,12 @@ class HalCallback : public Aidl::BnVibratorCallback { HalCallback() = default; ~HalCallback() = default; - android::binder::Status onComplete() override { + ndk::ScopedAStatus onComplete() override { mPromise.set_value(); - return android::binder::Status::ok(); + return ndk::ScopedAStatus::ok(); } - void waitForComplete() { - // Wait until the HAL has finished processing previous vibration before starting a new one, - // so the HAL state is consistent on each run and metrics are less noisy. Some of the newest - // HAL implementations are waiting on previous vibration cleanup and might be significantly - // slower, so make sure we measure vibrations on a clean slate. - mPromise.get_future().wait_for(VIBRATION_CALLBACK_TIMEOUT); - } + std::future getFuture() { return mPromise.get_future(); } private: std::promise mPromise; @@ -418,7 +429,11 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, on, { auto ms = MAX_ON_DURATION_MS; for (auto _ : state) { - auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr; + auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) + ? ndk::SharedRefBase::make() + : nullptr; + // Grab the future before callback promise is destroyed by the HAL. + auto cbFuture = cb ? cb->getFuture() : std::future(); // Test if (shouldSkipWithError(state, mVibrator->on(ms, cb))) { @@ -430,9 +445,7 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, on, { if (shouldSkipWithError(state, mVibrator->off())) { return; } - if (cb) { - cb->waitForComplete(); - } + waitForComplete(cbFuture); state.ResumeTiming(); } }); @@ -441,7 +454,11 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, off, { auto ms = MAX_ON_DURATION_MS; for (auto _ : state) { - auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr; + auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) + ? ndk::SharedRefBase::make() + : nullptr; + // Grab the future before callback promise is destroyed by the HAL. + auto cbFuture = cb ? cb->getFuture() : std::future(); // Setup state.PauseTiming(); @@ -457,9 +474,7 @@ BENCHMARK_WRAPPER(SlowVibratorBench_Aidl, off, { // Cleanup state.PauseTiming(); - if (cb) { - cb->waitForComplete(); - } + waitForComplete(cbFuture); state.ResumeTiming(); } }); @@ -483,7 +498,9 @@ BENCHMARK_WRAPPER(VibratorBench_Aidl, setAmplitude, { return; } - auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) ? new HalCallback() : nullptr; + auto cb = hasCapabilities(Aidl::IVibrator::CAP_ON_CALLBACK) + ? ndk::SharedRefBase::make() + : nullptr; if (shouldSkipWithError(state, mVibrator->on(ms, cb))) { return; } @@ -685,8 +702,11 @@ BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, { int32_t lengthMs = 0; for (auto _ : state) { - auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) ? new HalCallback() - : nullptr; + auto cb = hasCapabilities(Aidl::IVibrator::CAP_PERFORM_CALLBACK) + ? ndk::SharedRefBase::make() + : nullptr; + // Grab the future before callback promise is destroyed by the HAL. + auto cbFuture = cb ? cb->getFuture() : std::future(); // Test if (shouldSkipWithError(state, mVibrator->perform(effect, strength, cb, &lengthMs))) { @@ -698,9 +718,7 @@ BENCHMARK_WRAPPER(SlowVibratorEffectsBench_Aidl, perform, { if (shouldSkipWithError(state, mVibrator->off())) { return; } - if (cb) { - cb->waitForComplete(); - } + waitForComplete(cbFuture); state.ResumeTiming(); } }); @@ -799,7 +817,9 @@ BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, { effects.push_back(effect); for (auto _ : state) { - auto cb = new HalCallback(); + auto cb = ndk::SharedRefBase::make(); + // Grab the future before callback promise is moved and destroyed by the HAL. + auto cbFuture = cb->getFuture(); // Test if (shouldSkipWithError(state, mVibrator->compose(effects, cb))) { @@ -811,7 +831,7 @@ BENCHMARK_WRAPPER(SlowVibratorPrimitivesBench_Aidl, compose, { if (shouldSkipWithError(state, mVibrator->off())) { return; } - cb->waitForComplete(); + waitForComplete(cbFuture); state.ResumeTiming(); } }); diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp index d82450e348..d99edaab9b 100644 --- a/wifi/aidl/default/aidl_struct_util.cpp +++ b/wifi/aidl/default/aidl_struct_util.cpp @@ -3394,6 +3394,7 @@ bool convertAidlNanBootstrappingIndicationResponseToLegacy( *legacy_request = {}; legacy_request->service_instance_id = aidl_request.bootstrappingInstanceId; + legacy_request->bootstrapping_instance_id = aidl_request.bootstrappingInstanceId; legacy_request->rsp_code = aidl_request.acceptRequest ? NAN_BOOTSTRAPPING_REQUEST_ACCEPT : NAN_BOOTSTRAPPING_REQUEST_REJECT; legacy_request->publish_subscribe_id = static_cast(aidl_request.discoverySessionId); diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp index 9b9c565dd5..fccfc15859 100644 --- a/wifi/aidl/default/wifi_chip.cpp +++ b/wifi/aidl/default/wifi_chip.cpp @@ -62,7 +62,9 @@ template std::vector getNames(std::vector>& ifaces) { std::vector names; for (const auto& iface : ifaces) { - names.emplace_back(iface->getName()); + if (iface) { + names.emplace_back(iface->getName()); + } } return names; } @@ -971,6 +973,10 @@ std::pair, ndk::ScopedAStatus> WifiChip::createNa } std::shared_ptr iface = WifiNanIface::create(ifname, is_dedicated_iface, legacy_hal_, iface_util_); + if (!iface) { + LOG(ERROR) << "Unable to create NAN iface"; + return {nullptr, createWifiStatus(WifiStatusCode::ERROR_UNKNOWN)}; + } nan_ifaces_.push_back(iface); for (const auto& callback : event_cb_handler_.getCallbacks()) { if (!callback->onIfaceAdded(IfaceType::NAN_IFACE, ifname).isOk()) { diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp index 21d50ac325..c68d8fddb5 100644 --- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp +++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.cpp @@ -177,8 +177,7 @@ std::shared_ptr getWifiNanIface(const char* instance_name) { return iface; } -std::shared_ptr getWifiApIface(const char* instance_name) { - std::shared_ptr wifi_chip = getWifiChip(instance_name); +std::shared_ptr getWifiApIface(std::shared_ptr wifi_chip) { if (!wifi_chip.get()) { return nullptr; } @@ -193,6 +192,11 @@ std::shared_ptr getWifiApIface(const char* instance_name) { return iface; } +std::shared_ptr getWifiApIface(const char* instance_name) { + std::shared_ptr wifi_chip = getWifiChip(instance_name); + return getWifiApIface(wifi_chip); +} + std::shared_ptr getBridgedWifiApIface(std::shared_ptr wifi_chip) { if (!wifi_chip.get()) { return nullptr; diff --git a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h index 1369dd487a..9b47a9f4c3 100644 --- a/wifi/aidl/vts/functional/wifi_aidl_test_utils.h +++ b/wifi/aidl/vts/functional/wifi_aidl_test_utils.h @@ -40,6 +40,7 @@ std::shared_ptr getWifiChip(const char* instance_name); std::shared_ptr getWifiStaIface(const char* instance_name); std::shared_ptr getWifiNanIface(const char* instance_name); std::shared_ptr getWifiApIface(const char* instance_name); +std::shared_ptr getWifiApIface(std::shared_ptr wifi_chip); std::shared_ptr getBridgedWifiApIface(const char* instance_name); std::shared_ptr getBridgedWifiApIface(std::shared_ptr wifi_chip); // Configure the chip in a mode to support the creation of the provided iface type. diff --git a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp index d39cfb4f93..a58fd5bcdd 100644 --- a/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp +++ b/wifi/aidl/vts/functional/wifi_ap_iface_aidl_test.cpp @@ -37,12 +37,21 @@ class WifiApIfaceAidlTest : public testing::TestWithParam { "/system/bin/cmd wifi get-softap-supported-features", "wifi_softap_bridged_ap_supported"); stopWifiService(getInstanceName()); + + wifi_chip_ = getWifiChip(getInstanceName()); + ASSERT_NE(nullptr, wifi_chip_.get()); + + bool isApSupported = doesChipSupportConcurrencyType(wifi_chip_, IfaceConcurrencyType::AP); + if (!isApSupported) { + GTEST_SKIP() << "AP interfaces are not supported"; + } } void TearDown() override { stopWifiService(getInstanceName()); } protected: bool isBridgedSupport_ = false; + std::shared_ptr wifi_chip_; const char* getInstanceName() { return GetParam().c_str(); } }; @@ -50,7 +59,7 @@ class WifiApIfaceAidlTest : public testing::TestWithParam { * SetMacAddress */ TEST_P(WifiApIfaceAidlTest, SetMacAddress) { - std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); std::array mac = {0x12, 0x22, 0x33, 0x52, 0x10, 0x44}; EXPECT_TRUE(wifi_ap_iface->setMacAddress(mac).isOk()); @@ -60,7 +69,7 @@ TEST_P(WifiApIfaceAidlTest, SetMacAddress) { * SetCountryCode */ TEST_P(WifiApIfaceAidlTest, SetCountryCode) { - std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); const std::array country_code = {0x55, 0x53}; @@ -71,7 +80,7 @@ TEST_P(WifiApIfaceAidlTest, SetCountryCode) { * GetFactoryMacAddress */ TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) { - std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); std::array mac; @@ -84,7 +93,7 @@ TEST_P(WifiApIfaceAidlTest, GetFactoryMacAddress) { * GetBridgedInstances - non-bridged mode */ TEST_P(WifiApIfaceAidlTest, GetBridgedInstances) { - std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); std::vector instances; @@ -99,7 +108,7 @@ TEST_P(WifiApIfaceAidlTest, GetBridgedInstances_Bridged) { if (!isBridgedSupport_) { GTEST_SKIP() << "Missing Bridged AP support"; } - std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); std::vector instances; @@ -111,7 +120,7 @@ TEST_P(WifiApIfaceAidlTest, GetBridgedInstances_Bridged) { * ResetToFactoryMacAddress - non-bridged mode */ TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress) { - std::shared_ptr wifi_ap_iface = getWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk()); } @@ -123,7 +132,7 @@ TEST_P(WifiApIfaceAidlTest, ResetToFactoryMacAddress_Bridged) { if (!isBridgedSupport_) { GTEST_SKIP() << "Missing Bridged AP support"; } - std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(getInstanceName()); + std::shared_ptr wifi_ap_iface = getBridgedWifiApIface(wifi_chip_); ASSERT_NE(nullptr, wifi_ap_iface.get()); EXPECT_TRUE(wifi_ap_iface->resetToFactoryMacAddress().isOk()); } diff --git a/wifi/hostapd/aidl/Android.bp b/wifi/hostapd/aidl/Android.bp index 2e4d4d1eb2..88f4ef22f0 100644 --- a/wifi/hostapd/aidl/Android.bp +++ b/wifi/hostapd/aidl/Android.bp @@ -65,5 +65,5 @@ aidl_interface { }, ], - frozen: true, + frozen: false, } diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl index b1e7f66ed4..fa9f1982d5 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/BandMask.aidl @@ -34,8 +34,8 @@ package android.hardware.wifi.hostapd; @Backing(type="int") @VintfStability enum BandMask { - BAND_2_GHZ = 1, - BAND_5_GHZ = 2, - BAND_6_GHZ = 4, - BAND_60_GHZ = 8, + BAND_2_GHZ = (1 << 0) /* 1 */, + BAND_5_GHZ = (1 << 1) /* 2 */, + BAND_6_GHZ = (1 << 2) /* 4 */, + BAND_60_GHZ = (1 << 3) /* 8 */, } diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl index a7b20fa053..840b8755c1 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/EncryptionType.aidl @@ -34,11 +34,11 @@ package android.hardware.wifi.hostapd; @Backing(type="int") @VintfStability enum EncryptionType { - NONE = 0, - WPA = 1, - WPA2 = 2, - WPA3_SAE_TRANSITION = 3, - WPA3_SAE = 4, - WPA3_OWE_TRANSITION = 5, - WPA3_OWE = 6, + NONE, + WPA, + WPA2, + WPA3_SAE_TRANSITION, + WPA3_SAE, + WPA3_OWE_TRANSITION, + WPA3_OWE, } diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl index 5bb0d32869..a0c1886021 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/Generation.aidl @@ -34,7 +34,7 @@ package android.hardware.wifi.hostapd; @Backing(type="int") @VintfStability enum Generation { - WIFI_STANDARD_UNKNOWN = -1, + WIFI_STANDARD_UNKNOWN = (-1) /* -1 */, WIFI_STANDARD_LEGACY = 0, WIFI_STANDARD_11N = 1, WIFI_STANDARD_11AC = 2, diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl index 548e497680..7edff15c5e 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/HostapdStatusCode.aidl @@ -34,10 +34,10 @@ package android.hardware.wifi.hostapd; @Backing(type="int") @VintfStability enum HostapdStatusCode { - SUCCESS = 0, - FAILURE_UNKNOWN = 1, - FAILURE_ARGS_INVALID = 2, - FAILURE_IFACE_UNKNOWN = 3, - FAILURE_IFACE_EXISTS = 4, - FAILURE_CLIENT_UNKNOWN = 5, + SUCCESS, + FAILURE_UNKNOWN, + FAILURE_ARGS_INVALID, + FAILURE_IFACE_UNKNOWN, + FAILURE_IFACE_EXISTS, + FAILURE_CLIENT_UNKNOWN, } diff --git a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl index 64367bbe70..8da3441d9f 100644 --- a/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl +++ b/wifi/hostapd/aidl/aidl_api/android.hardware.wifi.hostapd/current/android/hardware/wifi/hostapd/IfaceParams.aidl @@ -38,4 +38,6 @@ parcelable IfaceParams { android.hardware.wifi.hostapd.HwModeParams hwModeParams; android.hardware.wifi.hostapd.ChannelParams[] channelParams; @nullable android.hardware.wifi.common.OuiKeyedData[] vendorData; + @nullable String[] instanceIdentities; + boolean isMlo; } diff --git a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl index 3f8ee39c74..bb646e308d 100644 --- a/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl +++ b/wifi/hostapd/aidl/android/hardware/wifi/hostapd/IfaceParams.aidl @@ -41,4 +41,12 @@ parcelable IfaceParams { * Optional vendor-specific configuration parameters. */ @nullable OuiKeyedData[] vendorData; + /** + * The list of the instance identities. + */ + @nullable String[] instanceIdentities; + /** + * Whether the current iface is MLO. + */ + boolean isMlo; } diff --git a/wifi/hostapd/aidl/vts/functional/Android.bp b/wifi/hostapd/aidl/vts/functional/Android.bp index f614679c44..bf1b0d0e0a 100644 --- a/wifi/hostapd/aidl/vts/functional/Android.bp +++ b/wifi/hostapd/aidl/vts/functional/Android.bp @@ -21,7 +21,7 @@ cc_test { "libvndksupport", ], static_libs: [ - "android.hardware.wifi.hostapd-V2-ndk", + "android.hardware.wifi.hostapd-V3-ndk", "VtsHalWifiV1_0TargetTestUtil", "VtsHalWifiV1_5TargetTestUtil", "VtsHalWifiV1_6TargetTestUtil", diff --git a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h index 55034d131e..4e490d98d0 100644 --- a/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h +++ b/wifi/legacy_headers/include/hardware_legacy/wifi_nan.h @@ -2972,11 +2972,17 @@ typedef struct { u16 publish_subscribe_id; /* - This Id is the Peer Instance that is passed as - part of earlier MatchInd/FollowupInd message. + Same as the bootstrapping_instance_id */ u32 service_instance_id; + /* + Unique Instance Id corresponding to a service/session. + This is similar to the publish_id generated on the + publisher side + */ + u32 bootstrapping_instance_id; + /* Discovery MAC addr of the peer/initiator */ u8 peer_disc_mac_addr[NAN_MAC_ADDR_LEN]; diff --git a/wifi/supplicant/aidl/Android.bp b/wifi/supplicant/aidl/Android.bp index b7242ed2b7..8d16cb7966 100644 --- a/wifi/supplicant/aidl/Android.bp +++ b/wifi/supplicant/aidl/Android.bp @@ -71,5 +71,5 @@ aidl_interface { }, ], - frozen: true, + frozen: false, } diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl index 330f2aa267..6bae4cf049 100644 --- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl +++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl @@ -41,4 +41,5 @@ enum WpaDriverCapabilitiesMask { TRUST_ON_FIRST_USE = (1 << 4) /* 16 */, SET_TLS_MINIMUM_VERSION = (1 << 5) /* 32 */, TLS_V1_3 = (1 << 6) /* 64 */, + RSN_OVERRIDING = (1 << 7) /* 128 */, } diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl index a9434c4f11..b6e57c66c3 100644 --- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl +++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/WpaDriverCapabilitiesMask.aidl @@ -50,4 +50,8 @@ enum WpaDriverCapabilitiesMask { * TLS V1.3 */ TLS_V1_3 = 1 << 6, + /** + * RSN Overriding + */ + RSN_OVERRIDING = 1 << 7, } diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp index 4166850e33..4ffec3f433 100644 --- a/wifi/supplicant/aidl/vts/functional/Android.bp +++ b/wifi/supplicant/aidl/vts/functional/Android.bp @@ -46,7 +46,7 @@ cc_test { "android.hardware.wifi.common-V1-ndk", "android.hardware.wifi.supplicant@1.0", "android.hardware.wifi.supplicant@1.1", - "android.hardware.wifi.supplicant-V3-ndk", + "android.hardware.wifi.supplicant-V4-ndk", "libwifi-system", "libwifi-system-iface", "VtsHalWifiV1_0TargetTestUtil", @@ -84,7 +84,7 @@ cc_test { "android.hardware.wifi.common-V1-ndk", "android.hardware.wifi.supplicant@1.0", "android.hardware.wifi.supplicant@1.1", - "android.hardware.wifi.supplicant-V3-ndk", + "android.hardware.wifi.supplicant-V4-ndk", "libwifi-system", "libwifi-system-iface", "VtsHalWifiV1_0TargetTestUtil", @@ -122,7 +122,7 @@ cc_test { "android.hardware.wifi.common-V1-ndk", "android.hardware.wifi.supplicant@1.0", "android.hardware.wifi.supplicant@1.1", - "android.hardware.wifi.supplicant-V3-ndk", + "android.hardware.wifi.supplicant-V4-ndk", "libwifi-system", "libwifi-system-iface", "VtsHalWifiV1_0TargetTestUtil",