Merge "Added supportedEnums logic description to enum files" 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/Stream.cpp b/audio/aidl/default/Stream.cpp
index a70c12d..31b0645 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -183,17 +183,19 @@
switch (command.getTag()) {
case Tag::halReservedExit: {
const int32_t cookie = command.get<Tag::halReservedExit>();
+ StreamInWorkerLogic::Status status = Status::CONTINUE;
if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
mDriver->shutdown();
setClosed();
+ status = Status::EXIT;
} else {
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
if (cookie != 0) { // This is an internal command, no need to reply.
- return Status::EXIT;
- } else {
- break;
+ return status;
}
+ // `cookie == 0` can only occur in the context of a VTS test, need to reply.
+ break;
}
case Tag::getStatus:
populateReply(&reply, mIsConnected);
@@ -411,17 +413,19 @@
switch (command.getTag()) {
case Tag::halReservedExit: {
const int32_t cookie = command.get<Tag::halReservedExit>();
+ StreamOutWorkerLogic::Status status = Status::CONTINUE;
if (cookie == (mContext->getInternalCommandCookie() ^ getTid())) {
mDriver->shutdown();
setClosed();
+ status = Status::EXIT;
} else {
LOG(WARNING) << __func__ << ": EXIT command has a bad cookie: " << cookie;
}
if (cookie != 0) { // This is an internal command, no need to reply.
- return Status::EXIT;
- } else {
- break;
+ return status;
}
+ // `cookie == 0` can only occur in the context of a VTS test, need to reply.
+ break;
}
case Tag::getStatus:
populateReply(&reply, mIsConnected);
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/Android.bp b/automotive/vehicle/aidl/Android.bp
index ed18ebc..ce9e7a1 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -60,5 +60,5 @@
},
],
-
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/aidl_test/Android.bp b/automotive/vehicle/aidl/aidl_test/Android.bp
index ea6a710..f517df8 100644
--- a/automotive/vehicle/aidl/aidl_test/Android.bp
+++ b/automotive/vehicle/aidl/aidl_test/Android.bp
@@ -40,7 +40,7 @@
cc_test {
name: "VehiclePropertyAnnotationCppTest",
srcs: ["VehiclePropertyAnnotationCppTest.cpp"],
- header_libs: ["IVehicleGeneratedHeaders"],
+ header_libs: ["IVehicleGeneratedHeaders-V3"],
defaults: ["VehicleHalInterfaceDefaults"],
test_suites: ["general-tests"],
}
diff --git a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
index 135f30a..de0e398 100644
--- a/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
+++ b/automotive/vehicle/aidl/emu_metadata/android.hardware.automotive.vehicle-types-meta.json
@@ -516,12 +516,12 @@
{
"name": "DISPLAY_BRIGHTNESS",
"value": 289409539,
- "description": "Property to represent brightness of the display.\nSome cars have single control for the brightness of all displays and this property is to share change in that control. In cars which have displays whose brightness is controlled separately, they must use PER_DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nIf this is writable, android side can set this value when user changes display brightness from Settings. If this is read only, user may still change display brightness from Settings, but that must not be reflected to other displays."
+ "description": "Property to represent brightness of the display.\nSome cars have single control for the brightness of all displays and this property is to share change in that control. In cars which have displays whose brightness is controlled separately, they must use PER_DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nIf this is writable, android side can set this value when user changes display brightness from Settings. If this is read only, user may still change display brightness from Settings, but that must not be reflected to other displays.\nIf this is writable, writing this property must cause an on property change event even if the new display brightness is the same as the current value."
},
{
"name": "PER_DISPLAY_BRIGHTNESS",
"value": 289475076,
- "description": "Property to represent brightness of the displays which are controlled separately.\nSome cars have one or more displays whose brightness is controlled separately and this property is to inform the brightness of each passenger display. In cars where all displays' brightness is controlled together, they must use DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nThe display port uniquely identifies a physical connector on the device for display output, ranging from 0 to 255.\nint32Values[0] : display port int32Values[1] : brightness"
+ "description": "Property to represent brightness of the displays which are controlled separately.\nSome cars have one or more displays whose brightness is controlled separately and this property is to inform the brightness of each passenger display. In cars where all displays' brightness is controlled together, they must use DISPLAY_BRIGHTNESS.\nOnly one of DISPLAY_BRIGHTNESS and PER_DISPLAY_BRIGHTNESS should be implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by AAOS.\nIf this is supported, PER_DISPLAY_MAX_BRIGHTNESS must be supported to represent the max display brightness for each display. Otherwise, the max display brightness is by default 1. The VehicleAreaConfig.maxInt32Value must not be used to represent max display brightness, because maxInt32Value is defined to be the max value for all the elements inside the integer value, which includes display port and brightness. So it is not meaningful.\nThe display port uniquely identifies a physical connector on the device for display output, ranging from 0 to 255.\nWriting this property must cause an on property change event that contains the same [display port, brightness] tuple even if the new display brightness is the same as the current value.\nTo get the display brightness for a specific display port, the GetValueRequest must contain a VehiclePropValue, which contains one int32Value: displayPort. Getting this property without specifying the the display port is undefined behavior.\nint32Values[0] : display port int32Values[1] : brightness"
},
{
"name": "Valet mode enabled",
@@ -1364,6 +1364,11 @@
"description": "Reports current state of CarEvsService types.\nInforms other components of current state of each CarEvsService service type with values defined in CameraServiceState. CarEvsService will update this property whenever a service type transitions into a new state.\nint32[0]: Current state of REARVIEW service type. int32[1]: Current state of SURROUNDVIEW service type. int32[2]: Current state of FRONTVIEW service type. int32[3]: Current state of LEFTVIEW service type. int32[4]: Current state of RIGHTVIEW service type. int32[5]: Current state of DRIVERVIEW service type. int32[6]: Current state of FRONT_PASSENGERVIEW service type. int32[7]: Current state of REAR_PASSENGERVIEW service type."
},
{
+ "name": "PER_DISPLAY_MAX_BRIGHTNESS",
+ "value": 289476430,
+ "description": "Property to represent max brightness of the displays which are controlled separately.\nThis is only used if PER_DISPLAY_BRIGHTNESS is supported.\nThe display port uniquely identifies a physical connector on the device for display output, ranging from 0 to 255.\nint32Values[0] : display port number int32Values[1] : max brightness for display port number specified at int32Values[0] int32Values[2] : display port number int32Values[3] : max brightness for display port number specified at int32Values[2] ..."
+ },
+ {
"name": "AUTOMATIC_EMERGENCY_BRAKING_ENABLED",
"value": 287313920,
"description": "Enable or disable Automatic Emergency Braking (AEB).\nSet true to enable AEB and false to disable AEB. When AEB is enabled, the ADAS system in the vehicle should be turned on and monitoring to avoid potential collisions. This property should apply for higher speed applications only. For enabling low speed automatic emergency braking, LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED should be used.\nIn general, AUTOMATIC_EMERGENCY_BRAKING_ENABLED should always return true or false. If the feature is not available due to some temporary state, such as the vehicle speed being too low, that information must be conveyed through the ErrorState values in the AUTOMATIC_EMERGENCY_BRAKING_STATE property.\nThis property is defined as VehiclePropertyAccess.READ_WRITE, but OEMs have the option to implement it as VehiclePropertyAccess.READ only."
diff --git a/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
index 83043e5..7ff27a4 100644
--- a/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/3/cpp/Android.bp
@@ -24,4 +24,5 @@
local_include_dirs: ["."],
export_include_dirs: ["."],
defaults: ["VehicleHalInterfaceDefaults"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/4/cpp/AccessForVehicleProperty.h
index 51a3025..6d07fe5 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/AccessForVehicleProperty.h
@@ -263,6 +263,7 @@
{VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyAccess::WRITE},
{VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyAccess::READ},
{VehicleProperty::CAMERA_SERVICE_CURRENT_STATE, VehiclePropertyAccess::WRITE},
+ {VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess::READ},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess::READ},
{VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess::READ_WRITE},
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp b/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
index 6ece865..5bee849 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/Android.bp
@@ -24,6 +24,7 @@
local_include_dirs: ["."],
export_include_dirs: ["."],
defaults: ["VehicleHalInterfaceDefaults"],
+ host_supported: true,
}
cc_library_headers {
@@ -32,4 +33,5 @@
local_include_dirs: ["."],
export_include_dirs: ["."],
defaults: ["VehicleHalInterfaceDefaults"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
index 60e9a72..5ecee95 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/ChangeModeForVehicleProperty.h
@@ -263,6 +263,7 @@
{VehicleProperty::CLUSTER_HEARTBEAT, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::CAMERA_SERVICE_CURRENT_STATE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode::STATIC},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/4/cpp/VersionForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/4/cpp/VersionForVehicleProperty.h
index 0e80bd8..8b9c1bd 100644
--- a/automotive/vehicle/aidl/generated_lib/4/cpp/VersionForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/4/cpp/VersionForVehicleProperty.h
@@ -262,6 +262,7 @@
{VehicleProperty::CLUSTER_HEARTBEAT, 3},
{VehicleProperty::VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, 3},
{VehicleProperty::CAMERA_SERVICE_CURRENT_STATE, 3},
+ {VehicleProperty::PER_DISPLAY_MAX_BRIGHTNESS, 3},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED, 2},
{VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE, 2},
{VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED, 2},
diff --git a/automotive/vehicle/aidl/generated_lib/4/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/4/java/AccessForVehicleProperty.java
index afb6cab..e9f35a5 100644
--- a/automotive/vehicle/aidl/generated_lib/4/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/4/java/AccessForVehicleProperty.java
@@ -256,6 +256,7 @@
Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyAccess.WRITE),
Map.entry(VehicleProperty.VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.CAMERA_SERVICE_CURRENT_STATE, VehiclePropertyAccess.WRITE),
+ Map.entry(VehicleProperty.PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyAccess.READ_WRITE),
diff --git a/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
index 12aff40..3fb52b7 100644
--- a/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/4/java/ChangeModeForVehicleProperty.java
@@ -256,6 +256,7 @@
Map.entry(VehicleProperty.CLUSTER_HEARTBEAT, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.CAMERA_SERVICE_CURRENT_STATE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.PER_DISPLAY_MAX_BRIGHTNESS, VehiclePropertyChangeMode.STATIC),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.AUTOMATIC_EMERGENCY_BRAKING_STATE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.FORWARD_COLLISION_WARNING_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
index 0a33e5b..28c95ce 100644
--- a/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
+++ b/automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/Android.bp
@@ -49,6 +49,7 @@
],
cflags: ["-DENABLE_VEHICLE_HAL_TEST_PROPERTIES"],
shared_libs: ["libjsoncpp"],
+ host_supported: true,
}
cc_library_headers {
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/GeneratorHub/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
index ab223d3..a250a47 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/GeneratorHub/Android.bp
@@ -32,4 +32,5 @@
shared_libs: [
"libjsoncpp",
],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
index 5fc07c9..6030e15 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -37,6 +37,7 @@
whole_static_libs: [
"wakeup_client_protos",
],
+ host_supported: true,
}
cc_defaults {
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 644d1cd..79d3e77 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -184,7 +184,7 @@
std::unordered_set<int32_t> hvacPowerDependentProps;
const bool mForceOverride;
- bool mAddExtraTestVendorConfigs;
+ bool mAddExtraTestVendorConfigs = false;
// Only used during initialization.
JsonConfigLoader mLoader;
@@ -206,7 +206,7 @@
EXCLUDES(mLock);
// Load the config files in format '*.json' from the directory and parse the config files
// into a map from property ID to ConfigDeclarations.
- void loadPropConfigsFromDir(const std::string& dirPath,
+ bool loadPropConfigsFromDir(const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configs);
// Function to be called when a value change event comes from vehicle bus. In our fake
// implementation, this function is only called during "--inject-event" dump command.
@@ -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 c4bcdb3..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) {
@@ -363,7 +376,12 @@
std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
- loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+ bool defaultConfigLoaded = loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
+ if (!defaultConfigLoaded) {
+ // This cannot work without a valid default config.
+ ALOGE("Failed to load default config, exiting");
+ exit(1);
+ }
if (UseOverrideConfigDir()) {
loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
}
@@ -1765,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();
@@ -1843,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,
@@ -1860,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);
@@ -1870,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;
@@ -1906,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 = {};
@@ -2378,30 +2420,35 @@
(*mOnPropertyChangeCallback)(std::move(subscribedUpdatedValues));
}
-void FakeVehicleHardware::loadPropConfigsFromDir(
+bool FakeVehicleHardware::loadPropConfigsFromDir(
const std::string& dirPath,
std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
ALOGI("loading properties from %s", dirPath.c_str());
- if (auto dir = opendir(dirPath.c_str()); dir != NULL) {
- std::regex regJson(".*[.]json", std::regex::icase);
- while (auto f = readdir(dir)) {
- if (!std::regex_match(f->d_name, regJson)) {
- continue;
- }
- std::string filePath = dirPath + "/" + std::string(f->d_name);
- ALOGI("loading properties from %s", filePath.c_str());
- auto result = mLoader.loadPropConfig(filePath);
- if (!result.ok()) {
- ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
- result.error().message().c_str());
- continue;
- }
- for (auto& [propId, configDeclaration] : result.value()) {
- (*configsByPropId)[propId] = std::move(configDeclaration);
- }
- }
- closedir(dir);
+ auto dir = opendir(dirPath.c_str());
+ if (dir == nullptr) {
+ ALOGE("Failed to open config directory: %s", dirPath.c_str());
+ return false;
}
+
+ std::regex regJson(".*[.]json", std::regex::icase);
+ while (auto f = readdir(dir)) {
+ if (!std::regex_match(f->d_name, regJson)) {
+ continue;
+ }
+ std::string filePath = dirPath + "/" + std::string(f->d_name);
+ ALOGI("loading properties from %s", filePath.c_str());
+ auto result = mLoader.loadPropConfig(filePath);
+ if (!result.ok()) {
+ ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
+ result.error().message().c_str());
+ continue;
+ }
+ for (auto& [propId, configDeclaration] : result.value()) {
+ (*configsByPropId)[propId] = std::move(configDeclaration);
+ }
+ }
+ closedir(dir);
+ return true;
}
Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
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/fake_impl/obd2frame/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
index c1cee84..8fc7341 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/obd2frame/Android.bp
@@ -29,4 +29,5 @@
"VehicleHalUtils",
],
export_static_lib_headers: ["VehicleHalUtils"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
index 2e95531..181fd10 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
+++ b/automotive/vehicle/aidl/impl/fake_impl/userhal/Android.bp
@@ -29,4 +29,5 @@
"VehicleHalUtils",
],
export_static_lib_headers: ["VehicleHalUtils"],
+ host_supported: true,
}
diff --git a/automotive/vehicle/aidl/impl/grpc/Android.bp b/automotive/vehicle/aidl/impl/grpc/Android.bp
index e5106f8..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"],
}
@@ -127,4 +128,5 @@
cflags: [
"-Wno-unused-parameter",
],
+ host_supported: true,
}
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 52ef7be..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
@@ -39,25 +39,24 @@
],
defaults: ["VehicleHalDefaults"],
export_static_lib_headers: ["VehicleHalUtils"],
+ 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/hardware/Android.bp b/automotive/vehicle/aidl/impl/hardware/Android.bp
index edb0f29..52fd5e4 100644
--- a/automotive/vehicle/aidl/impl/hardware/Android.bp
+++ b/automotive/vehicle/aidl/impl/hardware/Android.bp
@@ -30,4 +30,5 @@
export_header_lib_headers: [
"VehicleHalUtilHeaders",
],
+ host_supported: true,
}
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/Android.bp b/automotive/vehicle/aidl/impl/utils/common/Android.bp
index e5d9346..5cd07b4 100644
--- a/automotive/vehicle/aidl/impl/utils/common/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/Android.bp
@@ -25,10 +25,12 @@
local_include_dirs: ["include"],
export_include_dirs: ["include"],
defaults: ["VehicleHalDefaults"],
+ host_supported: true,
}
cc_library_headers {
name: "VehicleHalUtilHeaders",
export_include_dirs: ["include"],
vendor: true,
+ host_supported: true,
}
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/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index 97efdf6..a7caeb1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -172,9 +172,7 @@
}
if (onValuesChangeCallback == nullptr && onValueChangeCallback == nullptr) {
- ALOGW("No callback registered, ignoring property update for propId: %" PRId32
- ", area ID: %" PRId32,
- propId, areaId);
+ // No callback registered.
return {};
}
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/automotive/vehicle/aidl_property/Android.bp b/automotive/vehicle/aidl_property/Android.bp
index bce2284..b8a978b 100644
--- a/automotive/vehicle/aidl_property/Android.bp
+++ b/automotive/vehicle/aidl_property/Android.bp
@@ -28,7 +28,7 @@
// This HAL was originally part of android.hardware.automotive.vehicle
"android/hardware/automotive/vehicle/*.aidl",
],
- frozen: true,
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
@@ -61,6 +61,7 @@
},
],
+ host_supported: true,
}
filegroup {
diff --git a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index be8d3ac..4c5dad2 100644
--- a/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/aidl_api/android.hardware.automotive.vehicle.property/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -262,6 +262,7 @@
CLUSTER_HEARTBEAT = (((0x0F4B + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.MIXED) /* 299896651 */,
VEHICLE_DRIVING_AUTOMATION_CURRENT_LEVEL = (((0x0F4C + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289410892 */,
CAMERA_SERVICE_CURRENT_STATE = (((0x0F4D + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 289476429 */,
+ PER_DISPLAY_MAX_BRIGHTNESS = (((0x0F4E + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32_VEC) /* 289476430 */,
AUTOMATIC_EMERGENCY_BRAKING_ENABLED = (((0x1000 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313920 */,
AUTOMATIC_EMERGENCY_BRAKING_STATE = (((0x1001 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.INT32) /* 289411073 */,
FORWARD_COLLISION_WARNING_ENABLED = (((0x1002 + android.hardware.automotive.vehicle.VehiclePropertyGroup.SYSTEM) + android.hardware.automotive.vehicle.VehicleArea.GLOBAL) + android.hardware.automotive.vehicle.VehiclePropertyType.BOOLEAN) /* 287313922 */,
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index ab8023d..0863adf 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -1734,8 +1734,13 @@
* change display brightness from Settings, but that must not be reflected
* to other displays.
*
+ * If this is writable, writing this property must cause an on property
+ * change event even if the new display brightness is the same as the
+ * current value.
+ *
* @change_mode VehiclePropertyChangeMode.ON_CHANGE
* @access VehiclePropertyAccess.READ_WRITE
+ * @access VehiclePropertyAccess.READ
* @version 2
*/
DISPLAY_BRIGHTNESS = 0x0A03 + 0x10000000 + 0x01000000
@@ -1752,9 +1757,24 @@
* implemented. If both are available, PER_DISPLAY_BRIGHTNESS is used by
* AAOS.
*
+ * If this is supported, PER_DISPLAY_MAX_BRIGHTNESS must be supported to represent the max
+ * display brightness for each display. Otherwise, the max display brightness is by default 1.
+ * The VehicleAreaConfig.maxInt32Value must not be used to represent max display brightness,
+ * because maxInt32Value is defined to be the max value for all the elements inside the integer
+ * value, which includes display port and brightness. So it is not meaningful.
+ *
* The display port uniquely identifies a physical connector on the device
* for display output, ranging from 0 to 255.
*
+ * Writing this property must cause an on property change event that
+ * contains the same [display port, brightness] tuple even if the new
+ * display brightness is the same as the current value.
+ *
+ * To get the display brightness for a specific display port, the
+ * GetValueRequest must contain a VehiclePropValue, which contains one
+ * int32Value: displayPort. Getting this property without specifying the
+ * the display port is undefined behavior.
+ *
* int32Values[0] : display port
* int32Values[1] : brightness
*
@@ -5200,6 +5220,27 @@
CAMERA_SERVICE_CURRENT_STATE = 0x0F4D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL
+ VehiclePropertyType.INT32_VEC,
+ /**
+ * Property to represent max brightness of the displays which are controlled separately.
+ *
+ * This is only used if PER_DISPLAY_BRIGHTNESS is supported.
+ *
+ * The display port uniquely identifies a physical connector on the device
+ * for display output, ranging from 0 to 255.
+ *
+ * int32Values[0] : display port number
+ * int32Values[1] : max brightness for display port number specified at int32Values[0]
+ * int32Values[2] : display port number
+ * int32Values[3] : max brightness for display port number specified at int32Values[2]
+ * ...
+ *
+ * @change_mode VehiclePropertyChangeMode.STATIC
+ * @access VehiclePropertyAccess.READ
+ * @version 3
+ */
+ PER_DISPLAY_MAX_BRIGHTNESS = 0x0F4E + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL
+ + VehiclePropertyType.INT32_VEC,
+
/***********************************************************************************************
* Start of ADAS Properties
*
diff --git a/automotive/vehicle/tools/translate_aidl_enums.py b/automotive/vehicle/tools/translate_aidl_enums.py
index d224f6f..a7c1808 100644
--- a/automotive/vehicle/tools/translate_aidl_enums.py
+++ b/automotive/vehicle/tools/translate_aidl_enums.py
@@ -110,7 +110,7 @@
import static com.google.common.truth.Truth.assertWithMessage;
-import android.test.suitebuilder.annotation.SmallTest;
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -228,4 +228,4 @@
f.write("".join(parser.outputMsgCtsTest))
if __name__ == "__main__":
- main()
\ No newline at end of file
+ main()
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 11de087..1f5742d 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -11,8 +11,8 @@
name: "android.hardware.common",
host_supported: true,
vendor_available: true,
+ product_available: true,
double_loadable: true,
- vndk_use_version: "2",
srcs: [
"android/hardware/common/*.aidl",
],
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 17c11ab..9c1b45d 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.common.fmq",
host_supported: true,
vendor_available: true,
+ product_available: true,
double_loadable: true,
srcs: [
"android/hardware/common/fmq/*.aidl",
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 12ab1f7..56700fa 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -10,6 +10,7 @@
cc_library_static {
name: "libaidlcommonsupport",
vendor_available: true,
+ product_available: true,
host_supported: true,
target: {
darwin: {
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/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 1f51d07..0e714a4 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -84,7 +84,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.automotive.vehicle</name>
- <version>1-3</version>
+ <version>1-4</version>
<interface>
<name>IVehicle</name>
<instance>default</instance>
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/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index d3842c5..da6116f 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -288,6 +288,20 @@
return false;
}
+ std::string printConfig(int config) {
+ const auto displayConfig = getDisplayConfig(config);
+ const auto vrrConfigOpt = displayConfig.vrrConfigOpt;
+ std::stringstream ss;
+ if (displayConfig.vrrConfigOpt) {
+ ss << "{Config " << config << ": vsyncPeriod " << displayConfig.vsyncPeriod
+ << ", minFrameIntervalNs " << vrrConfigOpt->minFrameIntervalNs << "}";
+ }
+ else {
+ ss << "{Config " << config << ": vsyncPeriod " << displayConfig.vsyncPeriod << "}";
+ }
+ return ss.str();
+ }
+
std::unordered_map<int32_t, DisplayConfig> getDisplayConfigs() { return mDisplayConfigs; }
private:
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/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 0227e39..ba15421 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -2877,8 +2877,9 @@
} while (--retryCount > 0);
if (retryCount == 0) {
- GTEST_FAIL() << "failed to get a callback for the display " << displayId
- << " with config " << config2;
+ GTEST_FAIL() << "Failed to get a callback for Display " << displayId
+ << " switching from " << display.printConfig(config1)
+ << " to " << display.printConfig(config2);
}
});
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/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
index 92ed1cd..9a7fe5e 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/ProtectCallback.h
@@ -56,6 +56,8 @@
// Thread safe class
class DeathMonitor final {
public:
+ explicit DeathMonitor(uintptr_t cookieKey) : kCookieKey(cookieKey) {}
+
static void serviceDied(void* cookie);
void serviceDied();
// Precondition: `killable` must be non-null.
@@ -63,9 +65,18 @@
// Precondition: `killable` must be non-null.
void remove(IProtectedCallback* killable) const;
+ uintptr_t getCookieKey() const { return kCookieKey; }
+
+ ~DeathMonitor();
+ DeathMonitor(const DeathMonitor&) = delete;
+ DeathMonitor(DeathMonitor&&) noexcept = delete;
+ DeathMonitor& operator=(const DeathMonitor&) = delete;
+ DeathMonitor& operator=(DeathMonitor&&) noexcept = delete;
+
private:
mutable std::mutex mMutex;
mutable std::vector<IProtectedCallback*> mObjects GUARDED_BY(mMutex);
+ const uintptr_t kCookieKey;
};
class DeathHandler final {
diff --git a/neuralnetworks/aidl/utils/src/ProtectCallback.cpp b/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
index 54a673c..4a7ac08 100644
--- a/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
+++ b/neuralnetworks/aidl/utils/src/ProtectCallback.cpp
@@ -25,6 +25,7 @@
#include <algorithm>
#include <functional>
+#include <map>
#include <memory>
#include <mutex>
#include <vector>
@@ -33,6 +34,16 @@
namespace aidl::android::hardware::neuralnetworks::utils {
+namespace {
+
+// Only dereference the cookie if it's valid (if it's in this set)
+// Only used with ndk
+std::mutex sCookiesMutex;
+uintptr_t sCookieKeyCounter GUARDED_BY(sCookiesMutex) = 0;
+std::map<uintptr_t, std::weak_ptr<DeathMonitor>> sCookies GUARDED_BY(sCookiesMutex);
+
+} // namespace
+
void DeathMonitor::serviceDied() {
std::lock_guard guard(mMutex);
std::for_each(mObjects.begin(), mObjects.end(),
@@ -40,8 +51,24 @@
}
void DeathMonitor::serviceDied(void* cookie) {
- auto deathMonitor = static_cast<DeathMonitor*>(cookie);
- deathMonitor->serviceDied();
+ std::shared_ptr<DeathMonitor> monitor;
+ {
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie)); it != sCookies.end()) {
+ monitor = it->second.lock();
+ sCookies.erase(it);
+ } else {
+ LOG(INFO)
+ << "Service died, but cookie is no longer valid so there is nothing to notify.";
+ return;
+ }
+ }
+ if (monitor) {
+ LOG(INFO) << "Notifying DeathMonitor from serviceDied.";
+ monitor->serviceDied();
+ } else {
+ LOG(INFO) << "Tried to notify DeathMonitor from serviceDied but could not promote.";
+ }
}
void DeathMonitor::add(IProtectedCallback* killable) const {
@@ -57,12 +84,25 @@
mObjects.erase(removedIter);
}
+DeathMonitor::~DeathMonitor() {
+ // lock must be taken so object is not used in OnBinderDied"
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ sCookies.erase(kCookieKey);
+}
+
nn::GeneralResult<DeathHandler> DeathHandler::create(std::shared_ptr<ndk::ICInterface> object) {
if (object == nullptr) {
return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
<< "utils::DeathHandler::create must have non-null object";
}
- auto deathMonitor = std::make_shared<DeathMonitor>();
+
+ std::shared_ptr<DeathMonitor> deathMonitor;
+ {
+ std::lock_guard<std::mutex> guard(sCookiesMutex);
+ deathMonitor = std::make_shared<DeathMonitor>(sCookieKeyCounter++);
+ sCookies[deathMonitor->getCookieKey()] = deathMonitor;
+ }
+
auto deathRecipient = ndk::ScopedAIBinder_DeathRecipient(
AIBinder_DeathRecipient_new(DeathMonitor::serviceDied));
@@ -70,8 +110,9 @@
// STATUS_INVALID_OPERATION. We ignore this case because we only use local binders in tests
// where this is not an error.
if (object->isRemote()) {
- const auto ret = ndk::ScopedAStatus::fromStatus(AIBinder_linkToDeath(
- object->asBinder().get(), deathRecipient.get(), deathMonitor.get()));
+ const auto ret = ndk::ScopedAStatus::fromStatus(
+ AIBinder_linkToDeath(object->asBinder().get(), deathRecipient.get(),
+ reinterpret_cast<void*>(deathMonitor->getCookieKey())));
HANDLE_ASTATUS(ret) << "AIBinder_linkToDeath failed";
}
@@ -91,8 +132,9 @@
DeathHandler::~DeathHandler() {
if (kObject != nullptr && kDeathRecipient.get() != nullptr && kDeathMonitor != nullptr) {
- const auto ret = ndk::ScopedAStatus::fromStatus(AIBinder_unlinkToDeath(
- kObject->asBinder().get(), kDeathRecipient.get(), kDeathMonitor.get()));
+ const auto ret = ndk::ScopedAStatus::fromStatus(
+ AIBinder_unlinkToDeath(kObject->asBinder().get(), kDeathRecipient.get(),
+ reinterpret_cast<void*>(kDeathMonitor->getCookieKey())));
const auto maybeSuccess = handleTransportError(ret);
if (!maybeSuccess.ok()) {
LOG(ERROR) << maybeSuccess.error().message;
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index 73727b3..ffd3b8e 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -697,7 +697,8 @@
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
const auto ret = [&device]() {
- DeathMonitor::serviceDied(device->getDeathMonitor());
+ DeathMonitor::serviceDied(
+ reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
return ndk::ScopedAStatus::ok();
};
EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
@@ -846,7 +847,8 @@
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
const auto ret = [&device]() {
- DeathMonitor::serviceDied(device->getDeathMonitor());
+ DeathMonitor::serviceDied(
+ reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
return ndk::ScopedAStatus::ok();
};
EXPECT_CALL(*mockDevice, prepareModelWithConfig(_, _, _))
@@ -970,7 +972,8 @@
const auto mockDevice = createMockDevice();
const auto device = Device::create(kName, mockDevice, kVersion).value();
const auto ret = [&device]() {
- DeathMonitor::serviceDied(device->getDeathMonitor());
+ DeathMonitor::serviceDied(
+ reinterpret_cast<void*>(device->getDeathMonitor()->getCookieKey()));
return ndk::ScopedAStatus::ok();
};
EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 3d3abe4..e4db40c 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -519,26 +519,38 @@
TEST_P(RadioHidlTest_v1_5, setSystemSelectionChannels_1_5) {
serial = GetRandomSerialNumber();
- ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands bandP900;
- bandP900.geranBands() = {GeranBands::BAND_P900};
- ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band850;
- band850.geranBands() = {GeranBands::BAND_850};
- ::android::hardware::radio::V1_5::RadioAccessSpecifier specifierP900 = {
- .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
- .bands = bandP900,
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band3;
+ band3.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_3});
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band17;
+ band17.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_17});
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band20;
+ band20.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_20});
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier::Bands band40;
+ band40.eutranBands({::android::hardware::radio::V1_5::EutranBands::BAND_40});
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier3 = {
+ .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+ .bands = band3,
.channels = {1, 2}};
- ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier850 = {
- .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::GERAN,
- .bands = band850,
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier17 = {
+ .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+ .bands = band17,
+ .channels = {1, 2}};
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier20 = {
+ .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+ .bands = band20,
+ .channels = {128, 129}};
+ ::android::hardware::radio::V1_5::RadioAccessSpecifier specifier40 = {
+ .radioAccessNetwork = ::android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN,
+ .bands = band40,
.channels = {128, 129}};
- Return<void> res =
- radio_v1_5->setSystemSelectionChannels_1_5(serial, true, {specifierP900, specifier850});
+ Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(
+ serial, true, {specifier3, specifier17, specifier20, specifier40});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+ ALOGI("setSystemSelectionChannels_1_5, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
@@ -547,12 +559,12 @@
if (radioRsp_v1_5->rspInfo.error == RadioError::NONE) {
serial = GetRandomSerialNumber();
Return<void> res = radio_v1_5->setSystemSelectionChannels_1_5(
- serial, false, {specifierP900, specifier850});
+ serial, false, {specifier3, specifier17, specifier20, specifier40});
ASSERT_OK(res);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- ALOGI("setSystemSelectionChannels, rspInfo.error = %s\n",
+ ALOGI("setSystemSelectionChannels_1_5, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
}
@@ -1190,11 +1202,12 @@
// can't camp on nonexistent MCCMNC, so we expect this to fail.
Return<void> res = radio_v1_5->setNetworkSelectionModeManual_1_5(
- serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::GERAN);
+ serial, "123456", android::hardware::radio::V1_5::RadioAccessNetworks::EUTRAN);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
-
+ ALOGI("setNetworkSelectionModeManual_1_5, rspInfo.error = %s\n",
+ toString(radioRsp_v1_5->rspInfo.error).c_str());
if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index d9eea03..b67e8e0 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -747,6 +747,7 @@
/**
* Response of isCellularIdentifierTransparencyEnabled.
+ * This is an optional API.
*
* @param info Response info struct containing response type, serial no. and error.
* @param isEnabled Indicates whether cellular identifier transparency is enabled or not.
@@ -757,12 +758,14 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void isCellularIdentifierTransparencyEnabledResponse(
in RadioResponseInfo info, boolean isEnabled);
/**
* Response of setCellularIdentifierTransparencyEnabled.
+ * This is an optional API.
*
* @param info Response info struct containing response type, serial no. and error.
*
@@ -773,11 +776,13 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:INVALID_STATE
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void setCellularIdentifierTransparencyEnabledResponse(in RadioResponseInfo info);
/**
* Response of setSecurityAlgorithmsUpdatedEnabled.
+ * This is an optional API.
*
* @param info Response info struct containing response type, serial no. and error.
*
@@ -788,11 +793,13 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:INVALID_STATE
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void setSecurityAlgorithmsUpdatedEnabledResponse(in RadioResponseInfo info);
/**
* Response of isSecurityAlgorithmsUpdatedEnabled.
+ * This is an optional API.
*
* @param info Response info struct containing response type, serial no. and error.
* @param isEnabled Indicates whether cellular ciphering transparency is enabled or not.
@@ -803,6 +810,7 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void isSecurityAlgorithmsUpdatedEnabledResponse(
in RadioResponseInfo info, in boolean isEnabled);
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/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index a98c0bf..b214401 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2459,9 +2459,9 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
}
TEST_P(RadioNetworkTest, setCellularIdentifierTransparencyEnabled) {
@@ -2490,9 +2490,9 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
// Assert the value has changed
serial = GetRandomSerialNumber();
@@ -2502,9 +2502,9 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
// Reset original state
@@ -2543,9 +2543,9 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
// Assert the value has changed
serial = GetRandomSerialNumber();
@@ -2555,9 +2555,9 @@
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
// Reset original state
@@ -2589,7 +2589,7 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
}
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 65a4645..527b5e0 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() && isSecondImeiIdAttestationRequired()) {
+ 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() && isSecondImeiIdAttestationRequired()) {
+ 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.
@@ -8917,13 +9003,6 @@
using aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase;
int main(int argc, char** argv) {
- std::cout << "Testing ";
- auto halInstances = KeyMintAidlTestBase::build_params();
- std::cout << "HAL instances:\n";
- for (auto& entry : halInstances) {
- std::cout << " " << entry << '\n';
- }
-
::testing::InitGoogleTest(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
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/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 2a8fd96..2dbc73f 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -188,9 +188,15 @@
}
ASSERT_NE(provisionable_, nullptr);
auto status = provisionable_->getHardwareInfo(&rpcHardwareInfo);
- if (GetParam() == RKP_VM_INSTANCE_NAME &&
- status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
- GTEST_SKIP() << "The RKP VM is not supported on this system.";
+ if (GetParam() == RKP_VM_INSTANCE_NAME) {
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "The RKP VM is not supported on this system.";
+ }
+ int apiLevel = get_vsr_api_level();
+ if (apiLevel < __ANDROID_API_V__) {
+ GTEST_SKIP() << "The RKP VM is supported only on V+ devices. Vendor API level: "
+ << apiLevel;
+ }
}
ASSERT_TRUE(status.isOk());
}
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/threadnetwork/aidl/default/main.cpp b/threadnetwork/aidl/default/main.cpp
index 26683bf..6514184 100644
--- a/threadnetwork/aidl/default/main.cpp
+++ b/threadnetwork/aidl/default/main.cpp
@@ -18,7 +18,11 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <netinet/in.h>
+#include <net/if.h>
#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <sys/stat.h>
#include "service.hpp"
#include "thread_chip.hpp"
@@ -26,6 +30,8 @@
using aidl::android::hardware::threadnetwork::IThreadChip;
using aidl::android::hardware::threadnetwork::ThreadChip;
+#define THREADNETWORK_COPROCESSOR_SIMULATION_PATH "/apex/com.android.hardware.threadnetwork/bin/ot-rcp"
+
namespace {
void addThreadChip(int id, const char* url) {
binder_status_t status;
@@ -41,14 +47,36 @@
status = AServiceManager_addService(threadChip->asBinder().get(), serviceName.c_str());
CHECK_EQ(status, STATUS_OK);
}
+
+void addSimulatedThreadChip() {
+ char local_interface[PROP_VALUE_MAX];
+
+ CHECK_GT(property_get("persist.vendor.otsim.local_interface",
+ local_interface, "eth1"), 0);
+
+ int node_id = property_get_int32("ro.boot.openthread_node_id", 0);
+ CHECK_GT(node_id,0);
+
+ std::string url = std::string("spinel+hdlc+forkpty://" \
+ THREADNETWORK_COPROCESSOR_SIMULATION_PATH "?forkpty-arg=-L") \
+ + local_interface + "&forkpty-arg=" + std::to_string(node_id);
+ addThreadChip(0, url.c_str());
+}
}
int main(int argc, char* argv[]) {
- CHECK_GT(argc, 1);
aidl::android::hardware::threadnetwork::Service service;
- for (int id = 0; id < argc - 1; id++) {
- addThreadChip(id, argv[id + 1]);
+ if (argc > 1) {
+ for (int id = 0; id < argc - 1; id++) {
+ addThreadChip(id, argv[id + 1]);
+ }
+ } else {
+ struct stat sb;
+
+ CHECK_EQ(stat(THREADNETWORK_COPROCESSOR_SIMULATION_PATH, &sb), 0);
+ CHECK(sb.st_mode & S_IXUSR);
+ addSimulatedThreadChip();
}
ALOGI("Thread Network HAL is running");
diff --git a/threadnetwork/aidl/default/threadnetwork-service.rc b/threadnetwork/aidl/default/threadnetwork-service.rc
index 3b889eb..a2ac0f7 100644
--- a/threadnetwork/aidl/default/threadnetwork-service.rc
+++ b/threadnetwork/aidl/default/threadnetwork-service.rc
@@ -1,3 +1,3 @@
-service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1
+service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service
class hal
user thread_network
diff --git a/tv/Android.mk b/tv/Android.mk
deleted file mode 100644
index d78614a..0000000
--- a/tv/Android.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_0.xml))
-$(eval $(call declare-1p-copy-files,hardware/interfaces/tv,tuner_vts_config_1_1.xml))
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 491a79b..6cabb3d 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -31,11 +31,7 @@
bool initConfiguration() {
std::array<char, PROPERTY_VALUE_MAX> variant;
- auto res = property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
- if (res <= 0) {
- ALOGE("[vts] failed to read system property ro.vendor.vts_tuner_configuration_variant");
- return false;
- }
+ property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
string configFilePath = "/vendor/etc/tuner_vts_config_aidl_V1";
if (variant.size() != 0) {
configFilePath = configFilePath + "." + variant.data();
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,