相关推荐recommended
【AudioPolicy To AudioHAL笔记(三)】安卓S上audio
作者:mmseoamin日期:2024-02-24

安卓S上audio_policy_configuration.xml 加载过程分析

/*****************************************************************************************************************/

声明: 本博客内容均由https://blog.csdn.net/weixin_47702410原创,转载or引用请注明出处,谢谢!

创作不易,如果文章对你有帮助,麻烦点赞 收藏支持~感谢

/*****************************************************************************************************************/

上一篇文章启动过程提到:

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
void AudioPolicyManager::loadConfig() {
    ALOGE("Mylog_AP:AudioPolicyManager::loadConfig() !");
    if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
        ALOGE("could not load audio policy configuration file, setting defaults");
        getConfig().setDefault();
    }
}

本文详细讲一下这个解析配置文件的过程。

deserializeAudioPolicyXmlConfig()的定义在:

/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
    if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
            !audioPolicyXmlConfigFile.empty()) {
        status_t ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile.c_str(), &config);
        if (ret == NO_ERROR) {
            config.setSource(audioPolicyXmlConfigFile);
        }
        return ret;
    }
    return BAD_VALUE;
}

这个函数主要做了两个事情:

  • 调用函数audio_get_audio_policy_config_file获取配置文件的信息
  • 调用函数deserializeAudioPolicyFile处理配置文件

    其中第一步骤的函数在如下的定义(有可能这个函数会被客制化修改):

    //https://cs.android.com/android/platform/superproject/+/android-12.0.0_r8:system/media/audio/include/system/audio_config.h?hl=zh-cn
    /system/media/audio/include/system/audio_config.h
    static inline std::string audio_get_audio_policy_config_file() 
    

    函数内容不是很难,感兴趣可以自己阅读源码,我这里总结一下:

    这个函数主要是根据系统的属性选择不同的配置文件,简单的画个系统属性和配置文件的关系图:

    【AudioPolicy To AudioHAL笔记(三)】安卓S上audio,系统属性与配置文件的关系,第1张

    这里我们主要分析第二个函数deserializeAudioPolicyFile.但在分析这个函数前需要了解一下知识:

    也就是audio_policy_config_file中child的概念,我画一张简图表示一下这个关系(以audio_policy_configuration.xml为例):

    【AudioPolicy To AudioHAL笔记(三)】安卓S上audio,audio_policy_config_file中child的概念,第2张

    看图应该不难分析,就是套娃又套娃。一个modules对应一个so文件,例如,这个就是对于一个primary HAL;其中一个module允许有多个设备列表。

    有上面的了解后,再看一下源码:

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
    {
        PolicySerializer serializer;
        status_t status = serializer.deserialize(fileName, config);   --> 重构+函数模板
        if (status != OK) config->clear();
        return status;
    }
    

    结合C++的语法,上面函数调用到:

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,
                                           bool ignoreVendorExtensions)
    {
        mIgnoreVendorExtensions = ignoreVendorExtensions;
        auto doc = make_xmlUnique(xmlParseFile(configFile));    --> 解析XML配置文件
        if (doc == nullptr) {
            ALOGE("%s: Could not parse %s document.", __func__, configFile);
            return BAD_VALUE;
        }
        xmlNodePtr root = xmlDocGetRootElement(doc.get());     --> 获取XML文档的根节点
        if (root == NULL) {
            ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
            return BAD_VALUE;
        }
        if (xmlXIncludeProcess(doc.get()) < 0) {               --> 处理XML文档中的XInclude指令
            ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
        }
        if (xmlStrcmp(root->name, reinterpret_cast(rootName)))  {   -->// 检查根节点的名称是否与"rootName = "audioPolicyConfiguration""的一致
            ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
                    reinterpret_cast(root->name));
            return BAD_VALUE;
        }
        std::string version = getXmlAttribute(root, versionAttribute);     --> 获取根节点的版本属性
        if (version.empty()) {
            ALOGE("%s: No version found in root node %s", __func__, rootName);
            return BAD_VALUE;
        }
        if (version == "7.0") {
            mChannelMasksSeparator = mSamplingRatesSeparator = mFlagsSeparator = " ";
        } else if (version != "1.0") {
            ALOGE("%s: Version does not match; expected \"1.0\" or \"7.0\" got \"%s\"",
                    __func__, version.c_str());
            return BAD_VALUE;
        }
        // Let's deserialize children
        // Modules
        ModuleTraits::Collection modules;
        status_t status = deserializeCollection(root, &modules, config);
        if (status != NO_ERROR) {
            return status;
        }
        config->setHwModules(modules);
        // Global Configuration
        deserialize(root, config);  --> 利用C++的函数模板语法调用到不同的deserialize
        // Surround configuration
        deserialize(root, config);
        return android::OK;
    }
    

    上面这个函数重点关注一下下面的语句,其是在这个函数中解析文件的:

    status_t status = deserializeCollection(root, &modules, config);
    其调用的函数是:
    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
    template 
    status_t PolicySerializer::deserializeCollection(const xmlNode *cur,
            typename Trait::Collection *collection,
            typename Trait::PtrSerializingCtx serializingContext)
    {
        --> 用两个for循环,遍历当前xml节点的所有子节点
        for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
            const xmlNode *child = NULL;
            if (!xmlStrcmp(cur->name, reinterpret_cast(Trait::collectionTag))) {
                child = cur->xmlChildrenNode;
            } else if (!xmlStrcmp(cur->name, reinterpret_cast(Trait::tag))) {
                child = cur;
            }
            for (; child != NULL; child = child->next) {
                if (!xmlStrcmp(child->name, reinterpret_cast(Trait::tag))) {
                    auto maybeElement = deserialize(child, serializingContext);
                    if (maybeElement.index() == 1) {
                        status_t status = Trait::addElementToCollection(
                                std::get<1>(maybeElement), collection);
                        if (status != NO_ERROR) {
                            ALOGE("%s: could not add element to %s collection", __func__,
                                Trait::collectionTag);
                            return status;
                        }
                    } else if (mIgnoreVendorExtensions && std::get(maybeElement) == NO_INIT) {
                        // Skip a vendor extension element.
                    } else {
                        return BAD_VALUE;
                    }
                }
            }
            if (!xmlStrcmp(cur->name, reinterpret_cast(Trait::tag))) {
                return NO_ERROR;
            }
        }
        return NO_ERROR;
    }
    

    单从函数分析并不难,找到对应模板的名字,然后再调用

    auto maybeElement = deserialize(child, serializingContext);
    

    最后的结果就是:

    /frameworks/av/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
    class AudioPolicyConfig
    {
    public:
        ....
    private:
        std::string mSource;
        std::string mEngineLibraryNameSuffix;
        HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
        DeviceVector &mOutputDevices;   // xm中所以output devices模块集合
        DeviceVector &mInputDevices;    //xml中所以input devices模块集合
        sp &mDefaultOutputDevice;   //默认的output device
        ...
    };
    

    推荐阅读:

    • https://www.twblogs.net/a/5d42bfc7bd9eee51fbf9ebab
    • https://anvydon.github.io/2020/09/01/Android%E9%9F%B3%E9%A2%91%E7%AD%96%E7%95%A5%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90/