ViewCapture 是一款软件工具,用于捕获附加到其所连接窗口的视图的属性(例如位置、大小、比例和可见性)。ViewCapture 捕获窗口内各种视图及其属性的相关信息,让您了解特定时刻的用户体验状态,并跟踪随时间推移的变化。
屏幕录制可以直观地显示特定时间的视图状态以及视图状态的变化方式,但它们需要大量的 CPU 资源,并且可能会影响性能。ViewCapture 工具的资源影响较小,可以更频繁地启用。此外,ViewCapture 以视图级别逐帧显示可视化效果,与屏幕录制相比,可以更直接地检查特定时刻的视图状态。
本页面介绍了如何在系统应用中加入 ViewCapture。
用途
ViewCapture.java
实现了 onDrawListener
的实例,并在绘制过程中收集 ViewCapture 跟踪记录。每个帧重绘都会触发从窗口的根视图开始遍历视图树层次结构。ViewCapture 使用公共 View.java
getter 方法来获取值并将其复制到后台线程,以提高性能。ViewCapture 实现通过使用 captureViewTree
检查视图是否脏或无效,从而优化此过程,从而避免遍历整个视图层次结构。captureViewTree
仅适用于系统应用,并且是 UnsupportedAppUsage API 的一部分。此 API 的使用仅限于基于其目标 SDK 版本的应用。
限制
以下部分介绍了运行 ViewCapture 的性能和内存限制。
性能
ViewCapture 性能的平均主线程开销为 195 微秒。但是,在最坏的情况下,它可能大约需要 5 毫秒。请参阅 Perfetto 跟踪记录中的 vc#onDraw
切片。
开销成本主要归因于以下操作
- 遍历层次结构需要 50 微秒,即使经过修剪也是如此。
- 从 freelist 分配器中拉取对象以存储视图属性副本需要 20 微秒。
- 通过 getter 函数获取每个属性值会导致每个视图进行许多额外的函数调用,从而耗费 110 微秒。
因此,在始终开启跟踪 (AOT) 中启用 ViewCapture 会对系统性能产生负面影响,并导致卡顿。由于这些性能和内存限制,此方法尚未为 AOT 做好准备。我们建议仅将 ViewCapture 用于实验室和本地调试。
内存
Perfetto 的 ViewCapture 追踪方法使用单个环形缓冲区,该缓冲区具有预定义的内存占用空间,以防止过度使用内存。这种方法通过避免为每个窗口使用单独的环形缓冲区来防止过度消耗内存,但无法解决在 Perfetto 中为每一帧存储整个视图层级结构的问题。记录单个窗口(如 NexusLauncher)可能会在 10 MB 的缓冲区中产生超过 30 秒的 ViewCapture 数据。但是,从 System UI 捕获超过 30 个窗口需要更大的缓冲区或大大缩短录制时间窗口。
说明
请按照以下说明在系统应用中启用 ViewCapture
将依赖项添加到您的
Android.bp
文件中,如Launcher 代码中所示。android_library { name: "YourLib", static_libs: [ ... "//frameworks/libs/systemui:view_capture", ... ], platform_apis: true, privileged: true, }
在创建窗口时创建 ViewCapture 实例,例如
示例 1:
private SafeCloseable mViewCapture; @Override protected void onCreate(Bundle savedInstanceState) { ... mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow()); }
示例 2:
private SafeCloseable mViewCapture; @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (enableViewCaptureTracing()) { mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext()) .startCapture(getRootView(), ".NotificationShadeWindowView"); } ... }
在销毁窗口时关闭 ViewCapture 实例,如以下示例所示