基于安全加强的考虑, 自Android6.0后,Audio模块便从 mediaserver进程中分离开,作为独立的进程运行,是为audioserver进程。
那么audioserver入口在哪呢?通过源码文件查找,我们找到了其模块位置
frameworks/av/media/audioserver
看下有那些文件组成, 使用tree
命令
android6.0以后, google将init.rc文件做了拆分, 由模块独立管理其rc文件,不再由init进程集中管理, 这里audioserver.rc
便是audio系统的启动文件, 看下其内容
[–> audioserver.rc]
# 作为service启动,说明启动路径
service audioserver /system/bin/audioserver
# 核心
class core
#用户为audioserver
user audioserver
# media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
onrestart restart vendor.audio-hal-2-0
# Keep the original service name for backward compatibility when upgrading
# O-MR1 devices with framework-only.
onrestart restart audio-hal-2-0
on property:vts.native_server.on=1
stop audioserver
on property:vts.native_server.on=0
start audioserver
再看audioserver的启动入口main函数
[–>main_audioserver.cpp]
int main(int argc __unused, char **argv)
{
// 限制audioserver内存使用上限
limitProcessMemory(
"audio.maxmem", /* "ro.audio.maxmem", property that defines limit */
(size_t)512 * (1 << 20), /* SIZE_MAX, upper limit in bytes */
20 /* upper limit as percentage of physical RAM */);
signal(SIGPIPE, SIG_IGN);
bool doLog = (bool) property_get_bool("ro.test_harness", 0);
pid_t childPid;
//是否启动子进程启动log记录,这里不是流程分析关注点
if (doLog && (childPid = fork()) != 0) {
......
} else {
// all other services
......
android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
//(1) 启动AF
AudioFlinger::instantiate();
//(2) 启动APS
AudioPolicyService::instantiate();
.......
//(3)和语音唤醒及识别有关的服务
SoundTriggerHwService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
}
好了,看到了AF和APS启动的身影了,那么进入其instantiate
函数看下其初始化都做了哪些事吧
先看下AF的初始化
然而,我们在AudioFlinger.cpp文件中并没在找到instantiate
函数,那么想必定义在其父类,AudioFlinger类继承关系如下
[–>AudioFlinger.h]
class AudioFlinger :
public BinderService<AudioFlinger>,
public BnAudioFlinger {
}
我们在BinderService
模板类中找到了instantiate
函数的定义
[–>BinderService.h]
template<typename SERVICE>
class BinderService
{
public:
//(1) 创建服务对象并加入到Sm中
static status_t publish(bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
dumpFlags);
}
static void publishAndJoinThreadPool(
bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
publish(allowIsolated, dumpFlags);
joinThreadPool();
}
//(2)静态方法调用
static void instantiate() { publish(); }
.......
};
}; // namespace android
instantiate
静态方法直接调用publish
创建对象,并加入到ServiceManager中,便于其他模块路由到AF模块。
看下AF生命周期相关的三个函数, 构造函数AudioFlinger、onFirstRef在类初始化调用,~AudioFlinger是析构函数,类销毁时调用。
[–>AudioFlinger.cpp]
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),
mMediaLogNotifier(new AudioFlinger::MediaLogNotifier()),
mPrimaryHardwareDev(NULL), //主硬件设备, audio_policy_configuration.xml配置的
mAudioHwDevs(NULL), //所有硬件设备, audio_policy_configuration.xml配置的
mHardwareStatus(AUDIO_HW_IDLE),
mMasterVolume(1.0f),
mMasterMute(false),
// mNextUniqueId(AUDIO_UNIQUE_ID_USE_MAX),
mMode(AUDIO_MODE_INVALID),
mBtNrecIsOff(false),
mIsLowRamDevice(true),
mIsDeviceTypeKnown(false),
mTotalMemory(0),
mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes),
mGlobalEffectEnableTime(0),
mSystemReady(false)
{
// unsigned instead of audio_unique_id_use_t, because ++ operator is unavailable for enum
for (unsigned use = AUDIO_UNIQUE_ID_USE_UNSPECIFIED; use < AUDIO_UNIQUE_ID_USE_MAX; use++) {
// zero ID has a special meaning, so unavailable
mNextUniqueIds[use] = AUDIO_UNIQUE_ID_USE_MAX;
}
getpid_cached = getpid();
const bool doLog = property_get_bool("ro.test_harness", false);
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
MemoryHeapBase::READ_ONLY);
(void) pthread_once(&sMediaLogOnce, sMediaLogInit);
}
// reset battery stats.
// if the audio service has crashed, battery stats could be left
// in bad state, reset the state upon service start.
BatteryNotifier::getInstance().noteResetAudio();
//设备Hal加载使用,设备加载使用了懒加载,看openOutput >> openOutput_l >> findSuitableHwDev_l >>outHwDev->openOutputStream
mDevicesFactoryHal = DevicesFactoryHalInterface::create();
mEffectsFactoryHal = EffectsFactoryHalInterface::create();
mMediaLogNotifier->run("MediaLogNotifier");
......
}
void AudioFlinger::onFirstRef()
{
Mutex::Autolock _l(mLock);
/* TODO: move all this work into an Init() function */
char val_str[PROPERTY_VALUE_MAX] = { 0 };
if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
......
}
mPatchPanel = new PatchPanel(this);
mMode = AUDIO_MODE_NORMAL;
//保存全局引用
gAudioFlinger = this;
}
AudioFlinger::~AudioFlinger()
{
//关闭reocrd线程
while (!mRecordThreads.isEmpty()) {
// closeInput_nonvirtual() will remove specified entry from mRecordThreads
closeInput_nonvirtual(mRecordThreads.keyAt(0));
}
//关闭playback线程
while (!mPlaybackThreads.isEmpty()) {
// closeOutput_nonvirtual() will remove specified entry from mPlaybackThreads
closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
}
//回收硬件设备占用内存
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
// no mHardwareLock needed, as there are no other references to this
delete mAudioHwDevs.valueAt(i);
}
// Tell media.log service about any old writers that still need to be unregistered
if (sMediaLogService != 0) {
.......
}
}
AF的初始化我们找到了,那么我们继续跟踪
Android Audio System深入探究之AudioTrack
中AF创建Track的流程吧,AT中调用AF的createTrack是Binder调用,代码如下:
[–>AudioTrack.cpp]
......
IAudioFlinger::CreateTrackOutput output;
//(1) Binder调用AF的createTrack方法
sp<IAudioTrack> track = audioFlinger->createTrack(input,
output,
&status);
......
继续看标号(1)处的调用
[–>AudioFlinger.cpp]
sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
CreateTrackOutput& output,
status_t *status) {
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
......
//Binder调用APS,根据input参数获取output相关参数
lStatus = AudioSystem::getOutputForAttr(&input.attr, &output.outputId, sessionId, &streamType,
clientPid, clientUid, &input.config, input.flags,
&output.selectedDeviceId, &portId);
,,,,,,
//(1)这里直接根据outputId拿到了PlaybackThread线程,那么PlayBackThread线程在哪创建的呢?
PlaybackThread *thread = checkPlaybackThread_l(output.outputId);
......
//在PlaybackThread中创建track
track = thread->createTrack_l(client, streamType, input.attr, &output.sampleRate,
input.config.format, input.config.channel_mask,
&output.frameCount, &output.notificationFrameCount,
input.notificationsPerBuffer, input.speed,
input.sharedBuffer, sessionId, &output.flags,
input.clientInfo.clientTid, clientUid, &lStatus, portId);
......
// return handle to client
trackHandle = new TrackHandle(track);// (2)注意,其对象实例没有在AF中保存, TrackHandle对象是什么?
......
return trackHandle;
}
AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
{
return mPlaybackThreads.valueFor(output).get();
}
上面的代码有两个问题
(1)PlaybackThread在哪创建的呢?
(2)TrackHandle对象是什么?
针对问题:PlaybackThread在哪创建的呢?
我们首先在AF代码先找找,看看有没有PlayBackThread创建的线索
openOutput
中调用了openOutput_l
, 主要工作在openOutput_l
中完成
我们在AF的openOutput_l函数中找到一些线索
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
......
//(1)找到合适的输出设备
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
......
// (2) 打开输出流
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
......
//创建PlaybackThread, 通过源码我们可知OffloadThread、DirectOutputThread及 MixerThread 都是
//PlaybackThread的子类
//根据flags, 不做特殊设置情况下,我们走的是Mix线程
if (status == NO_ERROR) {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
//注意`checkPlaybackThread_l`调用就是从这里找到的PlaybackThread
mPlaybackThreads.add(*output, thread);
return thread;
}
}
上面的标号(1)、(2)、(3) 暴露了音频放音的重要步骤流程, 打开设备、创建输出流、创建放音线程, 那剩下的工作不就是向输出流写入数据了吗。
那么问题又来了,AudioFlinger->openOutput_l又是被谁调用的呢?
通过代码追踪,我们发现 openOutput_l函数调用原来实在APS初始化时完成,APS初始化时,会读取audio_policy.conf文件,解析HwModule、Device 的profile等信息,然后通过调用AF的openOutput打开相关的设备。
[–>AudioPolicyClientImpl.cpp]
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
......
//调用AF的openOutput函数
return af->openOutput(module, output, config, devices, address, latencyMs, flags);
APS的初始化流程参考如下
Android Audio System深入探究之AudioPolicyService
AF中createTrack返回的是TrackHandle对象,它以Track为参数构造。那么两者有什么关系呢?
TrackHandle代理
通过查看源码我们得知,android这里使用了Proxy模式,即TrackHandle是Track的代理,那么TrackHandle实现了怎样的代理呢?
(1)Track没有BInder通信,不能接收来自远端进程的请求。
(2)TrackHandle能基于Binder通信,它可以接收来自远端进程的请求,能够调用Track对应的函数。
那么Android为什么不直接让Track从IBinder派生,直接支持Binder通信呢?
职责分担
从查看代码我们得知,Track承担的职责非常重,如果再承担Binder通信的任务,可能整个类将显得无比巨大,逻辑也变得很复杂。
AF是Audio系统核心,看下其继承关系:
[–> AudioFlinger.h]
class AudioFlinger :
public BinderService<AudioFlinger>,
public BnAudioFlinger
{
......
}
AudioFlinger主要工作由其许多内部类完成,看下其内部类构成吧。图中大括号是包含与被包含的关系。
相关类功能介绍:
PlaybackThread: 放音线程,用于音频输出。
RecordThread:录音线程,用于音频输入。
PlaybackThread有三个派生类
MixerThread: 混音线程,它将来自多个源的音频数据混合后再输出。
DirectOutputThread:直接输出线程,它会选择一路音频流将数据直接输出,由于没有混音,可以减少很多延时。
DuplicatingThread:多路输出线程,它从MixerThread派生,意味着他也能混音。它最终会把混音后的数据写道多个输出中,也就是一份数据多个接收者。这就是Duplicate含义。在蓝牙A2DP设备输出有使用。
另外从下图中AF Thread的UML图还可以看出:
PlaybackThread维护两个Track列表,一个mActiveTracks,表示当前活跃的Track; 另一个mTracks,表示这个线程创建的所有Track。
DuplicatingThread还维护了一个mOutputTracks, 表示多路输出的目的端。
在上面UML图中,我们可以发现PlaybackThread线程有一个AudioStreamOutput类型对象,这个对象提供了音频数据输出功能。下面的图大致可以示意音频数据的流动轨迹。以最常用的MixThread为代表。
根据上图可以大致描述MixerThread线程的工作流程:
工作线程中最重要的工作是围绕Track展开的,看下Track家族组成。
TrackHandle和RecordHandle是基于BInder通信的,作为Server端的Proxy,接收来自Client的请求并派发到对应的Track和RecordTrack。
Track类作为工作线程的内部类来实现的,其中: