AudioFlinger 如何通过 hwBinder 调用 Audio HAL

68 篇文章 13 订阅
12 篇文章 0 订阅

AudioFlinger 如何通过 hwBinder 调用 Audio HAL

注意:本文基于 Android 8.1 进行分析
Qidi 2020.07.03 (Markdown & Haroopad)


我们已经知道,在AudioPolicyManager构造时,会解析配置文件audio_policy.confaudio_policy_configuration.xml。之后,它会获取到AudioFlinger的实例,并根据解析结果,调用loadHwModule()依次加载各个 audio HAL。

因此,AudioFlinger与 Audio HAL 建立联系的过程一定能在它内部的代码中找到。让我们直接从AudioFlinger的代码开始分析:

AudioFlinger::AudioFlinger()
    : BnAudioFlinger(),
      mMediaLogNotifier(new AudioFlinger::MediaLogNotifier()),
      mPrimaryHardwareDev(NULL),
      mAudioHwDevs(NULL),
      //...
{
    //...
    // 初始化 mDevicesFactoryHal
    mDevicesFactoryHal = DevicesFactoryHalInterface::create();
    //...
}

// loadHwModule_l() must be called with AudioFlinger::mLock held
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;

    // 以 Legacy 方式或 Binder 方式,真正加载 Audio HAL 的入口
    int rc = mDevicesFactoryHal->openDevice(name, &dev);
    if (rc) {
        ALOGE("loadHwModule() error %d loading module %s", rc, name);
        return AUDIO_MODULE_HANDLE_NONE;
    }

    //...
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));

    ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);

    return handle;

}

我们看到 AudioFlinger::loadHwModule_l() 调用了mDevicesFactoryHal->openDevice(),而实际上 mDeviceFactoryHal 是类DevicesFactoryHalHybrid的一个实例。
在源文件 /frameworks/av/media/libaudiohal/DevicesFactoryHalHybrid.cpp 里,我们可以看到类的实现:

sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
    return new DevicesFactoryHalHybrid();
}

// DevicesFatoryHalHybrid 类的作用是对 mLocalFactory 和 mHidlFactory 进行包裹,
// 而这两个成员实际上都是 sp<DevicesFactoryHalInterface> 类型
DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
        : mLocalFactory(new DevicesFactoryHalLocal()),
          mHidlFactory(
#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
                  nullptr
#else
                  new DevicesFactoryHalHidl()
#endif
                       ) {
}

DevicesFactoryHalHybrid::~DevicesFactoryHalHybrid() {
}

status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    // 当目标不是 A2DP HAL, 且宏 USE_LEGACY_LOCAL_AUDIO_HAL 未定义时,
    // 始终使用 hwbinder 方式获取 Audio HAL
    //
    // 以我所开发的设备为例, 宏 USE_LEGACY_LOCAL_AUDIO_HAL 在 BoardCongif_common.mk 中
    // 被定义为 false
    if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0) {
        return mHidlFactory->openDevice(name, device);
    }
    return mLocalFactory->openDevice(name, device);
}

顺带一提,这里可以看到通过定义宏USE_LEGACY_LOCAL_AUDIO_HAL,我们可以强制AudioFlinger不使用 hwBinder 访问 Audio HAL,而是采用老方法加载*.so库文件。这个宏一般定义在BoardConfig.mk文件中。但需要注意,即便使用加载库的方式也稍稍有了变化:以前 AudioFlinger 通过 dlopen() 直接加载,现在变成了调用 vndk 接口 android_load_sphal_library()来实现。

闲话休题。到了这里实际依然还没抵达 hwBinder 的入口,而是继续调用了 DevicesFactoryHalHybrid 的成员接口 openDevice()。层层深入,再来看看 DevicesFactoryHalHidl 类中的实现:

status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    if (mDevicesFactory == 0) return NO_INIT;
    IDevicesFactory::Device hidlDevice;
    status_t status = nameFromHal(name, &hidlDevice);
    if (status != OK) return status;
    Result retval = Result::NOT_INITIALIZED;
    // 此处的 openDevice() 会调用到 BpHwDevicesFactory::openDevice() 中,
    // BpHwDevicesFactory 的实现代码是在编译时由 soong 自动生成的
    Return<void> ret = mDevicesFactory->openDevice(
            hidlDevice,
            // 该 lamda 函数作为回调函数传入 Bp 端,
            // 当 Binder 调用完成时,该 lamda 函数会被调用
            [&](Result r, const sp<IDevice>& result) {
                retval = r;
                if (retval == Result::OK) {
                    *device = new DeviceHalHidl(result); // result 是从 Binder 调用完成后返回的 IDevice 实例
                }
            });
    if (ret.isOk()) {
        if (retval == Result::OK) return OK;
        else if (retval == Result::INVALID_ARGUMENTS) return BAD_VALUE;
        else return NO_INIT;
    }
    return FAILED_TRANSACTION;
}

终于,在这里面我们看到了另一个 openDevice(),它属于 IDevicesFactory,这就是和 audio HAL 相关的具体的 hwBinder 接口类了。这个类相应的代码实际上是在编译时自动生成的,源文件(或者说接口定义文件,HIDL 本来也是这个含义)中只有对接口的定义,位于 /hardware/interfaces/audio/2.0/IDevicesFactory.hal 中:

package android.hardware.audio@2.0;

import android.hardware.audio.common@2.0;
import IDevice;

interface IDevicesFactory {
    typedef android.hardware.audio@2.0::Result Result;

    enum Device : int32_t {
        PRIMARY,
        A2DP,
        USB,
        R_SUBMIX,
        STUB
    };

    /**
     * Opens an audio device. To close the device, it is necessary to release
     * references to the returned device object.
     *
     * @param device device type.
     * @return retval operation completion status. Returns INVALID_ARGUMENTS
     *         if there is no corresponding hardware module found,
     *         NOT_INITIALIZED if an error occured while opening the hardware
     *         module.
     * @return result the interface for the created device.
     */
    openDevice(Device device) generates (Result retval, IDevice result);
};

编译时,上方的 .hal 文件会转换成相应的 .cpp.h 文件。这些文件均可以对应在 /out/soong/.intermediates/hardware/interfaces/audio/2.0/ 路径下找到。这里我们简要查看 openDevice() 接口相关的生成代码,看看都做了些什么:

// Methods from IDevicesFactory follow.
::android::hardware::Return<void> BpHwDevicesFactory::_hidl_openDevice(::android::hardware::IInterface *_hidl_this, ::android::hardware::details::HidlInstrumentor *_hidl_this_instrumentor, IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
    #ifdef __ANDROID_DEBUGGABLE__
    //...
    #else
    (void) _hidl_this_instrumentor;
    #endif // __ANDROID_DEBUGGABLE__
    //...
    #endif // __ANDROID_DEBUGGABLE__

    ::android::hardware::Parcel _hidl_data;
    ::android::hardware::Parcel _hidl_reply;
    ::android::status_t _hidl_err;
    ::android::hardware::Status _hidl_status;

    Result _hidl_out_retval;
    ::android::sp<IDevice> _hidl_out_result;

    _hidl_err = _hidl_data.writeInterfaceToken(BpHwDevicesFactory::descriptor);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = _hidl_data.writeInt32((int32_t)device);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    // (生成代码)执行 transact 调用, 传入 command code 1 (openDevice)
    _hidl_err = ::android::hardware::IInterface::asBinder(_hidl_this)->transact(1 /* openDevice */, _hidl_data, &_hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    _hidl_err = ::android::hardware::readFromParcel(&_hidl_status, _hidl_reply);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    if (!_hidl_status.isOk()) { return _hidl_status; }

    _hidl_err = _hidl_reply.readInt32((int32_t *)&_hidl_out_retval);
    if (_hidl_err != ::android::OK) { goto _hidl_error; }

    {
        ::android::sp<::android::hardware::IBinder> _hidl__hidl_out_result_binder;
        // (生成代码)获得 audio HAL binder 实例
        _hidl_err = _hidl_reply.readNullableStrongBinder(&_hidl__hidl_out_result_binder);
        if (_hidl_err != ::android::OK) { goto _hidl_error; }

        // 获得 audio device 实例
        _hidl_out_result = ::android::hardware::fromBinder<IDevice,BpHwDevice,BnHwDevice>(_hidl__hidl_out_result_binder);
    }

    // 调用回调函数(也就是前面的 lamda 函数)将 audio device 实例传回上层
    _hidl_cb(_hidl_out_retval, _hidl_out_result);

    atrace_end(ATRACE_TAG_HAL);
    #ifdef __ANDROID_DEBUGGABLE__
    //...
    #endif // __ANDROID_DEBUGGABLE__

    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<void>();

_hidl_error:
    _hidl_status.setFromStatusT(_hidl_err);
    return ::android::hardware::Return<void>(_hidl_status);
}

能看出来,这些自动生成的代码仍然是使用的 Parcel.writeXXX --> asBinder()/remote() --> transact() --> BinderDriver --> onTransact() --> Parcel.readXXX 那一套。(实际上,binder, hwbinder 和 vndbinder 共用一套 Binder 类关系和代码逻辑)

至此,AudioFlinger 便获得了 audio HAL 的 Bp 端实例,通过它即可自由调用 audio HAL 任意接口。以 setMasterVolume() 为例:

status_t AudioFlinger::setMasterVolume(float value)
{
    //...
    // Set master volume in the HALs which support it.
    for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
        AutoMutex lock(mHardwareLock);
        AudioHwDevice *dev = mAudioHwDevs.valueAt(i);

        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
        if (dev->canSetMasterVolume()) {
            // 通过 audio device 实例调用 Audio HAL 中实现的 setMasterVolume() 接口
            // 实际执行时依然以 HIDL 方式经过 hwBinder 完成
            dev->hwDevice()->setMasterVolume(value);
        }
        mHardwareStatus = AUDIO_HW_IDLE;
    }

    //...
    return NO_ERROR;
}

最后,我们再一起通过下方的类图,回顾和理清刚刚提到的几个类之间的关系吧:
在这里插入图片描述

AudioFlingerAndroid平台上的一个系统服务,它主要负责管理所有的音频数据和音频设备,包括音频采集、音频处理、音频输出等。它与应用程序、音频设备驱动程序及硬件抽象层(HAL)进行交互,从而实现音频的输入、处理和输出。 与HAL的交互:AudioFlinger通过HAL与底层音频硬件进行交互。HAL是一种硬件抽象层,它为上层的AudioFlinger提供了一种与底层音频硬件进行通信的标准接口。HAL层可以根据不同的硬件平台、不同的设备需求等进行适配,并将这些信息提供给AudioFlingerAudioFlinger可以通过HAL层来控制不同的音频硬件设备,例如麦克风、扬声器等。 与应用程序的交互:应用程序可以通过Android提供的音频API调用AudioFlinger服务,从而控制音频的输入、处理和输出。例如,应用程序可以使用AudioRecord类来录制音频数据,使用AudioTrack类来播放音频数据。这些类都是通过与AudioFlinger进行交互来实现音频的输入和输出。 与音频设备驱动程序的交互:音频设备驱动程序是在HAL层之下的一层软件,它主要负责控制音频硬件设备的操作。AudioFlinger可以通过与音频设备驱动程序的交互来控制音频设备的采样率、位深度、声道数等属性,从而实现更加精细的音频处理。 总之,AudioFlingerAndroid平台上非常重要的音频管理服务,它通过与HAL、应用程序和音频设备驱动程序进行交互,实现了音频的输入、处理和输出。这些交互的方式也为应用程序开发者提供了更加灵活的音频控制和处理方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值