“ 工作中会遇到一些问题,需要把单个图层的数据导出到文件来判断raw data是否有异常,同一时刻往往会存在多个图层,那如何根据需要导出单个指定的图层数据呢?”
01
—
导出指定图层数据的技术要点
技术要点
-
service call命令传递Layer的序列号到SurfaceFlinger;
-
遍历mDrawingState中的Layer找到对应的图层;
-
获取图层的GraphicBuffer;
-
获取GraphicBuffer的格式、宽、高等信息,把数据写入文件;
要点解读
>Layer的序列号
可以看Layer中的定义,sequence是layer的的序列号或者称之为layer id,它可以作为图层的唯一标识
// Layer serial number. This gives layers an explicit ordering, so we
// have a stable sort order when their layer stack and Z-order are
// the same.
const int32_t sequence;
有一个public api可以获取它
int32_t getSequence() const { return sequence; }
sequence是在构造函数中被赋值的,同时layer的名字中也会后缀加上这个序列号,
Layer::Layer(const LayerCreationArgs& args)
: sequence(args.sequence),
mFlinger(sp<SurfaceFlinger>::fromExisting(args.flinger)),
mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)),
就如同我们dumpsys看到的
当然,我们也可以通过传递layer name来达到相同的目的,但是layer name往往是很长的字符串,所以还是sequence比较简洁!更显的我专业,嘻嘻!
> mDrawingState
SurfaceFlinger类有两个类型为State的成员变量mCurrentState和mDrawingState。其中,成员变量mCurrentState用来描述系统下一次要渲染的UI的状态;而mDrawingState用来描述当前正要渲染的UI的状态。
遍历mDrawingState中的所有图层,找到对应sequence的Layer。
> 不同颜色格式的存储结构
常见的RGB、YUV数据在内存中的存储格式是不同的,这些内容网络上已有很多介绍,在此不赘述,Android中常常处理的有RGBA888,YV12等
主要是在下面三个文件中查询主要的hal pixel format
/system/core/libsystem/include/system/graphics-base-v1.0.h
/system/core/libsystem/include/system/graphics-base-v1.1.h
/system/core/libsystem/include/system/graphics-base-v1.2.h
> Dump档案存储位置
我们选择存储在/data/misc/wmtrace/下,原因是在不添加额外权限的前提下SurfaceFlinger进行可以有足够的权限写文件:
-
具有Linux文件系统的写权限;
-
具有SELinux意义上的写权限,不要有avc: denied;
> binder call功能响应
SurfaceFlinger收到binder call且code==1000时,就去执行我们定义的导出指定图层数据的方法。
02
—
效果展示&图层探秘
导出指定图层数据的命令
$ adb root
$ adb shell service call SurfaceFlinger 1000 i32 75
Result: Parcel(
0x00000000: 7461642f 696d2f61 772f6373 6172746d '/data/misc/wmtra'
0x00000010: 622f6563 65666675 5f385f72 775f3166 'ce/buffer_8_f1_w'
0x00000020: 30383031 3639685f 3031735f 722e3838 '1080_h96_s1088.r'
0x00000030: 00007761 'aw.. ')
命令简洁优美:
-
service call SurfaceFlinger :binder呼叫SF;
-
1000 : transact code,我们在代码中响应它来做特定事情;
-
i32 75 : 传递一个int32_t类型的整数参数给SF,75就是指定图层的序列号;
返回值很人性:
代表了数据存储到了哪个档案中
/data/misc/wmtrace/buffer_8_f1_w1080_h96_s1088.raw
档案的名字也有特殊意义,这样我们在使用7yuv查看时方便根据档案名字来设置显示参数format。
sprintf(dumpFileName,
"/data/misc/wmtrace/buffer_%u_f%d_w%u_h%u_s%u.raw",
sDumpCount++, // 计数器
format, // hal pixel format
width, // 宽
height, // 高
stride); // 步长
Home界面 - 导出图层与解读
用户看到的Home界面(screencap截屏获取)
看到这个图片,作为专业人员,大概就知道有几个可见图层了
-
最上面的状态栏 StatusBar
-
最下面的导航栏 NavigationBar
-
作为背景的壁纸 Wallpaper
-
Launcher Actvity显示的各种app图标和按钮等
确认下猜测的对不对,dumpsys SurfaceFlinger查看图层信息,有木有?!
4个可见图层,而且序列号分别是:60,136,79,75
Display 4619827353912518656 (active) HWC layers:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) (Seamlessness) [Focused]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Wallpaper BBQ wrapper#60
rel 0 | 0 | DEVICE | 0 | 0 0 1080 1920 | 26.0 47.0 550.0 977.0 | [ ]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher#136
rel 0 | 1 | DEVICE | 0 | 0 0 1080 1920 | 0.0 0.0 1080.0 1920.0 | [*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
StatusBar#79
rel 0 | 2000 | DEVICE | 0 | 0 0 1080 48 | 0.0 0.0 1080.0 48.0 | [ ]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
NavigationBar0#75
rel 0 | 2019 | DEVICE | 0 | 0 1824 1080 1920 | 0.0 0.0 1080.0 96.0 | [ ]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
分别把各个图层的数据导出来
1. 最上面的状态栏 StatusBar
2. 最下面的导航栏 NavigationBar
3. 作为背景的壁纸 Wallpaper
4. Launcher Actvity显示的各种app图标和按钮等
想象一下,把上面的4个图层按照z-order的顺序(还有透明度alpha、crop等)进行合成,是不是就是用户最终看到的画面!
如果再进一步确认信息,dumpsys可以读到更多信息
比如Launcher Actvity的图层,activeBuffer=[1080x1920:2352,RGBA_8888],格式大小和我们导出的都匹配。
+ Layer (com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher#136) uid=10078
Region TransparentRegion (this=0 count=0)
Region VisibleRegion (this=0 count=1)
[ 0, 0, 1080, 1920]
Region SurfaceDamageRegion (this=0 count=0)
layerStack= 0, z= 0, pos=(0,0), size=( 0, 0), crop=[ 0, 0, -1, -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=0, invalidate=0, dataspace=BT709 sRGB Full range, defaultPixelFormat=RGBA_8888, backgroundBlurRadius=0, color=(-1.000,-1.000,-1.000,1.000), flags=0x00000100, tr=[0.00, 0.00][0.00, 0.00]
parent=483880f com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher#83
zOrderRelativeOf=none
activeBuffer=[1080x1920:2352,RGBA_8888], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0 metadata={ownerPID:1088, ownerUID:10078, dequeueTime:1618230790072, windowType:1, 9:4bytes}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00], shadowRadius=0.000,
视频播放界面 - 导出图层与解读
播放视频时,用户会看到的画面(screencap截屏获取)
dumpsys SurfaceFlinger查看可见图层信息
Display 4619827353912518656 (active) HWC layers:
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Layer name
Z | Window Type | Comp Type | Transform | Disp Frame (LTRB) | Source Crop (LTRB) | Frame Rate (Explicit) (Seamlessness) [Focused]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
SurfaceView[com.android.gallery3d/co[...]lery3d.app.MovieActivity](BLAST)#125
rel 0 | 0 | DEVICE | 0 | 0 0 1080 1920 | 0.0 0.0 720.0 1280.0 | [*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
com.android.gallery3d/com.android.gallery3d.app.MovieActivity#120
rel 0 | 1 | DEVICE | 0 | 0 0 1080 1920 | 0.0 0.0 1080.0 1920.0 | [*]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
NavigationBar0#75
rel 0 | 2019 | DEVICE | 0 | 0 1824 1080 1920 | 0.0 0.0 1080.0 96.0 | [ ]
---------------------------------------------------------------------------------------------------------------------------------------------------------------
分别导出三个可见图层的raw data
视频图层
播放器Activity的控制组件 图层
底部的导航栏NavigationBar
进一步看视频图层的信息,activeBuffer=[ 768x1280:2355,Unknown 0x32315659],其中格式就是
HAL_PIXEL_FORMAT_YV12 = 842094169
+ Layer (SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity](BLAST)#125) uid=10062
Region TransparentRegion (this=0 count=0)
Region VisibleRegion (this=0 count=1)
[ 0, 0, 1080, 1920]
Region SurfaceDamageRegion (this=0 count=0)
layerStack= 0, z= 0, pos=(0,0), size=( 0, 0), crop=[ 0, 0, -1, -1], cornerRadius=0.000000, isProtected=0, isTrustedOverlay=0, isOpaque=1, invalidate=0, dataspace=BT709 SMPTE_170M Limited range, defaultPixelFormat=Unknown 0x32315659, backgroundBlurRadius=0, color=(-1.000,-1.000,-1.000,1.000), flags=0x00000102, tr=[1.41, 0.00][0.00, 1.50]
parent=SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity]#124
zOrderRelativeOf=none
activeBuffer=[ 768x1280:2355,Unknown 0x32315659], tr=[0.00, 0.00][0.00, 0.00] queued-frames=0 metadata={dequeueTime:77766559795, 9:4bytes}, cornerRadiusCrop=[0.00, 0.00, 0.00, 0.00], shadowRadius=0.000,
3个图层合成后显示到屏幕上就是用户看到的效果了!
导出指定图层的数据,放到电脑上用7yuv等工具对比查看,对于我们理解图层及合成的概念非常有意义,让抽象的概念更加生动具体!
03
—
源码
阅读原文获取源码
Android Graphics 显示系统 - 导出指定图层Layer数据与图层合成探秘 (qq.com)