シミュレーターでスクリーンショットを撮るのはCmd+Shift+4で終わる話ですが、実機のFire TV(Vega)は勝手が違います。最初はvega device screenshotのようなコマンドがあるだろうと決めつけて探し回りましたが、そんなものは存在しませんでした。答えはgwsi-tool-screenshooterという聞き慣れないバイナリと、XDG_RUNTIME_DIRの指定です。
シミュレーターは素直、実機は一癖ある
シミュレーターならウィンドウをそのままキャプチャできるので悩む余地がありません。実機の場合はデバイス内部でスクリーンショットを生成してから、ホストにコピーしてくる、という二段構えになります。ここで最初につまずくのが、コマンドの選び方です。
なぜscreenshooterではなくgwsi-tool-screenshooterなのか
Fire TV上には/usr/bin/screenshooterという、名前からしていかにもそれっぽいバイナリが存在します。自分も最初はこれを叩いて済ませようとしました。ところがこのscreenshooterはwl_shm(Waylandの共有メモリ)を使う実装になっていて、Vegaのseccompサンドボックスではmemfd_createというsyscallそのものがブロックされているため動きません。
代わりに使うのが/usr/bin/gwsi-tool-screenshooterです。これはAmazon独自のGWSI(Graphics Wayland Surface Interface)とOBM(Open Buffer Manager)を経由し、DRMバッファを直接扱う実装になっています。共有メモリ経由のパスを通らないぶん、seccompの制限に引っかからずに撮影できるという理屈です。
名前が似ているぶん紛らわしいのですが、「標準っぽい方は動かない、独自ツールの方が正解」という逆転がこの手のプラットフォーム特有の落とし穴だと思います。
実際の手順
VEGA_DEVICE_ID=`vega device list | awk 'NR!=1 {if($1!="VirtualDevice"){print $1}}'`
# ① デバイス内にスクリーンショットを保存
# XDG_RUNTIME_DIR=/run/display が必須(Waylandソケットの場所を指定するため)
vega device run-cmd --device $VEGA_DEVICE_ID --command 'XDG_RUNTIME_DIR=/run/display gwsi-tool-screenshooter /tmp/screenshot.png'
# ② ホストマシンにコピー
# --destination screenshot.png はコマンドを実行したカレントディレクトリに保存される
vega device copy-from --device $VEGA_DEVICE_ID --source /tmp/screenshot.png --destination screenshot.png
# ③ Finder で開く
open screenshot.png
1行目のawkはvega device listの出力からヘッダー行(NR!=1)を飛ばし、VirtualDevice(シミュレーター)を除外して実機のIDだけを拾っています。複数の実機をつないでいる環境だと、ここで意図しないデバイスIDを掴んでしまうことがあるので、VEGA_DEVICE_IDの中身を一度echoで確認してから次に進むと安全です。
XDG_RUNTIME_DIR=/run/displayを省略するとgwsi-tool-screenshooterはWaylandソケット(/run/display/wayland-0)とコンポジター(SystemGlass)を見つけられません。環境変数ひとつでハマりどころになるので、コマンドを写経するときにここだけ削らないよう注意してください。
デバイス一覧の確認
vega device list
DeviceId Status Type
VirtualDevice Running Simulator
192.168.x.x:xxxx Connected Device
Androidを触ったことがあればadb devicesの感覚そのままで読めます。Type列でSimulatorとDeviceが並んでいるので、複数台つないでいるときはここでどのIDが実機かを目視で確認してから作業に入るのが確実です。