Android Audio子系统之Parameter-Framework详解

0 阅读15分钟

摘要:本文深入解析 Android Audio 系统中 Parameter-Framework(PFW)的实现原理与运行时机制。从程序模块关系出发,逐步拆解 AudioPolicyEngine 初始化、PFW 配置加载(ElementLibrary、Subsystem 插件、参数结构树、Domain 配置)的完整流程,并以 UsbHeadset 设备接入和录音请求路由两个场景为例,串联展示 PFW 如何通过 SelectionCriterion → ConfigurableDomain → AreaConfiguration → Blackboard → Syncer 的链路实现数据驱动的策略决策。全文以源码调用栈、PlantUML 类图和内存布局图辅助说明,适合有一定 Android Audio 底层基础的读者。

提示:建议在浏览器中打开原文链接,即可无损缩放查看文中 PlantUML 类图的细节。

1. 程序模块关系

pfw程序模块关系.png

程序模块简介

  • AudioPolicyManager (libaudiopolicymanagerdefault.so): Android 音频系统的策略中心,负责管理音频设备连接状态、处理音频路由请求并控制音量策略。

  • AudioPolicyEngine (libaudiopolicyengineconfigurable.so): AudioPolicyManager 内部的核心决策模块,根据当前系统状态(如设备连接情况、强制使用配置),通过 parameter-framework 读取 XML 配置来动态决定路由、音量、设备选择等策略。其核心特点是行为由数据驱动

  • parameter-framework (libparameter.so): 参数管理与配置框架,提供一套层级化的参数结构(域、子系统、准则等),支持从 XML 加载配置、运行时参数变更与插件式扩展。在此它被用作 AudioPolicyEngine 的策略配置后端

  • libpolicy-subsystem.so: 策略子系统插件,用于扩展 parameter-framework 的策略能力。它动态注册到 parameter-framework 中,提供具体的策略逻辑实现(如 InputSource 路由规则)。本质上是一个可插拔的策略行为库

2. 初始化流程

AudioPolicyManager::initialize()
│
│   //init_1: AudioPolicyEngine 库的选择和加载
├── engLib = EngineLibrary::load()
│
│    //init_2: 创建 AudioPolicyEngine 实例
├── mEngine = engLib->createEngine()
│   └── Engine::Engine()
│       │
│       │   //init_2.1: 创建 CParameterMgr 实例
│       ├── new ParameterManagerWrapper()
│       │   │   //strConfigurationFilePath :PFW 配置文件路径
│       │   └── new CParameterMgrPlatformConnector(strConfigurationFilePath)
│       │       └── new CParameterMgr(strConfigurationFilePath)
│       │
│       │   //init_2.2: 加载配置文件创建 CSelectionCriterionType 实例
│       │   //  和 CSelectionCriterion 实例
│       └── Engine::loadAudioPolicyEngineConfig()
│           ├── EngineBase::loadAudioPolicyEngineConfig()
│           └── ParameterManagerWrapper::addCriterion()
│               ├── CParameterMgr::createSelectionCriterionType()
│               │   //遍历 ValuePairs
│               ├── CSelectionCriterionType::addValuePair()
│               └── CParameterMgr::createSelectionCriterion()
│
│   // init_3. 加载 PFW 配置文件
└── mEngine->initCheck()
    └── ParameterManagerWrapper::start()
        └── CParameterMgrPlatformConnector::start()
            └── CParameterMgr::load()

主要工作:

  1. 加载 AudioPolicyEngine 库
  2. 创建 AudioPolicyEngine 实例
    • 2.1: 创建 CParameterMgr 实例
    • 2.2: 加载配置文件,创建 CSelectionCriterionType 和 CSelectionCriterion 实例
  3. 加载 PFW 配置文件

PFW 初始化过程中会加载多种配置文件,理解这些配置内容在程序中的实例化方式,对掌握 PFW 很有帮助。

2.1. AudioPolicyEngine 库的选择和加载

在 AOSP 源码中,AudioPolicyEngine 有两个实现库:libaudiopolicyengineconfigurable.so 和 libaudiopolicyenginedefault.so。选用哪个取决于 audioPolicyConfiguration 配置,例如: /odm/etc/audio/audio_policy_configuration_a2dp_offload_disabled.xml

<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->

    <!-- Global configuration Decalaration -->
    <globalConfiguration speaker_drc_enabled="false" engine_library="configurable" call_screen_mode_supported="true" />
</audioPolicyConfiguration>

配置文件里的 engine_library="configurable" 指定 AudioPolicyEngine 拼接为 libaudiopolicyengine + configurable + .so = libaudiopolicyengineconfigurable.so

代码逻辑

Step 1: 加载配置 frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

AudioPolicyManager::AudioPolicyManager()
    ↓
AudioPolicyManager::loadConfig()
    loadConfig()
    └─ deserializeAudioPolicyXmlConfig()
       │  // 获取配置文件路径,如
       │  // /odm/etc/audio/audio_policy_configuration_a2dp_offload_disabled.xml
       ├─ audio_get_audio_policy_config_file()
       │  // 解析 XML,构建 AudioPolicyConfig 实例
       └─ deserializeAudioPolicyFile()

最终设置 AudioPolicyConfig.mEngineLibraryNameSuffix = "configurable"

Step 2: 加载 AudioPolicyEngine 库 frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

status_t AudioPolicyManager::initialize() {
    {
        auto engLib = EngineLibrary::load(
                        "libaudiopolicyengine" + getConfig().getEngineLibraryNameSuffix() + ".so");

        mEngine = engLib->createEngine();
    }
}

将 "libaudiopolicyengine" 与 AudioPolicyConfig.mEngineLibraryNameSuffix 的值拼接为文件名,然后加载 .so 文件并创建 Engine 实例。

2.2: 创建 AudioPolicyEngine 实例

代码调用栈如下:

AudioPolicyManager::initialize()
│
│   //init_1: AudioPolicyEngine 库的选择和加载
├── engLib = EngineLibrary::load()
│
│    //init_2: 创建 AudioPolicyEngine 实例
└── mEngine = engLib->createEngine()
        ||
    EngineLibrary::createEngine()
    └── EngineInterface* createEngineInstance()
        └── EngineInstance::getInstance()
            └── EngineInstance::queryInterface()
                └── EngineInstance::getEngine()
                    └── static Engine engine

最终创建了一个 Engine 实例赋值给 AudioPolicyManager.mEngine

2.2.1: 创建 CParameterMgr 实例

Engine::Engine()
│
│   //init_2.1: 创建 CParameterMgr 实例
└── new ParameterManagerWrapper()
    │   //strConfigurationFilePath : PFW 配置文件路径
    └── new CParameterMgrPlatformConnector(strConfigurationFilePath)
        └── new CParameterMgr(strConfigurationFilePath)

frameworks/av/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp

const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
    "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
const char *const ParameterManagerWrapper::mPolicyPfwVendorConfFileName =
    "/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
    
ParameterManagerWrapper::ParameterManagerWrapper()
{
    // Connector
    if (access(mPolicyPfwVendorConfFileName, R_OK) == 0) {
        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwVendorConfFileName);
    } else {
        mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
    }
}

external/parameter-framework/upstream/parameter/ParameterMgr.cpp:

CParameterMgr::CParameterMgr(const string &strConfigurationFilePath, log::ILogger &logger)
    : _pMainParameterBlackboard(new CParameterBlackboard),
      _pElementLibrarySet(new CElementLibrarySet),
      _xmlConfigurationUri(CXmlDocSource::mkUri(strConfigurationFilePath, "")), _logger(logger)
{
    // Deal with children
    addChild(new CParameterFrameworkConfiguration);
    addChild(new CSelectionCriteria);
    addChild(new CSystemClass(_logger));
    addChild(new CConfigurableDomains);
}

PFW 配置文件路径 "/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml" 被保存在 _xmlConfigurationUri

CParameterMgr::CParameterMgr() 中创建了四大核心模块,构建 PFW 的层级结构:

  • CParameterFrameworkConfiguration
  • CSelectionCriteria
  • CSystemClass
  • CConfigurableDomains

这四个类对应 PFW 的四个维度:

代表职责
CParameterFrameworkConfiguration框架配置PFW 自身的运行参数
CSelectionCriteria选择条件定义配置选择的条件(如通话状态、设备类型),用于决定在何种场景下应用哪套配置
CSystemClass系统类参数结构的定义,包含所有 Subsystem 及其参数树,是 Blackboard 内存布局的依据
CConfigurableDomains可配置域参数配置的值集合,每个 Domain 包含多套 Configuration,由 SelectionCriteria 决定哪套生效

层级关系

CParameterMgr (根)
├── CParameterFrameworkConfiguration   ← "框架怎么运行"
├── CSelectionCriteria                 ← "什么条件下选哪套配置"
├── CSystemClass                       ← "有哪些参数" (结构定义)
│   └── CSubsystem "Policy"
│       └── 参数树...
└── CConfigurableDomains               ← "参数的值是什么" (配置数据)
    └── CConfigurableDomain "Phone"
        ├── CDomainConfiguration "Normal"   ← 非通话时的参数值
        └── CDomainConfiguration "InCall"   ← 通话时的参数值

CParameterFrameworkConfiguration 管理框架行为,CSelectionCriteria 管理条件选择,CSystemClass 管理参数结构(有什么参数),CConfigurableDomains 管理参数取值(参数值是什么),四者共同实现"在什么条件下,给哪些参数,赋什么值"的功能。

2.2.2: 加载配置文件创建 CSelectionCriterionType 实例和 CSelectionCriterion 实例

Engine::loadAudioPolicyEngineConfig()
├── EngineBase::loadAudioPolicyEngineConfig()
└── ParameterManagerWrapper::addCriterion()
   ├── CParameterMgr::createSelectionCriterionType()
   │   //遍历 ValuePairs
   ├── CSelectionCriterionType::addValuePair()
   └── CParameterMgr::createSelectionCriterion()

配置文件路径的定义: frameworks/av/services/audiopolicy/engine/config/include/EngineConfig.h

constexpr char DEFAULT_PATH[] = "/vendor/etc/audio_policy_engine_configuration.xml";

配置文件内容: audio_policy_engine_configuration.xml

<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">

    <xi:include href="audio_policy_engine_product_strategies.xml"/>
    <xi:include href="audio_policy_engine_criterion_types.xml"/>
    <xi:include href="vendor_audio_policy_engine_criteria.xml"/>
    <xi:include href="audio_policy_engine_stream_volumes.xml"/>
    <xi:include href="audio_policy_engine_default_stream_volumes.xml"/>

</configuration>

audio_policy_engine_criterion_types.xml:

<criterion_types>
	<criterion_type name="OutputDevicesMaskType" type="inclusive">
		<values>
			<value numerical="1" literal="Earpiece" android_type="0x1"/>
...
	<criterion_type name="InputDevicesMaskType" type="inclusive">
		<values>
			<value numerical="1" literal="Communication" android_type="0x80000001"/>
			<value numerical="2" literal="Ambient" android_type="0x80000002"/>
			...
			<value numerical="33554432" literal="UsbHeadset" android_type="0x82000000"/>
			...

vendor_audio_policy_engine_criteria.xml:

<criteria>
    <criterion name="AvailableInputDevices" type="InputDevicesMaskType" default="none"/>
    <criterion name="AvailableOutputDevices" type="OutputDevicesMaskType" default="none"/>
...
</criteria>

配置实例化结果:

SelectionCriterion类型与实例结构.png

3. 加载 PFW 配置文件

Engine 和 CParameterMgr 创建完成后,程序来到了 mEngine->initCheck() ---> CParameterMgr::load()。

CParameterMgr::load()
├── feedElementLibraries()
├── loadFrameworkConfiguration()
├── loadSubsystems()
├── loadStructure()
└── loadSettings()

3.1 feedElementLibraries()

PFW 定义了三种元素库(ElementLibrary)枚举,分别对应三个 XML 解析阶段,每个阶段用不同的 Builder 映射表来创建元素: external/parameter-framework/upstream/parameter/ParameterMgr.h

class CParameterMgr : private CElement
{
    enum ElementLibrary
    {
        EFrameworkConfigurationLibrary, //0
        EParameterCreationLibrary, //1
        EParameterConfigurationLibrary //2
    };
private:
	CElementLibrarySet *_pElementLibrarySet;
}

_pElementLibrarySet三种 ElementLibrary 的容器,通过 vector<CElementLibrary*> 按索引存储,与前面的枚举一一对应:

_pElementLibrarySet[0] = EFrameworkConfigurationLibrary   → 框架配置 Builder 映射表
_pElementLibrarySet[1] = EParameterCreationLibrary        → 参数结构 Builder 映射表
_pElementLibrarySet[2] = EParameterConfigurationLibrary   → 参数配置 Builder 映射表
枚举值对应解析阶段用途
EFrameworkConfigurationLibrary解析框架配置 XML创建 CParameterFrameworkConfigurationCSubsystemPlugins 等顶层配置元素
EParameterCreationLibrary解析结构定义 XML(Subsystem 结构)创建 CSubsystemCComponentTypeCComponentInstance 等参数结构元素
EParameterConfigurationLibrary解析参数配置 XML(Domain 配置)创建 CConfigurableDomainCDomainConfiguration 等可配置域元素

针对 XML 标签,将 Builder 注册到三种 CElementLibrary 中。

external/parameter-framework/upstream/parameter/ParameterMgr.cpp

// Dynamic creation library feeding
void CParameterMgr::feedElementLibraries()
{
    // Global Configuration handling
    auto pFrameworkConfigurationLibrary = new CElementLibrary;

    pFrameworkConfigurationLibrary->addElementBuilder(
        "ParameterFrameworkConfiguration",
        new TElementBuilderTemplate<CParameterFrameworkConfiguration>());
    pFrameworkConfigurationLibrary->addElementBuilder(
        "SubsystemPlugins", new TKindElementBuilderTemplate<CSubsystemPlugins>());
	......
	/* 加入到 _pElementLibrarySet[0] */
	_pElementLibrarySet->addElementLibrary(pFrameworkConfigurationLibrary);

    // Parameter creation
    auto pParameterCreationLibrary = new CElementLibrary;

    pParameterCreationLibrary->addElementBuilder(
        "Subsystem", new CSubsystemElementBuilder(getSystemClass()->getSubsystemLibrary()));
    pParameterCreationLibrary->addElementBuilder(
        "ComponentType", new TNamedElementBuilderTemplate<CComponentType>());
    pParameterCreationLibrary->addElementBuilder(
        "Component", new TNamedElementBuilderTemplate<CComponentInstance>());
	......
	/* 加入到 _pElementLibrarySet[1] */
    _pElementLibrarySet->addElementLibrary(pParameterCreationLibrary);

    // Parameter Configuration Domains creation
    auto pParameterConfigurationLibrary = new CElementLibrary;

    pParameterConfigurationLibrary->addElementBuilder(
        "ConfigurableDomain", new TElementBuilderTemplate<CConfigurableDomain>());
    pParameterConfigurationLibrary->addElementBuilder(
        "Configuration", new TNamedElementBuilderTemplate<CDomainConfiguration>());
    pParameterConfigurationLibrary->addElementBuilder("CompoundRule",
                                                      new TElementBuilderTemplate<CCompoundRule>());
    pParameterConfigurationLibrary->addElementBuilder(
        "SelectionCriterionRule", new TElementBuilderTemplate<CSelectionCriterionRule>());
	/* 加入到 _pElementLibrarySet[2] */
    _pElementLibrarySet->addElementLibrary(pParameterConfigurationLibrary);
}

注册结果示例: _pElementLibrarySet[EParameterCreationLibrary] 中增加了 CElementLibrary::_elementBuilderMap["Subsystem"] = CSubsystemElementBuilder

使用时:

  • 将 ElementLibrary 枚举值传入 xmlParse()
bool CParameterMgr::loadStructure(string &strError)
{
	xmlParse(parameterBuildContext, pSystemClass, doc, structureUri,
                      EParameterCreationLibrary)
}
  • xmlParse() 中按枚举值取出对应的 Library
bool CParameterMgr::xmlParse(CXmlElementSerializingContext &elementSerializingContext,
                             CElement *pRootElement, _xmlDoc *doc, const string &baseUri,
                             CParameterMgr::ElementLibrary eElementLibrary, bool replace,
                             const string &strNameAttributeName)
{
    // Init serializing context
    elementSerializingContext.set(_pElementLibrarySet->getElementLibrary(eElementLibrary), baseUri);
}

3.2 loadFrameworkConfiguration()

loadFrameworkConfiguration() 主要做了以下工作:

  • 解析 ParameterFrameworkConfigurationPolicy.xml
<?xml version="1.0" encoding="UTF-8"?>
<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    SystemClassName="Policy" TuningAllowed="false">

    <SubsystemPlugins>
        <Location Folder="">
            <Plugin Name="libpolicy-subsystem.so"/>
        </Location>
    </SubsystemPlugins>
    <StructureDescriptionFileLocation Path="Structure/Policy/audio_PolicyClass.xml"/>
    <SettingsConfiguration>
        <ConfigurableDomainsFileLocation Path="Settings/Policy/PolicyConfigurableDomains.xml"/>
    </SettingsConfiguration>
</ParameterFrameworkConfiguration>
  • 将 CSystemClass 和 CConfigurableDomains 的名称设为配置文件中的 SystemClassName 属性值
  • 将 SubsystemPlugins 配置的解析结果存入 _pSubsystemPlugins,供后续加载插件库使用

3.3 loadSubsystems()

loadSubsystems() 的主要作用是加载插件 .so,并注册插件中的 PolicySubsystemBuilder:

CParameterMgr::loadSubsystems()
│
└── CSystemClass::loadSubsystems(_pSubsystemPlugins) //见⓵
    │
    └── CSystemClass::loadSubsystemsFromSharedLibraries()
        │
        └── CSystemClass::loadPlugins() //见⓶
            └── 加载插件 .so,注册插件里的 PolicySubsystemBuilder

⓵ _pSubsystemPlugins 的来源
_pSubsystemPlugins 的值来自配置文件 ParameterFrameworkConfigurationPolicy.xml 中的 SubsystemPlugins

    <SubsystemPlugins>
        <Location Folder="">
            <Plugin Name="libpolicy-subsystem.so"/>
        </Location>
    </SubsystemPlugins>

_pSubsystemPlugins = "libpolicy-subsystem.so"

⓶ 注册 PolicySubsystemBuilder PolicySubsystem 作为扩展 Subsystem,在动态加载的插件 libpolicy-subsystem.so 中实现。

external/parameter-framework/upstream/parameter/SystemClass.cpp

const char CSystemClass::entryPointSymbol[] =
    MACRO_TO_STR(PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1);
using PluginEntryPointV1 = void (*)(CSubsystemLibrary *, core::log::Logger &);

bool CSystemClass::loadPlugins(list<string> &lstrPluginFiles, core::Results &errors)
{
        try {
            auto library = utility::make_unique<DynamicLibrary>(strPluginFileName);

            // Load symbol from library
            auto subSystemBuilder = library->getSymbol<PluginEntryPointV1>(entryPointSymbol);

            // Store libraries handles
            _subsystemLibraryHandleList.push_back(std::move(library));

            // Fill library
            subSystemBuilder(_pSubsystemLibrary, _logger);

        }
}
  • 使用 libpolicy-subsystem.so 创建 DynamicLibrary 实例
  • libpolicy-subsystem.so 获取名为 PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1 的函数地址,赋值给 subSystemBuilder
  • 调用 subSystemBuilder 函数,即 libpolicy-subsystem.so 中的 PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1

libpolicy-subsystem.soPARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1 函数的实现:

frameworks/av/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystemBuilder.cpp

static const char *const POLICY_SUBSYSTEM_NAME = "Policy";

void PARAMETER_FRAMEWORK_PLUGIN_ENTRYPOINT_V1(CSubsystemLibrary *subsystemLibrary, core::log::Logger& logger)
{
    subsystemLibrary->addElementBuilder(POLICY_SUBSYSTEM_NAME,
                                        new TLoggingElementBuilderTemplate<PolicySubsystem>(logger));
}

PolicySubsystem 的 Builder 以 "Policy" 为 key 注册到 CSubsystemLibrary(即 CSystemClass._pSubsystemLibrary),使得 XML 中 <Subsystem Type="Policy"> 能被创建为 PolicySubsystem 对象。

对应的 XML 配置:
vendor/etc/parameter-framework/Structure/Policy/audio_PolicySubsystem.xml

<Subsystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:xi="http://www.w3.org/2001/XInclude"
           xsi:noNamespaceSchemaLocation="Schemas/Subsystem.xsd"
           Name="policy" Type="Policy">

CSubsystemLibrary 继承于 CElementLibrary,CElementLibrary 默认是按 XML 标签名匹配:
external/parameter-framework/upstream/parameter/ElementLibrary.cpp

std::string CElementLibrary::getBuilderType(const CXmlElement &xmlElement) const
{
    return xmlElement.getType();  // 返回 XML 标签名
}

其他 Builder 都是按标签名注册的,例如:

addElementBuilder 的第一个参数XML 标签对应的 Builder
"Subsystem"<Subsystem ...>CSubsystemElementBuilder
"SubsystemInclude"<SubsystemInclude ...>CFileIncluderElementBuilder

当解析器遇到 <SubsystemInclude Path="..."> 时,getBuilderType() 返回 "SubsystemInclude",直接命中 CFileIncluderElementBuilder

但是,CSubsystemLibrary 重写了 getBuilderType()

std::string getBuilderType(const CXmlElement &xmlElement) const override
{
    std::string type;
    xmlElement.getAttribute("Type", type);   // 读取 Type 属性,而不是标签名
    return type;
}

所以 CSubsystemLibrary 按 Type 属性值匹配。

CSystemClass._pSubsystemLibrary 中注册的是:

注册的 keyXML Type 属性值对应的 Builder
"Virtual"Type="Virtual"TLoggingElementBuilderTemplate<CVirtualSubsystem>
"Policy"Type="Policy"TLoggingElementBuilderTemplate<PolicySubsystem>

注:"Virtual"CSubsystemLibrary 的默认 fallback builder(通过 CDefaultElementLibrary 的模板参数指定),"Policy" 由插件 libpolicy-subsystem.so 注册。

3.4 loadStructure()

调用栈:

CParameterMgr::loadStructure()
│
└─ CParameterMgr::xmlParse(pSystemClass, EParameterCreationLibrary)
   │
   ├─ 设置上下文
   │  elementSerializingContext.set(pParameterCreationLibrary, baseUri)
   │  pRootElement = pSystemClass
   │
   └─ CXmlMemoryDocSink::doProcess()
      │
      └─ CConfigurableElement::fromXml()                  // CSystemClass 继承自 CConfigurableElement
         │
         └─ CElement::fromXml()                           // 递归遍历XML子节点
            │
            │  CSystemClass::childrenAreDynamic() → true  // 走 createChild 分支
            │
            ├─ CElement::createChild(childElement)        // 遇到 <Subsystem> 标签
            │  │
            │  ├─ 从上下文获取 ElementLibrary
            │  │  elementSerializingContext.getElementLibrary()
            │  │  → EParameterCreationLibrary
            │  │
            │  ├─ pParameterCreationLibrary->createElement(childElement)
            │  │  │
            │  │  └─ CElementLibrary::createElement()
            │  │     │  _elementBuilderMap["Subsystem"] → CSubsystemElementBuilder
            │  │     │
            │  │     └─ CSubsystemElementBuilder::createElement()
            │  │        │
            │  │        └─ CSubsystemLibrary::createElement()  // 委托给子系统库
            │  │           │
            │  │           └─ CElementLibrary::createElement()
            │  │              │
            │  │              ├─ CSubsystemLibrary::getBuilderType()
            │  │              │  从 Type 属性获取 → "Policy"
            │  │              │
            │  │              ├─ _elementBuilderMap["Policy"] → PolicySubsystemBuilder
            │  │              │
            │  │              └─ TLoggingElementBuilderTemplate::createElement()
            │  │                 new PolicySubsystem(name, logger)
            │  │
            │  └─ CSystemClass::addChild(PolicySubsystem*)   // 挂到 CSystemClass 下
            │
            └─ pChild->fromXml()
                ||
               PolicySubsystem::fromXml()
                ||
               CConfigurableElement::fromXml()
               └─ CSubsystem::structureFromXml() //解析 XML,构建参数树填充 PolicySubsystem

loadStructure() 里主要功能是:

  • 创建"libpolicy-subsystem.so"里的 PolicySubsystem 实例,并作为一个 child CElement 挂到 CSystemClass 下
  • CSubsystem::structureFromXml() 解析 XML,构建参数树填充 PolicySubsystem

CSubsystem::structureFromXml()

CSubsystem::structureFromXml() 对应的配置文件是: audio_PolicySubsystem.xml

audio_PolicySubsystem.xml 包含了(include) 另外两个配置文件:

  • audio_PolicySubsystem-CommonTypes.xml
  • ProductStrategies.xml

配置文件内容节选: audio_PolicySubsystem-CommonTypes.xml:

<ComponentTypeSet
    <ComponentType Name="InputDevicesMask" Description="64bit representation of devices">
        <BitParameterBlock Name="mask" Size="64">
            <BitParameter Name="communication" Size="1" Pos="0"/>
            <BitParameter Name="usb_headset" Size="1" Pos="25"/>
            ...
        </BitParameterBlock>
    </ComponentType>
    <ComponentType Name="InputSource">
        <Component Name="applicable_input_device" Type="InputDevicesMask" Mapping="InputSource" Description="Selected Input device"/>
    </ComponentType>
</ComponentTypeSet>

audio_PolicySubsystem.xml:

<Subsystem Name="policy" Type="Policy">

    <!-- 第一步:定义 ComponentType(类型模板) -->
    <ComponentLibrary>
        <ComponentType Name="InputSources">
            <Component Name="mic" Type="InputSource" Mapping="Name:AUDIO_SOURCE_MIC"/>
            ...
        </ComponentType>
    </ComponentLibrary>

    <!-- 第二步:声明要实例化哪些 ComponentType -->
    <InstanceDefinition>
        <Component Name="streams" Type="Streams"/>
        <Component Name="input_sources" Type="InputSources"/>
        <Component Name="product_strategies" Type="ProductStrategies"/>
    </InstanceDefinition>

</Subsystem>

CSubsystem::structureFromXml() 主要做了三件事:

    CSubsystem::structureFromXml()
    │
    │  //Step 1: 解析 XML,构建类型树(ComponentLibrary/InstanceDefinition)
    ├─ _pComponentLibrary->fromXml()
    ├─ _pInstanceDefinition->fromXml()
    │
    │  //Step 2: 调用 createInstances(),构建 component 实例树
    ├─ _pInstanceDefinition->createInstances(this)
    │
    │  //Step 3: 将 XML 中的 Mapping 属性关联到 CInstanceConfigurableElement,//创建对应的 CSubsystemObject,建立//CInstanceConfigurableElement ↔ CSubsystemObject 的关联
    └── CSubsystem::mapSubsystemElements()

流程示意图和实例化后参数树:

CSubsystem--structureFromXml类型树与实例树.png

其中 CSubsystem::mapSubsystemElements() 的详细流程如下:

CSubsystem::structureFromXml// 解析完所有xml配置后
└── CSubsystem::mapSubsystemElements()
    │   // 遍历 CInstanceConfigurableElement, 传入 CSubsystem : IMapper
    └── CInstanceConfigurableElement::map(IMapper &mapper)
        ├── CSubsystem::mapBegin(CInstanceConfigurableElement *)
        └── CSubsystem::handleSubsystemObjectCreation(CInstanceConfigurableElement *)
            │   // 遍历 _subsystemObjectCreatorArray 里的 CSubsystemObjectCreator
            ├── string strKey = pSubsystemObjectCreator->getMappingKey()
            │   // 判断当前CInstanceConfigurableElement实例节点的 Mapping 数据是否包含// CSubsystemObjectCreator 的 _strMappingKey, 有则匹配成功,准备创建// 对应的CSubsystemObject对象
            ├── pInstanceConfigurableElement->getMappingData(strKey, pStrValue)
            ├── TSubsystemObjectFactory::objectCreate
            ├── new InputSource(strMappingValue, pInstanceConfigurableElement, context, logger)
            │   ├── CFormattedSubsystemObject::CFormattedSubsystemObject()
            │   └── CSubsystemObject::CSubsystemObject(pInstanceConfigurableElement)
            │           // 将 InputSource 实例传入CInstanceConfigurableElement::setSyncer(ISyncer *pSyncer)
            └── _subsystemObjectList.push_back()

对应示意图:

CSubsystem-mapSubsystemElements_Mapping关联.png

3.5 loadSettings()

loadSettings() 加载的是 PolicyConfigurableDomains.xml。这是 PFW 的 Settings 层,是整个音频路由决策的核心规则库。文件定义了所有 ConfigurableDomain,每个 domain 是一组互斥的路由规则。

3.5.1 文件整体结构

PolicyConfigurableDomains.xml
│
├── DeviceForInputSource.*          输入源 → 输入设备 路由规则
│   ├── Calibration                 永久清零不可用的 bits("黑名单")
│   ├── DefaultAndMic               default / mic 的设备选择
│   ├── VoiceUplinkAndVoiceDownlinkAndVoiceCall
│   ├── VoicePerformance
│   ├── Camcorder
│   ├── VoiceRecognitionAndUnprocessedAndHotword
│   ├── VoiceCommunication          ← 关键域,下文详细分析
│   ├── RemoteSubmix
│   └── FmTuner
│
├── VolumeProfilesForStream.*       stream → 音量曲线映射
│
└── DeviceForProductStrategy.*      输出策略 → 输出设备 路由规则
    ├── Media.*
    ├── Accessibility.*
    ├── Dtmf.*
    ├── EnforcedAudible.*
    ├── Phone.*
    ├── Sonification.*
    ├── SonificationRespectful.*
    └── TransmittedThroughSpeaker.*

文件内容节选:

<ConfigurableDomains SystemClassName="Policy">
  <ConfigurableDomain Name="DeviceForInputSource.VoiceCommunication" SequenceAware="false">
    <Configurations>
      <Configuration Name="UsbHeadset">
        <CompoundRule Type="All">
          <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
          <SelectionCriterionRule SelectionCriterion="AvailableInputDevices" MatchesWhen="Includes" Value="UsbHeadset"/>
        </CompoundRule>
      </Configuration>
      ...
    <ConfigurableElements>
      <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/bluetooth_sco_headset"/>
      <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/wired_headset"/>
      <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/usb_headset"/>
      <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/builtin_mic"/>
      <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/back_mic"/>
    </ConfigurableElements>
    <Settings>
      <Configuration Name="UsbHeadset">
        <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/bluetooth_sco_headset">
          <BitParameter Name="bluetooth_sco_headset">0</BitParameter>
        </ConfigurableElement>
        <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/wired_headset">
          <BitParameter Name="wired_headset">0</BitParameter>
        </ConfigurableElement>
        <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/usb_headset">
          <BitParameter Name="usb_headset">1</BitParameter>
        </ConfigurableElement>
        <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/builtin_mic">
          <BitParameter Name="builtin_mic">0</BitParameter>
        </ConfigurableElement>
        <ConfigurableElement Path="/Policy/policy/input_sources/voice_communication/applicable_input_device/mask/back_mic">
          <BitParameter Name="back_mic">0</BitParameter>
        </ConfigurableElement>
      </Configuration>
      ...
    </Settings>
  </ConfigurableDomain>
</ConfigurableDomains>

3.5.2 配置实例化

配置实例化后的结果如图:

PolicyConfigurableDomains配置实例化.png

3.5.3 CParameterMgr._pMainParameterBlackboard 和 AreaConfiguration

3.5.3.1 CParameterMgr._pMainParameterBlackboard

CParameterMgr._pMainParameterBlackboardCParameterBlackboard * 类型的全局唯一变量,存储当前生效的全部参数值。

CParameterBlackboard 字面意思是参数存储的"黑板",本质是一个字节缓冲区,存储参数的原始二进制数据:

std::vector<uint8_t> mBlackboard;  // 内部就是一个 byte 数组

CParameterMgr::loadStructure() 解析完 XML 后对 _pMainParameterBlackboard 进行初始化:

CParameterMgr::loadStructure() {
	xmlParse();

    // Initialize offsets
    pSystemClass->setOffset(0);

    // Initialize main blackboard's size
    _pMainParameterBlackboard->setSize(pSystemClass->getFootPrint());
}

先看个类关系图:

Level 1 (顶层):       CConfigurableElement
                              │
            ┌─────────────────┴─────────────────┐
            │                                   │
Level 2: CSystemClass [final]    CInstanceConfigurableElement
        (终点,无法继续派生)                       │
                                     ┌──────────┴──────────┐
                                     │                     │
Level 3:                        CComponent         CBitParameterBlock
                                                   └── getFootPrint() = CBitParameterBlockType::getSize()

pSystemClass->setOffset(0)
    CConfigurableElement::setOffset(0)

所以 pSystemClass->setOffset(0) 实际调用的是 CConfigurableElement::setOffset()内部递归给所有子元素分配偏移

void CConfigurableElement::setOffset(size_t offset)
{
    _offset = offset;                          // 设置自身偏移

    for (size_t index = 0; index < getNbChildren(); index++) {
        pConfigurableElement->setOffset(offset);           // 子元素偏移 = 当前offset
        offset += pConfigurableElement->getFootPrint();    // offset 累加子元素占用的字节数
    }
}
size_t CConfigurableElement::getFootPrint() const
{
    size_t uiSize = 0;
    size_t uiNbChildren = getNbChildren();

    for (size_t index = 0; index < uiNbChildren; index++) {

        const CConfigurableElement *pConfigurableElement =
            static_cast<const CConfigurableElement *>(getChild(index));

        uiSize += pConfigurableElement->getFootPrint();
    }

    return uiSize;
}

其中,getFootPrint() 返回 CConfigurableElement 在 Blackboard(参数内存)中占用的字节数

效果:从 SystemClass 开始,按深度优先顺序给整棵元素树分配连续的内存偏移,每个子元素的 offset = 前面所有兄弟的 Footprint 之和,形成一块连续的参数内存布局(Blackboard)。

分配完offset后,就可以得到所有子元素所占用的内存大小总和,然后通过

_pMainParameterBlackboard->setSize(pSystemClass->getFootPrint())

设置 _pMainParameterBlackboard 的 size。

最后,所有实例在_pMainParameterBlackboard中的offset和footprint:

SystemClass (offset=0)
└── PolicySubsystem (offset=0, footprint=x)
    ├── CComponent:streams (offset=0, footprint=a=14x4=56])
    ├── CComponent:input_sources (offset=a, footprint=14x8=112)
    │   ├── CComponent:default (offset=a, footprint = 8)
    │   │   └── CComponent:applicable_input_device (offset=a, footprint = 8)
    │   │       └── CBitParameterBlock:mask (offset=a, footprint = 8)
    │   │           ├── CBitParameter:communication (offset=a, footprint = 0)
    │   │           ├── CBitParameter:ambient (offset=a, footprint = 0)
    │   │           ├── CBitParameter:builtin_mic
    │   │           └── ...
    │   ├── CComponent:mic (offset=a + 8, footprint = 8)
    │   │   └── CComponent:applicable_input_device (offset=a + 8, footprint = 8)
    │   │       └── CBitParameterBlock:mask (offset=a + 8, footprint = 8)
    │   │           ├── CBitParameter:communication (offset=a + 8, footprint = 0)
    │   │           ├── CBitParameter:ambient (offset=a + 8, footprint = 0)
    │   │           ├── CBitParameter:builtin_mic (offset=a + 8, footprint = 0)
    │   │           └── ...
    │   ├── ...
    │   ├── CComponent:voice_communication
    │   └── ...
    └── CComponent:product_strategies (offset=a+112, footprint=?)

内存分布示意图:

0x00    ┌────────────────────┬──────────────────────────────────────────────────────────────┬─────────────────┐
 │      │ streams            │ ...                                                          │                 │
 │      ├────────────────────┼──────────────────────┬─────────────────────────┬─────────────┼─────────────────┤
 │      │                    │ default              │ applicable_input_device │ mask 64 bit │0: communication │
 │      │                    │                      │                         │             ├─────────────────┤
 │      │                    │                      │                         │             │1: ambient       │
 │      │                    │                      │                         │             ├─────────────────┤
 │      │                    │                      │                         │             │ ...             │
 │      │                    │                      │                         │             ├─────────────────┤
 │      │                    │                      │                         │             │25: usb_headset  │
 │      │                    │                      │                         │             ├─────────────────┤
 │      │                    │                      │                         │             │63: ...          │
 │      │                    ├──────────────────────┼─────────────────────────┼─────────────┼─────────────────┤
 │      │                    │ mic                  │ applicable_input_device │ mask 64 bit │                 │
 │      │                    ├──────────────────────┼─────────────────────────┼─────────────┼─────────────────┤
 │      │                    │ voice_uplink         │ applicable_input_device │ mask 64 bit │                 │
 │      │ input_sources      ├──────────────────────┼─────────────────────────┼─────────────┼─────────────────┤
 │      │                    │ ...                  │       ...               │ ...         │                 │
 │      │                    ├──────────────────────┼─────────────────────────┼─────────────┼─────────────────┤
 │      │                    │ voice_communication  │ applicable_input_device │ mask 64 bit │                 │
 │      │                    ├──────────────────────┼─────────────────────────┼─────────────┼─────────────────┤
 │      │                    │ ...                  │       ...               │ ...         │                 │
 │      ├────────────────────┼──────────────────────┴─────────────────────────┴─────────────┼─────────────────┤
 │      │ product_strategies │ ...                                                          │                 │
 ↓      └────────────────────┴──────────────────────────────────────────────────────────────┴─────────────────┘
pSystemClass->getFootPrint()
3.5.3.2 AreaConfiguration

在 PFW 中,AreaConfiguration 表示一个"配置域" —— 一组参数值的预设方案。 参数值存于 _blackboard

AreaConfiguration类关系.png

经过 CParameterMgr::loadSettings() 解析 PolicyConfigurableDomains.xml 后,得到 CBitwiseAreaConfiguration(即 AreaConfiguration),例如:

DeviceForInputSource.VoiceCommunication : CConfigurableDomain
    UsbHeadset : CDomainConfiguration
	    mAreaConfigurationList:
			bluetooth_sco_headset : CBitwiseAreaConfiguration = 0
			wired_headset : CBitwiseAreaConfiguration = 0
			usb_headset : CBitwiseAreaConfiguration = 0x2000000
			builtin_mic : CBitwiseAreaConfiguration = 0
			back_mic : CBitwiseAreaConfiguration = 0

在 VoiceCommunication 场景下,UsbHeadset 的 mAreaConfigurationList 中的 CBitwiseAreaConfiguration 表示当使用 USB 耳机作为输入设备时,各物理区域(麦克风位置)的使能状态。

3.5.3.3 两者关系
┌────────────────────────────────────────────────┐
│  CParameterMgr._pMainParameterBlackboard       │
│  (全局唯一, 存储当前生效的参数值)                 │
│ ...[wired_headset][usb_headset][builtin_mic]...│
└────────────────────────────────────────────────┘
         ↓ save()                   ↑ restore()
         │                          │
┌────────┴─────────┐       ┌────────┴─────────┐
│ AreaConfiguration│       │ AreaConfiguration│
│   "usb_headset"  │       │   "builtin_mic"  │
│  ┌────────────┐  │       │  ┌────────────┐  │
│  │ _blackboard│  │       │  │ _blackboard│  │
│  └────────────┘  │       │  └────────────┘  │
└──────────────────┘       └──────────────────┘

save() 和 restore() 的源码:

// Save data from current
void CAreaConfiguration::save(const CParameterBlackboard *pMainBlackboard)
{
    copyFrom(pMainBlackboard, _pConfigurableElement->getOffset());
}

// Apply data to current
bool CAreaConfiguration::restore(CParameterBlackboard *pMainBlackboard, bool bSync,
                                 core::Results *errors) const
{
    assert(_bValid);

    copyTo(pMainBlackboard, _pConfigurableElement->getOffset());

    // Synchronize if required
    return !bSync || _pSyncerSet->sync(*pMainBlackboard, false, errors);
}
  • CAreaConfiguration::save() 从 CParameterMgr._pMainParameterBlackboard 拷贝数据到自己的 _blackboard(保存当前配置)
  • CAreaConfiguration::restore() 把自己的 _blackboard 数据拷回 CParameterMgr._pMainParameterBlackboard(恢复配置)

其中使用的 offset 通过 _pConfigurableElement->getOffset() 获取,例如 usb_headset :CBitwiseAreaConfigurationusb_headset : CBitParameter 获取 offset。

4. UsbHeadset 设备接入流程

如 3.5.2 节「PolicyConfigurableDomains 配置实例化」图中 Step 4 所示,当 UsbHeadset 设备接入时,调用栈如下:

AudioPolicyManager::setDeviceConnectionState()
    ↓
AudioPolicyManager::setEngineDeviceConnectionState()
    ↓
Engine::setDeviceConnectionState()
    ↓
ParameterManagerWrapper::setAvailableInputDevices()
    ↓
CSelectionCriterion::setCriterionState(1<<25)

将 AvailableInputDevices._iState 设置为 0x2000000 (1 << 25)

然后开始应用配置:

ParameterManagerWrapper::setAvailableInputDevices()
├── CSelectionCriterion::setCriterionState(1<<25)
│
└── ParameterManagerWrapper::applyPlatformConfiguration()
        ↓
CParameterMgr::applyConfigurations()
└── doApplyConfigurations(false)
    ├── CSystemClass::checkForSubsystemsToResync()     ← 处理需要 resync 的子系统
    └── CConfigurableDomains::apply(_pMainParameterBlackboard, syncerSet)  ← 应用配置域
        │   //遍历CConfigurableDomain实例
        ├── CConfigurableDomain::apply(pSyncerSet) ["DeviceForInputSource.VoiceCommunication"]
        │   ├── CConfigurableDomain::findApplicableDomainConfiguration() 返回一个CDomainConfiguration
        │   │   │
        │   │   │   // Step 4.2 查找 Rule 匹配的 CDomainConfiguration
        │   │   │
        │   │   │   // 遍历所有DomainConfiguration,调用其isApplicable()方法判断是否适用
        │   │   └── CDomainConfiguration::isApplicable() //UsbHeadset
        │   │       └── CCompoundRule::matches() "All"
        │   │           │   // 遍历所有 SelectionCriterionRule:
        │   │           │   // ForceUseForCommunication, Is, ForceNone
        │   │           │   // AvailableInputDevices, Includes, UsbHeadset
        │   │           └── CSelectionCriterionRule::matches()
        │   │               │   // 根据 MatchesWhen 的值,调用CSelectionCriterion
        │   │               │   // 的is/isNot/includes/excludes方法判断是否满足规则
        │   │               └── CSelectionCriterion::is/isNot/includes/excludes()
        │   │                   └── 根据_iState的值做判断
        │   │   bool bSync = !pSyncerSet && _bSequenceAware = false
        │   │
        │   │   // Step 4.3: 将匹配到 CompoundRule 的 CDomainConfiguration 的配置值
        │   │   // restore 到 CParameterMgr._pMainParameterBlackboard
        │   │
        │   ├── CDomainConfiguration::restore(pParameterBlackboard, false) //"UsbHeadset"
        │   │   │   // 遍历 mAreaConfigurationList
        │   │   └── CAreaConfiguration::restore(pParameterBlackboard, bSync=false) //"usb_headset"
        │   │       ├── CBitParameter::getOffset() //"usb_headset"
        │   │       ├── copyTo(mainBlackboard)  ← 把配置值拷入CParameterMgr._pMainParameterBlackboard
        │   │       └── 因为 bSync=false,所以不执行 SyncerSet::sync()
        │   └── *pSyncerSet += _syncerSet //voice_communication:InputSource
        │
        │   // Step 4.4: 将状态同步到 Engine
        │
        │   // Synchronize those collected syncers
        └── syncerSet.sync(*pParameterBlackboard, false, nullptr)
            │   for each ISyncer:
            └── ISyncer::sync()    ← 虚函数调用
                = CSubsystemObject::sync(pParameterBlackboard, bBack=false)
                ├── _blackboard = &parameterBlackboard //赋值了CParameterMgr._pMainParameterBlackboard
                └── CSubsystemObject::accessHW()
                    └── InputSource::sendToHW() //voice_communication:InputSource// 从CParameterMgr._pMainParameterBlackboard读取可用设备
                        ├── CSubsystemObject::blackboardRead() 
                        └── Engine::setDeviceForInputSource(7, 0x2000000)
                            └── Engine::setPropertyForKey()

其中 Step 4.2 匹配到:

<SelectionCriterionRule SelectionCriterion="AvailableInputDevices" MatchesWhen="Includes" Value="UsbHeadset"/>

进而匹配到包含以上 SelectionCriterionRule 的CompoundRule 如:

<CompoundRule Type="All">
  <SelectionCriterionRule SelectionCriterion="ForceUseForCommunication" MatchesWhen="Is" Value="ForceNone"/>
  <SelectionCriterionRule SelectionCriterion="AvailableInputDevices" MatchesWhen="Includes" Value="UsbHeadset"/>
</CompoundRule>

最后, Step 4.4: 将状态同步到 Engine,更新 Engine.mInputSourceCollectionAUDIO_SOURCE_VOICE_COMMUNICATION 对应的 mApplicableDevices0x82000000

D APM::AudioPolicyEngine: setDeviceForInputSource: set deviceType 0x82000000 for input source 7, device = 0x2000000

5. 录音请求获取设备流程

如 3.5.2 节「PolicyConfigurableDomains 配置实例化」图中 Step 5 所示,当 App 发出录音请求时,代码会走 AudioPolicyManager 中的:

getInputForAttr(source, flags)
│
└── Engine::getInputDeviceForAttributes()
	│	→ 查 PFW 配置,返回设备 (如 USB_HEADSET)
	└── Engine::getPropertyForKey(AUDIO_SOURCE_VOICE_COMMUNICATION)
		└──  Element<audio_source_t>::get(audio_devices_t devices)

Engine::getPropertyForKey() 以 AUDIO_SOURCE_VOICE_COMMUNICATION 为 key,获取到 Step 4.4 和 Step 4.5 中设置的 mApplicableDevices = 0x82000000,即 AUDIO_DEVICE_IN_USB_HEADSET

6. 总结

本文围绕 Android Audio 的 Parameter-Framework,从源码层面梳理了其核心设计思想与实现链路:

  • 数据驱动策略:PFW 将路由决策逻辑从代码中剥离,以 XML 配置(Criterion → ConfigurableDomain → AreaConfiguration)定义规则,运行时通过 SelectionCriterion 状态匹配生效。
  • 四维模型:CParameterFrameworkConfiguration(框架配置)、CSelectionCriteria(条件选择)、CSystemClass(参数结构)、CConfigurableDomains(参数取值)四者共同构成 PFW 的层级结构。
  • 插件化扩展:Subsystem 通过动态库(如 libpolicy-subsystem.so)注册到框架中,使 PFW 具备与具体平台解耦的可扩展性。
  • Blackboard 机制:全局唯一的 CParameterMgr._pMainParameterBlackboard 作为参数值的统一存储,通过 Offset + Footprint 实现线性内存布局,配合 AreaConfiguration 的 save/restore 完成配置切换。
  • Syncer 同步链:配置生效后通过 ISyncer::sync() 将 Blackboard 数据同步到 Engine 侧的具体策略对象(如 InputSource.mApplicableDevices),完成从配置到行为的闭环。

理解 PFW 的设计有助于深入掌握 Android 音频路由策略的动态决策过程,也为在 HAL 层或 Framework 层扩展自定义策略提供了参考。

C289B571-FC59-480F-B744-7075111137F6_1_105_c.jpeg