Android 8.0(O)音频write数据流程变化(HIDL)

///Android 8.0(O)音频write数据流程变化(HIDL)

Android 8.0(O)音频write数据流程变化(HIDL)

简单回顾下,Audio write数据流程,
AudioTrack->write
AudioFlinger::PlaybackThread::threadLoop_write()
mNormalSink->write
而mNormalSink其实是NBAIO_Sink,实现类是:AudioStreamOutSink
那我们直接看
frameworks/av/media/libnbaio/AudioStreamOutSink.cpp

//AudioStreamOutSink::write节选
status_t ret = mStream->write(buffer, count * mFrameSize, &written);
//AudioStreamOutSink.h
sp mStream;

 

果然,mStream类型变成了StreamOutHalInterface(Android 5.1上是audio_stream_out类型)

然后,我们发现frameworks/av/media/底下多了个文件夹
libaudiohal

Android.mk DeviceHalLocal.h DevicesFactoryHalLocal.h EffectHalHidl.h EffectsFactoryHalLocal.h StreamHalLocal.h
ConversionHelperHidl.cpp DevicesFactoryHalHidl.cpp EffectBufferHalHidl.cpp EffectHalLocal.cpp HalDeathHandlerHidl.cpp
ConversionHelperHidl.h DevicesFactoryHalHidl.h EffectBufferHalHidl.h EffectHalLocal.h include
DeviceHalHidl.cpp DevicesFactoryHalHybrid.cpp EffectBufferHalLocal.cpp EffectsFactoryHalHidl.cpp StreamHalHidl.cpp
DeviceHalHidl.h DevicesFactoryHalHybrid.h EffectBufferHalLocal.h EffectsFactoryHalHidl.h StreamHalHidl.h
DeviceHalLocal.cpp DevicesFactoryHalLocal.cpp EffectHalHidl.cpp EffectsFactoryHalLocal.cpp StreamHalLocal.cpp

 

很明显,从文件名命名方式来看,一类是以Hidl结尾,一类是Local结尾,很明显!Local结尾的应该是兼容之前的方式,即谷歌在文档里描述的

https://source.android.com/devices/architecture/hidl/
Using passthrough mode(我翻译为直通模式)

StreamOutHalInterface的实现类就在这底下了:
class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl

继续write流程
StreamOutHalHidl::write
callWriterThread(WriteCommand::WRITE,…

//StreamOutHalHidl::callWriterThread
if (!mCommandMQ->write(&cmd)) {
ALOGE(“command message queue write failed for \”%s\””, cmdName);
return -EAGAIN;
}
if (data != nullptr) {
size_t availableToWrite = mDataMQ->availableToWrite();
if (dataSize > availableToWrite) {
ALOGW(“truncating write data from %lld to %lld due to insufficient data queue space”,
(long long)dataSize, (long long)availableToWrite);
dataSize = availableToWrite;
}
if (!mDataMQ->write(data, dataSize)) {
ALOGE(“data message queue write failed for \”%s\””, cmdName);
}
}

 

mDataMQ:
typedef MessageQueue<uint8_t, hardware::kSynchronizedReadWrite> DataMQ;
看本文件的顶部:
#include <fmq/MessageQueue.h>
好吧。fmq!

先看看WriteCommand

//StreamHalHidl.h
using WriteCommand = ::android::hardware::audio::V2_0::IStreamOut::WriteCommand;

 

到这里很明显能看出Binder化的痕迹了。这是要开始跨进程调用了!
fmq(Fast Message Queue)就是实现这种跨进程的关键!
编译hardware/interfaces/audio模块的输出:
/out/soong/.intermediates/hardware/interfaces/audio/2.0/android.hardware.audio@2.0_genc++/gen/android/hardware/audio/2.0目录下面:
DeviceAll.cpp DevicesFactoryAll.cpp PrimaryDeviceAll.cpp StreamAll.cpp StreamInAll.cpp StreamOutAll.cpp StreamOutCallbackAll.cpp types.cpp
这些文件自动生成出来,然后可以实现audioflinger通过libaudiohal模块,binder化地调用hal!

现在回到:
/hardware/interfaces/audio/2.0/
default里已经有一堆实现好的代码了(server端)
还是用write接口举例:

//WriteThread::threadLoop
case IStreamOut::WriteCommand::WRITE:
doWrite();

 

让我们看看doWrite中:

//StreamOut.cpp
ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
//StreamOut.h
audio_stream_out_t *mStream;

 

嗯!就是熟悉的它!!!
接下来,通过函数指针,白转千回找到
hardware/qcom/audio/hal/audio_hw.c
调用out_write函数,然后调用pcm_write从而进入tinyAlsa驱动的流程就不表了,和以前的流程应该大同小异。

和Android O以前的机制相比,其实多了一个将命令写入FMQ,然后FMQ引擎取出命令进行响应的过程。这个过程就实现了hal层的binder化。
hardware/interfaces文件夹下的各种硬件,定义了各自的HIDL接口,还要规定版本号(版本化)。
通过rc文件,在系统加载的时候被include到init.rc文件里,然后被启动,实现系统级别的service。时刻响应FW端的远程Binder调用。
FW开发者和HW开发者各自只需了解interface(名字,版本号),然后进行开发。这样就实现了FW和HW的分离!

2018-03-16T17:27:57+08:00 三月 16th, 2018|Android开发|0 条评论

评一波