ViewCapture はフックされたウィンドウに関連付けられたビューのプロパティ(位置、サイズ、スケール、表示状態など)をキャプチャするソフトウェア ツールです。ViewCapture ではウィンドウ内のさまざまなビューに関する情報とビューのプロパティをキャプチャできるため、特定の瞬間のユーザー エクスペリエンスの状態を把握し、変更の履歴をトラッキングできます。
画面の録画でも特定の瞬間のビューの状態を可視化して、ビューがどのように変化しているかを確認できますが、膨大な量の CPU リソースが必要となるため、パフォーマンスに影響を及ぼします。ViewCapture ツールの場合、リソースへの影響が少ないため、より頻繁に使用できます。さらに、ViewCapture ではビューレベルでフレームごとに表示できるため、画面の録画に比べて、特定の瞬間のビューの状態をより簡単に確認できます。
このページでは、システムアプリでの ViewCapture のオンボーディングの方法について説明します。
使用
ViewCapture.java
は onDrawListener
のインスタンスを実装し、描画プロセス時の ViewCapture トレースを収集します。フレームの再描写のたびに、ウィンドウのルートビューから始まる、ビューのツリー階層のトラバーサルがトリガーされます。ViewCapture は View.java
公開ゲッター メソッドを使用して値を取得し、バックグラウンド スレッドにコピーして、パフォーマンスを高めます。ViewCapture 実装はこのプロセスを最適化するために、captureViewTree
を使用して、ビューがダーティか無効かどうかを確認し、ビュー階層全体のトラバーサルを回避します。captureViewTree
はシステムアプリでのみ利用できる、UnsupportedAppUsage API の一つです。この API の使用はターゲット SDK のバージョンのアプリに制限されます。
制限事項
次のセクションでは、ViewCapture の実行時のパフォーマンスとメモリの制限について説明します。
パフォーマンス
ViewCapture パフォーマンスのメインスレッドの平均オーバーヘッドは 195 μs です。ただし、最悪のケースでは約 5 ms となる場合があります。Perfetto トレースの vc#onDraw
スライスをご参照ください。
オーバーヘッド コストは主に次のアクションにより発生します。
- 階層のトラバーサルはプルーニングされているときでも 50 μs かかります。
- フリーリスト アロケータからオブジェクトを取得して、ビュー プロパティのコピーを格納すると 20 μs かかります。
- ゲッター関数を使用して各プロパティの値を取得すると、ビューごとに追加で多くの関数呼び出しが必要となり、110 μs かかります。
このため、ViewCapture の常時トレース(AOT)を有効にすると、システム パフォーマンスに悪影響を及ぼし、ジャンクにつながります。このようなパフォーマンスとメモリの制限があるため、このアプローチに AOT は適していません。ViewCapture はラボとローカルでのデバッグにのみ使用することをおすすめします。
メモリ
Perfetto での ViewCapture トレース メソッドは、単一のリングバッファを使用します。これはメモリ使用量が事前に決まっているため、過剰なメモリの使用を抑制できます。このアプローチでは、各ウィンドウに個別のリングバッファを使用しないようにして、過剰なメモリの消費を防ぎます。ただし、各フレームの Perfetto のそれぞれの状態に関するビュー階層全体を保存する問題は解消されません。NexusLauncher などの単一ウィンドウを記録すると、10 MB バッファで 30 秒以上の ViewCapture データが生成されます。ただし、システム UI から 30 以上のウィンドウをキャプチャする場合、より大きなバッファが必要になるか、大幅に録画時間を短縮する必要があります。
手順
次の手順に沿って、システムアプリでの ViewCapture のオンボーディングができます。
ランチャー コードのとおり、依存関係を
Android.bp
ファイルに追加します。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 インスタンスを閉じます。