Merge "Revert^2 "Add PER_DISPLAY_MAX_BRIGHTNESS VHAL property."" into main
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index a3f0de9..56b7926 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -51,9 +51,7 @@
DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
DRAIN_PAUSED -> IDLE [label="flush"]; // buffer is cleared
- IDLE -> ERROR [label="←IStreamCallback.onError"];
- DRAINING -> ERROR [label="←IStreamCallback.onError"];
- TRANSFERRING -> ERROR [label="←IStreamCallback.onError"];
+ ANY_STATE -> ERROR [label="←IStreamCallback.onError"];
ANY_STATE -> CLOSED [label="→IStream*.close"];
CLOSED -> F;
}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9547865..c01eb3f 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -77,7 +77,6 @@
<effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
<effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
<effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
- <effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
<effect name="reverb_env_aux" library="reverb" uuid="4a387fc0-8ab3-11df-8bad-0002a5d5c51b"/>
<effect name="reverb_env_ins" library="reverb" uuid="c7a511a0-a3bb-11df-860e-0002a5d5c51b"/>
<effect name="reverb_pre_aux" library="reverb" uuid="f29a1400-a3bb-11df-8ddc-0002a5d5c51b"/>
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index b236831..cbd42c0 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -121,6 +121,9 @@
name: "VtsHalEnvironmentalReverbTargetTest",
defaults: ["VtsHalAudioEffectTargetTestDefaults"],
srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
+ shared_libs: [
+ "libaudioutils",
+ ],
}
cc_test {
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index abc5a91..5ce2a20 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -114,7 +114,7 @@
}
static constexpr int kSamplingFrequency = 44100;
- static constexpr int kDurationMilliSec = 2000;
+ static constexpr int kDurationMilliSec = 720;
static constexpr int kInputSize = kSamplingFrequency * kDurationMilliSec / 1000;
long mInputFrameCount, mOutputFrameCount;
std::shared_ptr<IFactory> mFactory;
@@ -231,7 +231,7 @@
return gains[0] - gains[1];
}
- static constexpr int kNPointFFT = 32768;
+ static constexpr int kNPointFFT = 16384;
static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
std::set<int> mStrengthValues;
int32_t mChannelLayout;
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index 93a3dcd..c7c6505 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -16,28 +16,132 @@
#define LOG_TAG "VtsHalEnvironmentalReverbTest"
#include <android-base/logging.h>
+#include <audio_utils/power.h>
+#include <system/audio.h>
#include "EffectHelper.h"
using namespace android;
-
-using aidl::android::hardware::audio::effect::Descriptor;
-using aidl::android::hardware::audio::effect::EnvironmentalReverb;
-using aidl::android::hardware::audio::effect::getEffectTypeUuidEnvReverb;
-using aidl::android::hardware::audio::effect::IEffect;
-using aidl::android::hardware::audio::effect::IFactory;
-using aidl::android::hardware::audio::effect::Parameter;
+using namespace aidl::android::hardware::audio::effect;
+using aidl::android::hardware::audio::common::getChannelCount;
using android::hardware::audio::common::testing::detail::TestExecutionTracer;
+using TagVectorPair = std::pair<EnvironmentalReverb::Tag, std::vector<int>>;
+using TagValuePair = std::pair<EnvironmentalReverb::Tag, int>;
+static constexpr int kMaxRoomLevel = 0;
+static constexpr int kMinRoomLevel = -6000;
+static constexpr int kMinRoomHfLevel = -4000;
+static constexpr int kMinDecayTime = 0;
+static constexpr int kMinHfRatio = 100;
+static constexpr int kMinLevel = -6000;
+static constexpr int kMinDensity = 0;
+static constexpr int kMinDiffusion = 0;
+static constexpr int kMinDelay = 0;
+
+static const std::vector<TagVectorPair> kParamsIncreasingVector = {
+
+ {EnvironmentalReverb::roomLevelMb, {-3500, -2800, -2100, -1400, -700, 0}},
+ {EnvironmentalReverb::roomHfLevelMb, {-4000, -3200, -2400, -1600, -800, 0}},
+ {EnvironmentalReverb::decayTimeMs, {800, 1600, 2400, 3200, 4000}},
+ {EnvironmentalReverb::decayHfRatioPm, {100, 600, 1100, 1600, 2000}},
+ {EnvironmentalReverb::levelMb, {-3500, -2800, -2100, -1400, -700, 0}},
+};
+
+static const std::vector<TagValuePair> kParamsMinimumValue = {
+ {EnvironmentalReverb::roomLevelMb, kMinRoomLevel},
+ {EnvironmentalReverb::decayTimeMs, kMinDecayTime},
+ {EnvironmentalReverb::levelMb, kMinLevel}};
+
+std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
+
+using Maker = std::set<int> (*)();
+static const std::array<Maker, static_cast<int>(EnvironmentalReverb::bypass) + 1>
+ kTestValueSetMaker = {
+ nullptr,
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::roomLevelMb>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::roomHfLevelMb>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::decayTimeMs>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::decayHfRatioPm>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ nullptr,
+ nullptr,
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::levelMb>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::delayMs>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::diffusionPm>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::densityPm>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+ []() -> std::set<int> {
+ return EffectHelper::getTestValueSet<EnvironmentalReverb, int,
+ Range::environmentalReverb,
+ EnvironmentalReverb::bypass>(
+ kDescPair, EffectHelper::expandTestValueBasic<int>);
+ },
+};
+
+static std::vector<TagValuePair> buildSetAndGetTestParams() {
+ std::vector<TagValuePair> valueTag;
+ for (EnvironmentalReverb::Tag tag : ndk::enum_range<EnvironmentalReverb::Tag>()) {
+ std::set<int> values;
+ int intTag = static_cast<int>(tag);
+ if (intTag <= static_cast<int>(EnvironmentalReverb::bypass) &&
+ kTestValueSetMaker[intTag] != nullptr) {
+ values = kTestValueSetMaker[intTag]();
+ }
+
+ for (const auto& value : values) {
+ valueTag.push_back(std::make_pair(tag, value));
+ }
+ }
+
+ return valueTag;
+}
/**
- * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
- * VtsAudioEffectTargetTest.
- * Testing parameter range, assuming the parameter supported by effect is in this range.
- * This range is verified with IEffect.getDescriptor() and range defined in the documentation, for
- * any index supported value test expects EX_NONE from IEffect.setParameter(), otherwise expects
- * EX_ILLEGAL_ARGUMENT.
+ * Tests do the following:
+ * - Testing parameter range supported by the effect. Range is verified with IEffect.getDescriptor()
+ * and range defined in the documentation.
+ * - Validating the effect by comparing the outputs of the supported parameters.
*/
+enum ParamName { DESCRIPTOR_INDEX, TAG_VALUE_PAIR };
+
class EnvironmentalReverbHelper : public EffectHelper {
public:
EnvironmentalReverbHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair) {
@@ -51,8 +155,7 @@
Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
- kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
- IEffect::OpenEffectReturn ret;
+ mFrameCount /* iFrameCount */, mFrameCount /* oFrameCount */);
ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
ASSERT_NE(nullptr, mEffect);
}
@@ -63,475 +166,291 @@
}
Parameter::Specific getDefaultParamSpecific() {
- EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(-6000);
+ EnvironmentalReverb er =
+ EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(kMaxRoomLevel);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
return specific;
}
- static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
- std::shared_ptr<IFactory> mFactory;
- std::shared_ptr<IEffect> mEffect;
- Descriptor mDescriptor;
- int mRoomLevel = -6000;
- int mRoomHfLevel = 0;
- int mDecayTime = 1000;
- int mDecayHfRatio = 500;
- int mLevel = -6000;
- int mDelay = 40;
- int mDiffusion = 1000;
- int mDensity = 1000;
- bool mBypass = false;
+ bool isParamValid(EnvironmentalReverb env) {
+ return isParameterValid<EnvironmentalReverb, Range::environmentalReverb>(env, mDescriptor);
+ }
- void SetAndGetReverbParameters() {
- for (auto& it : mTags) {
- auto& tag = it.first;
- auto& er = it.second;
+ Parameter createParam(EnvironmentalReverb env) {
+ return Parameter::make<Parameter::specific>(
+ Parameter::Specific::make<Parameter::Specific::environmentalReverb>(env));
+ }
- // validate parameter
- Descriptor desc;
- ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
- const bool valid = isParameterValid<EnvironmentalReverb, Range::environmentalReverb>(
- it.second, desc);
- const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+ void setAndVerifyParam(binder_exception_t expected, EnvironmentalReverb env,
+ EnvironmentalReverb::Tag tag) {
+ auto expectedParam = createParam(env);
- // set
- Parameter expectParam;
- Parameter::Specific specific;
- specific.set<Parameter::Specific::environmentalReverb>(er);
- expectParam.set<Parameter::specific>(specific);
- EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+ EXPECT_STATUS(expected, mEffect->setParameter(expectedParam)) << expectedParam.toString();
- // only get if parameter in range and set success
- if (expected == EX_NONE) {
- Parameter getParam;
- Parameter::Id id;
- EnvironmentalReverb::Id erId;
- erId.set<EnvironmentalReverb::Id::commonTag>(tag);
- id.set<Parameter::Id::environmentalReverbTag>(erId);
- // if set success, then get should match
- EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
- EXPECT_EQ(expectParam, getParam);
- }
+ if (expected == EX_NONE) {
+ auto erId = EnvironmentalReverb::Id::make<EnvironmentalReverb::Id::commonTag>(
+ EnvironmentalReverb::Tag(tag));
+
+ auto id = Parameter::Id::make<Parameter::Id::environmentalReverbTag>(erId);
+
+ // get parameter
+ Parameter getParam;
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+ EXPECT_EQ(expectedParam, getParam) << "\nexpectedParam:" << expectedParam.toString()
+ << "\ngetParam:" << getParam.toString();
}
}
- void addRoomLevelParam() {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::roomLevelMb>(mRoomLevel);
- mTags.push_back({EnvironmentalReverb::roomLevelMb, er});
+ bool isAuxiliary() {
+ return mDescriptor.common.flags.type ==
+ aidl::android::hardware::audio::effect::Flags::Type::AUXILIARY;
}
- void addRoomHfLevelParam(int roomHfLevel) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::roomHfLevelMb>(roomHfLevel);
- mTags.push_back({EnvironmentalReverb::roomHfLevelMb, er});
+ float computeOutputEnergy(const std::vector<float>& input, std::vector<float> output) {
+ if (!isAuxiliary()) {
+ // Extract auxiliary output
+ for (size_t i = 0; i < output.size(); i++) {
+ output[i] -= input[i];
+ }
+ }
+ return audio_utils_compute_energy_mono(output.data(), AUDIO_FORMAT_PCM_FLOAT,
+ output.size());
}
- void addDecayTimeParam(int decayTime) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::decayTimeMs>(decayTime);
- mTags.push_back({EnvironmentalReverb::decayTimeMs, er});
+ void generateSineWaveInput(std::vector<float>& input) {
+ int frequency = 1000;
+ size_t kSamplingFrequency = 44100;
+ for (size_t i = 0; i < input.size(); i++) {
+ input[i] = sin(2 * M_PI * frequency * i / kSamplingFrequency);
+ }
+ }
+ using Maker = EnvironmentalReverb (*)(int);
+
+ static constexpr std::array<Maker, static_cast<int>(EnvironmentalReverb::bypass) + 1>
+ kEnvironmentalReverbParamMaker = {
+ nullptr,
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::roomHfLevelMb>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::decayTimeMs>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::decayHfRatioPm>(
+ value);
+ },
+ nullptr,
+ nullptr,
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::levelMb>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::delayMs>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::diffusionPm>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::densityPm>(value);
+ },
+ [](int value) -> EnvironmentalReverb {
+ return EnvironmentalReverb::make<EnvironmentalReverb::bypass>(value);
+ }};
+
+ void createEnvParam(EnvironmentalReverb::Tag tag, int paramValue) {
+ int intTag = static_cast<int>(tag);
+ if (intTag <= static_cast<int>(EnvironmentalReverb::bypass) &&
+ kEnvironmentalReverbParamMaker[intTag] != NULL) {
+ mEnvParam = kEnvironmentalReverbParamMaker[intTag](paramValue);
+ } else {
+ GTEST_SKIP() << "Invalid parameter, skipping the test\n";
+ }
}
- void addDecayHfRatioParam(int decayHfRatio) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::decayHfRatioPm>(decayHfRatio);
- mTags.push_back({EnvironmentalReverb::decayHfRatioPm, er});
+ void setParameterAndProcess(std::vector<float>& input, std::vector<float>& output, int val,
+ EnvironmentalReverb::Tag tag) {
+ createEnvParam(tag, val);
+ if (isParamValid(mEnvParam)) {
+ ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, tag));
+ ASSERT_NO_FATAL_FAILURE(processAndWriteToOutput(input, output, mEffect, &ret));
+ }
}
- void addLevelParam(int level) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::levelMb>(level);
- mTags.push_back({EnvironmentalReverb::levelMb, er});
- }
+ static constexpr int kSamplingFrequency = 44100;
+ static constexpr int kDurationMilliSec = 500;
+ static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
- void addDelayParam(int delay) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::delayMs>(delay);
- mTags.push_back({EnvironmentalReverb::delayMs, er});
- }
+ int mStereoChannelCount =
+ getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO));
+ int mFrameCount = kBufferSize / mStereoChannelCount;
- void addDiffusionParam(int diffusion) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::diffusionPm>(diffusion);
- mTags.push_back({EnvironmentalReverb::diffusionPm, er});
- }
-
- void addDensityParam(int density) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::densityPm>(density);
- mTags.push_back({EnvironmentalReverb::densityPm, er});
- }
-
- void addBypassParam(bool bypass) {
- EnvironmentalReverb er;
- er.set<EnvironmentalReverb::bypass>(bypass);
- mTags.push_back({EnvironmentalReverb::bypass, er});
- }
-
- private:
- std::vector<std::pair<EnvironmentalReverb::Tag, EnvironmentalReverb>> mTags;
- void CleanUp() { mTags.clear(); }
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ IEffect::OpenEffectReturn ret;
+ Descriptor mDescriptor;
+ EnvironmentalReverb mEnvParam;
};
-class EnvironmentalReverbRoomLevelTest
+class EnvironmentalReverbParamTest
: public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagValuePair>>,
public EnvironmentalReverbHelper {
public:
- EnvironmentalReverbRoomLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mRoomLevel = std::get<1>(GetParam());
+ EnvironmentalReverbParamTest()
+ : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+ std::tie(mTag, mParamValue) = std::get<TAG_VALUE_PAIR>(GetParam());
}
-
void SetUp() override { SetUpReverb(); }
-
void TearDown() override { TearDownReverb(); }
+
+ EnvironmentalReverb::Tag mTag;
+ int mParamValue;
};
-TEST_P(EnvironmentalReverbRoomLevelTest, SetAndGetRoomLevel) {
- EXPECT_NO_FATAL_FAILURE(addRoomLevelParam());
- SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbParamTest, SetAndGetParameter) {
+ createEnvParam(mTag, mParamValue);
+ ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(
+ isParamValid(mEnvParam) ? EX_NONE : EX_ILLEGAL_ARGUMENT, mEnvParam, mTag));
}
-std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kDescPair;
-
INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
+ EnvironmentalReverbTest, EnvironmentalReverbParamTest,
::testing::Combine(
testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<EnvironmentalReverb, int,
- Range::environmentalReverb,
- EnvironmentalReverb::roomLevelMb>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbRoomLevelTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string roomLevel = std::to_string(std::get<1>(info.param));
-
- std::string name = getPrefix(descriptor) + "_roomLevel" + roomLevel;
+ testing::ValuesIn(buildSetAndGetTestParams())),
+ [](const testing::TestParamInfo<EnvironmentalReverbParamTest::ParamType>& info) {
+ auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+ auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+ auto val = std::get<TAG_VALUE_PAIR>(info.param).second;
+ std::string name =
+ getPrefix(descriptor) + "_Tag_" + toString(tag) + std::to_string(val);
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomLevelTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbParamTest);
-class EnvironmentalReverbRoomHfLevelTest
+class EnvironmentalReverbDataTest
: public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagVectorPair>>,
public EnvironmentalReverbHelper {
public:
- EnvironmentalReverbRoomHfLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mRoomHfLevel = std::get<1>(GetParam());
+ EnvironmentalReverbDataTest()
+ : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+ std::tie(mTag, mParamValues) = std::get<TAG_VALUE_PAIR>(GetParam());
+ mInput.resize(kBufferSize);
+ generateSineWaveInput(mInput);
+ }
+ void SetUp() override { SetUpReverb(); }
+ void TearDown() override { TearDownReverb(); }
+
+ void assertEnergyIncreasingWithParameter(bool bypass) {
+ createEnvParam(EnvironmentalReverb::bypass, bypass);
+ ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::bypass));
+ float baseEnergy = 0;
+ for (int val : mParamValues) {
+ std::vector<float> output(kBufferSize);
+ setParameterAndProcess(mInput, output, val, mTag);
+ float energy = computeOutputEnergy(mInput, output);
+ ASSERT_GT(energy, baseEnergy);
+ baseEnergy = energy;
+ }
}
- void SetUp() override { SetUpReverb(); }
+ void assertZeroEnergyWithBypass(bool bypass) {
+ createEnvParam(EnvironmentalReverb::bypass, bypass);
+ ASSERT_NO_FATAL_FAILURE(setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::bypass));
+ for (int val : mParamValues) {
+ std::vector<float> output(kBufferSize);
+ setParameterAndProcess(mInput, output, val, mTag);
+ float energy = computeOutputEnergy(mInput, output);
+ ASSERT_EQ(energy, 0);
+ }
+ }
- void TearDown() override { TearDownReverb(); }
+ EnvironmentalReverb::Tag mTag;
+ std::vector<int> mParamValues;
+ std::vector<float> mInput;
};
-TEST_P(EnvironmentalReverbRoomHfLevelTest, SetAndGetRoomHfLevel) {
- EXPECT_NO_FATAL_FAILURE(addRoomHfLevelParam(mRoomHfLevel));
- SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbDataTest, IncreasingParamValue) {
+ assertEnergyIncreasingWithParameter(false);
+}
+
+TEST_P(EnvironmentalReverbDataTest, WithBypassEnabled) {
+ assertZeroEnergyWithBypass(true);
}
INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::roomHfLevelMb>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbRoomHfLevelTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string roomHfLevel = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_roomHfLevel" + roomHfLevel;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ EnvironmentalReverbTest, EnvironmentalReverbDataTest,
+ ::testing::Combine(
+ testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+ testing::ValuesIn(kParamsIncreasingVector)),
+ [](const testing::TestParamInfo<EnvironmentalReverbDataTest::ParamType>& info) {
+ auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+ auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+ std::string name = getPrefix(descriptor) + "_Tag_" + toString(tag);
return name;
});
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomHfLevelTest);
-class EnvironmentalReverbDecayTimeTest
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDataTest);
+
+class EnvironmentalReverbMinimumParamTest
: public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, TagValuePair>>,
public EnvironmentalReverbHelper {
public:
- EnvironmentalReverbDecayTimeTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mDecayTime = std::get<1>(GetParam());
+ EnvironmentalReverbMinimumParamTest()
+ : EnvironmentalReverbHelper(std::get<DESCRIPTOR_INDEX>(GetParam())) {
+ std::tie(mTag, mValue) = std::get<TAG_VALUE_PAIR>(GetParam());
}
-
- void SetUp() override { SetUpReverb(); }
-
+ void SetUp() override {
+ SetUpReverb();
+ createEnvParam(EnvironmentalReverb::roomLevelMb, kMinRoomLevel);
+ ASSERT_NO_FATAL_FAILURE(
+ setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::roomLevelMb));
+ }
void TearDown() override { TearDownReverb(); }
+
+ EnvironmentalReverb::Tag mTag;
+ int mValue;
};
-TEST_P(EnvironmentalReverbDecayTimeTest, SetAndGetDecayTime) {
- EXPECT_NO_FATAL_FAILURE(addDecayTimeParam(mDecayTime));
- SetAndGetReverbParameters();
+TEST_P(EnvironmentalReverbMinimumParamTest, MinimumValueTest) {
+ std::vector<float> input(kBufferSize);
+ generateSineWaveInput(input);
+ std::vector<float> output(kBufferSize);
+ setParameterAndProcess(input, output, mValue, mTag);
+ float energy = computeOutputEnergy(input, output);
+ // No Auxiliary output for minimum param values
+ ASSERT_EQ(energy, 0);
}
INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::decayTimeMs>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDecayTimeTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string decayTime = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_decayTime" + decayTime;
+ EnvironmentalReverbTest, EnvironmentalReverbMinimumParamTest,
+ ::testing::Combine(
+ testing::ValuesIn(kDescPair = EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, getEffectTypeUuidEnvReverb())),
+ testing::ValuesIn(kParamsMinimumValue)),
+ [](const testing::TestParamInfo<EnvironmentalReverbMinimumParamTest::ParamType>& info) {
+ auto descriptor = std::get<DESCRIPTOR_INDEX>(info.param).second;
+ auto tag = std::get<TAG_VALUE_PAIR>(info.param).first;
+ auto val = std::get<TAG_VALUE_PAIR>(info.param).second;
+ std::string name =
+ getPrefix(descriptor) + "_Tag_" + toString(tag) + std::to_string(val);
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayTimeTest);
-class EnvironmentalReverbDecayHfRatioTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbDecayHfRatioTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mDecayHfRatio = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDecayHfRatioTest, SetAndGetDecayHfRatio) {
- EXPECT_NO_FATAL_FAILURE(addDecayHfRatioParam(mDecayHfRatio));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::decayHfRatioPm>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string decayHfRatio = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_decayHfRatio" + decayHfRatio;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayHfRatioTest);
-
-class EnvironmentalReverbLevelTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mLevel = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbLevelTest, SetAndGetLevel) {
- EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::levelMb>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string level = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_level" + level;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbLevelTest);
-
-class EnvironmentalReverbDelayTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbDelayTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mDelay = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDelayTest, SetAndGetDelay) {
- EXPECT_NO_FATAL_FAILURE(addDelayParam(mDelay));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::delayMs>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDelayTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string delay = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_delay" + delay;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDelayTest);
-
-class EnvironmentalReverbDiffusionTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbDiffusionTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mDiffusion = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDiffusionTest, SetAndGetDiffusion) {
- EXPECT_NO_FATAL_FAILURE(addDiffusionParam(mDiffusion));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::diffusionPm>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string diffusion = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_diffusion" + diffusion;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
-
-class EnvironmentalReverbDensityTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mDensity = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbDensityTest, SetAndGetDensity) {
- EXPECT_NO_FATAL_FAILURE(addDensityParam(mDensity));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::ValuesIn(EffectHelper::getTestValueSet<
- EnvironmentalReverb, int, Range::environmentalReverb,
- EnvironmentalReverb::densityPm>(
- kDescPair, EffectHelper::expandTestValueBasic<int>))),
- [](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string density = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_density" + density;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
-
-class EnvironmentalReverbBypassTest
- : public ::testing::TestWithParam<
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>>,
- public EnvironmentalReverbHelper {
- public:
- EnvironmentalReverbBypassTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
- mBypass = std::get<1>(GetParam());
- }
-
- void SetUp() override { SetUpReverb(); }
-
- void TearDown() override { TearDownReverb(); }
-};
-
-TEST_P(EnvironmentalReverbBypassTest, SetAndGetBypass) {
- EXPECT_NO_FATAL_FAILURE(addBypassParam(mBypass));
- SetAndGetReverbParameters();
-}
-
-INSTANTIATE_TEST_SUITE_P(
- EnvironmentalReverbTest, EnvironmentalReverbBypassTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, getEffectTypeUuidEnvReverb())),
- testing::Bool()),
- [](const testing::TestParamInfo<EnvironmentalReverbBypassTest::ParamType>& info) {
- auto descriptor = std::get<0>(info.param).second;
- std::string bypass = std::to_string(std::get<1>(info.param));
-
- std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
- descriptor.common.name + "_UUID_" +
- toString(descriptor.common.id.uuid) + "_bypass" + bypass;
- std::replace_if(
- name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbBypassTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbMinimumParamTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
index 2229ff8..542f0d8 100644
--- a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -82,7 +82,7 @@
}
static constexpr int kSamplingFrequency = 44100;
- static constexpr int kDurationMilliSec = 2000;
+ static constexpr int kDurationMilliSec = 500;
static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
int mStereoChannelCount =
getChannelCount(AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
diff --git a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index f121f7c..b449f3c 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -96,7 +96,7 @@
static constexpr int kSamplingFrequency = 44100;
static constexpr int kDefaultChannelLayout = AudioChannelLayout::LAYOUT_STEREO;
- static constexpr int kDurationMilliSec = 2000;
+ static constexpr int kDurationMilliSec = 720;
static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
int kChannelCount = getChannelCount(
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(kDefaultChannelLayout));
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
index 4115eca..2c21d2e 100644
--- a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -94,7 +94,7 @@
}
static constexpr int kSamplingFrequency = 44100;
- static constexpr int kDurationMilliSec = 2000;
+ static constexpr int kDurationMilliSec = 720;
static constexpr int kBufferSize = kSamplingFrequency * kDurationMilliSec / 1000;
static constexpr int kMinLevel = -96;
static constexpr int kDefaultChannelLayout = AudioChannelLayout::LAYOUT_STEREO;
@@ -180,7 +180,7 @@
const int kVsrApiLevel;
static constexpr int kMaxAudioSample = 1;
static constexpr int kTransitionDuration = 300;
- static constexpr int kNPointFFT = 32768;
+ static constexpr int kNPointFFT = 16384;
static constexpr float kBinWidth = (float)kSamplingFrequency / kNPointFFT;
static constexpr size_t offset = kSamplingFrequency * kTransitionDuration / 1000;
static constexpr float kBaseLevel = 0;
diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp
index 05691d9..0a68fbc 100644
--- a/automotive/can/1.0/default/Android.bp
+++ b/automotive/can/1.0/default/Android.bp
@@ -55,7 +55,6 @@
],
static_libs: [
"android.hardware.automotive.can@libnetdevice",
- "android.hardware.automotive@libc++fs",
"libnl++",
],
vintf_fragments: ["manifest_android.hardware.automotive.can@1.0.xml"],
diff --git a/automotive/can/1.0/default/CanBus.h b/automotive/can/1.0/default/CanBus.h
index 8b73258..977bfcc 100644
--- a/automotive/can/1.0/default/CanBus.h
+++ b/automotive/can/1.0/default/CanBus.h
@@ -24,6 +24,7 @@
#include <utils/Mutex.h>
#include <atomic>
+#include <mutex>
#include <thread>
namespace android::hardware::automotive::can::V1_0::implementation {
diff --git a/automotive/can/1.0/default/CanController.cpp b/automotive/can/1.0/default/CanController.cpp
index 1b5bf5b..4a7ab7e 100644
--- a/automotive/can/1.0/default/CanController.cpp
+++ b/automotive/can/1.0/default/CanController.cpp
@@ -23,7 +23,7 @@
#include <android-base/logging.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <automotive/filesystem>
+#include <filesystem>
#include <fstream>
#include <regex>
@@ -31,7 +31,7 @@
using IfId = ICanController::BusConfig::InterfaceId;
using IfIdDisc = ICanController::BusConfig::InterfaceId::hidl_discriminator;
-namespace fs = android::hardware::automotive::filesystem;
+namespace fs = ::std::filesystem;
namespace fsErrors {
static const std::error_code ok;
diff --git a/automotive/can/1.0/default/libc++fs/.clang-format b/automotive/can/1.0/default/libc++fs/.clang-format
deleted file mode 100644
index dd59681..0000000
--- a/automotive/can/1.0/default/libc++fs/.clang-format
+++ /dev/null
@@ -1,13 +0,0 @@
-BasedOnStyle: LLVM
-
----
-Language: Cpp
-Standard: Cpp03
-
-AlwaysBreakTemplateDeclarations: true
-PointerAlignment: Left
-
-# Disable formatting options which may break tests.
-SortIncludes: false
-ReflowComments: false
----
diff --git a/automotive/can/1.0/default/libc++fs/Android.bp b/automotive/can/1.0/default/libc++fs/Android.bp
deleted file mode 100644
index 0641991..0000000
--- a/automotive/can/1.0/default/libc++fs/Android.bp
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright (C) 2020 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.
-//
-
-// TODO(152067309): Stop building this yourself once it's ABI stable and has
-// been made vendor available. Just use libc++fs instead of this.
-
-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-NCSA
- default_applicable_licenses: ["hardware_interfaces_license"],
-}
-
-cc_defaults {
- name: "android.hardware.automotive@libc++fsdefaults",
- local_include_dirs: ["include"],
- export_include_dirs: ["include"],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- ],
- cppflags: [
- "-std=c++17",
- "-fexceptions",
- "-DLIBCXX_BUILDING_LIBCXXABI",
- "-D_LIBCPP_BUILDING_LIBRARY",
- ],
- rtti: true,
-}
-
-cc_library_static {
- name: "android.hardware.automotive@libc++fs",
- recovery_available: true,
- vendor: true,
- defaults: ["android.hardware.automotive@libc++fsdefaults"],
- srcs: [
- "src/filesystem/directory_iterator.cpp",
- "src/filesystem/operations.cpp",
- ],
- multilib: {
- lib32: {
- // off_t usage is constrained to within the libc++ source (not the
- // headers), so we can build the filesystem library with a 64-bit
- // off_t on LP32 to get large file support without needing all users
- // of the library to match.
- cflags: ["-D_FILE_OFFSET_BITS=64"],
- },
- },
- target: {
- windows: {
- enabled: false,
- },
- },
-}
diff --git a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem b/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
deleted file mode 100644
index bd3dda5..0000000
--- a/automotive/can/1.0/default/libc++fs/include/automotive/filesystem
+++ /dev/null
@@ -1,2713 +0,0 @@
-// -*- C++ -*-
-//===--------------------------- filesystem -------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-#ifndef _LIBAUTO_FILESYSTEM
-#define _LIBAUTO_FILESYSTEM
-
-// TODO(152067309): Remove this once the libc++ upgrade is complete.
-#include <__config>
-#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
-
-#include <filesystem>
-namespace android::hardware::automotive {
-namespace filesystem = std::filesystem;
-}
-
-#else
-
-/*
- filesystem synopsis
-
- namespace android::hardware::automotive { namespace filesystem {
-
- class path;
-
- void swap(path& lhs, path& rhs) noexcept;
- size_t hash_value(const path& p) noexcept;
-
- bool operator==(const path& lhs, const path& rhs) noexcept;
- bool operator!=(const path& lhs, const path& rhs) noexcept;
- bool operator< (const path& lhs, const path& rhs) noexcept;
- bool operator<=(const path& lhs, const path& rhs) noexcept;
- bool operator> (const path& lhs, const path& rhs) noexcept;
- bool operator>=(const path& lhs, const path& rhs) noexcept;
-
- path operator/ (const path& lhs, const path& rhs);
-
- // fs.path.io operators are friends of path.
- template <class charT, class traits>
- friend basic_ostream<charT, traits>&
- operator<<(basic_ostream<charT, traits>& os, const path& p);
-
- template <class charT, class traits>
- friend basic_istream<charT, traits>&
- operator>>(basic_istream<charT, traits>& is, path& p);
-
- template <class Source>
- path u8path(const Source& source);
- template <class InputIterator>
- path u8path(InputIterator first, InputIterator last);
-
- class filesystem_error;
- class directory_entry;
-
- class directory_iterator;
-
- // enable directory_iterator range-based for statements
- directory_iterator begin(directory_iterator iter) noexcept;
- directory_iterator end(const directory_iterator&) noexcept;
-
- class recursive_directory_iterator;
-
- // enable recursive_directory_iterator range-based for statements
- recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept;
- recursive_directory_iterator end(const recursive_directory_iterator&) noexcept;
-
- class file_status;
-
- struct space_info
- {
- uintmax_t capacity;
- uintmax_t free;
- uintmax_t available;
- };
-
- enum class file_type;
- enum class perms;
- enum class perm_options;
- enum class copy_options;
- enum class directory_options;
-
- typedef chrono::time_point<trivial-clock> file_time_type;
-
- // operational functions
-
- path absolute(const path& p);
- path absolute(const path& p, error_code &ec);
-
- path canonical(const path& p);
- path canonical(const path& p, error_code& ec);
-
- void copy(const path& from, const path& to);
- void copy(const path& from, const path& to, error_code& ec);
- void copy(const path& from, const path& to, copy_options options);
- void copy(const path& from, const path& to, copy_options options,
- error_code& ec);
-
- bool copy_file(const path& from, const path& to);
- bool copy_file(const path& from, const path& to, error_code& ec);
- bool copy_file(const path& from, const path& to, copy_options option);
- bool copy_file(const path& from, const path& to, copy_options option,
- error_code& ec);
-
- void copy_symlink(const path& existing_symlink, const path& new_symlink);
- void copy_symlink(const path& existing_symlink, const path& new_symlink,
- error_code& ec) noexcept;
-
- bool create_directories(const path& p);
- bool create_directories(const path& p, error_code& ec);
-
- bool create_directory(const path& p);
- bool create_directory(const path& p, error_code& ec) noexcept;
-
- bool create_directory(const path& p, const path& attributes);
- bool create_directory(const path& p, const path& attributes,
- error_code& ec) noexcept;
-
- void create_directory_symlink(const path& to, const path& new_symlink);
- void create_directory_symlink(const path& to, const path& new_symlink,
- error_code& ec) noexcept;
-
- void create_hard_link(const path& to, const path& new_hard_link);
- void create_hard_link(const path& to, const path& new_hard_link,
- error_code& ec) noexcept;
-
- void create_symlink(const path& to, const path& new_symlink);
- void create_symlink(const path& to, const path& new_symlink,
- error_code& ec) noexcept;
-
- path current_path();
- path current_path(error_code& ec);
- void current_path(const path& p);
- void current_path(const path& p, error_code& ec) noexcept;
-
- bool exists(file_status s) noexcept;
- bool exists(const path& p);
- bool exists(const path& p, error_code& ec) noexcept;
-
- bool equivalent(const path& p1, const path& p2);
- bool equivalent(const path& p1, const path& p2, error_code& ec) noexcept;
-
- uintmax_t file_size(const path& p);
- uintmax_t file_size(const path& p, error_code& ec) noexcept;
-
- uintmax_t hard_link_count(const path& p);
- uintmax_t hard_link_count(const path& p, error_code& ec) noexcept;
-
- bool is_block_file(file_status s) noexcept;
- bool is_block_file(const path& p);
- bool is_block_file(const path& p, error_code& ec) noexcept;
-
- bool is_character_file(file_status s) noexcept;
- bool is_character_file(const path& p);
- bool is_character_file(const path& p, error_code& ec) noexcept;
-
- bool is_directory(file_status s) noexcept;
- bool is_directory(const path& p);
- bool is_directory(const path& p, error_code& ec) noexcept;
-
- bool is_empty(const path& p);
- bool is_empty(const path& p, error_code& ec) noexcept;
-
- bool is_fifo(file_status s) noexcept;
- bool is_fifo(const path& p);
- bool is_fifo(const path& p, error_code& ec) noexcept;
-
- bool is_other(file_status s) noexcept;
- bool is_other(const path& p);
- bool is_other(const path& p, error_code& ec) noexcept;
-
- bool is_regular_file(file_status s) noexcept;
- bool is_regular_file(const path& p);
- bool is_regular_file(const path& p, error_code& ec) noexcept;
-
- bool is_socket(file_status s) noexcept;
- bool is_socket(const path& p);
- bool is_socket(const path& p, error_code& ec) noexcept;
-
- bool is_symlink(file_status s) noexcept;
- bool is_symlink(const path& p);
- bool is_symlink(const path& p, error_code& ec) noexcept;
-
- file_time_type last_write_time(const path& p);
- file_time_type last_write_time(const path& p, error_code& ec) noexcept;
- void last_write_time(const path& p, file_time_type new_time);
- void last_write_time(const path& p, file_time_type new_time,
- error_code& ec) noexcept;
-
- void permissions(const path& p, perms prms,
- perm_options opts=perm_options::replace);
- void permissions(const path& p, perms prms, error_code& ec) noexcept;
- void permissions(const path& p, perms prms, perm_options opts,
- error_code& ec);
-
- path proximate(const path& p, error_code& ec);
- path proximate(const path& p, const path& base = current_path());
- path proximate(const path& p, const path& base, error_code &ec);
-
- path read_symlink(const path& p);
- path read_symlink(const path& p, error_code& ec);
-
- path relative(const path& p, error_code& ec);
- path relative(const path& p, const path& base=current_path());
- path relative(const path& p, const path& base, error_code& ec);
-
- bool remove(const path& p);
- bool remove(const path& p, error_code& ec) noexcept;
-
- uintmax_t remove_all(const path& p);
- uintmax_t remove_all(const path& p, error_code& ec);
-
- void rename(const path& from, const path& to);
- void rename(const path& from, const path& to, error_code& ec) noexcept;
-
- void resize_file(const path& p, uintmax_t size);
- void resize_file(const path& p, uintmax_t size, error_code& ec) noexcept;
-
- space_info space(const path& p);
- space_info space(const path& p, error_code& ec) noexcept;
-
- file_status status(const path& p);
- file_status status(const path& p, error_code& ec) noexcept;
-
- bool status_known(file_status s) noexcept;
-
- file_status symlink_status(const path& p);
- file_status symlink_status(const path& p, error_code& ec) noexcept;
-
- path temp_directory_path();
- path temp_directory_path(error_code& ec);
-
- path weakly_canonical(path const& p);
- path weakly_canonical(path const& p, error_code& ec);
-
-
-} } // namespace android::hardware::automotive::filesystem
-
-*/
-
-#include <__config>
-#include <cstddef>
-#include <cstdlib>
-#include <chrono>
-#include <iterator>
-#include <iosfwd>
-#include <locale>
-#include <memory>
-#include <stack>
-#include <string>
-#include <system_error>
-#include <utility>
-#include <iomanip> // for quoted
-#include <string_view>
-#include <version>
-
-#include <__debug>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#pragma GCC system_header
-#endif
-
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
-#ifndef _LIBCPP_CXX03_LANG
-
-namespace android::hardware::automotive::filesystem {
-using namespace std;
-using namespace std::chrono;
-
-using std::basic_string;
-using std::enable_if;
-using std::error_code;
-using std::false_type;
-
-#ifndef _VSTD
-#define _LIBAUTO_UNDEF_VSTD
-#define _VSTD std
-#endif
-
-#ifdef _VSTD_FS
-#pragma push_macro("_VSTD_FS")
-#else
-#define _LIBAUTO_UNDEF_VSTD_FS
-#endif
-#define _VSTD_FS android::hardware::automotive::filesystem
-
-/* Begin copy of _FilesystemClock from include/chrono */
-struct _FilesystemClock {
-#if !defined(_LIBCPP_HAS_NO_INT128)
- typedef __int128_t rep;
- typedef nano period;
-#else
- typedef long long rep;
- typedef nano period;
-#endif
-
- typedef chrono::duration<rep, period> duration;
- typedef chrono::time_point<_FilesystemClock> time_point;
-
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 const bool is_steady = false;
-
- _LIBCPP_FUNC_VIS static time_point now() noexcept;
-
- _LIBCPP_INLINE_VISIBILITY
- static time_t to_time_t(const time_point& __t) noexcept {
- typedef chrono::duration<rep> __secs;
- return time_t(
- chrono::duration_cast<__secs>(__t.time_since_epoch()).count());
- }
-
- _LIBCPP_INLINE_VISIBILITY
- static time_point from_time_t(time_t __t) noexcept {
- typedef chrono::duration<rep> __secs;
- return time_point(__secs(__t));
- }
-};
-/* End copy of _FilesystemClock from include/chrono */
-
-typedef chrono::time_point<_FilesystemClock> file_time_type;
-
-struct _LIBCPP_TYPE_VIS space_info {
- uintmax_t capacity;
- uintmax_t free;
- uintmax_t available;
-};
-
-enum class _LIBCPP_ENUM_VIS file_type : signed char {
- none = 0,
- not_found = -1,
- regular = 1,
- directory = 2,
- symlink = 3,
- block = 4,
- character = 5,
- fifo = 6,
- socket = 7,
- unknown = 8
-};
-
-enum class _LIBCPP_ENUM_VIS perms : unsigned {
- none = 0,
-
- owner_read = 0400,
- owner_write = 0200,
- owner_exec = 0100,
- owner_all = 0700,
-
- group_read = 040,
- group_write = 020,
- group_exec = 010,
- group_all = 070,
-
- others_read = 04,
- others_write = 02,
- others_exec = 01,
- others_all = 07,
-
- all = 0777,
-
- set_uid = 04000,
- set_gid = 02000,
- sticky_bit = 01000,
- mask = 07777,
- unknown = 0xFFFF,
-};
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perms operator&(perms _LHS, perms _RHS) {
- return static_cast<perms>(static_cast<unsigned>(_LHS) &
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perms operator|(perms _LHS, perms _RHS) {
- return static_cast<perms>(static_cast<unsigned>(_LHS) |
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perms operator^(perms _LHS, perms _RHS) {
- return static_cast<perms>(static_cast<unsigned>(_LHS) ^
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perms operator~(perms _LHS) {
- return static_cast<perms>(~static_cast<unsigned>(_LHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline perms& operator&=(perms& _LHS, perms _RHS) { return _LHS = _LHS & _RHS; }
-
-_LIBCPP_INLINE_VISIBILITY
-inline perms& operator|=(perms& _LHS, perms _RHS) { return _LHS = _LHS | _RHS; }
-
-_LIBCPP_INLINE_VISIBILITY
-inline perms& operator^=(perms& _LHS, perms _RHS) { return _LHS = _LHS ^ _RHS; }
-
-enum class _LIBCPP_ENUM_VIS perm_options : unsigned char {
- replace = 1,
- add = 2,
- remove = 4,
- nofollow = 8
-};
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perm_options operator&(perm_options _LHS, perm_options _RHS) {
- return static_cast<perm_options>(static_cast<unsigned>(_LHS) &
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perm_options operator|(perm_options _LHS, perm_options _RHS) {
- return static_cast<perm_options>(static_cast<unsigned>(_LHS) |
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perm_options operator^(perm_options _LHS, perm_options _RHS) {
- return static_cast<perm_options>(static_cast<unsigned>(_LHS) ^
- static_cast<unsigned>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr perm_options operator~(perm_options _LHS) {
- return static_cast<perm_options>(~static_cast<unsigned>(_LHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline perm_options& operator&=(perm_options& _LHS, perm_options _RHS) {
- return _LHS = _LHS & _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline perm_options& operator|=(perm_options& _LHS, perm_options _RHS) {
- return _LHS = _LHS | _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline perm_options& operator^=(perm_options& _LHS, perm_options _RHS) {
- return _LHS = _LHS ^ _RHS;
-}
-
-enum class _LIBCPP_ENUM_VIS copy_options : unsigned short {
- none = 0,
- skip_existing = 1,
- overwrite_existing = 2,
- update_existing = 4,
- recursive = 8,
- copy_symlinks = 16,
- skip_symlinks = 32,
- directories_only = 64,
- create_symlinks = 128,
- create_hard_links = 256,
- __in_recursive_copy = 512,
-};
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr copy_options operator&(copy_options _LHS, copy_options _RHS) {
- return static_cast<copy_options>(static_cast<unsigned short>(_LHS) &
- static_cast<unsigned short>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr copy_options operator|(copy_options _LHS, copy_options _RHS) {
- return static_cast<copy_options>(static_cast<unsigned short>(_LHS) |
- static_cast<unsigned short>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr copy_options operator^(copy_options _LHS, copy_options _RHS) {
- return static_cast<copy_options>(static_cast<unsigned short>(_LHS) ^
- static_cast<unsigned short>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr copy_options operator~(copy_options _LHS) {
- return static_cast<copy_options>(~static_cast<unsigned short>(_LHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline copy_options& operator&=(copy_options& _LHS, copy_options _RHS) {
- return _LHS = _LHS & _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline copy_options& operator|=(copy_options& _LHS, copy_options _RHS) {
- return _LHS = _LHS | _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline copy_options& operator^=(copy_options& _LHS, copy_options _RHS) {
- return _LHS = _LHS ^ _RHS;
-}
-
-enum class _LIBCPP_ENUM_VIS directory_options : unsigned char {
- none = 0,
- follow_directory_symlink = 1,
- skip_permission_denied = 2
-};
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr directory_options operator&(directory_options _LHS,
- directory_options _RHS) {
- return static_cast<directory_options>(static_cast<unsigned char>(_LHS) &
- static_cast<unsigned char>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr directory_options operator|(directory_options _LHS,
- directory_options _RHS) {
- return static_cast<directory_options>(static_cast<unsigned char>(_LHS) |
- static_cast<unsigned char>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr directory_options operator^(directory_options _LHS,
- directory_options _RHS) {
- return static_cast<directory_options>(static_cast<unsigned char>(_LHS) ^
- static_cast<unsigned char>(_RHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline constexpr directory_options operator~(directory_options _LHS) {
- return static_cast<directory_options>(~static_cast<unsigned char>(_LHS));
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline directory_options& operator&=(directory_options& _LHS,
- directory_options _RHS) {
- return _LHS = _LHS & _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline directory_options& operator|=(directory_options& _LHS,
- directory_options _RHS) {
- return _LHS = _LHS | _RHS;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline directory_options& operator^=(directory_options& _LHS,
- directory_options _RHS) {
- return _LHS = _LHS ^ _RHS;
-}
-
-class _LIBCPP_TYPE_VIS file_status {
-public:
- // constructors
- _LIBCPP_INLINE_VISIBILITY
- file_status() noexcept : file_status(file_type::none) {}
- _LIBCPP_INLINE_VISIBILITY
- explicit file_status(file_type __ft, perms __prms = perms::unknown) noexcept
- : __ft_(__ft),
- __prms_(__prms) {}
-
- file_status(const file_status&) noexcept = default;
- file_status(file_status&&) noexcept = default;
-
- _LIBCPP_INLINE_VISIBILITY
- ~file_status() {}
-
- file_status& operator=(const file_status&) noexcept = default;
- file_status& operator=(file_status&&) noexcept = default;
-
- // observers
- _LIBCPP_INLINE_VISIBILITY
- file_type type() const noexcept { return __ft_; }
-
- _LIBCPP_INLINE_VISIBILITY
- perms permissions() const noexcept { return __prms_; }
-
- // modifiers
- _LIBCPP_INLINE_VISIBILITY
- void type(file_type __ft) noexcept { __ft_ = __ft; }
-
- _LIBCPP_INLINE_VISIBILITY
- void permissions(perms __p) noexcept { __prms_ = __p; }
-
-private:
- file_type __ft_;
- perms __prms_;
-};
-
-class _LIBCPP_TYPE_VIS directory_entry;
-
-template <class _Tp>
-struct __can_convert_char {
- static const bool value = false;
-};
-template <class _Tp>
-struct __can_convert_char<const _Tp> : public __can_convert_char<_Tp> {};
-template <>
-struct __can_convert_char<char> {
- static const bool value = true;
- using __char_type = char;
-};
-template <>
-struct __can_convert_char<wchar_t> {
- static const bool value = true;
- using __char_type = wchar_t;
-};
-template <>
-struct __can_convert_char<char16_t> {
- static const bool value = true;
- using __char_type = char16_t;
-};
-template <>
-struct __can_convert_char<char32_t> {
- static const bool value = true;
- using __char_type = char32_t;
-};
-
-template <class _ECharT>
-typename enable_if<__can_convert_char<_ECharT>::value, bool>::type
-__is_separator(_ECharT __e) {
- return __e == _ECharT('/');
-}
-
-struct _NullSentinal {};
-
-template <class _Tp>
-using _Void = void;
-
-template <class _Tp, class = void>
-struct __is_pathable_string : public false_type {};
-
-template <class _ECharT, class _Traits, class _Alloc>
-struct __is_pathable_string<
- basic_string<_ECharT, _Traits, _Alloc>,
- _Void<typename __can_convert_char<_ECharT>::__char_type> >
- : public __can_convert_char<_ECharT> {
- using _Str = basic_string<_ECharT, _Traits, _Alloc>;
- using _Base = __can_convert_char<_ECharT>;
- static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
- static _ECharT const* __range_end(_Str const& __s) {
- return __s.data() + __s.length();
- }
- static _ECharT __first_or_null(_Str const& __s) {
- return __s.empty() ? _ECharT{} : __s[0];
- }
-};
-
-template <class _ECharT, class _Traits>
-struct __is_pathable_string<
- basic_string_view<_ECharT, _Traits>,
- _Void<typename __can_convert_char<_ECharT>::__char_type> >
- : public __can_convert_char<_ECharT> {
- using _Str = basic_string_view<_ECharT, _Traits>;
- using _Base = __can_convert_char<_ECharT>;
- static _ECharT const* __range_begin(_Str const& __s) { return __s.data(); }
- static _ECharT const* __range_end(_Str const& __s) {
- return __s.data() + __s.length();
- }
- static _ECharT __first_or_null(_Str const& __s) {
- return __s.empty() ? _ECharT{} : __s[0];
- }
-};
-
-template <class _Source, class _DS = typename decay<_Source>::type,
- class _UnqualPtrType =
- typename remove_const<typename remove_pointer<_DS>::type>::type,
- bool _IsCharPtr = is_pointer<_DS>::value&&
- __can_convert_char<_UnqualPtrType>::value>
-struct __is_pathable_char_array : false_type {};
-
-template <class _Source, class _ECharT, class _UPtr>
-struct __is_pathable_char_array<_Source, _ECharT*, _UPtr, true>
- : __can_convert_char<typename remove_const<_ECharT>::type> {
- using _Base = __can_convert_char<typename remove_const<_ECharT>::type>;
-
- static _ECharT const* __range_begin(const _ECharT* __b) { return __b; }
- static _ECharT const* __range_end(const _ECharT* __b) {
- using _Iter = const _ECharT*;
- const _ECharT __sentinal = _ECharT{};
- _Iter __e = __b;
- for (; *__e != __sentinal; ++__e)
- ;
- return __e;
- }
-
- static _ECharT __first_or_null(const _ECharT* __b) { return *__b; }
-};
-
-template <class _Iter, bool _IsIt = __is_input_iterator<_Iter>::value,
- class = void>
-struct __is_pathable_iter : false_type {};
-
-template <class _Iter>
-struct __is_pathable_iter<
- _Iter, true,
- _Void<typename __can_convert_char<
- typename iterator_traits<_Iter>::value_type>::__char_type> >
- : __can_convert_char<typename iterator_traits<_Iter>::value_type> {
- using _ECharT = typename iterator_traits<_Iter>::value_type;
- using _Base = __can_convert_char<_ECharT>;
-
- static _Iter __range_begin(_Iter __b) { return __b; }
- static _NullSentinal __range_end(_Iter) { return _NullSentinal{}; }
-
- static _ECharT __first_or_null(_Iter __b) { return *__b; }
-};
-
-template <class _Tp, bool _IsStringT = __is_pathable_string<_Tp>::value,
- bool _IsCharIterT = __is_pathable_char_array<_Tp>::value,
- bool _IsIterT = !_IsCharIterT && __is_pathable_iter<_Tp>::value>
-struct __is_pathable : false_type {
- static_assert(!_IsStringT && !_IsCharIterT && !_IsIterT, "Must all be false");
-};
-
-template <class _Tp>
-struct __is_pathable<_Tp, true, false, false> : __is_pathable_string<_Tp> {};
-
-template <class _Tp>
-struct __is_pathable<_Tp, false, true, false> : __is_pathable_char_array<_Tp> {
-};
-
-template <class _Tp>
-struct __is_pathable<_Tp, false, false, true> : __is_pathable_iter<_Tp> {};
-
-template <class _ECharT>
-struct _PathCVT {
- static_assert(__can_convert_char<_ECharT>::value,
- "Char type not convertible");
-
- typedef __narrow_to_utf8<sizeof(_ECharT) * __CHAR_BIT__> _Narrower;
-
- static void __append_range(string& __dest, _ECharT const* __b,
- _ECharT const* __e) {
- _Narrower()(back_inserter(__dest), __b, __e);
- }
-
- template <class _Iter>
- static void __append_range(string& __dest, _Iter __b, _Iter __e) {
- static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
- if (__b == __e)
- return;
- basic_string<_ECharT> __tmp(__b, __e);
- _Narrower()(back_inserter(__dest), __tmp.data(),
- __tmp.data() + __tmp.length());
- }
-
- template <class _Iter>
- static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
- static_assert(!is_same<_Iter, _ECharT*>::value, "Call const overload");
- const _ECharT __sentinal = _ECharT{};
- if (*__b == __sentinal)
- return;
- basic_string<_ECharT> __tmp;
- for (; *__b != __sentinal; ++__b)
- __tmp.push_back(*__b);
- _Narrower()(back_inserter(__dest), __tmp.data(),
- __tmp.data() + __tmp.length());
- }
-
- template <class _Source>
- static void __append_source(string& __dest, _Source const& __s) {
- using _Traits = __is_pathable<_Source>;
- __append_range(__dest, _Traits::__range_begin(__s),
- _Traits::__range_end(__s));
- }
-};
-
-template <>
-struct _PathCVT<char> {
-
- template <class _Iter>
- static typename enable_if<__is_exactly_input_iterator<_Iter>::value>::type
- __append_range(string& __dest, _Iter __b, _Iter __e) {
- for (; __b != __e; ++__b)
- __dest.push_back(*__b);
- }
-
- template <class _Iter>
- static typename enable_if<__is_forward_iterator<_Iter>::value>::type
- __append_range(string& __dest, _Iter __b, _Iter __e) {
- __dest.__append_forward_unsafe(__b, __e);
- }
-
- template <class _Iter>
- static void __append_range(string& __dest, _Iter __b, _NullSentinal) {
- const char __sentinal = char{};
- for (; *__b != __sentinal; ++__b)
- __dest.push_back(*__b);
- }
-
- template <class _Source>
- static void __append_source(string& __dest, _Source const& __s) {
- using _Traits = __is_pathable<_Source>;
- __append_range(__dest, _Traits::__range_begin(__s),
- _Traits::__range_end(__s));
- }
-};
-
-class _LIBCPP_TYPE_VIS path {
- template <class _SourceOrIter, class _Tp = path&>
- using _EnableIfPathable =
- typename enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type;
-
- template <class _Tp>
- using _SourceChar = typename __is_pathable<_Tp>::__char_type;
-
- template <class _Tp>
- using _SourceCVT = _PathCVT<_SourceChar<_Tp> >;
-
-public:
- typedef char value_type;
- typedef basic_string<value_type> string_type;
- typedef _VSTD::string_view __string_view;
- static constexpr value_type preferred_separator = '/';
-
- enum class _LIBCPP_ENUM_VIS format : unsigned char {
- auto_format,
- native_format,
- generic_format
- };
-
- // constructors and destructor
- _LIBCPP_INLINE_VISIBILITY path() noexcept {}
- _LIBCPP_INLINE_VISIBILITY path(const path& __p) : __pn_(__p.__pn_) {}
- _LIBCPP_INLINE_VISIBILITY path(path&& __p) noexcept
- : __pn_(_VSTD::move(__p.__pn_)) {}
-
- _LIBCPP_INLINE_VISIBILITY
- path(string_type&& __s, format = format::auto_format) noexcept
- : __pn_(_VSTD::move(__s)) {}
-
- template <class _Source, class = _EnableIfPathable<_Source, void> >
- path(const _Source& __src, format = format::auto_format) {
- _SourceCVT<_Source>::__append_source(__pn_, __src);
- }
-
- template <class _InputIt>
- path(_InputIt __first, _InputIt __last, format = format::auto_format) {
- typedef typename iterator_traits<_InputIt>::value_type _ItVal;
- _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
- }
-
- // TODO Implement locale conversions.
- template <class _Source, class = _EnableIfPathable<_Source, void> >
- path(const _Source& __src, const locale& __loc, format = format::auto_format);
- template <class _InputIt>
- path(_InputIt __first, _InputIt _last, const locale& __loc,
- format = format::auto_format);
-
- _LIBCPP_INLINE_VISIBILITY
- ~path() = default;
-
- // assignments
- _LIBCPP_INLINE_VISIBILITY
- path& operator=(const path& __p) {
- __pn_ = __p.__pn_;
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& operator=(path&& __p) noexcept {
- __pn_ = _VSTD::move(__p.__pn_);
- return *this;
- }
-
- template <class = void>
- _LIBCPP_INLINE_VISIBILITY path& operator=(string_type&& __s) noexcept {
- __pn_ = _VSTD::move(__s);
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& assign(string_type&& __s) noexcept {
- __pn_ = _VSTD::move(__s);
- return *this;
- }
-
- template <class _Source>
- _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
- operator=(const _Source& __src) {
- return this->assign(__src);
- }
-
- template <class _Source>
- _EnableIfPathable<_Source> assign(const _Source& __src) {
- __pn_.clear();
- _SourceCVT<_Source>::__append_source(__pn_, __src);
- return *this;
- }
-
- template <class _InputIt>
- path& assign(_InputIt __first, _InputIt __last) {
- typedef typename iterator_traits<_InputIt>::value_type _ItVal;
- __pn_.clear();
- _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
- return *this;
- }
-
-private:
- template <class _ECharT>
- static bool __source_is_absolute(_ECharT __first_or_null) {
- return __is_separator(__first_or_null);
- }
-
-public:
- // appends
- path& operator/=(const path& __p) {
- if (__p.is_absolute()) {
- __pn_ = __p.__pn_;
- return *this;
- }
- if (has_filename())
- __pn_ += preferred_separator;
- __pn_ += __p.native();
- return *this;
- }
-
- // FIXME: Use _LIBCPP_DIAGNOSE_WARNING to produce a diagnostic when __src
- // is known at compile time to be "/' since the user almost certainly intended
- // to append a separator instead of overwriting the path with "/"
- template <class _Source>
- _LIBCPP_INLINE_VISIBILITY _EnableIfPathable<_Source>
- operator/=(const _Source& __src) {
- return this->append(__src);
- }
-
- template <class _Source>
- _EnableIfPathable<_Source> append(const _Source& __src) {
- using _Traits = __is_pathable<_Source>;
- using _CVT = _PathCVT<_SourceChar<_Source> >;
- if (__source_is_absolute(_Traits::__first_or_null(__src)))
- __pn_.clear();
- else if (has_filename())
- __pn_ += preferred_separator;
- _CVT::__append_source(__pn_, __src);
- return *this;
- }
-
- template <class _InputIt>
- path& append(_InputIt __first, _InputIt __last) {
- typedef typename iterator_traits<_InputIt>::value_type _ItVal;
- static_assert(__can_convert_char<_ItVal>::value, "Must convertible");
- using _CVT = _PathCVT<_ItVal>;
- if (__first != __last && __source_is_absolute(*__first))
- __pn_.clear();
- else if (has_filename())
- __pn_ += preferred_separator;
- _CVT::__append_range(__pn_, __first, __last);
- return *this;
- }
-
- // concatenation
- _LIBCPP_INLINE_VISIBILITY
- path& operator+=(const path& __x) {
- __pn_ += __x.__pn_;
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& operator+=(const string_type& __x) {
- __pn_ += __x;
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& operator+=(__string_view __x) {
- __pn_ += __x;
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& operator+=(const value_type* __x) {
- __pn_ += __x;
- return *this;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- path& operator+=(value_type __x) {
- __pn_ += __x;
- return *this;
- }
-
- template <class _ECharT>
- typename enable_if<__can_convert_char<_ECharT>::value, path&>::type
- operator+=(_ECharT __x) {
- basic_string<_ECharT> __tmp;
- __tmp += __x;
- _PathCVT<_ECharT>::__append_source(__pn_, __tmp);
- return *this;
- }
-
- template <class _Source>
- _EnableIfPathable<_Source> operator+=(const _Source& __x) {
- return this->concat(__x);
- }
-
- template <class _Source>
- _EnableIfPathable<_Source> concat(const _Source& __x) {
- _SourceCVT<_Source>::__append_source(__pn_, __x);
- return *this;
- }
-
- template <class _InputIt>
- path& concat(_InputIt __first, _InputIt __last) {
- typedef typename iterator_traits<_InputIt>::value_type _ItVal;
- _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
- return *this;
- }
-
- // modifiers
- _LIBCPP_INLINE_VISIBILITY
- void clear() noexcept { __pn_.clear(); }
-
- path& make_preferred() { return *this; }
-
- _LIBCPP_INLINE_VISIBILITY
- path& remove_filename() {
- auto __fname = __filename();
- if (!__fname.empty())
- __pn_.erase(__fname.data() - __pn_.data());
- return *this;
- }
-
- path& replace_filename(const path& __replacement) {
- remove_filename();
- return (*this /= __replacement);
- }
-
- path& replace_extension(const path& __replacement = path());
-
- _LIBCPP_INLINE_VISIBILITY
- void swap(path& __rhs) noexcept { __pn_.swap(__rhs.__pn_); }
-
- // private helper to allow reserving memory in the path
- _LIBCPP_INLINE_VISIBILITY
- void __reserve(size_t __s) { __pn_.reserve(__s); }
-
- // native format observers
- _LIBCPP_INLINE_VISIBILITY
- const string_type& native() const noexcept { return __pn_; }
-
- _LIBCPP_INLINE_VISIBILITY
- const value_type* c_str() const noexcept { return __pn_.c_str(); }
-
- _LIBCPP_INLINE_VISIBILITY operator string_type() const { return __pn_; }
-
- template <class _ECharT, class _Traits = char_traits<_ECharT>,
- class _Allocator = allocator<_ECharT> >
- basic_string<_ECharT, _Traits, _Allocator>
- string(const _Allocator& __a = _Allocator()) const {
- using _CVT = __widen_from_utf8<sizeof(_ECharT) * __CHAR_BIT__>;
- using _Str = basic_string<_ECharT, _Traits, _Allocator>;
- _Str __s(__a);
- __s.reserve(__pn_.size());
- _CVT()(back_inserter(__s), __pn_.data(), __pn_.data() + __pn_.size());
- return __s;
- }
-
- _LIBCPP_INLINE_VISIBILITY std::string string() const { return __pn_; }
- _LIBCPP_INLINE_VISIBILITY std::wstring wstring() const {
- return string<wchar_t>();
- }
- _LIBCPP_INLINE_VISIBILITY std::string u8string() const { return __pn_; }
- _LIBCPP_INLINE_VISIBILITY std::u16string u16string() const {
- return string<char16_t>();
- }
- _LIBCPP_INLINE_VISIBILITY std::u32string u32string() const {
- return string<char32_t>();
- }
-
- // generic format observers
- template <class _ECharT, class _Traits = char_traits<_ECharT>,
- class _Allocator = allocator<_ECharT> >
- basic_string<_ECharT, _Traits, _Allocator>
- generic_string(const _Allocator& __a = _Allocator()) const {
- return string<_ECharT, _Traits, _Allocator>(__a);
- }
-
- std::string generic_string() const { return __pn_; }
- std::wstring generic_wstring() const { return string<wchar_t>(); }
- std::string generic_u8string() const { return __pn_; }
- std::u16string generic_u16string() const { return string<char16_t>(); }
- std::u32string generic_u32string() const { return string<char32_t>(); }
-
-private:
- int __compare(__string_view) const;
- __string_view __root_name() const;
- __string_view __root_directory() const;
- __string_view __root_path_raw() const;
- __string_view __relative_path() const;
- __string_view __parent_path() const;
- __string_view __filename() const;
- __string_view __stem() const;
- __string_view __extension() const;
-
-public:
- // compare
- _LIBCPP_INLINE_VISIBILITY int compare(const path& __p) const noexcept {
- return __compare(__p.__pn_);
- }
- _LIBCPP_INLINE_VISIBILITY int compare(const string_type& __s) const {
- return __compare(__s);
- }
- _LIBCPP_INLINE_VISIBILITY int compare(__string_view __s) const {
- return __compare(__s);
- }
- _LIBCPP_INLINE_VISIBILITY int compare(const value_type* __s) const {
- return __compare(__s);
- }
-
- // decomposition
- _LIBCPP_INLINE_VISIBILITY path root_name() const {
- return string_type(__root_name());
- }
- _LIBCPP_INLINE_VISIBILITY path root_directory() const {
- return string_type(__root_directory());
- }
- _LIBCPP_INLINE_VISIBILITY path root_path() const {
- return root_name().append(string_type(__root_directory()));
- }
- _LIBCPP_INLINE_VISIBILITY path relative_path() const {
- return string_type(__relative_path());
- }
- _LIBCPP_INLINE_VISIBILITY path parent_path() const {
- return string_type(__parent_path());
- }
- _LIBCPP_INLINE_VISIBILITY path filename() const {
- return string_type(__filename());
- }
- _LIBCPP_INLINE_VISIBILITY path stem() const { return string_type(__stem()); }
- _LIBCPP_INLINE_VISIBILITY path extension() const {
- return string_type(__extension());
- }
-
- // query
- _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY bool
- empty() const noexcept {
- return __pn_.empty();
- }
-
- _LIBCPP_INLINE_VISIBILITY bool has_root_name() const {
- return !__root_name().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_root_directory() const {
- return !__root_directory().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_root_path() const {
- return !__root_path_raw().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_relative_path() const {
- return !__relative_path().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_parent_path() const {
- return !__parent_path().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_filename() const {
- return !__filename().empty();
- }
- _LIBCPP_INLINE_VISIBILITY bool has_stem() const { return !__stem().empty(); }
- _LIBCPP_INLINE_VISIBILITY bool has_extension() const {
- return !__extension().empty();
- }
-
- _LIBCPP_INLINE_VISIBILITY bool is_absolute() const {
- return has_root_directory();
- }
- _LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); }
-
- // relative paths
- path lexically_normal() const;
- path lexically_relative(const path& __base) const;
-
- _LIBCPP_INLINE_VISIBILITY path lexically_proximate(const path& __base) const {
- path __result = this->lexically_relative(__base);
- if (__result.native().empty())
- return *this;
- return __result;
- }
-
- // iterators
- class _LIBCPP_TYPE_VIS iterator;
- typedef iterator const_iterator;
-
- iterator begin() const;
- iterator end() const;
-
- template <class _CharT, class _Traits>
- _LIBCPP_INLINE_VISIBILITY friend
- typename enable_if<is_same<_CharT, char>::value &&
- is_same<_Traits, char_traits<char> >::value,
- basic_ostream<_CharT, _Traits>&>::type
- operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
- __os << std::__quoted(__p.native());
- return __os;
- }
-
- template <class _CharT, class _Traits>
- _LIBCPP_INLINE_VISIBILITY friend
- typename enable_if<!is_same<_CharT, char>::value ||
- !is_same<_Traits, char_traits<char> >::value,
- basic_ostream<_CharT, _Traits>&>::type
- operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) {
- __os << std::__quoted(__p.string<_CharT, _Traits>());
- return __os;
- }
-
- template <class _CharT, class _Traits>
- _LIBCPP_INLINE_VISIBILITY friend basic_istream<_CharT, _Traits>&
- operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) {
- basic_string<_CharT, _Traits> __tmp;
- __is >> __quoted(__tmp);
- __p = __tmp;
- return __is;
- }
-
- friend _LIBCPP_INLINE_VISIBILITY bool operator==(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) == 0;
- }
- friend _LIBCPP_INLINE_VISIBILITY bool operator!=(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) != 0;
- }
- friend _LIBCPP_INLINE_VISIBILITY bool operator<(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) < 0;
- }
- friend _LIBCPP_INLINE_VISIBILITY bool operator<=(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) <= 0;
- }
- friend _LIBCPP_INLINE_VISIBILITY bool operator>(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) > 0;
- }
- friend _LIBCPP_INLINE_VISIBILITY bool operator>=(const path& __lhs, const path& __rhs) noexcept {
- return __lhs.compare(__rhs) >= 0;
- }
-
- friend _LIBCPP_INLINE_VISIBILITY path operator/(const path& __lhs,
- const path& __rhs) {
- path __result(__lhs);
- __result /= __rhs;
- return __result;
- }
-private:
- inline _LIBCPP_INLINE_VISIBILITY path&
- __assign_view(__string_view const& __s) noexcept {
- __pn_ = string_type(__s);
- return *this;
- }
- string_type __pn_;
-};
-
-inline _LIBCPP_INLINE_VISIBILITY void swap(path& __lhs, path& __rhs) noexcept {
- __lhs.swap(__rhs);
-}
-
-_LIBCPP_FUNC_VIS
-size_t hash_value(const path& __p) noexcept;
-
-template <class _Source>
-_LIBCPP_INLINE_VISIBILITY
- typename enable_if<__is_pathable<_Source>::value, path>::type
- u8path(const _Source& __s) {
- static_assert(
- is_same<typename __is_pathable<_Source>::__char_type, char>::value,
- "u8path(Source const&) requires Source have a character type of type "
- "'char'");
- return path(__s);
-}
-
-template <class _InputIt>
-_LIBCPP_INLINE_VISIBILITY
- typename enable_if<__is_pathable<_InputIt>::value, path>::type
- u8path(_InputIt __f, _InputIt __l) {
- static_assert(
- is_same<typename __is_pathable<_InputIt>::__char_type, char>::value,
- "u8path(Iter, Iter) requires Iter have a value_type of type 'char'");
- return path(__f, __l);
-}
-
-class _LIBCPP_TYPE_VIS path::iterator {
-public:
- enum _ParserState : unsigned char {
- _Singular,
- _BeforeBegin,
- _InRootName,
- _InRootDir,
- _InFilenames,
- _InTrailingSep,
- _AtEnd
- };
-
-public:
- typedef bidirectional_iterator_tag iterator_category;
-
- typedef path value_type;
- typedef std::ptrdiff_t difference_type;
- typedef const path* pointer;
- typedef const path& reference;
-
- typedef void
- __stashing_iterator_tag; // See reverse_iterator and __is_stashing_iterator
-
-public:
- _LIBCPP_INLINE_VISIBILITY
- iterator()
- : __stashed_elem_(), __path_ptr_(nullptr), __entry_(),
- __state_(_Singular) {}
-
- iterator(const iterator&) = default;
- ~iterator() = default;
-
- iterator& operator=(const iterator&) = default;
-
- _LIBCPP_INLINE_VISIBILITY
- reference operator*() const { return __stashed_elem_; }
-
- _LIBCPP_INLINE_VISIBILITY
- pointer operator->() const { return &__stashed_elem_; }
-
- _LIBCPP_INLINE_VISIBILITY
- iterator& operator++() {
- _LIBCPP_ASSERT(__state_ != _Singular,
- "attempting to increment a singular iterator");
- _LIBCPP_ASSERT(__state_ != _AtEnd,
- "attempting to increment the end iterator");
- return __increment();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- iterator operator++(int) {
- iterator __it(*this);
- this->operator++();
- return __it;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- iterator& operator--() {
- _LIBCPP_ASSERT(__state_ != _Singular,
- "attempting to decrement a singular iterator");
- _LIBCPP_ASSERT(__entry_.data() != __path_ptr_->native().data(),
- "attempting to decrement the begin iterator");
- return __decrement();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- iterator operator--(int) {
- iterator __it(*this);
- this->operator--();
- return __it;
- }
-
-private:
- friend class path;
-
- inline _LIBCPP_INLINE_VISIBILITY friend bool operator==(const iterator&,
- const iterator&);
-
- iterator& __increment();
- iterator& __decrement();
-
- path __stashed_elem_;
- const path* __path_ptr_;
- path::__string_view __entry_;
- _ParserState __state_;
-};
-
-inline _LIBCPP_INLINE_VISIBILITY bool operator==(const path::iterator& __lhs,
- const path::iterator& __rhs) {
- return __lhs.__path_ptr_ == __rhs.__path_ptr_ &&
- __lhs.__entry_.data() == __rhs.__entry_.data();
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool operator!=(const path::iterator& __lhs,
- const path::iterator& __rhs) {
- return !(__lhs == __rhs);
-}
-
-class _LIBCPP_EXCEPTION_ABI filesystem_error : public system_error {
-public:
- _LIBCPP_INLINE_VISIBILITY
- filesystem_error(const string& __what, error_code __ec)
- : system_error(__ec, __what),
- __storage_(make_shared<_Storage>(path(), path())) {
- __create_what(0);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- filesystem_error(const string& __what, const path& __p1, error_code __ec)
- : system_error(__ec, __what),
- __storage_(make_shared<_Storage>(__p1, path())) {
- __create_what(1);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- filesystem_error(const string& __what, const path& __p1, const path& __p2,
- error_code __ec)
- : system_error(__ec, __what),
- __storage_(make_shared<_Storage>(__p1, __p2)) {
- __create_what(2);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- const path& path1() const noexcept { return __storage_->__p1_; }
-
- _LIBCPP_INLINE_VISIBILITY
- const path& path2() const noexcept { return __storage_->__p2_; }
-
- ~filesystem_error() override; // key function
-
- _LIBCPP_INLINE_VISIBILITY
- const char* what() const noexcept override {
- return __storage_->__what_.c_str();
- }
-
- _LIBCPP_FUNC_VIS
- void __create_what(int __num_paths);
-
-private:
- struct _Storage {
- _LIBCPP_INLINE_VISIBILITY
- _Storage(const path& __p1, const path& __p2) : __p1_(__p1), __p2_(__p2) {}
-
- path __p1_;
- path __p2_;
- string __what_;
- };
- shared_ptr<_Storage> __storage_;
-};
-
-template <class... _Args>
-_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
-#ifndef _LIBCPP_NO_EXCEPTIONS
- void
- __throw_filesystem_error(_Args&&... __args) {
- throw filesystem_error(std::forward<_Args>(__args)...);
-}
-#else
- void
- __throw_filesystem_error(_Args&&...) {
- _VSTD::abort();
-}
-#endif
-
-// operational functions
-
-_LIBCPP_FUNC_VIS
-path __absolute(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-path __canonical(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __copy(const path& __from, const path& __to, copy_options __opt,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __copy_file(const path& __from, const path& __to, copy_options __opt,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __copy_symlink(const path& __existing_symlink, const path& __new_symlink,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __create_directories(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __create_directory(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __create_directory(const path& p, const path& attributes,
- error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __create_directory_symlink(const path& __to, const path& __new_symlink,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __create_hard_link(const path& __to, const path& __new_hard_link,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __create_symlink(const path& __to, const path& __new_symlink,
- error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-path __current_path(error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __current_path(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __equivalent(const path&, const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-uintmax_t __file_size(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-uintmax_t __hard_link_count(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __fs_is_empty(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-file_time_type __last_write_time(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __last_write_time(const path& p, file_time_type new_time,
- error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __permissions(const path&, perms, perm_options, error_code* = nullptr);
-_LIBCPP_FUNC_VIS
-path __read_symlink(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-bool __remove(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-uintmax_t __remove_all(const path& p, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __rename(const path& from, const path& to, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-void __resize_file(const path& p, uintmax_t size, error_code* ec = nullptr);
-_LIBCPP_FUNC_VIS
-space_info __space(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-file_status __status(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-file_status __symlink_status(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-path __system_complete(const path&, error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-path __temp_directory_path(error_code* __ec = nullptr);
-_LIBCPP_FUNC_VIS
-path __weakly_canonical(path const& __p, error_code* __ec = nullptr);
-
-inline _LIBCPP_INLINE_VISIBILITY path current_path() {
- return __current_path();
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path current_path(error_code& __ec) {
- return __current_path(&__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p) {
- __current_path(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void current_path(const path& __p,
- error_code& __ec) noexcept {
- __current_path(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p) {
- return __absolute(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path absolute(const path& __p,
- error_code& __ec) {
- return __absolute(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p) {
- return __canonical(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path canonical(const path& __p,
- error_code& __ec) {
- return __canonical(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from,
- const path& __to) {
- __copy(__from, __to, copy_options::none);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
- error_code& __ec) {
- __copy(__from, __to, copy_options::none, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
- copy_options __opt) {
- __copy(__from, __to, __opt);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void copy(const path& __from, const path& __to,
- copy_options __opt,
- error_code& __ec) {
- __copy(__from, __to, __opt, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from,
- const path& __to) {
- return __copy_file(__from, __to, copy_options::none);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-copy_file(const path& __from, const path& __to, error_code& __ec) {
- return __copy_file(__from, __to, copy_options::none, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-copy_file(const path& __from, const path& __to, copy_options __opt) {
- return __copy_file(__from, __to, __opt);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool copy_file(const path& __from,
- const path& __to,
- copy_options __opt,
- error_code& __ec) {
- return __copy_file(__from, __to, __opt, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void copy_symlink(const path& __existing,
- const path& __new) {
- __copy_symlink(__existing, __new);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-copy_symlink(const path& __ext, const path& __new, error_code& __ec) noexcept {
- __copy_symlink(__ext, __new, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p) {
- return __create_directories(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool create_directories(const path& __p,
- error_code& __ec) {
- return __create_directories(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p) {
- return __create_directory(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-create_directory(const path& __p, error_code& __ec) noexcept {
- return __create_directory(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool create_directory(const path& __p,
- const path& __attrs) {
- return __create_directory(__p, __attrs);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-create_directory(const path& __p, const path& __attrs,
- error_code& __ec) noexcept {
- return __create_directory(__p, __attrs, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-create_directory_symlink(const path& __to, const path& __new) {
- __create_directory_symlink(__to, __new);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-create_directory_symlink(const path& __to, const path& __new,
- error_code& __ec) noexcept {
- __create_directory_symlink(__to, __new, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void create_hard_link(const path& __to,
- const path& __new) {
- __create_hard_link(__to, __new);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-create_hard_link(const path& __to, const path& __new,
- error_code& __ec) noexcept {
- __create_hard_link(__to, __new, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void create_symlink(const path& __to,
- const path& __new) {
- __create_symlink(__to, __new);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-create_symlink(const path& __to, const path& __new, error_code& __ec) noexcept {
- return __create_symlink(__to, __new, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool status_known(file_status __s) noexcept {
- return __s.type() != file_type::none;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool exists(file_status __s) noexcept {
- return status_known(__s) && __s.type() != file_type::not_found;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p) {
- return exists(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool exists(const path& __p,
- error_code& __ec) noexcept {
- auto __s = __status(__p, &__ec);
- if (status_known(__s))
- __ec.clear();
- return exists(__s);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool equivalent(const path& __p1,
- const path& __p2) {
- return __equivalent(__p1, __p2);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept {
- return __equivalent(__p1, __p2, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t file_size(const path& __p) {
- return __file_size(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t
-file_size(const path& __p, error_code& __ec) noexcept {
- return __file_size(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t hard_link_count(const path& __p) {
- return __hard_link_count(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t
-hard_link_count(const path& __p, error_code& __ec) noexcept {
- return __hard_link_count(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(file_status __s) noexcept {
- return __s.type() == file_type::block;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p) {
- return is_block_file(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p,
- error_code& __ec) noexcept {
- return is_block_file(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-is_character_file(file_status __s) noexcept {
- return __s.type() == file_type::character;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_character_file(const path& __p) {
- return is_character_file(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-is_character_file(const path& __p, error_code& __ec) noexcept {
- return is_character_file(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_directory(file_status __s) noexcept {
- return __s.type() == file_type::directory;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p) {
- return is_directory(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p,
- error_code& __ec) noexcept {
- return is_directory(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p) {
- return __fs_is_empty(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p,
- error_code& __ec) {
- return __fs_is_empty(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(file_status __s) noexcept {
- return __s.type() == file_type::fifo;
-}
-inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p) {
- return is_fifo(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p,
- error_code& __ec) noexcept {
- return is_fifo(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-is_regular_file(file_status __s) noexcept {
- return __s.type() == file_type::regular;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_regular_file(const path& __p) {
- return is_regular_file(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-is_regular_file(const path& __p, error_code& __ec) noexcept {
- return is_regular_file(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_socket(file_status __s) noexcept {
- return __s.type() == file_type::socket;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p) {
- return is_socket(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p,
- error_code& __ec) noexcept {
- return is_socket(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(file_status __s) noexcept {
- return __s.type() == file_type::symlink;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p) {
- return is_symlink(__symlink_status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p,
- error_code& __ec) noexcept {
- return is_symlink(__symlink_status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_other(file_status __s) noexcept {
- return exists(__s) && !is_regular_file(__s) && !is_directory(__s) &&
- !is_symlink(__s);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p) {
- return is_other(__status(__p));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p,
- error_code& __ec) noexcept {
- return is_other(__status(__p, &__ec));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_time_type
-last_write_time(const path& __p) {
- return __last_write_time(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_time_type
-last_write_time(const path& __p, error_code& __ec) noexcept {
- return __last_write_time(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void last_write_time(const path& __p,
- file_time_type __t) {
- __last_write_time(__p, __t);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-last_write_time(const path& __p, file_time_type __t,
- error_code& __ec) noexcept {
- __last_write_time(__p, __t, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-permissions(const path& __p, perms __prms,
- perm_options __opts = perm_options::replace) {
- __permissions(__p, __prms, __opts);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms,
- error_code& __ec) noexcept {
- __permissions(__p, __prms, perm_options::replace, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void permissions(const path& __p, perms __prms,
- perm_options __opts,
- error_code& __ec) {
- __permissions(__p, __prms, __opts, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p,
- const path& __base,
- error_code& __ec) {
- path __tmp = __weakly_canonical(__p, &__ec);
- if (__ec)
- return {};
- path __tmp_base = __weakly_canonical(__base, &__ec);
- if (__ec)
- return {};
- return __tmp.lexically_proximate(__tmp_base);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path proximate(const path& __p,
- error_code& __ec) {
- return proximate(__p, current_path(), __ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path
-proximate(const path& __p, const path& __base = current_path()) {
- return __weakly_canonical(__p).lexically_proximate(
- __weakly_canonical(__base));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p) {
- return __read_symlink(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path read_symlink(const path& __p,
- error_code& __ec) {
- return __read_symlink(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p,
- const path& __base,
- error_code& __ec) {
- path __tmp = __weakly_canonical(__p, &__ec);
- if (__ec)
- return path();
- path __tmpbase = __weakly_canonical(__base, &__ec);
- if (__ec)
- return path();
- return __tmp.lexically_relative(__tmpbase);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path relative(const path& __p,
- error_code& __ec) {
- return relative(__p, current_path(), __ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path
-relative(const path& __p, const path& __base = current_path()) {
- return __weakly_canonical(__p).lexically_relative(__weakly_canonical(__base));
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p) {
- return __remove(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool remove(const path& __p,
- error_code& __ec) noexcept {
- return __remove(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p) {
- return __remove_all(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY uintmax_t remove_all(const path& __p,
- error_code& __ec) {
- return __remove_all(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void rename(const path& __from,
- const path& __to) {
- return __rename(__from, __to);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-rename(const path& __from, const path& __to, error_code& __ec) noexcept {
- return __rename(__from, __to, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void resize_file(const path& __p,
- uintmax_t __ns) {
- return __resize_file(__p, __ns);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY void
-resize_file(const path& __p, uintmax_t __ns, error_code& __ec) noexcept {
- return __resize_file(__p, __ns, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p) {
- return __space(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY space_info space(const path& __p,
- error_code& __ec) noexcept {
- return __space(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p) {
- return __status(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_status status(const path& __p,
- error_code& __ec) noexcept {
- return __status(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_status symlink_status(const path& __p) {
- return __symlink_status(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY file_status
-symlink_status(const path& __p, error_code& __ec) noexcept {
- return __symlink_status(__p, &__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path() {
- return __temp_directory_path();
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path temp_directory_path(error_code& __ec) {
- return __temp_directory_path(&__ec);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p) {
- return __weakly_canonical(__p);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY path weakly_canonical(path const& __p,
- error_code& __ec) {
- return __weakly_canonical(__p, &__ec);
-}
-
-class directory_iterator;
-class recursive_directory_iterator;
-class __dir_stream;
-
-class directory_entry {
- typedef _VSTD_FS::path _Path;
-
-public:
- // constructors and destructors
- directory_entry() noexcept = default;
- directory_entry(directory_entry const&) = default;
- directory_entry(directory_entry&&) noexcept = default;
-
- _LIBCPP_INLINE_VISIBILITY
- explicit directory_entry(_Path const& __p) : __p_(__p) {
- error_code __ec;
- __refresh(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- directory_entry(_Path const& __p, error_code& __ec) : __p_(__p) {
- __refresh(&__ec);
- }
-
- ~directory_entry() {}
-
- directory_entry& operator=(directory_entry const&) = default;
- directory_entry& operator=(directory_entry&&) noexcept = default;
-
- _LIBCPP_INLINE_VISIBILITY
- void assign(_Path const& __p) {
- __p_ = __p;
- error_code __ec;
- __refresh(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void assign(_Path const& __p, error_code& __ec) {
- __p_ = __p;
- __refresh(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void replace_filename(_Path const& __p) {
- __p_.replace_filename(__p);
- error_code __ec;
- __refresh(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void replace_filename(_Path const& __p, error_code& __ec) {
- __p_ = __p_.parent_path() / __p;
- __refresh(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void refresh() { __refresh(); }
-
- _LIBCPP_INLINE_VISIBILITY
- void refresh(error_code& __ec) noexcept { __refresh(&__ec); }
-
- _LIBCPP_INLINE_VISIBILITY
- _Path const& path() const noexcept { return __p_; }
-
- _LIBCPP_INLINE_VISIBILITY
- operator const _Path&() const noexcept { return __p_; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool exists() const { return _VSTD_FS::exists(file_status{__get_ft()}); }
-
- _LIBCPP_INLINE_VISIBILITY
- bool exists(error_code& __ec) const noexcept {
- return _VSTD_FS::exists(file_status{__get_ft(&__ec)});
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_block_file() const { return __get_ft() == file_type::block; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_block_file(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::block;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_character_file() const { return __get_ft() == file_type::character; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_character_file(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::character;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_directory() const { return __get_ft() == file_type::directory; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_directory(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::directory;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_fifo() const { return __get_ft() == file_type::fifo; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_fifo(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::fifo;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_other() const { return _VSTD_FS::is_other(file_status{__get_ft()}); }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_other(error_code& __ec) const noexcept {
- return _VSTD_FS::is_other(file_status{__get_ft(&__ec)});
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_regular_file() const { return __get_ft() == file_type::regular; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_regular_file(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::regular;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_socket() const { return __get_ft() == file_type::socket; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_socket(error_code& __ec) const noexcept {
- return __get_ft(&__ec) == file_type::socket;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_symlink() const { return __get_sym_ft() == file_type::symlink; }
-
- _LIBCPP_INLINE_VISIBILITY
- bool is_symlink(error_code& __ec) const noexcept {
- return __get_sym_ft(&__ec) == file_type::symlink;
- }
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t file_size() const { return __get_size(); }
-
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t file_size(error_code& __ec) const noexcept {
- return __get_size(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t hard_link_count() const { return __get_nlink(); }
-
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t hard_link_count(error_code& __ec) const noexcept {
- return __get_nlink(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_time_type last_write_time() const { return __get_write_time(); }
-
- _LIBCPP_INLINE_VISIBILITY
- file_time_type last_write_time(error_code& __ec) const noexcept {
- return __get_write_time(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status status() const { return __get_status(); }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status status(error_code& __ec) const noexcept {
- return __get_status(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status symlink_status() const { return __get_symlink_status(); }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status symlink_status(error_code& __ec) const noexcept {
- return __get_symlink_status(&__ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator<(directory_entry const& __rhs) const noexcept {
- return __p_ < __rhs.__p_;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator==(directory_entry const& __rhs) const noexcept {
- return __p_ == __rhs.__p_;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator!=(directory_entry const& __rhs) const noexcept {
- return __p_ != __rhs.__p_;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator<=(directory_entry const& __rhs) const noexcept {
- return __p_ <= __rhs.__p_;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator>(directory_entry const& __rhs) const noexcept {
- return __p_ > __rhs.__p_;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- bool operator>=(directory_entry const& __rhs) const noexcept {
- return __p_ >= __rhs.__p_;
- }
-
-private:
- friend class directory_iterator;
- friend class recursive_directory_iterator;
- friend class __dir_stream;
-
- enum _CacheType : unsigned char {
- _Empty,
- _IterSymlink,
- _IterNonSymlink,
- _RefreshSymlink,
- _RefreshSymlinkUnresolved,
- _RefreshNonSymlink
- };
-
- struct __cached_data {
- uintmax_t __size_;
- uintmax_t __nlink_;
- file_time_type __write_time_;
- perms __sym_perms_;
- perms __non_sym_perms_;
- file_type __type_;
- _CacheType __cache_type_;
-
- _LIBCPP_INLINE_VISIBILITY
- __cached_data() noexcept { __reset(); }
-
- _LIBCPP_INLINE_VISIBILITY
- void __reset() {
- __cache_type_ = _Empty;
- __type_ = file_type::none;
- __sym_perms_ = __non_sym_perms_ = perms::unknown;
- __size_ = __nlink_ = uintmax_t(-1);
- __write_time_ = file_time_type::min();
- }
- };
-
- _LIBCPP_INLINE_VISIBILITY
- static __cached_data __create_iter_result(file_type __ft) {
- __cached_data __data;
- __data.__type_ = __ft;
- __data.__cache_type_ = [&]() {
- switch (__ft) {
- case file_type::none:
- return _Empty;
- case file_type::symlink:
- return _IterSymlink;
- default:
- return _IterNonSymlink;
- }
- }();
- return __data;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void __assign_iter_entry(_Path&& __p, __cached_data __dt) {
- __p_ = std::move(__p);
- __data_ = __dt;
- }
-
- _LIBCPP_FUNC_VIS
- error_code __do_refresh() noexcept;
-
- _LIBCPP_INLINE_VISIBILITY
- static bool __is_dne_error(error_code const& __ec) {
- if (!__ec)
- return true;
- switch (static_cast<errc>(__ec.value())) {
- case errc::no_such_file_or_directory:
- case errc::not_a_directory:
- return true;
- default:
- return false;
- }
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void __handle_error(const char* __msg, error_code* __dest_ec,
- error_code const& __ec, bool __allow_dne = false) const {
- if (__dest_ec) {
- *__dest_ec = __ec;
- return;
- }
- if (__ec && (!__allow_dne || !__is_dne_error(__ec)))
- __throw_filesystem_error(__msg, __p_, __ec);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- void __refresh(error_code* __ec = nullptr) {
- __handle_error("in directory_entry::refresh", __ec, __do_refresh(),
- /*allow_dne*/ true);
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_type __get_sym_ft(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- return __symlink_status(__p_, __ec).type();
- case _IterSymlink:
- case _RefreshSymlink:
- case _RefreshSymlinkUnresolved:
- if (__ec)
- __ec->clear();
- return file_type::symlink;
- case _IterNonSymlink:
- case _RefreshNonSymlink:
- file_status __st(__data_.__type_);
- if (__ec && !_VSTD_FS::exists(__st))
- *__ec = make_error_code(errc::no_such_file_or_directory);
- else if (__ec)
- __ec->clear();
- return __data_.__type_;
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_type __get_ft(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterSymlink:
- case _RefreshSymlinkUnresolved:
- return __status(__p_, __ec).type();
- case _IterNonSymlink:
- case _RefreshNonSymlink:
- case _RefreshSymlink: {
- file_status __st(__data_.__type_);
- if (__ec && !_VSTD_FS::exists(__st))
- *__ec = make_error_code(errc::no_such_file_or_directory);
- else if (__ec)
- __ec->clear();
- return __data_.__type_;
- }
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status __get_status(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterNonSymlink:
- case _IterSymlink:
- case _RefreshSymlinkUnresolved:
- return __status(__p_, __ec);
- case _RefreshNonSymlink:
- case _RefreshSymlink:
- return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_status __get_symlink_status(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterNonSymlink:
- case _IterSymlink:
- return __symlink_status(__p_, __ec);
- case _RefreshNonSymlink:
- return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
- case _RefreshSymlink:
- case _RefreshSymlinkUnresolved:
- return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t __get_size(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterNonSymlink:
- case _IterSymlink:
- case _RefreshSymlinkUnresolved:
- return _VSTD_FS::__file_size(__p_, __ec);
- case _RefreshSymlink:
- case _RefreshNonSymlink: {
- error_code __m_ec;
- file_status __st(__get_ft(&__m_ec));
- __handle_error("in directory_entry::file_size", __ec, __m_ec);
- if (_VSTD_FS::exists(__st) && !_VSTD_FS::is_regular_file(__st)) {
- errc __err_kind = _VSTD_FS::is_directory(__st) ? errc::is_a_directory
- : errc::not_supported;
- __handle_error("in directory_entry::file_size", __ec,
- make_error_code(__err_kind));
- }
- return __data_.__size_;
- }
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- uintmax_t __get_nlink(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterNonSymlink:
- case _IterSymlink:
- case _RefreshSymlinkUnresolved:
- return _VSTD_FS::__hard_link_count(__p_, __ec);
- case _RefreshSymlink:
- case _RefreshNonSymlink: {
- error_code __m_ec;
- (void)__get_ft(&__m_ec);
- __handle_error("in directory_entry::hard_link_count", __ec, __m_ec);
- return __data_.__nlink_;
- }
- }
- _LIBCPP_UNREACHABLE();
- }
-
- _LIBCPP_INLINE_VISIBILITY
- file_time_type __get_write_time(error_code* __ec = nullptr) const {
- switch (__data_.__cache_type_) {
- case _Empty:
- case _IterNonSymlink:
- case _IterSymlink:
- case _RefreshSymlinkUnresolved:
- return _VSTD_FS::__last_write_time(__p_, __ec);
- case _RefreshSymlink:
- case _RefreshNonSymlink: {
- error_code __m_ec;
- file_status __st(__get_ft(&__m_ec));
- __handle_error("in directory_entry::last_write_time", __ec, __m_ec);
- if (_VSTD_FS::exists(__st) &&
- __data_.__write_time_ == file_time_type::min())
- __handle_error("in directory_entry::last_write_time", __ec,
- make_error_code(errc::value_too_large));
- return __data_.__write_time_;
- }
- }
- _LIBCPP_UNREACHABLE();
- }
-
-private:
- _Path __p_;
- __cached_data __data_;
-};
-
-class __dir_element_proxy {
-public:
- inline _LIBCPP_INLINE_VISIBILITY directory_entry operator*() {
- return _VSTD::move(__elem_);
- }
-
-private:
- friend class directory_iterator;
- friend class recursive_directory_iterator;
- explicit __dir_element_proxy(directory_entry const& __e) : __elem_(__e) {}
- __dir_element_proxy(__dir_element_proxy&& __o)
- : __elem_(_VSTD::move(__o.__elem_)) {}
- directory_entry __elem_;
-};
-
-class directory_iterator {
-public:
- typedef directory_entry value_type;
- typedef ptrdiff_t difference_type;
- typedef value_type const* pointer;
- typedef value_type const& reference;
- typedef input_iterator_tag iterator_category;
-
-public:
- //ctor & dtor
- directory_iterator() noexcept {}
-
- explicit directory_iterator(const path& __p)
- : directory_iterator(__p, nullptr) {}
-
- directory_iterator(const path& __p, directory_options __opts)
- : directory_iterator(__p, nullptr, __opts) {}
-
- directory_iterator(const path& __p, error_code& __ec)
- : directory_iterator(__p, &__ec) {}
-
- directory_iterator(const path& __p, directory_options __opts,
- error_code& __ec)
- : directory_iterator(__p, &__ec, __opts) {}
-
- directory_iterator(const directory_iterator&) = default;
- directory_iterator(directory_iterator&&) = default;
- directory_iterator& operator=(const directory_iterator&) = default;
-
- directory_iterator& operator=(directory_iterator&& __o) noexcept {
- // non-default implementation provided to support self-move assign.
- if (this != &__o) {
- __imp_ = _VSTD::move(__o.__imp_);
- }
- return *this;
- }
-
- ~directory_iterator() = default;
-
- const directory_entry& operator*() const {
- _LIBCPP_ASSERT(__imp_, "The end iterator cannot be dereferenced");
- return __dereference();
- }
-
- const directory_entry* operator->() const { return &**this; }
-
- directory_iterator& operator++() { return __increment(); }
-
- __dir_element_proxy operator++(int) {
- __dir_element_proxy __p(**this);
- __increment();
- return __p;
- }
-
- directory_iterator& increment(error_code& __ec) { return __increment(&__ec); }
-
-private:
- inline _LIBCPP_INLINE_VISIBILITY friend bool
- operator==(const directory_iterator& __lhs,
- const directory_iterator& __rhs) noexcept;
-
- // construct the dir_stream
- _LIBCPP_FUNC_VIS
- directory_iterator(const path&, error_code*,
- directory_options = directory_options::none);
-
- _LIBCPP_FUNC_VIS
- directory_iterator& __increment(error_code* __ec = nullptr);
-
- _LIBCPP_FUNC_VIS
- const directory_entry& __dereference() const;
-
-private:
- shared_ptr<__dir_stream> __imp_;
-};
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-operator==(const directory_iterator& __lhs,
- const directory_iterator& __rhs) noexcept {
- return __lhs.__imp_ == __rhs.__imp_;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-operator!=(const directory_iterator& __lhs,
- const directory_iterator& __rhs) noexcept {
- return !(__lhs == __rhs);
-}
-
-// enable directory_iterator range-based for statements
-inline _LIBCPP_INLINE_VISIBILITY directory_iterator
-begin(directory_iterator __iter) noexcept {
- return __iter;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY directory_iterator
-end(const directory_iterator&) noexcept {
- return directory_iterator();
-}
-
-class recursive_directory_iterator {
-public:
- using value_type = directory_entry;
- using difference_type = std::ptrdiff_t;
- using pointer = directory_entry const*;
- using reference = directory_entry const&;
- using iterator_category = std::input_iterator_tag;
-
-public:
- // constructors and destructor
- _LIBCPP_INLINE_VISIBILITY
- recursive_directory_iterator() noexcept : __rec_(false) {}
-
- _LIBCPP_INLINE_VISIBILITY
- explicit recursive_directory_iterator(
- const path& __p, directory_options __xoptions = directory_options::none)
- : recursive_directory_iterator(__p, __xoptions, nullptr) {}
-
- _LIBCPP_INLINE_VISIBILITY
- recursive_directory_iterator(const path& __p, directory_options __xoptions,
- error_code& __ec)
- : recursive_directory_iterator(__p, __xoptions, &__ec) {}
-
- _LIBCPP_INLINE_VISIBILITY
- recursive_directory_iterator(const path& __p, error_code& __ec)
- : recursive_directory_iterator(__p, directory_options::none, &__ec) {}
-
- recursive_directory_iterator(const recursive_directory_iterator&) = default;
- recursive_directory_iterator(recursive_directory_iterator&&) = default;
-
- recursive_directory_iterator&
- operator=(const recursive_directory_iterator&) = default;
-
- _LIBCPP_INLINE_VISIBILITY
- recursive_directory_iterator&
- operator=(recursive_directory_iterator&& __o) noexcept {
- // non-default implementation provided to support self-move assign.
- if (this != &__o) {
- __imp_ = _VSTD::move(__o.__imp_);
- __rec_ = __o.__rec_;
- }
- return *this;
- }
-
- ~recursive_directory_iterator() = default;
-
- _LIBCPP_INLINE_VISIBILITY
- const directory_entry& operator*() const { return __dereference(); }
-
- _LIBCPP_INLINE_VISIBILITY
- const directory_entry* operator->() const { return &__dereference(); }
-
- recursive_directory_iterator& operator++() { return __increment(); }
-
- _LIBCPP_INLINE_VISIBILITY
- __dir_element_proxy operator++(int) {
- __dir_element_proxy __p(**this);
- __increment();
- return __p;
- }
-
- _LIBCPP_INLINE_VISIBILITY
- recursive_directory_iterator& increment(error_code& __ec) {
- return __increment(&__ec);
- }
-
- _LIBCPP_FUNC_VIS directory_options options() const;
- _LIBCPP_FUNC_VIS int depth() const;
-
- _LIBCPP_INLINE_VISIBILITY
- void pop() { __pop(); }
-
- _LIBCPP_INLINE_VISIBILITY
- void pop(error_code& __ec) { __pop(&__ec); }
-
- _LIBCPP_INLINE_VISIBILITY
- bool recursion_pending() const { return __rec_; }
-
- _LIBCPP_INLINE_VISIBILITY
- void disable_recursion_pending() { __rec_ = false; }
-
-private:
- recursive_directory_iterator(const path& __p, directory_options __opt,
- error_code* __ec);
-
- _LIBCPP_FUNC_VIS
- const directory_entry& __dereference() const;
-
- _LIBCPP_FUNC_VIS
- bool __try_recursion(error_code* __ec);
-
- _LIBCPP_FUNC_VIS
- void __advance(error_code* __ec = nullptr);
-
- _LIBCPP_FUNC_VIS
- recursive_directory_iterator& __increment(error_code* __ec = nullptr);
-
- _LIBCPP_FUNC_VIS
- void __pop(error_code* __ec = nullptr);
-
- inline _LIBCPP_INLINE_VISIBILITY friend bool
- operator==(const recursive_directory_iterator&,
- const recursive_directory_iterator&) noexcept;
-
- struct __shared_imp;
- shared_ptr<__shared_imp> __imp_;
- bool __rec_;
-}; // class recursive_directory_iterator
-
-inline _LIBCPP_INLINE_VISIBILITY bool
-operator==(const recursive_directory_iterator& __lhs,
- const recursive_directory_iterator& __rhs) noexcept {
- return __lhs.__imp_ == __rhs.__imp_;
-}
-
-_LIBCPP_INLINE_VISIBILITY
-inline bool operator!=(const recursive_directory_iterator& __lhs,
- const recursive_directory_iterator& __rhs) noexcept {
- return !(__lhs == __rhs);
-}
-// enable recursive_directory_iterator range-based for statements
-inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator
-begin(recursive_directory_iterator __iter) noexcept {
- return __iter;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY recursive_directory_iterator
-end(const recursive_directory_iterator&) noexcept {
- return recursive_directory_iterator();
-}
-
-} // namespace android::hardware::automotive::filesystem
-#ifdef _LIBAUTO_UNDEF_VSTD
-#undef _VSTD
-#undef _LIBAUTO_UNDEF_VSTD
-#endif
-
-#ifndef _LIBAUTO_UNDEF_VSTD_FS
-#pragma pop_macro("_VSTD_FS")
-#else
-#undef _VSTD
-#undef _LIBAUTO_UNDEF_VSTD_FS
-#endif
-
-#endif // !_LIBCPP_CXX03_LANG
-
-_LIBCPP_POP_MACROS
-
-#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION > 8000
-
-#endif // _LIBAUTO_FILESYSTEM
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
deleted file mode 100644
index 0dbf492..0000000
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/directory_iterator.cpp
+++ /dev/null
@@ -1,405 +0,0 @@
-//===------------------ directory_iterator.cpp ----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// TODO(152067309): Remove this once the libc++ upgrade is complete.
-#include <__config>
-#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
-
-/* clang-format off */
-#include "automotive/filesystem"
-#include <__config>
-
-#if defined(_LIBCPP_WIN32API)
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
-#else
-#include <dirent.h>
-#endif
-#include <errno.h>
-
-#include "filesystem_common.h"
-
-namespace android::hardware::automotive::filesystem {
-
-namespace detail {
-namespace {
-
-#if !defined(_LIBCPP_WIN32API)
-template <class DirEntT, class = decltype(DirEntT::d_type)>
-static file_type get_file_type(DirEntT* ent, int) {
- switch (ent->d_type) {
- case DT_BLK:
- return file_type::block;
- case DT_CHR:
- return file_type::character;
- case DT_DIR:
- return file_type::directory;
- case DT_FIFO:
- return file_type::fifo;
- case DT_LNK:
- return file_type::symlink;
- case DT_REG:
- return file_type::regular;
- case DT_SOCK:
- return file_type::socket;
- // Unlike in lstat, hitting "unknown" here simply means that the underlying
- // filesystem doesn't support d_type. Report is as 'none' so we correctly
- // set the cache to empty.
- case DT_UNKNOWN:
- break;
- }
- return file_type::none;
-}
-
-template <class DirEntT>
-static file_type get_file_type(DirEntT* ent, long) {
- return file_type::none;
-}
-
-static pair<string_view, file_type> posix_readdir(DIR* dir_stream,
- error_code& ec) {
- struct dirent* dir_entry_ptr = nullptr;
- errno = 0; // zero errno in order to detect errors
- ec.clear();
- if ((dir_entry_ptr = ::readdir(dir_stream)) == nullptr) {
- if (errno)
- ec = capture_errno();
- return {};
- } else {
- return {dir_entry_ptr->d_name, get_file_type(dir_entry_ptr, 0)};
- }
-}
-#else
-
-static file_type get_file_type(const WIN32_FIND_DATA& data) {
- //auto attrs = data.dwFileAttributes;
- // FIXME(EricWF)
- return file_type::unknown;
-}
-static uintmax_t get_file_size(const WIN32_FIND_DATA& data) {
- return (data.nFileSizeHight * (MAXDWORD + 1)) + data.nFileSizeLow;
-}
-static file_time_type get_write_time(const WIN32_FIND_DATA& data) {
- ULARGE_INTEGER tmp;
- FILETIME& time = data.ftLastWriteTime;
- tmp.u.LowPart = time.dwLowDateTime;
- tmp.u.HighPart = time.dwHighDateTime;
- return file_time_type(file_time_type::duration(time.QuadPart));
-}
-
-#endif
-
-} // namespace
-} // namespace detail
-
-using detail::ErrorHandler;
-
-#if defined(_LIBCPP_WIN32API)
-class __dir_stream {
-public:
- __dir_stream() = delete;
- __dir_stream& operator=(const __dir_stream&) = delete;
-
- __dir_stream(__dir_stream&& __ds) noexcept : __stream_(__ds.__stream_),
- __root_(move(__ds.__root_)),
- __entry_(move(__ds.__entry_)) {
- __ds.__stream_ = INVALID_HANDLE_VALUE;
- }
-
- __dir_stream(const path& root, directory_options opts, error_code& ec)
- : __stream_(INVALID_HANDLE_VALUE), __root_(root) {
- __stream_ = ::FindFirstFileEx(root.c_str(), &__data_);
- if (__stream_ == INVALID_HANDLE_VALUE) {
- ec = error_code(::GetLastError(), generic_category());
- const bool ignore_permission_denied =
- bool(opts & directory_options::skip_permission_denied);
- if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
- ec.clear();
- return;
- }
- }
-
- ~__dir_stream() noexcept {
- if (__stream_ == INVALID_HANDLE_VALUE)
- return;
- close();
- }
-
- bool good() const noexcept { return __stream_ != INVALID_HANDLE_VALUE; }
-
- bool advance(error_code& ec) {
- while (::FindNextFile(__stream_, &__data_)) {
- if (!strcmp(__data_.cFileName, ".") || strcmp(__data_.cFileName, ".."))
- continue;
- // FIXME: Cache more of this
- //directory_entry::__cached_data cdata;
- //cdata.__type_ = get_file_type(__data_);
- //cdata.__size_ = get_file_size(__data_);
- //cdata.__write_time_ = get_write_time(__data_);
- __entry_.__assign_iter_entry(
- __root_ / __data_.cFileName,
- directory_entry::__create_iter_result(get_file_type(__data)));
- return true;
- }
- ec = error_code(::GetLastError(), generic_category());
- close();
- return false;
- }
-
-private:
- error_code close() noexcept {
- error_code ec;
- if (!::FindClose(__stream_))
- ec = error_code(::GetLastError(), generic_category());
- __stream_ = INVALID_HANDLE_VALUE;
- return ec;
- }
-
- HANDLE __stream_{INVALID_HANDLE_VALUE};
- WIN32_FIND_DATA __data_;
-
-public:
- path __root_;
- directory_entry __entry_;
-};
-#else
-class __dir_stream {
-public:
- __dir_stream() = delete;
- __dir_stream& operator=(const __dir_stream&) = delete;
-
- __dir_stream(__dir_stream&& other) noexcept : __stream_(other.__stream_),
- __root_(std::move(other.__root_)),
- __entry_(std::move(other.__entry_)) {
- other.__stream_ = nullptr;
- }
-
- __dir_stream(const path& root, directory_options opts, error_code& ec)
- : __stream_(nullptr), __root_(root) {
- if ((__stream_ = ::opendir(root.c_str())) == nullptr) {
- ec = detail::capture_errno();
- const bool allow_eacess =
- bool(opts & directory_options::skip_permission_denied);
- if (allow_eacess && ec.value() == EACCES)
- ec.clear();
- return;
- }
- advance(ec);
- }
-
- ~__dir_stream() noexcept {
- if (__stream_)
- close();
- }
-
- bool good() const noexcept { return __stream_ != nullptr; }
-
- bool advance(error_code& ec) {
- while (true) {
- auto str_type_pair = detail::posix_readdir(__stream_, ec);
- auto& str = str_type_pair.first;
- if (str == "." || str == "..") {
- continue;
- } else if (ec || str.empty()) {
- close();
- return false;
- } else {
- __entry_.__assign_iter_entry(
- __root_ / str,
- directory_entry::__create_iter_result(str_type_pair.second));
- return true;
- }
- }
- }
-
-private:
- error_code close() noexcept {
- error_code m_ec;
- if (::closedir(__stream_) == -1)
- m_ec = detail::capture_errno();
- __stream_ = nullptr;
- return m_ec;
- }
-
- DIR* __stream_{nullptr};
-
-public:
- path __root_;
- directory_entry __entry_;
-};
-#endif
-
-// directory_iterator
-
-directory_iterator::directory_iterator(const path& p, error_code* ec,
- directory_options opts) {
- ErrorHandler<void> err("directory_iterator::directory_iterator(...)", ec, &p);
-
- error_code m_ec;
- __imp_ = make_shared<__dir_stream>(p, opts, m_ec);
- if (ec)
- *ec = m_ec;
- if (!__imp_->good()) {
- __imp_.reset();
- if (m_ec)
- err.report(m_ec);
- }
-}
-
-directory_iterator& directory_iterator::__increment(error_code* ec) {
- _LIBCPP_ASSERT(__imp_, "Attempting to increment an invalid iterator");
- ErrorHandler<void> err("directory_iterator::operator++()", ec);
-
- error_code m_ec;
- if (!__imp_->advance(m_ec)) {
- path root = std::move(__imp_->__root_);
- __imp_.reset();
- if (m_ec)
- err.report(m_ec, "at root \"%s\"", root);
- }
- return *this;
-}
-
-directory_entry const& directory_iterator::__dereference() const {
- _LIBCPP_ASSERT(__imp_, "Attempting to dereference an invalid iterator");
- return __imp_->__entry_;
-}
-
-// recursive_directory_iterator
-
-struct recursive_directory_iterator::__shared_imp {
- stack<__dir_stream> __stack_;
- directory_options __options_;
-};
-
-recursive_directory_iterator::recursive_directory_iterator(
- const path& p, directory_options opt, error_code* ec)
- : __imp_(nullptr), __rec_(true) {
- ErrorHandler<void> err("recursive_directory_iterator", ec, &p);
-
- error_code m_ec;
- __dir_stream new_s(p, opt, m_ec);
- if (m_ec)
- err.report(m_ec);
- if (m_ec || !new_s.good())
- return;
-
- __imp_ = make_shared<__shared_imp>();
- __imp_->__options_ = opt;
- __imp_->__stack_.push(std::move(new_s));
-}
-
-void recursive_directory_iterator::__pop(error_code* ec) {
- _LIBCPP_ASSERT(__imp_, "Popping the end iterator");
- if (ec)
- ec->clear();
- __imp_->__stack_.pop();
- if (__imp_->__stack_.size() == 0)
- __imp_.reset();
- else
- __advance(ec);
-}
-
-directory_options recursive_directory_iterator::options() const {
- return __imp_->__options_;
-}
-
-int recursive_directory_iterator::depth() const {
- return __imp_->__stack_.size() - 1;
-}
-
-const directory_entry& recursive_directory_iterator::__dereference() const {
- return __imp_->__stack_.top().__entry_;
-}
-
-recursive_directory_iterator&
-recursive_directory_iterator::__increment(error_code* ec) {
- if (ec)
- ec->clear();
- if (recursion_pending()) {
- if (__try_recursion(ec) || (ec && *ec))
- return *this;
- }
- __rec_ = true;
- __advance(ec);
- return *this;
-}
-
-void recursive_directory_iterator::__advance(error_code* ec) {
- ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
-
- const directory_iterator end_it;
- auto& stack = __imp_->__stack_;
- error_code m_ec;
- while (stack.size() > 0) {
- if (stack.top().advance(m_ec))
- return;
- if (m_ec)
- break;
- stack.pop();
- }
-
- if (m_ec) {
- path root = std::move(stack.top().__root_);
- __imp_.reset();
- err.report(m_ec, "at root \"%s\"", root);
- } else {
- __imp_.reset();
- }
-}
-
-bool recursive_directory_iterator::__try_recursion(error_code* ec) {
- ErrorHandler<void> err("recursive_directory_iterator::operator++()", ec);
-
- bool rec_sym = bool(options() & directory_options::follow_directory_symlink);
-
- auto& curr_it = __imp_->__stack_.top();
-
- bool skip_rec = false;
- error_code m_ec;
- if (!rec_sym) {
- file_status st(curr_it.__entry_.__get_sym_ft(&m_ec));
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || is_symlink(st) || !is_directory(st))
- skip_rec = true;
- } else {
- file_status st(curr_it.__entry_.__get_ft(&m_ec));
- if (m_ec && status_known(st))
- m_ec.clear();
- if (m_ec || !is_directory(st))
- skip_rec = true;
- }
-
- if (!skip_rec) {
- __dir_stream new_it(curr_it.__entry_.path(), __imp_->__options_, m_ec);
- if (new_it.good()) {
- __imp_->__stack_.push(std::move(new_it));
- return true;
- }
- }
- if (m_ec) {
- const bool allow_eacess =
- bool(__imp_->__options_ & directory_options::skip_permission_denied);
- if (m_ec.value() == EACCES && allow_eacess) {
- if (ec)
- ec->clear();
- } else {
- path at_ent = std::move(curr_it.__entry_.__p_);
- __imp_.reset();
- err.report(m_ec, "attempting recursion into \"%s\"", at_ent);
- }
- }
- return false;
-}
-
-} // namespace android::hardware::automotive::filesystem
-/* clang-format on */
-
-#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h b/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h
deleted file mode 100644
index 4f44661..0000000
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/filesystem_common.h
+++ /dev/null
@@ -1,441 +0,0 @@
-//===----------------------------------------------------------------------===////
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===////
-/* clang-format off */
-#ifndef AUTO_FILESYSTEM_COMMON_H
-#define AUTO_FILESYSTEM_COMMON_H
-
-#include "automotive/filesystem"
-#include <array>
-#include <chrono>
-#include <cstdlib>
-#include <climits>
-
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/time.h> // for ::utimes as used in __last_write_time
-#include <fcntl.h> /* values for fchmodat */
-
-#if !defined(__APPLE__)
-// We can use the presence of UTIME_OMIT to detect platforms that provide
-// utimensat.
-#if defined(UTIME_OMIT)
-#define _LIBCPP_USE_UTIMENSAT
-#endif
-#endif
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-function"
-#endif
-
-namespace android::hardware::automotive::filesystem {
-using namespace std::chrono;
-
-using std::error_code;
-using std::is_floating_point;
-using std::micro;
-using std::nano;
-using std::ratio;
-
-namespace detail {
-namespace {
-
-static string format_string_imp(const char* msg, ...) {
- // we might need a second shot at this, so pre-emptivly make a copy
- struct GuardVAList {
- va_list& target;
- bool active = true;
- GuardVAList(va_list& target) : target(target), active(true) {}
- void clear() {
- if (active)
- va_end(target);
- active = false;
- }
- ~GuardVAList() {
- if (active)
- va_end(target);
- }
- };
- va_list args;
- va_start(args, msg);
- GuardVAList args_guard(args);
-
- va_list args_cp;
- va_copy(args_cp, args);
- GuardVAList args_copy_guard(args_cp);
-
- std::string result;
-
- array<char, 256> local_buff;
- size_t size_with_null = local_buff.size();
- auto ret = ::vsnprintf(local_buff.data(), size_with_null, msg, args_cp);
-
- args_copy_guard.clear();
-
- // handle empty expansion
- if (ret == 0)
- return result;
- if (static_cast<size_t>(ret) < size_with_null) {
- result.assign(local_buff.data(), static_cast<size_t>(ret));
- return result;
- }
-
- // we did not provide a long enough buffer on our first attempt. The
- // return value is the number of bytes (excluding the null byte) that are
- // needed for formatting.
- size_with_null = static_cast<size_t>(ret) + 1;
- result.__resize_default_init(size_with_null - 1);
- ret = ::vsnprintf(&result[0], size_with_null, msg, args);
- _LIBCPP_ASSERT(static_cast<size_t>(ret) == (size_with_null - 1), "TODO");
-
- return result;
-}
-
-const char* unwrap(string const& s) { return s.c_str(); }
-const char* unwrap(path const& p) { return p.native().c_str(); }
-template <class Arg>
-Arg const& unwrap(Arg const& a) {
- static_assert(!is_class<Arg>::value, "cannot pass class here");
- return a;
-}
-
-template <class... Args>
-string format_string(const char* fmt, Args const&... args) {
- return format_string_imp(fmt, unwrap(args)...);
-}
-
-error_code capture_errno() {
- _LIBCPP_ASSERT(errno, "Expected errno to be non-zero");
- return error_code(errno, generic_category());
-}
-
-template <class T>
-T error_value();
-template <>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 void error_value<void>() {}
-template <>
-bool error_value<bool>() {
- return false;
-}
-template <>
-uintmax_t error_value<uintmax_t>() {
- return uintmax_t(-1);
-}
-template <>
-_LIBCPP_CONSTEXPR_AFTER_CXX11 file_time_type error_value<file_time_type>() {
- return file_time_type::min();
-}
-template <>
-path error_value<path>() {
- return {};
-}
-
-template <class T>
-struct ErrorHandler {
- const char* func_name;
- error_code* ec = nullptr;
- const path* p1 = nullptr;
- const path* p2 = nullptr;
-
- ErrorHandler(const char* fname, error_code* ec, const path* p1 = nullptr,
- const path* p2 = nullptr)
- : func_name(fname), ec(ec), p1(p1), p2(p2) {
- if (ec)
- ec->clear();
- }
-
- T report(const error_code& m_ec) const {
- if (ec) {
- *ec = m_ec;
- return error_value<T>();
- }
- string what = string("in ") + func_name;
- switch (bool(p1) + bool(p2)) {
- case 0:
- __throw_filesystem_error(what, m_ec);
- case 1:
- __throw_filesystem_error(what, *p1, m_ec);
- case 2:
- __throw_filesystem_error(what, *p1, *p2, m_ec);
- }
- _LIBCPP_UNREACHABLE();
- }
-
- template <class... Args>
- T report(const error_code& m_ec, const char* msg, Args const&... args) const {
- if (ec) {
- *ec = m_ec;
- return error_value<T>();
- }
- string what =
- string("in ") + func_name + ": " + format_string(msg, args...);
- switch (bool(p1) + bool(p2)) {
- case 0:
- __throw_filesystem_error(what, m_ec);
- case 1:
- __throw_filesystem_error(what, *p1, m_ec);
- case 2:
- __throw_filesystem_error(what, *p1, *p2, m_ec);
- }
- _LIBCPP_UNREACHABLE();
- }
-
- T report(errc const& err) const { return report(make_error_code(err)); }
-
- template <class... Args>
- T report(errc const& err, const char* msg, Args const&... args) const {
- return report(make_error_code(err), msg, args...);
- }
-
-private:
- ErrorHandler(ErrorHandler const&) = delete;
- ErrorHandler& operator=(ErrorHandler const&) = delete;
-};
-
-using chrono::duration;
-using chrono::duration_cast;
-
-using TimeSpec = struct ::timespec;
-using StatT = struct ::stat;
-
-template <class FileTimeT, class TimeT,
- bool IsFloat = is_floating_point<typename FileTimeT::rep>::value>
-struct time_util_base {
- using rep = typename FileTimeT::rep;
- using fs_duration = typename FileTimeT::duration;
- using fs_seconds = duration<rep>;
- using fs_nanoseconds = duration<rep, nano>;
- using fs_microseconds = duration<rep, micro>;
-
- static constexpr rep max_seconds =
- duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
-
- static constexpr rep max_nsec =
- duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
- fs_seconds(max_seconds))
- .count();
-
- static constexpr rep min_seconds =
- duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
-
- static constexpr rep min_nsec_timespec =
- duration_cast<fs_nanoseconds>(
- (FileTimeT::duration::min() - fs_seconds(min_seconds)) +
- fs_seconds(1))
- .count();
-
-private:
-#if _LIBCPP_STD_VER > 11 && !defined(_LIBCPP_HAS_NO_CXX14_CONSTEXPR)
- static constexpr fs_duration get_min_nsecs() {
- return duration_cast<fs_duration>(
- fs_nanoseconds(min_nsec_timespec) -
- duration_cast<fs_nanoseconds>(fs_seconds(1)));
- }
- // Static assert that these values properly round trip.
- static_assert(fs_seconds(min_seconds) + get_min_nsecs() ==
- FileTimeT::duration::min(),
- "value doesn't roundtrip");
-
- static constexpr bool check_range() {
- // This kinda sucks, but it's what happens when we don't have __int128_t.
- if (sizeof(TimeT) == sizeof(rep)) {
- typedef duration<long long, ratio<3600 * 24 * 365> > Years;
- return duration_cast<Years>(fs_seconds(max_seconds)) > Years(250) &&
- duration_cast<Years>(fs_seconds(min_seconds)) < Years(-250);
- }
- return max_seconds >= numeric_limits<TimeT>::max() &&
- min_seconds <= numeric_limits<TimeT>::min();
- }
- static_assert(check_range(), "the representable range is unacceptable small");
-#endif
-};
-
-template <class FileTimeT, class TimeT>
-struct time_util_base<FileTimeT, TimeT, true> {
- using rep = typename FileTimeT::rep;
- using fs_duration = typename FileTimeT::duration;
- using fs_seconds = duration<rep>;
- using fs_nanoseconds = duration<rep, nano>;
- using fs_microseconds = duration<rep, micro>;
-
- static const rep max_seconds;
- static const rep max_nsec;
- static const rep min_seconds;
- static const rep min_nsec_timespec;
-};
-
-template <class FileTimeT, class TimeT>
-const typename FileTimeT::rep
- time_util_base<FileTimeT, TimeT, true>::max_seconds =
- duration_cast<fs_seconds>(FileTimeT::duration::max()).count();
-
-template <class FileTimeT, class TimeT>
-const typename FileTimeT::rep time_util_base<FileTimeT, TimeT, true>::max_nsec =
- duration_cast<fs_nanoseconds>(FileTimeT::duration::max() -
- fs_seconds(max_seconds))
- .count();
-
-template <class FileTimeT, class TimeT>
-const typename FileTimeT::rep
- time_util_base<FileTimeT, TimeT, true>::min_seconds =
- duration_cast<fs_seconds>(FileTimeT::duration::min()).count();
-
-template <class FileTimeT, class TimeT>
-const typename FileTimeT::rep
- time_util_base<FileTimeT, TimeT, true>::min_nsec_timespec =
- duration_cast<fs_nanoseconds>((FileTimeT::duration::min() -
- fs_seconds(min_seconds)) +
- fs_seconds(1))
- .count();
-
-template <class FileTimeT, class TimeT, class TimeSpecT>
-struct time_util : time_util_base<FileTimeT, TimeT> {
- using Base = time_util_base<FileTimeT, TimeT>;
- using Base::max_nsec;
- using Base::max_seconds;
- using Base::min_nsec_timespec;
- using Base::min_seconds;
-
- using typename Base::fs_duration;
- using typename Base::fs_microseconds;
- using typename Base::fs_nanoseconds;
- using typename Base::fs_seconds;
-
-public:
- template <class CType, class ChronoType>
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool checked_set(CType* out,
- ChronoType time) {
- using Lim = numeric_limits<CType>;
- if (time > Lim::max() || time < Lim::min())
- return false;
- *out = static_cast<CType>(time);
- return true;
- }
-
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(TimeSpecT tm) {
- if (tm.tv_sec >= 0) {
- return tm.tv_sec < max_seconds ||
- (tm.tv_sec == max_seconds && tm.tv_nsec <= max_nsec);
- } else if (tm.tv_sec == (min_seconds - 1)) {
- return tm.tv_nsec >= min_nsec_timespec;
- } else {
- return tm.tv_sec >= min_seconds;
- }
- }
-
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool is_representable(FileTimeT tm) {
- auto secs = duration_cast<fs_seconds>(tm.time_since_epoch());
- auto nsecs = duration_cast<fs_nanoseconds>(tm.time_since_epoch() - secs);
- if (nsecs.count() < 0) {
- secs = secs + fs_seconds(1);
- nsecs = nsecs + fs_seconds(1);
- }
- using TLim = numeric_limits<TimeT>;
- if (secs.count() >= 0)
- return secs.count() <= TLim::max();
- return secs.count() >= TLim::min();
- }
-
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 FileTimeT
- convert_from_timespec(TimeSpecT tm) {
- if (tm.tv_sec >= 0 || tm.tv_nsec == 0) {
- return FileTimeT(fs_seconds(tm.tv_sec) +
- duration_cast<fs_duration>(fs_nanoseconds(tm.tv_nsec)));
- } else { // tm.tv_sec < 0
- auto adj_subsec = duration_cast<fs_duration>(fs_seconds(1) -
- fs_nanoseconds(tm.tv_nsec));
- auto Dur = fs_seconds(tm.tv_sec + 1) - adj_subsec;
- return FileTimeT(Dur);
- }
- }
-
- template <class SubSecT>
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool
- set_times_checked(TimeT* sec_out, SubSecT* subsec_out, FileTimeT tp) {
- auto dur = tp.time_since_epoch();
- auto sec_dur = duration_cast<fs_seconds>(dur);
- auto subsec_dur = duration_cast<fs_nanoseconds>(dur - sec_dur);
- // The tv_nsec and tv_usec fields must not be negative so adjust accordingly
- if (subsec_dur.count() < 0) {
- if (sec_dur.count() > min_seconds) {
- sec_dur = sec_dur - fs_seconds(1);
- subsec_dur = subsec_dur + fs_seconds(1);
- } else {
- subsec_dur = fs_nanoseconds::zero();
- }
- }
- return checked_set(sec_out, sec_dur.count()) &&
- checked_set(subsec_out, subsec_dur.count());
- }
- static _LIBCPP_CONSTEXPR_AFTER_CXX11 bool convert_to_timespec(TimeSpecT& dest,
- FileTimeT tp) {
- if (!is_representable(tp))
- return false;
- return set_times_checked(&dest.tv_sec, &dest.tv_nsec, tp);
- }
-};
-
-using fs_time = time_util<file_time_type, time_t, TimeSpec>;
-
-#if defined(__APPLE__)
-TimeSpec extract_mtime(StatT const& st) { return st.st_mtimespec; }
-TimeSpec extract_atime(StatT const& st) { return st.st_atimespec; }
-#else
-TimeSpec extract_mtime(StatT const& st) { return st.st_mtim; }
-TimeSpec extract_atime(StatT const& st) { return st.st_atim; }
-#endif
-
-// allow the utimes implementation to compile even it we're not going
-// to use it.
-
-bool posix_utimes(const path& p, std::array<TimeSpec, 2> const& TS,
- error_code& ec) {
- using namespace chrono;
- auto Convert = [](long nsec) {
- using int_type = decltype(std::declval< ::timeval>().tv_usec);
- auto dur = duration_cast<microseconds>(nanoseconds(nsec)).count();
- return static_cast<int_type>(dur);
- };
- struct ::timeval ConvertedTS[2] = {{TS[0].tv_sec, Convert(TS[0].tv_nsec)},
- {TS[1].tv_sec, Convert(TS[1].tv_nsec)}};
- if (::utimes(p.c_str(), ConvertedTS) == -1) {
- ec = capture_errno();
- return true;
- }
- return false;
-}
-
-#if defined(_LIBCPP_USE_UTIMENSAT)
-bool posix_utimensat(const path& p, std::array<TimeSpec, 2> const& TS,
- error_code& ec) {
- if (::utimensat(AT_FDCWD, p.c_str(), TS.data(), 0) == -1) {
- ec = capture_errno();
- return true;
- }
- return false;
-}
-#endif
-
-bool set_file_times(const path& p, std::array<TimeSpec, 2> const& TS,
- error_code& ec) {
-#if !defined(_LIBCPP_USE_UTIMENSAT)
- return posix_utimes(p, TS, ec);
-#else
- return posix_utimensat(p, TS, ec);
-#endif
-}
-
-} // namespace
-} // end namespace detail
-
-} // namespace android::hardware::automotive::filesystem
-
-#endif // AUTO_FILESYSTEM_COMMON_H
-/* clang-format on */
diff --git a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp b/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
deleted file mode 100644
index 6a76bdc..0000000
--- a/automotive/can/1.0/default/libc++fs/src/filesystem/operations.cpp
+++ /dev/null
@@ -1,1780 +0,0 @@
-//===--------------------- filesystem/ops.cpp -----------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// TODO(152067309): Remove this once the libc++ upgrade is complete.
-#include <__config>
-#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
-
-/* clang-format off */
-#include "automotive/filesystem"
-#include <array>
-#include <iterator>
-#include <fstream>
-#include <random> /* for unique_path */
-#include <string_view>
-#include <type_traits>
-#include <vector>
-#include <cstdlib>
-#include <climits>
-
-#include "filesystem_common.h"
-
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <time.h>
-#include <fcntl.h> /* values for fchmodat */
-
-#if defined(__linux__)
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
-#include <sys/sendfile.h>
-#define _LIBCPP_USE_SENDFILE
-#endif
-#elif defined(__APPLE__) || __has_include(<copyfile.h>)
-#include <copyfile.h>
-#define _LIBCPP_USE_COPYFILE
-#endif
-
-#if !defined(__APPLE__)
-#define _LIBCPP_USE_CLOCK_GETTIME
-#endif
-
-#if !defined(CLOCK_REALTIME) || !defined(_LIBCPP_USE_CLOCK_GETTIME)
-#include <sys/time.h> // for gettimeofday and timeval
-#endif // !defined(CLOCK_REALTIME)
-
-#if defined(_LIBCPP_COMPILER_GCC)
-#if _GNUC_VER < 500
-#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-#endif
-
-namespace android::hardware::automotive::filesystem {
-
-#ifdef _VSTD_FS
-#pragma push_macro("_VSTD_FS")
-#else
-#define _LIBAUTO_UNDEF_VSTD_FS
-#endif
-#define _VSTD_FS android::hardware::automotive::filesystem
-
-namespace {
-namespace parser {
-
-using string_view_t = path::__string_view;
-using string_view_pair = pair<string_view_t, string_view_t>;
-using PosPtr = path::value_type const*;
-
-struct PathParser {
- enum ParserState : unsigned char {
- // Zero is a special sentinel value used by default constructed iterators.
- PS_BeforeBegin = path::iterator::_BeforeBegin,
- PS_InRootName = path::iterator::_InRootName,
- PS_InRootDir = path::iterator::_InRootDir,
- PS_InFilenames = path::iterator::_InFilenames,
- PS_InTrailingSep = path::iterator::_InTrailingSep,
- PS_AtEnd = path::iterator::_AtEnd
- };
-
- const string_view_t Path;
- string_view_t RawEntry;
- ParserState State;
-
-private:
- PathParser(string_view_t P, ParserState State) noexcept : Path(P),
- State(State) {}
-
-public:
- PathParser(string_view_t P, string_view_t E, unsigned char S)
- : Path(P), RawEntry(E), State(static_cast<ParserState>(S)) {
- // S cannot be '0' or PS_BeforeBegin.
- }
-
- static PathParser CreateBegin(string_view_t P) noexcept {
- PathParser PP(P, PS_BeforeBegin);
- PP.increment();
- return PP;
- }
-
- static PathParser CreateEnd(string_view_t P) noexcept {
- PathParser PP(P, PS_AtEnd);
- return PP;
- }
-
- PosPtr peek() const noexcept {
- auto TkEnd = getNextTokenStartPos();
- auto End = getAfterBack();
- return TkEnd == End ? nullptr : TkEnd;
- }
-
- void increment() noexcept {
- const PosPtr End = getAfterBack();
- const PosPtr Start = getNextTokenStartPos();
- if (Start == End)
- return makeState(PS_AtEnd);
-
- switch (State) {
- case PS_BeforeBegin: {
- PosPtr TkEnd = consumeSeparator(Start, End);
- if (TkEnd)
- return makeState(PS_InRootDir, Start, TkEnd);
- else
- return makeState(PS_InFilenames, Start, consumeName(Start, End));
- }
- case PS_InRootDir:
- return makeState(PS_InFilenames, Start, consumeName(Start, End));
-
- case PS_InFilenames: {
- PosPtr SepEnd = consumeSeparator(Start, End);
- if (SepEnd != End) {
- PosPtr TkEnd = consumeName(SepEnd, End);
- if (TkEnd)
- return makeState(PS_InFilenames, SepEnd, TkEnd);
- }
- return makeState(PS_InTrailingSep, Start, SepEnd);
- }
-
- case PS_InTrailingSep:
- return makeState(PS_AtEnd);
-
- case PS_InRootName:
- case PS_AtEnd:
- _LIBCPP_UNREACHABLE();
- }
- }
-
- void decrement() noexcept {
- const PosPtr REnd = getBeforeFront();
- const PosPtr RStart = getCurrentTokenStartPos() - 1;
- if (RStart == REnd) // we're decrementing the begin
- return makeState(PS_BeforeBegin);
-
- switch (State) {
- case PS_AtEnd: {
- // Try to consume a trailing separator or root directory first.
- if (PosPtr SepEnd = consumeSeparator(RStart, REnd)) {
- if (SepEnd == REnd)
- return makeState(PS_InRootDir, Path.data(), RStart + 1);
- return makeState(PS_InTrailingSep, SepEnd + 1, RStart + 1);
- } else {
- PosPtr TkStart = consumeName(RStart, REnd);
- return makeState(PS_InFilenames, TkStart + 1, RStart + 1);
- }
- }
- case PS_InTrailingSep:
- return makeState(PS_InFilenames, consumeName(RStart, REnd) + 1,
- RStart + 1);
- case PS_InFilenames: {
- PosPtr SepEnd = consumeSeparator(RStart, REnd);
- if (SepEnd == REnd)
- return makeState(PS_InRootDir, Path.data(), RStart + 1);
- PosPtr TkEnd = consumeName(SepEnd, REnd);
- return makeState(PS_InFilenames, TkEnd + 1, SepEnd + 1);
- }
- case PS_InRootDir:
- // return makeState(PS_InRootName, Path.data(), RStart + 1);
- case PS_InRootName:
- case PS_BeforeBegin:
- _LIBCPP_UNREACHABLE();
- }
- }
-
- /// \brief Return a view with the "preferred representation" of the current
- /// element. For example trailing separators are represented as a '.'
- string_view_t operator*() const noexcept {
- switch (State) {
- case PS_BeforeBegin:
- case PS_AtEnd:
- return "";
- case PS_InRootDir:
- return "/";
- case PS_InTrailingSep:
- return "";
- case PS_InRootName:
- case PS_InFilenames:
- return RawEntry;
- }
- _LIBCPP_UNREACHABLE();
- }
-
- explicit operator bool() const noexcept {
- return State != PS_BeforeBegin && State != PS_AtEnd;
- }
-
- PathParser& operator++() noexcept {
- increment();
- return *this;
- }
-
- PathParser& operator--() noexcept {
- decrement();
- return *this;
- }
-
- bool atEnd() const noexcept {
- return State == PS_AtEnd;
- }
-
- bool inRootDir() const noexcept {
- return State == PS_InRootDir;
- }
-
- bool inRootName() const noexcept {
- return State == PS_InRootName;
- }
-
- bool inRootPath() const noexcept {
- return inRootName() || inRootDir();
- }
-
-private:
- void makeState(ParserState NewState, PosPtr Start, PosPtr End) noexcept {
- State = NewState;
- RawEntry = string_view_t(Start, End - Start);
- }
- void makeState(ParserState NewState) noexcept {
- State = NewState;
- RawEntry = {};
- }
-
- PosPtr getAfterBack() const noexcept { return Path.data() + Path.size(); }
-
- PosPtr getBeforeFront() const noexcept { return Path.data() - 1; }
-
- /// \brief Return a pointer to the first character after the currently
- /// lexed element.
- PosPtr getNextTokenStartPos() const noexcept {
- switch (State) {
- case PS_BeforeBegin:
- return Path.data();
- case PS_InRootName:
- case PS_InRootDir:
- case PS_InFilenames:
- return &RawEntry.back() + 1;
- case PS_InTrailingSep:
- case PS_AtEnd:
- return getAfterBack();
- }
- _LIBCPP_UNREACHABLE();
- }
-
- /// \brief Return a pointer to the first character in the currently lexed
- /// element.
- PosPtr getCurrentTokenStartPos() const noexcept {
- switch (State) {
- case PS_BeforeBegin:
- case PS_InRootName:
- return &Path.front();
- case PS_InRootDir:
- case PS_InFilenames:
- case PS_InTrailingSep:
- return &RawEntry.front();
- case PS_AtEnd:
- return &Path.back() + 1;
- }
- _LIBCPP_UNREACHABLE();
- }
-
- PosPtr consumeSeparator(PosPtr P, PosPtr End) const noexcept {
- if (P == End || *P != '/')
- return nullptr;
- const int Inc = P < End ? 1 : -1;
- P += Inc;
- while (P != End && *P == '/')
- P += Inc;
- return P;
- }
-
- PosPtr consumeName(PosPtr P, PosPtr End) const noexcept {
- if (P == End || *P == '/')
- return nullptr;
- const int Inc = P < End ? 1 : -1;
- P += Inc;
- while (P != End && *P != '/')
- P += Inc;
- return P;
- }
-};
-
-string_view_pair separate_filename(string_view_t const& s) {
- if (s == "." || s == ".." || s.empty())
- return string_view_pair{s, ""};
- auto pos = s.find_last_of('.');
- if (pos == string_view_t::npos || pos == 0)
- return string_view_pair{s, string_view_t{}};
- return string_view_pair{s.substr(0, pos), s.substr(pos)};
-}
-
-string_view_t createView(PosPtr S, PosPtr E) noexcept {
- return {S, static_cast<size_t>(E - S) + 1};
-}
-
-} // namespace parser
-} // namespace
-
-// POSIX HELPERS
-
-namespace detail {
-namespace {
-
-using value_type = path::value_type;
-using string_type = path::string_type;
-
-struct FileDescriptor {
- const path& name;
- int fd = -1;
- StatT m_stat;
- file_status m_status;
-
- template <class... Args>
- static FileDescriptor create(const path* p, error_code& ec, Args... args) {
- ec.clear();
- int fd;
- if ((fd = ::open(p->c_str(), args...)) == -1) {
- ec = capture_errno();
- return FileDescriptor{p};
- }
- return FileDescriptor(p, fd);
- }
-
- template <class... Args>
- static FileDescriptor create_with_status(const path* p, error_code& ec,
- Args... args) {
- FileDescriptor fd = create(p, ec, args...);
- if (!ec)
- fd.refresh_status(ec);
-
- return fd;
- }
-
- file_status get_status() const { return m_status; }
- StatT const& get_stat() const { return m_stat; }
-
- bool status_known() const { return _VSTD_FS::status_known(m_status); }
-
- file_status refresh_status(error_code& ec);
-
- void close() noexcept {
- if (fd != -1)
- ::close(fd);
- fd = -1;
- }
-
- FileDescriptor(FileDescriptor&& other)
- : name(other.name), fd(other.fd), m_stat(other.m_stat),
- m_status(other.m_status) {
- other.fd = -1;
- other.m_status = file_status{};
- }
-
- ~FileDescriptor() { close(); }
-
- FileDescriptor(FileDescriptor const&) = delete;
- FileDescriptor& operator=(FileDescriptor const&) = delete;
-
-private:
- explicit FileDescriptor(const path* p, int fd = -1) : name(*p), fd(fd) {}
-};
-
-perms posix_get_perms(const StatT& st) noexcept {
- return static_cast<perms>(st.st_mode) & perms::mask;
-}
-
-::mode_t posix_convert_perms(perms prms) {
- return static_cast< ::mode_t>(prms & perms::mask);
-}
-
-file_status create_file_status(error_code& m_ec, path const& p,
- const StatT& path_stat, error_code* ec) {
- if (ec)
- *ec = m_ec;
- if (m_ec && (m_ec.value() == ENOENT || m_ec.value() == ENOTDIR)) {
- return file_status(file_type::not_found);
- } else if (m_ec) {
- ErrorHandler<void> err("posix_stat", ec, &p);
- err.report(m_ec, "failed to determine attributes for the specified path");
- return file_status(file_type::none);
- }
- // else
-
- file_status fs_tmp;
- auto const mode = path_stat.st_mode;
- if (S_ISLNK(mode))
- fs_tmp.type(file_type::symlink);
- else if (S_ISREG(mode))
- fs_tmp.type(file_type::regular);
- else if (S_ISDIR(mode))
- fs_tmp.type(file_type::directory);
- else if (S_ISBLK(mode))
- fs_tmp.type(file_type::block);
- else if (S_ISCHR(mode))
- fs_tmp.type(file_type::character);
- else if (S_ISFIFO(mode))
- fs_tmp.type(file_type::fifo);
- else if (S_ISSOCK(mode))
- fs_tmp.type(file_type::socket);
- else
- fs_tmp.type(file_type::unknown);
-
- fs_tmp.permissions(detail::posix_get_perms(path_stat));
- return fs_tmp;
-}
-
-file_status posix_stat(path const& p, StatT& path_stat, error_code* ec) {
- error_code m_ec;
- if (::stat(p.c_str(), &path_stat) == -1)
- m_ec = detail::capture_errno();
- return create_file_status(m_ec, p, path_stat, ec);
-}
-
-file_status posix_stat(path const& p, error_code* ec) {
- StatT path_stat;
- return posix_stat(p, path_stat, ec);
-}
-
-file_status posix_lstat(path const& p, StatT& path_stat, error_code* ec) {
- error_code m_ec;
- if (::lstat(p.c_str(), &path_stat) == -1)
- m_ec = detail::capture_errno();
- return create_file_status(m_ec, p, path_stat, ec);
-}
-
-file_status posix_lstat(path const& p, error_code* ec) {
- StatT path_stat;
- return posix_lstat(p, path_stat, ec);
-}
-
-bool posix_ftruncate(const FileDescriptor& fd, size_t to_size, error_code& ec) {
- if (::ftruncate(fd.fd, to_size) == -1) {
- ec = capture_errno();
- return true;
- }
- ec.clear();
- return false;
-}
-
-bool posix_fchmod(const FileDescriptor& fd, const StatT& st, error_code& ec) {
- if (::fchmod(fd.fd, st.st_mode) == -1) {
- ec = capture_errno();
- return true;
- }
- ec.clear();
- return false;
-}
-
-bool stat_equivalent(const StatT& st1, const StatT& st2) {
- return (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino);
-}
-
-file_status FileDescriptor::refresh_status(error_code& ec) {
- // FD must be open and good.
- m_status = file_status{};
- m_stat = {};
- error_code m_ec;
- if (::fstat(fd, &m_stat) == -1)
- m_ec = capture_errno();
- m_status = create_file_status(m_ec, name, m_stat, &ec);
- return m_status;
-}
-} // namespace
-} // end namespace detail
-
-using detail::capture_errno;
-using detail::ErrorHandler;
-using detail::StatT;
-using detail::TimeSpec;
-using parser::createView;
-using parser::PathParser;
-using parser::string_view_t;
-
-const bool _FilesystemClock::is_steady;
-
-_FilesystemClock::time_point _FilesystemClock::now() noexcept {
- typedef chrono::duration<rep> __secs;
-#if defined(_LIBCPP_USE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
- typedef chrono::duration<rep, nano> __nsecs;
- struct timespec tp;
- if (0 != clock_gettime(CLOCK_REALTIME, &tp))
- __throw_system_error(errno, "clock_gettime(CLOCK_REALTIME) failed");
- return time_point(__secs(tp.tv_sec) +
- chrono::duration_cast<duration>(__nsecs(tp.tv_nsec)));
-#else
- typedef chrono::duration<rep, micro> __microsecs;
- timeval tv;
- gettimeofday(&tv, 0);
- return time_point(__secs(tv.tv_sec) + __microsecs(tv.tv_usec));
-#endif // _LIBCPP_USE_CLOCK_GETTIME && CLOCK_REALTIME
-}
-
-filesystem_error::~filesystem_error() {}
-
-void filesystem_error::__create_what(int __num_paths) {
- const char* derived_what = system_error::what();
- __storage_->__what_ = [&]() -> string {
- const char* p1 = path1().native().empty() ? "\"\"" : path1().c_str();
- const char* p2 = path2().native().empty() ? "\"\"" : path2().c_str();
- switch (__num_paths) {
- default:
- return detail::format_string("filesystem error: %s", derived_what);
- case 1:
- return detail::format_string("filesystem error: %s [%s]", derived_what,
- p1);
- case 2:
- return detail::format_string("filesystem error: %s [%s] [%s]",
- derived_what, p1, p2);
- }
- }();
-}
-
-static path __do_absolute(const path& p, path* cwd, error_code* ec) {
- if (ec)
- ec->clear();
- if (p.is_absolute())
- return p;
- *cwd = __current_path(ec);
- if (ec && *ec)
- return {};
- return (*cwd) / p;
-}
-
-path __absolute(const path& p, error_code* ec) {
- path cwd;
- return __do_absolute(p, &cwd, ec);
-}
-
-path __canonical(path const& orig_p, error_code* ec) {
- path cwd;
- ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
-
- path p = __do_absolute(orig_p, &cwd, ec);
- char buff[PATH_MAX + 1];
- char* ret;
- if ((ret = ::realpath(p.c_str(), buff)) == nullptr)
- return err.report(capture_errno());
- return {ret};
-}
-
-void __copy(const path& from, const path& to, copy_options options,
- error_code* ec) {
- ErrorHandler<void> err("copy", ec, &from, &to);
-
- const bool sym_status = bool(
- options & (copy_options::create_symlinks | copy_options::skip_symlinks));
-
- const bool sym_status2 = bool(options & copy_options::copy_symlinks);
-
- error_code m_ec1;
- StatT f_st = {};
- const file_status f = sym_status || sym_status2
- ? detail::posix_lstat(from, f_st, &m_ec1)
- : detail::posix_stat(from, f_st, &m_ec1);
- if (m_ec1)
- return err.report(m_ec1);
-
- StatT t_st = {};
- const file_status t = sym_status ? detail::posix_lstat(to, t_st, &m_ec1)
- : detail::posix_stat(to, t_st, &m_ec1);
-
- if (not status_known(t))
- return err.report(m_ec1);
-
- if (!exists(f) || is_other(f) || is_other(t) ||
- (is_directory(f) && is_regular_file(t)) ||
- detail::stat_equivalent(f_st, t_st)) {
- return err.report(errc::function_not_supported);
- }
-
- if (ec)
- ec->clear();
-
- if (is_symlink(f)) {
- if (bool(copy_options::skip_symlinks & options)) {
- // do nothing
- } else if (not exists(t)) {
- __copy_symlink(from, to, ec);
- } else {
- return err.report(errc::file_exists);
- }
- return;
- } else if (is_regular_file(f)) {
- if (bool(copy_options::directories_only & options)) {
- // do nothing
- } else if (bool(copy_options::create_symlinks & options)) {
- __create_symlink(from, to, ec);
- } else if (bool(copy_options::create_hard_links & options)) {
- __create_hard_link(from, to, ec);
- } else if (is_directory(t)) {
- __copy_file(from, to / from.filename(), options, ec);
- } else {
- __copy_file(from, to, options, ec);
- }
- return;
- } else if (is_directory(f) && bool(copy_options::create_symlinks & options)) {
- return err.report(errc::is_a_directory);
- } else if (is_directory(f) && (bool(copy_options::recursive & options) ||
- copy_options::none == options)) {
-
- if (!exists(t)) {
- // create directory to with attributes from 'from'.
- __create_directory(to, from, ec);
- if (ec && *ec) {
- return;
- }
- }
- directory_iterator it =
- ec ? directory_iterator(from, *ec) : directory_iterator(from);
- if (ec && *ec) {
- return;
- }
- error_code m_ec2;
- for (; it != directory_iterator(); it.increment(m_ec2)) {
- if (m_ec2) {
- return err.report(m_ec2);
- }
- __copy(it->path(), to / it->path().filename(),
- options | copy_options::__in_recursive_copy, ec);
- if (ec && *ec) {
- return;
- }
- }
- }
-}
-
-namespace detail {
-namespace {
-
-#ifdef _LIBCPP_USE_SENDFILE
-bool copy_file_impl_sendfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
- error_code& ec) {
-
- size_t count = read_fd.get_stat().st_size;
- do {
- ssize_t res;
- if ((res = ::sendfile(write_fd.fd, read_fd.fd, nullptr, count)) == -1) {
- ec = capture_errno();
- return false;
- }
- count -= res;
- } while (count > 0);
-
- ec.clear();
-
- return true;
-}
-#elif defined(_LIBCPP_USE_COPYFILE)
-bool copy_file_impl_copyfile(FileDescriptor& read_fd, FileDescriptor& write_fd,
- error_code& ec) {
- struct CopyFileState {
- copyfile_state_t state;
- CopyFileState() { state = copyfile_state_alloc(); }
- ~CopyFileState() { copyfile_state_free(state); }
-
- private:
- CopyFileState(CopyFileState const&) = delete;
- CopyFileState& operator=(CopyFileState const&) = delete;
- };
-
- CopyFileState cfs;
- if (fcopyfile(read_fd.fd, write_fd.fd, cfs.state, COPYFILE_DATA) < 0) {
- ec = capture_errno();
- return false;
- }
-
- ec.clear();
- return true;
-}
-#endif
-
-// Note: This function isn't guarded by ifdef's even though it may be unused
-// in order to assure it still compiles.
-__attribute__((unused)) bool copy_file_impl_default(FileDescriptor& read_fd,
- FileDescriptor& write_fd,
- error_code& ec) {
- ifstream in;
- in.__open(read_fd.fd, ios::binary);
- if (!in.is_open()) {
- // This assumes that __open didn't reset the error code.
- ec = capture_errno();
- return false;
- }
- ofstream out;
- out.__open(write_fd.fd, ios::binary);
- if (!out.is_open()) {
- ec = capture_errno();
- return false;
- }
-
- if (in.good() && out.good()) {
- using InIt = istreambuf_iterator<char>;
- using OutIt = ostreambuf_iterator<char>;
- InIt bin(in);
- InIt ein;
- OutIt bout(out);
- copy(bin, ein, bout);
- }
- if (out.fail() || in.fail()) {
- ec = make_error_code(errc::io_error);
- return false;
- }
-
- ec.clear();
- return true;
-}
-
-bool copy_file_impl(FileDescriptor& from, FileDescriptor& to, error_code& ec) {
-#if defined(_LIBCPP_USE_SENDFILE)
- return copy_file_impl_sendfile(from, to, ec);
-#elif defined(_LIBCPP_USE_COPYFILE)
- return copy_file_impl_copyfile(from, to, ec);
-#else
- return copy_file_impl_default(from, to, ec);
-#endif
-}
-
-} // namespace
-} // namespace detail
-
-bool __copy_file(const path& from, const path& to, copy_options options,
- error_code* ec) {
- using detail::FileDescriptor;
- ErrorHandler<bool> err("copy_file", ec, &to, &from);
-
- error_code m_ec;
- FileDescriptor from_fd =
- FileDescriptor::create_with_status(&from, m_ec, O_RDONLY | O_NONBLOCK);
- if (m_ec)
- return err.report(m_ec);
-
- auto from_st = from_fd.get_status();
- StatT const& from_stat = from_fd.get_stat();
- if (!is_regular_file(from_st)) {
- if (not m_ec)
- m_ec = make_error_code(errc::not_supported);
- return err.report(m_ec);
- }
-
- const bool skip_existing = bool(copy_options::skip_existing & options);
- const bool update_existing = bool(copy_options::update_existing & options);
- const bool overwrite_existing =
- bool(copy_options::overwrite_existing & options);
-
- StatT to_stat_path;
- file_status to_st = detail::posix_stat(to, to_stat_path, &m_ec);
- if (!status_known(to_st))
- return err.report(m_ec);
-
- const bool to_exists = exists(to_st);
- if (to_exists && !is_regular_file(to_st))
- return err.report(errc::not_supported);
-
- if (to_exists && detail::stat_equivalent(from_stat, to_stat_path))
- return err.report(errc::file_exists);
-
- if (to_exists && skip_existing)
- return false;
-
- bool ShouldCopy = [&]() {
- if (to_exists && update_existing) {
- auto from_time = detail::extract_mtime(from_stat);
- auto to_time = detail::extract_mtime(to_stat_path);
- if (from_time.tv_sec < to_time.tv_sec)
- return false;
- if (from_time.tv_sec == to_time.tv_sec &&
- from_time.tv_nsec <= to_time.tv_nsec)
- return false;
- return true;
- }
- if (!to_exists || overwrite_existing)
- return true;
- return err.report(errc::file_exists);
- }();
- if (!ShouldCopy)
- return false;
-
- // Don't truncate right away. We may not be opening the file we originally
- // looked at; we'll check this later.
- int to_open_flags = O_WRONLY;
- if (!to_exists)
- to_open_flags |= O_CREAT;
- FileDescriptor to_fd = FileDescriptor::create_with_status(
- &to, m_ec, to_open_flags, from_stat.st_mode);
- if (m_ec)
- return err.report(m_ec);
-
- if (to_exists) {
- // Check that the file we initially stat'ed is equivalent to the one
- // we opened.
- // FIXME: report this better.
- if (!detail::stat_equivalent(to_stat_path, to_fd.get_stat()))
- return err.report(errc::bad_file_descriptor);
-
- // Set the permissions and truncate the file we opened.
- if (detail::posix_fchmod(to_fd, from_stat, m_ec))
- return err.report(m_ec);
- if (detail::posix_ftruncate(to_fd, 0, m_ec))
- return err.report(m_ec);
- }
-
- if (!copy_file_impl(from_fd, to_fd, m_ec)) {
- // FIXME: Remove the dest file if we failed, and it didn't exist previously.
- return err.report(m_ec);
- }
-
- return true;
-}
-
-void __copy_symlink(const path& existing_symlink, const path& new_symlink,
- error_code* ec) {
- const path real_path(__read_symlink(existing_symlink, ec));
- if (ec && *ec) {
- return;
- }
- // NOTE: proposal says you should detect if you should call
- // create_symlink or create_directory_symlink. I don't think this
- // is needed with POSIX
- __create_symlink(real_path, new_symlink, ec);
-}
-
-bool __create_directories(const path& p, error_code* ec) {
- ErrorHandler<bool> err("create_directories", ec, &p);
-
- error_code m_ec;
- auto const st = detail::posix_stat(p, &m_ec);
- if (!status_known(st))
- return err.report(m_ec);
- else if (is_directory(st))
- return false;
- else if (exists(st))
- return err.report(errc::file_exists);
-
- const path parent = p.parent_path();
- if (!parent.empty()) {
- const file_status parent_st = status(parent, m_ec);
- if (not status_known(parent_st))
- return err.report(m_ec);
- if (not exists(parent_st)) {
- __create_directories(parent, ec);
- if (ec && *ec) {
- return false;
- }
- }
- }
- return __create_directory(p, ec);
-}
-
-bool __create_directory(const path& p, error_code* ec) {
- ErrorHandler<bool> err("create_directory", ec, &p);
-
- if (::mkdir(p.c_str(), static_cast<int>(perms::all)) == 0)
- return true;
- if (errno != EEXIST)
- err.report(capture_errno());
- return false;
-}
-
-bool __create_directory(path const& p, path const& attributes, error_code* ec) {
- ErrorHandler<bool> err("create_directory", ec, &p, &attributes);
-
- StatT attr_stat;
- error_code mec;
- auto st = detail::posix_stat(attributes, attr_stat, &mec);
- if (!status_known(st))
- return err.report(mec);
- if (!is_directory(st))
- return err.report(errc::not_a_directory,
- "the specified attribute path is invalid");
-
- if (::mkdir(p.c_str(), attr_stat.st_mode) == 0)
- return true;
- if (errno != EEXIST)
- err.report(capture_errno());
- return false;
-}
-
-void __create_directory_symlink(path const& from, path const& to,
- error_code* ec) {
- ErrorHandler<void> err("create_directory_symlink", ec, &from, &to);
- if (::symlink(from.c_str(), to.c_str()) != 0)
- return err.report(capture_errno());
-}
-
-void __create_hard_link(const path& from, const path& to, error_code* ec) {
- ErrorHandler<void> err("create_hard_link", ec, &from, &to);
- if (::link(from.c_str(), to.c_str()) == -1)
- return err.report(capture_errno());
-}
-
-void __create_symlink(path const& from, path const& to, error_code* ec) {
- ErrorHandler<void> err("create_symlink", ec, &from, &to);
- if (::symlink(from.c_str(), to.c_str()) == -1)
- return err.report(capture_errno());
-}
-
-path __current_path(error_code* ec) {
- ErrorHandler<path> err("current_path", ec);
-
- auto size = ::pathconf(".", _PC_PATH_MAX);
- _LIBCPP_ASSERT(size >= 0, "pathconf returned a 0 as max size");
-
- auto buff = unique_ptr<char[]>(new char[size + 1]);
- char* ret;
- if ((ret = ::getcwd(buff.get(), static_cast<size_t>(size))) == nullptr)
- return err.report(capture_errno(), "call to getcwd failed");
-
- return {buff.get()};
-}
-
-void __current_path(const path& p, error_code* ec) {
- ErrorHandler<void> err("current_path", ec, &p);
- if (::chdir(p.c_str()) == -1)
- err.report(capture_errno());
-}
-
-bool __equivalent(const path& p1, const path& p2, error_code* ec) {
- ErrorHandler<bool> err("equivalent", ec, &p1, &p2);
-
- error_code ec1, ec2;
- StatT st1 = {}, st2 = {};
- auto s1 = detail::posix_stat(p1.native(), st1, &ec1);
- if (!exists(s1))
- return err.report(errc::not_supported);
- auto s2 = detail::posix_stat(p2.native(), st2, &ec2);
- if (!exists(s2))
- return err.report(errc::not_supported);
-
- return detail::stat_equivalent(st1, st2);
-}
-
-uintmax_t __file_size(const path& p, error_code* ec) {
- ErrorHandler<uintmax_t> err("file_size", ec, &p);
-
- error_code m_ec;
- StatT st;
- file_status fst = detail::posix_stat(p, st, &m_ec);
- if (!exists(fst) || !is_regular_file(fst)) {
- errc error_kind =
- is_directory(fst) ? errc::is_a_directory : errc::not_supported;
- if (!m_ec)
- m_ec = make_error_code(error_kind);
- return err.report(m_ec);
- }
- // is_regular_file(p) == true
- return static_cast<uintmax_t>(st.st_size);
-}
-
-uintmax_t __hard_link_count(const path& p, error_code* ec) {
- ErrorHandler<uintmax_t> err("hard_link_count", ec, &p);
-
- error_code m_ec;
- StatT st;
- detail::posix_stat(p, st, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- return static_cast<uintmax_t>(st.st_nlink);
-}
-
-bool __fs_is_empty(const path& p, error_code* ec) {
- ErrorHandler<bool> err("is_empty", ec, &p);
-
- error_code m_ec;
- StatT pst;
- auto st = detail::posix_stat(p, pst, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- else if (!is_directory(st) && !is_regular_file(st))
- return err.report(errc::not_supported);
- else if (is_directory(st)) {
- auto it = ec ? directory_iterator(p, *ec) : directory_iterator(p);
- if (ec && *ec)
- return false;
- return it == directory_iterator{};
- } else if (is_regular_file(st))
- return static_cast<uintmax_t>(pst.st_size) == 0;
-
- _LIBCPP_UNREACHABLE();
-}
-
-static file_time_type __extract_last_write_time(const path& p, const StatT& st,
- error_code* ec) {
- using detail::fs_time;
- ErrorHandler<file_time_type> err("last_write_time", ec, &p);
-
- auto ts = detail::extract_mtime(st);
- if (!fs_time::is_representable(ts))
- return err.report(errc::value_too_large);
-
- return fs_time::convert_from_timespec(ts);
-}
-
-file_time_type __last_write_time(const path& p, error_code* ec) {
- using namespace chrono;
- ErrorHandler<file_time_type> err("last_write_time", ec, &p);
-
- error_code m_ec;
- StatT st;
- detail::posix_stat(p, st, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- return __extract_last_write_time(p, st, ec);
-}
-
-void __last_write_time(const path& p, file_time_type new_time, error_code* ec) {
- using detail::fs_time;
- ErrorHandler<void> err("last_write_time", ec, &p);
-
- error_code m_ec;
- array<TimeSpec, 2> tbuf;
-#if !defined(_LIBCPP_USE_UTIMENSAT)
- // This implementation has a race condition between determining the
- // last access time and attempting to set it to the same value using
- // ::utimes
- StatT st;
- file_status fst = detail::posix_stat(p, st, &m_ec);
- if (m_ec)
- return err.report(m_ec);
- tbuf[0] = detail::extract_atime(st);
-#else
- tbuf[0].tv_sec = 0;
- tbuf[0].tv_nsec = UTIME_OMIT;
-#endif
- if (!fs_time::convert_to_timespec(tbuf[1], new_time))
- return err.report(errc::value_too_large);
-
- detail::set_file_times(p, tbuf, m_ec);
- if (m_ec)
- return err.report(m_ec);
-}
-
-void __permissions(const path& p, perms prms, perm_options opts,
- error_code* ec) {
- ErrorHandler<void> err("permissions", ec, &p);
-
- auto has_opt = [&](perm_options o) { return bool(o & opts); };
- const bool resolve_symlinks = !has_opt(perm_options::nofollow);
- const bool add_perms = has_opt(perm_options::add);
- const bool remove_perms = has_opt(perm_options::remove);
- _LIBCPP_ASSERT(
- (add_perms + remove_perms + has_opt(perm_options::replace)) == 1,
- "One and only one of the perm_options constants replace, add, or remove "
- "is present in opts");
-
- bool set_sym_perms = false;
- prms &= perms::mask;
- if (!resolve_symlinks || (add_perms || remove_perms)) {
- error_code m_ec;
- file_status st = resolve_symlinks ? detail::posix_stat(p, &m_ec)
- : detail::posix_lstat(p, &m_ec);
- set_sym_perms = is_symlink(st);
- if (m_ec)
- return err.report(m_ec);
- _LIBCPP_ASSERT(st.permissions() != perms::unknown,
- "Permissions unexpectedly unknown");
- if (add_perms)
- prms |= st.permissions();
- else if (remove_perms)
- prms = st.permissions() & ~prms;
- }
- const auto real_perms = detail::posix_convert_perms(prms);
-
-#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_FDCWD)
- const int flags = set_sym_perms ? AT_SYMLINK_NOFOLLOW : 0;
- if (::fchmodat(AT_FDCWD, p.c_str(), real_perms, flags) == -1) {
- return err.report(capture_errno());
- }
-#else
- if (set_sym_perms)
- return err.report(errc::operation_not_supported);
- if (::chmod(p.c_str(), real_perms) == -1) {
- return err.report(capture_errno());
- }
-#endif
-}
-
-path __read_symlink(const path& p, error_code* ec) {
- ErrorHandler<path> err("read_symlink", ec, &p);
-
- char buff[PATH_MAX + 1];
- error_code m_ec;
- ::ssize_t ret;
- if ((ret = ::readlink(p.c_str(), buff, PATH_MAX)) == -1) {
- return err.report(capture_errno());
- }
- _LIBCPP_ASSERT(ret <= PATH_MAX, "TODO");
- _LIBCPP_ASSERT(ret > 0, "TODO");
- buff[ret] = 0;
- return {buff};
-}
-
-bool __remove(const path& p, error_code* ec) {
- ErrorHandler<bool> err("remove", ec, &p);
- if (::remove(p.c_str()) == -1) {
- if (errno != ENOENT)
- err.report(capture_errno());
- return false;
- }
- return true;
-}
-
-namespace {
-
-uintmax_t remove_all_impl(path const& p, error_code& ec) {
- const auto npos = static_cast<uintmax_t>(-1);
- const file_status st = __symlink_status(p, &ec);
- if (ec)
- return npos;
- uintmax_t count = 1;
- if (is_directory(st)) {
- for (directory_iterator it(p, ec); !ec && it != directory_iterator();
- it.increment(ec)) {
- auto other_count = remove_all_impl(it->path(), ec);
- if (ec)
- return npos;
- count += other_count;
- }
- if (ec)
- return npos;
- }
- if (!__remove(p, &ec))
- return npos;
- return count;
-}
-
-} // end namespace
-
-uintmax_t __remove_all(const path& p, error_code* ec) {
- ErrorHandler<uintmax_t> err("remove_all", ec, &p);
-
- error_code mec;
- auto count = remove_all_impl(p, mec);
- if (mec) {
- if (mec == errc::no_such_file_or_directory)
- return 0;
- return err.report(mec);
- }
- return count;
-}
-
-void __rename(const path& from, const path& to, error_code* ec) {
- ErrorHandler<void> err("rename", ec, &from, &to);
- if (::rename(from.c_str(), to.c_str()) == -1)
- err.report(capture_errno());
-}
-
-void __resize_file(const path& p, uintmax_t size, error_code* ec) {
- ErrorHandler<void> err("resize_file", ec, &p);
- if (::truncate(p.c_str(), static_cast< ::off_t>(size)) == -1)
- return err.report(capture_errno());
-}
-
-space_info __space(const path& p, error_code* ec) {
- ErrorHandler<void> err("space", ec, &p);
- space_info si;
- struct statvfs m_svfs = {};
- if (::statvfs(p.c_str(), &m_svfs) == -1) {
- err.report(capture_errno());
- si.capacity = si.free = si.available = static_cast<uintmax_t>(-1);
- return si;
- }
- // Multiply with overflow checking.
- auto do_mult = [&](uintmax_t& out, uintmax_t other) {
- out = other * m_svfs.f_frsize;
- if (other == 0 || out / other != m_svfs.f_frsize)
- out = static_cast<uintmax_t>(-1);
- };
- do_mult(si.capacity, m_svfs.f_blocks);
- do_mult(si.free, m_svfs.f_bfree);
- do_mult(si.available, m_svfs.f_bavail);
- return si;
-}
-
-file_status __status(const path& p, error_code* ec) {
- return detail::posix_stat(p, ec);
-}
-
-file_status __symlink_status(const path& p, error_code* ec) {
- return detail::posix_lstat(p, ec);
-}
-
-path __temp_directory_path(error_code* ec) {
- ErrorHandler<path> err("temp_directory_path", ec);
-
- const char* env_paths[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR"};
- const char* ret = nullptr;
-
- for (auto& ep : env_paths)
- if ((ret = getenv(ep)))
- break;
- if (ret == nullptr)
- ret = "/tmp";
-
- path p(ret);
- error_code m_ec;
- file_status st = detail::posix_stat(p, &m_ec);
- if (!status_known(st))
- return err.report(m_ec, "cannot access path \"%s\"", p);
-
- if (!exists(st) || !is_directory(st))
- return err.report(errc::not_a_directory, "path \"%s\" is not a directory",
- p);
-
- return p;
-}
-
-path __weakly_canonical(const path& p, error_code* ec) {
- ErrorHandler<path> err("weakly_canonical", ec, &p);
-
- if (p.empty())
- return __canonical("", ec);
-
- path result;
- path tmp;
- tmp.__reserve(p.native().size());
- auto PP = PathParser::CreateEnd(p.native());
- --PP;
- vector<string_view_t> DNEParts;
-
- while (PP.State != PathParser::PS_BeforeBegin) {
- tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
- error_code m_ec;
- file_status st = __status(tmp, &m_ec);
- if (!status_known(st)) {
- return err.report(m_ec);
- } else if (exists(st)) {
- result = __canonical(tmp, ec);
- break;
- }
- DNEParts.push_back(*PP);
- --PP;
- }
- if (PP.State == PathParser::PS_BeforeBegin)
- result = __canonical("", ec);
- if (ec)
- ec->clear();
- if (DNEParts.empty())
- return result;
- for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)
- result /= *It;
- return result.lexically_normal();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// path definitions
-///////////////////////////////////////////////////////////////////////////////
-
-constexpr path::value_type path::preferred_separator;
-
-path& path::replace_extension(path const& replacement) {
- path p = extension();
- if (not p.empty()) {
- __pn_.erase(__pn_.size() - p.native().size());
- }
- if (!replacement.empty()) {
- if (replacement.native()[0] != '.') {
- __pn_ += ".";
- }
- __pn_.append(replacement.__pn_);
- }
- return *this;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// path.decompose
-
-string_view_t path::__root_name() const {
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName)
- return *PP;
- return {};
-}
-
-string_view_t path::__root_directory() const {
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName)
- ++PP;
- if (PP.State == PathParser::PS_InRootDir)
- return *PP;
- return {};
-}
-
-string_view_t path::__root_path_raw() const {
- auto PP = PathParser::CreateBegin(__pn_);
- if (PP.State == PathParser::PS_InRootName) {
- auto NextCh = PP.peek();
- if (NextCh && *NextCh == '/') {
- ++PP;
- return createView(__pn_.data(), &PP.RawEntry.back());
- }
- return PP.RawEntry;
- }
- if (PP.State == PathParser::PS_InRootDir)
- return *PP;
- return {};
-}
-
-static bool ConsumeRootName(PathParser *PP) {
- static_assert(PathParser::PS_BeforeBegin == 1 &&
- PathParser::PS_InRootName == 2,
- "Values for enums are incorrect");
- while (PP->State <= PathParser::PS_InRootName)
- ++(*PP);
- return PP->State == PathParser::PS_AtEnd;
-}
-
-static bool ConsumeRootDir(PathParser* PP) {
- static_assert(PathParser::PS_BeforeBegin == 1 &&
- PathParser::PS_InRootName == 2 &&
- PathParser::PS_InRootDir == 3, "Values for enums are incorrect");
- while (PP->State <= PathParser::PS_InRootDir)
- ++(*PP);
- return PP->State == PathParser::PS_AtEnd;
-}
-
-string_view_t path::__relative_path() const {
- auto PP = PathParser::CreateBegin(__pn_);
- if (ConsumeRootDir(&PP))
- return {};
- return createView(PP.RawEntry.data(), &__pn_.back());
-}
-
-string_view_t path::__parent_path() const {
- if (empty())
- return {};
- // Determine if we have a root path but not a relative path. In that case
- // return *this.
- {
- auto PP = PathParser::CreateBegin(__pn_);
- if (ConsumeRootDir(&PP))
- return __pn_;
- }
- // Otherwise remove a single element from the end of the path, and return
- // a string representing that path
- {
- auto PP = PathParser::CreateEnd(__pn_);
- --PP;
- if (PP.RawEntry.data() == __pn_.data())
- return {};
- --PP;
- return createView(__pn_.data(), &PP.RawEntry.back());
- }
-}
-
-string_view_t path::__filename() const {
- if (empty())
- return {};
- {
- PathParser PP = PathParser::CreateBegin(__pn_);
- if (ConsumeRootDir(&PP))
- return {};
- }
- return *(--PathParser::CreateEnd(__pn_));
-}
-
-string_view_t path::__stem() const {
- return parser::separate_filename(__filename()).first;
-}
-
-string_view_t path::__extension() const {
- return parser::separate_filename(__filename()).second;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// path.gen
-
-enum PathPartKind : unsigned char {
- PK_None,
- PK_RootSep,
- PK_Filename,
- PK_Dot,
- PK_DotDot,
- PK_TrailingSep
-};
-
-static PathPartKind ClassifyPathPart(string_view_t Part) {
- if (Part.empty())
- return PK_TrailingSep;
- if (Part == ".")
- return PK_Dot;
- if (Part == "..")
- return PK_DotDot;
- if (Part == "/")
- return PK_RootSep;
- return PK_Filename;
-}
-
-path path::lexically_normal() const {
- if (__pn_.empty())
- return *this;
-
- using PartKindPair = pair<string_view_t, PathPartKind>;
- vector<PartKindPair> Parts;
- // Guess as to how many elements the path has to avoid reallocating.
- Parts.reserve(32);
-
- // Track the total size of the parts as we collect them. This allows the
- // resulting path to reserve the correct amount of memory.
- size_t NewPathSize = 0;
- auto AddPart = [&](PathPartKind K, string_view_t P) {
- NewPathSize += P.size();
- Parts.emplace_back(P, K);
- };
- auto LastPartKind = [&]() {
- if (Parts.empty())
- return PK_None;
- return Parts.back().second;
- };
-
- bool MaybeNeedTrailingSep = false;
- // Build a stack containing the remaining elements of the path, popping off
- // elements which occur before a '..' entry.
- for (auto PP = PathParser::CreateBegin(__pn_); PP; ++PP) {
- auto Part = *PP;
- PathPartKind Kind = ClassifyPathPart(Part);
- switch (Kind) {
- case PK_Filename:
- case PK_RootSep: {
- // Add all non-dot and non-dot-dot elements to the stack of elements.
- AddPart(Kind, Part);
- MaybeNeedTrailingSep = false;
- break;
- }
- case PK_DotDot: {
- // Only push a ".." element if there are no elements preceding the "..",
- // or if the preceding element is itself "..".
- auto LastKind = LastPartKind();
- if (LastKind == PK_Filename) {
- NewPathSize -= Parts.back().first.size();
- Parts.pop_back();
- } else if (LastKind != PK_RootSep)
- AddPart(PK_DotDot, "..");
- MaybeNeedTrailingSep = LastKind == PK_Filename;
- break;
- }
- case PK_Dot:
- case PK_TrailingSep: {
- MaybeNeedTrailingSep = true;
- break;
- }
- case PK_None:
- _LIBCPP_UNREACHABLE();
- }
- }
- // [fs.path.generic]p6.8: If the path is empty, add a dot.
- if (Parts.empty())
- return ".";
-
- // [fs.path.generic]p6.7: If the last filename is dot-dot, remove any
- // trailing directory-separator.
- bool NeedTrailingSep = MaybeNeedTrailingSep && LastPartKind() == PK_Filename;
-
- path Result;
- Result.__pn_.reserve(Parts.size() + NewPathSize + NeedTrailingSep);
- for (auto& PK : Parts)
- Result /= PK.first;
-
- if (NeedTrailingSep)
- Result /= "";
-
- return Result;
-}
-
-static int DetermineLexicalElementCount(PathParser PP) {
- int Count = 0;
- for (; PP; ++PP) {
- auto Elem = *PP;
- if (Elem == "..")
- --Count;
- else if (Elem != "." && Elem != "")
- ++Count;
- }
- return Count;
-}
-
-path path::lexically_relative(const path& base) const {
- { // perform root-name/root-directory mismatch checks
- auto PP = PathParser::CreateBegin(__pn_);
- auto PPBase = PathParser::CreateBegin(base.__pn_);
- auto CheckIterMismatchAtBase = [&]() {
- return PP.State != PPBase.State &&
- (PP.inRootPath() || PPBase.inRootPath());
- };
- if (PP.inRootName() && PPBase.inRootName()) {
- if (*PP != *PPBase)
- return {};
- } else if (CheckIterMismatchAtBase())
- return {};
-
- if (PP.inRootPath())
- ++PP;
- if (PPBase.inRootPath())
- ++PPBase;
- if (CheckIterMismatchAtBase())
- return {};
- }
-
- // Find the first mismatching element
- auto PP = PathParser::CreateBegin(__pn_);
- auto PPBase = PathParser::CreateBegin(base.__pn_);
- while (PP && PPBase && PP.State == PPBase.State && *PP == *PPBase) {
- ++PP;
- ++PPBase;
- }
-
- // If there is no mismatch, return ".".
- if (!PP && !PPBase)
- return ".";
-
- // Otherwise, determine the number of elements, 'n', which are not dot or
- // dot-dot minus the number of dot-dot elements.
- int ElemCount = DetermineLexicalElementCount(PPBase);
- if (ElemCount < 0)
- return {};
-
- // if n == 0 and (a == end() || a->empty()), returns path("."); otherwise
- if (ElemCount == 0 && (PP.atEnd() || *PP == ""))
- return ".";
-
- // return a path constructed with 'n' dot-dot elements, followed by the
- // elements of '*this' after the mismatch.
- path Result;
- // FIXME: Reserve enough room in Result that it won't have to re-allocate.
- while (ElemCount--)
- Result /= "..";
- for (; PP; ++PP)
- Result /= *PP;
- return Result;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// path.comparisons
-static int CompareRootName(PathParser *LHS, PathParser *RHS) {
- if (!LHS->inRootName() && !RHS->inRootName())
- return 0;
-
- auto GetRootName = [](PathParser *Parser) -> string_view_t {
- return Parser->inRootName() ? **Parser : "";
- };
- int res = GetRootName(LHS).compare(GetRootName(RHS));
- ConsumeRootName(LHS);
- ConsumeRootName(RHS);
- return res;
-}
-
-static int CompareRootDir(PathParser *LHS, PathParser *RHS) {
- if (!LHS->inRootDir() && RHS->inRootDir())
- return -1;
- else if (LHS->inRootDir() && !RHS->inRootDir())
- return 1;
- else {
- ConsumeRootDir(LHS);
- ConsumeRootDir(RHS);
- return 0;
- }
-}
-
-static int CompareRelative(PathParser *LHSPtr, PathParser *RHSPtr) {
- auto &LHS = *LHSPtr;
- auto &RHS = *RHSPtr;
-
- int res;
- while (LHS && RHS) {
- if ((res = (*LHS).compare(*RHS)) != 0)
- return res;
- ++LHS;
- ++RHS;
- }
- return 0;
-}
-
-static int CompareEndState(PathParser *LHS, PathParser *RHS) {
- if (LHS->atEnd() && !RHS->atEnd())
- return -1;
- else if (!LHS->atEnd() && RHS->atEnd())
- return 1;
- return 0;
-}
-
-int path::__compare(string_view_t __s) const {
- auto LHS = PathParser::CreateBegin(__pn_);
- auto RHS = PathParser::CreateBegin(__s);
- int res;
-
- if ((res = CompareRootName(&LHS, &RHS)) != 0)
- return res;
-
- if ((res = CompareRootDir(&LHS, &RHS)) != 0)
- return res;
-
- if ((res = CompareRelative(&LHS, &RHS)) != 0)
- return res;
-
- return CompareEndState(&LHS, &RHS);
-}
-
-////////////////////////////////////////////////////////////////////////////
-// path.nonmembers
-size_t hash_value(const path& __p) noexcept {
- auto PP = PathParser::CreateBegin(__p.native());
- size_t hash_value = 0;
- hash<string_view_t> hasher;
- while (PP) {
- hash_value = __hash_combine(hash_value, hasher(*PP));
- ++PP;
- }
- return hash_value;
-}
-
-////////////////////////////////////////////////////////////////////////////
-// path.itr
-path::iterator path::begin() const {
- auto PP = PathParser::CreateBegin(__pn_);
- iterator it;
- it.__path_ptr_ = this;
- it.__state_ = static_cast<path::iterator::_ParserState>(PP.State);
- it.__entry_ = PP.RawEntry;
- it.__stashed_elem_.__assign_view(*PP);
- return it;
-}
-
-path::iterator path::end() const {
- iterator it{};
- it.__state_ = path::iterator::_AtEnd;
- it.__path_ptr_ = this;
- return it;
-}
-
-path::iterator& path::iterator::__increment() {
- PathParser PP(__path_ptr_->native(), __entry_, __state_);
- ++PP;
- __state_ = static_cast<_ParserState>(PP.State);
- __entry_ = PP.RawEntry;
- __stashed_elem_.__assign_view(*PP);
- return *this;
-}
-
-path::iterator& path::iterator::__decrement() {
- PathParser PP(__path_ptr_->native(), __entry_, __state_);
- --PP;
- __state_ = static_cast<_ParserState>(PP.State);
- __entry_ = PP.RawEntry;
- __stashed_elem_.__assign_view(*PP);
- return *this;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// directory entry definitions
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _LIBCPP_WIN32API
-error_code directory_entry::__do_refresh() noexcept {
- __data_.__reset();
- error_code failure_ec;
-
- StatT full_st;
- file_status st = detail::posix_lstat(__p_, full_st, &failure_ec);
- if (!status_known(st)) {
- __data_.__reset();
- return failure_ec;
- }
-
- if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
- } else { // we have a symlink
- __data_.__sym_perms_ = st.permissions();
- // Get the information about the linked entity.
- // Ignore errors from stat, since we don't want errors regarding symlink
- // resolution to be reported to the user.
- error_code ignored_ec;
- st = detail::posix_stat(__p_, full_st, &ignored_ec);
-
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
-
- // If we failed to resolve the link, then only partially populate the
- // cache.
- if (!status_known(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
- return error_code{};
- }
- // Otherwise, we resolved the link, potentially as not existing.
- // That's OK.
- __data_.__cache_type_ = directory_entry::_RefreshSymlink;
- }
-
- if (_VSTD_FS::is_regular_file(st))
- __data_.__size_ = static_cast<uintmax_t>(full_st.st_size);
-
- if (_VSTD_FS::exists(st)) {
- __data_.__nlink_ = static_cast<uintmax_t>(full_st.st_nlink);
-
- // Attempt to extract the mtime, and fail if it's not representable using
- // file_time_type. For now we ignore the error, as we'll report it when
- // the value is actually used.
- error_code ignored_ec;
- __data_.__write_time_ =
- __extract_last_write_time(__p_, full_st, &ignored_ec);
- }
-
- return failure_ec;
-}
-#else
-error_code directory_entry::__do_refresh() noexcept {
- __data_.__reset();
- error_code failure_ec;
-
- file_status st = _VSTD_FS::symlink_status(__p_, failure_ec);
- if (!status_known(st)) {
- __data_.__reset();
- return failure_ec;
- }
-
- if (!_VSTD_FS::exists(st) || !_VSTD_FS::is_symlink(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshNonSymlink;
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
- } else { // we have a symlink
- __data_.__sym_perms_ = st.permissions();
- // Get the information about the linked entity.
- // Ignore errors from stat, since we don't want errors regarding symlink
- // resolution to be reported to the user.
- error_code ignored_ec;
- st = _VSTD_FS::status(__p_, ignored_ec);
-
- __data_.__type_ = st.type();
- __data_.__non_sym_perms_ = st.permissions();
-
- // If we failed to resolve the link, then only partially populate the
- // cache.
- if (!status_known(st)) {
- __data_.__cache_type_ = directory_entry::_RefreshSymlinkUnresolved;
- return error_code{};
- }
- __data_.__cache_type_ = directory_entry::_RefreshSymlink;
- }
-
- // FIXME: This is currently broken, and the implementation only a placeholder.
- // We need to cache last_write_time, file_size, and hard_link_count here before
- // the implementation actually works.
-
- return failure_ec;
-}
-#endif
-
-#ifndef _LIBAUTO_UNDEF_VSTD_FS
-#pragma pop_macro("_VSTD_FS")
-#else
-#undef _VSTD
-#undef _LIBAUTO_UNDEF_VSTD_FS
-#endif
-} // namespace android::hardware::automotive::filesystem
-/* clang-format on */
-
-#endif // defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 8000
diff --git a/automotive/can/1.0/default/tests/fuzzer/Android.bp b/automotive/can/1.0/default/tests/fuzzer/Android.bp
index 16030d8..474b5a6 100644
--- a/automotive/can/1.0/default/tests/fuzzer/Android.bp
+++ b/automotive/can/1.0/default/tests/fuzzer/Android.bp
@@ -43,7 +43,6 @@
],
static_libs: [
"android.hardware.automotive.can@libnetdevice",
- "android.hardware.automotive@libc++fs",
"libnl++",
],
fuzz_config: {
diff --git a/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h
index b0ea260..e35feee 100644
--- a/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h
+++ b/automotive/can/1.0/tools/libprotocan/include/libprotocan/MessageInjector.h
@@ -22,6 +22,7 @@
#include <libprotocan/MessageDef.h>
#include <utils/Mutex.h>
+#include <mutex>
#include <queue>
namespace android::hardware::automotive::protocan {
diff --git a/automotive/can/aidl/default/Android.bp b/automotive/can/aidl/default/Android.bp
index d44cb91..d4e2840 100644
--- a/automotive/can/aidl/default/Android.bp
+++ b/automotive/can/aidl/default/Android.bp
@@ -44,7 +44,6 @@
],
static_libs: [
"android.hardware.automotive.can@libnetdevice",
- "android.hardware.automotive@libc++fs",
"libnl++",
],
vintf_fragments: ["android.hardware.automotive.can.xml"],
diff --git a/automotive/can/aidl/default/CanController.cpp b/automotive/can/aidl/default/CanController.cpp
index e4b5306..1435a02 100644
--- a/automotive/can/aidl/default/CanController.cpp
+++ b/automotive/can/aidl/default/CanController.cpp
@@ -23,13 +23,13 @@
#include <android-base/format.h>
#include <android-base/logging.h>
-#include <automotive/filesystem>
+#include <filesystem>
#include <fstream>
#include <regex>
namespace aidl::android::hardware::automotive::can {
-namespace fs = ::android::hardware::automotive::filesystem;
+namespace fs = ::std::filesystem;
namespace fsErrors {
static const std::error_code ok;
diff --git a/automotive/evs/aidl/impl/default/resources/evs_mock_configuration.xml b/automotive/evs/aidl/impl/default/resources/evs_mock_configuration.xml
index 6cbc18e..af5b354 100644
--- a/automotive/evs/aidl/impl/default/resources/evs_mock_configuration.xml
+++ b/automotive/evs/aidl/impl/default/resources/evs_mock_configuration.xml
@@ -55,6 +55,30 @@
/>
</characteristics>
</device>
+ <device id='/dev/video11' position='front'>
+ <caps>
+ <!-- list of supported controls -->
+ <supported_controls>
+ <control name='BRIGHTNESS' min='0' max='255'/>
+ <control name='CONTRAST' min='0' max='255'/>
+ </supported_controls>
+
+ <stream id='0' width='640' height='360' format='RGBA_8888' framerate='30'/>
+ </caps>
+
+ <!-- list of parameters -->
+ <characteristics>
+ <!-- Camera intrinsic calibration matrix. See
+ https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#LENS_INTRINSIC_CALIBRATION
+ -->
+ <parameter
+ name='LENS_INTRINSIC_CALIBRATION'
+ type='float'
+ size='5'
+ value='0.0,0.0,0.0,0.0,0.0'
+ />
+ </characteristics>
+ </device>
</camera>
<display>
<device id='display0' position='driver'>
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 7306b47..77629a9 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -55,5 +55,10 @@
{
"name": "VehicleHalProtoMessageConverterTest"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "VehicleHalProtoMessageConverterTest"
+ }
]
}
diff --git a/automotive/vehicle/aidl/impl/default_config/config/Android.bp b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
index 8f1c7d1..c4f93c4 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/config/Android.bp
@@ -45,3 +45,24 @@
sub_dir: "automotive/vhalconfig/",
vendor: true,
}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalDefaultProperties_JSON",
+ filename_from_src: true,
+ src: "DefaultProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalTestProperties_JSON",
+ filename_from_src: true,
+ src: "TestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
+
+prebuilt_etc_host {
+ name: "Host_Prebuilt_VehicleHalVendorClusterTestProperties_JSON",
+ filename_from_src: true,
+ src: "VendorClusterTestProperties.json",
+ relative_install_path: "automotive/vhalconfig/",
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index 583e40b..79d3e77 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -269,16 +269,6 @@
std::string dumpInjectEvent(const std::vector<std::string>& options);
std::string dumpSubscriptions();
- template <typename T>
- android::base::Result<T> safelyParseInt(int index, const std::string& s) {
- T out;
- if (!::android::base::ParseInt(s, &out)) {
- return android::base::Error() << android::base::StringPrintf(
- "non-integer argument at index %d: %s\n", index, s.c_str());
- }
- return out;
- }
- android::base::Result<float> safelyParseFloat(int index, const std::string& s);
std::vector<std::string> getOptionValues(const std::vector<std::string>& options,
size_t* index);
android::base::Result<aidl::android::hardware::automotive::vehicle::VehiclePropValue>
@@ -325,6 +315,18 @@
const aidl::android::hardware::automotive::vehicle::VehiclePropConfig&
vehiclePropConfig,
int32_t areaId);
+ template <typename T>
+ static android::base::Result<T> safelyParseInt(int index, const std::string& s) {
+ T out;
+ if (!::android::base::ParseInt(s, &out)) {
+ return android::base::Error() << android::base::StringPrintf(
+ "non-integer argument at index %d: %s\n", index, s.c_str());
+ }
+ return out;
+ }
+ static android::base::Result<float> safelyParseFloat(int index, const std::string& s);
+ static android::base::Result<int32_t> parsePropId(const std::vector<std::string>& options,
+ size_t index);
};
} // namespace fake
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 9b880cd..4f060e2 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -281,6 +281,19 @@
ifs.close();
}
+inline std::string vecToStringOfHexValues(const std::vector<int32_t>& vec) {
+ std::stringstream ss;
+ ss << "[";
+ for (size_t i = 0; i < vec.size(); i++) {
+ if (i != 0) {
+ ss << ",";
+ }
+ ss << std::showbase << std::hex << vec[i];
+ }
+ ss << "]";
+ return ss.str();
+}
+
} // namespace
void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) {
@@ -1770,19 +1783,26 @@
return "Usage: \n\n"
"[no args]: dumps (id and value) all supported properties \n"
"--help: shows this help\n"
- "--list: lists the ids of all supported properties\n"
- "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties. \n"
- "--getWithArg <PROP> [ValueArguments]: gets the value for a specific property with "
- "arguments. \n"
- "--set <PROP> [ValueArguments]: sets the value of property PROP. \n"
- "--save-prop <prop> [-a AREA_ID]: saves the current value for PROP, integration test"
- " that modifies prop value must call this before test and restore-prop after test. \n"
- "--restore-prop <prop> [-a AREA_ID]: restores a previously saved property value. \n"
- "--inject-event <PROP> [ValueArguments]: inject a property update event from car\n\n"
- "ValueArguments are in the format of [-i INT_VALUE [INT_VALUE ...]] "
- "[-i64 INT64_VALUE [INT64_VALUE ...]] [-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] "
- "[-b BYTES_VALUE] [-a AREA_ID].\n"
- "Notice that the string, bytes and area value can be set just once, while the other can"
+ "--list: lists the property IDs and their supported area IDs for all supported "
+ "properties\n"
+ "--get <PROP_ID_1> [PROP_ID_2] [PROP_ID_N]: dumps the value of specific properties. \n"
+ "--getWithArg <PROP_ID> [ValueArguments]: gets the value for a specific property. "
+ "The value arguments constructs a VehiclePropValue used in the getValue request. \n"
+ "--set <PROP_ID> [ValueArguments]: sets the value of property PROP_ID, the value "
+ "arguments constructs a VehiclePropValue used in the setValue request. \n"
+ "--save-prop <PROP_ID> [-a AREA_ID]: saves the current value for PROP_ID, integration "
+ "tests that modify prop value must call this before test and restore-prop after test. \n"
+ "--restore-prop <PROP_ID> [-a AREA_ID]: restores a previously saved property value. \n"
+ "--inject-event <PROP_ID> [ValueArguments]: inject a property update event from car\n\n"
+ "ValueArguments are in the format of [-a OPTIONAL_AREA_ID] "
+ "[-i INT_VALUE_1 [INT_VALUE_2 ...]] "
+ "[-i64 INT64_VALUE_1 [INT64_VALUE_2 ...]] "
+ "[-f FLOAT_VALUE_1 [FLOAT_VALUE_2 ...]] "
+ "[-s STR_VALUE] "
+ "[-b BYTES_VALUE].\n"
+ "For example: to set property ID 0x1234, areaId 0x1 to int32 values: [1, 2, 3], "
+ "use \"--set 0x1234 -a 0x1 -i 1 2 3\"\n"
+ "Note that the string, bytes and area value can be set just once, while the other can"
" have multiple values (so they're used in the respective array), "
"BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n" +
genFakeDataHelp() + "Fake user HAL usage: \n" + mFakeUserHal->showDumpHelp();
@@ -1848,11 +1868,18 @@
return "no properties to list\n";
}
int rowNumber = 1;
- std::string msg = StringPrintf("listing %zu properties\n", configs.size());
+ std::stringstream ss;
+ ss << "listing " << configs.size() << " properties" << std::endl;
for (const auto& config : configs) {
- msg += StringPrintf("%d: %s\n", rowNumber++, PROP_ID_TO_CSTR(config.prop));
+ std::vector<int32_t> areaIds;
+ for (const auto& areaConfig : config.areaConfigs) {
+ areaIds.push_back(areaConfig.areaId);
+ }
+ ss << rowNumber++ << ": " << PROP_ID_TO_CSTR(config.prop) << ", propID: " << std::showbase
+ << std::hex << config.prop << std::noshowbase << std::dec
+ << ", areaIDs: " << vecToStringOfHexValues(areaIds) << std::endl;
}
- return msg;
+ return ss.str();
}
Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
@@ -1865,6 +1892,16 @@
minSize, size);
}
+Result<int32_t> FakeVehicleHardware::parsePropId(const std::vector<std::string>& options,
+ size_t index) {
+ const std::string& propIdStr = options[index];
+ auto result = stringToPropId(propIdStr);
+ if (result.ok()) {
+ return result;
+ }
+ return safelyParseInt<int32_t>(index, propIdStr);
+}
+
std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
return getErrorMsg(result);
@@ -1875,7 +1912,7 @@
size_t size = options.size();
std::string msg = "";
for (size_t i = 1; i < size; ++i) {
- auto propResult = safelyParseInt<int32_t>(i, options[i]);
+ auto propResult = parsePropId(options, i);
if (!propResult.ok()) {
msg += getErrorMsg(propResult);
continue;
@@ -1911,9 +1948,9 @@
// --set/get/inject-event PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...]
// [-b b1 b2...] [-a a] [-t timestamp]
size_t optionIndex = 1;
- auto result = safelyParseInt<int32_t>(optionIndex, options[optionIndex]);
+ auto result = parsePropId(options, optionIndex);
if (!result.ok()) {
- return Error() << StringPrintf("Property value: \"%s\" is not a valid int: %s\n",
+ return Error() << StringPrintf("Property ID/Name: \"%s\" is not valid: %s\n",
options[optionIndex].c_str(), getErrorMsg(result).c_str());
}
VehiclePropValue prop = {};
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 664c877..9f002dd 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -56,6 +56,8 @@
defaults: [
"VehicleHalDefaults",
],
+ // Need root to use vendor lib: libgrpc++.
+ require_root: true,
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index cab33e1..0924360 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -2613,6 +2613,23 @@
prop1.c_str(), prop2.c_str(), prop2.c_str())));
}
+TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesWithName) {
+ std::vector<std::string> options;
+ options.push_back("--get");
+ std::string prop1 = "INFO_FUEL_CAPACITY";
+ std::string prop2 = "TIRE_PRESSURE";
+ int prop1Int = toInt(VehicleProperty::INFO_FUEL_CAPACITY);
+ int prop2Int = toInt(VehicleProperty::TIRE_PRESSURE);
+ options.push_back(prop1);
+ options.push_back(prop2);
+ DumpResult result = getHardware()->dump(options);
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_NE(result.buffer, "");
+ ASSERT_THAT(result.buffer,
+ ContainsRegex(StringPrintf("1:.*prop: %d.*\n2-0:.*prop: %d.*\n2-1:.*prop: %d.*\n",
+ prop1Int, prop2Int, prop2Int)));
+}
+
TEST_F(FakeVehicleHardwareTest, testDumpSpecificPropertiesInvalidProp) {
std::vector<std::string> options;
options.push_back("--get");
@@ -2766,6 +2783,7 @@
std::string infoMakeProperty = std::to_string(toInt(VehicleProperty::INFO_MAKE));
return {
{"success_set_string", {"--set", infoMakeProperty, "-s", CAR_MAKE}, true},
+ {"success_set_with_name", {"--set", "INFO_MAKE", "-s", CAR_MAKE}, true},
{"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true},
{"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true},
{"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true},
@@ -2790,10 +2808,7 @@
false,
"No values specified"},
{"fail_unknown_options", {"--set", infoMakeProperty, "-abcd"}, false, "Unknown option"},
- {"fail_invalid_property",
- {"--set", "not valid", "-s", CAR_MAKE},
- false,
- "not a valid int"},
+ {"fail_invalid_property", {"--set", "not_valid", "-s", CAR_MAKE}, false, "not valid"},
{"fail_duplicate_string",
{"--set", infoMakeProperty, "-s", CAR_MAKE, "-s", CAR_MAKE},
false,
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index fd1d1ca..7a8da59 100644
--- a/automotive/vehicle/aidl/impl/grpc/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/Android.bp
@@ -22,7 +22,7 @@
"aprotoc",
"protoc-gen-grpc-cpp-plugin",
],
- cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ cmd: "$(location aprotoc) -I$$(dirname $(location proto/VehicleServer.proto)) -Ihardware/interfaces/automotive/vehicle/aidl/impl/proto -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(location proto/VehicleServer.proto) --grpc_opt=generate_mock_code=true --grpc_out=$(genDir) --cpp_out=$(genDir)",
srcs: [
"proto/VehicleServer.proto",
":libprotobuf-internal-protos",
@@ -31,6 +31,7 @@
out: [
"VehicleServer.pb.h",
"VehicleServer.grpc.pb.h",
+ "VehicleServer_mock.grpc.pb.h",
],
visibility: ["//visibility:private"],
}
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index 0742283..f44573a 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -39,6 +39,13 @@
mGrpcStub(proto::VehicleServer::NewStub(mGrpcChannel)),
mValuePollingThread([this] { ValuePollingLoop(); }) {}
+// Only used for unit testing.
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
+ : mServiceAddr(""),
+ mGrpcChannel(nullptr),
+ mGrpcStub(std::move(stub)),
+ mValuePollingThread([] {}) {}
+
GRPCVehicleHardware::~GRPCVehicleHardware() {
{
std::lock_guard lck(mShutdownMutex);
@@ -181,6 +188,43 @@
return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
}
+aidlvhal::StatusCode GRPCVehicleHardware::subscribe(aidlvhal::SubscribeOptions options) {
+ proto::SubscribeRequest request;
+ ::grpc::ClientContext context;
+ proto::VehicleHalCallStatus protoStatus;
+ proto_msg_converter::aidlToProto(options, request.mutable_options());
+ auto grpc_status = mGrpcStub->Subscribe(&context, request, &protoStatus);
+ if (!grpc_status.ok()) {
+ if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+ // This is a legacy sever. It should handle updateSampleRate.
+ LOG(INFO) << __func__ << ": GRPC Subscribe is not supported by the server";
+ return aidlvhal::StatusCode::OK;
+ }
+ LOG(ERROR) << __func__ << ": GRPC Subscribe Failed: " << grpc_status.error_message();
+ return aidlvhal::StatusCode::INTERNAL_ERROR;
+ }
+ return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
+ proto::UnsubscribeRequest request;
+ ::grpc::ClientContext context;
+ proto::VehicleHalCallStatus protoStatus;
+ request.set_prop_id(propId);
+ request.set_area_id(areaId);
+ auto grpc_status = mGrpcStub->Unsubscribe(&context, request, &protoStatus);
+ if (!grpc_status.ok()) {
+ if (grpc_status.error_code() == ::grpc::StatusCode::UNIMPLEMENTED) {
+ // This is a legacy sever. Ignore unsubscribe request.
+ LOG(INFO) << __func__ << ": GRPC Unsubscribe is not supported by the server";
+ return aidlvhal::StatusCode::OK;
+ }
+ LOG(ERROR) << __func__ << ": GRPC Unsubscribe Failed: " << grpc_status.error_message();
+ return aidlvhal::StatusCode::INTERNAL_ERROR;
+ }
+ return static_cast<aidlvhal::StatusCode>(protoStatus.status_code());
+}
+
aidlvhal::StatusCode GRPCVehicleHardware::updateSampleRate(int32_t propId, int32_t areaId,
float sampleRate) {
::grpc::ClientContext context;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index ddd620e..9750f62 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -43,6 +43,9 @@
public:
explicit GRPCVehicleHardware(std::string service_addr);
+ // Only used for unit testing.
+ explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
+
~GRPCVehicleHardware();
// Get all the property configs.
@@ -80,6 +83,10 @@
aidlvhal::StatusCode updateSampleRate(int32_t propId, int32_t areaId,
float sampleRate) override;
+ aidlvhal::StatusCode subscribe(aidlvhal::SubscribeOptions options) override;
+
+ aidlvhal::StatusCode unsubscribe(int32_t propId, int32_t areaId) override;
+
bool waitForConnected(std::chrono::milliseconds waitTime);
protected:
@@ -91,7 +98,7 @@
std::string mServiceAddr;
std::shared_ptr<::grpc::Channel> mGrpcChannel;
- std::unique_ptr<proto::VehicleServer::Stub> mGrpcStub;
+ std::unique_ptr<proto::VehicleServer::StubInterface> mGrpcStub;
std::thread mValuePollingThread;
std::unique_ptr<const PropertySetErrorCallback> mOnSetErr;
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index af3dd59..a6abfa3 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -164,6 +164,27 @@
return ::grpc::Status::OK;
}
+::grpc::Status GrpcVehicleProxyServer::Subscribe(::grpc::ServerContext* context,
+ const proto::SubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) {
+ const auto& protoSubscribeOptions = request->options();
+ aidlvhal::SubscribeOptions aidlSubscribeOptions = {};
+ proto_msg_converter::protoToAidl(protoSubscribeOptions, &aidlSubscribeOptions);
+ const auto status_code = mHardware->subscribe(aidlSubscribeOptions);
+ status->set_status_code(static_cast<proto::StatusCode>(status_code));
+ return ::grpc::Status::OK;
+}
+
+::grpc::Status GrpcVehicleProxyServer::Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) {
+ int32_t propId = request->prop_id();
+ int32_t areaId = request->area_id();
+ const auto status_code = mHardware->unsubscribe(propId, areaId);
+ status->set_status_code(static_cast<proto::StatusCode>(status_code));
+ return ::grpc::Status::OK;
+}
+
::grpc::Status GrpcVehicleProxyServer::CheckHealth(::grpc::ServerContext* context,
const ::google::protobuf::Empty*,
proto::VehicleHalCallStatus* status) {
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
index 3596354..dd9e2aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.h
@@ -57,6 +57,13 @@
const proto::UpdateSampleRateRequest* request,
proto::VehicleHalCallStatus* status) override;
+ ::grpc::Status Subscribe(::grpc::ServerContext* context, const proto::SubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) override;
+
+ ::grpc::Status Unsubscribe(::grpc::ServerContext* context,
+ const proto::UnsubscribeRequest* request,
+ proto::VehicleHalCallStatus* status) override;
+
::grpc::Status CheckHealth(::grpc::ServerContext* context, const ::google::protobuf::Empty*,
proto::VehicleHalCallStatus* status) override;
diff --git a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
index 22b11d8..732957f 100644
--- a/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
+++ b/automotive/vehicle/aidl/impl/grpc/proto/VehicleServer.proto
@@ -20,7 +20,9 @@
import "android/hardware/automotive/vehicle/DumpOptions.proto";
import "android/hardware/automotive/vehicle/DumpResult.proto";
+import "android/hardware/automotive/vehicle/SubscribeRequest.proto";
import "android/hardware/automotive/vehicle/StatusCode.proto";
+import "android/hardware/automotive/vehicle/UnsubscribeRequest.proto";
import "android/hardware/automotive/vehicle/VehiclePropConfig.proto";
import "android/hardware/automotive/vehicle/VehiclePropValue.proto";
import "android/hardware/automotive/vehicle/VehiclePropValueRequest.proto";
@@ -40,4 +42,8 @@
rpc Dump(DumpOptions) returns (DumpResult) {}
rpc StartPropertyValuesStream(google.protobuf.Empty) returns (stream VehiclePropValues) {}
+
+ rpc Subscribe(SubscribeRequest) returns (VehicleHalCallStatus) {}
+
+ rpc Unsubscribe(UnsubscribeRequest) returns (VehicleHalCallStatus) {}
}
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index f578021..3bd7e0e 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -15,6 +15,7 @@
#include "GRPCVehicleHardware.h"
#include "VehicleServer.grpc.pb.h"
#include "VehicleServer.pb.h"
+#include "VehicleServer_mock.grpc.pb.h"
#include <gmock/gmock.h>
#include <grpc++/grpc++.h>
@@ -26,6 +27,17 @@
namespace android::hardware::automotive::vehicle::virtualization {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArgPointee;
+
+using proto::MockVehicleServerStub;
+
const std::string kFakeServerAddr = "0.0.0.0:54321";
class FakeVehicleServer : public proto::VehicleServer::Service {
@@ -91,4 +103,131 @@
}
}
+class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+ protected:
+ NiceMock<MockVehicleServerStub>* mGrpcStub;
+ std::unique_ptr<GRPCVehicleHardware> mHardware;
+
+ void SetUp() override {
+ auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+ ;
+ mGrpcStub = stub.get();
+ mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+ }
+
+ void TearDown() override { mHardware.reset(); }
+};
+
+MATCHER_P(RepeatedInt32Eq, expected_values, "") {
+ return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::OK);
+ proto::SubscribeRequest actualRequest;
+
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+ Return(::grpc::Status::OK)));
+
+ aidlvhal::SubscribeOptions options = {.propId = 1,
+ .areaIds = {1, 2, 3, 4},
+ .sampleRate = 1.234,
+ .resolution = 0.01,
+ .enableVariableUpdateRate = true};
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+ const auto& protoOptions = actualRequest.options();
+ EXPECT_EQ(protoOptions.prop_id(), 1);
+ EXPECT_THAT(protoOptions.area_ids(), RepeatedInt32Eq(std::vector<int32_t>({1, 2, 3, 4})));
+ EXPECT_FLOAT_EQ(protoOptions.sample_rate(), 1.234);
+ EXPECT_FLOAT_EQ(protoOptions.resolution(), 0.01);
+ EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+ EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
+ Return(::grpc::Status::OK)));
+
+ aidlvhal::SubscribeOptions options;
+ auto status = mHardware->subscribe(options);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::OK);
+ proto::UnsubscribeRequest actualRequest;
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SaveArg<1>(&actualRequest), SetArgPointee<2>(protoStatus),
+ Return(::grpc::Status::OK)));
+
+ int32_t propId = 1;
+ int32_t areaId = 2;
+ auto status = mHardware->unsubscribe(propId, areaId);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+ EXPECT_EQ(actualRequest.prop_id(), propId);
+ EXPECT_EQ(actualRequest.area_id(), areaId);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::OK);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+ proto::VehicleHalCallStatus protoStatus;
+ protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+
+ EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
+ .WillOnce(DoAll(SetArgPointee<2>(protoStatus), // Set the output status
+ Return(::grpc::Status::OK)));
+
+ auto status = mHardware->unsubscribe(1, 2);
+
+ EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
index 49e6fc9..ca5c2d5 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleProxyServerUnitTest.cpp
@@ -30,6 +30,13 @@
namespace android::hardware::automotive::vehicle::virtualization {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
const std::string kFakeServerAddr = "0.0.0.0:54321";
class VehicleHardwareForTest : public IVehicleHardware {
@@ -39,38 +46,30 @@
mOnProp = std::move(callback);
}
- void onPropertyEvent(
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue> values) {
+ void onPropertyEvent(std::vector<aidlvhal::VehiclePropValue> values) {
if (mOnProp) {
(*mOnProp)(std::move(values));
}
}
// Functions that we do not care.
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
- getAllPropertyConfigs() const override {
- return {};
- }
+ std::vector<aidlvhal::VehiclePropConfig> getAllPropertyConfigs() const override { return {}; }
- aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+ aidlvhal::StatusCode setValues(
std::shared_ptr<const SetValuesCallback> callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
- requests) override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+ const std::vector<aidlvhal::SetValueRequest>& requests) override {
+ return aidlvhal::StatusCode::OK;
}
- aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+ aidlvhal::StatusCode getValues(
std::shared_ptr<const GetValuesCallback> callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
- requests) const override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
+ const std::vector<aidlvhal::GetValueRequest>& requests) const override {
+ return aidlvhal::StatusCode::OK;
}
DumpResult dump(const std::vector<std::string>& options) override { return {}; }
- aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override {
- return aidl::android::hardware::automotive::vehicle::StatusCode::OK;
- }
+ aidlvhal::StatusCode checkHealth() override { return aidlvhal::StatusCode::OK; }
void registerOnPropertySetErrorEvent(
std::unique_ptr<const PropertySetErrorCallback> callback) override {}
@@ -79,6 +78,35 @@
std::unique_ptr<const PropertyChangeCallback> mOnProp;
};
+class MockVehicleHardware : public IVehicleHardware {
+ public:
+ // Mock methods from IVehicleHardware
+ MOCK_METHOD(std::vector<aidlvhal::VehiclePropConfig>, getAllPropertyConfigs, (),
+ (const, override));
+
+ MOCK_METHOD((aidlvhal::StatusCode), setValues,
+ (std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<aidlvhal::SetValueRequest>& requests),
+ (override));
+
+ MOCK_METHOD((aidlvhal::StatusCode), getValues,
+ (std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<aidlvhal::GetValueRequest>& requests),
+ (const, override));
+
+ MOCK_METHOD(DumpResult, dump, (const std::vector<std::string>& options), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, checkHealth, (), (override));
+ MOCK_METHOD(void, registerOnPropertyChangeEvent,
+ (std::unique_ptr<const PropertyChangeCallback> callback), (override));
+ MOCK_METHOD(void, registerOnPropertySetErrorEvent,
+ (std::unique_ptr<const PropertySetErrorCallback> callback), (override));
+ MOCK_METHOD(std::chrono::nanoseconds, getPropertyOnChangeEventBatchingWindow, (), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, subscribe, (aidlvhal::SubscribeOptions options), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, unsubscribe, (int32_t propId, int32_t areaId), (override));
+ MOCK_METHOD(aidlvhal::StatusCode, updateSampleRate,
+ (int32_t propId, int32_t areaId, float sampleRate), (override));
+};
+
TEST(GRPCVehicleProxyServerUnitTest, ClientConnectDisconnect) {
auto testHardware = std::make_unique<VehicleHardwareForTest>();
// HACK: manipulate the underlying hardware via raw pointer for testing.
@@ -144,4 +172,70 @@
vehicleServer->Shutdown().Wait();
}
+TEST(GRPCVehicleProxyServerUnitTest, Subscribe) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::SubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+ aidlvhal::SubscribeOptions aidlOptions;
+ request.mutable_options()->set_prop_id(1);
+ request.mutable_options()->add_area_ids(2);
+ request.mutable_options()->set_sample_rate(1.234);
+ request.mutable_options()->set_resolution(0.01);
+ request.mutable_options()->set_enable_variable_update_rate(true);
+
+ EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+ .WillOnce(DoAll(SaveArg<0>(&aidlOptions), Return(aidlvhal::StatusCode::OK)));
+
+ auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+ EXPECT_EQ(aidlOptions.propId, 1);
+ EXPECT_EQ(aidlOptions.areaIds, std::vector<int32_t>{2});
+ EXPECT_FLOAT_EQ(aidlOptions.sampleRate, 1.234);
+ EXPECT_FLOAT_EQ(aidlOptions.resolution, 0.01);
+ EXPECT_TRUE(aidlOptions.enableVariableUpdateRate);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, SubscribeNotAvailable) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::SubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+
+ EXPECT_CALL(*mockHardwarePtr, subscribe(_))
+ .WillOnce(Return(aidlvhal::StatusCode::NOT_AVAILABLE));
+
+ auto grpcStatus = server.Subscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::NOT_AVAILABLE);
+}
+
+TEST(GRPCVehicleProxyServerUnitTest, Unsubscribe) {
+ auto mockHardware = std::make_unique<MockVehicleHardware>();
+ // We make sure this is alive inside the function scope.
+ MockVehicleHardware* mockHardwarePtr = mockHardware.get();
+ GrpcVehicleProxyServer server = GrpcVehicleProxyServer("", std::move(mockHardware));
+ ::grpc::ServerContext context;
+ proto::UnsubscribeRequest request;
+ proto::VehicleHalCallStatus returnStatus;
+ request.set_prop_id(1);
+ request.set_area_id(2);
+
+ EXPECT_CALL(*mockHardwarePtr, unsubscribe(1, 2)).WillOnce(Return(aidlvhal::StatusCode::OK));
+
+ auto grpcStatus = server.Unsubscribe(&context, &request, &returnStatus);
+
+ EXPECT_TRUE(grpcStatus.ok());
+ EXPECT_EQ(returnStatus.status_code(), proto::StatusCode::OK);
+}
+
} // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
index d10aa3e..94c09aa 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/Android.bp
@@ -42,23 +42,21 @@
host_supported: true,
}
-cc_test {
+cc_test_host {
name: "VehicleHalProtoMessageConverterTest",
srcs: [
"test/*.cpp",
],
vendor: true,
defaults: ["VehicleHalDefaults"],
- shared_libs: [
- "libprotobuf-cpp-full",
- "libjsoncpp",
- ],
static_libs: [
"VehicleHalJsonConfigLoaderEnableTestProperties",
"VehicleHalProtoMessageConverter",
"VehicleHalProtos",
"VehicleHalUtils",
"libgtest",
+ "libprotobuf-cpp-full",
+ "libjsoncpp",
],
data: [
":VehicleHalDefaultProperties_JSON",
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
index 1c26fe8..25c07ef 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/include/ProtoMessageConverter.h
@@ -18,6 +18,7 @@
#define android_hardware_automotive_vehicle_aidl_impl_grpc_utils_proto_message_converter_include_ProtoMessageConverter_H_
#include <VehicleHalTypes.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
#include <android/hardware/automotive/vehicle/VehicleAreaConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
@@ -46,6 +47,12 @@
void protoToAidl(
const ::android::hardware::automotive::vehicle::proto::VehiclePropValue& inProtoVal,
::aidl::android::hardware::automotive::vehicle::VehiclePropValue* outAidlVal);
+// Convert AIDL SubscribeOptions to Protobuf SubscribeOptions.
+void aidlToProto(const ::aidl::android::hardware::automotive::vehicle::SubscribeOptions& in,
+ ::android::hardware::automotive::vehicle::proto::SubscribeOptions* out);
+// Convert Protobuf SubscribeOptions to AIDL SubscribeOptions.
+void protoToAidl(const ::android::hardware::automotive::vehicle::proto::SubscribeOptions& in,
+ ::aidl::android::hardware::automotive::vehicle::SubscribeOptions* out);
} // namespace proto_msg_converter
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
index 1ea0df4..c40004a 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/src/ProtoMessageConverter.cpp
@@ -152,6 +152,24 @@
COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, float_values, out, value.floatValues);
}
+void aidlToProto(const aidl_vehicle::SubscribeOptions& in, proto::SubscribeOptions* out) {
+ out->set_prop_id(in.propId);
+ for (int areaId : in.areaIds) {
+ out->add_area_ids(areaId);
+ }
+ out->set_sample_rate(in.sampleRate);
+ out->set_resolution(in.resolution);
+ out->set_enable_variable_update_rate(in.enableVariableUpdateRate);
+}
+
+void protoToAidl(const proto::SubscribeOptions& in, aidl_vehicle::SubscribeOptions* out) {
+ out->propId = in.prop_id();
+ COPY_PROTOBUF_VEC_TO_VHAL_TYPE(in, area_ids, out, areaIds);
+ out->sampleRate = in.sample_rate();
+ out->resolution = in.resolution();
+ out->enableVariableUpdateRate = in.enable_variable_update_rate();
+}
+
#undef COPY_PROTOBUF_VEC_TO_VHAL_TYPE
#undef CAST_COPY_PROTOBUF_VEC_TO_VHAL_TYPE
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index 308be46..2efda5b 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -22,6 +22,7 @@
#include <android-base/file.h>
#include <android-base/format.h>
+#include <android/hardware/automotive/vehicle/SubscribeOptions.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropConfig.pb.h>
#include <android/hardware/automotive/vehicle/VehiclePropValue.pb.h>
#include <gtest/gtest.h>
@@ -114,6 +115,21 @@
return ::fmt::format("property_{:d}", info.param.prop);
});
+TEST_F(PropValueConversionTest, testConvertSubscribeOption) {
+ proto::SubscribeOptions protoOptions;
+ aidl_vehicle::SubscribeOptions aidlOptions = {.propId = 1,
+ .areaIds = {1, 2},
+ .sampleRate = 1.234,
+ .resolution = 0.01,
+ .enableVariableUpdateRate = true};
+ aidl_vehicle::SubscribeOptions outputOptions;
+
+ aidlToProto(aidlOptions, &protoOptions);
+ protoToAidl(protoOptions, &outputOptions);
+
+ EXPECT_EQ(aidlOptions, outputOptions);
+}
+
} // namespace proto_msg_converter
} // namespace vehicle
} // namespace automotive
diff --git a/automotive/vehicle/aidl/impl/proto/Android.bp b/automotive/vehicle/aidl/impl/proto/Android.bp
index 56fad7e..b2edf75 100644
--- a/automotive/vehicle/aidl/impl/proto/Android.bp
+++ b/automotive/vehicle/aidl/impl/proto/Android.bp
@@ -50,6 +50,9 @@
"android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.h",
"android/hardware/automotive/vehicle/VehiclePropValue.pb.h",
"android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.h",
+ "android/hardware/automotive/vehicle/SubscribeOptions.pb.h",
+ "android/hardware/automotive/vehicle/SubscribeRequest.pb.h",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.h",
],
}
@@ -74,6 +77,9 @@
"android/hardware/automotive/vehicle/VehiclePropertyStatus.pb.cc",
"android/hardware/automotive/vehicle/VehiclePropValue.pb.cc",
"android/hardware/automotive/vehicle/VehiclePropValueRequest.pb.cc",
+ "android/hardware/automotive/vehicle/SubscribeOptions.pb.cc",
+ "android/hardware/automotive/vehicle/SubscribeRequest.pb.cc",
+ "android/hardware/automotive/vehicle/UnsubscribeRequest.pb.cc",
],
}
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
new file mode 100644
index 0000000..3fc6581
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeOptions.proto
@@ -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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message SubscribeOptions {
+ int32 prop_id = 1;
+ repeated int32 area_ids = 2;
+ float sample_rate = 3;
+ float resolution = 4;
+ bool enable_variable_update_rate = 5;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
new file mode 100644
index 0000000..4ce6335
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/SubscribeRequest.proto
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+import "android/hardware/automotive/vehicle/SubscribeOptions.proto";
+
+message SubscribeRequest {
+ SubscribeOptions options = 1;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
new file mode 100644
index 0000000..314fbf0
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/proto/android/hardware/automotive/vehicle/UnsubscribeRequest.proto
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.hardware.automotive.vehicle.proto;
+
+message UnsubscribeRequest {
+ int32 prop_id = 1;
+ int32 area_id = 2;
+}
\ No newline at end of file
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index aca725d..f48bb2a 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -328,11 +328,15 @@
}
};
+// This is for debug purpose only.
inline std::string propIdToString(int32_t propId) {
return toString(
static_cast<aidl::android::hardware::automotive::vehicle::VehicleProperty>(propId));
}
+// This is for debug purpose only.
+android::base::Result<int32_t> stringToPropId(const std::string& propName);
+
template <typename T>
void roundToNearestResolution(std::vector<T>& arrayToSanitize, float resolution) {
if (resolution == 0) {
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
index f85728d..4d06e4e 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -16,14 +16,18 @@
#include "VehicleUtils.h"
+#include <unordered_map>
+
namespace android {
namespace hardware {
namespace automotive {
namespace vehicle {
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::toString;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
@@ -31,6 +35,39 @@
using ::android::base::Result;
using ::ndk::ScopedAStatus;
+namespace {
+
+class PropertyIdByNameSingleton {
+ public:
+ static PropertyIdByNameSingleton& getInstance() {
+ static PropertyIdByNameSingleton instance;
+ return instance;
+ }
+
+ Result<int32_t> getPropertyId(const std::string& name) {
+ auto it = mPropertyIdByName.find(name);
+ if (it == mPropertyIdByName.end()) {
+ return Error();
+ }
+ return it->second;
+ }
+
+ PropertyIdByNameSingleton(PropertyIdByNameSingleton const&) = delete;
+ void operator=(PropertyIdByNameSingleton const&) = delete;
+
+ private:
+ std::unordered_map<std::string, int32_t> mPropertyIdByName;
+
+ PropertyIdByNameSingleton() {
+ constexpr auto values = ndk::internal::enum_values<VehicleProperty>;
+ for (unsigned int i = 0; i < values.size(); i++) {
+ mPropertyIdByName.emplace(toString(values[i]), toInt(values[i]));
+ }
+ }
+};
+
+} // namespace
+
Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
int32_t property = value.prop;
VehiclePropertyType type = getPropType(property);
@@ -213,6 +250,10 @@
return aidl::android::hardware::automotive::vehicle::toString(mCode);
}
+Result<int32_t> stringToPropId(const std::string& propName) {
+ return PropertyIdByNameSingleton::getInstance().getPropertyId(propName);
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 9abb2a2..1048877 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -770,6 +770,23 @@
ASSERT_EQ(result.error().message(), "error message: INVALID_ARG");
}
+TEST(VehicleUtilsTest, testPropIdToString) {
+ ASSERT_EQ(propIdToString(toInt(VehicleProperty::PERF_VEHICLE_SPEED)), "PERF_VEHICLE_SPEED");
+}
+
+TEST(VehicleUtilsTest, testStringToPropId) {
+ auto result = stringToPropId("PERF_VEHICLE_SPEED");
+
+ ASSERT_TRUE(result.ok());
+ ASSERT_EQ(result.value(), toInt(VehicleProperty::PERF_VEHICLE_SPEED));
+}
+
+TEST(VehicleUtilsTest, testStringToPropId_InvalidName) {
+ auto result = stringToPropId("PERF_VEHICLE_SPEED12345");
+
+ ASSERT_FALSE(result.ok());
+}
+
class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 250b30c..fa2a310 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -42,10 +42,11 @@
namespace automotive {
namespace vehicle {
-class DefaultVehicleHal final : public aidl::android::hardware::automotive::vehicle::BnVehicle {
+namespace aidlvhal = ::aidl::android::hardware::automotive::vehicle;
+
+class DefaultVehicleHal final : public aidlvhal::BnVehicle {
public:
- using CallbackType =
- std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+ using CallbackType = std::shared_ptr<aidlvhal::IVehicleCallback>;
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
@@ -54,26 +55,16 @@
~DefaultVehicleHal();
- ndk::ScopedAStatus getAllPropConfigs(
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus getValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
- override;
- ndk::ScopedAStatus setValues(
- const CallbackType& callback,
- const aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
- override;
- ndk::ScopedAStatus getPropConfigs(
- const std::vector<int32_t>& props,
- aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
- override;
- ndk::ScopedAStatus subscribe(
- const CallbackType& callback,
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options,
- int32_t maxSharedMemoryFileCount) override;
+ ndk::ScopedAStatus getAllPropConfigs(aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus getValues(const CallbackType& callback,
+ const aidlvhal::GetValueRequests& requests) override;
+ ndk::ScopedAStatus setValues(const CallbackType& callback,
+ const aidlvhal::SetValueRequests& requests) override;
+ ndk::ScopedAStatus getPropConfigs(const std::vector<int32_t>& props,
+ aidlvhal::VehiclePropConfigs* returnConfigs) override;
+ ndk::ScopedAStatus subscribe(const CallbackType& callback,
+ const std::vector<aidlvhal::SubscribeOptions>& options,
+ int32_t maxSharedMemoryFileCount) override;
ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
const std::vector<int32_t>& propIds) override;
ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
@@ -86,12 +77,8 @@
// friend class for unit testing.
friend class DefaultVehicleHalTest;
- using GetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::GetValueResult,
- aidl::android::hardware::automotive::vehicle::GetValueResults>;
- using SetValuesClient =
- GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
- aidl::android::hardware::automotive::vehicle::SetValueResults>;
+ using GetValuesClient = GetSetValuesClient<aidlvhal::GetValueResult, aidlvhal::GetValueResults>;
+ using SetValuesClient = GetSetValuesClient<aidlvhal::SetValueResult, aidlvhal::SetValueResults>;
// A wrapper for binder lifecycle operations to enable stubbing for test.
class BinderLifecycleInterface {
@@ -137,28 +124,27 @@
bool mShouldRefreshPropertyConfigs;
std::unique_ptr<IVehicleHardware> mVehicleHardware;
- // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
- // lock guard them.
- std::unordered_map<int32_t, aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
- mConfigsByPropId;
- // Only modified in constructor, so thread-safe.
- std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile;
// PendingRequestPool is thread-safe.
std::shared_ptr<PendingRequestPool> mPendingRequestPool;
// SubscriptionManager is thread-safe.
std::shared_ptr<SubscriptionManager> mSubscriptionManager;
// ConcurrentQueue is thread-safe.
- std::shared_ptr<ConcurrentQueue<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
- mBatchedEventQueue;
+ std::shared_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>> mBatchedEventQueue;
// BatchingConsumer is thread-safe.
- std::shared_ptr<
- BatchingConsumer<aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+ std::shared_ptr<BatchingConsumer<aidlvhal::VehiclePropValue>>
mPropertyChangeEventsBatchingConsumer;
// Only set once during initialization.
std::chrono::nanoseconds mEventBatchingWindow;
// Only used for testing.
int32_t mTestInterfaceVersion = 0;
+ // mConfigsByPropId and mConfigFile is lazy initialized.
+ mutable std::mutex mConfigInitLock;
+ mutable bool mConfigInit GUARDED_BY(mConfigInitLock) = false;
+ mutable std::unordered_map<int32_t, aidlvhal::VehiclePropConfig> mConfigsByPropId
+ GUARDED_BY(mConfigInitLock);
+ mutable std::unique_ptr<ndk::ScopedFileDescriptor> mConfigFile GUARDED_BY(mConfigInitLock);
+
std::mutex mLock;
std::unordered_map<const AIBinder*, std::unique_ptr<OnBinderDiedContext>> mOnBinderDiedContexts
GUARDED_BY(mLock);
@@ -182,32 +168,23 @@
// A thread to handle onBinderDied or onBinderUnlinked event.
std::thread mOnBinderDiedUnlinkedHandlerThread;
- android::base::Result<void> checkProperty(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+ android::base::Result<void> checkProperty(const aidlvhal::VehiclePropValue& propValue);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&
- requests);
+ const std::vector<aidlvhal::GetValueRequest>& requests);
android::base::Result<std::vector<int64_t>> checkDuplicateRequests(
- const std::vector<aidl::android::hardware::automotive::vehicle::SetValueRequest>&
- requests);
- VhalResult<void> checkSubscribeOptions(
- const std::vector<aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
- options);
+ const std::vector<aidlvhal::SetValueRequest>& requests);
+ VhalResult<void> checkSubscribeOptions(const std::vector<aidlvhal::SubscribeOptions>& options);
- VhalResult<void> checkPermissionHelper(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
- aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess accessToTest) const;
+ VhalResult<void> checkPermissionHelper(const aidlvhal::VehiclePropValue& value,
+ aidlvhal::VehiclePropertyAccess accessToTest) const;
- VhalResult<void> checkReadPermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkReadPermission(const aidlvhal::VehiclePropValue& value) const;
- VhalResult<void> checkWritePermission(
- const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
+ VhalResult<void> checkWritePermission(const aidlvhal::VehiclePropValue& value) const;
- android::base::Result<const aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
- getConfig(int32_t propId) const;
+ android::base::Result<const aidlvhal::VehiclePropConfig*> getConfig(int32_t propId) const;
void onBinderDiedWithContext(const AIBinder* clientId);
@@ -219,7 +196,7 @@
bool checkDumpPermission();
- bool getAllPropConfigsFromHardware();
+ bool getAllPropConfigsFromHardwareLocked() const REQUIRES(mConfigInitLock);
// The looping handler function to process all onBinderDied or onBinderUnlinked events in
// mBinderEvents.
@@ -228,19 +205,19 @@
size_t countSubscribeClients();
// Handles the property change events in batch.
- void handleBatchedPropertyEvents(
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- batchedEvents);
+ void handleBatchedPropertyEvents(std::vector<aidlvhal::VehiclePropValue>&& batchedEvents);
- int32_t getVhalInterfaceVersion();
+ int32_t getVhalInterfaceVersion() const;
+
+ // Gets mConfigsByPropId, lazy init it if necessary.
+ const std::unordered_map<int32_t, aidlvhal::VehiclePropConfig>& getConfigsByPropId() const;
+ // Gets mConfigFile, lazy init it if necessary.
+ const ndk::ScopedFileDescriptor* getConfigFile() const;
// Puts the property change events into a queue so that they can handled in batch.
static void batchPropertyChangeEvent(
- const std::weak_ptr<ConcurrentQueue<
- aidl::android::hardware::automotive::vehicle::VehiclePropValue>>&
- batchedEventQueue,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ const std::weak_ptr<ConcurrentQueue<aidlvhal::VehiclePropValue>>& batchedEventQueue,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
// Gets or creates a {@code T} object for the client to or from {@code clients}.
template <class T>
@@ -248,10 +225,8 @@
std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
- static void onPropertyChangeEvent(
- const std::weak_ptr<SubscriptionManager>& subscriptionManager,
- std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
- updatedValues);
+ static void onPropertyChangeEvent(const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+ std::vector<aidlvhal::VehiclePropValue>&& updatedValues);
static void onPropertySetErrorEvent(
const std::weak_ptr<SubscriptionManager>& subscriptionManager,
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index a29861f..9dc039d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -24,6 +24,7 @@
#include <VehicleUtils.h>
#include <VersionForVehicleProperty.h>
+#include <android-base/logging.h>
#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android/binder_ibinder.h>
@@ -71,6 +72,7 @@
using ::ndk::ScopedAIBinder_DeathRecipient;
using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
std::string toString(const std::unordered_set<int64_t>& values) {
std::string str = "";
@@ -103,10 +105,7 @@
: mVehicleHardware(std::move(vehicleHardware)),
mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)),
mTestInterfaceVersion(testInterfaceVersion) {
- if (!getAllPropConfigsFromHardware()) {
- return;
- }
-
+ ALOGD("DefaultVehicleHal init");
IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
mEventBatchingWindow = mVehicleHardware->getPropertyOnChangeEventBatchingWindow();
@@ -319,16 +318,18 @@
mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
}
-int32_t DefaultVehicleHal::getVhalInterfaceVersion() {
+int32_t DefaultVehicleHal::getVhalInterfaceVersion() const {
if (mTestInterfaceVersion != 0) {
return mTestInterfaceVersion;
}
int32_t myVersion = 0;
- getInterfaceVersion(&myVersion);
+ // getInterfaceVersion is in-reality a const method.
+ const_cast<DefaultVehicleHal*>(this)->getInterfaceVersion(&myVersion);
return myVersion;
}
-bool DefaultVehicleHal::getAllPropConfigsFromHardware() {
+bool DefaultVehicleHal::getAllPropConfigsFromHardwareLocked() const {
+ ALOGD("Get all property configs from hardware");
auto configs = mVehicleHardware->getAllPropertyConfigs();
std::vector<VehiclePropConfig> filteredConfigs;
int32_t myVersion = getVhalInterfaceVersion();
@@ -373,22 +374,46 @@
return true;
}
+const ScopedFileDescriptor* DefaultVehicleHal::getConfigFile() const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigFile.get();
+}
+
+const std::unordered_map<int32_t, VehiclePropConfig>& DefaultVehicleHal::getConfigsByPropId()
+ const {
+ std::scoped_lock lockGuard(mConfigInitLock);
+ if (!mConfigInit) {
+ CHECK(getAllPropConfigsFromHardwareLocked())
+ << "Failed to get property configs from hardware";
+ mConfigInit = true;
+ }
+ return mConfigsByPropId;
+}
+
ScopedAStatus DefaultVehicleHal::getAllPropConfigs(VehiclePropConfigs* output) {
- if (mConfigFile != nullptr) {
+ const ScopedFileDescriptor* configFile = getConfigFile();
+ const auto& configsByPropId = getConfigsByPropId();
+ if (configFile != nullptr) {
output->payloads.clear();
- output->sharedMemoryFd.set(dup(mConfigFile->get()));
+ output->sharedMemoryFd.set(dup(configFile->get()));
return ScopedAStatus::ok();
}
- output->payloads.reserve(mConfigsByPropId.size());
- for (const auto& [_, config] : mConfigsByPropId) {
+ output->payloads.reserve(configsByPropId.size());
+ for (const auto& [_, config] : configsByPropId) {
output->payloads.push_back(config);
}
return ScopedAStatus::ok();
}
Result<const VehiclePropConfig*> DefaultVehicleHal::getConfig(int32_t propId) const {
- auto it = mConfigsByPropId.find(propId);
- if (it == mConfigsByPropId.end()) {
+ const auto& configsByPropId = getConfigsByPropId();
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return Error() << "no config for property, ID: " << propId;
}
return &(it->second);
@@ -634,9 +659,11 @@
ScopedAStatus DefaultVehicleHal::getPropConfigs(const std::vector<int32_t>& props,
VehiclePropConfigs* output) {
std::vector<VehiclePropConfig> configs;
+ const auto& configsByPropId = getConfigsByPropId();
for (int32_t prop : props) {
- if (mConfigsByPropId.find(prop) != mConfigsByPropId.end()) {
- configs.push_back(mConfigsByPropId[prop]);
+ auto it = configsByPropId.find(prop);
+ if (it != configsByPropId.end()) {
+ configs.push_back(it->second);
} else {
return ScopedAStatus::fromServiceSpecificErrorWithMessage(
toInt(StatusCode::INVALID_ARG),
@@ -665,13 +692,15 @@
VhalResult<void> DefaultVehicleHal::checkSubscribeOptions(
const std::vector<SubscribeOptions>& options) {
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
- if (mConfigsByPropId.find(propId) == mConfigsByPropId.end()) {
+ auto it = configsByPropId.find(propId);
+ if (it == configsByPropId.end()) {
return StatusError(StatusCode::INVALID_ARG)
<< StringPrintf("no config for property, ID: %" PRId32, propId);
}
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = it->second;
std::vector<VehicleAreaConfig> areaConfigs;
if (option.areaIds.empty()) {
areaConfigs = config.areaConfigs;
@@ -744,10 +773,11 @@
}
std::vector<SubscribeOptions> onChangeSubscriptions;
std::vector<SubscribeOptions> continuousSubscriptions;
+ const auto& configsByPropId = getConfigsByPropId();
for (const auto& option : options) {
int32_t propId = option.propId;
// We have already validate config exists.
- const VehiclePropConfig& config = mConfigsByPropId[propId];
+ const VehiclePropConfig& config = configsByPropId.at(propId);
SubscribeOptions optionCopy = option;
// If areaIds is empty, subscribe to all areas.
@@ -871,7 +901,7 @@
(areaConfig == nullptr || !hasRequiredAccess(areaConfig->access, accessToTest))) {
return StatusError(StatusCode::ACCESS_DENIED)
<< StringPrintf("Property %" PRId32 " does not have the following access: %" PRId32,
- propId, accessToTest);
+ propId, static_cast<int32_t>(accessToTest));
}
return {};
}
@@ -936,17 +966,19 @@
}
DumpResult result = mVehicleHardware->dump(options);
if (result.refreshPropertyConfigs) {
- getAllPropConfigsFromHardware();
+ std::scoped_lock lockGuard(mConfigInitLock);
+ getAllPropConfigsFromHardwareLocked();
}
dprintf(fd, "%s", (result.buffer + "\n").c_str());
if (!result.callerShouldDumpState) {
return STATUS_OK;
}
dprintf(fd, "Vehicle HAL State: \n");
+ const auto& configsByPropId = getConfigsByPropId();
{
std::scoped_lock<std::mutex> lockGuard(mLock);
dprintf(fd, "Interface version: %" PRId32 "\n", getVhalInterfaceVersion());
- dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
+ dprintf(fd, "Containing %zu property configs\n", configsByPropId.size());
dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index f1106ee..14ee707 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -40,6 +40,7 @@
using ::android::base::StringPrintf;
using ::ndk::ScopedAStatus;
+constexpr float EPSILON = 0.0000001;
constexpr float ONE_SECOND_IN_NANOS = 1'000'000'000.;
SubscribeOptions newSubscribeOptions(int32_t propId, int32_t areaId, float sampleRateHz,
@@ -88,7 +89,7 @@
}
float log = std::log10(resolution);
- return log == (int)log;
+ return std::abs(log - std::round(log)) < EPSILON;
}
void ContSubConfigs::refreshCombinedConfig() {
@@ -433,6 +434,9 @@
}
for (const auto& [client, callback] : mClientsByPropIdAreaId[propIdAreaId]) {
+ // if propId is on-change, propIdAreaId will not exist in mContSubConfigsByPropIdArea,
+ // returning an empty ContSubConfigs value for subConfigs i.e. with resolution = 0 and
+ // enableVur = false.
auto& subConfigs = mContSubConfigsByPropIdArea[propIdAreaId];
// Clients must be sent different VehiclePropValues with different levels of granularity
// as requested by the client using resolution.
diff --git a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
index f377202..440a9f9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/SubscriptionManagerTest.cpp
@@ -521,6 +521,8 @@
}
TEST_F(SubscriptionManagerTest, testCheckResolutionValid) {
+ ASSERT_TRUE(SubscriptionManager::checkResolution(0.0));
+ ASSERT_TRUE(SubscriptionManager::checkResolution(0.1));
ASSERT_TRUE(SubscriptionManager::checkResolution(1.0));
}
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 8b8d046..67eb837 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -544,6 +544,10 @@
void FakeFingerprintEngine::waitForFingerDown(ISessionCallback* cb,
const std::future<void>& cancel) {
+ if (mFingerIsDown) {
+ LOG(WARNING) << "waitForFingerDown: mFingerIsDown==true already!";
+ }
+
while (!mFingerIsDown) {
if (shouldCancel(cancel)) {
LOG(ERROR) << "waitForFingerDown, Fail: cancel";
diff --git a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
index 0699781..24693ef 100644
--- a/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
+++ b/bluetooth/aidl/default/net_bluetooth_mgmt.cpp
@@ -161,6 +161,16 @@
struct mgmt_ev_read_index_list* data =
(struct mgmt_ev_read_index_list*)ev.data;
+ // Prefer the exact hci_interface
+ for (int i = 0; i < data->num_controllers; i++) {
+ if (data->index[i] == hci_interface) {
+ ALOGI("hci interface %d found", data->index[i]);
+ ret = data->index[i];
+ goto end;
+ }
+ }
+
+ // Accept a larger one if we can't find the exact one
for (int i = 0; i < data->num_controllers; i++) {
if (data->index[i] >= hci_interface) {
ALOGI("hci interface %d found", data->index[i]);
@@ -173,7 +183,7 @@
// Received [Index Added] event.
if (ev.opcode == MGMT_EV_INDEX_ADDED && ev.index == hci_interface) {
ALOGI("hci interface %d added", hci_interface);
- ret = 0;
+ ret = hci_interface;
goto end;
}
}
@@ -253,9 +263,9 @@
rfkill(1);
// Wait for the HCI interface to complete initialization or to come online.
- hci_interface = waitHciDev(hci_interface);
- if (hci_interface < 0) {
- ALOGE("hci interface not found");
+ int hci = waitHciDev(hci_interface);
+ if (hci < 0) {
+ ALOGE("hci interface %d not found", hci_interface);
return -1;
}
@@ -268,7 +278,7 @@
struct sockaddr_hci hci_addr = {
.hci_family = AF_BLUETOOTH,
- .hci_dev = static_cast<uint16_t>(hci_interface),
+ .hci_dev = static_cast<uint16_t>(hci),
.hci_channel = HCI_CHANNEL_USER,
};
@@ -279,7 +289,7 @@
return -1;
}
- ALOGI("hci interface %d ready", hci_interface);
+ ALOGI("hci interface %d ready", hci);
bt_fd_ = fd;
return fd;
}
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index f8818fd..f273c7a 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -105,3 +105,25 @@
latest_android_hardware_bluetooth_audio + "-ndk",
],
}
+
+cc_defaults {
+ name: "latest_android_hardware_bluetooth_audio_ndk_android_shared",
+ target: {
+ android: {
+ shared_libs: [
+ latest_android_hardware_bluetooth_audio + "-ndk",
+ ],
+ },
+ },
+}
+
+cc_defaults {
+ name: "latest_android_hardware_bluetooth_audio_ndk_android_static",
+ target: {
+ android: {
+ static_libs: [
+ latest_android_hardware_bluetooth_audio + "-ndk",
+ ],
+ },
+ },
+}
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
index dc36ac0..2a2cab0 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProviderFactory.cpp
@@ -184,12 +184,13 @@
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
std::vector<CodecInfo> db_codec_info =
BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(session_type);
- if (!db_codec_info.empty()) {
- auto& provider_info = _aidl_return->emplace();
- provider_info.name = kLeAudioOffloadProviderName;
- provider_info.codecInfos = db_codec_info;
- return ndk::ScopedAStatus::ok();
- }
+ // Return provider info supports without checking db_codec_info
+ // This help with various flow implementation for multidirectional support.
+ auto& provider_info = _aidl_return->emplace();
+ provider_info.supportsMultidirectionalCapabilities = true;
+ provider_info.name = kLeAudioOffloadProviderName;
+ provider_info.codecInfos = db_codec_info;
+ return ndk::ScopedAStatus::ok();
}
if (session_type == SessionType::HFP_HARDWARE_OFFLOAD_DATAPATH) {
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index a692d84..6783c0f 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -30,6 +30,8 @@
constexpr uint8_t kLeAudioDirectionSink = 0x01;
constexpr uint8_t kLeAudioDirectionSource = 0x02;
+constexpr uint8_t kIsoDataPathHci = 0x00;
+constexpr uint8_t kIsoDataPathPlatformDefault = 0x01;
const std::map<CodecSpecificConfigurationLtv::SamplingFrequency, uint32_t>
freq_to_support_bitmask_map = {
@@ -85,6 +87,7 @@
std::map<int32_t, CodecSpecificConfigurationLtv::SamplingFrequency>
sampling_freq_map = {
{16000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000},
+ {24000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000},
{48000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000},
{96000, CodecSpecificConfigurationLtv::SamplingFrequency::HZ96000},
};
@@ -165,8 +168,8 @@
return cfg_codec == req_codec;
}
-bool LeAudioOffloadAudioProvider::isCapabilitiesMatchedContext(
- AudioContext setting_context,
+bool LeAudioOffloadAudioProvider::filterCapabilitiesMatchedContext(
+ AudioContext& setting_context,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
// If has no metadata, assume match
if (!capabilities.metadata.has_value()) return true;
@@ -175,10 +178,15 @@
if (!metadata.has_value()) continue;
if (metadata.value().getTag() == MetadataLtv::Tag::preferredAudioContexts) {
// Check all pref audio context to see if anything matched
- auto& context = metadata.value()
- .get<MetadataLtv::Tag::preferredAudioContexts>()
- .values;
- if (setting_context.bitmask & context.bitmask) return true;
+ auto& prefer_context =
+ metadata.value()
+ .get<MetadataLtv::Tag::preferredAudioContexts>()
+ .values;
+ if (setting_context.bitmask & prefer_context.bitmask) {
+ // New mask with matched capability
+ setting_context.bitmask &= prefer_context.bitmask;
+ return true;
+ }
}
}
@@ -189,8 +197,12 @@
CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies&
capability_freq) {
- for (auto [freq, bitmask] : freq_to_support_bitmask_map)
- if (cfg_freq == freq) return (capability_freq.bitmask & bitmask);
+ auto p = freq_to_support_bitmask_map.find(cfg_freq);
+ if (p != freq_to_support_bitmask_map.end()) {
+ if (capability_freq.bitmask & p->second) {
+ return true;
+ }
+ }
return false;
}
@@ -198,9 +210,11 @@
CodecSpecificConfigurationLtv::FrameDuration& cfg_fduration,
CodecSpecificCapabilitiesLtv::SupportedFrameDurations&
capability_fduration) {
- for (auto [fduration, bitmask] : fduration_to_support_fduration_map)
- if (cfg_fduration == fduration)
- return (capability_fduration.bitmask & bitmask);
+ auto p = fduration_to_support_fduration_map.find(cfg_fduration);
+ if (p != fduration_to_support_fduration_map.end())
+ if (capability_fduration.bitmask & p->second) {
+ return true;
+ }
return false;
}
@@ -209,8 +223,9 @@
/*cfg_channel*/,
CodecSpecificCapabilitiesLtv::SupportedAudioChannelCounts&
/*capability_channel*/) {
+ // Simply ignore.
+ // Later can use additional capabilities to match requirement.
bool isMatched = true;
- // TODO: how to match?
return isMatched;
}
@@ -240,69 +255,103 @@
for (auto& codec_capability : codec_capabilities) {
auto cfg = cfg_tag_map.find(cap_to_cfg_tag_map[codec_capability.getTag()]);
- // Cannot find tag for the capability:
- if (cfg == cfg_tag_map.end()) return false;
+ // If capability has this tag, but our configuration doesn't
+ // Then we will assume it is matched
+ if (cfg == cfg_tag_map.end()) {
+ continue;
+ }
- // Matching logic for sampling frequency
- if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies) {
- if (!isMatchedSamplingFreq(
- cfg->second
- .get<CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedSamplingFrequencies>()))
- return false;
- } else if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations) {
- if (!isMatchedFrameDuration(
- cfg->second
- .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedFrameDurations>()))
- return false;
- } else if (codec_capability.getTag() ==
- CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts) {
- if (!isMatchedAudioChannel(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedAudioChannelCounts>()))
- return false;
- } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
- supportedMaxCodecFramesPerSDU) {
- if (!isMatchedCodecFramesPerSDU(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::codecFrameBlocksPerSDU>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedMaxCodecFramesPerSDU>()))
- return false;
- } else if (codec_capability.getTag() == CodecSpecificCapabilitiesLtv::Tag::
- supportedOctetsPerCodecFrame) {
- if (!isMatchedOctetsPerCodecFrame(
- cfg->second.get<
- CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
- codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
- supportedOctetsPerCodecFrame>()))
- return false;
+ switch (codec_capability.getTag()) {
+ case CodecSpecificCapabilitiesLtv::Tag::supportedSamplingFrequencies: {
+ if (!isMatchedSamplingFreq(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedSamplingFrequencies>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedFrameDurations: {
+ if (!isMatchedFrameDuration(
+ cfg->second
+ .get<CodecSpecificConfigurationLtv::Tag::frameDuration>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedFrameDurations>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedAudioChannelCounts: {
+ if (!isMatchedAudioChannel(
+ cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+ audioChannelAllocation>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedAudioChannelCounts>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedMaxCodecFramesPerSDU: {
+ if (!isMatchedCodecFramesPerSDU(
+ cfg->second.get<CodecSpecificConfigurationLtv::Tag::
+ codecFrameBlocksPerSDU>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedMaxCodecFramesPerSDU>())) {
+ return false;
+ }
+ break;
+ }
+
+ case CodecSpecificCapabilitiesLtv::Tag::supportedOctetsPerCodecFrame: {
+ if (!isMatchedOctetsPerCodecFrame(
+ cfg->second.get<
+ CodecSpecificConfigurationLtv::Tag::octetsPerCodecFrame>(),
+ codec_capability.get<CodecSpecificCapabilitiesLtv::Tag::
+ supportedOctetsPerCodecFrame>())) {
+ return false;
+ }
+ break;
+ }
}
}
return true;
}
-bool LeAudioOffloadAudioProvider::isMatchedAseConfiguration(
- LeAudioAseConfiguration setting_cfg,
- LeAudioAseConfiguration requirement_cfg) {
+bool isMonoConfig(
+ CodecSpecificConfigurationLtv::AudioChannelAllocation allocation) {
+ auto channel_count = std::bitset<32>(allocation.bitmask);
+ return (channel_count.count() <= 1);
+}
+
+bool LeAudioOffloadAudioProvider::filterMatchedAseConfiguration(
+ LeAudioAseConfiguration& setting_cfg,
+ const LeAudioAseConfiguration& requirement_cfg) {
// Check matching for codec configuration <=> requirement ASE codec
// Also match if no CodecId requirement
if (requirement_cfg.codecId.has_value()) {
if (!setting_cfg.codecId.has_value()) return false;
if (!isMatchedValidCodec(setting_cfg.codecId.value(),
- requirement_cfg.codecId.value()))
+ requirement_cfg.codecId.value())) {
+ LOG(WARNING) << __func__ << ": Doesn't match valid codec, cfg = "
+ << setting_cfg.codecId.value().toString()
+ << ", req = " << requirement_cfg.codecId.value().toString();
return false;
+ }
}
- if (setting_cfg.targetLatency != requirement_cfg.targetLatency) return false;
+ if (requirement_cfg.targetLatency !=
+ LeAudioAseConfiguration::TargetLatency::UNDEFINED &&
+ setting_cfg.targetLatency != requirement_cfg.targetLatency) {
+ LOG(WARNING) << __func__ << ": Doesn't match target latency, cfg = "
+ << int(setting_cfg.targetLatency)
+ << ", req = " << int(requirement_cfg.targetLatency);
+ return false;
+ }
// Ignore PHY requirement
// Check all codec configuration
@@ -314,9 +363,26 @@
for (auto requirement_cfg : requirement_cfg.codecConfiguration) {
// Directly compare CodecSpecificConfigurationLtv
auto cfg = cfg_tag_map.find(requirement_cfg.getTag());
- if (cfg == cfg_tag_map.end()) return false;
+ // Config not found for this requirement, cannot match
+ if (cfg == cfg_tag_map.end()) {
+ LOG(WARNING) << __func__ << ": Config not found for the requirement "
+ << requirement_cfg.toString();
+ return false;
+ }
- if (cfg->second != requirement_cfg) return false;
+ // Ignore matching for audio channel allocation
+ // since the rule is complicated. Match outside instead
+ if (requirement_cfg.getTag() ==
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation)
+ continue;
+
+ if (cfg->second != requirement_cfg) {
+ LOG(WARNING) << __func__
+ << ": Config doesn't match the requirement, cfg = "
+ << cfg->second.toString()
+ << ", req = " << requirement_cfg.toString();
+ return false;
+ }
}
// Ignore vendor configuration and metadata requirement
@@ -326,10 +392,13 @@
bool LeAudioOffloadAudioProvider::isMatchedBISConfiguration(
LeAudioBisConfiguration bis_cfg,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities) {
- if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) return false;
- if (!isCapabilitiesMatchedCodecConfiguration(
- bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities))
+ if (!isMatchedValidCodec(bis_cfg.codecId, capabilities.codecId)) {
return false;
+ }
+ if (!isCapabilitiesMatchedCodecConfiguration(
+ bis_cfg.codecConfiguration, capabilities.codecSpecificCapabilities)) {
+ return false;
+ }
return true;
}
@@ -356,30 +425,132 @@
}
}
-void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
- std::vector<std::optional<AseDirectionConfiguration>>&
- direction_configurations,
- const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
- requirements,
- std::vector<std::optional<AseDirectionConfiguration>>&
- valid_direction_configurations) {
- for (auto direction_configuration : direction_configurations) {
- if (!requirements.has_value()) {
- // If there's no requirement, all are valid
- valid_direction_configurations.push_back(direction_configuration);
- continue;
+int getLeAudioAseConfigurationAllocationBitmask(LeAudioAseConfiguration cfg) {
+ for (auto cfg_ltv : cfg.codecConfiguration) {
+ if (cfg_ltv.getTag() ==
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+ return cfg_ltv
+ .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
}
- if (!direction_configuration.has_value()) continue;
+ }
+ return 0;
+}
- for (auto& requirement : requirements.value()) {
- if (!requirement.has_value()) continue;
- if (!isMatchedAseConfiguration(
+int getCountFromBitmask(int bitmask) {
+ return std::bitset<32>(bitmask).count();
+}
+
+std::optional<AseDirectionConfiguration> findValidMonoConfig(
+ std::vector<AseDirectionConfiguration>& valid_direction_configurations,
+ int bitmask) {
+ for (auto& cfg : valid_direction_configurations) {
+ int cfg_bitmask =
+ getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+ if (getCountFromBitmask(cfg_bitmask) <= 1) {
+ // Modify the bitmask to be the same as the requirement
+ for (auto& codec_cfg : cfg.aseConfiguration.codecConfiguration) {
+ if (codec_cfg.getTag() ==
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation) {
+ codec_cfg
+ .get<CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask = bitmask;
+ return cfg;
+ }
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+std::vector<AseDirectionConfiguration> getValidConfigurationsFromAllocation(
+ int req_allocation_bitmask,
+ std::vector<AseDirectionConfiguration>& valid_direction_configurations,
+ bool is_exact) {
+ // Prefer the same allocation_bitmask
+ int channel_count = getCountFromBitmask(req_allocation_bitmask);
+
+ if (is_exact) {
+ for (auto& cfg : valid_direction_configurations) {
+ int cfg_bitmask =
+ getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration);
+ if (cfg_bitmask == req_allocation_bitmask) {
+ LOG(DEBUG)
+ << __func__
+ << ": Found an exact match for the requirement allocation of "
+ << cfg_bitmask;
+ return {cfg};
+ }
+ }
+ return {};
+ }
+ // Not using exact match strategy
+ if (channel_count <= 1) {
+ // Mono requirement matched if cfg is a mono config
+ auto cfg = findValidMonoConfig(valid_direction_configurations,
+ req_allocation_bitmask);
+ if (cfg.has_value()) return {cfg.value()};
+ } else {
+ // Stereo requirement returns 2 mono configs
+ // that has a combined bitmask equal to the stereo config
+ std::vector<AseDirectionConfiguration> temp;
+ for (int bit = 0; bit < 32; ++bit)
+ if (req_allocation_bitmask & (1 << bit)) {
+ auto cfg =
+ findValidMonoConfig(valid_direction_configurations, (1 << bit));
+ if (cfg.has_value()) temp.push_back(cfg.value());
+ }
+ if (temp.size() == channel_count) return temp;
+ }
+ return {};
+}
+
+void LeAudioOffloadAudioProvider::filterRequirementAseDirectionConfiguration(
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
+ direction_configurations,
+ const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
+ valid_direction_configurations,
+ bool is_exact) {
+ // For every requirement, find the matched ase configuration
+ if (!direction_configurations.has_value()) return;
+
+ if (!valid_direction_configurations.has_value()) {
+ valid_direction_configurations =
+ std::vector<std::optional<AseDirectionConfiguration>>();
+ }
+
+ for (auto& requirement : requirements) {
+ if (!requirement.has_value()) continue;
+ auto req_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+ requirement.value().aseConfiguration);
+ auto req_channel_count = getCountFromBitmask(req_allocation_bitmask);
+
+ auto temp = std::vector<AseDirectionConfiguration>();
+
+ for (auto direction_configuration : direction_configurations.value()) {
+ if (!direction_configuration.has_value()) continue;
+ if (!filterMatchedAseConfiguration(
direction_configuration.value().aseConfiguration,
requirement.value().aseConfiguration))
continue;
// Valid if match any requirement.
- valid_direction_configurations.push_back(direction_configuration);
- break;
+ temp.push_back(direction_configuration.value());
+ }
+
+ // Get the best matching config based on channel allocation
+ auto total_cfg_channel_count = 0;
+ auto req_valid_configs = getValidConfigurationsFromAllocation(
+ req_allocation_bitmask, temp, is_exact);
+ // Count and check required channel counts
+ for (auto& cfg : req_valid_configs) {
+ total_cfg_channel_count += getCountFromBitmask(
+ getLeAudioAseConfigurationAllocationBitmask(cfg.aseConfiguration));
+ valid_direction_configurations.value().push_back(cfg);
+ }
+ if (total_cfg_channel_count != req_channel_count) {
+ valid_direction_configurations = std::nullopt;
+ return;
}
}
}
@@ -392,37 +563,45 @@
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
uint8_t direction) {
- // Try to match context in metadata.
- if (!isCapabilitiesMatchedContext(setting.audioContext, capabilities))
- return std::nullopt;
+ // Create a new LeAudioAseConfigurationSetting and return
+ // For other direction will contain all settings
+ LeAudioAseConfigurationSetting filtered_setting{
+ .audioContext = setting.audioContext,
+ .sinkAseConfiguration = setting.sinkAseConfiguration,
+ .sourceAseConfiguration = setting.sourceAseConfiguration,
+ .flags = setting.flags,
+ .packing = setting.packing,
+ };
// Get a list of all matched AseDirectionConfiguration
// for the input direction
std::vector<std::optional<AseDirectionConfiguration>>*
direction_configuration = nullptr;
if (direction == kLeAudioDirectionSink) {
- if (!setting.sinkAseConfiguration.has_value()) return std::nullopt;
- direction_configuration = &setting.sinkAseConfiguration.value();
+ if (!filtered_setting.sinkAseConfiguration.has_value()) return std::nullopt;
+ direction_configuration = &filtered_setting.sinkAseConfiguration.value();
} else {
- if (!setting.sourceAseConfiguration.has_value()) return std::nullopt;
- direction_configuration = &setting.sourceAseConfiguration.value();
+ if (!filtered_setting.sourceAseConfiguration.has_value())
+ return std::nullopt;
+ direction_configuration = &filtered_setting.sourceAseConfiguration.value();
}
std::vector<std::optional<AseDirectionConfiguration>>
valid_direction_configuration;
filterCapabilitiesAseDirectionConfiguration(
*direction_configuration, capabilities, valid_direction_configuration);
- if (valid_direction_configuration.empty()) return std::nullopt;
+
+ // No valid configuration for this direction
+ if (valid_direction_configuration.empty()) {
+ return std::nullopt;
+ }
// Create a new LeAudioAseConfigurationSetting and return
- LeAudioAseConfigurationSetting filtered_setting;
- filtered_setting.audioContext = setting.audioContext;
- filtered_setting.packing = setting.packing;
+ // For other direction will contain all settings
if (direction == kLeAudioDirectionSink) {
filtered_setting.sinkAseConfiguration = valid_direction_configuration;
} else {
filtered_setting.sourceAseConfiguration = valid_direction_configuration;
}
- filtered_setting.flags = setting.flags;
return filtered_setting;
}
@@ -433,44 +612,87 @@
std::optional<LeAudioAseConfigurationSetting>
LeAudioOffloadAudioProvider::getRequirementMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
- const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
- requirement) {
+ const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+ bool is_exact) {
// Try to match context in metadata.
- if (setting.audioContext != requirement.audioContext) return std::nullopt;
+ if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
+ requirement.audioContext.bitmask)
+ return std::nullopt;
- // Check requirement for the correct direction
- const std::optional<std::vector<std::optional<AseDirectionRequirement>>>*
- direction_requirement;
- std::vector<std::optional<AseDirectionConfiguration>>*
- direction_configuration;
- if (setting.sinkAseConfiguration.has_value()) {
- direction_configuration = &setting.sinkAseConfiguration.value();
- direction_requirement = &requirement.sinkAseRequirement;
- } else {
- direction_configuration = &setting.sourceAseConfiguration.value();
- direction_requirement = &requirement.sourceAseRequirement;
+ // Further filter setting's context
+ setting.audioContext.bitmask &= requirement.audioContext.bitmask;
+
+ // Create a new LeAudioAseConfigurationSetting to return
+ LeAudioAseConfigurationSetting filtered_setting{
+ .audioContext = setting.audioContext,
+ .packing = setting.packing,
+ .flags = setting.flags,
+ };
+
+ if (requirement.sinkAseRequirement.has_value()) {
+ filterRequirementAseDirectionConfiguration(
+ setting.sinkAseConfiguration, requirement.sinkAseRequirement.value(),
+ filtered_setting.sinkAseConfiguration, is_exact);
+ if (!filtered_setting.sinkAseConfiguration.has_value()) {
+ return std::nullopt;
+ }
}
- std::vector<std::optional<AseDirectionConfiguration>>
- valid_direction_configuration;
- filterRequirementAseDirectionConfiguration(*direction_configuration,
- *direction_requirement,
- valid_direction_configuration);
- if (valid_direction_configuration.empty()) return std::nullopt;
-
- // Create a new LeAudioAseConfigurationSetting and return
- LeAudioAseConfigurationSetting filtered_setting;
- filtered_setting.audioContext = setting.audioContext;
- filtered_setting.packing = setting.packing;
- if (setting.sinkAseConfiguration.has_value())
- filtered_setting.sinkAseConfiguration = valid_direction_configuration;
- else
- filtered_setting.sourceAseConfiguration = valid_direction_configuration;
- filtered_setting.flags = setting.flags;
+ if (requirement.sourceAseRequirement.has_value()) {
+ filterRequirementAseDirectionConfiguration(
+ setting.sourceAseConfiguration,
+ requirement.sourceAseRequirement.value(),
+ filtered_setting.sourceAseConfiguration, is_exact);
+ if (!filtered_setting.sourceAseConfiguration.has_value()) {
+ return std::nullopt;
+ }
+ }
return filtered_setting;
}
+std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+LeAudioOffloadAudioProvider::matchWithRequirement(
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
+ matched_ase_configuration_settings,
+ const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+ in_requirements,
+ bool is_exact) {
+ // Each requirement will match with a valid setting
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
+ for (auto& requirement : in_requirements) {
+ LOG(INFO) << __func__ << ": Trying to match for the requirement "
+ << requirement.toString();
+ bool is_matched = false;
+
+ for (auto& setting : matched_ase_configuration_settings) {
+ auto filtered_ase_configuration_setting =
+ getRequirementMatchedAseConfigurationSettings(setting, requirement,
+ is_exact);
+ if (filtered_ase_configuration_setting.has_value()) {
+ result.push_back(filtered_ase_configuration_setting.value());
+ LOG(INFO) << __func__ << ": Result = "
+ << filtered_ase_configuration_setting.value().toString();
+ // Found a matched setting, ignore other settings
+ is_matched = true;
+ break;
+ }
+ }
+ if (!is_matched) {
+ // If cannot satisfy this requirement, return an empty result
+ LOG(WARNING) << __func__ << ": Cannot match the requirement "
+ << requirement.toString();
+ result.clear();
+ break;
+ }
+ }
+ return result;
+}
+
+// For each requirement, a valid ASE configuration will satify:
+// - matched with any sink capability (if presented)
+// - OR matched with any source capability (if presented)
+// - and the setting need to pass the requirement
ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseConfiguration(
const std::optional<std::vector<
std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>&
@@ -487,48 +709,106 @@
ase_configuration_settings =
BluetoothAudioCodecs::GetLeAudioAseConfigurationSettings();
- // Currently won't handle case where both sink and source capabilities
- // are passed in. Only handle one of them.
- const std::optional<std::vector<
- std::optional<IBluetoothAudioProvider::LeAudioDeviceCapabilities>>>*
- in_remoteAudioCapabilities;
- uint8_t direction = 0;
- if (in_remoteSinkAudioCapabilities.has_value()) {
- direction = kLeAudioDirectionSink;
- in_remoteAudioCapabilities = &in_remoteSinkAudioCapabilities;
- } else {
- direction = kLeAudioDirectionSource;
- in_remoteAudioCapabilities = &in_remoteSourceAudioCapabilities;
+ if (!in_remoteSinkAudioCapabilities.has_value() &&
+ !in_remoteSourceAudioCapabilities.has_value()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ // Split out preferred and non-preferred settings based on context
+ // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
+ // -> preferred list will have settings with MEDIA context
+ // -> non-preferred list will have settings with any context
+ // We want to match requirement with preferred context settings first
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
- capability_matched_ase_configuration_settings;
- // Matching with remote capabilities
- for (auto& setting : ase_configuration_settings) {
- for (auto& capability : in_remoteAudioCapabilities->value()) {
- if (!capability.has_value()) continue;
- auto filtered_ase_configuration_setting =
- getCapabilitiesMatchedAseConfigurationSettings(
- setting, capability.value(), direction);
- if (filtered_ase_configuration_setting.has_value()) {
- capability_matched_ase_configuration_settings.push_back(
- filtered_ase_configuration_setting.value());
- }
- }
- }
+ matched_ase_configuration_settings;
+ // Matched ASE configuration with non-preferred audio context
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+ non_prefer_matched_ase_configuration_settings;
- // Matching with requirements
- std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
- for (auto& setting : capability_matched_ase_configuration_settings) {
- for (auto& requirement : in_requirements) {
- auto filtered_ase_configuration_setting =
- getRequirementMatchedAseConfigurationSettings(setting, requirement);
- if (filtered_ase_configuration_setting.has_value()) {
- result.push_back(filtered_ase_configuration_setting.value());
+ if (in_remoteSinkAudioCapabilities.has_value())
+ // Matching each setting with any remote capabilities
+ for (auto& setting : ase_configuration_settings)
+ for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_ase_configuration_setting =
+ getCapabilitiesMatchedAseConfigurationSettings(
+ setting, capability.value(), kLeAudioDirectionSink);
+ if (filtered_ase_configuration_setting.has_value()) {
+ // Push to non-prefer first for the broadest matching possible
+ non_prefer_matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ // Try to filter out prefer context to another vector.
+ if (filterCapabilitiesMatchedContext(
+ filtered_ase_configuration_setting.value().audioContext,
+ capability.value())) {
+ matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ }
+ }
}
- }
- }
+ // Combine filter every source capability
+ if (in_remoteSourceAudioCapabilities.has_value())
+ // Matching each setting with any remote capabilities
+ for (auto& setting : ase_configuration_settings)
+ for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_ase_configuration_setting =
+ getCapabilitiesMatchedAseConfigurationSettings(
+ setting, capability.value(), kLeAudioDirectionSource);
+ if (filtered_ase_configuration_setting.has_value()) {
+ // Put into the same list
+ // possibly duplicated, filtered by requirement later
+ // Push to non-prefer first for the broadest matching possible
+ non_prefer_matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ // Try to filter out prefer context to another vector.
+ if (filterCapabilitiesMatchedContext(
+ filtered_ase_configuration_setting.value().audioContext,
+ capability.value())) {
+ matched_ase_configuration_settings.push_back(
+ filtered_ase_configuration_setting.value());
+ }
+ }
+ }
+
+ // Matching priority list:
+ // Preferred context - exact match with allocation
+ // Any context - exact match with allocation
+ // Preferred context - loose match with allocation
+ // Any context - loose match with allocation
+
+ // A loose match will attempt to return 2 settings with the
+ // combined allocation bitmask equal the required allocation.
+ // For example, we can return 2 link (left link and right link) when
+ // the requirement required 1 (left + right) link.
+ auto result = matchWithRequirement(matched_ase_configuration_settings,
+ in_requirements, true);
+ if (result.empty()) {
+ LOG(WARNING)
+ << __func__
+ << ": Cannot match with preferred context settings - exact match";
+ result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
+ in_requirements, true);
+ }
+ if (result.empty()) {
+ LOG(WARNING)
+ << __func__
+ << ": Cannot match with non-preferred context settings - exact match";
+ result = matchWithRequirement(matched_ase_configuration_settings,
+ in_requirements, false);
+ }
+ if (result.empty()) {
+ LOG(WARNING) << __func__
+ << ": Cannot match with preferred context settings - "
+ "non-exact match";
+ result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
+ in_requirements, false);
+ }
+ if (result.empty())
+ LOG(ERROR) << __func__
+ << ": Cannot match with non preferred context settings - "
+ "non-exact match";
*_aidl_return = result;
return ndk::ScopedAStatus::ok();
};
@@ -537,19 +817,116 @@
LeAudioAseQosConfiguration setting_qos,
AseQosDirectionRequirement requirement_qos) {
if (setting_qos.retransmissionNum !=
- requirement_qos.preferredRetransmissionNum)
+ requirement_qos.preferredRetransmissionNum) {
return false;
- if (setting_qos.maxTransportLatencyMs > requirement_qos.maxTransportLatencyMs)
+ }
+ if (setting_qos.maxTransportLatencyMs >
+ requirement_qos.maxTransportLatencyMs) {
return false;
- // Ignore other parameters, as they are not populated in the setting_qos
+ }
return true;
}
+bool isValidQosRequirement(AseQosDirectionRequirement qosRequirement) {
+ return ((qosRequirement.maxTransportLatencyMs > 0) &&
+ (qosRequirement.presentationDelayMaxUs > 0) &&
+ (qosRequirement.presentationDelayMaxUs >=
+ qosRequirement.presentationDelayMinUs));
+}
+
+std::optional<LeAudioAseQosConfiguration>
+LeAudioOffloadAudioProvider::getDirectionQosConfiguration(
+ uint8_t direction,
+ const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+ qosRequirement,
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
+ bool is_exact) {
+ std::optional<AseQosDirectionRequirement> direction_qos_requirement =
+ std::nullopt;
+
+ // Get the correct direction
+ if (direction == kLeAudioDirectionSink) {
+ direction_qos_requirement = qosRequirement.sinkAseQosRequirement.value();
+ } else {
+ direction_qos_requirement = qosRequirement.sourceAseQosRequirement.value();
+ }
+
+ for (auto& setting : ase_configuration_settings) {
+ // Context matching
+ if ((setting.audioContext.bitmask & qosRequirement.audioContext.bitmask) !=
+ qosRequirement.audioContext.bitmask)
+ continue;
+
+ // Match configuration flags
+ // Currently configuration flags are not populated, ignore.
+
+ // Get a list of all matched AseDirectionConfiguration
+ // for the input direction
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>
+ direction_configuration = std::nullopt;
+ if (direction == kLeAudioDirectionSink) {
+ if (!setting.sinkAseConfiguration.has_value()) continue;
+ direction_configuration.emplace(setting.sinkAseConfiguration.value());
+ } else {
+ if (!setting.sourceAseConfiguration.has_value()) continue;
+ direction_configuration.emplace(setting.sourceAseConfiguration.value());
+ }
+
+ if (!direction_configuration.has_value()) {
+ return std::nullopt;
+ }
+
+ // Collect all valid cfg into a vector
+ // Then try to get the best match for audio allocation
+
+ auto temp = std::vector<AseDirectionConfiguration>();
+
+ for (auto& cfg : direction_configuration.value()) {
+ if (!cfg.has_value()) continue;
+ // If no requirement, return the first QoS
+ if (!direction_qos_requirement.has_value()) {
+ return cfg.value().qosConfiguration;
+ }
+
+ // If has requirement, return the first matched QoS
+ // Try to match the ASE configuration
+ // and QoS with requirement
+ if (!cfg.value().qosConfiguration.has_value()) continue;
+ if (filterMatchedAseConfiguration(
+ cfg.value().aseConfiguration,
+ direction_qos_requirement.value().aseConfiguration) &&
+ isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
+ direction_qos_requirement.value())) {
+ temp.push_back(cfg.value());
+ }
+ }
+ LOG(WARNING) << __func__ << ": Got " << temp.size()
+ << " configs, start matching allocation";
+
+ int qos_allocation_bitmask = getLeAudioAseConfigurationAllocationBitmask(
+ direction_qos_requirement.value().aseConfiguration);
+ // Get the best matching config based on channel allocation
+ auto req_valid_configs = getValidConfigurationsFromAllocation(
+ qos_allocation_bitmask, temp, is_exact);
+ if (req_valid_configs.empty()) {
+ LOG(WARNING) << __func__
+ << ": Cannot find matching allocation for bitmask "
+ << qos_allocation_bitmask;
+
+ } else {
+ return req_valid_configs[0].qosConfiguration;
+ }
+ }
+
+ return std::nullopt;
+}
+
ndk::ScopedAStatus LeAudioOffloadAudioProvider::getLeAudioAseQosConfiguration(
const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
in_qosRequirement,
IBluetoothAudioProvider::LeAudioAseQosConfigurationPair* _aidl_return) {
IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+
// Get all configuration settings
std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
ase_configuration_settings =
@@ -557,67 +934,35 @@
// Direction QoS matching
// Only handle one direction input case
- uint8_t direction = 0;
- std::optional<AseQosDirectionRequirement> direction_qos_requirement =
- std::nullopt;
if (in_qosRequirement.sinkAseQosRequirement.has_value()) {
- direction_qos_requirement = in_qosRequirement.sinkAseQosRequirement.value();
- direction = kLeAudioDirectionSink;
- } else if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
- direction_qos_requirement =
- in_qosRequirement.sourceAseQosRequirement.value();
- direction = kLeAudioDirectionSource;
- }
-
- for (auto& setting : ase_configuration_settings) {
- // Context matching
- if (setting.audioContext != in_qosRequirement.audioContext) continue;
-
- // Match configuration flags
- // Currently configuration flags are not populated, ignore.
-
- // Get a list of all matched AseDirectionConfiguration
- // for the input direction
- std::vector<std::optional<AseDirectionConfiguration>>*
- direction_configuration = nullptr;
- if (direction == kLeAudioDirectionSink) {
- if (!setting.sinkAseConfiguration.has_value()) continue;
- direction_configuration = &setting.sinkAseConfiguration.value();
- } else {
- if (!setting.sourceAseConfiguration.has_value()) continue;
- direction_configuration = &setting.sourceAseConfiguration.value();
- }
-
- for (auto cfg : *direction_configuration) {
- if (!cfg.has_value()) continue;
- // If no requirement, return the first QoS
- if (!direction_qos_requirement.has_value()) {
- result.sinkQosConfiguration = cfg.value().qosConfiguration;
- result.sourceQosConfiguration = cfg.value().qosConfiguration;
- *_aidl_return = result;
- return ndk::ScopedAStatus::ok();
- }
-
- // If has requirement, return the first matched QoS
- // Try to match the ASE configuration
- // and QoS with requirement
- if (!cfg.value().qosConfiguration.has_value()) continue;
- if (isMatchedAseConfiguration(
- cfg.value().aseConfiguration,
- direction_qos_requirement.value().aseConfiguration) &&
- isMatchedQosRequirement(cfg.value().qosConfiguration.value(),
- direction_qos_requirement.value())) {
- if (direction == kLeAudioDirectionSink)
- result.sinkQosConfiguration = cfg.value().qosConfiguration;
- else
- result.sourceQosConfiguration = cfg.value().qosConfiguration;
- *_aidl_return = result;
- return ndk::ScopedAStatus::ok();
+ if (!isValidQosRequirement(in_qosRequirement.sinkAseQosRequirement.value()))
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ {
+ // Try exact match first
+ result.sinkQosConfiguration =
+ getDirectionQosConfiguration(kLeAudioDirectionSink, in_qosRequirement,
+ ase_configuration_settings, true);
+ if (!result.sinkQosConfiguration.has_value()) {
+ result.sinkQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSink, in_qosRequirement,
+ ase_configuration_settings, false);
}
}
}
+ if (in_qosRequirement.sourceAseQosRequirement.has_value()) {
+ if (!isValidQosRequirement(
+ in_qosRequirement.sourceAseQosRequirement.value()))
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ result.sourceQosConfiguration =
+ getDirectionQosConfiguration(kLeAudioDirectionSource, in_qosRequirement,
+ ase_configuration_settings, true);
+ if (!result.sourceQosConfiguration.has_value()) {
+ result.sourceQosConfiguration = getDirectionQosConfiguration(
+ kLeAudioDirectionSource, in_qosRequirement,
+ ase_configuration_settings, false);
+ }
+ }
- // No match, return empty QoS
*_aidl_return = result;
return ndk::ScopedAStatus::ok();
};
@@ -640,24 +985,127 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
};
+LeAudioBroadcastConfigurationSetting getDefaultBroadcastSetting(
+ int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
+ LeAudioBroadcastConfigurationSetting setting;
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.sduIntervalUs = 10000;
+ setting.maxSduOctets = 40;
+
+ if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
+ LOG(INFO) << __func__ << ": High quality, returning high quality settings";
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 65;
+ setting.maxSduOctets = 200;
+ return setting;
+ }
+
+ // Populate other settings base on context
+ // TODO: Populate with better design
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
+ setting.retransmitionNum = 2;
+ setting.maxTransportLatencyMs = 10;
+ setting.maxSduOctets = 120;
+ } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
+ setting.retransmitionNum = 2;
+ setting.maxTransportLatencyMs = 10;
+ setting.maxSduOctets = 40;
+ } else if (context_bitmask &
+ (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 80;
+ } else if (context_bitmask &
+ (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
+ AudioContext::EMERGENCY_ALARM)) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 40;
+ } else if (context_bitmask & AudioContext::MEDIA) {
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.maxSduOctets = 120;
+ }
+
+ return setting;
+}
+void modifySubBISConfigAllocation(
+ IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration& sub_bis_cfg,
+ int allocation_bitmask) {
+ for (auto& codec_cfg : sub_bis_cfg.bisConfiguration.codecConfiguration) {
+ if (codec_cfg.getTag() ==
+ CodecSpecificConfigurationLtv::audioChannelAllocation) {
+ codec_cfg.get<CodecSpecificConfigurationLtv::audioChannelAllocation>()
+ .bitmask = allocation_bitmask;
+ break;
+ }
+ }
+}
+void modifySubgroupConfiguration(
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration&
+ subgroup_cfg,
+ int context_bitmask) {
+ // STEREO configs
+ // Split into 2 sub BIS config, each has numBis = 1
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
+ AudioContext::SOUND_EFFECTS |
+ AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
+ if (subgroup_cfg.bisConfigurations.size() == 1)
+ subgroup_cfg.bisConfigurations.push_back(
+ subgroup_cfg.bisConfigurations[0]);
+
+ subgroup_cfg.bisConfigurations[0].numBis = 1;
+ modifySubBISConfigAllocation(
+ subgroup_cfg.bisConfigurations[0],
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT);
+
+ subgroup_cfg.bisConfigurations[1].numBis = 1;
+ modifySubBISConfigAllocation(
+ subgroup_cfg.bisConfigurations[1],
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT);
+ return;
+ }
+
+ // MONO configs
+ for (auto& sub_bis_cfg : subgroup_cfg.bisConfigurations) {
+ sub_bis_cfg.numBis = 1;
+ modifySubBISConfigAllocation(
+ sub_bis_cfg,
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER);
+ }
+}
+
void LeAudioOffloadAudioProvider::getBroadcastSettings() {
if (!broadcast_settings.empty()) return;
- LOG(INFO) << __func__ << ": Loading broadcast settings from provider info";
+ LOG(INFO) << __func__
+ << ": Loading basic broadcast settings from provider info";
std::vector<CodecInfo> db_codec_info =
BluetoothAudioCodecs::GetLeAudioOffloadCodecInfo(
SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH);
+ for (auto x : db_codec_info) {
+ LOG(INFO) << __func__ << ": codec info = " << x.toString();
+ }
broadcast_settings.clear();
+
+ // Default value population
CodecSpecificConfigurationLtv::AudioChannelAllocation default_allocation;
default_allocation.bitmask =
CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_CENTER;
+ CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU default_frame;
+ default_frame.value = 1;
for (auto& codec_info : db_codec_info) {
if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio)
continue;
auto& transport = codec_info.transport.get<CodecInfo::Transport::leAudio>();
LeAudioBroadcastConfigurationSetting setting;
+ setting.retransmitionNum = 4;
+ setting.maxTransportLatencyMs = 60;
+ setting.sduIntervalUs = 10000;
+ setting.maxSduOctets = 40;
// Default setting
setting.numBis = 1;
setting.phy = {Phy::TWO_M};
@@ -669,14 +1117,21 @@
octets.value = transport.bitdepth[0];
bis_cfg.codecConfiguration = {
- sampling_freq_map[transport.samplingFrequencyHz[0]], octets,
- frame_duration_map[transport.frameDurationUs[0]], default_allocation};
+ sampling_freq_map[transport.samplingFrequencyHz[0]],
+ octets,
+ frame_duration_map[transport.frameDurationUs[0]],
+ default_allocation,
+ default_frame,
+ };
+
+ // Ignore bis_cfg.metadata
// Add information to structure
IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration sub_bis_cfg;
sub_bis_cfg.numBis = 1;
sub_bis_cfg.bisConfiguration = bis_cfg;
IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration sub_cfg;
+ // Populate the same sub config
sub_cfg.bisConfigurations = {sub_bis_cfg};
setting.subgroupsConfigurations = {sub_cfg};
@@ -721,6 +1176,93 @@
return filtered_setting;
}
+std::vector<CodecSpecificConfigurationLtv> getCodecRequirementBasedOnContext(
+ int context_bitmask, IBluetoothAudioProvider::BroadcastQuality quality) {
+ // Default requirement: lc3_stereo_16_2
+ std::vector<CodecSpecificConfigurationLtv> requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+
+ if (quality == IBluetoothAudioProvider::BroadcastQuality::HIGH) {
+ LOG(INFO) << __func__
+ << ": High quality, returning high quality requirement";
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ48000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ return requirement;
+ }
+
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME)) {
+ // lc3_stereo_24_2_1
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask & (AudioContext::INSTRUCTIONAL)) {
+ // lc3_mono_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask &
+ (AudioContext::SOUND_EFFECTS | AudioContext::UNSPECIFIED)) {
+ // lc3_stereo_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask &
+ (AudioContext::ALERTS | AudioContext::NOTIFICATIONS |
+ AudioContext::EMERGENCY_ALARM)) {
+ // Default requirement: lc3_stereo_16_2
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ } else if (context_bitmask & AudioContext::MEDIA) {
+ // Default requirement: lc3_stereo_16_2
+ // Return the 48k requirement
+ requirement = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ24000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ };
+ }
+ return requirement;
+}
+
+bool LeAudioOffloadAudioProvider::isSubgroupConfigurationMatchedContext(
+ AudioContext requirement_context,
+ IBluetoothAudioProvider::BroadcastQuality quality,
+ LeAudioBroadcastSubgroupConfiguration configuration) {
+ // Find any valid context metadata in the bisConfigurations
+ // assuming the bis configuration in the same bis subgroup
+ // will have the same context metadata
+ std::optional<AudioContext> config_context = std::nullopt;
+
+ auto codec_requirement =
+ getCodecRequirementBasedOnContext(requirement_context.bitmask, quality);
+ std::map<CodecSpecificConfigurationLtv::Tag, CodecSpecificConfigurationLtv>
+ req_tag_map;
+ for (auto x : codec_requirement) req_tag_map[x.getTag()] = x;
+
+ for (auto& bis_cfg : configuration.bisConfigurations) {
+ // Check every sub_bis_cfg to see which match
+ for (auto& x : bis_cfg.bisConfiguration.codecConfiguration) {
+ auto p = req_tag_map.find(x.getTag());
+ if (p == req_tag_map.end()) continue;
+ if (p->second != x) {
+ LOG(WARNING) << __func__ << ": does not match for context "
+ << requirement_context.toString()
+ << ", cfg = " << x.toString();
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
ndk::ScopedAStatus
LeAudioOffloadAudioProvider::getLeAudioBroadcastConfiguration(
const std::optional<std::vector<
@@ -729,23 +1271,29 @@
const IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement&
in_requirement,
LeAudioBroadcastConfigurationSetting* _aidl_return) {
- getBroadcastSettings();
- _aidl_return = nullptr;
-
- // Match and filter capability
- std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
- if (!in_remoteSinkAudioCapabilities.has_value()) {
- LOG(WARNING) << __func__ << ": Empty capability";
- return ndk::ScopedAStatus::ok();
+ if (in_requirement.subgroupConfigurationRequirements.empty()) {
+ LOG(WARNING) << __func__ << ": Empty requirement";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- for (auto& setting : broadcast_settings) {
- for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
- if (!capability.has_value()) continue;
- auto filtered_setting =
- getCapabilitiesMatchedBroadcastConfigurationSettings(
- setting, capability.value());
- if (filtered_setting.has_value())
- filtered_settings.push_back(filtered_setting.value());
+
+ // Broadcast setting are from provider info
+ // We will allow empty capability input, match all settings with requirements.
+ getBroadcastSettings();
+ std::vector<LeAudioBroadcastConfigurationSetting> filtered_settings;
+ if (!in_remoteSinkAudioCapabilities.has_value() ||
+ in_remoteSinkAudioCapabilities.value().empty()) {
+ LOG(INFO) << __func__ << ": Empty capability, get all broadcast settings";
+ filtered_settings = broadcast_settings;
+ } else {
+ for (auto& setting : broadcast_settings) {
+ for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
+ if (!capability.has_value()) continue;
+ auto filtered_setting =
+ getCapabilitiesMatchedBroadcastConfigurationSettings(
+ setting, capability.value());
+ if (filtered_setting.has_value())
+ filtered_settings.push_back(filtered_setting.value());
+ }
}
}
@@ -754,39 +1302,82 @@
return ndk::ScopedAStatus::ok();
}
- // Match and return the first matched requirement
if (in_requirement.subgroupConfigurationRequirements.empty()) {
LOG(INFO) << __func__ << ": Empty requirement";
*_aidl_return = filtered_settings[0];
return ndk::ScopedAStatus::ok();
}
- for (auto& setting : filtered_settings) {
- // Further filter out bis configuration
- LeAudioBroadcastConfigurationSetting filtered_setting(setting);
- filtered_setting.subgroupsConfigurations.clear();
- for (auto& sub_cfg : setting.subgroupsConfigurations) {
- bool isMatched = false;
- for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
- // Matching number of BIS
- if (sub_req.bisNumPerSubgroup != sub_cfg.bisConfigurations.size())
- continue;
- // Currently will ignore quality and context hint.
- isMatched = true;
+ // For each subgroup config requirement, find a suitable subgroup config.
+ // Gather these suitable subgroup config in an array.
+ // If the setting can satisfy all requirement, we can return the setting
+ // with the filtered array.
+
+ auto context_bitmask =
+ in_requirement.subgroupConfigurationRequirements[0].audioContext.bitmask;
+ auto quality = in_requirement.subgroupConfigurationRequirements[0].quality;
+ LeAudioBroadcastConfigurationSetting return_setting =
+ getDefaultBroadcastSetting(context_bitmask, quality);
+ // Default setting
+ return_setting.numBis = 0;
+ return_setting.subgroupsConfigurations = {};
+
+ LeAudioDataPathConfiguration path;
+ path.isoDataPathConfiguration.isTransparent = true;
+ path.dataPathId = kIsoDataPathPlatformDefault;
+
+ // Each subreq, find a setting that match
+ for (auto& sub_req : in_requirement.subgroupConfigurationRequirements) {
+ bool is_setting_matched = false;
+ for (auto setting : filtered_settings) {
+ bool is_matched = true;
+ // Check if every sub BIS config satisfy
+ for (auto& sub_group_config : setting.subgroupsConfigurations) {
+ if (!isSubgroupConfigurationMatchedContext(
+ sub_req.audioContext, sub_req.quality, sub_group_config)) {
+ is_matched = false;
+ break;
+ }
+ path.isoDataPathConfiguration.codecId =
+ sub_group_config.bisConfigurations[0].bisConfiguration.codecId;
+ // Also modify the subgroup config to match the context
+ modifySubgroupConfiguration(sub_group_config, context_bitmask);
+ }
+
+ if (is_matched) {
+ is_setting_matched = true;
+ for (auto& sub_group_config : setting.subgroupsConfigurations)
+ return_setting.subgroupsConfigurations.push_back(sub_group_config);
break;
}
- if (isMatched)
- filtered_setting.subgroupsConfigurations.push_back(sub_cfg);
}
- // Return the first match
- if (!filtered_setting.subgroupsConfigurations.empty()) {
- LOG(INFO) << __func__ << ": Matched requirement";
- *_aidl_return = filtered_setting;
+
+ if (!is_setting_matched) {
+ LOG(WARNING) << __func__
+ << ": Cannot find a setting that match requirement "
+ << sub_req.toString();
return ndk::ScopedAStatus::ok();
}
}
- LOG(WARNING) << __func__ << ": Cannot match any requirement";
+ // Populate all numBis
+ for (auto& sub_group_config : return_setting.subgroupsConfigurations) {
+ for (auto& sub_bis_config : sub_group_config.bisConfigurations) {
+ return_setting.numBis += sub_bis_config.numBis;
+ }
+ }
+ return_setting.phy = std::vector<Phy>(return_setting.numBis, Phy::TWO_M);
+ // Populate data path config
+ return_setting.dataPathConfiguration = path;
+ // TODO: Workaround for STEREO configs maxSduOctets being doubled
+ if (context_bitmask & (AudioContext::LIVE_AUDIO | AudioContext::GAME |
+ AudioContext::SOUND_EFFECTS |
+ AudioContext::UNSPECIFIED | AudioContext::MEDIA)) {
+ return_setting.maxSduOctets /= 2;
+ }
+ LOG(INFO) << __func__
+ << ": Combined setting that match: " << return_setting.toString();
+ *_aidl_return = return_setting;
return ndk::ScopedAStatus::ok();
};
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 2785e7f..043d923 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -96,8 +96,8 @@
// Private matching function definitions
bool isMatchedValidCodec(CodecId cfg_codec, CodecId req_codec);
- bool isCapabilitiesMatchedContext(
- AudioContext setting_context,
+ bool filterCapabilitiesMatchedContext(
+ AudioContext& setting_context,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
bool isMatchedSamplingFreq(
CodecSpecificConfigurationLtv::SamplingFrequency& cfg_freq,
@@ -122,8 +122,9 @@
bool isCapabilitiesMatchedCodecConfiguration(
std::vector<CodecSpecificConfigurationLtv>& codec_cfg,
std::vector<CodecSpecificCapabilitiesLtv> codec_capabilities);
- bool isMatchedAseConfiguration(LeAudioAseConfiguration setting_cfg,
- LeAudioAseConfiguration requirement_cfg);
+ bool filterMatchedAseConfiguration(
+ LeAudioAseConfiguration& setting_cfg,
+ const LeAudioAseConfiguration& requirement_cfg);
bool isMatchedBISConfiguration(
LeAudioBisConfiguration bis_cfg,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
@@ -134,12 +135,12 @@
std::vector<std::optional<AseDirectionConfiguration>>&
valid_direction_configurations);
void filterRequirementAseDirectionConfiguration(
- std::vector<std::optional<AseDirectionConfiguration>>&
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
direction_configurations,
- const std::optional<std::vector<std::optional<AseDirectionRequirement>>>&
- requirements,
- std::vector<std::optional<AseDirectionConfiguration>>&
- valid_direction_configurations);
+ const std::vector<std::optional<AseDirectionRequirement>>& requirements,
+ std::optional<std::vector<std::optional<AseDirectionConfiguration>>>&
+ valid_direction_configurations,
+ bool is_exact);
std::optional<LeAudioAseConfigurationSetting>
getCapabilitiesMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
@@ -149,7 +150,8 @@
getRequirementMatchedAseConfigurationSettings(
IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
- requirement);
+ requirement,
+ bool is_exact);
bool isMatchedQosRequirement(LeAudioAseQosConfiguration setting_qos,
AseQosDirectionRequirement requirement_qos);
std::optional<LeAudioBroadcastConfigurationSetting>
@@ -157,6 +159,24 @@
LeAudioBroadcastConfigurationSetting& setting,
const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities);
void getBroadcastSettings();
+ std::optional<LeAudioAseQosConfiguration> getDirectionQosConfiguration(
+ uint8_t direction,
+ const IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement&
+ qosRequirement,
+ std::vector<LeAudioAseConfigurationSetting>& ase_configuration_settings,
+ bool is_exact);
+ bool isSubgroupConfigurationMatchedContext(
+ AudioContext requirement_context,
+ IBluetoothAudioProvider::BroadcastQuality quality,
+ LeAudioBroadcastSubgroupConfiguration configuration);
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+ matchWithRequirement(
+ std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
+ matched_ase_configuration_settings,
+ const std::vector<
+ IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
+ in_requirements,
+ bool is_exact);
};
class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index c313fb7..e83cb9e 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -58,6 +58,7 @@
using aidl::android::hardware::bluetooth::audio::CodecSpecificCapabilitiesLtv;
using aidl::android::hardware::bluetooth::audio::CodecSpecificConfigurationLtv;
using aidl::android::hardware::bluetooth::audio::CodecType;
+using aidl::android::hardware::bluetooth::audio::ConfigurationFlags;
using aidl::android::hardware::bluetooth::audio::HfpConfiguration;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioPort;
using aidl::android::hardware::bluetooth::audio::IBluetoothAudioProvider;
@@ -68,6 +69,7 @@
using aidl::android::hardware::bluetooth::audio::LdacCapabilities;
using aidl::android::hardware::bluetooth::audio::LdacConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioAseConfiguration;
+using aidl::android::hardware::bluetooth::audio::LeAudioBisConfiguration;
using aidl::android::hardware::bluetooth::audio::LeAudioBroadcastConfiguration;
using aidl::android::hardware::bluetooth::audio::
LeAudioCodecCapabilitiesSetting;
@@ -105,12 +107,24 @@
LeAudioAseConfigurationSetting::AseDirectionConfiguration;
using AseQosDirectionRequirement = IBluetoothAudioProvider::
LeAudioAseQosConfigurationRequirement::AseQosDirectionRequirement;
+using LeAudioAseQosConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement;
using LeAudioAseQosConfiguration =
IBluetoothAudioProvider::LeAudioAseQosConfiguration;
using LeAudioDeviceCapabilities =
IBluetoothAudioProvider::LeAudioDeviceCapabilities;
using LeAudioConfigurationRequirement =
IBluetoothAudioProvider::LeAudioConfigurationRequirement;
+using LeAudioBroadcastConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement;
+using LeAudioBroadcastSubgroupConfiguration =
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfiguration;
+using LeAudioBroadcastSubgroupConfigurationRequirement =
+ IBluetoothAudioProvider::LeAudioBroadcastSubgroupConfigurationRequirement;
+using LeAudioBroadcastConfigurationSetting =
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting;
+using LeAudioSubgroupBisConfiguration =
+ IBluetoothAudioProvider::LeAudioSubgroupBisConfiguration;
// Constants
@@ -2228,6 +2242,37 @@
BluetoothAudioProviderFactoryAidl::TearDown();
}
+ bool IsMultidirectionalCapabilitiesEnabled() {
+ if (!temp_provider_info_.has_value()) return false;
+
+ return temp_provider_info_.value().supportsMultidirectionalCapabilities;
+ }
+
+ bool IsAsymmetricConfigurationAllowed() {
+ if (!temp_provider_info_.has_value()) return false;
+ if (temp_provider_info_.value().codecInfos.empty()) return false;
+
+ for (auto& codec_info : temp_provider_info_.value().codecInfos) {
+ if (codec_info.transport.getTag() != CodecInfo::Transport::leAudio) {
+ return false;
+ }
+
+ auto flags =
+ codec_info.transport.get<CodecInfo::Transport::leAudio>().flags;
+
+ if (!flags) {
+ continue;
+ }
+
+ if (flags->bitmask &
+ ConfigurationFlags::ALLOW_ASYMMETRIC_CONFIGURATIONS) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
bool IsOffloadOutputSupported() {
for (auto& capability : temp_provider_capabilities_) {
if (capability.getTag() != AudioCapabilities::leAudioCapabilities) {
@@ -2284,27 +2329,31 @@
return media_audio_context;
}
- LeAudioDeviceCapabilities GetDefaultRemoteCapability() {
+ LeAudioDeviceCapabilities GetDefaultRemoteSinkCapability() {
// Create a capability
LeAudioDeviceCapabilities capability;
capability.codecId = CodecId::Core::LC3;
auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
- pref_context_metadata.values = GetAudioContext(AudioContext::MEDIA);
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+ AudioContext::GAME);
capability.metadata = {pref_context_metadata};
auto sampling_rate =
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
auto frame_duration =
CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
frame_duration.bitmask =
- CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500;
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
octets.min = 0;
- octets.max = 60;
+ octets.max = 120;
auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
frames.value = 2;
capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
@@ -2312,29 +2361,394 @@
return capability;
}
- LeAudioConfigurationRequirement GetDefaultRequirement(
- bool is_source_requriement) {
+ LeAudioDeviceCapabilities GetDefaultRemoteSourceCapability() {
+ // Create a capability
+ LeAudioDeviceCapabilities capability;
+
+ capability.codecId = CodecId::Core::LC3;
+
+ auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::LIVE_AUDIO |
+ AudioContext::CONVERSATIONAL | AudioContext::GAME);
+ capability.metadata = {pref_context_metadata};
+
+ auto sampling_rate =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+ sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000 |
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ8000;
+ auto frame_duration =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+ frame_duration.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+ auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+ octets.min = 0;
+ octets.max = 120;
+ auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+ frames.value = 2;
+ capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+ octets, frames};
+ return capability;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+ const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+ CodecSpecificConfigurationLtv::Tag tag) {
+ for (const auto ltv : configurationLtvs) {
+ if (ltv.getTag() == tag) {
+ return ltv;
+ }
+ }
+ return std::nullopt;
+ }
+
+ bool IsAseRequirementSatisfiedWithUnknownChannelCount(
+ const std::vector<std::optional<AseDirectionRequirement>>&
+ ase_requirements,
+ const std::vector<std::optional<AseDirectionConfiguration>>&
+ ase_configurations) {
+ /* This is mandatory to match sample freq, allocation however, when in the
+ * device group there is only one device which supports left and right
+ * allocation, and channel count is hidden from the BT stack, the BT stack
+ * will send single requirement but it can receive two configurations if the
+ * channel count is 1.
+ */
+
+ int num_of_ase_requirements = 0;
+ for (const auto& ase_req : ase_requirements) {
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (required_allocation_ltv == std::nullopt) {
+ continue;
+ }
+ int required_allocation =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+ num_of_ase_requirements += std::bitset<32>(required_allocation).count();
+ }
+
+ int num_of_satisfied_ase_requirements = 0;
+ for (const auto& ase_req : ase_requirements) {
+ if (!ase_req) {
+ continue;
+ }
+ auto required_sample_freq_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+ /* Allocation and sample freq shall be always in the requirement */
+ if (!required_sample_freq_ltv || !required_allocation_ltv) {
+ return false;
+ }
+
+ int required_allocation =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+
+ for (const auto& ase_conf : ase_configurations) {
+ if (!ase_conf) {
+ continue;
+ }
+ auto config_sample_freq_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto config_allocation_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (config_sample_freq_ltv == std::nullopt ||
+ config_allocation_ltv == std::nullopt) {
+ return false;
+ }
+
+ int configured_allocation = config_allocation_ltv
+ ->get<CodecSpecificConfigurationLtv::
+ Tag::audioChannelAllocation>()
+ .bitmask;
+
+ if (config_sample_freq_ltv == required_sample_freq_ltv &&
+ (required_allocation & configured_allocation)) {
+ num_of_satisfied_ase_requirements +=
+ std::bitset<32>(configured_allocation).count();
+ }
+ }
+ }
+
+ return (num_of_satisfied_ase_requirements == num_of_ase_requirements);
+ }
+
+ bool IsAseRequirementSatisfied(
+ const std::vector<std::optional<AseDirectionRequirement>>&
+ ase_requirements,
+ const std::vector<std::optional<AseDirectionConfiguration>>&
+ ase_configurations) {
+ // This is mandatory to match sample freq, allocation
+ int num_of_satisfied_ase_requirements = 0;
+
+ int required_allocations = 0;
+ for (const auto& ase_req : ase_requirements) {
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (required_allocation_ltv == std::nullopt) {
+ continue;
+ }
+
+ int allocations =
+ required_allocation_ltv
+ ->get<
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation>()
+ .bitmask;
+ required_allocations += std::bitset<32>(allocations).count();
+ }
+
+ if (ase_requirements.size() != required_allocations) {
+ /* If more than one allication is requested in the requirement, then use
+ * different verifier */
+ return IsAseRequirementSatisfiedWithUnknownChannelCount(
+ ase_requirements, ase_configurations);
+ }
+
+ for (const auto& ase_req : ase_requirements) {
+ if (!ase_req) {
+ continue;
+ }
+ auto required_sample_freq_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto required_allocation_ltv = GetConfigurationLtv(
+ ase_req->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+
+ /* Allocation and sample freq shall be always in the requirement */
+ if (!required_sample_freq_ltv || !required_allocation_ltv) {
+ return false;
+ }
+
+ for (const auto& ase_conf : ase_configurations) {
+ if (!ase_conf) {
+ continue;
+ }
+ auto config_sample_freq_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ auto config_allocation_ltv = GetConfigurationLtv(
+ ase_conf->aseConfiguration.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::audioChannelAllocation);
+ if (config_sample_freq_ltv == std::nullopt ||
+ config_allocation_ltv == std::nullopt) {
+ return false;
+ }
+
+ if (config_sample_freq_ltv == required_sample_freq_ltv &&
+ config_allocation_ltv == required_allocation_ltv) {
+ num_of_satisfied_ase_requirements++;
+ break;
+ }
+ }
+ }
+
+ return (num_of_satisfied_ase_requirements == ase_requirements.size());
+ }
+
+ void VerifyIfRequirementsSatisfied(
+ const std::vector<LeAudioConfigurationRequirement>& requirements,
+ const std::vector<LeAudioAseConfigurationSetting>& configurations) {
+ if (requirements.empty() && configurations.empty()) {
+ return;
+ }
+
+ /* It might happen that vendor lib will provide same configuration for
+ * multiple contexts and it should be accepted
+ */
+
+ int num_of_requirements = 0;
+ for (const auto& req : requirements) {
+ num_of_requirements += std::bitset<32>(req.audioContext.bitmask).count();
+ }
+
+ int num_of_configurations = 0;
+ for (const auto& conf : configurations) {
+ num_of_configurations +=
+ std::bitset<32>(conf.audioContext.bitmask).count();
+ }
+
+ ASSERT_EQ(num_of_requirements, num_of_configurations);
+
+ int num_of_satisfied_requirements = 0;
+ for (const auto& req : requirements) {
+ for (const auto& conf : configurations) {
+ if ((req.audioContext.bitmask & conf.audioContext.bitmask) !=
+ req.audioContext.bitmask) {
+ continue;
+ }
+
+ if (req.sinkAseRequirement && req.sourceAseRequirement) {
+ if (!conf.sinkAseConfiguration || !conf.sourceAseConfiguration) {
+ continue;
+ }
+
+ if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+ *conf.sinkAseConfiguration) ||
+ !IsAseRequirementSatisfied(*req.sourceAseRequirement,
+ *conf.sourceAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+
+ break;
+ } else if (req.sinkAseRequirement) {
+ if (!IsAseRequirementSatisfied(*req.sinkAseRequirement,
+ *conf.sinkAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+ break;
+ } else if (req.sourceAseRequirement) {
+ if (!IsAseRequirementSatisfied(*req.sourceAseRequirement,
+ *conf.sourceAseConfiguration)) {
+ continue;
+ }
+ num_of_satisfied_requirements +=
+ std::bitset<32>(req.audioContext.bitmask).count();
+ break;
+ }
+ }
+ }
+ ASSERT_EQ(num_of_satisfied_requirements, num_of_requirements);
+ }
+
+ LeAudioConfigurationRequirement GetUnicastDefaultRequirement(
+ int32_t context_bits, bool is_sink_requirement,
+ bool is_source_requriement,
+ CodecSpecificConfigurationLtv::SamplingFrequency freq =
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000) {
// Create a requirements
LeAudioConfigurationRequirement requirement;
- requirement.audioContext = GetAudioContext(AudioContext::MEDIA);
+ requirement.audioContext = GetAudioContext(context_bits);
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
auto direction_ase_requriement = AseDirectionRequirement();
direction_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
direction_ase_requriement.aseConfiguration.targetLatency =
LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
- // Mismatch sampling frequency
direction_ase_requriement.aseConfiguration.codecConfiguration = {
- CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025,
- CodecSpecificConfigurationLtv::FrameDuration::US7500,
+ freq, CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation
+
};
+ if (is_sink_requirement)
+ requirement.sinkAseRequirement = {direction_ase_requriement};
+
if (is_source_requriement)
requirement.sourceAseRequirement = {direction_ase_requriement};
- else
- requirement.sinkAseRequirement = {direction_ase_requriement};
+
return requirement;
}
+ LeAudioConfigurationRequirement GetUnicastGameRequirement(bool asymmetric) {
+ // Create a requirements
+ LeAudioConfigurationRequirement requirement;
+ requirement.audioContext = GetAudioContext(AudioContext::GAME);
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto sink_ase_requriement = AseDirectionRequirement();
+ sink_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+ sink_ase_requriement.aseConfiguration.targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+ sink_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+
+ auto source_ase_requriement = AseDirectionRequirement();
+ source_ase_requriement.aseConfiguration.codecId = CodecId::Core::LC3;
+ source_ase_requriement.aseConfiguration.targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY;
+
+ if (asymmetric) {
+ source_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ8000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+ } else {
+ source_ase_requriement.aseConfiguration.codecConfiguration = {
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation};
+ }
+
+ requirement.sinkAseRequirement = {sink_ase_requriement};
+ requirement.sourceAseRequirement = {source_ase_requriement};
+
+ return requirement;
+ }
+
+ LeAudioAseQosConfigurationRequirement GetQosRequirements(
+ bool is_sink_requirement, bool is_source_requriement, bool valid = true) {
+ LeAudioAseQosConfigurationRequirement qosRequirement;
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ AseQosDirectionRequirement directionalRequirement = {
+ .framing = IBluetoothAudioProvider::Framing::UNFRAMED,
+ .preferredRetransmissionNum = 2,
+ .maxTransportLatencyMs = 10,
+ .presentationDelayMinUs = 40000,
+ .presentationDelayMaxUs = 40000,
+ .aseConfiguration =
+ {
+ .targetLatency = LeAudioAseConfiguration::TargetLatency::
+ BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000,
+ allocation},
+ },
+ };
+
+ if (!valid) {
+ // clear some required values;
+ directionalRequirement.maxTransportLatencyMs = 0;
+ directionalRequirement.presentationDelayMaxUs = 0;
+ }
+
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ if (is_source_requriement && is_sink_requirement) {
+ qosRequirement.sourceAseQosRequirement = directionalRequirement;
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ } else if (is_source_requriement) {
+ qosRequirement.sourceAseQosRequirement = directionalRequirement;
+ qosRequirement.sinkAseQosRequirement = std::nullopt;
+ } else if (is_sink_requirement) {
+ qosRequirement.sourceAseQosRequirement = std::nullopt;
+ qosRequirement.sinkAseQosRequirement = directionalRequirement;
+ }
+
+ return qosRequirement;
+ }
+
std::vector<Lc3Configuration> GetUnicastLc3SupportedList(bool decoding,
bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
@@ -2460,6 +2874,11 @@
AudioContext::NOTIFICATIONS, AudioContext::RINGTONE_ALERTS,
AudioContext::ALERTS, AudioContext::EMERGENCY_ALARM,
};
+
+ AudioContext bidirectional_contexts = {
+ .bitmask = AudioContext::CONVERSATIONAL | AudioContext::GAME |
+ AudioContext::VOICE_ASSISTANTS | AudioContext::LIVE_AUDIO,
+ };
};
/**
@@ -2511,6 +2930,40 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+
+ // Check empty capability for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability_Multidirectiona) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
std::vector<LeAudioConfigurationRequirement> empty_requirement;
std::vector<LeAudioAseConfigurationSetting> configurations;
@@ -2536,50 +2989,388 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
- std::vector<std::optional<LeAudioDeviceCapabilities>> capabilities = {
- GetDefaultRemoteCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ auto not_supported_sampling_rate_by_remote =
+ CodecSpecificConfigurationLtv::SamplingFrequency::HZ11025;
// Check empty capability for source direction
std::vector<LeAudioAseConfigurationSetting> configurations;
std::vector<LeAudioConfigurationRequirement> source_requirements = {
- GetDefaultRequirement(true)};
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /*sink */,
+ true /* source */,
+ not_supported_sampling_rate_by_remote)};
auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
- std::nullopt, capabilities, source_requirements, &configurations);
+ std::nullopt, source_capabilities, source_requirements, &configurations);
ASSERT_TRUE(aidl_retval.isOk());
ASSERT_TRUE(configurations.empty());
// Check empty capability for sink direction
std::vector<LeAudioConfigurationRequirement> sink_requirements = {
- GetDefaultRequirement(false)};
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /*sink */,
+ false /* source */,
+ not_supported_sampling_rate_by_remote)};
aidl_retval = audio_provider_->getLeAudioAseConfiguration(
- capabilities, std::nullopt, source_requirements, &configurations);
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
ASSERT_TRUE(aidl_retval.isOk());
ASSERT_TRUE(configurations.empty());
}
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetAseConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Should not ask for Source on ENCODING session if Multidiretional not
+ // supported
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check capability for remote sink direction
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ // Check multiple capability for remote sink direction
+ std::vector<LeAudioConfigurationRequirement> multi_sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, multi_sink_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+
+ // Check multiple context types in a single requirement.
+ std::vector<LeAudioConfigurationRequirement> multi_context_sink_requirements =
+ {GetUnicastDefaultRequirement(
+ AudioContext::MEDIA | AudioContext::SOUND_EFFECTS, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, multi_context_sink_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(multi_sink_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Verify source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+ // Verify sink configuration is received
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, combined_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetAsymmetricAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ if (!IsAsymmetricConfigurationAllowed()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ std::vector<LeAudioConfigurationRequirement> asymmetric_requirements = {
+ GetUnicastGameRequirement(true /* Asymmetric */)};
+
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, asymmetric_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(asymmetric_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetQoSConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement requirement =
+ GetQosRequirements(true, true);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ bool is_supported = false;
+ for (auto bitmask : all_context_bitmasks) {
+ requirement.audioContext = GetAudioContext(bitmask);
+ bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+
+ if (is_bidirectional) {
+ requirement.sourceAseQosRequirement = requirement.sinkAseQosRequirement;
+ } else {
+ requirement.sourceAseQosRequirement = std::nullopt;
+ }
+
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval =
+ audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ }
+
+ is_supported = true;
+ if (result.sinkQosConfiguration.has_value()) {
+ if (is_bidirectional) {
+ ASSERT_TRUE(result.sourceQosConfiguration.has_value());
+ } else {
+ ASSERT_FALSE(result.sourceQosConfiguration.has_value());
+ }
+ QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+ }
+ }
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetQoSConfiguration_InvalidRequirements) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement invalid_requirement =
+ GetQosRequirements(true /* sink */, false /* source */,
+ false /* valid */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ for (auto bitmask : all_context_bitmasks) {
+ invalid_requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+ invalid_requirement, &result);
+ ASSERT_FALSE(aidl_retval.isOk());
+ }
+}
+
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl, GetQoSConfiguration) {
if (GetProviderFactoryInterfaceVersion() <
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+ requirement = GetQosRequirements(true /* sink */, false /* source */);
+
std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
QoSConfigurations;
+ bool is_supported = false;
for (auto bitmask : all_context_bitmasks) {
requirement.audioContext = GetAudioContext(bitmask);
IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
auto aidl_retval =
audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
- ASSERT_TRUE(aidl_retval.isOk());
- if (result.sinkQosConfiguration.has_value())
- QoSConfigurations.push_back(result.sinkQosConfiguration.value());
- if (result.sourceQosConfiguration.has_value())
- QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.sinkQosConfiguration.has_value()) {
+ QoSConfigurations.push_back(result.sinkQosConfiguration.value());
+ }
+ }
}
- // QoS Configurations should not be empty, as we searched for all contexts
- ASSERT_FALSE(QoSConfigurations.empty());
+
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
+ GetDataPathConfiguration_Multidirectional) {
+ IBluetoothAudioProvider::StreamConfig sink_requirement;
+ IBluetoothAudioProvider::StreamConfig source_requirement;
+ std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
+ DataPathConfigurations;
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ bool is_supported = false;
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto streamMap = LeAudioConfiguration::StreamMap();
+
+ // Use some mandatory configuration
+ streamMap.streamHandle = 0x0001;
+ streamMap.audioChannelAllocation = 0x03;
+ streamMap.aseConfiguration = {
+ .targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+ };
+
+ // Bidirectional
+ sink_requirement.streamMap = {streamMap};
+ source_requirement.streamMap = {streamMap};
+
+ for (auto bitmask : all_context_bitmasks) {
+ sink_requirement.audioContext = GetAudioContext(bitmask);
+ source_requirement.audioContext = sink_requirement.audioContext;
+
+ IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
+ ::ndk::ScopedAStatus aidl_retval;
+
+ bool is_bidirectional = bidirectional_contexts.bitmask & bitmask;
+ if (is_bidirectional) {
+ aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+ sink_requirement, source_requirement, &result);
+ } else {
+ aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
+ sink_requirement, std::nullopt, &result);
+ }
+
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.outputConfig.has_value()) {
+ if (is_bidirectional) {
+ ASSERT_TRUE(result.inputConfig.has_value());
+ } else {
+ ASSERT_TRUE(!result.inputConfig.has_value());
+ }
+ DataPathConfigurations.push_back(result.outputConfig.value());
+ }
+ }
+ }
+
+ if (is_supported) {
+ // Datapath Configurations should not be empty, as we searched for all
+ // contexts
+ ASSERT_FALSE(DataPathConfigurations.empty());
+ }
}
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
@@ -2589,26 +3380,45 @@
GTEST_SKIP();
}
IBluetoothAudioProvider::StreamConfig sink_requirement;
- IBluetoothAudioProvider::StreamConfig source_requirement;
std::vector<IBluetoothAudioProvider::LeAudioDataPathConfiguration>
DataPathConfigurations;
bool is_supported = false;
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ auto streamMap = LeAudioConfiguration::StreamMap();
+
+ // Use some mandatory configuration
+ streamMap.streamHandle = 0x0001;
+ streamMap.audioChannelAllocation = 0x03;
+ streamMap.aseConfiguration = {
+ .targetLatency =
+ LeAudioAseConfiguration::TargetLatency::BALANCED_LATENCY_RELIABILITY,
+ .codecId = CodecId::Core::LC3,
+ .codecConfiguration =
+ {CodecSpecificConfigurationLtv::SamplingFrequency::HZ16000,
+ CodecSpecificConfigurationLtv::FrameDuration::US10000, allocation},
+ };
+
+ sink_requirement.streamMap = {streamMap};
for (auto bitmask : all_context_bitmasks) {
sink_requirement.audioContext = GetAudioContext(bitmask);
- source_requirement.audioContext = GetAudioContext(bitmask);
IBluetoothAudioProvider::LeAudioDataPathConfigurationPair result;
auto aidl_retval = audio_provider_->getLeAudioAseDatapathConfiguration(
- sink_requirement, source_requirement, &result);
+ sink_requirement, std::nullopt, &result);
+
if (!aidl_retval.isOk()) {
- // If not OK, then it could be not supported, as it is an optional feature
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
} else {
is_supported = true;
- if (result.inputConfig.has_value())
- DataPathConfigurations.push_back(result.inputConfig.value());
- if (result.inputConfig.has_value())
- DataPathConfigurations.push_back(result.inputConfig.value());
+ if (result.outputConfig.has_value()) {
+ DataPathConfigurations.push_back(result.outputConfig.value());
+ }
}
}
@@ -2655,10 +3465,9 @@
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
- * Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioOutputHardwareAidl,
- DISABLED_StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
+ StartAndEndLeAudioOutputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadOutputSupported()) {
GTEST_SKIP();
}
@@ -2678,8 +3487,8 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start session with invalid configuration
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
@@ -2758,8 +3567,8 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start session with invalid configuration
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
@@ -2879,10 +3688,9 @@
* SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH can be started and
* stopped with Unicast hardware encoding config
*
- * Disabled since offload codec checking is not ready
*/
TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
- DISABLED_StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
+ StartAndEndLeAudioInputSessionWithInvalidAudioConfiguration) {
if (!IsOffloadInputSupported()) {
GTEST_SKIP();
}
@@ -2903,12 +3711,229 @@
audio_port_, AudioConfiguration(le_audio_config), latency_modes,
&mq_desc);
- // AIDL call should fail on invalid codec
- ASSERT_FALSE(aidl_retval.isOk());
+ // It is OK to start with invalid configuration as it might be unknown on
+ // start
+ ASSERT_TRUE(aidl_retval.isOk());
EXPECT_TRUE(audio_provider_->endSession().isOk());
}
}
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check success for source direction (Input == DecodingSession == remote
+ // source)
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check failure for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetEmptyAseConfigurationEmptyCapability_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ std::vector<LeAudioConfigurationRequirement> empty_requirement;
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, empty_capability, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+
+ // Check empty capability for sink direction
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ empty_capability, std::nullopt, empty_requirement, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_TRUE(configurations.empty());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetAseConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Check source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+
+ // Check error result when requesting sink on DECODING session
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetAseConfiguration_Multidirectional) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsMultidirectionalCapabilitiesEnabled()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> sink_capabilities = {
+ GetDefaultRemoteSinkCapability()};
+ std::vector<std::optional<LeAudioDeviceCapabilities>> source_capabilities = {
+ GetDefaultRemoteSourceCapability()};
+
+ // Check source configuration is received
+ std::vector<LeAudioAseConfigurationSetting> configurations;
+ std::vector<LeAudioConfigurationRequirement> source_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */)};
+ auto aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ std::nullopt, source_capabilities, source_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(source_requirements, configurations);
+
+ // Check empty capability for sink direction
+ std::vector<LeAudioConfigurationRequirement> sink_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, std::nullopt, sink_requirements, &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(sink_requirements, configurations);
+
+ std::vector<LeAudioConfigurationRequirement> combined_requirements = {
+ GetUnicastDefaultRequirement(AudioContext::LIVE_AUDIO, false /* sink */,
+ true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::CONVERSATIONAL,
+ true /* sink */, true /* source */),
+ GetUnicastDefaultRequirement(AudioContext::MEDIA, true /* sink */,
+ false /* source */)};
+
+ aidl_retval = audio_provider_->getLeAudioAseConfiguration(
+ sink_capabilities, source_capabilities, combined_requirements,
+ &configurations);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_FALSE(configurations.empty());
+ VerifyIfRequirementsSatisfied(combined_requirements, configurations);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl,
+ GetQoSConfiguration_InvalidRequirements) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ LeAudioAseQosConfigurationRequirement invalid_requirement =
+ GetQosRequirements(false /* sink */, true /* source */,
+ false /* valid */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ for (auto bitmask : all_context_bitmasks) {
+ invalid_requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval = audio_provider_->getLeAudioAseQosConfiguration(
+ invalid_requirement, &result);
+ ASSERT_FALSE(aidl_retval.isOk());
+ }
+}
+
+TEST_P(BluetoothAudioProviderLeAudioInputHardwareAidl, GetQoSConfiguration) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+ auto allocation = CodecSpecificConfigurationLtv::AudioChannelAllocation();
+ allocation.bitmask =
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_LEFT |
+ CodecSpecificConfigurationLtv::AudioChannelAllocation::FRONT_RIGHT;
+
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationRequirement requirement;
+ requirement = GetQosRequirements(false /* sink */, true /* source */);
+
+ std::vector<IBluetoothAudioProvider::LeAudioAseQosConfiguration>
+ QoSConfigurations;
+ bool is_supported = false;
+ for (auto bitmask : all_context_bitmasks) {
+ requirement.audioContext = GetAudioContext(bitmask);
+ IBluetoothAudioProvider::LeAudioAseQosConfigurationPair result;
+ auto aidl_retval =
+ audio_provider_->getLeAudioAseQosConfiguration(requirement, &result);
+ if (!aidl_retval.isOk()) {
+ // If not OK, then it could be not supported, as it is an optional
+ // feature
+ ASSERT_EQ(aidl_retval.getExceptionCode(), EX_UNSUPPORTED_OPERATION);
+ } else {
+ is_supported = true;
+ if (result.sourceQosConfiguration.has_value()) {
+ QoSConfigurations.push_back(result.sourceQosConfiguration.value());
+ }
+ }
+ }
+
+ if (is_supported) {
+ // QoS Configurations should not be empty, as we searched for all contexts
+ ASSERT_FALSE(QoSConfigurations.empty());
+ }
+}
/**
* openProvider LE_AUDIO_BROADCAST_SOFTWARE_ENCODING_DATAPATH
*/
@@ -3058,6 +4083,147 @@
return le_audio_codec_configs;
}
+ AudioContext GetAudioContext(int32_t bitmask) {
+ AudioContext media_audio_context;
+ media_audio_context.bitmask = bitmask;
+ return media_audio_context;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv> GetConfigurationLtv(
+ const std::vector<CodecSpecificConfigurationLtv>& configurationLtvs,
+ CodecSpecificConfigurationLtv::Tag tag) {
+ for (const auto ltv : configurationLtvs) {
+ if (ltv.getTag() == tag) {
+ return ltv;
+ }
+ }
+ return std::nullopt;
+ }
+
+ std::optional<CodecSpecificConfigurationLtv::SamplingFrequency>
+ GetBisSampleFreq(const LeAudioBisConfiguration& bis_conf) {
+ auto sample_freq_ltv = GetConfigurationLtv(
+ bis_conf.codecConfiguration,
+ CodecSpecificConfigurationLtv::Tag::samplingFrequency);
+ if (!sample_freq_ltv) {
+ return std::nullopt;
+ }
+ return (*sample_freq_ltv)
+ .get<CodecSpecificConfigurationLtv::samplingFrequency>();
+ }
+
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+ GetSubgroupSampleFreqs(
+ const LeAudioBroadcastSubgroupConfiguration& subgroup_conf) {
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> result = {};
+
+ for (const auto& bis_conf : subgroup_conf.bisConfigurations) {
+ auto sample_freq = GetBisSampleFreq(bis_conf.bisConfiguration);
+ if (sample_freq) {
+ result.push_back(*sample_freq);
+ }
+ }
+ return result;
+ }
+
+ void VerifyBroadcastConfiguration(
+ const LeAudioBroadcastConfigurationRequirement& requirements,
+ const LeAudioBroadcastConfigurationSetting& configuration,
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency>
+ expectedSampleFreqs = {}) {
+ std::vector<CodecSpecificConfigurationLtv::SamplingFrequency> sampleFreqs =
+ {};
+
+ int number_of_requested_bises = 0;
+ for (const auto& subgroup_req :
+ requirements.subgroupConfigurationRequirements) {
+ number_of_requested_bises += subgroup_req.bisNumPerSubgroup;
+ }
+
+ if (!expectedSampleFreqs.empty()) {
+ for (const auto& subgroup_conf : configuration.subgroupsConfigurations) {
+ auto result = GetSubgroupSampleFreqs(subgroup_conf);
+ sampleFreqs.insert(sampleFreqs.end(), result.begin(), result.end());
+ }
+ }
+
+ ASSERT_EQ(number_of_requested_bises, configuration.numBis);
+ ASSERT_EQ(requirements.subgroupConfigurationRequirements.size(),
+ configuration.subgroupsConfigurations.size());
+
+ if (expectedSampleFreqs.empty()) {
+ return;
+ }
+
+ std::sort(sampleFreqs.begin(), sampleFreqs.end());
+ std::sort(expectedSampleFreqs.begin(), expectedSampleFreqs.end());
+
+ ASSERT_EQ(sampleFreqs, expectedSampleFreqs);
+ }
+
+ LeAudioDeviceCapabilities GetDefaultBroadcastSinkCapability() {
+ // Create a capability
+ LeAudioDeviceCapabilities capability;
+
+ capability.codecId = CodecId::Core::LC3;
+
+ auto pref_context_metadata = MetadataLtv::PreferredAudioContexts();
+ pref_context_metadata.values =
+ GetAudioContext(AudioContext::MEDIA | AudioContext::CONVERSATIONAL |
+ AudioContext::GAME);
+ capability.metadata = {pref_context_metadata};
+
+ auto sampling_rate =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies();
+ sampling_rate.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ48000 |
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ24000 |
+ CodecSpecificCapabilitiesLtv::SupportedSamplingFrequencies::HZ16000;
+ auto frame_duration =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations();
+ frame_duration.bitmask =
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US7500 |
+ CodecSpecificCapabilitiesLtv::SupportedFrameDurations::US10000;
+ auto octets = CodecSpecificCapabilitiesLtv::SupportedOctetsPerCodecFrame();
+ octets.min = 0;
+ octets.max = 120;
+ auto frames = CodecSpecificCapabilitiesLtv::SupportedMaxCodecFramesPerSDU();
+ frames.value = 2;
+ capability.codecSpecificCapabilities = {sampling_rate, frame_duration,
+ octets, frames};
+ return capability;
+ }
+
+ LeAudioBroadcastConfigurationRequirement GetBroadcastRequirement(
+ bool standard_quality, bool high_quality) {
+ LeAudioBroadcastConfigurationRequirement requirement;
+
+ AudioContext media_audio_context;
+ media_audio_context.bitmask = AudioContext::MEDIA;
+
+ LeAudioBroadcastSubgroupConfigurationRequirement
+ standard_quality_requirement = {
+ .audioContext = media_audio_context,
+ .quality = IBluetoothAudioProvider::BroadcastQuality::STANDARD,
+ .bisNumPerSubgroup = 2};
+
+ LeAudioBroadcastSubgroupConfigurationRequirement high_quality_requirement =
+ {.audioContext = media_audio_context,
+ .quality = IBluetoothAudioProvider::BroadcastQuality::HIGH,
+ .bisNumPerSubgroup = 2};
+
+ if (standard_quality) {
+ requirement.subgroupConfigurationRequirements.push_back(
+ standard_quality_requirement);
+ }
+
+ if (high_quality) {
+ requirement.subgroupConfigurationRequirements.push_back(
+ high_quality_requirement);
+ }
+ return requirement;
+ }
+
std::vector<Lc3Configuration> GetBroadcastLc3SupportedList(bool supported) {
std::vector<Lc3Configuration> le_audio_codec_configs;
if (!supported) {
@@ -3164,18 +4330,80 @@
BluetoothAudioHalVersion::VERSION_AIDL_V4) {
GTEST_SKIP();
}
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
empty_requirement;
- IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting* configuration =
- new IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting();
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
// Check empty capability for source direction
auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
- empty_capability, empty_requirement, configuration);
+ empty_capability, empty_requirement, &configuration);
+
+ ASSERT_FALSE(aidl_retval.isOk());
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+ GetBroadcastConfigurationEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> empty_capability;
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+ one_subgroup_requirement =
+ GetBroadcastRequirement(true /* standard*/, false /* high */);
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+ empty_capability, one_subgroup_requirement, &configuration);
ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_NE(configuration.numBis, 0);
+ ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+ VerifyBroadcastConfiguration(one_subgroup_requirement, configuration);
+}
+
+TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
+ GetBroadcastConfigurationNonEmptyCapability) {
+ if (GetProviderFactoryInterfaceVersion() <
+ BluetoothAudioHalVersion::VERSION_AIDL_V4) {
+ GTEST_SKIP();
+ }
+
+ if (!IsBroadcastOffloadSupported()) {
+ GTEST_SKIP();
+ }
+
+ std::vector<std::optional<LeAudioDeviceCapabilities>> capability = {
+ GetDefaultBroadcastSinkCapability()};
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationRequirement
+ requirement =
+ GetBroadcastRequirement(true /* standard*/, false /* high */);
+
+ IBluetoothAudioProvider::LeAudioBroadcastConfigurationSetting configuration;
+
+ // Check empty capability for source direction
+ auto aidl_retval = audio_provider_->getLeAudioBroadcastConfiguration(
+ capability, requirement, &configuration);
+
+ ASSERT_TRUE(aidl_retval.isOk());
+ ASSERT_NE(configuration.numBis, 0);
+ ASSERT_FALSE(configuration.subgroupsConfigurations.empty());
+ VerifyBroadcastConfiguration(requirement, configuration);
}
/**
@@ -3186,7 +4414,7 @@
TEST_P(BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
StartAndEndLeAudioBroadcastSessionWithPossibleBroadcastConfig) {
if (!IsBroadcastOffloadSupported()) {
- return;
+ GTEST_SKIP();
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(true /* supported */);
@@ -3225,7 +4453,7 @@
BluetoothAudioProviderLeAudioBroadcastHardwareAidl,
DISABLED_StartAndEndLeAudioBroadcastSessionWithInvalidAudioConfiguration) {
if (!IsBroadcastOffloadSupported()) {
- return;
+ GTEST_SKIP();
}
auto lc3_codec_configs = GetBroadcastLc3SupportedList(false /* supported */);
diff --git a/bluetooth/audio/flags/btaudiohal.aconfig b/bluetooth/audio/flags/btaudiohal.aconfig
index 4c1500a..13e2116 100644
--- a/bluetooth/audio/flags/btaudiohal.aconfig
+++ b/bluetooth/audio/flags/btaudiohal.aconfig
@@ -7,3 +7,10 @@
description: "Flag for DSA Over LEA"
bug: "270987427"
}
+
+flag {
+ name: "leaudio_report_broadcast_ac_to_hal"
+ namespace: "pixel_bluetooth"
+ description: "Flag for reporting lea broadcast audio config to HAL"
+ bug: "321168976"
+}
\ No newline at end of file
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 779a90f..1661362 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -90,6 +90,9 @@
cc_test {
name: "BluetoothLeAudioCodecsProviderTest",
+ defaults: [
+ "latest_android_hardware_bluetooth_audio_ndk_shared",
+ ],
srcs: [
"aidl_session/BluetoothLeAudioCodecsProvider.cpp",
"aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
@@ -100,7 +103,6 @@
shared_libs: [
"libbase",
"libbinder_ndk",
- "android.hardware.bluetooth.audio-V4-ndk",
"libxml2",
],
test_suites: [
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
index 67ba93c..d0f2a26 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioSession.cpp
@@ -121,18 +121,41 @@
void BluetoothAudioSession::ReportAudioConfigChanged(
const AudioConfiguration& audio_config) {
- if (session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
- session_type_ !=
- SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
- return;
- }
-
std::lock_guard<std::recursive_mutex> guard(mutex_);
- if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
- LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
- << toString(session_type_);
- return;
+ if (com::android::btaudio::hal::flags::leaudio_report_broadcast_ac_to_hal()) {
+ if (session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH ||
+ session_type_ ==
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else if (session_type_ ==
+ SessionType::LE_AUDIO_BROADCAST_HARDWARE_OFFLOAD_ENCODING_DATAPATH) {
+ if (audio_config.getTag() != AudioConfiguration::leAudioBroadcastConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ LOG(ERROR) << __func__ << " invalid SessionType ="
+ << toString(session_type_);
+ return;
+ }
+ } else {
+ if (session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_ENCODING_DATAPATH &&
+ session_type_ !=
+ SessionType::LE_AUDIO_HARDWARE_OFFLOAD_DECODING_DATAPATH) {
+ return;
+ }
+ if (audio_config.getTag() != AudioConfiguration::leAudioConfig) {
+ LOG(ERROR) << __func__ << " invalid audio config type for SessionType ="
+ << toString(session_type_);
+ return;
+ }
}
audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
index 5429a8f..780154a 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.cpp
@@ -267,7 +267,7 @@
ase_configuration_settings_.clear();
configurations_.clear();
auto loaded = LoadContent(kLeAudioSetConfigs, kLeAudioSetScenarios,
- CodecLocation::HOST);
+ CodecLocation::ADSP);
if (!loaded)
LOG(ERROR) << ": Unable to load le audio set configuration files.";
} else
@@ -371,7 +371,6 @@
CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU();
frame_sdu_structure.value = codec_frames_blocks_per_sdu;
ase.codecConfiguration.push_back(frame_sdu_structure);
- // TODO: Channel count
}
void AudioSetConfigurationProviderJson::populateAseConfiguration(
@@ -415,8 +414,53 @@
}
void AudioSetConfigurationProviderJson::populateAseQosConfiguration(
- LeAudioAseQosConfiguration& qos,
- const le_audio::QosConfiguration* qos_cfg) {
+ LeAudioAseQosConfiguration& qos, const le_audio::QosConfiguration* qos_cfg,
+ LeAudioAseConfiguration& ase) {
+ std::optional<CodecSpecificConfigurationLtv::CodecFrameBlocksPerSDU>
+ frameBlock = std::nullopt;
+ std::optional<CodecSpecificConfigurationLtv::FrameDuration> frameDuration =
+ std::nullopt;
+ std::optional<CodecSpecificConfigurationLtv::AudioChannelAllocation>
+ allocation = std::nullopt;
+ std::optional<CodecSpecificConfigurationLtv::OctetsPerCodecFrame> octet =
+ std::nullopt;
+
+ for (auto& cfg_ltv : ase.codecConfiguration) {
+ auto tag = cfg_ltv.getTag();
+ if (tag == CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU) {
+ frameBlock =
+ cfg_ltv.get<CodecSpecificConfigurationLtv::codecFrameBlocksPerSDU>();
+ } else if (tag == CodecSpecificConfigurationLtv::frameDuration) {
+ frameDuration =
+ cfg_ltv.get<CodecSpecificConfigurationLtv::frameDuration>();
+ } else if (tag == CodecSpecificConfigurationLtv::audioChannelAllocation) {
+ allocation =
+ cfg_ltv.get<CodecSpecificConfigurationLtv::audioChannelAllocation>();
+ } else if (tag == CodecSpecificConfigurationLtv::octetsPerCodecFrame) {
+ octet = cfg_ltv.get<CodecSpecificConfigurationLtv::octetsPerCodecFrame>();
+ }
+ }
+
+ int frameBlockValue = 1;
+ if (frameBlock.has_value()) frameBlockValue = frameBlock.value().value;
+
+ // Populate maxSdu
+ if (allocation.has_value() && octet.has_value()) {
+ auto channel_count = std::bitset<32>(allocation.value().bitmask).count();
+ qos.maxSdu = channel_count * octet.value().value * frameBlockValue;
+ }
+ // Populate sduIntervalUs
+ if (frameDuration.has_value()) {
+ switch (frameDuration.value()) {
+ case CodecSpecificConfigurationLtv::FrameDuration::US7500:
+ qos.sduIntervalUs = 7500;
+ break;
+ case CodecSpecificConfigurationLtv::FrameDuration::US10000:
+ qos.sduIntervalUs = 10000;
+ break;
+ }
+ qos.sduIntervalUs *= frameBlockValue;
+ }
qos.maxTransportLatencyMs = qos_cfg->max_transport_latency();
qos.retransmissionNum = qos_cfg->retransmission_number();
}
@@ -436,7 +480,7 @@
populateAseConfiguration(ase, flat_subconfig, qos_cfg);
// Translate into LeAudioAseQosConfiguration
- populateAseQosConfiguration(qos, qos_cfg);
+ populateAseQosConfiguration(qos, qos_cfg, ase);
// Translate location to data path id
switch (location) {
@@ -453,6 +497,8 @@
path.dataPathId = kIsoDataPathPlatformDefault;
break;
}
+ // Move codecId to iso data path
+ path.isoDataPathConfiguration.codecId = ase.codecId.value();
direction_conf.aseConfiguration = ase;
direction_conf.qosConfiguration = qos;
@@ -678,7 +724,8 @@
media_context.bitmask =
(AudioContext::ALERTS | AudioContext::INSTRUCTIONAL |
AudioContext::NOTIFICATIONS | AudioContext::EMERGENCY_ALARM |
- AudioContext::UNSPECIFIED | AudioContext::MEDIA);
+ AudioContext::UNSPECIFIED | AudioContext::MEDIA |
+ AudioContext::SOUND_EFFECTS);
AudioContext conversational_context = AudioContext();
conversational_context.bitmask =
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
index ce91fca..6639009 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioAseConfigurationSettingProvider.h
@@ -79,7 +79,7 @@
static void populateAseQosConfiguration(
LeAudioAseQosConfiguration& qos,
- const le_audio::QosConfiguration* qos_cfg);
+ const le_audio::QosConfiguration* qos_cfg, LeAudioAseConfiguration& ase);
static AseDirectionConfiguration SetConfigurationFromFlatSubconfig(
const le_audio::AudioSetSubConfiguration* flat_subconfig,
diff --git a/bluetooth/finder/aidl/default/BluetoothFinder.cpp b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
index 236a1f8..a43846b 100644
--- a/bluetooth/finder/aidl/default/BluetoothFinder.cpp
+++ b/bluetooth/finder/aidl/default/BluetoothFinder.cpp
@@ -19,7 +19,7 @@
namespace aidl::android::hardware::bluetooth::finder::impl {
::ndk::ScopedAStatus BluetoothFinder::sendEids(const ::std::vector<Eid>& keys) {
- keys_.insert(keys_.end(), keys.begin(), keys.end());
+ keys_.assign(keys.begin(), keys.end());
return ::ndk::ScopedAStatus::ok();
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index f133372..236bcaf 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -580,25 +580,25 @@
/**
* android.flash.singleStrengthMaxLevel [static, int32, public]
*
- * <p>Maximum flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*/
ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
/**
* android.flash.singleStrengthDefaultLevel [static, int32, public]
*
- * <p>Default flash brightness level for manual flash control in SINGLE mode.</p>
+ * <p>Default flash brightness level for manual flash control in <code>SINGLE</code> mode.</p>
*/
ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
/**
* android.flash.torchStrengthMaxLevel [static, int32, public]
*
- * <p>Maximum flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Maximum flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*/
ANDROID_FLASH_TORCH_STRENGTH_MAX_LEVEL,
/**
* android.flash.torchStrengthDefaultLevel [static, int32, public]
*
- * <p>Default flash brightness level for manual flash control in TORCH mode</p>
+ * <p>Default flash brightness level for manual flash control in <code>TORCH</code> mode</p>
*/
ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
/**
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 431059b..1f5742d 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -13,7 +13,6 @@
vendor_available: true,
product_available: true,
double_loadable: true,
- vndk_use_version: "2",
srcs: [
"android/hardware/common/*.aidl",
],
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 951ca85..ad42015 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -92,3 +92,25 @@
],
}
+
+// Phony target that installs all system compatibility matrix files
+SYSTEM_MATRIX_DEPS = [
+ "framework_compatibility_matrix.5.xml",
+ "framework_compatibility_matrix.6.xml",
+ "framework_compatibility_matrix.7.xml",
+ "framework_compatibility_matrix.8.xml",
+ "framework_compatibility_matrix.202404.xml",
+ "framework_compatibility_matrix.device.xml",
+]
+
+phony {
+ name: "system_compatibility_matrix.xml",
+ required: SYSTEM_MATRIX_DEPS,
+ product_variables: {
+ release_aidl_use_unfrozen: {
+ required: [
+ "framework_compatibility_matrix.202504.xml",
+ ],
+ },
+ },
+}
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
index ab57b8c..338c075 100644
--- a/compatibility_matrices/Android.mk
+++ b/compatibility_matrices/Android.mk
@@ -119,15 +119,6 @@
my_framework_matrix_deps += \
$(my_system_matrix_deps)
-# Phony target that installs all system compatibility matrix files
-include $(CLEAR_VARS)
-LOCAL_MODULE := system_compatibility_matrix.xml
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-LOCAL_REQUIRED_MODULES := $(my_system_matrix_deps)
-include $(BUILD_PHONY_PACKAGE)
-
# Phony target that installs all framework compatibility matrix files (system + product)
include $(CLEAR_VARS)
LOCAL_MODULE := framework_compatibility_matrix.xml
diff --git a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
index 92328a8..dcce7ef 100644
--- a/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
+++ b/confirmationui/aidl/android/hardware/confirmationui/IConfirmationResultCallback.aidl
@@ -38,15 +38,15 @@
* prevented the TUI from being shut down gracefully.
*
* @param formattedMessage holds the prompt text and extra data.
- * The message is CBOR (RFC 7049) encoded and has the following format:
- * CBOR_MAP{ "prompt", <promptText>, "extra", <extraData> }
- * The message is a CBOR encoded map (type 5) with the keys
- * "prompt" and "extra". The keys are encoded as CBOR text string
- * (type 3). The value <promptText> is encoded as CBOR text string
- * (type 3), and the value <extraData> is encoded as CBOR byte string
- * (type 2). The map must have exactly one key value pair for each of
- * the keys "prompt" and "extra". Other keys are not allowed.
- * The value of "prompt" is given by the proptText argument to
+ * The message is CBOR (RFC 7049) encoded and has the exact format
+ * given by the following CDDL:
+ *
+ * formattedMessage = {
+ * "prompt" : tstr,
+ * "extra" : bstr,
+ * }
+ *
+ * The value of "prompt" is given by the promptText argument to
* IConfirmationUI::promptUserConfirmation and must not be modified
* by the implementation.
* The value of "extra" is given by the extraData argument to
@@ -59,8 +59,7 @@
* the "", concatenated with the formatted message as returned in the
* formattedMessage argument. The HMAC is keyed with a 256-bit secret
* which is shared with Keymaster. In test mode the test key MUST be
- * used (see TestModeCommands.aidl and
- * IConfirmationUI::TEST_KEY_BYTE).
+ * used (see TestModeCommands.aidl and IConfirmationUI::TEST_KEY_BYTE)
*/
void result(in int error, in byte[] formattedMessage, in byte[] confirmationToken);
}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index c31f991..94d4d00 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -162,12 +162,13 @@
return ScopedAStatus::ok();
}
-void Gnss::reportLocation(const GnssLocation& location) const {
+void Gnss::reportLocation(const GnssLocation& location) {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback == nullptr) {
ALOGE("%s: GnssCallback is null.", __func__);
return;
}
+ mLastLocation = std::make_shared<GnssLocation>(location);
auto status = sGnssCallback->gnssLocationCb(location);
if (!status.isOk()) {
ALOGE("%s: Unable to invoke gnssLocationCb", __func__);
@@ -359,7 +360,6 @@
ndk::ScopedAStatus Gnss::getExtensionGnssDebug(std::shared_ptr<IGnssDebug>* iGnssDebug) {
ALOGD("Gnss::getExtensionGnssDebug");
-
*iGnssDebug = SharedRefBase::make<GnssDebug>();
return ndk::ScopedAStatus::ok();
}
@@ -398,4 +398,8 @@
mGnssMeasurementIntervalMs = intervalMs;
}
+std::shared_ptr<GnssLocation> Gnss::getLastLocation() const {
+ return mLastLocation;
+}
+
} // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 245d607..73085ef 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -87,18 +87,19 @@
void reportSvStatus() const;
void setGnssMeasurementEnabled(const bool enabled);
void setGnssMeasurementInterval(const long intervalMs);
+ std::shared_ptr<GnssLocation> getLastLocation() const;
std::shared_ptr<GnssConfiguration> mGnssConfiguration;
std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
private:
- void reportLocation(const GnssLocation&) const;
+ void reportLocation(const GnssLocation&);
void reportSvStatus(const std::vector<IGnssCallback::GnssSvInfo>& svInfoList) const;
+ void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
+ void reportNmea() const;
std::vector<IGnssCallback::GnssSvInfo> filterBlocklistedSatellites(
std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
- void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
std::unique_ptr<GnssLocation> getLocationFromHW();
- void reportNmea() const;
static std::shared_ptr<IGnssCallback> sGnssCallback;
@@ -109,6 +110,7 @@
std::atomic<bool> mIsNmeaActive;
std::atomic<bool> mFirstFixReceived;
std::atomic<bool> mGnssMeasurementEnabled;
+ std::shared_ptr<GnssLocation> mLastLocation;
std::thread mThread;
::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
diff --git a/gnss/aidl/default/GnssDebug.cpp b/gnss/aidl/default/GnssDebug.cpp
index f40c0bc..5ae6edd 100644
--- a/gnss/aidl/default/GnssDebug.cpp
+++ b/gnss/aidl/default/GnssDebug.cpp
@@ -18,10 +18,15 @@
#include "GnssDebug.h"
#include <log/log.h>
+#include <utils/SystemClock.h>
+#include "Constants.h"
+#include "Gnss.h"
#include "MockLocation.h"
namespace aidl::android::hardware::gnss {
+using ::android::hardware::gnss::common::kMockTimestamp;
+
ndk::ScopedAStatus GnssDebug::getDebugData(DebugData* debugData) {
ALOGD("GnssDebug::getDebugData");
@@ -36,10 +41,94 @@
.speedAccuracyMetersPerSecond = 1,
.bearingAccuracyDegrees = 90,
.ageSeconds = 0.99};
- TimeDebug timeDebug = {.timeEstimateMs = 1519930775453L,
+ TimeDebug timeDebug = {.timeEstimateMs = static_cast<int64_t>(
+ kMockTimestamp + ::android::elapsedRealtimeNano() / 1e6),
.timeUncertaintyNs = 1000,
- .frequencyUncertaintyNsPerSec = 5.0e4};
- std::vector<SatelliteData> satelliteDataArrayDebug = {};
+ .frequencyUncertaintyNsPerSec = 800};
+ SatelliteData satelliteData1 = {
+ .svid = 3,
+ .constellation = GnssConstellationType::GPS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData2 = {
+ .svid = 5,
+ .constellation = GnssConstellationType::GPS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData3 = {
+ .svid = 17,
+ .constellation = GnssConstellationType::GPS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData4 = {
+ .svid = 26,
+ .constellation = GnssConstellationType::GPS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData5 = {
+ .svid = 5,
+ .constellation = GnssConstellationType::GLONASS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData6 = {
+ .svid = 17,
+ .constellation = GnssConstellationType::GLONASS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData7 = {
+ .svid = 18,
+ .constellation = GnssConstellationType::GLONASS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData8 = {
+ .svid = 10,
+ .constellation = GnssConstellationType::GLONASS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ SatelliteData satelliteData9 = {
+ .svid = 3,
+ .constellation = GnssConstellationType::IRNSS,
+ .ephemerisType = SatelliteEphemerisType::EPHEMERIS,
+ .ephemerisSource = SatellitePvt::SatelliteEphemerisSource::SERVER_LONG_TERM,
+ .ephemerisHealth = SatelliteEphemerisHealth::GOOD,
+ .ephemerisAgeSeconds = 12,
+ .serverPredictionIsAvailable = true,
+ .serverPredictionAgeSeconds = 30};
+ std::vector<SatelliteData> satelliteDataArrayDebug = {
+ satelliteData1, satelliteData2, satelliteData3, satelliteData4, satelliteData5,
+ satelliteData6, satelliteData7, satelliteData8, satelliteData9};
debugData->position = positionDebug;
debugData->time = timeDebug;
debugData->satelliteDataArray = satelliteDataArrayDebug;
diff --git a/gnss/aidl/default/GnssDebug.h b/gnss/aidl/default/GnssDebug.h
index 001d47c..b6844b3 100644
--- a/gnss/aidl/default/GnssDebug.h
+++ b/gnss/aidl/default/GnssDebug.h
@@ -20,6 +20,8 @@
namespace aidl::android::hardware::gnss {
+class Gnss;
+
struct GnssDebug : public BnGnssDebug {
public:
ndk::ScopedAStatus getDebugData(DebugData* debugData) override;
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 4309187..f7408d8 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -1149,40 +1149,139 @@
sp<IGnssDebug> iGnssDebug;
auto status = aidl_gnss_hal_->getExtensionGnssDebug(&iGnssDebug);
ASSERT_TRUE(status.isOk());
-
- if (!IsAutomotiveDevice()) {
- ASSERT_TRUE(iGnssDebug != nullptr);
-
- IGnssDebug::DebugData data;
- auto status = iGnssDebug->getDebugData(&data);
- ASSERT_TRUE(status.isOk());
-
- if (data.position.valid) {
- ASSERT_TRUE(data.position.latitudeDegrees >= -90 &&
- data.position.latitudeDegrees <= 90);
- ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
- data.position.longitudeDegrees <= 180);
- ASSERT_TRUE(data.position.altitudeMeters >= -1000 && // Dead Sea: -414m
- data.position.altitudeMeters <= 20000); // Mount Everest: 8850m
- ASSERT_TRUE(data.position.speedMetersPerSec >= 0 &&
- data.position.speedMetersPerSec <= 600);
- ASSERT_TRUE(data.position.bearingDegrees >= -360 &&
- data.position.bearingDegrees <= 360);
- ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
- data.position.horizontalAccuracyMeters <= 20000000);
- ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
- data.position.verticalAccuracyMeters <= 20000);
- ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
- data.position.speedAccuracyMetersPerSecond <= 500);
- ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
- data.position.bearingAccuracyDegrees <= 180);
- ASSERT_TRUE(data.position.ageSeconds >= 0);
- }
- ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000); // Jan 01 2017 00:00:00 GMT.
- ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
- ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
- data.time.frequencyUncertaintyNsPerSec <= 2.0e5); // 200 ppm
+ if (IsAutomotiveDevice()) {
+ return;
}
+ ASSERT_TRUE(iGnssDebug != nullptr);
+
+ IGnssDebug::DebugData data;
+ status = iGnssDebug->getDebugData(&data);
+ ASSERT_TRUE(status.isOk());
+ Utils::checkPositionDebug(data);
+
+ // Additional GnssDebug tests for AIDL version >= 4 (launched in Android 15(V)+)
+ if (aidl_gnss_hal_->getInterfaceVersion() <= 3) {
+ return;
+ }
+
+ // Start location and check the consistency between SvStatus and DebugData
+ aidl_gnss_cb_->location_cbq_.reset();
+ aidl_gnss_cb_->sv_info_list_cbq_.reset();
+ StartAndCheckLocations(/* count= */ 2);
+ int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+ ALOGD("Observed %d GnssSvStatus, while awaiting 2 locations (%d received)",
+ aidl_gnss_cb_->sv_info_list_cbq_.size(), location_called_count);
+
+ // Wait for up to kNumSvInfoLists events for kTimeoutSeconds for each event.
+ int kTimeoutSeconds = 2;
+ int kNumSvInfoLists = 4;
+ std::list<std::vector<IGnssCallback::GnssSvInfo>> sv_info_lists;
+ std::vector<IGnssCallback::GnssSvInfo> last_sv_info_list;
+
+ do {
+ EXPECT_GT(aidl_gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists,
+ kTimeoutSeconds),
+ 0);
+ if (!sv_info_lists.empty()) {
+ last_sv_info_list = sv_info_lists.back();
+ ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
+ }
+ } while (!sv_info_lists.empty() && last_sv_info_list.size() == 0);
+
+ StopAndClearLocations();
+
+ status = iGnssDebug->getDebugData(&data);
+ Utils::checkPositionDebug(data);
+
+ // Validate SatelliteEphemerisType, SatelliteEphemerisSource, SatelliteEphemerisHealth
+ for (auto sv_info : last_sv_info_list) {
+ if ((sv_info.svFlag & static_cast<int>(IGnssCallback::GnssSvFlags::USED_IN_FIX)) == 0) {
+ continue;
+ }
+ ALOGD("Found usedInFix const: %d, svid: %d", static_cast<int>(sv_info.constellation),
+ sv_info.svid);
+ bool foundDebugData = false;
+ for (auto satelliteData : data.satelliteDataArray) {
+ if (satelliteData.constellation == sv_info.constellation &&
+ satelliteData.svid == sv_info.svid) {
+ foundDebugData = true;
+ ALOGD("Found GnssDebug data for this sv.");
+ EXPECT_TRUE(satelliteData.serverPredictionIsAvailable ||
+ satelliteData.ephemerisType ==
+ IGnssDebug::SatelliteEphemerisType::EPHEMERIS);
+ // for satellites with ephType=0, they need ephHealth=0 if used-in-fix
+ if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
+ EXPECT_TRUE(satelliteData.ephemerisHealth ==
+ IGnssDebug::SatelliteEphemerisHealth::GOOD);
+ }
+ break;
+ }
+ }
+ // Every Satellite where GnssStatus says it is used-in-fix has a valid ephemeris - i.e. it's
+ // it shows either a serverPredAvail: 1, or a ephType=0
+ EXPECT_TRUE(foundDebugData);
+ }
+
+ bool hasServerPredictionAvailable = false;
+ bool hasNoneZeroServerPredictionAgeSeconds = false;
+ bool hasNoneDemodEphSource = false;
+ for (auto satelliteData : data.satelliteDataArray) {
+ // for satellites with serverPredAvail: 1, the serverPredAgeSec: is not 0 for all
+ // satellites (at least not on 2 fixes in a row - it could get lucky once)
+ if (satelliteData.serverPredictionIsAvailable) {
+ hasServerPredictionAvailable = true;
+ if (satelliteData.serverPredictionAgeSeconds != 0) {
+ hasNoneZeroServerPredictionAgeSeconds = true;
+ }
+ }
+ // for satellites with ephType=0, they need ephSource 0-3
+ if (satelliteData.ephemerisType == IGnssDebug::SatelliteEphemerisType::EPHEMERIS) {
+ EXPECT_TRUE(satelliteData.ephemerisSource >=
+ SatellitePvt::SatelliteEphemerisSource::DEMODULATED &&
+ satelliteData.ephemerisSource <=
+ SatellitePvt::SatelliteEphemerisSource::OTHER);
+ if (satelliteData.ephemerisSource !=
+ SatellitePvt::SatelliteEphemerisSource::DEMODULATED) {
+ hasNoneDemodEphSource = true;
+ }
+ }
+ }
+ if (hasNoneDemodEphSource && hasServerPredictionAvailable) {
+ EXPECT_TRUE(hasNoneZeroServerPredictionAgeSeconds);
+ }
+
+ /**
+ - Gnss Location Data:: should show some valid information, ideally reasonably close (+/-1km) to
+ the Location output - at least after the 2nd valid location output (maybe in general, wait
+ for 2 good Location outputs before checking this, in case they don't update the assistance
+ until after they output the Location)
+ */
+ double distanceM =
+ Utils::distanceMeters(data.position.latitudeDegrees, data.position.longitudeDegrees,
+ aidl_gnss_cb_->last_location_.latitudeDegrees,
+ aidl_gnss_cb_->last_location_.longitudeDegrees);
+ ALOGD("distance between debug position and last position: %.2lf", distanceM);
+ EXPECT_LT(distanceM, 1000.0); // 1km
+
+ /**
+ - Gnss Time Data:: timeEstimate should be reasonably close to the current GPS time.
+ - Gnss Time Data:: timeUncertaintyNs should always be > 0 and < 5e9 (could be large due
+ to solve-for-time type solutions)
+ - Gnss Time Data:: frequencyUncertaintyNsPerSec: should always be > 0 and < 1000 (1000 ns/s
+ corresponds to roughly a 300 m/s speed error, which should be pretty rare)
+ */
+ ALOGD("debug time: %" PRId64 ", position time: %" PRId64, data.time.timeEstimateMs,
+ aidl_gnss_cb_->last_location_.timestampMillis);
+ // Allowing 5s between the last location time and the current GPS time
+ EXPECT_LT(abs(data.time.timeEstimateMs - aidl_gnss_cb_->last_location_.timestampMillis), 5000);
+
+ ALOGD("debug time uncertainty: %f ns", data.time.timeUncertaintyNs);
+ EXPECT_GT(data.time.timeUncertaintyNs, 0);
+ EXPECT_LT(data.time.timeUncertaintyNs, 5e9);
+
+ ALOGD("debug freq uncertainty: %f ns/s", data.time.frequencyUncertaintyNsPerSec);
+ EXPECT_GT(data.time.frequencyUncertaintyNsPerSec, 0);
+ EXPECT_LT(data.time.frequencyUncertaintyNsPerSec, 1000);
}
/*
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 69e2b34..e3ff0f3 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -20,6 +20,7 @@
#include "gtest/gtest.h"
#include <cutils/properties.h>
+#include <math.h>
#include <utils/SystemClock.h>
namespace android {
@@ -58,6 +59,31 @@
checkElapsedRealtime(location.elapsedRealtime);
}
+void Utils::checkPositionDebug(android::hardware::gnss::IGnssDebug::DebugData data) {
+ if (data.position.valid) {
+ ASSERT_TRUE(data.position.latitudeDegrees >= -90 && data.position.latitudeDegrees <= 90);
+ ASSERT_TRUE(data.position.longitudeDegrees >= -180 &&
+ data.position.longitudeDegrees <= 180);
+ ASSERT_TRUE(data.position.altitudeMeters >= -1000 && // Dead Sea: -414m
+ data.position.altitudeMeters <= 20000); // Mount Everest: 8850m
+ ASSERT_TRUE(data.position.speedMetersPerSec >= 0 && data.position.speedMetersPerSec <= 600);
+ ASSERT_TRUE(data.position.bearingDegrees >= -360 && data.position.bearingDegrees <= 360);
+ ASSERT_TRUE(data.position.horizontalAccuracyMeters > 0 &&
+ data.position.horizontalAccuracyMeters <= 20000000);
+ ASSERT_TRUE(data.position.verticalAccuracyMeters > 0 &&
+ data.position.verticalAccuracyMeters <= 20000);
+ ASSERT_TRUE(data.position.speedAccuracyMetersPerSecond > 0 &&
+ data.position.speedAccuracyMetersPerSecond <= 500);
+ ASSERT_TRUE(data.position.bearingAccuracyDegrees > 0 &&
+ data.position.bearingAccuracyDegrees <= 180);
+ ASSERT_TRUE(data.position.ageSeconds >= 0);
+ }
+ ASSERT_TRUE(data.time.timeEstimateMs >= 1483228800000); // Jan 01 2017 00:00:00 GMT.
+ ASSERT_TRUE(data.time.timeUncertaintyNs > 0);
+ ASSERT_TRUE(data.time.frequencyUncertaintyNsPerSec > 0 &&
+ data.time.frequencyUncertaintyNsPerSec <= 2.0e5); // 200 ppm
+}
+
void Utils::checkElapsedRealtime(const ElapsedRealtime& elapsedRealtime) {
ASSERT_TRUE(elapsedRealtime.flags >= 0 &&
elapsedRealtime.flags <= (ElapsedRealtime::HAS_TIMESTAMP_NS |
@@ -282,6 +308,17 @@
return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
}
+double Utils::distanceMeters(double lat1, double lon1, double lat2, double lon2) {
+ double R = 6378.137; // Radius of earth in KM
+ double dLat = lat2 * M_PI / 180 - lat1 * M_PI / 180;
+ double dLon = lon2 * M_PI / 180 - lon1 * M_PI / 180;
+ double a = sin(dLat / 2) * sin(dLat / 2) +
+ cos(lat1 * M_PI / 180) * cos(lat2 * M_PI / 180) * sin(dLon / 2) * sin(dLon / 2);
+ double c = 2 * atan2(sqrt(a), sqrt(1 - a));
+ double d = R * c;
+ return d * 1000; // meters
+}
+
} // namespace common
} // namespace gnss
} // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index 7b89078..62d409a 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -43,6 +43,7 @@
static void checkElapsedRealtime(
const android::hardware::gnss::ElapsedRealtime& elapsedRealtime);
+ static void checkPositionDebug(android::hardware::gnss::IGnssDebug::DebugData data);
static const android::hardware::gnss::GnssLocation getMockLocation(
double latitudeDegrees, double longitudeDegrees, double horizontalAccuracyMeters);
@@ -57,6 +58,7 @@
V2_0::GnssConstellationType constellation);
static bool isAutomotiveDevice();
+ static double distanceMeters(double lat1, double lon1, double lat2, double lon2);
private:
template <class T>
diff --git a/graphics/allocator/aidl/Android.bp b/graphics/allocator/aidl/Android.bp
index 0b916bf..7bb6b50 100644
--- a/graphics/allocator/aidl/Android.bp
+++ b/graphics/allocator/aidl/Android.bp
@@ -12,7 +12,6 @@
name: "android.hardware.graphics.allocator",
vendor_available: true,
double_loadable: true,
- vndk_use_version: "2",
srcs: ["android/hardware/graphics/allocator/*.aidl"],
imports: [
"android.hardware.common-V2",
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 33d0938..4f5c3d9 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -13,7 +13,6 @@
host_supported: true,
vendor_available: true,
double_loadable: true,
- vndk_use_version: "5",
srcs: [
"android/hardware/graphics/common/*.aidl",
],
diff --git a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
index 336d15d..6a45987 100644
--- a/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
+++ b/graphics/composer/2.1/utils/command-buffer/include/composer-command-buffer/2.1/ComposerCommandBuffer.h
@@ -33,6 +33,7 @@
#include <string.h>
#include <android/hardware/graphics/composer/2.1/IComposer.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
#include <fmq/MessageQueue.h>
#include <log/log.h>
#include <sync/sync.h>
@@ -649,7 +650,8 @@
*outLength = static_cast<uint16_t>(val & length_mask);
if (mDataRead + *outLength > mDataSize) {
- ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+ ALOGE("command %s has invalid command length %" PRIu16,
+ toString(*outCommand).c_str(), *outLength);
// undo the read() above
mDataRead--;
return false;
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index fad70d8..c4e6878 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -30,7 +30,6 @@
vendor_available: true,
double_loadable: true,
frozen: true,
- vndk_use_version: "1",
srcs: [
"android/hardware/graphics/composer3/*.aidl",
],
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index d4ce3ba..3d9253f 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -59,10 +59,12 @@
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk());
+ const auto format = getHasReadbackBuffer() ? mPixelFormat : common::PixelFormat::RGBA_8888;
+
ASSERT_NO_FATAL_FAILURE(
mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine(
::android::renderengine::RenderEngineCreationArgs::Builder()
- .setPixelFormat(static_cast<int>(common::PixelFormat::RGBA_8888))
+ .setPixelFormat(static_cast<int>(format))
.setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers)
.setEnableProtectedContext(false)
.setPrecacheToneMapperShaderOnly(false)
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
index 3d206ac..423fd84 100644
--- a/media/bufferpool/aidl/default/Accessor.cpp
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "AidlBufferPoolAcc"
//#define LOG_NDEBUG 0
+#include <android-base/no_destructor.h>
+
#include <sys/types.h>
#include <stdint.h>
#include <time.h>
@@ -41,7 +43,25 @@
#endif
static constexpr uint32_t kSeqIdMax = 0x7fffffff;
-uint32_t Accessor::sSeqId = time(nullptr) & kSeqIdMax;
+
+Accessor::ConnectionIdGenerator::ConnectionIdGenerator() {
+ mSeqId = static_cast<uint32_t>(time(nullptr) & kSeqIdMax);
+ mPid = static_cast<int32_t>(getpid());
+}
+
+ConnectionId Accessor::ConnectionIdGenerator::getConnectionId() {
+ uint32_t seq;
+ {
+ std::lock_guard<std::mutex> l(mLock);
+ seq = mSeqId;
+ if (mSeqId == kSeqIdMax) {
+ mSeqId = 0;
+ } else {
+ ++mSeqId;
+ }
+ }
+ return (int64_t)mPid << 32 | seq | kSeqIdVndkBit;
+}
namespace {
// anonymous namespace
@@ -239,13 +259,14 @@
uint32_t *pMsgId,
StatusDescriptor* statusDescPtr,
InvalidationDescriptor* invDescPtr) {
+ static ::android::base::NoDestructor<ConnectionIdGenerator> sConIdGenerator;
std::shared_ptr<Connection> newConnection = ::ndk::SharedRefBase::make<Connection>();
BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
{
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
int32_t pid = getpid();
- ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+ ConnectionId id = sConIdGenerator->getConnectionId();
status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(ref<Accessor>(), id);
@@ -255,11 +276,6 @@
mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
- if (sSeqId == kSeqIdMax) {
- sSeqId = 0;
- } else {
- ++sSeqId;
- }
}
}
diff --git a/media/bufferpool/aidl/default/Accessor.h b/media/bufferpool/aidl/default/Accessor.h
index 85e2fa7..0ebe347 100644
--- a/media/bufferpool/aidl/default/Accessor.h
+++ b/media/bufferpool/aidl/default/Accessor.h
@@ -189,7 +189,14 @@
private:
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
- static uint32_t sSeqId;
+ struct ConnectionIdGenerator {
+ int32_t mPid;
+ uint32_t mSeqId;
+ std::mutex mLock;
+
+ ConnectionIdGenerator();
+ ConnectionId getConnectionId();
+ };
const std::shared_ptr<BufferPoolAllocator> mAllocator;
nsecs_t mScheduleEvictTs;
diff --git a/media/bufferpool/aidl/default/Android.bp b/media/bufferpool/aidl/default/Android.bp
index 72cd903..3c31446 100644
--- a/media/bufferpool/aidl/default/Android.bp
+++ b/media/bufferpool/aidl/default/Android.bp
@@ -29,6 +29,9 @@
export_include_dirs: [
"include",
],
+ header_libs: [
+ "libbase_headers",
+ ],
shared_libs: [
"libbinder_ndk",
"libcutils",
diff --git a/radio/aidl/vts/radio_config_test.cpp b/radio/aidl/vts/radio_config_test.cpp
index 6f18d18..e7214e5 100644
--- a/radio/aidl/vts/radio_config_test.cpp
+++ b/radio/aidl/vts/radio_config_test.cpp
@@ -278,7 +278,14 @@
EXPECT_LT(logicalSlotId, slotPortMappingList.size());
if (logicalSlotId >= 0 && logicalSlotId < slotPortMappingList.size()) {
slotPortMappingList[logicalSlotId].physicalSlotId = i;
- slotPortMappingList[logicalSlotId].portId = j;
+ if (radioRsp_config->simSlotStatus[i].supportedMepMode ==
+ MultipleEnabledProfilesMode::MEP_A1 ||
+ radioRsp_config->simSlotStatus[i].supportedMepMode ==
+ MultipleEnabledProfilesMode::MEP_A2) {
+ slotPortMappingList[logicalSlotId].portId = j + 1;
+ } else {
+ slotPortMappingList[logicalSlotId].portId = j;
+ }
}
}
}
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 7fbca36..5106561 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -16,7 +16,6 @@
#define LOG_TAG "keymint_1_attest_key_test"
#include <android-base/logging.h>
-#include <android-base/strings.h>
#include <cutils/log.h>
#include <cutils/properties.h>
@@ -29,66 +28,12 @@
namespace aidl::android::hardware::security::keymint::test {
namespace {
-string TELEPHONY_CMD_GET_IMEI = "cmd phone get-imei ";
bool IsSelfSigned(const vector<Certificate>& chain) {
if (chain.size() != 1) return false;
return ChainSignaturesAreValid(chain);
}
-/*
- * Run a shell command and collect the output of it. If any error, set an empty string as the
- * output.
- */
-string exec_command(string command) {
- char buffer[128];
- string result = "";
-
- FILE* pipe = popen(command.c_str(), "r");
- if (!pipe) {
- LOG(ERROR) << "popen failed.";
- return result;
- }
-
- // read till end of process:
- while (!feof(pipe)) {
- if (fgets(buffer, 128, pipe) != NULL) {
- result += buffer;
- }
- }
-
- pclose(pipe);
- return result;
-}
-
-/*
- * Get IMEI using Telephony service shell command. If any error while executing the command
- * then empty string will be returned as output.
- */
-string get_imei(int slot) {
- string cmd = TELEPHONY_CMD_GET_IMEI + std::to_string(slot);
- string output = exec_command(cmd);
-
- if (output.empty()) {
- LOG(ERROR) << "Command failed. Cmd: " << cmd;
- return "";
- }
-
- vector<string> out = ::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:");
-
- if (out.size() != 1) {
- LOG(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
- return "";
- }
-
- string imei = ::android::base::Trim(out[0]);
- if (imei.compare("null") == 0) {
- LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
- return "";
- }
-
- return imei;
-}
} // namespace
class AttestKeyTest : public KeyMintAidlTestBase {
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 332fcd4..cef8120 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -26,6 +26,7 @@
#include "keymint_support/keymint_tags.h"
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android/binder_manager.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <cppbor_parse.h>
@@ -1588,7 +1589,7 @@
// with any other key purpose, but the original VTS tests incorrectly did exactly that.
// This means that a device that launched prior to Android T (API level 33) may
// accept or even require KeyPurpose::SIGN too.
- if (property_get_int32("ro.board.first_api_level", 0) < __ANDROID_API_T__) {
+ if (get_vsr_api_level() < __ANDROID_API_T__) {
AuthorizationSet key_desc_plus_sign = key_desc;
key_desc_plus_sign.push_back(TAG_PURPOSE, KeyPurpose::SIGN);
@@ -2337,6 +2338,67 @@
return result;
}
+namespace {
+
+std::string TELEPHONY_CMD_GET_IMEI = "cmd phone get-imei ";
+
+/*
+ * Run a shell command and collect the output of it. If any error, set an empty string as the
+ * output.
+ */
+std::string exec_command(const std::string& command) {
+ char buffer[128];
+ std::string result = "";
+
+ FILE* pipe = popen(command.c_str(), "r");
+ if (!pipe) {
+ LOG(ERROR) << "popen failed.";
+ return result;
+ }
+
+ // read till end of process:
+ while (!feof(pipe)) {
+ if (fgets(buffer, 128, pipe) != NULL) {
+ result += buffer;
+ }
+ }
+
+ pclose(pipe);
+ return result;
+}
+
+} // namespace
+
+/*
+ * Get IMEI using Telephony service shell command. If any error while executing the command
+ * then empty string will be returned as output.
+ */
+std::string get_imei(int slot) {
+ std::string cmd = TELEPHONY_CMD_GET_IMEI + std::to_string(slot);
+ std::string output = exec_command(cmd);
+
+ if (output.empty()) {
+ LOG(ERROR) << "Command failed. Cmd: " << cmd;
+ return "";
+ }
+
+ vector<std::string> out =
+ ::android::base::Tokenize(::android::base::Trim(output), "Device IMEI:");
+
+ if (out.size() != 1) {
+ LOG(ERROR) << "Error in parsing the command output. Cmd: " << cmd;
+ return "";
+ }
+
+ std::string imei = ::android::base::Trim(out[0]);
+ if (imei.compare("null") == 0) {
+ LOG(WARNING) << "Failed to get IMEI from Telephony service: value is null. Cmd: " << cmd;
+ return "";
+ }
+
+ return imei;
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index b884cc7..1bf2d9d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -430,6 +430,7 @@
void device_id_attestation_check_acceptable_error(Tag tag, const ErrorCode& result);
bool check_feature(const std::string& name);
std::optional<int32_t> keymint_feature_value(bool strongbox);
+std::string get_imei(int slot);
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 35e5e84..3c49a82 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -2026,7 +2026,7 @@
* NewKeyGenerationTest.EcdsaAttestationIdTags
*
* Verifies that creation of an attested ECDSA key includes various ID tags in the
- * attestation extension.
+ * attestation extension one by one.
*/
TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
auto challenge = "hello";
@@ -2054,6 +2054,15 @@
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
+ string imei = get_imei(0);
+ if (!imei.empty()) {
+ extra_tags.Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size());
+ }
+ string second_imei = get_imei(1);
+ if (!second_imei.empty()) {
+ extra_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(),
+ second_imei.size());
+ }
for (const KeyParameter& tag : extra_tags) {
SCOPED_TRACE(testing::Message() << "tag-" << tag);
@@ -2091,6 +2100,83 @@
}
/*
+ * NewKeyGenerationTest.EcdsaAttestationIdAllTags
+ *
+ * Verifies that creation of an attested ECDSA key includes various ID tags in the
+ * attestation extension all together.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationIdAllTags) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+ auto subject = "cert subj 2";
+ vector<uint8_t> subject_der(make_name_from_str(subject));
+ uint64_t serial_int = 0x1010;
+ vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Digest(Digest::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+ .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+ .SetDefaultValidity();
+
+ // Various ATTESTATION_ID_* tags that map to fields in the attestation extension ASN.1 schema.
+ auto extra_tags = AuthorizationSetBuilder();
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+ add_attestation_id(&extra_tags, TAG_ATTESTATION_ID_MODEL, "model");
+ add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
+ string imei = get_imei(0);
+ if (!imei.empty()) {
+ extra_tags.Authorization(TAG_ATTESTATION_ID_IMEI, imei.data(), imei.size());
+ }
+ string second_imei = get_imei(1);
+ if (!second_imei.empty()) {
+ extra_tags.Authorization(TAG_ATTESTATION_ID_SECOND_IMEI, second_imei.data(),
+ second_imei.size());
+ }
+ for (const KeyParameter& tag : extra_tags) {
+ builder.push_back(tag);
+ }
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+ if (result == ErrorCode::CANNOT_ATTEST_IDS && !isDeviceIdAttestationRequired()) {
+ // ID attestation was optional till api level 32, from api level 33 it is mandatory.
+ return;
+ }
+ ASSERT_EQ(result, ErrorCode::OK);
+ KeyBlobDeleter deleter(keymint_, key_blob);
+ ASSERT_GT(key_blob.size(), 0U);
+
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+ ASSERT_GT(cert_chain_.size(), 0);
+ verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+
+ // The attested key characteristics will not contain APPLICATION_ID_* fields (their
+ // spec definitions all have "Must never appear in KeyCharacteristics"), but the
+ // attestation extension should contain them, so make sure the extra tags are added.
+ for (const KeyParameter& tag : extra_tags) {
+ hw_enforced.push_back(tag);
+ }
+
+ // Verifying the attestation record will check for the specific tag because
+ // it's included in the authorizations.
+ EXPECT_TRUE(verify_attestation_record(AidlVersion(), challenge, app_id, sw_enforced,
+ hw_enforced, SecLevel(),
+ cert_chain_[0].encodedCertificate))
+ << "failed to verify " << bin2hex(cert_chain_[0].encodedCertificate);
+}
+
+/*
* NewKeyGenerationTest.EcdsaAttestationUniqueId
*
* Verifies that creation of an attested ECDSA key with a UNIQUE_ID included.
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
new file mode 100644
index 0000000..1b1a580
--- /dev/null
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -0,0 +1,69 @@
+/*
+ * 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 {
+ // 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"],
+ default_team: "trendy_team_android_hardware_backed_security",
+}
+
+cc_defaults {
+ name: "keymint_fuzzer_defaults",
+ static_libs: [
+ "libhidlbase",
+ "libkeymint_support",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libutils",
+ "libhardware",
+ "libbinder_ndk",
+ "liblog",
+ ],
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ include_dirs: [
+ "hardware/interfaces/security/keymint/support/include",
+ "frameworks/native/libs/binder/ndk/include_platform",
+ ],
+}
+
+cc_fuzz {
+ name: "keymint_attestation_fuzzer",
+ srcs: [
+ "keymint_attestation_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "keymint_authSet_fuzzer",
+ srcs: [
+ "keymint_authSet_fuzzer.cpp",
+ ],
+ defaults: [
+ "keymint_fuzzer_defaults",
+ ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
new file mode 100644
index 0000000..d41af08
--- /dev/null
+++ b/security/keymint/support/fuzzer/README.md
@@ -0,0 +1,79 @@
+# Fuzzers for libkeymint_support
+
+## Plugin Design Considerations
+The fuzzer plugins for libkeymint_support are designed based on the understanding of the source code and try to achieve the following:
+
+#### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on incoming data. This ensures more code paths are reached by the fuzzers.
+
+#### Maximize utilization of input data
+The plugins feed the entire input data to the module. This ensures that the plugins tolerate any kind of input (empty, huge, malformed, etc) and dont `exit()` on any input and thereby increasing the chance of identifying vulnerabilities.
+
+## Table of contents
++ [keymint_attestation_fuzzer](#KeyMintAttestation)
++ [keymint_authSet_fuzzer](#KeyMintAuthSet)
+
+# <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
+KeyMintAttestation supports the following parameters:
+1. PaddingMode(parameter name: "padding")
+2. Digest(parameter name: "digest")
+3. Index(parameter name: "idx")
+4. Timestamp(parameter name: "timestamp")
+5. AuthSet(parameter name: "authSet")
+6. IssuerSubjectName(parameter name: "issuerSubjectName")
+7. AttestationChallenge(parameter name: "challenge")
+8. AttestationApplicationId(parameter name: "id")
+9. EcCurve(parameter name: "ecCurve")
+10. BlockMode(parameter name: "blockmode")
+11. minMacLength(parameter name: "minMacLength")
+12. macLength(parameter name: "macLength")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`padding`| `PaddingMode` |Value obtained from FuzzedDataProvider|
+|`digest`| `Digest` |Value obtained from FuzzedDataProvider|
+|`idx`| `size_t` |Value obtained from FuzzedDataProvider|
+|`timestamp`| `uint64_t` |Value obtained from FuzzedDataProvider|
+|`authSet`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`issuerSubjectName`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`AttestationChallenge`| `string` |Value obtained from FuzzedDataProvider|
+|`AttestationApplicationId`| `string` |Value obtained from FuzzedDataProvider|
+|`blockmode`| `BlockMode` |Value obtained from FuzzedDataProvider|
+|`minMacLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+|`macLength`| `uint32_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_attestation_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_attestation_fuzzer/keymint_attestation_fuzzer
+```
+
+# <a name="KeyMintAuthSet"></a> Fuzzer for KeyMintAuthSet
+KeyMintAuthSet supports the following parameters:
+1. AuthorizationSet(parameter name: "authSet")
+2. AuthorizationSet(parameter name: "params")
+3. KeyParameters(parameter name: "numKeyParam")
+4. Tag(parameter name: "tag")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`authSet`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`params`| `AuthorizationSet` |Value obtained from FuzzedDataProvider|
+|`numKeyParam`| `size_t` |Value obtained from FuzzedDataProvider|
+|`tag`| `Tag` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_authSet_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
new file mode 100644
index 0000000..bd781ac
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_attestation_fuzzer.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 <aidl/android/hardware/security/keymint/AttestationKey.h>
+#include <aidl/android/hardware/security/keymint/KeyCreationResult.h>
+#include <android/binder_manager.h>
+#include <keymint_common.h>
+#include <keymint_support/attestation_record.h>
+#include <keymint_support/openssl_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+using namespace android;
+using AStatus = ::ndk::ScopedAStatus;
+std::shared_ptr<IKeyMintDevice> gKeyMint = nullptr;
+
+constexpr size_t kMaxBytes = 256;
+const std::string kServiceName = "android.hardware.security.keymint.IKeyMintDevice/default";
+
+class KeyMintAttestationFuzzer {
+ public:
+ KeyMintAttestationFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ KeyCreationResult generateKey(const AuthorizationSet& keyDesc,
+ const std::optional<AttestationKey>& attestKey,
+ vector<uint8_t>* keyBlob,
+ vector<KeyCharacteristics>* keyCharacteristics,
+ vector<Certificate>* certChain);
+ X509_Ptr parseCertificateBlob(const vector<uint8_t>& blob);
+ ASN1_OCTET_STRING* getAttestationRecord(const X509* certificate);
+ bool verifyAttestationRecord(const vector<uint8_t>& attestationCert);
+ FuzzedDataProvider mFdp;
+};
+
+KeyCreationResult KeyMintAttestationFuzzer::generateKey(
+ const AuthorizationSet& keyDesc, const std::optional<AttestationKey>& attestKey,
+ vector<uint8_t>* keyBlob, vector<KeyCharacteristics>* keyCharacteristics,
+ vector<Certificate>* certChain) {
+ KeyCreationResult creationResult;
+ AStatus result = gKeyMint->generateKey(keyDesc.vector_data(), attestKey, &creationResult);
+ if (result.isOk() && creationResult.keyBlob.size() > 0) {
+ *keyBlob = std::move(creationResult.keyBlob);
+ *keyCharacteristics = std::move(creationResult.keyCharacteristics);
+ *certChain = std::move(creationResult.certificateChain);
+ }
+ return creationResult;
+}
+
+X509_Ptr KeyMintAttestationFuzzer::parseCertificateBlob(const vector<uint8_t>& blob) {
+ const uint8_t* data = blob.data();
+ return X509_Ptr(d2i_X509(nullptr, &data, blob.size()));
+}
+
+ASN1_OCTET_STRING* KeyMintAttestationFuzzer::getAttestationRecord(const X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ if (!oid.get()) {
+ return nullptr;
+ }
+
+ int32_t location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ if (location == -1) {
+ return nullptr;
+ }
+
+ X509_EXTENSION* attestRecordExt = X509_get_ext(certificate, location);
+ if (!attestRecordExt) {
+ return nullptr;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = X509_EXTENSION_get_data(attestRecordExt);
+ return attestRecord;
+}
+
+bool KeyMintAttestationFuzzer::verifyAttestationRecord(const vector<uint8_t>& attestationCert) {
+ X509_Ptr cert(parseCertificateBlob(attestationCert));
+ if (!cert.get()) {
+ return false;
+ }
+
+ ASN1_OCTET_STRING* attestRecord = getAttestationRecord(cert.get());
+ if (!attestRecord) {
+ return false;
+ }
+
+ AuthorizationSet attestationSwEnforced;
+ AuthorizationSet attestationHwEnforced;
+ SecurityLevel attestationSecurityLevel;
+ SecurityLevel keymintSecurityLevel;
+ vector<uint8_t> attestationChallenge;
+ vector<uint8_t> attestationUniqueId;
+ uint32_t attestationVersion;
+ uint32_t keymintVersion;
+
+ auto error = parse_attestation_record(attestRecord->data, attestRecord->length,
+ &attestationVersion, &attestationSecurityLevel,
+ &keymintVersion, &keymintSecurityLevel,
+ &attestationChallenge, &attestationSwEnforced,
+ &attestationHwEnforced, &attestationUniqueId);
+ if (error != ErrorCode::OK) {
+ return false;
+ }
+
+ VerifiedBoot verifiedBootState;
+ vector<uint8_t> verifiedBootKey;
+ vector<uint8_t> verifiedBootHash;
+ bool device_locked;
+
+ error = parse_root_of_trust(attestRecord->data, attestRecord->length, &verifiedBootKey,
+ &verifiedBootState, &device_locked, &verifiedBootHash);
+ if (error != ErrorCode::OK) {
+ return false;
+ }
+ return true;
+}
+
+void KeyMintAttestationFuzzer::process() {
+ AttestationKey attestKey;
+ vector<Certificate> attestKeyCertChain;
+ vector<KeyCharacteristics> attestKeyCharacteristics;
+ generateKey(createAuthSetForAttestKey(&mFdp), {}, &attestKey.keyBlob, &attestKeyCharacteristics,
+ &attestKeyCertChain);
+
+ vector<Certificate> attestedKeyCertChain;
+ vector<KeyCharacteristics> attestedKeyCharacteristics;
+ vector<uint8_t> attestedKeyBlob;
+ attestKey.issuerSubjectName = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+ generateKey(createAuthorizationSet(&mFdp), attestKey, &attestedKeyBlob,
+ &attestedKeyCharacteristics, &attestedKeyCertChain);
+
+ if (attestedKeyCertChain.size() > 0) {
+ size_t leafCert = attestedKeyCertChain.size() - 1;
+ verifyAttestationRecord(attestedKeyCertChain[leafCert].encodedCertificate);
+ }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+ gKeyMint = std::move(IKeyMintDevice::fromBinder(binder));
+ LOG_ALWAYS_FATAL_IF(!gKeyMint, "Failed to get IKeyMintDevice instance.");
+ return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintAttestationFuzzer kmAttestationFuzzer(data, size);
+ kmAttestationFuzzer.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
new file mode 100644
index 0000000..fcc3d91
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_authSet_fuzzer.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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 <keymint_common.h>
+#include <fstream>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+constexpr size_t kMinAction = 0;
+constexpr size_t kMaxAction = 10;
+constexpr size_t kMinKeyParameter = 1;
+constexpr size_t kMaxKeyParameter = 10;
+
+constexpr Tag kTagArray[] = {Tag::INVALID,
+ Tag::PURPOSE,
+ Tag::ALGORITHM,
+ Tag::KEY_SIZE,
+ Tag::BLOCK_MODE,
+ Tag::DIGEST,
+ Tag::PADDING,
+ Tag::CALLER_NONCE,
+ Tag::MIN_MAC_LENGTH,
+ Tag::EC_CURVE,
+ Tag::RSA_PUBLIC_EXPONENT,
+ Tag::INCLUDE_UNIQUE_ID,
+ Tag::RSA_OAEP_MGF_DIGEST,
+ Tag::BOOTLOADER_ONLY,
+ Tag::ROLLBACK_RESISTANCE,
+ Tag::HARDWARE_TYPE,
+ Tag::EARLY_BOOT_ONLY,
+ Tag::ACTIVE_DATETIME,
+ Tag::ORIGINATION_EXPIRE_DATETIME,
+ Tag::USAGE_EXPIRE_DATETIME,
+ Tag::MIN_SECONDS_BETWEEN_OPS,
+ Tag::MAX_USES_PER_BOOT,
+ Tag::USAGE_COUNT_LIMIT,
+ Tag::USER_ID,
+ Tag::USER_SECURE_ID,
+ Tag::NO_AUTH_REQUIRED,
+ Tag::USER_AUTH_TYPE,
+ Tag::AUTH_TIMEOUT,
+ Tag::ALLOW_WHILE_ON_BODY,
+ Tag::TRUSTED_USER_PRESENCE_REQUIRED,
+ Tag::TRUSTED_CONFIRMATION_REQUIRED,
+ Tag::UNLOCKED_DEVICE_REQUIRED,
+ Tag::APPLICATION_ID,
+ Tag::APPLICATION_DATA,
+ Tag::CREATION_DATETIME,
+ Tag::ORIGIN,
+ Tag::ROOT_OF_TRUST,
+ Tag::OS_VERSION,
+ Tag::OS_PATCHLEVEL,
+ Tag::UNIQUE_ID,
+ Tag::ATTESTATION_CHALLENGE,
+ Tag::ATTESTATION_APPLICATION_ID,
+ Tag::ATTESTATION_ID_BRAND,
+ Tag::ATTESTATION_ID_DEVICE,
+ Tag::ATTESTATION_ID_PRODUCT,
+ Tag::ATTESTATION_ID_SERIAL,
+ Tag::ATTESTATION_ID_IMEI,
+ Tag::ATTESTATION_ID_MEID,
+ Tag::ATTESTATION_ID_MANUFACTURER,
+ Tag::ATTESTATION_ID_MODEL,
+ Tag::VENDOR_PATCHLEVEL,
+ Tag::BOOT_PATCHLEVEL,
+ Tag::DEVICE_UNIQUE_ATTESTATION,
+ Tag::IDENTITY_CREDENTIAL_KEY,
+ Tag::STORAGE_KEY,
+ Tag::ASSOCIATED_DATA,
+ Tag::NONCE,
+ Tag::MAC_LENGTH,
+ Tag::RESET_SINCE_ID_ROTATION,
+ Tag::CONFIRMATION_TOKEN,
+ Tag::CERTIFICATE_SERIAL,
+ Tag::CERTIFICATE_SUBJECT,
+ Tag::CERTIFICATE_NOT_BEFORE,
+ Tag::CERTIFICATE_NOT_AFTER,
+ Tag::MAX_BOOT_LEVEL};
+
+class KeyMintAuthSetFuzzer {
+ public:
+ KeyMintAuthSetFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+ void process();
+
+ private:
+ FuzzedDataProvider mFdp;
+};
+
+void KeyMintAuthSetFuzzer::process() {
+ AuthorizationSet authSet = createAuthorizationSet(&mFdp);
+ while (mFdp.remaining_bytes()) {
+ auto invokeAuthSetAPI = mFdp.PickValueInArray<const std::function<void()>>({
+ [&]() { authSet.Sort(); },
+ [&]() { authSet.Deduplicate(); },
+ [&]() { authSet.Union(createAuthorizationSet(&mFdp)); },
+ [&]() { authSet.Subtract(createAuthorizationSet(&mFdp)); },
+ [&]() { // invoke push_back()
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder();
+ for (const KeyParameter& tag : authSet) {
+ builder.push_back(tag);
+ }
+ AuthorizationSet params = createAuthorizationSet(&mFdp);
+ authSet.push_back(params);
+ },
+ [&]() { // invoke copy constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = params;
+ },
+ [&]() { // invoke move constructor
+ auto params = AuthorizationSetBuilder().Authorizations(authSet);
+ authSet = std::move(params);
+ },
+ [&]() { // invoke Constructor from vector<KeyParameter>
+ vector<KeyParameter> keyParam;
+ size_t numKeyParam =
+ mFdp.ConsumeIntegralInRange<size_t>(kMinKeyParameter, kMaxKeyParameter);
+ keyParam.resize(numKeyParam);
+ for (size_t idx = 0; idx < numKeyParam - 1; ++idx) {
+ keyParam[idx].tag = mFdp.PickValueInArray(kTagArray);
+ }
+ if (mFdp.ConsumeBool()) {
+ AuthorizationSet auths(keyParam);
+ auths.push_back(AuthorizationSet(keyParam));
+ } else { // invoke operator=
+ AuthorizationSet auths = keyParam;
+ }
+ },
+ [&]() { // invoke 'Contains()'
+ Tag tag = Tag::INVALID;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+ .tag;
+ }
+ authSet.Contains(mFdp.ConsumeBool() ? tag : mFdp.PickValueInArray(kTagArray));
+ },
+ [&]() { // invoke 'GetTagCount()'
+ Tag tag = Tag::INVALID;
+ if (authSet.size() > 0) {
+ tag = authSet[mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1)]
+ .tag;
+ }
+ authSet.GetTagCount(mFdp.ConsumeBool() ? tag
+ : mFdp.PickValueInArray(kTagArray));
+ },
+ [&]() { // invoke 'erase()'
+ if (authSet.size() > 0) {
+ authSet.erase(mFdp.ConsumeIntegralInRange<size_t>(0, authSet.size() - 1));
+ }
+ },
+ });
+ invokeAuthSetAPI();
+ }
+ authSet.Clear();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ KeyMintAuthSetFuzzer kmAuthSetFuzzer(data, size);
+ kmAuthSetFuzzer.process();
+ return 0;
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_common.h b/security/keymint/support/fuzzer/keymint_common.h
new file mode 100644
index 0000000..5c30e38
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_common.h
@@ -0,0 +1,260 @@
+/*
+ * 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 __KEYMINT_COMMON_H__
+#define __KEYMINT_COMMON_H__
+
+#include <aidl/android/hardware/security/keymint/BlockMode.h>
+#include <aidl/android/hardware/security/keymint/Digest.h>
+#include <aidl/android/hardware/security/keymint/EcCurve.h>
+#include <aidl/android/hardware/security/keymint/PaddingMode.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <keymint_support/authorization_set.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint;
+
+constexpr uint32_t kStringSize = 64;
+constexpr uint32_t k3DesKeySize = 168;
+constexpr uint32_t kSymmKeySize = 256;
+constexpr uint32_t kRsaKeySize = 2048;
+constexpr uint32_t kPublicExponent = 65537;
+
+constexpr EcCurve kCurve[] = {EcCurve::P_224, EcCurve::P_256, EcCurve::P_384, EcCurve::P_521,
+ EcCurve::CURVE_25519};
+
+constexpr PaddingMode kPaddingMode[] = {
+ PaddingMode::NONE,
+ PaddingMode::RSA_OAEP,
+ PaddingMode::RSA_PSS,
+ PaddingMode::RSA_PKCS1_1_5_ENCRYPT,
+ PaddingMode::RSA_PKCS1_1_5_SIGN,
+ PaddingMode::PKCS7,
+};
+
+constexpr Digest kDigest[] = {
+ Digest::NONE, Digest::MD5, Digest::SHA1, Digest::SHA_2_224,
+ Digest::SHA_2_256, Digest::SHA_2_384, Digest::SHA_2_512,
+};
+
+constexpr BlockMode kBlockMode[] = {
+ BlockMode::ECB,
+ BlockMode::CBC,
+ BlockMode::CTR,
+ BlockMode::GCM,
+};
+
+enum AttestAuthSet : uint32_t {
+ RSA_ATTEST_KEY = 0u,
+ ECDSA_ATTEST_KEY,
+};
+
+enum AuthSet : uint32_t {
+ RSA_KEY = 0u,
+ RSA_SIGNING_KEY,
+ RSA_ENCRYPTION_KEY,
+ ECDSA_SIGNING_CURVE,
+ AES_ENCRYPTION_KEY,
+ TRIPLE_DES,
+ HMAC,
+ NO_DIGEST,
+ ECB_MODE,
+ GSM_MODE_MIN_MAC,
+ GSM_MODE_MAC,
+ BLOCK_MODE,
+};
+
+AuthorizationSet createAuthSetForAttestKey(FuzzedDataProvider* dataProvider) {
+ uint32_t attestAuthSet = dataProvider->ConsumeBool() ? AttestAuthSet::RSA_ATTEST_KEY
+ : AttestAuthSet::ECDSA_ATTEST_KEY;
+ uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+ std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+ switch (attestAuthSet) {
+ case RSA_ATTEST_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+ } break;
+ case ECDSA_ATTEST_KEY: {
+ EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaKey(ecCurve)
+ .AttestKey()
+ .Digest(digest)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+ } break;
+ default:
+ break;
+ };
+ return AuthorizationSetBuilder();
+}
+
+AuthorizationSet createAuthorizationSet(FuzzedDataProvider* dataProvider) {
+ uint32_t authSet =
+ dataProvider->ConsumeIntegralInRange<uint32_t>(AuthSet::RSA_KEY, AuthSet::BLOCK_MODE);
+ uint64_t timestamp = dataProvider->ConsumeIntegral<uint64_t>();
+ Digest digest = dataProvider->PickValueInArray(kDigest);
+ PaddingMode padding = dataProvider->PickValueInArray(kPaddingMode);
+ std::string challenge = dataProvider->ConsumeRandomLengthString(kStringSize);
+ std::string id = dataProvider->ConsumeRandomLengthString(kStringSize);
+ switch (authSet) {
+ case RSA_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestKey()
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case RSA_SIGNING_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaSigningKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case RSA_ENCRYPTION_KEY: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .RsaEncryptionKey(kRsaKeySize, kPublicExponent)
+ .Digest(digest)
+ .Padding(padding)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case ECDSA_SIGNING_CURVE: {
+ EcCurve ecCurve = dataProvider->PickValueInArray(kCurve);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .EcdsaSigningKey(ecCurve)
+ .Digest(digest)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(id)
+ .SetDefaultValidity()
+ .Authorization(TAG_CREATION_DATETIME, timestamp)
+ .Authorization(TAG_INCLUDE_UNIQUE_ID);
+ } break;
+ case AES_ENCRYPTION_KEY: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case TRIPLE_DES: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .TripleDesEncryptionKey(k3DesKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding)
+ .EcbMode()
+ .SetDefaultValidity();
+ } break;
+ case HMAC: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .HmacKey(kSymmKeySize)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case NO_DIGEST: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .NoDigestOrPadding()
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case ECB_MODE: {
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .EcbMode()
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case GSM_MODE_MIN_MAC: {
+ uint32_t minMacLength = dataProvider->ConsumeIntegral<uint32_t>();
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .GcmModeMinMacLen(minMacLength)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case GSM_MODE_MAC: {
+ uint32_t macLength = dataProvider->ConsumeIntegral<uint32_t>();
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .GcmModeMacLen(macLength)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ case BLOCK_MODE: {
+ BlockMode blockmode = dataProvider->PickValueInArray(kBlockMode);
+ return AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AesEncryptionKey(kSymmKeySize)
+ .BlockMode(blockmode)
+ .Digest(digest)
+ .Padding(padding);
+ } break;
+ default:
+ break;
+ };
+ return AuthorizationSetBuilder();
+}
+
+} // namespace android::hardware::security::keymint_support::fuzzer
+
+#endif // __KEYMINT_COMMON_H__
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
index d36d986..7f33e2d 100644
--- a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -352,8 +352,8 @@
// @VsrTest = VSR-3.2.5-002
TEST_P(ThermalAidlTest, SkinTemperatureThresholdsTest) {
auto apiLevel = ::android::base::GetIntProperty<int32_t>("ro.vendor.api_level", 0);
- if (apiLevel < 35) {
- GTEST_SKIP() << "Skipping test as the vendor level is below 35: " << apiLevel;
+ if (apiLevel < 202404) {
+ GTEST_SKIP() << "Skipping test as the vendor level is below 202404: " << apiLevel;
}
for (const auto& feature : kNonHandheldFeatures) {
if (::testing::deviceSupportsFeature(feature.c_str())) {
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index d02cf4d..bb543f2 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -46,4 +46,5 @@
NB_OF_ELEVATION_MEASUREMENTS = 0xE5,
ENABLE_DIAGNOSTICS = 0xE8,
DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
+ ANTENNA_MODE = 0xEA,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
index 65bb1c9..b8b4490 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionAppConfigTlvTypes.aidl
@@ -87,4 +87,12 @@
* b3 - b7: RFU
*/
DIAGRAMS_FRAME_REPORTS_FIELDS = 0xE9,
+
+ /**
+ * 1 byte data
+ * 0x0: Omni mode - the ranging antenna is used for both Tx and Rx.
+ * 0x1: Directional mode - the patch antenna is used for both Tx and Rx.
+ * 0x2 - 0xFF: RFU
+ */
+ ANTENNA_MODE = 0xEA,
}
diff --git a/uwb/aidl/default/src/uwb_chip.rs b/uwb/aidl/default/src/uwb_chip.rs
index 878aa64..956cf6c 100644
--- a/uwb/aidl/default/src/uwb_chip.rs
+++ b/uwb/aidl/default/src/uwb_chip.rs
@@ -71,7 +71,7 @@
let packet_vec: Vec<UciControlPacketHal> = packet.into();
for hal_packet in packet_vec.into_iter() {
serial
- .write(&hal_packet.to_vec())
+ .write(&hal_packet.encode_to_vec().unwrap())
.map(|written| written as i32)
.map_err(|_| binder::StatusCode::UNKNOWN_ERROR)?;
}
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index cf86120..bd92a20 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -2012,7 +2012,7 @@
}
wifi_error WifiLegacyHal::setScanMode(const std::string& iface_name, bool enable) {
- return global_func_table_.wifi_set_scan_mode(iface_name.c_str(), enable);
+ return global_func_table_.wifi_set_scan_mode(getIfaceHandle(iface_name), enable);
}
wifi_error WifiLegacyHal::setDtimConfig(const std::string& iface_name, uint32_t multiplier) {
diff --git a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
index c87fe13..f659bf6 100644
--- a/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_sta_iface_aidl_test.cpp
@@ -148,7 +148,7 @@
* Ensures the APF packet filter is fully supported as required in VSR 14:
* https://docs.partner.android.com/gms/policies/vsr/vsr-14
*/
-// @VsrTest = 5.3.12
+// @VsrTest = VSR-5.3.12-001|VSR-5.3.12-003|VSR-5.3.12-004|VSR-5.3.12-009
TEST_P(WifiStaIfaceAidlTest, CheckApfIsSupported) {
const std::string oem_key1 = getPropertyString("ro.oem.key1");
if (isTvDevice()) {
diff --git a/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h b/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
index e770777..9baa2c7 100644
--- a/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
+++ b/wifi/legacy_headers/include/hardware_legacy/wifi_hal.h
@@ -715,7 +715,7 @@
/* Wi-Fi coex channel avoidance support */
-#define WIFI_COEX_NO_POWER_CAP (int32_t)0x7FFFFFF
+#define WIFI_COEX_NO_POWER_CAP (int32_t)0x7FFFFFFF
typedef enum {
WIFI_AWARE = 1 << 0,
@@ -1386,7 +1386,7 @@
* @param enable true if current is scan only mode
* @return Synchronous wifi_error
*/
- wifi_error (*wifi_set_scan_mode)(const char * ifname, bool enable);
+ wifi_error (*wifi_set_scan_mode)(wifi_interface_handle iface, bool enable);
wifi_error (*wifi_nan_pairing_end)(transaction_id id,
wifi_interface_handle iface,