【车载Audio】【AudioHal 03】【深入解析 Android 音频策略:onNewAudioModulesAvailableInt 的全链路探索】

深入解析 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 源码全貌与关键点注解

c 复制代码
 /**
  * 函数背景:
  * 此函数是 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 呼叫外界执行动作的"手臂"。

详细调用链可参考:

核心路径总结:

  1. APM 调用 mpClientInterface->loadHwModule
  2. AudioPolicyService 转发请求给 AudioFlinger
  3. AudioFlinger 最终触发 mDevicesFactoryHal->openDevice(name, &dev)
  4. HIDL 接口 :调用 factory->openPrimaryDevice 跨进程进入 audio.hal 服务进程。

4. 服务端实现:Audio HAL 如何 handle openPrimaryDevice

core/all-versions/default/DevicesFactory.cpp 中,我们能看到 HAL 层的具体响应:

c 复制代码
#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

c 复制代码
// 厂商实现的入口符号
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. 总结:系统启动时的"蝴蝶效应"

通过上述源码解析,我们可以清晰地勾勒出音频设备"从无到有"的演进全链路:

  1. 解析期 :APM 解析 audio_policy_configuration.xml,心中有了"蓝图"(mHwModulesAll)。
  2. 指令期 :APM 调用 loadHwModule 发出加载指令。
  3. 穿梭期:信号跨越 APS -> AF -> HIDL -> HAL 服务进程。
  4. 激活期 :底层调用 adev_open,高通 Init 启动 PAL 引擎。
  5. 验证期 :APM 通过"试开流"(outputDesc->open)确认链路可用。
  6. 注册期 :设备正式加入 mAvailableOutputDevices,从此 Android 系统的状态栏和设置界面才真正"认识"了这些硬件。

这种"静态配置 + 跨进程指令 + 动态链路验证"的设计,保证了 Android 音频系统在复杂硬件拓扑下的极高健壮性。

相关推荐
hinewcc1 小时前
Android SELinux权限
android
CrystalShaw2 小时前
节前最后一天mark:Perfetto
android
奔跑吧 android2 小时前
【车载Audio】【AudioHal 04】【高通音频架构】【从 AHAL adev_open 到 PAL XML 解析:30微秒内的调用链深度追踪】
音视频·audiohal·车载audio·高通音频架构·ahal·audiofinger
我命由我123452 小时前
Kotlin 面向对象 - 匿名内部类、匿名内部类简化
android·java·开发语言·java-ee·kotlin·android studio·android jetpack
catchadmin2 小时前
“Fatal error: require(): Failed opening required...” 以及如何彻底避免它再次出现
android·ide·android studio
城东米粉儿2 小时前
Android WindowManageService 笔记
android
城东米粉儿2 小时前
Android InputChannel socket 笔记
android
城东米粉儿2 小时前
Android View体系 笔记
android
城东米粉儿3 小时前
Android Messenger 笔记
android