Android Graphics 显示系统 - 导出指定图层Layer数据与图层合成探秘

“ 工作中会遇到一些问题,需要把单个图层的数据导出到文件来判断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进行可以有足够的权限写文件:

  1. 具有Linux文件系统的写权限;

  2. 具有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截屏获取)

图片

看到这个图片,作为专业人员,大概就知道有几个可见图层了

  1. 最上面的状态栏 StatusBar

  2. 最下面的导航栏 NavigationBar

  3. 作为背景的壁纸 Wallpaper

  4. 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)

关注公众号获取更多Android Graphics知识

  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值