基于Android P版本分析
一、Service功能描述
Audio系统是Android中负责音频方面的数据流传输和控制的,也负责音频设备的管理。
一个音频系统大概包括音频的管理、声音播放、声音录音和声音音效几个部分,这几个部分分工协作来完成音频的功能;
- 音频管理:负责音量调节、音频设备选择、响铃模式选择等;
- 声音播放:负责一个音频流的创建、参数设置、播放、暂停、释放;
- 声音录音:负责一个录音音轨的创建、管理;
- 声音音效:负责控制声音的效果。
二、Service架构图
架构图
从层级上看,Audio的架构层次和其他的模块的架构基本类同,都分为了4个层次:Application、Framework、Native、HAL层;
Application:
上层应用,包括各种音乐播放器、语音播报扥个声音输出软件。
Framework:
提供Application层用于定义开发的Audio接口以及对应的JNI层的接口;
我们常见的使用方式为MediaRecorder/MediaPlayer和AudioRecord/AudioTrack用于录制(采集)和播放音频文件或者是音频流数据;
工具类 | 描述 |
---|---|
MediaRecorder | 录制生成的是音频文件,即继承了录制、编码、压缩等功能,生成的文件支持常见的播放器播放 |
AudioRecord | 录制生成的是PCM音频数据,即音频的原始数据,对应的生成的PCM音频文件不能直接使用播放器播放,而需要适应对应AudioTrack进行读取播放 |
MediaPlayer | 可以支持多种音频文件格式的播放,例如MP3、AAC、WAV、OGG等一些常见的音频格式 |
AudioTrack | 只支持PCM音频数据的读取,然后使用AudioFlinger进行混音,然后通过硬件设备播放 |
其中MediaRecorder和MediaPlayer分别集成了AudioRecord和AudioTrack,同时还集成了AudioRecord和AudioTrack所不支持的MediaCodec,用于编解码音视频数据;
其中还有一些AudioManager、AudioSystem、AudioService,用于提供声音控制、音效设置、通道选择等功能;
上述描述的是Framework Java层的API接口分析,JNI层会有对应的JNI的实现,用于连接Native层对应的类;
Native:
在Native层,一般情况下,Android中的大多数模块都会划分为两个部分:客户端和服务端,客户端用于和JNI层进行通信,服务端用于执行client层传入的请求或者是命令等;
-
client:
AudioTrack、AudioRecord、MediaPlayer、MediaRecorder、AudioSystem对应Java层的实现类。
-
server:
在client和server中,其实还有一块,就是Binder IPC Proxies,其中定义了IAudioTrack.cpp、IAudioRecord.cpp、IAudioFlinger.cpp等,用于client和server进行通信;
在server中包含了最核心的AudioPolicyService和AudioFlinger,其中AudioPolicyService是Audio系统策略的制定者,掌管系统中声音设备的选择和切换、音量控制等功能;而AudioFlinger为Audio系统策略的执行者,即工作引擎,管理着系统中的输入输出音频流,承担音频数据的混音以及读写Audio硬件等工作;
HAL:
HAL层是AudioFlinger向下访问的对象,该层一般厂商会实现自己的接口层,桥接硬件驱动和上层框架;
Android Audio上层设计框架中与硬件抽象层直接交互的只有AudioFlinger和AudioPolicyService。HAL层的任务就是提供同一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式;
Kernel:
一般常见的有ALSA(先进Linux声音架构)、OSS(开放声音系统)以及定制化的Driver,OSS是一个商业声卡驱动程序,需要购买,一般我们使用ALSA驱动程序;
总之,基于上述的描述,汇总了一下;
在 Android Audio 系统设计中,无论是上层还是下层都是用一个管理类和输入输出两个类来表示 Audio 系统,输入输出两个类负责数据通道,在各个层级间对应关系:
Audio管理环节 | Audio输出 | Audio输入 | |
---|---|---|---|
Java层 | android.media.AudioSystem | android.media.AudioTrack | android.media.AudioRecord |
本地框架层 | AudioSystem | AudioTrack | AudioRecord |
AudioFlinger | IAudioFlinger | IAudioTrack | IAudioRecord |
硬件抽象层 | AudioHardwareInterface | AudioStreamOut | AudioStreamIn |
各层级之间的调用关系:
三、开机时运行的逻辑梳理
AudioService的启动流程分为两个阶段,一个是创建AudioService阶段,另一个就是systemReady阶段;
创建AudioService
流程图
时序图
在创建AudioService阶段,执行的逻辑比较简单:
- 创建AudioService实例;
- 创建AudioSystemThread线程以及对应的AudioHandler,用于处理AudioService过程比较耗时的一些操作,这个在后续的过程中会频繁的使用;
- 创建MediaFocusControl实例,该实例用于Audio Focus的管理,例如音频焦点的申请、释放都是由该类来实现,其中包含了相应的音频焦点的冲裁策略,这个可以是自定义的,根据产品需求来定;
- 将创建好的AudioService添加到ServiceManager中进行维护;
- 紧接着就是响应PHASE_ACTIVITY_MANAGER_READY阶段;
systemReady
流程图
时序图
PHASE
Phase 设置时序
scss
private void startBootstrapServices() {
........................
// We need the default display before we can initialize the package manager.
traceBeginAndSlog("WaitForDisplay");
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
traceEnd();
........................
}
private void startCoreServices() {
..............................
}
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
..............................
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
if (isEmulator) {
Slog.i(TAG, "No Bluetooth Service (emulator)");
} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
} else if (!context.getPackageManager().hasSystemFeature
(PackageManager.FEATURE_BLUETOOTH)) {
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else {
traceBeginAndSlog("StartBluetoothService");
mSystemServiceManager.startService(BluetoothService.class);
traceEnd();
}
traceBeginAndSlog("IpConnectivityMetrics");
mSystemServiceManager.startService(IpConnectivityMetrics.class);
traceEnd();
..............................
// Needed by DevicePolicyManager for initialization
traceBeginAndSlog("StartBootPhaseLockSettingsReady");
mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
traceEnd();
traceBeginAndSlog("StartBootPhaseSystemServicesReady");
mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
traceEnd();
..............................
traceBeginAndSlog("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
traceEnd();
traceBeginAndSlog("GwmFeatureRecordService");
mSystemServiceManager.startService(GwmFeatureRecordService.class);
traceEnd();
..............................
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.
mActivityManagerService.systemReady(() -> {
Slog.i(TAG, "Making services ready");
traceBeginAndSlog("StartActivityManagerReadyPhase");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
traceEnd();
traceBeginAndSlog("StartObservingNativeCrashes");
try {
..............................
}
上述主要罗列了一下BT涉及到的一些Phase;
3.1 PHASE_WAIT_FOR_DEFAULT_DISPLAY
该阶段是在startBootstrapServices方法时设置的,在调用startService 启动了DisplayManagerService之后,将Phase状态设置为了PHASE_WAIT_FOR_DEFAULT_DISPLAY,然后在该方法的后续过程中,一直保持该阶段,直到进入了startOtherServices方法中,才再一次进行的阶段调整;
而在设置为PHASE_LOCK_SETTINGS_READY阶段之前,startOtherServices方法就执行了AudioService.Lifecycle的启动逻辑,对应创建了AudioService实例;
3.2 PHASE_LOCK_SETTINGS_READY
无
3.3 PHASE_SYSTEM_SERVICES_READY
我们需要关注Phase的设置方式:
java
/**
* Starts the specified boot phase for all system services that have been started up to
* this point.
*
* @param phase The boot phase to start.
*/
public void startBootPhase(final int phase) {
if (phase <= mCurrentPhase) {
throw new IllegalArgumentException("Next phase must be larger than previous");
}
mCurrentPhase = phase;
Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "OnBootPhase " + phase);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
throw new RuntimeException("Failed to boot service "
+ service.getClass().getName()
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
在startBootPhase方法中,遍历了所有的Service,执行了各个Service的onBootPhase方法;
我们关注一下BT模块的onBootPhase方法:
scss
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
mBluetoothManagerService);
} else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mBluetoothManagerService.handleOnBootPhase();
}
}
在BLUETOOTH_MANAGER_SERVICE阶段中,会调用publishBinderService方法将BluetoothManagerService实例添加到ServiceManager中进行管理;
3.4 PHASE_DEVICE_SPECIFIC_SERVICES_READY
无
3.5 PHASE_ACTIVITY_MANAGER_READY
我们需要关注Phase的设置方式:
java
/**
* Starts the specified boot phase for all system services that have been started up to
* this point.
*
* @param phase The boot phase to start.
*/
public void startBootPhase(final int phase) {
if (phase <= mCurrentPhase) {
throw new IllegalArgumentException("Next phase must be larger than previous");
}
mCurrentPhase = phase;
Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "OnBootPhase " + phase);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
throw new RuntimeException("Failed to boot service "
+ service.getClass().getName()
+ ": onBootPhase threw an exception during phase "
+ mCurrentPhase, ex);
}
warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
}
在startBootPhase方法中,遍历了所有的Service,执行了各个Service的onBootPhase方法;
我们关注一下Audio模块的onBootPhase方法:
java
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
mService.systemReady();
}
}
在该方法中,只针对PHASE_ACTIVITY_MANAGER_READY阶段进行了特殊处理,在该阶段调用了AudioService的systemReady方法;
3.6 PHASE_THIRD_PARTY_APPS_CAN_START
无
3.7 PHASE_BOOT_COMPLETED
无
3.8 systemRunning()
无
3.9 systemReady()
紧接着PHASE_ACTIVITY_MANAGER_READY阶段,在Audio的onBootPhase方法中,调用了AudioService的systemReady方法,该方法主要是用于Audio模块启动阶段的配置准备工作;
四、Service创建的线程列表并说明
在AudioService模块,目前涉及到的线程(除主线程)有两个:
- AudioSystemThread
- SoundPoolListenerThread
AudioSystemThread
AudioSystemThread线程是在AudioService的构造方法中创建,用于响应AudioService的Message。
AudioService模块采用了Handler机制,将比较耗时的操作放置到了Handler中进行处理,而比较简单的操作则直接在创建AudioService实例的时候执行,即在主线程中执行;
scala
/** Thread that handles native AudioSystem control. */
private class AudioSystemThread extends Thread {
AudioSystemThread() {
super("AudioService");
}
@Override
public void run() {
// Set this thread up so the handler will work on it
Looper.prepare();
synchronized(AudioService.this) {
mAudioHandler = new AudioHandler();
// Notify that the handler has been created
AudioService.this.notify();
}
// Listen for volume change requests that are set by VolumePanel
Looper.loop();
}
}
在AudioSystemThread的run线程体中,直接创建了AudioHandler实例,然后调用Looper.loop()方法开启消息轮询处理;
在run线程体中,执行了AudioService.this.notify(),用于创建在调用Thread的start()方法时执行的wait操作,表明当前线程已经准备就绪,可以开始处理Message;
AudioHandler
AudioSystemThread线程的创建就是为了AudioHandler,因为在Audio模块,存在着很多耗时操作,不能放置在主线程中执行,否则会阻塞线程其他核心逻辑的执行;
我们看一下AudioHandler中执行的Message:
Message | Desc |
---|---|
MSG_SET_DEVICE_VOLUME | 设置设备音量 |
MSG_SET_ALL_VOLUMES | 设置所有音量 |
MSG_PERSIST_VOLUME | 保持音量 |
MSG_PERSIST_RINGER_MODE | 保持铃声模式 |
MSG_AUDIO_SERVER_DIED | AudioService died |
MSG_DISPATCH_AUDIO_SERVER_STATE | 发送AudioService状态 |
MSG_UNLOAD_SOUND_EFFECTS | 卸载音效资源 |
MSG_LOAD_SOUND_EFFECTS | 加载音效资源 |
MSG_PLAY_SOUND_EFFECT | 播放音效 |
MSG_BTA2DP_DOCK_TIMEOUT | |
MSG_SET_FORCE_USE | 设置强制使用 |
MSG_SET_FORCE_BT_A2DP_USE | 设置强制使用蓝牙A2DP |
MSG_BT_HEADSET_CNCT_FAILED | 蓝牙Headset连接失败 |
MSG_SET_WIRED_DEVICE_CONNECTION_STATE | 设置有线设备连接状态 |
MSG_SET_A2DP_SRC_CONNECTION_STATE | 设置A2DP source 连接状态 |
MSG_SET_A2DP_SINK_CONNECTION_STATE | 设置A2DP sink 连接状态 |
MSG_SET_HEARING_AID_CONNECTION_STATE | 设置人机交互连接状态 |
MSG_A2DP_DEVICE_CONFIG_CHANGE | A2DP 设备配置变更 |
MSG_DISABLE_AUDIO_FOR_UID | 针对指定UID禁用Audio |
MSG_REPORT_NEW_ROUTES | 上报新的路由配置 |
MSG_CHECK_MUSIC_ACTIVE | 检验MUSIC激活状态 |
MSG_BROADCAST_AUDIO_BECOMING_NOISY | 广播通知音频受到干扰 |
MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED | 强制配置安全的多媒体音量 |
MSG_CONFIGURE_SAFE_MEDIA_VOLUME | 配置安全的多媒体音量 |
MSG_PERSIST_SAFE_VOLUME_STATE | 保持安全音量状态 |
MSG_BROADCAST_BT_CONNECTION_STATE | 广播通知蓝牙连接状态 |
MSG_SYSTEM_READY | systemReady响应 |
MSG_INDICATE_SYSTEM_READY | |
MSG_ACCESSORY_PLUG_MEDIA_UNMUTE | |
MSG_PERSIST_MUSIC_ACTIVE_MS | |
MSG_UNMUTE_STREAM | 取消静音流 |
MSG_DYN_POLICY_MIX_STATE_UPDATE | |
MSG_NOTIFY_VOL_EVENT | 通知音量事件 |
MSG_ENABLE_SURROUND_FORMATS | 使能支持的格式 |
SoundPoolListenerThread
SoundPool,适合短促且对反应速度比较高的情况,例如游戏音效或者按键声;
java
class SoundPoolListenerThread extends Thread {
public SoundPoolListenerThread() {
super("SoundPoolListenerThread");
}
@Override
public void run() {
Looper.prepare();
mSoundPoolLooper = Looper.myLooper();
synchronized (mSoundEffectsLock) {
if (mSoundPool != null) {
mSoundPoolCallBack = new SoundPoolCallback();
mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
}
mSoundEffectsLock.notify();
}
Looper.loop();
}
}
private final class SoundPoolCallback implements
android.media.SoundPool.OnLoadCompleteListener {
int mStatus = 1; // 1 means neither error nor last sample loaded yet
List<Integer> mSamples = new ArrayList<Integer>();
public int status() {
return mStatus;
}
public void setSamples(int[] samples) {
for (int i = 0; i < samples.length; i++) {
// do not wait ack for samples rejected upfront by SoundPool
if (samples[i] > 0) {
mSamples.add(samples[i]);
}
}
}
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
synchronized (mSoundEffectsLock) {
int i = mSamples.indexOf(sampleId);
if (i >= 0) {
mSamples.remove(i);
}
if ((status != 0) || mSamples. isEmpty()) {
mStatus = status;
mSoundEffectsLock.notify();
}
}
}
}
SoundPoolListenerThread也很简单,其中创建了SoundPoolCallback实例用于监听处理,但是和AudioSystemThread线程的区别在与:
SoundPoolListenerThread中没有Handler,即没有对应的Message,该流程结束之后,应该会有一个对应的Looper对象mSoundPoolLooper来调用quit来结束线程;
对应的quit逻辑在onLoadSoundEffects方法中触发;