Merge tag 'android-13.0.0_r32' into int/13/fp3
Android 13.0.0 release 32
* tag 'android-13.0.0_r32':
audio HAL: Optimize for Spatial Audio
Avoid holding lock while calling recurrent actions.
audio HAL: set minimum Binder access priority
Add additional bounds checks to NNAPI FMQ deserialize utility functions
Add additional bounds checks to NNAPI FMQ deserialize utility functions
Add additional bounds checks to NNAPI FMQ deserialize utility functions
Add additional bounds checks to NNAPI FMQ deserialize utility functions
Add additional bounds checks to NNAPI FMQ deserialize utility functions
audio HAL: Enable RT priority inheritance
Update Cuttlefish mock GNSS hardware model name
Add BluetoothLeAudioCodecsProvider Unit Test
EffectHal: Support retrieving worker thread tid
DO NOT MERGE Add missing seat memory properties to DefaultConfig.h for CTS tests
Change-Id: I324d2e040bad5d770511ff35f922c83d434051c7
diff --git a/audio/common/all-versions/default/service/android.hardware.audio.service.rc b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
index 45fef9a..0de4eea 100644
--- a/audio/common/all-versions/default/service/android.hardware.audio.service.rc
+++ b/audio/common/all-versions/default/service/android.hardware.audio.service.rc
@@ -3,7 +3,9 @@
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct wakelock context_hub
- capabilities BLOCK_SUSPEND
+ capabilities BLOCK_SUSPEND SYS_NICE
+ # setting RLIMIT_RTPRIO allows binder RT priority inheritance
+ rlimit rtprio 10 10
ioprio rt 4
task_profiles ProcessCapacityHigh HighPerformance
onrestart restart audioserver
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index b954fcd..d03118a 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -30,6 +30,7 @@
#include <algorithm>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <mediautils/MemoryLeakTrackUtil.h>
#include <memunreachable/memunreachable.h>
@@ -183,6 +184,7 @@
if (status == OK) {
streamOut = new StreamOut(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamOut, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, false /*isInput*/, suggestedConfig);
@@ -220,6 +222,7 @@
if (status == OK) {
streamIn = new StreamIn(this, halStream);
++mOpenedStreamsCount;
+ android::hardware::setMinSchedulerPolicy(streamIn, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
status_t convertStatus =
HidlUtils::audioConfigFromHal(halConfig, true /*isInput*/, suggestedConfig);
diff --git a/audio/core/all-versions/default/DevicesFactory.cpp b/audio/core/all-versions/default/DevicesFactory.cpp
index f44daf0..011f9ac 100644
--- a/audio/core/all-versions/default/DevicesFactory.cpp
+++ b/audio/core/all-versions/default/DevicesFactory.cpp
@@ -23,6 +23,8 @@
#include <string.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
+#include <system/thread_defs.h>
namespace android {
namespace hardware {
@@ -103,6 +105,7 @@
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
result = new DeviceShim(halDevice);
+ android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
retval = Result::OK;
} else if (halStatus == -EINVAL) {
retval = Result::NOT_INITIALIZED;
diff --git a/audio/effect/all-versions/default/Effect.cpp b/audio/effect/all-versions/default/Effect.cpp
index 5dc42dc..87e1ab7 100644
--- a/audio/effect/all-versions/default/Effect.cpp
+++ b/audio/effect/all-versions/default/Effect.cpp
@@ -25,8 +25,11 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include <HidlUtils.h>
#include <android/log.h>
+#include <cutils/properties.h>
#include <media/EffectsFactoryApi.h>
#include <mediautils/ScopedStatistics.h>
+#include <sys/syscall.h>
+#include <system/audio_effects/effect_spatializer.h>
#include <util/EffectUtils.h>
#include <utils/Trace.h>
@@ -47,6 +50,160 @@
namespace {
+/**
+ * Some basic scheduling tools.
+ */
+namespace scheduler {
+
+int getCpu() {
+ return sched_getcpu();
+}
+
+uint64_t getAffinity(pid_t tid) {
+ cpu_set_t set;
+ CPU_ZERO_S(sizeof(set), &set);
+
+ if (sched_getaffinity(tid, sizeof(set), &set)) {
+ ALOGW("%s: for tid:%d returning 0, failed %s", __func__, tid, strerror(errno));
+ return 0;
+ }
+ const int count = CPU_COUNT_S(sizeof(set), &set);
+ uint64_t mask = 0;
+ for (int i = 0; i < CPU_SETSIZE; ++i) {
+ if (CPU_ISSET_S(i, sizeof(set), &set)) {
+ mask |= 1 << i;
+ }
+ }
+ ALOGV("%s: for tid:%d returning cpu count %d mask %llu", __func__, tid, count,
+ (unsigned long long)mask);
+ return mask;
+}
+
+status_t setAffinity(pid_t tid, uint64_t mask) {
+ cpu_set_t set;
+ CPU_ZERO_S(sizeof(set), &set);
+
+ for (uint64_t m = mask; m != 0;) {
+ uint64_t tz = __builtin_ctz(m);
+ CPU_SET_S(tz, sizeof(set), &set);
+ m &= ~(1 << tz);
+ }
+ if (sched_setaffinity(tid, sizeof(set), &set)) {
+ ALOGW("%s: for tid:%d setting cpu mask %llu failed %s", __func__, tid,
+ (unsigned long long)mask, strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: for tid:%d setting cpu mask %llu", __func__, tid, (unsigned long long)mask);
+ return OK;
+}
+
+__unused status_t setPriority(pid_t tid, int policy, int priority) {
+ struct sched_param param {
+ .sched_priority = priority,
+ };
+ if (sched_setscheduler(tid, policy, ¶m) != 0) {
+ ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d priority %d %s", __func__, tid,
+ policy, priority, strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: Successfully set priority for tid %d to policy %d priority %d", __func__, tid,
+ policy, priority);
+ return NO_ERROR;
+}
+
+status_t setUtilMin(pid_t tid, uint32_t utilMin) {
+ // Currently, there is no wrapper in bionic: b/183240349.
+ struct {
+ uint32_t size;
+ uint32_t sched_policy;
+ uint64_t sched_flags;
+ int32_t sched_nice;
+ uint32_t sched_priority;
+ uint64_t sched_runtime;
+ uint64_t sched_deadline;
+ uint64_t sched_period;
+ uint32_t sched_util_min;
+ uint32_t sched_util_max;
+ } attr{
+ .size = sizeof(attr),
+ .sched_flags = SCHED_FLAG_KEEP_ALL | SCHED_FLAG_UTIL_CLAMP_MIN,
+ .sched_util_min = utilMin,
+ };
+
+ if (syscall(__NR_sched_setattr, tid, &attr, 0 /* flags */)) {
+ ALOGW("%s: Cannot set sched_util_min for pid %d to %u %s", __func__, tid, utilMin,
+ strerror(errno));
+ return -errno;
+ }
+ ALOGV("%s: Successfully set sched_util_min for pid %d to %u", __func__, tid, utilMin);
+ return NO_ERROR;
+}
+
+/*
+ Attempts to raise the priority and usage of tid for spatialization.
+ Returns OK if everything works.
+*/
+status_t updateSpatializerPriority(pid_t tid) {
+ status_t status = OK;
+
+ const int cpu = getCpu();
+ ALOGV("%s: current CPU:%d", __func__, cpu);
+
+ const auto currentAffinity = getAffinity(tid);
+ ALOGV("%s: current Affinity:%llx", __func__, (unsigned long long)currentAffinity);
+
+ // Set the desired CPU core affinity.
+ // Typically this would be done to move the Spatializer effect off of the little cores.
+ // The mid cores and large cores typically have more FP/NEON units
+ // and will advantageously reduce power and prevent glitches due CPU limitations.
+ //
+ // Since this is SOC dependent, we do not set the core affinity here but
+ // prefer to set the util_clamp_min below.
+ //
+ constexpr uint64_t kDefaultAffinity = 0;
+ const int32_t desiredAffinity =
+ property_get_int32("audio.spatializer.effect.affinity", kDefaultAffinity);
+ if (desiredAffinity != 0 && (desiredAffinity & ~currentAffinity) == 0) {
+ const status_t localStatus = setAffinity(tid, desiredAffinity);
+ status = status ? status : localStatus;
+ }
+
+ // Set the util_clamp_min.
+ // This is beneficial to reduce glitches when starting up, or due to scheduler
+ // thread statistics reset (e.g. core migration), which cause the CPU frequency to drop
+ // to minimum.
+ //
+ // Experimentation has found that moving to a mid core over a little core reduces
+ // power if the mid core (e.g. A76/78) has more (e.g. 2x) FP/NEON units
+ // than the little core (e.g. A55).
+ // A possible value is 300.
+ //
+ constexpr uint32_t kUtilMin = 0;
+ const int32_t utilMin = property_get_int32("audio.spatializer.effect.util_clamp_min", kUtilMin);
+ if (utilMin > 0 && utilMin <= 1024) {
+ const status_t localStatus = setUtilMin(tid, utilMin);
+ status = status ? status : localStatus;
+ }
+
+#if 0
+ // Provided for local vendor testing but not enabled as audioserver does this for us.
+ //
+ // Set priority if specified.
+ constexpr int32_t kRTPriorityMin = 1;
+ constexpr int32_t kRTPriorityMax = 3;
+ const int32_t priorityBoost =
+ property_get_int32("audio.spatializer.priority", kRTPriorityMin);
+ if (priorityBoost >= kRTPriorityMin && priorityBoost <= kRTPriorityMax) {
+ const status_t localStatus = scheduler::setPriority(threadId, SCHED_FIFO, priorityBoost);
+ status = status ? status : localStatus;
+ }
+#endif
+
+ return status;
+}
+
+} // namespace scheduler
+
#define SCOPED_STATS() \
::android::mediautils::ScopedStatistics scopedStatistics { \
std::string("EffectHal::").append(__func__), mEffectHal->mStatistics \
@@ -83,6 +240,16 @@
};
bool ProcessThread::threadLoop() {
+ // For a spatializer effect, we perform scheduler adjustments to reduce glitches and power.
+ {
+ effect_descriptor_t halDescriptor{};
+ if ((*mEffect)->get_descriptor(mEffect, &halDescriptor) == NO_ERROR &&
+ memcmp(&halDescriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) {
+ const status_t status = scheduler::updateSpatializerPriority(gettid());
+ ALOGW_IF(status != OK, "Failed to update Spatializer priority");
+ }
+ }
+
// This implementation doesn't return control back to the Thread until it decides to stop,
// as the Thread uses mutexes, and this can lead to priority inversion.
while (!std::atomic_load_explicit(mStop, std::memory_order_acquire)) {
diff --git a/audio/effect/all-versions/default/EffectsFactory.cpp b/audio/effect/all-versions/default/EffectsFactory.cpp
index e93ad89..9bf309c 100644
--- a/audio/effect/all-versions/default/EffectsFactory.cpp
+++ b/audio/effect/all-versions/default/EffectsFactory.cpp
@@ -32,6 +32,7 @@
#include <UuidUtils.h>
#include <android/log.h>
+#include <hidl/HidlTransportSupport.h>
#include <media/EffectsFactoryApi.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_agc.h>
@@ -44,6 +45,7 @@
#include <system/audio_effects/effect_presetreverb.h>
#include <system/audio_effects/effect_virtualizer.h>
#include <system/audio_effects/effect_visualizer.h>
+#include <system/thread_defs.h>
#include <util/EffectUtils.h>
namespace android {
@@ -189,6 +191,7 @@
status = (*handle)->get_descriptor(handle, &halDescriptor);
if (status == OK) {
effect = dispatchEffectInstanceCreation(halDescriptor, handle);
+ android::hardware::setMinSchedulerPolicy(effect, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
effectId = EffectMap::getInstance().add(handle);
} else {
ALOGE("Error querying effect descriptor for %s: %s",
diff --git a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
index 9a93e1a..622846a 100644
--- a/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
+++ b/automotive/vehicle/aidl/impl/default_config/include/DefaultConfig.h
@@ -190,6 +190,40 @@
},
.initialValue = {.int32Values = {toInt(VehicleUnit::KILOWATT_HOUR)}}},
+ {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SELECT),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3}}},
+ .initialValue = {.int32Values = {1}}},
+
+ {.config = {.prop = toInt(VehicleProperty::SEAT_MEMORY_SET),
+ .access = VehiclePropertyAccess::WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs = {VehicleAreaConfig{.areaId = SEAT_1_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_1_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_2_LEFT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3},
+ VehicleAreaConfig{.areaId = SEAT_2_RIGHT,
+ .minInt32Value = 0,
+ .maxInt32Value = 3}}},
+ .initialValue = {.int32Values = {1}}},
+
{.config = {.prop = toInt(VehicleProperty::SEAT_BELT_BUCKLED),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
index 5f0f716..cd2b727 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/RecurrentTimer.h
@@ -83,8 +83,9 @@
// each time we might introduce outdated elements to the top. We must make sure the heap is
// always valid from the top.
void removeInvalidCallbackLocked() REQUIRES(mLock);
- // Pops the next closest callback (must be valid) from the heap.
- std::unique_ptr<CallbackInfo> popNextCallbackLocked() REQUIRES(mLock);
+ // Gets the next calblack to run (must be valid) from the heap, update its nextTime and put
+ // it back to the heap.
+ std::shared_ptr<Callback> getNextCallbackLocked(int64_t now) REQUIRES(mLock);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
index 2eca6b7..908564c 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/RecurrentTimer.cpp
@@ -101,68 +101,71 @@
}
}
-std::unique_ptr<RecurrentTimer::CallbackInfo> RecurrentTimer::popNextCallbackLocked() {
+std::shared_ptr<RecurrentTimer::Callback> RecurrentTimer::getNextCallbackLocked(int64_t now) {
std::pop_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
- std::unique_ptr<CallbackInfo> info = std::move(mCallbackQueue[mCallbackQueue.size() - 1]);
- mCallbackQueue.pop_back();
+ auto& callbackInfo = mCallbackQueue[mCallbackQueue.size() - 1];
+ auto nextCallback = callbackInfo->callback;
+ // intervalCount is the number of interval we have to advance until we pass now.
+ size_t intervalCount = (now - callbackInfo->nextTime) / callbackInfo->interval + 1;
+ callbackInfo->nextTime += intervalCount * callbackInfo->interval;
+ std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
+
// Make sure the first element is always valid.
removeInvalidCallbackLocked();
- return info;
+
+ return nextCallback;
}
void RecurrentTimer::loop() {
- std::unique_lock<std::mutex> uniqueLock(mLock);
-
+ std::vector<std::shared_ptr<Callback>> callbacksToRun;
while (true) {
- // Wait until the timer exits or we have at least one recurrent callback.
- mCond.wait(uniqueLock, [this] {
- ScopedLockAssertion lockAssertion(mLock);
- return mStopRequested || mCallbackQueue.size() != 0;
- });
-
- int64_t interval;
{
+ std::unique_lock<std::mutex> uniqueLock(mLock);
ScopedLockAssertion lockAssertion(mLock);
+ // Wait until the timer exits or we have at least one recurrent callback.
+ mCond.wait(uniqueLock, [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested || mCallbackQueue.size() != 0;
+ });
+
+ int64_t interval;
if (mStopRequested) {
return;
}
// The first element is the nearest next event.
int64_t nextTime = mCallbackQueue[0]->nextTime;
int64_t now = uptimeNanos();
+
if (nextTime > now) {
interval = nextTime - now;
} else {
interval = 0;
}
- }
- // Wait for the next event or the timer exits.
- if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
- ScopedLockAssertion lockAssertion(mLock);
- return mStopRequested;
- })) {
- return;
- }
+ // Wait for the next event or the timer exits.
+ if (mCond.wait_for(uniqueLock, std::chrono::nanoseconds(interval), [this] {
+ ScopedLockAssertion lockAssertion(mLock);
+ return mStopRequested;
+ })) {
+ return;
+ }
- {
- ScopedLockAssertion lockAssertion(mLock);
- int64_t now = uptimeNanos();
+ now = uptimeNanos();
+ callbacksToRun.clear();
while (mCallbackQueue.size() > 0) {
int64_t nextTime = mCallbackQueue[0]->nextTime;
if (nextTime > now) {
break;
}
- std::unique_ptr<CallbackInfo> info = popNextCallbackLocked();
- info->nextTime += info->interval;
-
- auto callback = info->callback;
- mCallbackQueue.push_back(std::move(info));
- std::push_heap(mCallbackQueue.begin(), mCallbackQueue.end(), CallbackInfo::cmp);
-
- (*callback)();
+ callbacksToRun.push_back(getNextCallbackLocked(now));
}
}
+
+ // Do not execute the callback while holding the lock.
+ for (size_t i = 0; i < callbacksToRun.size(); i++) {
+ (*callbacksToRun[i])();
+ }
}
}
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index a033a24..141efc1 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -186,6 +186,33 @@
ASSERT_EQ(countTimerCallbackQueue(&timer), static_cast<size_t>(0));
}
+TEST_F(RecurrentTimerTest, testRegisterCallbackMultipleTimesNoDeadLock) {
+ // We want to avoid the following situation:
+ // Caller holds a lock while calling registerTimerCallback, registerTimerCallback will try
+ // to obtain an internal lock inside timer.
+ // Meanwhile an recurrent action happens with timer holding an internal lock. The action
+ // tries to obtain the lock currently hold by the caller.
+ // The solution is that while calling recurrent actions, timer must not hold the internal lock.
+
+ std::unique_ptr<RecurrentTimer> timer = std::make_unique<RecurrentTimer>();
+ std::mutex lock;
+ for (size_t i = 0; i < 1000; i++) {
+ std::scoped_lock<std::mutex> lockGuard(lock);
+ auto action = std::make_shared<RecurrentTimer::Callback>([&lock] {
+ // While calling this function, the timer must not hold lock in order not to dead
+ // lock.
+ std::scoped_lock<std::mutex> lockGuard(lock);
+ });
+ // 10ms
+ int64_t interval = 10'000'000;
+ timer->registerTimerCallback(interval, action);
+ // Sleep for a little while to let the recurrent actions begin.
+ std::this_thread::sleep_for(std::chrono::milliseconds(1));
+ }
+ // Make sure we stop the timer before we destroy lock.
+ timer.reset();
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/bluetooth/audio/utils/Android.bp b/bluetooth/audio/utils/Android.bp
index 674dd11..70797a7 100644
--- a/bluetooth/audio/utils/Android.bp
+++ b/bluetooth/audio/utils/Android.bp
@@ -63,6 +63,31 @@
generated_headers: ["le_audio_codec_capabilities"],
}
+cc_test {
+ name: "BluetoothLeAudioCodecsProviderTest",
+ srcs: [
+ "aidl_session/BluetoothLeAudioCodecsProvider.cpp",
+ "aidl_session/BluetoothLeAudioCodecsProviderTest.cpp",
+ ],
+ header_libs: [
+ "libxsdc-utils",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "android.hardware.bluetooth.audio-V2-ndk",
+ "libxml2",
+ ],
+ test_suites: [
+ "general-tests",
+ ],
+ test_options: {
+ unit_test: false,
+ },
+ generated_sources: ["le_audio_codec_capabilities"],
+ generated_headers: ["le_audio_codec_capabilities"],
+}
+
xsd_config {
name: "le_audio_codec_capabilities",
srcs: ["le_audio_codec_capabilities/le_audio_codec_capabilities.xsd"],
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
index 855dd28..faebbbf 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothAudioCodecs.cpp
@@ -398,8 +398,11 @@
}
if (kDefaultOffloadLeAudioCapabilities.empty()) {
+ auto le_audio_offload_setting =
+ BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile();
kDefaultOffloadLeAudioCapabilities =
- BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities();
+ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ le_audio_offload_setting);
}
return kDefaultOffloadLeAudioCapabilities;
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index bf49270..1dec900 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -34,20 +34,40 @@
static std::vector<LeAudioCodecCapabilitiesSetting> leAudioCodecCapabilities;
-std::vector<LeAudioCodecCapabilitiesSetting>
-BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities() {
- if (!leAudioCodecCapabilities.empty()) {
- return leAudioCodecCapabilities;
- }
+static bool isInvalidFileContent = false;
- const auto le_audio_offload_setting =
+std::optional<setting::LeAudioOffloadSetting>
+BluetoothLeAudioCodecsProvider::ParseFromLeAudioOffloadSettingFile() {
+ if (!leAudioCodecCapabilities.empty() || isInvalidFileContent) {
+ return std::nullopt;
+ }
+ auto le_audio_offload_setting =
setting::readLeAudioOffloadSetting(kLeAudioCodecCapabilitiesFile);
if (!le_audio_offload_setting.has_value()) {
LOG(ERROR) << __func__ << ": Failed to read "
<< kLeAudioCodecCapabilitiesFile;
+ }
+ return le_audio_offload_setting;
+}
+
+std::vector<LeAudioCodecCapabilitiesSetting>
+BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting) {
+ if (!leAudioCodecCapabilities.empty()) {
+ return leAudioCodecCapabilities;
+ }
+
+ if (!le_audio_offload_setting.has_value()) {
+ LOG(ERROR)
+ << __func__
+ << ": input le_audio_offload_setting content need to be non empty";
return {};
}
+ ClearLeAudioCodecCapabilities();
+ isInvalidFileContent = true;
+
std::vector<setting::Scenario> supported_scenarios =
GetScenarios(le_audio_offload_setting);
if (supported_scenarios.empty()) {
@@ -79,9 +99,18 @@
leAudioCodecCapabilities =
ComposeLeAudioCodecCapabilities(supported_scenarios);
+ isInvalidFileContent = leAudioCodecCapabilities.empty();
+
return leAudioCodecCapabilities;
}
+void BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities() {
+ leAudioCodecCapabilities.clear();
+ configuration_map_.clear();
+ codec_configuration_map_.clear();
+ strategy_configuration_map_.clear();
+}
+
std::vector<setting::Scenario> BluetoothLeAudioCodecsProvider::GetScenarios(
const std::optional<setting::LeAudioOffloadSetting>&
le_audio_offload_setting) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index 402235f..e879984 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -31,8 +31,13 @@
class BluetoothLeAudioCodecsProvider {
public:
+ static std::optional<setting::LeAudioOffloadSetting>
+ ParseFromLeAudioOffloadSettingFile();
static std::vector<LeAudioCodecCapabilitiesSetting>
- GetLeAudioCodecCapabilities();
+ GetLeAudioCodecCapabilities(
+ const std::optional<setting::LeAudioOffloadSetting>&
+ le_audio_offload_setting);
+ static void ClearLeAudioCodecCapabilities();
private:
static inline std::unordered_map<std::string, setting::Configuration>
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
new file mode 100644
index 0000000..5393cd7
--- /dev/null
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2022 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 <gtest/gtest.h>
+
+#include <optional>
+#include <tuple>
+
+#include "BluetoothLeAudioCodecsProvider.h"
+
+using aidl::android::hardware::bluetooth::audio::BluetoothLeAudioCodecsProvider;
+using aidl::android::hardware::bluetooth::audio::
+ LeAudioCodecCapabilitiesSetting;
+using aidl::android::hardware::bluetooth::audio::setting::AudioLocation;
+using aidl::android::hardware::bluetooth::audio::setting::CodecConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+ CodecConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::CodecType;
+using aidl::android::hardware::bluetooth::audio::setting::Configuration;
+using aidl::android::hardware::bluetooth::audio::setting::ConfigurationList;
+using aidl::android::hardware::bluetooth::audio::setting::LeAudioOffloadSetting;
+using aidl::android::hardware::bluetooth::audio::setting::Scenario;
+using aidl::android::hardware::bluetooth::audio::setting::ScenarioList;
+using aidl::android::hardware::bluetooth::audio::setting::StrategyConfiguration;
+using aidl::android::hardware::bluetooth::audio::setting::
+ StrategyConfigurationList;
+
+typedef std::tuple<std::vector<ScenarioList>, std::vector<ConfigurationList>,
+ std::vector<CodecConfigurationList>,
+ std::vector<StrategyConfigurationList>>
+ OffloadSetting;
+
+// Define valid components for each list
+// Scenario
+static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
+ std::make_optional("OneChanStereo_16_1"));
+// Configuration
+static const Configuration kValidConfigOneChanStereo_16_1(
+ std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"));
+// CodecConfiguration
+static const CodecConfiguration kValidCodecLC3_16k_1(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt);
+// StrategyConfiguration
+static const StrategyConfiguration kValidStrategyStereoOneCis(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::make_optional(2),
+ std::make_optional(1));
+static const StrategyConfiguration kValidStrategyStereoTwoCis(
+ std::make_optional("STEREO_TWO_CISES_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::make_optional(1),
+ std::make_optional(2));
+static const StrategyConfiguration kValidStrategyMonoOneCis(
+ std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::MONO), std::make_optional(1),
+ std::make_optional(1));
+
+// Define valid test list built from above valid components
+// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
+static const std::vector<ScenarioList> kValidScenarioList = {
+ ScenarioList(std::vector<Scenario>{kValidScenario})};
+static const std::vector<ConfigurationList> kValidConfigurationList = {
+ ConfigurationList(
+ std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
+static const std::vector<CodecConfigurationList> kValidCodecConfigurationList =
+ {CodecConfigurationList(
+ std::vector<CodecConfiguration>{kValidCodecLC3_16k_1})};
+static const std::vector<StrategyConfigurationList>
+ kValidStrategyConfigurationList = {
+ StrategyConfigurationList(std::vector<StrategyConfiguration>{
+ kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
+ kValidStrategyMonoOneCis})};
+
+class BluetoothLeAudioCodecsProviderTest
+ : public ::testing::TestWithParam<OffloadSetting> {
+ public:
+ static std::vector<OffloadSetting> CreateTestCases(
+ const std::vector<ScenarioList>& scenario_lists,
+ const std::vector<ConfigurationList>& configuration_lists,
+ const std::vector<CodecConfigurationList>& codec_configuration_lists,
+ const std::vector<StrategyConfigurationList>&
+ strategy_configuration_lists) {
+ // make each vector in output test_cases has only one element
+ // to match the input of test params
+ // normally only one vector in input has multiple elements
+ // we just split elements in this vector to several vector
+ std::vector<OffloadSetting> test_cases;
+ for (const auto& scenario_list : scenario_lists) {
+ for (const auto& configuration_list : configuration_lists) {
+ for (const auto& codec_configuration_list : codec_configuration_lists) {
+ for (const auto& strategy_configuration_list :
+ strategy_configuration_lists) {
+ test_cases.push_back(CreateTestCase(
+ scenario_list, configuration_list, codec_configuration_list,
+ strategy_configuration_list));
+ }
+ }
+ }
+ }
+ return test_cases;
+ }
+
+ protected:
+ void Initialize() {
+ BluetoothLeAudioCodecsProvider::ClearLeAudioCodecCapabilities();
+ }
+
+ std::vector<LeAudioCodecCapabilitiesSetting> RunTestCase() {
+ auto& [scenario_lists, configuration_lists, codec_configuration_lists,
+ strategy_configuration_lists] = GetParam();
+ LeAudioOffloadSetting le_audio_offload_setting(
+ scenario_lists, configuration_lists, codec_configuration_lists,
+ strategy_configuration_lists);
+ auto le_audio_codec_capabilities =
+ BluetoothLeAudioCodecsProvider::GetLeAudioCodecCapabilities(
+ std::make_optional(le_audio_offload_setting));
+ return le_audio_codec_capabilities;
+ }
+
+ private:
+ static inline OffloadSetting CreateTestCase(
+ const ScenarioList& scenario_list,
+ const ConfigurationList& configuration_list,
+ const CodecConfigurationList& codec_configuration_list,
+ const StrategyConfigurationList& strategy_configuration_list) {
+ return std::make_tuple(
+ std::vector<ScenarioList>{scenario_list},
+ std::vector<ConfigurationList>{configuration_list},
+ std::vector<CodecConfigurationList>{codec_configuration_list},
+ std::vector<StrategyConfigurationList>{strategy_configuration_list});
+ }
+};
+
+class GetScenariosTest : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<ScenarioList> CreateInvalidScenarios() {
+ std::vector<ScenarioList> invalid_scenario_test_cases;
+ invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+ Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));
+
+ invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+ Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));
+
+ invalid_scenario_test_cases.push_back(ScenarioList(
+ std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));
+
+ invalid_scenario_test_cases.push_back(
+ ScenarioList(std::vector<Scenario>{}));
+
+ return invalid_scenario_test_cases;
+ }
+};
+
+TEST_P(GetScenariosTest, InvalidScenarios) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<ConfigurationList> CreateInvalidConfigurations() {
+ std::vector<ConfigurationList> invalid_configuration_test_cases;
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{
+ Configuration(std::nullopt, std::make_optional("LC3_16k_1"),
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{Configuration(
+ std::make_optional("OneChanStereo_16_1"), std::nullopt,
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"))}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{
+ Configuration(std::make_optional("OneChanStereo_16_1"),
+ std::make_optional("LC3_16k_1"), std::nullopt)}));
+
+ invalid_configuration_test_cases.push_back(
+ ConfigurationList(std::vector<Configuration>{}));
+
+ return invalid_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateConfigurationsToMapTest, InvalidConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateCodecConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<CodecConfigurationList>
+ CreateInvalidCodecConfigurations() {
+ std::vector<CodecConfigurationList> invalid_codec_configuration_test_cases;
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::nullopt, std::make_optional(CodecType::LC3), std::nullopt,
+ std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::nullopt, std::nullopt,
+ std::make_optional(16000), std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::nullopt, std::make_optional(7500),
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::nullopt,
+ std::make_optional(30), std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(CodecConfigurationList(
+ std::vector<CodecConfiguration>{CodecConfiguration(
+ std::make_optional("LC3_16k_1"), std::make_optional(CodecType::LC3),
+ std::nullopt, std::make_optional(16000), std::make_optional(7500),
+ std::nullopt, std::nullopt)}));
+
+ invalid_codec_configuration_test_cases.push_back(
+ CodecConfigurationList(std::vector<CodecConfiguration>{}));
+
+ return invalid_codec_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateCodecConfigurationsToMapTest, InvalidCodecConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class UpdateStrategyConfigurationsToMapTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+ static std::vector<StrategyConfigurationList>
+ CreateInvalidStrategyConfigurations() {
+ std::vector<StrategyConfigurationList>
+ invalid_strategy_configuration_test_cases;
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(2))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(2))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::nullopt, std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"), std::nullopt,
+ std::make_optional(2), std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO), std::nullopt,
+ std::make_optional(1))}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(
+ std::vector<StrategyConfiguration>{StrategyConfiguration(
+ std::make_optional("STEREO_ONE_CIS_PER_DEVICE"),
+ std::make_optional(AudioLocation::STEREO),
+ std::make_optional(2), std::nullopt)}));
+
+ invalid_strategy_configuration_test_cases.push_back(
+ StrategyConfigurationList(std::vector<StrategyConfiguration>{}));
+
+ return invalid_strategy_configuration_test_cases;
+ }
+};
+
+TEST_P(UpdateStrategyConfigurationsToMapTest, InvalidStrategyConfigurations) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(le_audio_codec_capabilities.empty());
+}
+
+class ComposeLeAudioCodecCapabilitiesTest
+ : public BluetoothLeAudioCodecsProviderTest {
+ public:
+};
+
+TEST_P(ComposeLeAudioCodecCapabilitiesTest, CodecCapabilitiesNotEmpty) {
+ Initialize();
+ auto le_audio_codec_capabilities = RunTestCase();
+ ASSERT_TRUE(!le_audio_codec_capabilities.empty());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GetScenariosTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, GetScenariosTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ GetScenariosTest::CreateInvalidScenarios(), kValidConfigurationList,
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UpdateConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList,
+ UpdateConfigurationsToMapTest::CreateInvalidConfigurations(),
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ UpdateCodecConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateCodecConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ UpdateCodecConfigurationsToMapTest::CreateInvalidCodecConfigurations(),
+ kValidStrategyConfigurationList)));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ UpdateStrategyConfigurationsToMapTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, UpdateStrategyConfigurationsToMapTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ kValidCodecConfigurationList,
+ UpdateStrategyConfigurationsToMapTest::
+ CreateInvalidStrategyConfigurations())));
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(
+ ComposeLeAudioCodecCapabilitiesTest);
+INSTANTIATE_TEST_SUITE_P(
+ BluetoothLeAudioCodecsProviderTest, ComposeLeAudioCodecCapabilitiesTest,
+ ::testing::ValuesIn(BluetoothLeAudioCodecsProviderTest::CreateTestCases(
+ kValidScenarioList, kValidConfigurationList,
+ kValidCodecConfigurationList, kValidStrategyConfigurationList)));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index cf2c90d..2d6490c 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -68,7 +68,7 @@
IGnssCallback::GnssSystemInfo systemInfo = {
.yearOfHw = 2022,
- .name = "Google Mock GNSS Implementation AIDL v2",
+ .name = "Google, Cuttlefish, AIDL v2",
};
status = sGnssCallback->gnssSetSystemInfoCb(systemInfo);
if (!status.isOk()) {