【AudioPolicy To AudioHAL笔记(二)】AudioPolicy&AudioFliger To AudioHAL

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

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

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

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

在上篇文章中我们分析了new AudioPolicyManager(clientInterface, audiopolicymanager_IC_manu_name)的过程,但是却没有分析到AudioPolicyManger的一个初始化过程,本章就以AudioPolicy&AudioFliger To AudioHAL为线索进行分析:

c 复制代码
/frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
static AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
{
    ALOGE("%s Mylog_AP: new AudioPolicyManager !!! !", __func__);
    AudioPolicyManager *apm = new AudioPolicyManager(clientInterface, audiopolicymanager_IC_manu_name);
    ALOGE("%s Mylog_AP: new AudioPolicyManager done !", __func__);
    status_t status = apm->initialize();
    ALOGE("%s Mylog_AP: apm->initialize() !", __func__);
    ...
}

在上面的函数中,下面的语句就会使Framework C++ Native连接到IC_manu Audio HAL

c 复制代码
status_t status = apm->initialize();

在上面的语句中apm其实就是AudioPolicyManager的简称,这个函数最终会调到下面的函数:

c 复制代码
/frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::initialize() {
    {
...

    // after parsing the config, mOutputDevicesAll and mInputDevicesAll contain all known devices;
    // open all output streams needed to access attached devices
    onNewAudioModulesAvailableInt(nullptr /*newDevices*/);

    // make sure default device is reachable
    if (mDefaultOutputDevice == 0 || !mAvailableOutputDevices.contains(mDefaultOutputDevice)) {
        ALOGE_IF(mDefaultOutputDevice != 0, "Default device %s is unreachable",
                 mDefaultOutputDevice->toString().c_str());
        status = NO_INIT;
    }
...
}

其中onNewAudioModulesAvailableInt函数就会建立Framework JAVA Native To Audio HAL的关系,函数原型如下:

c 复制代码
xref: /frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
{
...
        hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));   // 加载音频硬件模块
        if (hwModule->getHandle() == AUDIO_MODULE_HANDLE_NONE) {
            ALOGW("could not open HW module %s", hwModule->getName());
            continue;
        }
...
}

loadHwModule的定义如下:

c 复制代码
xref: /frameworks/av/services/audioflinger/AudioFlinger.cpp
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
    if (name == NULL) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    if (!settingsAllowed()) {
        return AUDIO_MODULE_HANDLE_NONE;
    }
    Mutex::Autolock _l(mLock);
    AutoMutex lock(mHardwareLock);
    return loadHwModule_l(name);
}

其中loadHwModule_l的定义如下:

c 复制代码
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
            ALOGW("loadHwModule() module %s already loaded", name);
            return mAudioHwDevs.keyAt(i);
        }
    }

    sp<DeviceHalInterface> dev;

    int rc = mDevicesFactoryHal->openDevice(name, &dev);
...

}

重点关注这个openDevice函数,其会加载HAL并并将其封装在一个DeviceHalInterface对象中。

c 复制代码
status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    audio_hw_device_t *dev;
    status_t rc = load_audio_interface(name, &dev);
    if (rc == OK) {
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}

关注一下,这个选择加载HAL的过程,即函数load_audio_interface,它的原型如下:

c 复制代码
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
    const hw_module_t *mod;
    int rc;

    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
    if (rc) {
        ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__,
                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
        goto out;
    }
    rc = audio_hw_device_open(mod, dev);
    if (rc) {
        ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__,
                AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
        goto out;
    }
    if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
        ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
        rc = BAD_VALUE;
        audio_hw_device_close(*dev);
        goto out;
    }
    return OK;

out:
    *dev = NULL;
    return rc;
}

上面的函数中hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod)

就会获取HW Module的名字:

这个AUDIO_HARDWARE_MODULE_ID的定义就是Audio,原型如下:

c 复制代码
/hardware/libhardware/include/hardware/
H A D    audio.h    38 #define AUDIO_HARDWARE_MODULE_ID "audio"

参数"if_name"的数值在上层中传递下来,具体在函数AudioPolicyManager::onNewAudioModulesAvailableInt中传递,如下代码片段:

c 复制代码
 hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));    加载音频硬件模块

即参数"if_name"是"hwModule"的名字。

c 复制代码
 hwModule->getName()

这个名字通常具体在配置文件(*xml,例如Audio_policy_configuration.xml)中获取,通常有primary、A2dp、Usb、Remote Submix Audio这四种名字。见下篇文章分析。

继续分析源码:

c 复制代码
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);       
        //合成audio.primary或者audio.$moudle_name
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}

可以看到源码中还会获取property来具体确定调用那个HAL中了,获取的property是ro.hardware(没有则是:ro.product.board、ro.board.platform、ro.arch),查看板子这个property是什么:

c 复制代码
static const char *variant_keys[] = {
      "ro.hardware",  /* This goes first so that it can pick up a different
                         file on the emulator. */
      "ro.product.board",
      "ro.board.platform",
      "ro.arch"
};

板子的情况:

Android_S:/vendor/lib64/hw # ls audio*
audio.bluetooth.default.so  audio.primary.IC_manu_name.so  audio.r_submix.default.so   audio.r_submix.IC_name_1.so  audio_policy.stub.so
audio.primary.default.so    audio.primary.IC_name_1.so    audio.r_submix.IC_manu_name.so  audio.usb.default.so
Android_S:/vendor/lib64/hw #
Android_S:/vendor/lib64/hw # getprop ro.hardware
IC_name_2
Android_S:/vendor/lib64/hw # getprop ro.product.board
Android_S
Android_S:/vendor/lib64/hw # getprop ro.board.platform
IC_name_1
Android_S:/vendor/lib64/hw # getprop ro.arch

Android_S:/vendor/lib64/hw #

可见最终加载的是audio.primary.IC_name_1.so这个so文件,那么这个so文件哪里来的?在下面来的:

c 复制代码
\vendor\IC_manu_name\proprietary\hardware\audio

LOCAL_ARM_MODE := arm
LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_OWNER := IC_manu_name
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional

最终产物是audio.primary.IC_name_1.so

这个就是链接到IC_manu_name HAL那边了,后续可以通过这个so访问到IC_manu_name HAL。

相关推荐
波音彬要多做6 分钟前
41 stack类与queue类
开发语言·数据结构·c++·学习·算法
捕鲸叉6 分钟前
C++软件设计模式之外观(Facade)模式
c++·设计模式·外观模式
Swift社区14 分钟前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光18 分钟前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
丘狸尾19 分钟前
[cisco 模拟器] ftp服务器配置
android·运维·服务器
矛取矛求22 分钟前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生22 分钟前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it36 分钟前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
m0_7482567844 分钟前
WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
笔记·学习·开源
红色的山茶花1 小时前
YOLOv9-0.1部分代码阅读笔记-loss.py
笔记