Android_AudioService启动分析

基于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方法中触发;

相关推荐
深海呐3 小时前
Android AlertDialog圆角背景不生效的问题
android
ljl_jiaLiang3 小时前
android10 系统定制:增加应用使用数据埋点,应用使用时长统计
android·系统定制
花花鱼3 小时前
android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。
android
canonical_entropy4 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
落落落sss4 小时前
sharding-jdbc分库分表
android·java·开发语言·数据库·servlet·oracle
沛沛老爹5 小时前
服务监控插件全览:提升微服务可观测性的利器
微服务·云原生·架构·datadog·influx·graphite
huaqianzkh6 小时前
了解华为云容器引擎(Cloud Container Engine)
云原生·架构·华为云
消失的旧时光-19436 小时前
kotlin的密封类
android·开发语言·kotlin
Kika写代码6 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
刘某某.6 小时前
使用OpenFeign在不同微服务之间传递用户信息时失败
java·微服务·架构