【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。

相关推荐
未来可期LJ27 分钟前
【C++ 设计模式】单例模式的两种懒汉式和饿汉式
c++·单例模式·设计模式
Trouvaille ~1 小时前
【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略
c++·c++20·编译原理·编译器·类和对象·rvo·nrvo
little redcap1 小时前
第十九次CCF计算机软件能力认证-乔乔和牛牛逛超市
数据结构·c++·算法
开MINI的工科男1 小时前
【笔记】自动驾驶预测与决策规划_Part3_路径与轨迹规划
人工智能·笔记·自动驾驶·预测与决策
AI原吾2 小时前
掌握Python-uinput:打造你的输入设备控制大师
开发语言·python·apython-uinput
机器视觉知识推荐、就业指导2 小时前
Qt/C++事件过滤器与控件响应重写的使用、场景的不同
开发语言·数据库·c++·qt
毕设木哥2 小时前
25届计算机专业毕设选题推荐-基于python的二手电子设备交易平台【源码+文档+讲解】
开发语言·python·计算机·django·毕业设计·课程设计·毕设
珞瑜·2 小时前
Matlab R2024B软件安装教程
开发语言·matlab
weixin_455446172 小时前
Python学习的主要知识框架
开发语言·python·学习
孤寂大仙v2 小时前
【C++】STL----list常见用法
开发语言·c++·list