Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

Android Native Service 初始化笔记

Atom 2020-02-14 16:08:52 阅读数:42 评论数:0 点赞数:0 收藏数:0

这是很早前写的一片文章,已忘了代码是安卓几了,应该是5吧。
注意:对比最新的安卓,又添加了好多东西,我又懒得整理最新的代码,
但是大致的流程是OK的,有需要的可对比看

1. mediaserver

main_mediaserver.cpp (frameworks\av\media\mediaserver)
int main(int argc __unused, char** argv)
{
...
if (doLog && (childPid = fork()) != 0) {
...
} else {
....
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
#ifdef AUDIO_LISTEN_ENABLED
ALOGI("ListenService instantiated");
ListenService::instantiate();
#endif
AudioPolicyService::instantiate();
.....
}
}

XXX::instantiate()
继承自BinderService的模板类
最终通过sm->addservice()创建服务(这里就在构造相应的类了)并添加到sm中。

static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
......
static void instantiate() { publish(); }

2. AudioFlinger init

注意BnAudioFlinger继承自RefBase, IServiceManager::addService()第二个参数为强引用

AudioFlinger::instantiate(); --> ... -> AudioFlinger::AudioFlinger()
可其构造函数只是做了一些变量的初始化。
那么是就在这儿就停了还是在哪儿又继续了呢?

前面提过addService()第二个参数为强引用,所以会调用onFirstRef(), 在这里会继续初始化,看
void AudioFlinger::onFirstRef()
也没什么内容,就是对
mStandbyTimeInNsecs和mPatchPanel赋值
然后AudioFlinger初始化就完成了

3. AudioPolicyService init

接着可以继续分析AudioPolicyService::instantiate();
注意
AudioPolicyService会根据用户配置(audio_policy.conf)来指导AF加载设备接口

AudioPolicyService::AudioPolicyService()
构造函数也没做什么实质的事情。

同样APS继承自RefBase,会调用onFirstRef()

AudioPolicyService::onFirstRef()
+--> // start tone playback thread mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
+ // start audio commands thread
+ // start output activity command thread
+ mAudioPolicyClient = new AudioPolicyClient(this); //这里在构造里把this传给了APClient的mAudioPolicyService
+ mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); --> new AudioPolicyManager(clientInterface)
+ 然后new了个音效 // load audio processing modules, new AudioPolicyEffects();
+ 到此APS的onFirstRef内容也没了。

接下来自然想到的是要看new AudioPolicyManager(clientInterface)
和new AudioPolicyEffects()的构造函数里都有什么。

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ mForceUse[i] = AUDIO_POLICY_FORCE_NONE; //mForceUse数组的初始化
| mDefaultOutputDevice = new DeviceDescriptor(String8(""), AUDIO_DEVICE_OUT_SPEAKER); //默认的输出设备
| loadAudioPolicyConfig() 以/vendor/etc /system/etc的顺序解析audio_policy.conf,没有就给个默认的
| +--> loadHwModules() 这个就是具体解析audio config,具体不分析了,最后加到mHwModules, mOutputProfiles, mInputProfiles
| +--> loadGlobalConfig()
| initializeVolumeCurves(); //音阶曲线初始化 //这个应该在音量计算时会用到,以后再看。
| *** 解析完laudio_policy.conf,然后通过 for 循环,遍历各个module的output/input,该打开的就打开,这个单独列出来 ***
+ 后面好像也没什么事情做了。

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)里对各模块的遍历是个重点,好多事情都在这里面发生。
下面只以primary的module为例分析
注意刚才的loadHwModule()是APM的,下面也有个loadHwModule(),
不过却是通过client, 最终调到的AF的loadHwModule(), 这两个不要混淆了。
从功能上来说APM::loadHwModule()是解析audio_policy.conf文件,
AF::loadHwModule()的主要为加载HAL对应的lib库并做相应的初始化

mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
^ +--> mpClientInterface 是APS第一次引用是传下来的那个,以AudioPolicyClientImpl.cpp为中转
+ +-->... af->loadHwModule(name);
+ +-->....反正经过什么binder到了AudioFlinger::loadHwModule()
+ +--> settingsAllowed() 权限检查
+------------------<--+ 返回loadHwModule_l(name) 这里是audio_module_handle_t类型
| +--> AudioFlinger::loadHwModule_l()
| +--> 已经加载过,返回已加载的记录mAudioHwDevs.keyAt(i)
| + load_audio_interface(name, &dev)
| | +--> hw_get_module_by_class() 谷歌搞出来的东西,具体不说了,反正就是根据传的ID加载应对的libxxx.so,注意这里已经属于AHAL范围了
| | | audio_hw_device_open()
| | | +--> module->methods->open() 调用module的open方法
| | | +--> adev_open()
| | | +--> 一大堆的函数和变量的初始化
| | | | voice_init()
| | | | platform_init() --> 与平台相关的初始化,主要就是xml acdb的初始化,会与驱动打交道,具体不列了。
| | | | audio_extn_listen_init()
| | | | audio_extn_sound_trigger_init()
| | | | 可视化和offload音效加载
| | +--> +--> audio_extn_utils_update_streams_output_cfg_list() Android 5.0增加了个这么个东西,与output config有关,不知拿来干嘛的。
| + 如果是第一次加载并且HAL支持master volume/mute, 则使用主HAL提供的做为当前的master volue/mute设置
| + audio_module_handle_t handle = nextUniqueId();
| + mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
| + 上面两句就是生成唯一的标识,然后new了个AudioHwDevice(),传进了HAL所获得的dev,相当于进行了C++类和C调用的转换
| + 然后把handle和设备加到mAudioHwDevs向量里,这样就有了handle和AudioHwDevice()或者说HAL模块的一一对应关系
^ + 以后通过查找handl就可以找到对应的HAL操作
+----------+--> return handle;注意这是module的handle

module处理完了,又通过两个子的for循环,分别处理OutputProfiles和InputProfiles

对outputprofile的处理,注意下面这句

if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
continue;
}

也就是说有direct flag的都略过了, 后面的openoutput打开的其实只有primary和low_latency以及voice_tx的设备,
voice_tx这个名字很奇怪,我觉得应该是input设备,为什么要放在output里呢?不明白。
然后根据outProfile生成了个类 new AudioOutputDescriptor();

AudioPolicyManager.cpp
for mHwModules
for mHwModules[i]->mOutputProfiles
sp<AudioOutputDescriptor> outputDesc = new AudioOutputDescriptor(outProfile);
然后重点是 openOutput()打开输入流
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = outputDesc->mSamplingRate;
config.channel_mask = outputDesc->mChannelMask;
config.format = outputDesc->mFormat;
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
+--> 也是通过AudioPolicyClientImpl.cpp中转
+--> 最终调用 af->openOutput()
+--> sp<PlaybackThread> thread = openOutput_l(module, output, config, *devices, address, flags); //注意返回的是个线程
| ^ +--> findSuitableHwDev_l() 从上面AF加载module的向量mAudioHwDevs里查找
| | + audio_hw_device_t *hwDevHal = outHwDev->hwDevice();也就是指向HAL的那一大堆函数
| | + *output = nextUniqueId(); 如果handler为空,则生成个(初始化传下来的为空)。
| | + hwDevHal->open_output_stream() AHAL中那一大堆函数中的open_output_stream()
| | + +--> adev_open_output_stream()
| | | +--> 根据传进去的out, config和别的进行一大堆的初始化
| | | | 与流相关的一大堆函数初始化,这些函数以out_开头,
| | | | (而不是加载module的与adev_开头), 也就是说与module/设备相关的以
| | | | adev_开关,与流相关的以out_/in_开头。
| | | +--> 从代码上看,没打开kernel的流,即这个open_output_stream并不是要打开硬件流。
| | + AudioStreamOut *outputStream = new AudioStreamOut(outHwDev, outStream, flags); 根据打开的strem和hwdev,又new了个新的东东,将他们关联起来。
| | + 根据flag生成相应的线程
| | + 如果有AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD => new OffloadThread()
| | + AUDIO_OUTPUT_FLAG_DIRECT => new DirectOutputThread()
| | + 否则生成new MixerThread()
| | + ********还记得for循环里如果有direct flag则略过没? 所以应该初始化时只生成了MixerThread() *******
| | + 这几个thread以后有需要再看构造了什么。
| ^ + mPlaybackThreads.add(*output, thread); 将handler与thead对应,加到播放线程向量里
| +---+--> return thread;
+ // notify client processes of the new output creation
+ thread->audioConfigChanged(AudioSystem::OUTPUT_OPENED);通知IO改变了,这个代码看得有点晕,以后再看。
+--> mPrimaryHardwareDev->hwDevice()->set_mode(mPrimaryHardwareDev->hwDevice(), mMode);如果flags有primary,再设置下模式。
然后如果有 AUDIO_OUTPUT_FLAG_PRIMARY mPrimaryOutput = output;
addOutput(output, outputDesc); //将output流的handler (AF::openOutput_l()生成)与描述关联
setOutputDevice(); //设置输出,具体的不看了。

outputprofile 处理完后又是InputProfile
过程大致也差不多,具体不看了。
然后对错误的处理,
再调用updateDevicesAndOutputs();更新下也就构造完了


总结APM构造干的事情:
解析audio_policy.conf
根据解析出来的module,加载对应的lib
继续处理解析结果中的outputprofile, inputprofile,打开流,创建相应的线程

版权声明
本文为[Atom]所创,转载请带上原文链接,感谢
https://segmentfault.com/a/1190000021748091