【车载Audio】【AudioHal 03】【深入解析 Android 音频策略:onNewAudioModulesAvailableInt 的全链路探索】
Android音频策略管理器中的onNewAudioModulesAvailableInt函数负责将XML配置转化为可用的音频资源。该函数首先扫描预定义硬件模块,通过AudioFlinger加载厂商HAL库(如audio.primary.xxx.so),然后对输出能力进行探测,包括采样率、格式等参数验证。核心流程包含两个关键阶段:1)物理链路试开流,通过AudioFlinger的openOutpu
深入解析 Android 音频策略:onNewAudioModulesAvailableInt 的全链路探索
请先阅读 AudioFlinger 与 Audio HAL 的“握手”及硬件发现全链路
1. 核心流程总览:从扫描到激活
在 Android 音频策略管理器(AudioPolicyManager)中,onNewAudioModulesAvailableInt 是一个承上启下的核心函数。它的核心任务是将 XML 配置文件中的“静态描述”转化为系统中“动态可用”的音频资源。
本分析基于以下环境日志:log路径: /home/leo/data_4t/debug/03.work/26-02_09--02_14/test_audio_channel/log/android/logcat.log
2. 核心源码级深度解析:onNewAudioModulesAvailableInt
如果您对 mHwModulesAll 的初始加载过程尚不熟悉,建议先阅读前置文章:
2.1 源码全貌与关键点注解
/**
* 函数背景:
* 此函数是 Android 音频策略管理器的“拓扑扫描仪”。
* 它的核心任务是扫描系统所有预定义的音频硬件模块,并驱动 HAL 完成加载。
*/
void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
{
// 遍历从 XML 解析出的全量硬件模块列表
for (const auto& hwModule : mHwModulesAll) {
// 去重检查:防止重复加载已激活的模块
if (std::find(mHwModules.begin(), mHwModules.end(), hwModule) != mHwModules.end()) {
continue;
}
/**
* 【重点分析点 1:驱动加载入口】
* 逻辑:通过 mpClientInterface (即 AudioPolicyService) 通知 AudioFlinger。
* 动作:AudioFlinger 执行 dlopen 加载厂商的 audio.primary.xxx.so 库。
*/
hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
// 容错处理:如果 HAL 库加载失败,则跳过该模块
if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
ALOGW("could not open HW module %s", hwModule->getName());
continue;
}
// 将加载成功的模块加入活跃列表
mHwModules.push_back(hwModule);
/**
* 阶段一:输出能力探测 (Output Profiles)。
* 遍历每一个 mixPort,验证其支持的采样率、格式等是否能真正被底层接收。
*/
for (const auto& outProfile : hwModule->getOutputProfiles()) {
ALOGV("%s: Intializing output profile(mixport): %s", __func__, (outProfile->getTagName()).c_str());
// 检查并发上限 (maxOpenCount)
if (!outProfile->canOpenNewIo()) {
ALOGE("Invalid Output profile max open count %u for profile %s",
outProfile->maxOpenCount, outProfile->getTagName().c_str());
continue;
}
// 检查是否有关联的物理设备
if (!outProfile->hasSupportedDevices()) {
ALOGW("Output profile contains no device on module %s", hwModule->getName());
continue;
}
// TTS/超声波能力特殊标记
if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0 ||
(outProfile->getFlags() & AUDIO_OUTPUT_FLAG_ULTRASOUND) != 0) {
mTtsOutputAvailable = true;
}
// 筛选当前通路支持且在系统全量设备表中的设备
const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
DeviceVector availProfileDevices = supportedDevices.filter(mOutputDevicesAll);
sp<DeviceDescriptor> supportedDevice = 0;
// 优先选择默认输出设备进行“开流测试”
if (supportedDevices.contains(mDefaultOutputDevice)) {
supportedDevice = mDefaultOutputDevice;
} else {
if (availProfileDevices.isEmpty()) {
continue;
}
supportedDevice = availProfileDevices.itemAt(0);
}
if (!mOutputDevicesAll.contains(supportedDevice)) {
continue;
}
/**
* 【重点分析点 2:物理链路试开流】
* 目的:真正去调用 AudioFlinger 的 openOutput 接口。
* 意义:只有底层 HAL 成功返回 OK,系统才认为这条硬件通路是真实的、可用的。
*/
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = outputDesc->open(nullptr /* halConfig */, nullptr /* mixerConfig */,
DeviceVector(supportedDevice),
AUDIO_STREAM_DEFAULT,
AUDIO_OUTPUT_FLAG_NONE, &output);
// 如果底层物理链路打不开(如 DSP 还没准备好),则跳过此通路
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for devices %s on hw module %s",
supportedDevice->toString().c_str(), hwModule->getName());
continue;
}
/**
* 阶段二:设备激活与挂载。
* 只有开流成功的通路,其关联的设备才会被加入到 mAvailableOutputDevices 中。
*/
for (const auto &device : availProfileDevices) {
if (!device->isAttached()) {
device->attach(hwModule); // 建立模块绑定关系
mAvailableOutputDevices.add(device); // 加入可用设备池
device->setEncapsulationInfoFromHal(mpClientInterface);
if (newDevices) newDevices->add(device);
// 通知路由引擎 (Engine):新设备已上线,可以参与路由决策了
setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
}
}
// 确立系统的“主输出”地位
if (mPrimaryOutput == nullptr &&
outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
}
/**
* 阶段三:资源动态优化。
* DIRECT 通路验证完即关(省电),普通混合通路保持开启(提升响应速度)。
*/
if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
outputDesc->close();
} else {
addOutput(output, outputDesc);
// 设置初始路由
setOutputDevices(outputDesc,
DeviceVector(supportedDevice),
true,
0,
NULL);
}
}
/**
* 阶段四:输入能力探测 (Input Profiles)。
* 逻辑与输出侧镜像,重点验证麦克风等输入通道。
*/
for (const auto& inProfile : hwModule->getInputProfiles()) {
if (!inProfile->canOpenNewIo()) {
continue;
}
if (!inProfile->hasSupportedDevices()) {
continue;
}
const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
DeviceVector availProfileDevices = supportedDevices.filter(mInputDevicesAll);
if (availProfileDevices.isEmpty()) {
continue;
}
sp<AudioInputDescriptor> inputDesc =
new AudioInputDescriptor(inProfile, mpClientInterface);
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
// 试开录音流
status_t status = inputDesc->open(nullptr,
availProfileDevices.itemAt(0),
AUDIO_SOURCE_MIC,
AUDIO_INPUT_FLAG_NONE,
&input);
if (status != NO_ERROR) {
continue;
}
for (const auto &device : availProfileDevices) {
if (!device->isAttached()) {
device->attach(hwModule);
device->importAudioPortAndPickAudioProfile(inProfile, true);
mAvailableInputDevices.add(device);
if (newDevices) newDevices->add(device);
setEngineDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_AVAILABLE);
}
}
// 录音流验证完立即关闭
inputDesc->close();
}
}
/**
* 阶段五:空间音频 (Spatializer) 策略检查。
*/
std::vector<audio_io_handle_t> outputsClosed;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if ((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0
&& !isOutputOnlyAvailableRouteToSomeDevice(desc)) {
outputsClosed.push_back(desc->mIoHandle);
desc->close();
}
}
for (auto output : outputsClosed) {
removeOutput(output);
}
}
3. 跨进程的奥秘:mpClientInterface->loadHwModule
loadHwModule 是 APM 呼叫外界执行动作的“手臂”。
详细调用链可参考:
核心路径总结:
- APM 调用
mpClientInterface->loadHwModule。 - AudioPolicyService 转发请求给 AudioFlinger。
- AudioFlinger 最终触发
mDevicesFactoryHal->openDevice(name, &dev)。 - HIDL 接口:调用
factory->openPrimaryDevice跨进程进入audio.hal服务进程。
4. 服务端实现:Audio HAL 如何 handle openPrimaryDevice
在 core/all-versions/default/DevicesFactory.cpp 中,我们能看到 HAL 层的具体响应:
#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
// 响应 HIDL 请求:打开主音频设备
Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
return openDevice<PrimaryDevice>(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
}
Return<void> DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
audio_hw_device_t* halDevice;
Result retval(Result::INVALID_ARGUMENTS);
sp<DeviceShim> result;
// 1. 加载真正的底层 .so 驱动接口
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
// 2. 将原始 C 风格的 halDevice 包装成 HIDL 对象 DeviceShim
result = new DeviceShim(halDevice);
// 设置音频线程的调度策略为实时(ANDROID_PRIORITY_AUDIO)
android::hardware::setMinSchedulerPolicy(result, SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
retval = Result::OK;
}
// ...
_hidl_cb(retval, result); // 通过回调将结果返回给客户端
return Void();
}
int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
const hw_module_t* mod;
int rc;
// A. 加载硬件模块描述符
rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
// B. 调用厂商实现的 open 方法(即 adev_open)
rc = audio_hw_device_open(mod, dev);
// ...
return OK;
}
5. 厂商的具体实现:以高通 PAL 为例
在高通的方案中,audio_hw_device_open 最终会调到 hal-pal/AudioDevice.cpp 中的 adev_open。
// 厂商实现的入口符号
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.methods = &hal_module_methods, // 挂载方法表
},
};
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open, // HAL 框架调用这里的 open
};
static int adev_open(const hw_module_t *module, const char *name __unused,
hw_device_t **device) {
// ...
// 1. 获取 AudioDevice 单例
std::shared_ptr<AudioDevice> adevice = AudioDevice::GetInstance();
// 2. 引用计数管理:如果已经初始化过,直接返回现有实例
adevice->adev_init_mutex.lock();
if (adevice->adev_init_ref_count != 0) {
*device = adevice->GetAudioDeviceCommon();
adevice->adev_init_ref_count++;
adevice->adev_init_mutex.unlock();
return 0;
}
// 3. 核心初始化:这是 AHAL 与底层 PAL 引擎握手的关键
ret = adevice->Init(device, module);
// ...
adevice->adev_init_mutex.unlock();
return 0;
}
6. 总结:系统启动时的“蝴蝶效应”
通过上述源码解析,我们可以清晰地勾勒出音频设备“从无到有”的演进全链路:
- 解析期:APM 解析
audio_policy_configuration.xml,心中有了“蓝图”(mHwModulesAll)。 - 指令期:APM 调用
loadHwModule发出加载指令。 - 穿梭期:信号跨越 APS -> AF -> HIDL -> HAL 服务进程。
- 激活期:底层调用
adev_open,高通Init启动 PAL 引擎。 - 验证期:APM 通过“试开流”(
outputDesc->open)确认链路可用。 - 注册期:设备正式加入
mAvailableOutputDevices,从此 Android 系统的状态栏和设置界面才真正“认识”了这些硬件。
这种“静态配置 + 跨进程指令 + 动态链路验证”的设计,保证了 Android 音频系统在复杂硬件拓扑下的极高健壮性。
更多推荐



所有评论(0)