“ BufferQueue作为连接生产者和消费者的桥梁,时刻掌握队列中每一块Buffer的状态,对于解决一些卡死卡顿问题很有帮助,辨别是否有生产者或消费者长期持有大量Buffer不放导致运行不畅的情况。”
01
—
前言
在Android系统中,应用UI的显示、播放器解码后画面的显示、Camera预览画面的显示最终都是要送到Graphics系统的流程完成最终的合成送显,所以在出现画面卡顿卡死问题时Graphics系统往往成为"背锅侠"。
因此,我们要学会如何快速精准地理清问题(“甩锅”)。
最近遇到一些播放相关的问题:
player的小伙伴认为是decode时dequeue不出新的buffer导致解码流程卡住;
graphics的小伙伴认为是decoder长期持有大量的buffer,导致显示合成卡住;
那有没有办法可以实时监测下当前BufferQueue的状态呢?我简单研究了下,有点发现,但未必完美,在此分享下供大家讨论!
建议小伙伴们先阅读下早前BufferQueue的讲解文章:
Android Graphics 显示系统 - BufferQueue的工作流程(十二)
Android Graphics 显示系统 - BufferQueue的工作流程(十三)
Android Graphics 显示系统 - BufferQueue的工作流程(十四)
Android Graphics 显示系统 - BufferQueue的工作流程(十五)
在正常的显示流程中,每一块buffer的状态会进行转换
FREE -> DEQUEUED -> QUEUED -> ACQUIRED -> FREE
监测下当前BufferQueue的状态,目标就是获取当下队列中分配了多少了块Buffer?以及每一块Buffer所处的状态是什么?
02
—
演示效果
使用原生gallery3d app播放视频时,抓到的BufferQueue的状态信息
06-22 10:14:04.297 3400 3427 E BufferQueue: State: [SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity]#11(BLAST Consumer)11]
06-22 10:14:04.297 3400 3427 E BufferQueue: - BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=15
06-22 10:14:04.297 3400 3427 E BufferQueue: mDequeueBufferCannotBlock=0 mAsyncMode=0
06-22 10:14:04.297 3400 3427 E BufferQueue: mQueueBufferCanDrop=0 mLegacyBufferDrop=1
06-22 10:14:04.297 3400 3427 E BufferQueue: default-size=[720x1280] default-format=4 transform-hint=00 frame-counter=84
06-22 10:14:04.297 3400 3427 E BufferQueue: mTransformHintInUse=00 mAutoPrerotation=0
06-22 10:14:04.297 3400 3427 E BufferQueue: FIFO(1):
06-22 10:14:04.297 3400 3427 E BufferQueue: (mConsumerName=SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity]#11(BLAST Consumer)11, mConnectedApi=3, mConsumerUsageBits=2304, mId=d480000000b, producer=[532:???], consumer=[3400:com.android.gallery3d])
06-22 10:14:04.297 3400 3427 E BufferQueue: 15:0x7756e78afd10 crop=[0,0,720,1280] xform=0x00 time=1049.6518 scale=SCALE_TO_WINDOW
06-22 10:14:04.297 3400 3427 E BufferQueue: Slots:
06-22 10:14:04.297 3400 3427 E BufferQueue: [00:0x7756e78ad490] state=DEQUEUED 0x7756278c19d0 frame=75 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [01:0x7756e78c2190] state=DEQUEUED 0x7756278d0230 frame=71 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [02:0x7756e78bf010] state=DEQUEUED 0x7756278c5de0 frame=74 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [03:0x7756e78c2df0] state=DEQUEUED 0x7756278c4680 frame=80 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [04:0x7756e78b0df0] state=DEQUEUED 0x7756278d02e0 frame=70 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [05:0x7756e78c4e90] state=DEQUEUED 0x7756278cf310 frame=72 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [06:0x7756e78b82f0] state=DEQUEUED 0x7756278d7030 frame=73 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [07:0x7756e78c10b0] state=DEQUEUED 0x7756278d6e20 frame=76 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [08:0x7756e78c7950] state=DEQUEUED 0x7756278cfcb0 frame=77 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [09:0x7756e78c61b0] state=DEQUEUED 0x7756278d4f30 frame=78 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [10:0x7756e78bf910] state=DEQUEUED 0x7756278d5980 frame=79 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: >[11:0x7756e78af890] state=ACQUIRED 0x7756278c6570 frame=81 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [13:0x7756e78b7d50] state=DEQUEUED 0x7756278c94e0 frame=67 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: >[14:0x7756e78c22b0] state=ACQUIRED 0x7756278c54f0 frame=83 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [15:0x7756e78afd10] state=QUEUED 0x7756278c9590 frame=84 [ 768x1280: 768,32315659]
06-22 10:14:04.297 3400 3427 E BufferQueue: [12:0x7756e78ad370] state=FREE 0x7756278d7b30 frame=82 [ 768x1280: 768,32315659]
可以看到:
-
一共分配了16块buffer;
-
2块buffer处于ACQUIRED状态,说明已被消费者拿去准备合成显示了;
-
1块buffer处于QUEUED状态,说明生产者已经queueBuffer返还了;
-
1块buffer处于FREE状态;
-
12块buffer处于DEQUEUED状态,说明生产者dequeueBuffer准备填充数据;
-
还可以看到每一块buffer的width/height/stride/format
-
frame=xx,代表了该buffer被queueBuffer的顺序,即为BufferSlot中的
// mFrameNumber is the number of the queued frame for this slot. This // is used to dequeue buffers in LRU order (useful because buffers // may be released before their release fence is signaled). uint64_t mFrameNumber;
-
另外还有BufferQueue的配置信息;
使用原生gallery3d app展示图片时,抓到的BufferQueue的状态信息
06-22 11:24:40.224 3400 9472 E BufferQueue: State: [SurfaceView[com.android.gallery3d/com.android.gallery3d.app.GalleryActivity]#29(BLAST Consumer)29]
06-22 11:24:40.224 3400 9472 E BufferQueue: - BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=2
06-22 11:24:40.224 3400 9472 E BufferQueue: mDequeueBufferCannotBlock=0 mAsyncMode=0
06-22 11:24:40.224 3400 9472 E BufferQueue: mQueueBufferCanDrop=0 mLegacyBufferDrop=1
06-22 11:24:40.224 3400 9472 E BufferQueue: default-size=[1080x1776] default-format=3 transform-hint=00 frame-counter=414
06-22 11:24:40.224 3400 9472 E BufferQueue: mTransformHintInUse=00 mAutoPrerotation=0
06-22 11:24:40.224 3400 9472 E BufferQueue: FIFO(1):
06-22 11:24:40.224 3400 9472 E BufferQueue: (mConsumerName=SurfaceView[com.android.gallery3d/com.android.gallery3d.app.GalleryActivity]#29(BLAST Consumer)29, mConnectedApi=1, mConsumerUsageBits=2304, mId=d480000001d, producer=[3400:com.android.gallery3d], consumer=[3400:com.android.gallery3d])
06-22 11:24:40.224 3400 9472 E BufferQueue: 02:0x7756e78c73b0 crop=[0,0,0,0] xform=0x00 time=5285.5555 scale=SCALE_TO_WINDOW
06-22 11:24:40.224 3400 9472 E BufferQueue: Slots:
06-22 11:24:40.224 3400 9472 E BufferQueue: >[00:0x7756e78b7210] state=ACQUIRED 0x7756278cf050 frame=412 [1080x1776:1088, 1]
06-22 11:24:40.224 3400 9472 E BufferQueue: >[01:0x7756e78c0210] state=ACQUIRED 0x7756278c3ad0 frame=413 [1080x1776:1088, 1]
06-22 11:24:40.224 3400 9472 E BufferQueue: [02:0x7756e78c73b0] state=QUEUED 0x7756278d0e90 frame=414 [1080x1776:1088, 1]
03
—
方法及源码
现在的方法是把BufferQueue的状态信息直接打印到logcat中,通过设置一个属性值来指定需要打印哪一个BufferQueue的信息。
源码
阅读原文获取
Android Graphics 显示系统 - BufferQueue的状态监测