好的,我们接着深入探讨 audioserver 中的另一位核心成员——AudioPolicyService。它与 AudioFlinger 相辅相成,共同构成了 Android 音频系统的中枢。
🧭 角色定位:音频系统的“决策中心”
如果说 AudioFlinger 是“执行者”,负责音频数据的实际搬运与处理,那么 AudioPolicyService 就是“决策者”,负责回答三个核心问题:
- 何时、何地 播放或录制?
- 使用哪个设备(扬声器、耳机、蓝牙等)?
- 各个音频流之间如何协调(谁可以出声、音量多大)?
它不接触音频数据本身,而是制定规则并下达指令,指挥 AudioFlinger 和硬件抽象层(HAL)完成具体工作。
🚀 启动与架构
AudioPolicyService 同样运行在 audioserver 进程中,由 main_audioserver.cpp 在启动 AudioFlinger 之后创建并注册到 ServiceManager。
其核心组件结构如下:
AudioPolicyService (Binder 服务端)
└── AudioPolicyManager (主要实现逻辑)
├── Engine (策略引擎,解析配置、执行路由算法)
├── HwModuleCollection (管理音频硬件模块)
├── DeviceManager (管理可用设备及连接状态)
└── Output/Input 管理 (跟踪当前打开的所有音频流)
- AudioPolicyManager:策略的核心实现类(位于
services/audiopolicy/engine/)。 - Engine:可插拔的策略算法模块,不同产品(手机、汽车、电视)可替换引擎实现。
- HAL 接口:通过
Device HAL(IDevicesFactory等)获取可用的音频硬件模块(如 primary、a2dp、usb 等)。
📋 核心职责详解
1. 音频路由策略
根据当前系统状态(如通话中、媒体播放)和设备连接情况(有线耳机、蓝牙、HDMI 等),动态决定音频数据的输入/输出设备。
- 输出路由:例如媒体音乐通常优先输出到有线耳机,如果未连接则走扬声器。
- 输入路由:通话时使用主麦克风,录音时可能使用前麦克风或 USB 麦克风。
- 策略强制使用(
setForceUse):例如在车载模式下,强制所有音频输出到蓝牙或 AUX。
2. 音量管理
- 音量曲线:为每种流类型(媒体、闹钟、通话音量等)定义从静音到最大音量的非线性曲线(响度单位)。
- 音量步长:系统 UI 按下音量键时增加/减少的步进值。
- 音量限制:可配置最大音量、安全音量(如欧盟对耳机的限制)。
- 音量组:某些设备共享同一音量索引(如媒体和导航)。
3. 音频焦点管理(Audio Focus)
注:焦点管理的逻辑主要在 Java 层的
AudioService中实现,但 AudioPolicyService 负责执行焦点变化引起的底层策略调整,例如对失去焦点的流进行“闪避”(ducking)。
- 当应用申请或放弃焦点时,
AudioService会通过 Binder 调用 AudioPolicyService 的notifyAudioFocusChange()。 - AudioPolicyService 据此决定是否降低其他流的音量(闪避)、暂停播放等。
4. 动态策略与配置
- 静态配置文件:
/vendor/etc/audio_policy_configuration.xml(或.conf)定义了系统中的所有音频硬件模块、设备端口、混音端口、路由规则等。 - 动态策略:支持运行时加载新的策略模块(例如插入 USB 声卡时动态添加对应的路由)。
5. 输入/输出流管理
- 当应用通过
AudioTrack请求播放时,AudioService最终会调用 AudioPolicyService 的getOutputForAttr()。 - AudioPolicyService 根据属性(流类型、用途、采样率、标志位等)选择或创建一个合适的输出流句柄(
audio_io_handle_t),并通知 AudioFlinger 打开对应的输出线程。 - 同样,录音时会调用
getInputForAttr()。
🔄 与 AudioFlinger 的协作流程
AudioPolicyService 不直接操作硬件,所有实际工作都通过 AudioFlinger 完成。典型协作模式:
- 上层请求播放:应用调用
AudioTrack→AudioSystem(native) →AudioPolicyService::getOutputForAttr()。 - 策略决策:AudioPolicyService 根据请求的属性(例如
USAGE_MEDIA)和设备状态,决定应该使用哪个输出设备(如扬声器)。 - 通知 AudioFlinger:调用
AudioFlinger::openOutput()获取对应设备上的输出流,并返回audio_io_handle_t。 - 后续控制:当设备切换(如插入耳机),AudioPolicyService 会调用
AudioFlinger::closeOutput()关闭原流,再openOutput()打开新流,并触发 AudioFlinger 内部的线程切换,保证音频连续(无缝切换)。
🧪 典型工作流程示例:插入有线耳机
- 硬件事件:内核检测到耳机插入,通过
uevent上报。 - HAL 通知:音频 HAL 服务(如
audio.primary)调用AudioPolicyService::setDeviceConnectionState()。 - 策略重新评估:AudioPolicyService 运行
Engine::updateDeviceSelection(),根据策略规则(如媒体音乐优先输出到有线耳机)决定将当前播放的媒体流切换到耳机。 - 执行切换:
- 调用
AudioFlinger::closeOutput()关闭扬声器输出线程。 - 调用
AudioFlinger::openOutput()打开耳机输出线程。 - 如果有正在播放的
AudioTrack,AudioFlinger 会将其重新路由到新线程(通常通过线程切换或重新创建 Track)。
- 调用
- 上层通知:通过回调通知
AudioService(Java 层),后者发送广播(ACTION_HEADSET_PLUG),应用可据此调整 UI。
📄 配置文件详解
audio_policy_configuration.xml 是策略的“宪法”。典型结构:
<audioPolicyConfiguration>
<globalConfiguration speaker_drc_enabled="false"/>
<modules>
<module name="primary" halVersion="3.0">
<attachedDevices>
<item>Speaker</item>
<item>Built-In Mic</item>
</attachedDevices>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>
<!-- 其他设备端口 -->
</devicePorts>
<mixPorts>
<mixPort name="primary output" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
</mixPorts>
<routes>
<route type="mix" sink="Speaker" sources="primary output"/>
<!-- 其他路由规则 -->
</routes>
</module>
<!-- 其他模块:a2dp、usb 等 -->
</modules>
</audioPolicyConfiguration>
- devicePorts:描述物理设备(扬声器、麦克风、耳机插孔等)。
- mixPorts:描述软件混音端口(即 AudioFlinger 中的输出线程)。
- routes:定义哪些混音端口可以路由到哪些设备端口。
厂商可以修改此文件来定制路由行为(例如插入耳机后是否同时让扬声器发声,用于外放+耳机双模式)。
🎛️ 主要 Binder 接口(供 AudioService 调用)
| 方法 | 用途 |
|---|---|
setDeviceConnectionState | HAL 或系统服务通知设备连接/断开 |
setPhoneState | 设置电话状态(通话中、空闲、来电等),影响路由策略 |
setForceUse | 强制使用特定场景(如车载、HDMI 等) |
getOutputForAttr | 请求一个输出流句柄用于播放 |
releaseOutput | 释放输出流 |
getInputForAttr | 请求一个输入流句柄用于录音 |
startOutput/stopOutput | 通知策略服务某个流开始/停止使用(用于动态路由优化) |
setVolumeIndex | 设置某流类型的音量索引 |
🔒 安全与权限
- 运行在
audioserver用户组,拥有读取配置文件的权限。 - Binder 调用会检查调用者的
android.permission.MODIFY_AUDIO_SETTINGS等权限。 - 对于录音相关的策略(如
getInputForAttr),会额外检查RECORD_AUDIO权限。
🧩 版本演进要点
- Android 8.0 (Treble):将音频 HAL 与 AudioPolicyService 解耦,通过 HIDL 通信;策略引擎可独立升级。
- Android 10:引入
AudioPolicyEngine接口,支持完全自定义策略逻辑。 - Android 13+:部分接口转为 AIDL,但核心架构不变。
💎 总结
| 对比项 | AudioFlinger | AudioPolicyService |
|---|---|---|
| 核心角色 | 执行者(数据平面) | 决策者(控制平面) |
| 处理对象 | 音频数据 | 策略与事件 |
| 关键操作 | 混音、读写 HAL、效果处理 | 路由选择、设备切换、音量策略 |
| 运行线程 | 多个播放/录制线程(高负载) | 少量控制线程(低负载) |
| 依赖 HAL | 直接调用 StreamOut/In | 调用 Device HAL 获取信息 |
| 配置方式 | 硬编码 + 参数传递 | 配置文件 + 可替换引擎 |
AudioPolicyService 是 Android 音频系统灵活性和可定制性的基石。它使得手机、汽车、电视等不同形态的设备可以共享同一套音频框架,只需修改策略配置或引擎即可实现差异化的音频行为。理解 AudioPolicyService,是进行音频路由调试、音量曲线定制、多设备场景开发的关键。