【Android Audio】dumpsys media.metrics分析

Records Discarded: 3209 (by Count: 3209 by Expiration: 0)
    0: {audio.thread.53, (11-21 07:08:42.464), (audioserver, 0, 1041), (throttleMs=3.000000e+00)}
    1: {audio.thread.53, (11-21 07:08:42.485), (audioserver, 0, 1041), (throttleMs=2.000000e+00)}
    2: {audio.thread.53, (11-21 07:08:42.506), (audioserver, 0, 1041), (throttleMs=1.000000e+00)}
    3: {audio.thread.53, (11-21 07:08:42.574), (audioserver, 0, 1041), (throttleMs=2.000000e+00)}
    4: {audio.thread.53, (11-21 07:08:42.624), (audioserver, 0, 1041), (throttleMs=3.000000e+00)}
    5: {audio.thread.53, (11-21 07:08:42.688), (audioserver, 0, 1041), (throttleMs=1.000000e+00)}
    6: {audio.thread.53, (11-21 07:08:42.827), (audioserver, 0, 1041), (throttleMs=2.000000e+00)}
    7: {audio.track.61, (11-21 07:08:44.550), (android.uid.system, 0, 1000), (event#=setVolume, volume.left=1.000000e+00, volume.right=1.000000e+00)}
    8: {audio.thread.53, (11-21 07:08:44.599), (audioserver, 0, 1041), (event#=createAudioPatch, inputDevices=, outputDevices=(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, 6C:D3:EE:8A:43:20))}
    9: {audio.track.61, (11-21 07:08:44.619), (android.uid.system, 0, 1000), (callerName=soundpool, event#=start, executionTimeNs=69001500, state=STATE_ACTIVE, status#=0)}
   10: {audio.track.61, (11-21 07:08:44.716), (android.uid.system, 0, 1000), (bufferSizeFrames=4512, event#=stop, executionTimeNs=427583, state=STATE_STOPPED, underrun=0)}
   11: {audio.track.61, (11-21 07:08:44.738), (audioserver, 0, 1041), (latencyMs=1.006627e+02, startupMs=1.141446e+02)}
   12: {audio.track.63, (11-21 07:08:44.749), (media, 0, 1013), (event#=pause, executionTimeNs=3365333, state=STATE_PAUSED)}
   13: {audio.track.61, (11-21 07:08:44.755), (android.uid.system, 0, 1000), (event#=setVolume, volume.left=1.000000e+00, volume.right=1.000000e+00)}
   14: {audio.track.61, (11-21 07:08:44.756), (android.uid.system, 0, 1000), (callerName=soundpool, event#=start, executionTimeNs=199958, state=STATE_ACTIVE, status#=0)}
   15: {audio.track.61, (11-21 07:08:44.855), (android.uid.system, 0, 1000), (bufferSizeFrames=4512, event#=stop, executionTimeNs=810542, state=STATE_STOPPED, underrun=0)}
   16: {audio.track.61, (11-21 07:08:44.877), (audioserver, 0, 1041), (latencyMs=9.432017e+01, startupMs=2.717963e+01)}
   17: {audio.device.setBluetoothA2dpOn, (11-21 07:08:45.247), (android.uid.system, 708, 1000), (state=on)}
   18: {audio.forceUse.FOR_MEDIA, (11-21 07:08:45.247), (android.uid.system, 0, 1000), (event#=onSetForceUse, forceUseDueTo=setBluetoothA2dpOn(true) from u/pid:1000/708 src:AudioService.setBtA2dpOn, forceUseMode=FORCE_NONE                                                                                                                                                                                                                     E)}
   19: {audio.device.onReportNewRoutes, (11-21 07:08:45.248), (android.uid.system, 0, 1000), (observers=5)}
   20: {audio.volume.STREAM_VOICE_CALL.hdmi, (11-21 07:08:45.267), (android.uid.system, 0, 1000), (event#=put, index=1000, maxIndex=1000, minIndex=0)}
   21: {audio.volume.STREAM_SYSTEM.hdmi, (11-21 07:08:45.292), (android.uid.system, 0, 1000), (event#=put, index=1000, maxIndex=1000, minIndex=0)}
   22: {audio.volume.STREAM_RING.hdmi, (11-21 07:08:45.316), (android.uid.system, 0, 1000), (event#=put, index=1000, maxIndex=1000, minIndex=0)}
   23: {audio.volume.STREAM_MUSIC.hdmi, (11-21 07:08:45.331), (android.uid.system, 0, 1000), (event#=put, index=250, maxIndex=250, minIndex=0)}
   24: {audio.volume.STREAM_ALARM.hdmi, (11-21 07:08:45.347), (android.uid.system, 0, 1000), (event#=put, index=1000, maxIndex=1000, minIndex=10)}
  • 在敲下命令dumpsys media.metrics时,实际调用的是MediaMetricsService中的dump函数来打印缓存日志信息。
  • MediaMetricsService是 Android 系统中的一个后台服务,它的核心任务是持续收集和存储来自媒体组件(如音频、视频、编解码器等)的日志信息等。
  • 通过该命令可以查看Audio framework中java和c++ framework中各个关键操作的日志,从该日志可以辅助开发者定位问题。

1、Java中的Metrics

1.1、代码示例

代码中如果有new MediaMetrics.Item,那么调用的时候就会记录一条metric。

例如在AudioService.java中记录每次调节音量的信息:
frameworks\base\services\core\java\com\android\server\audio\AudioService.java

        private final SparseIntArray mIndexMap = new SparseIntArray(8) {
            @Override
            public void put(int key, int value) {
                super.put(key, value);
                record("put", key, value);
                if (cacheGetStreamVolume()) {
                    if (DEBUG_VOL) {
                        Log.d(TAG, "Clear volume cache after update index map");
                    }
                    AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
                }
            }
            @Override
            public void setValueAt(int index, int value) {
                super.setValueAt(index, value);
                record("setValueAt", keyAt(index), value);
                if (cacheGetStreamVolume()) {
                    if (DEBUG_VOL) {
                        Log.d(TAG, "Clear volume cache after update index map");
                    }
                    AudioManager.clearVolumeCache(AudioManager.VOLUME_CACHING_API);
                }
            }

            // Record all changes in the VolumeStreamState
            private void record(String event, int key, int value) {
                final String device = key == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
                        : AudioSystem.getOutputDeviceName(key);
                new MediaMetrics.Item(MediaMetrics.Name.AUDIO_VOLUME + MediaMetrics.SEPARATOR
                        + AudioSystem.streamToString(mStreamType)
                        + "." + device)
                        .set(MediaMetrics.Property.EVENT, event)
                        .set(MediaMetrics.Property.INDEX, value)
                        .set(MediaMetrics.Property.MIN_INDEX, mIndexMin)
                        .set(MediaMetrics.Property.MAX_INDEX, mIndexMax)
                        .record();
            }
        };

每次调节音量就有一条记录:

  {audio.volume.STREAM_ALARM.hdmi, (10-15 12:12:31.888), (android.uid.system, 0, 1000), (event#=put, index=800, maxIndex=1000, minIndex=0)}

1.2、tag定义

java的MediaMetrics.Name的定义在:
frameworks/base/media/java/android/media/MediaMetrics.java

...
        public static final String AUDIO_MODE = AUDIO + SEPARATOR + "mode";
        public static final String AUDIO_SERVICE = AUDIO + SEPARATOR + "service";
        public static final String AUDIO_VOLUME = AUDIO + SEPARATOR + "volume";
        public static final String AUDIO_VOLUME_EVENT = AUDIO_VOLUME + SEPARATOR + "event";
        public static final String METRICS_MANAGER = "metrics" + SEPARATOR + "manager";
...

2、C++中的Metrics

2.1、代码示例

代码中如果有mediametrics::LogItem调用就会记录一条metric。

例如在AudioTrack.cpp中启动一次track播放
frameworks/av/media/libaudioclient/AudioTrack.cpp

status_t AudioTrack::start()
{
    AutoMutex lock(mLock);

    if (mState == STATE_ACTIVE) {
        return INVALID_OPERATION;
    }
    ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
    // Defer logging here due to OpenSL ES repeated start calls.
    // TODO(b/154868033) after fix, restore this logging back to the beginning of start().
    const int64_t beginNs = systemTime();
    status_t status = NO_ERROR; // logged: make sure to set this before returning.
    mediametrics::Defer defer([&] {
        mediametrics::LogItem(mMetricsId)
            .set(AMEDIAMETRICS_PROP_CALLERNAME,
                    mCallerName.empty()
                    ? AMEDIAMETRICS_PROP_CALLERNAME_VALUE_UNKNOWN
                    : mCallerName.c_str())
            .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_START)
            .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
            .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
            .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
            .record(); });

每次AudioTrack start打印有:

 {audio.track.16, (10-15 12:12:32.024), (root, 0, 0), (callerName=unknown, event#=start, executionTimeNs=5194083, state=STATE_ACTIVE, status#=0)}

2.2、tag定义

c++的MediaMetrics.Name的定义在:

frameworks\av\media\libmediametrics\include\MediaMetricsConstants.h

#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."

// Device related key prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_DEVICE  AMEDIAMETRICS_KEY_PREFIX_AUDIO "device."

// The AudioMmap key appends the "trackId" to the prefix.
// This is the AudioFlinger equivalent of the AAudio Stream.
// TODO: unify with AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP  AMEDIAMETRICS_KEY_PREFIX_AUDIO "mmap."

// The AudioRecord key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."

// The Audio Sensor key appends the sensor handle integer.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_SENSOR AMEDIAMETRICS_KEY_PREFIX_AUDIO "sensor."

// The Audio Spatializer key appends the spatializerId (currently 0)
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER AMEDIAMETRICS_KEY_PREFIX_AUDIO "spatializer."

// The Audio Spatializer device key appends the device type.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER_DEVICE \
        AMEDIAMETRICS_KEY_PREFIX_AUDIO_SPATIALIZER "device."

// The AudioStream key appends the "streamId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM  AMEDIAMETRICS_KEY_PREFIX_AUDIO "stream."

// The AudioThread key appends the "threadId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread."

// The AudioTrack key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK  AMEDIAMETRICS_KEY_PREFIX_AUDIO "track."

// Keys are strings used for MediaMetrics Item Keys
#define AMEDIAMETRICS_KEY_AUDIO_FLINGER       AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger"
#define AMEDIAMETRICS_KEY_AUDIO_MIDI          AMEDIAMETRICS_KEY_PREFIX_AUDIO "midi"
#define AMEDIAMETRICS_KEY_AUDIO_POLICY        AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy"
<think>我们正在分析Android系统中的两个关键dumpsys命令:`media.audio_flinger`和`media.audio_policy`。根据引用内容,我们可以总结如下:1.**dumpsysmedia.audio_flinger**:聚焦于音频系统的硬件层,主要用于分析音频处理过程中的底层问题,如卡顿、延迟、欠载(underrun)等。它提供了关于音频流、混音器状态、硬件设备使用情况等详细信息(引用[2])。 2. **dumpsys media.audio_policy**:聚焦于音频策略层,主要处理音频路由策略、设备选择、音量控制等策略相关的问题。它适合诊断音频路由错误(例如音频输出到错误的设备)或设备不匹配问题(引用[2])。 ###功能详细对比| **功能/特性**|**dumpsysmedia.audio_flinger**| **dumpsys media.audio_policy**| |-----------------------|----------------------------------------------------------|----------------------------------------------------------| |**核心关注点**|音频硬件交互、混音过程、缓冲区状态|音频策略决策(路由、设备选择、音量策略)| |**适用问题类型**|卡顿、延迟、欠载、播放中断|路由错误(如音频未从预期设备输出)、设备切换失败| |**输出内容示例**|活动音频流、混音器状态、硬件设备状态、缓冲区状态|当前音频策略配置、可用设备列表、活动策略、音量曲线|| **调试场景**|播放异常(如杂音、断断续续)、录音延迟|蓝牙耳机无法切换、外放与听筒切换失败|###实际应用建议-当遇到音频播放卡顿、延迟或录音异常时,优先使用`dumpsysmedia.audio_flinger`检查硬件层状态(引用[3])。 -当音频输出设备错误(例如本该从蓝牙输出却从扬声器输出),或音量控制异常时,使用`dumpsysmedia.audio_policy`检查策略配置(引用[2])。 ###分析流程示例(车机音频问题)1.**初步定位**:通过`logcat`查看应用层错误日志。2.**分层诊断**:-使用`dumpsysmedia.audio_policy`确认音频路由策略是否正确。-若路由正常但仍有卡顿,再通过`dumpsys media.audio_flinger`分析硬件缓冲区和混音器状态。 3. **深度工具辅助**:结合`systrace`观察系统级延迟(引用[3])。###典型输出解读####audio_flinger片段```plaintextHardware status:Mastervolume:1.000000Stream volumes:- STREAM_MUSIC:1.000000Active tracks:Track name: AudioTrack,SessionID:123, Bufferstatus:512/1024frames``` 这里关注`Buffer status`(缓冲区填充状态),若值持续偏低则可能导致欠载(播放中断)。#### audio_policy片段```plaintextDevices:- Device:0x8 (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP), Name: "BTSpeaker"- Device:0x2 (AUDIO_DEVICE_OUT_SPEAKER),Name:"Built-in Speaker"Activepolicy:Outputformusic:device=0x8(BTSpeaker)``` 此处确认音乐流是否按预期路由到蓝牙设备。###总结- **audio_flinger**:硬件执行层监控,解决“播放是否流畅”问题。- **audio_policy**:策略决策层监控,解决“音频去哪儿了”问题(引用[2][3])。 §§相关问题§§1.如何解读`dumpsysmedia.audio_flinger`输出的缓冲区状态?2.`dumpsysmedia.audio_policy`中如何判断音量策略是否生效?3.Android音频问题分析中,`logcat`和`systrace`如何配合dumpsys使用?</think>### Android `dumpsys media.audio_flinger` 与 `dumpsys media.audio_policy` 功能对比分析 #### 1. **核心功能定位** - **`media.audio_flinger`** 聚焦 **音频硬件交互层**,直接管理音频流的混音、播放和硬件设备操作。 核心功能: - 实时监控音频缓冲区状态(欠载/溢出) - 跟踪混音器线程性能(延迟、卡顿) - 显示活跃音频轨道的硬件参数(采样率、帧数) - 诊断底层硬件异常(如 DMA 传输错误) *适用场景:音频播放卡顿、杂音、延迟问题分析* [^2][^3] - **`media.audio_policy`** 聚焦 **音频策略决策层**,管理音频路由规则和系统策略。 核心功能: - 显示当前音频设备路由状态(如蓝牙/扬声器切换) - 列出系统支持的音频输出/输入设备 - 检查音量策略和音频焦点冲突 - 验证策略规则匹配(如车载多音区控制) *适用场景:音频输出到错误设备、音量控制失效、多设备切换异常* [^2][^3] --- #### 2. **关键输出内容对比 | **特征** | `audio_flinger` 输出内容 | `audio_policy` 输出内容 | |-------------------------|--------------------------------------------------|---------------------------------------------| | **设备状态** | 硬件设备实时负载(如 DMA 缓冲区) | 可用设备列表及激活状态 | | **音频流** | 活动音频流详细参数(采样率、通道数、帧计数) | 音频流与设备的绑定关系 | | **性能指标** | 硬件级延迟数据、欠载(underrun)次数 | 路由策略执行时间 | | **策略配置** | 无 | 音量曲线、焦点策略、强制路由规则 | | **典型问题线索** | `Hardware status`/`Underrun` 字段 | `Devices`/`Outputs`/`Stream` 路由状态 | --- #### 3. **协同工作流程示例 ```mermaid graph LR A[应用请求播放音频] --> B(audio_policy 决策) B --> C{选择输出设备} C -->|蓝牙耳机| D[audio_flinger 驱动硬件] D --> E[监控缓冲区状态] E -->|欠载告警| F[audio_flinger 日志标记] ``` --- #### 4. **典型问题诊断指南 - **音频卡顿问题**: 先查 `audio_flinger` 的 `Underrun count`(缓冲区欠载次数),再结合 `systrace` 分析线程阻塞点 [^3] - **设备切换失败**: 检查 `audio_policy` 的 `Output devices` 是否包含目标设备,并验证 `Strategy` 匹配规则 [^2] - **音量异常**: 在 `audio_policy` 中确认音量曲线(`Curves for stream`)是否被修改,在 `audio_flinger` 验证硬件增益值 --- #### 5. **高级分析技巧 1. **关联日志过滤** ```bash adb logcat | grep -E "AudioFlinger|AudioPolicy" ``` 2. **时间戳对齐** 对比 `audio_flinger` 的帧时间戳和系统时钟,定位硬件延迟 3. **策略模拟测试** 通过 `audio_policy` 输出重建路由决策树 > 关键结论:`audio_flinger` 是音频流水线的"执行引擎",`audio_policy` 是"导航系统",二者协同保障 Android 音频架构运行 [^2][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值