1. はじめに
ページの読み込み中、およびその後にユーザーがページとやり取りしている間、アプリケーションと ブラウザーの両方がさまざまなイベントをキューに入れ、それらはその後ブラウザーによって実行される。たとえば、ユーザーエージェントは ユーザーの活動に基づいて入力イベントをスケジュールし、アプリケーションは requestAnimationFrame やその他のコールバックの コールバックをスケジュールする、などである。キューに入ると、ブラウザーはこれらのイベントを 1 つずつキューから取り出して実行する。
しかし、一部のタスクは長時間(複数フレーム)かかることがあり、その場合、UI スレッドが ブロックされ、他のすべてのタスクもブロックされる可能性がある。ユーザーには、これは一般に、ブラウザーがユーザー入力に 応答できない「ロックアップした」ページとして見える。これは今日の Web における悪いユーザー体験の大きな原因である:
- 遅延した「インタラクティブまでの時間」:
-
ページの読み込み中、あるいは完全に視覚的にレンダリングされた後であっても、長いタスクはしばしばメイン スレッドを占有し、ユーザーがページとやり取りすることを妨げる。設計の悪いサードパーティコンテンツが しばしば原因となる。
- 高い/変動する入力レイテンシ:
-
重要なユーザー操作イベント(例: tap、click、scroll、wheel など)は長いタスクの後ろにキューされ、 ぎこちなく予測できないユーザー体験をもたらす。
- 高い/変動するイベント処理レイテンシ:
-
入力と同様に、イベントコールバック(例: onload イベントなど)の処理はアプリケーションの更新を遅延させる。
- ぎこちないアニメーションとスクロール:
-
一部のアニメーションおよびスクロール操作には、コンポジターとメインスレッド間の協調が必要である。 長いタスクがメインスレッドをブロックしている場合、アニメーションとスクロールの応答性に影響を与える可能性がある。
一部のアプリケーション(および RUM ベンダー)は、 「長いタスク」が発生する場合を特定し追跡しようとすでに試みている。たとえば、既知のパターンの 1 つは、 短い周期タイマーを設置し、連続する発火間の経過時間を調べることである。経過時間が タイマー周期より大きい場合、1 つ以上の長いタスクがイベントループの実行を遅延させた可能性が高い。 この方法はおおむね機能するが、いくつかの悪いパフォーマンス上の影響がある。長いタスクを検出するためにポーリングすることで、 アプリケーションは静止状態と長いアイドルブロックを妨げる(requestIdleCallback を参照)。バッテリー寿命に悪影響を及ぼす。 遅延の原因が何であるか(例: ファーストパーティコードかサードパーティコードか)を知る方法がない。
RAIL パフォーマンスモデルは、 アプリケーションはユーザー入力に 100ms 未満で応答すべきであると示唆している(タッチ移動とスクロールでは、 しきい値は 16ms である)。この API の目的は、アプリケーションがこれらの目標を達成するのを妨げる可能性のある タスクについて通知を表面化することである。この API は 50ms 以上かかるタスクを表面化する。これらのタスクがない Web サイトは、 ユーザー入力に 100ms 未満で応答できるはずである。ユーザー入力を受け取った時点で実行中のタスクを完了するのに 50ms 未満、そのようなユーザー入力に反応するタスクを実行するのに 50ms 未満で済むからである。
1.1. 使用例
const observer= new PerformanceObserver( function ( list) { for ( const entryof list. getEntries()) { // 長いタスク通知を処理する: // 分析と監視のために報告する // ... } }); // 過去および将来の長いタスク通知のためにオブザーバーを登録する。 observer. observe({ type: "long-animation-frame" , buffered: true }); // この後の長いスクリプト実行により、オブザーバー内で // "long-animation-frame" エントリがキューされ、受信される。 // 過去および将来の長いアニメーションフレーム通知のためにオブザーバーを登録する。 // この後、メインスレッドがビジーである長い期間により、オブザーバー内で // "long-animation-frame" エントリがキューされ、受信される。 observer. observe({ type: "long-animation-frame" , buffered: true });
1.2. 長いアニメーションフレームと長いタスク
long tasks と長いアニメーションフレームはいずれも混雑とジャンクを測定するが、長い アニメーションフレームは、 ユーザーがこの種の混雑をどのように知覚するかとよりよく相関する情報を提供する。 これは、長いアニメーションフレームが、メインスレッドがアイドルになったときに始まり、 フレームがレンダリングされるか、またはユーザーエージェントがレンダリングするものはないと判断したときに終わるシーケンスを測定するためである。
task という用語は実装詳細のようなものであり、長いアニメーション フレームの追加は、 メインスレッドの混雑/ジャンクという同じ現象について、よりユーザー中心の指標を導入することによってそれを改善しようとする。
長いアニメーションフレームはレンダリングフェーズが最大 1 つであることが保証されるため、
レンダリングフェーズ自体に関する追加情報、たとえば
renderStart
や styleAndLayoutStart
も公開できる。
2. 長いアニメーションフレームのタイミング
long animation frame は、継続時間が 50ms を超える次のいずれかの発生を指す:
Long Animation Frame timing には、次の新しいインターフェイスが含まれる:
2.1. PerformanceLongAnimationFrameTiming
インターフェイス
[Exposed =Window ]interface :PerformanceLongAnimationFrameTiming PerformanceEntry { /* PerformanceEntry のオーバーロード */readonly attribute DOMHighResTimeStamp ;startTime readonly attribute DOMHighResTimeStamp ;duration readonly attribute DOMString ;name readonly attribute DOMString ;entryType readonly attribute DOMHighResTimeStamp ;renderStart readonly attribute DOMHighResTimeStamp ;styleAndLayoutStart readonly attribute DOMHighResTimeStamp ;blockingDuration readonly attribute DOMHighResTimeStamp ; [firstUIEventTimestamp SameObject ]readonly attribute FrozenArray <PerformanceScriptTiming >; [scripts Default ]object (); };toJSON PerformanceLongAnimationFrameTiming includes PaintTimingMixin ;
PerformanceLongAnimationFrameTiming
は frame timing info
timing info を持つ。
entryType
属性の getter 手順は、 を返すことである。
name
属性の getter 手順は、 を返すことである。
startTime
属性の getter 手順は、relative high resolution time を返すことである。これは this の timing info の start time と this の relevant global object が与えられたものである。
duration
属性の getter 手順は、duration を返すことである。これは this の startTime
と、relative high resolution time との間のものである。後者は this の timing info の end time と this の relevant global object が与えられたものである。
renderStart
属性の getter 手順は、relative high resolution time を返すことである。これは this の timing info の update the rendering start time と
this の relevant global object が与えられたものである。
styleAndLayoutStart
属性の getter 手順は、relative high resolution time を返すことである。これは this の timing info の style and layout start time と this の relevant global object が与えられたものである。
firstUIEventTimestamp
属性の getter 手順は、relative high resolution time を返すことである。これは this の timing info の first ui event timestamp と this の relevant global object が与えられたものである。
blockingDuration
属性の getter 手順は次のとおりである:
-
sortedTaskDurations を timing info の task durations を 降順にソートしたものとする。
-
this の timing info の update the rendering start time が 0 でない場合、次を実行する:
-
renderDuration を、duration とする。これは this の
renderStartと relative high resolution time との間のものであり、後者は this の timing info の end time が与えられたものである。 -
sortedTaskDurations[0] を renderDuration だけ増加させる。
注: これにより、最長の task duration + render duration は、その合計 duration が >50ms であれば blocking とみなされる。
-
-
totalBlockingDuration を 0 とする。
-
sortedTaskDurations 内の各 duration について 反復し、 duration が 50 より大きい場合、totalBlockingDuration を duration - 50 だけ増加させる。
-
totalBlockingDuration を返す。
scripts
属性の getter 手順は次のとおりである:
-
scripts を list « » とする。
-
entryWindow を this の relevant global object とする。
-
For each scriptInfo in this の frame timing info の scripts:
-
scriptWindow を scriptInfo の window とする。
-
scriptEntry を、this の relevant realm 内の新しい
PerformanceScriptTimingとする。 その timing info は scriptInfo であり、その window attribution は 最初に一致する文に対応する値である:- scriptWindow is undefined
- scriptWindow is entryWindow
- entryWindow の関連
Documentの node navigable の ancestor navigables が、scriptWindow の関連Documentの node navigable を contains する - scriptWindow の関連
Documentの node navigable の ancestor navigables が、entryWindow の関連Documentの node navigable を contains する - entryWindow の関連
Documentの node navigable の top-level traversable が、scriptWindow の 関連Documentの node navigable の top-level traversable である - Otherwise
-
scriptEntry を scripts に append する。
-
-
scripts を返す。
2.2.
PerformanceScriptTiming
インターフェイス
enum {ScriptInvokerType ,"classic-script" ,"module-script" ,"event-listener" ,"user-callback" ,"resolve-promise" };"reject-promise" enum {ScriptWindowAttribution ,"self" ,"descendant" ,"ancestor" ,"same-page" }; ["other" Exposed =Window ]interface :PerformanceScriptTiming PerformanceEntry { /* PerformanceEntry のオーバーロード */readonly attribute DOMHighResTimeStamp ;startTime readonly attribute DOMHighResTimeStamp ;duration readonly attribute DOMString ;name readonly attribute DOMString ;entryType readonly attribute ScriptInvokerType ;invokerType readonly attribute DOMString ;invoker readonly attribute DOMHighResTimeStamp ;executionStart readonly attribute DOMString ;sourceURL readonly attribute DOMString ;sourceFunctionName readonly attribute long long ;sourceCharPosition readonly attribute DOMHighResTimeStamp ;pauseDuration readonly attribute DOMHighResTimeStamp ;forcedStyleAndLayoutDuration readonly attribute Window ?;window readonly attribute ScriptWindowAttribution ; [windowAttribution Default ]object (); };toJSON
PerformanceScriptTiming
は、関連する script
timing info timing info を持つ。
PerformanceScriptTiming
は、関連する ScriptWindowAttribution
window attribution を持つ。
entryType
属性の getter 手順は、 を返すことである。
name
属性の getter 手順は、 を返すことである。
invokerType
属性の getter 手順は、this の timing info の invoker type
を返すことである。
invoker
属性の getter 手順は次のとおりである:
-
this の
invokerTypeに応じて分岐する:- "`classic-script`"
- "`module-script`"
-
this の timing info の source url を返す。
- "`event-listener`"
-
-
targetName を this の timing info の invoker name とする。
-
this の timing info の event target element id が空文字列でない場合: targetName を « targetName, "#", this の timing info の event target element id » の concatenation に設定する。
-
そうでなく、this の timing info の event target element src attribute が空文字列でない場合: targetName を « targetName, "[src=", this の timing info の event target element src attribute, "]" » の concatenation に設定する。
-
« targetName, ".on", this の timing info の event type » の concatenation を返す。
-
- "`user-callback`"
-
this の timing info の invoker name を返す。
- "`resolve-promise`"
- "`reject-promise`"
-
-
this の timing info の invoker name が空文字列である場合、 次を実行する:
-
this の
invokerTypeが "`resolve-promise`" であれば、"`Promise.resolve`" を返す。 -
そうでなければ、"`Promise.reject`" を返す。
-
-
invokerTypeが "`resolve-promise`" であれば thenOrCatch を "`then`" とし、そうでなければ "`reject-promise`" とする。 -
« invoker name, ".", thenOrCatch » の concatenation を返す。
-
- "`classic-script`"
startTime
属性の getter 手順は、relative high resolution time を返すことである。これは this の timing info の start time と this の relevant global object が与えられたものである。
duration
属性の getter 手順は、duration を返すことである。これは this の startTime
と、relative high resolution time との間のものである。後者は this の timing info の end time と this の relevant global object が与えられたものである。
executionStart
属性の getter 手順は、this の timing
info の execution start time が 0 であれば 0 を返し、そうでなければ relative high resolution time を返すことである。これは this の timing info の execution start time と this の relevant global object が与えられたものである。
forcedStyleAndLayoutDuration
属性の getter 手順は、スタイルとレイアウトを同期的に実行するために費やされた時間を表す
implementation-defined な値を返すことである。たとえば getComputedStyle()
や getBoundingClientRect()
の呼び出しによるものである。
これを 相互運用可能/規範的にする方法を見つける。おそらく WebIDL でこれらの関数を同期スタイル/レイアウトを必要とするものとしてマークするか? それが解決したら timing info に移す。
pauseDuration
属性の getter 手順は、this の timing info の pause
duration を返すことである。
sourceURL
属性の getter 手順は、this の timing info の source url
を返すことである。
sourceFunctionName
属性の getter 手順は、this の timing info の source function name を返すことである。
sourceCharPosition
属性の getter 手順は、this の timing info の source character position を返すことである。
window
属性の getter 手順は次のとおりである:
-
window を、deref を this の timing info の window に対して呼び出した結果とする。
-
window が undefined であれば null を返し、そうでなければ window を返す。
windowAttribution
属性の getter 手順は、this の window attribution を返すことである。
3. 処理モデル
注: Long Animation Frame
API を実装するユーザーエージェントは、それぞれ
を supportedEntryTypes
に、Window
コンテキスト用に含める必要がある。
3.1. フレームタイミング情報
frame timing info は、 長いアニメーションフレームのアルゴリズムによって帳簿管理の詳細として使用される struct である。 これは次の items を持つ:- start time
- current task start time
- update the rendering start time
- style and layout start time
- first ui event timestamp
- end time
- current task start time
-
DOMHighResTimeStamp。 初期値は 0。 注: 上記はすべて unsafe であり、 API を介して公開されるときには coarsened されるべきである。 - task durations
-
DOMHighResTimeStampの list。 初期値は空である。 - scripts
-
script timing info の list。 初期値は空である。
- pending script
-
Null または script timing info。初期値は null である。
script timing info は struct である。これは 次の items を持つ:
- invoker type
- start time
- end time
- execution start time
- end time
-
unsafe な
DOMHighResTimeStamp。 初期値は 0。 - pause duration
-
ミリ秒数を表す
DOMHighResTimeStamp。 初期値は 0。 - invoker name
- source url
- source function name
- event type
- event target element id
- event target element src attribute
- source url
-
文字列。初期値は空文字列である。
- source character position
-
数値。初期値は -1。
- window
Document
は、null または frame timing
info である current
frame timing info を持つ。初期値は null である。
3.2. 長いアニメーションフレームを報告する
3.2.1. 長いアニメーションフレームの監視 {#loaf-monitoring}
Document
document について nearest
same-origin root を取得するには:
-
ancestors を document の ancestor navigables とする。
-
ancestors 内の各 ancestorNavigable について 反復する: ancestorNavigable の active document の origin が document の origin と same origin であり、 かつ ancestorNavigable の active document の relevant agent が document の relevant agent である場合、 ancestorNavigable の active document を返す。
-
document を返す。
Document
document の relevant
frame timing info は、その nearest same-origin root の current frame timing
info である。
DOMHighResTimeStamp
unsafeTaskStartTime と Document
document が与えられたときに、record task start
time するには:
-
root を document の nearest same-origin root とする。
-
root の current frame timing info が null である場合、 root の current frame timing info を新しい frame timing info に設定する。その start time は unsafeTaskStartTime である。
-
root の current frame timing info の current task start time を unsafeTaskStartTime に設定する。
-
root の current frame timing info の 's start time が 0 の場合、root の current frame timing info の start time を unsafeTaskStartTime に設定する。
DOMHighResTimeStamp
unsafeTaskEndTime と Document
document が与えられたときに、record task end
time するには:
-
timingInfo を document の relevant frame timing info とする。
-
timingInfo が null の場合、return する。
注: これは、シーケンス中にブラウザーが hidden になった場合に発生しうる。
-
safeTaskEndTime を、unsafeTaskEndTime と document の relevant global object が与えられた relative high resolution time とする。
-
safeTaskStartTime を、timingInfo の current task start time と document の relevant global object が与えられた relative high resolution time とする。
-
safeTaskStartTime と safeTaskEndTime の間の duration を timingInfo の task durations に append する。
-
ユーザーエージェントが、document の node navigable のレンダリングを更新しても可視効果がないと考える場合:
-
document の nearest same-origin root の current frame timing info を null に設定する。
-
frameDuration を、timingInfo の start time と global が与えられた relative high resolution time と、unsafeTaskEndTime と global が与えられた relative high resolution time との間の duration とする。
-
frameDuration が 50 ミリ秒以上である場合、document、timingInfo、および新しい [/=paint timing info=] が与えられた queue a long animation frame entry を実行する。
注: 実際の視覚的更新がなかったとしても、 ここで long animation frame としてマークする。これは、無関係な視覚的更新と一致したシナリオでは blocking になるためである。
-
Document
document と DOMHighResTimeStamp
unsafeStyleAndLayoutStart が与えられたときに、record rendering
time するには:
-
timingInfo を document の relevant frame timing info とする。
-
timingInfo が null の場合、return する。
注: これは、シーケンス中にブラウザーが hidden になった場合に発生しうる。
-
frameDuration を、timingInfo の start time と global が与えられた relative high resolution time と、 global が与えられた current high resolution time との間の duration とする。
-
frameDuration が 50 ミリ秒未満である場合、document の nearest same-origin root の current frame timing info を null に設定し、return する。
-
timingInfo の update the rendering start time を timingInfo の current task start time に設定する。
-
timingInfo の style and layout start time を unsafeStyleAndLayoutStart に設定する。
Document
document、frame
timing info timingInfo、および paint timing
info paintTimingInfo が与えられたときに、queue a
long animation frame entry するには、
document の relevant realm 内の新しい PerformanceLongAnimationFrameTiming
を queue する。
その timing info は timingInfo
であり、その paint timing info は paintTimingInfo である。
3.2.2. 長いスクリプトの監視
-
scriptTimingInfo の invoker name を callback の identifier に設定する。
-
callback が与えられた scriptTimingInfo に対して Apply source location を実行する。
Function
handler、environment settings object settings、および
boolean
repeat が与えられたときに、record
timing info for timer handler するには:
settings、"`user-callback`"、
および script timing
info scriptTimingInfo が与えられた次の手順を用いて、
Create
script entry point を実行する:
-
repeat が true であれば setTimeoutOrInterval を "setInterval" とし、 そうでなければ "setTimeout" とする。
-
scriptTimingInfo の invoker name を « TimerHandler:", setTimeoutOrInterval » の concatenation に設定する。
-
handler が
Functionであれば、handler が与えられた scriptTimingInfo に対して apply source location を実行する。
Event
event と EventListener
listener が与えられたときに、record timing info for event listener するには:
listener の relevant settings object、"`event-listener`"、
および script timing
info scriptTimingInfo と frame timing info
frameTimingInfo が与えられた次の手順を用いて、Create
script entry point を実行する:
-
scriptTimingInfo の event type を event の
typeに設定する。 -
target を event の
currentTargetとする。 -
target が
Nodeであれば、次を実行する:-
scriptTimingInfo の invoker name を target の
nodeNameに設定する。 -
target が
Elementであれば、次を実行する:-
scriptTimingInfo の event target element id を target の id に設定する。
-
scriptTimingInfo の event target element src attribute を、target と "`src`" について getting an attribute value by name した結果に設定する。
-
-
-
そうでなければ、scriptTimingInfo の invoker name を target の interface name に設定する。
-
listener の callback が与えられた scriptTimingInfo に対して Apply source location を実行する。
-
event が
UIEventであり、 かつ frameTimingInfo の first ui event timestamp が 0 の場合、 frameTimingInfo の first ui event timestamp を event のtimeStampに設定する。
Promise
promise と "`resolve-promise`" または "`reject-promise`" の type が与えられたときに、
record
timing info for promise resolver するには:
-
promise の relevant realm の settings object、type、 および script timing info scriptTimingInfo が与えられた次の手順を用いて Create script entry point を実行する:
-
scriptTimingInfo の invoker name を promise の invoker name when created に設定する。
-
scriptTimingInfo の source url を promise の script url when created に設定する。
-
-
url が null の場合、return する。
-
url の scheme が "`http`" または "`https`" であれば、 scriptTimingInfo の source url を script の base URL に設定する。
-
そうでなく、url の scheme が "`blob`" または "`data`" であれば、 scriptTimingInfo の source url を « url の scheme, ":"" » の concatenation に設定する。
-
script の settings object、"`classic-script`"、 および script timing info scriptTimingInfo が与えられた次の手順を用いて Create script entry point を実行する: scriptTimingInfo、script、および originalSourceURL が与えられた Set source url for script block を実行する。
-
settings を script の settings object とする。
-
script の muted errors が true であれば、return する。
-
settings が
Windowでなければ、return する。 -
document を settings の
documentとする。 -
frameTimingInfo を document の relevant frame timing info とする。
-
frameTimingInfo が null、または frameTimingInfo の pending script が null でない場合、return する。
-
Assert: frameTimingInfo の pending script の invoker type は "`classic-script`" である。
-
frameTimingInfo の pending script の execution start time を unsafe shared current time に設定する。
-
scriptTimingInfo の execution start time を script の scriptTimingInfo の start time に設定する。
-
scriptTimingInfo、script、および script の base URL が与えられた Set source url for script block を実行する。
ScriptInvokerType
invokerType、および steps が与えられたときに、create script
entry point するには。
ここで steps は、script timing info と任意の frame timing info を取るアルゴリズムである:
-
settings が
Windowでなければ、return する。 -
document を settings の
documentとする。 -
document が fully active でない、または
である場合、return する。 -
frameTimingInfo を document の relevant frame timing info とする。
-
frameTimingInfo が null の場合、return する。
-
frameTimingInfo の pending script が null でない場合、return する。
-
scriptTimingInfo を新しい script timing info とする。 その start time は unsafe shared current time であり、 その invoker type は invokerType である。
-
steps を scriptTimingInfo と frameTimingInfo が与えられたものとして実行する。
-
scriptTimingInfo の window を settings に設定する。
-
frameTimingInfo の pending script を scriptTimingInfo に設定する。
-
script を running script とする。
-
settings を script の settings object とする。
-
document を settings の
documentとする。 -
document が fully active でない、または
である場合、return する。 -
frameTimingInfo を document の relevant frame timing info とする。
-
scriptTimingInfo を frameTimingInfo の pending script とする。
-
frameTimingInfo の pending script を null に設定する。
-
scriptTimingInfo が null の場合、return する。
-
scriptTimingInfo の end time を unsafe shared current time に設定する。
-
script が classic script であり、その muted errors が true である場合:
-
scriptTimingInfo の source url を空文字列に設定する。
-
scriptTimingInfo の source character position を -1 に設定する。
-
scriptTimingInfo の source function name を 空文字列に設定する。
-
-
scriptTimingInfo の start time と scriptTimingInfo の end time の間の duration が 5 ミリ秒より大きい場合、 scriptTimingInfo を frameTimingInfo の scripts に append する。
Function
callback が与えられたときに、scriptTimingInfo に apply source
location するには:
-
ユーザーエージェントは、scriptTimingInfo の source url を、callback が定義されたスクリプトのソース URL に設定してよい。
-
ユーザーエージェントは、scriptTimingInfo の source function name を callback の関数名に設定してよい。
-
ユーザーエージェントは、scriptTimingInfo の source character position を callback が定義された文字位置に設定してよい。
-
script を running script とする。
-
settings を script の settings object とする。
-
settings が
Windowでなければ、return する。 -
document を settings の
documentとする。 -
document が fully active でない、または
である場合、return する。 -
frameTimingInfo を document の relevant frame timing info とする。
-
frameTimingInfo が null の場合、return する。
-
frameTimingInfo の pending script が null の場合、return する。
-
frameTimingInfo の pending script の pause duration を、 duration のミリ秒値だけ増加させる。
4. 既存の標準への追加
4.1. WebIDL 標準へのモンキーパッチ
Promise
インターフェイスは、関連する文字列 invoker name when created を持つ。初期値は
"`Promise`" である。
Promise
インターフェイスは、関連する文字列 script url when created を持つ。初期値は空
文字列である。
creating a new
promise に、Promise
を返す前に、
次の手順を追加する:
-
interfaceName を、この promise の作成に責任を持つ interface を表す文字列とする。
-
attributeName を、この promise の作成に責任を持つ interface 内の attribute を表す文字列とする。
-
作成された
Promiseの script url when created を running script の base URL に設定する。 -
ユーザーエージェントは、作成された
Promiseの invoker name when created を、 « interfaceName, ".", attributeName » の最後に知られた concatenation に設定してよい。これはかなり 曖昧である。規範的な方法で行うことが難しいためである。 これを改善できるか、あるいは promise ハンドラーの source location は多少 implementation-defined のままになるのかを確認する必要がある。
Promise
p が与えられた resolve a promise
に、次の手順を前置する:
p と "`resolve-promise`" が与えられた
Record timing info for promise resolver
を実行する。
Promise
p が与えられた reject a promise に、
次の手順を前置する:
p と "`reject-promise`" が与えられた
Record timing info for promise resolver
を実行する。
5. セキュリティおよびプライバシーの考慮事項
Long Animation Frames API は、長いタスクのソースに関する origin-safe attribution information を含めることで same-origin policy に従う。長いタスクには 50ms のしきい値がある。継続時間は 1 ms の粒度でのみ提供される。これらにより、クロスオリジン漏洩に対して十分な保護が提供される。
Long Animation Frames API は、ユーザーによって実行されたタスクの継続時間と種類に関するタイミング情報、 および関数呼び出しを引き起こした browsing context などの attribution を提供する。これにより、攻撃者が ユーザーの行動を推測したり、ユーザーを識別したりするためのサイドチャネルタイミング攻撃を実行できる可能性がある。 たとえば、長いスクリプトの後に長いレンダーが続くパターンを組み合わせて、ソーシャル ウィジェットに対するユーザーの操作を推測できる。詳細な関数呼び出し attribution は、ユーザーの行動を特定するために使用されうる。
5.1. オブザーバーには何が公開されるか?
トップレベルページ内のすべてのオブザーバー(すなわち、ページ内のすべての iframe とメインフレーム)は、 長いアニメーションフレームの存在に関する通知を受け取る。タスクの開始時刻、その継続時間 (1 ms の粒度)、および原因となるフレームへのポインターを公開する。この情報は現在でも、 setTimeout を用いて、より高い解像度で観測できる。攻撃者は、ページ上の他のものをすべて消去し、 脆弱なクロスオリジンリソースを追加して、setTimeout からの遅延がそのリソースにより引き起こされることを保証することで、 これを行える。他の異なるページ(タブまたはウィンドウ)のオブザーバーは、ユーザーエージェントの アーキテクチャに関係なく通知を受け取るべきではない。
5.2. 考慮された攻撃シナリオ
考慮されたタイミング攻撃は次のとおりである:
-
従来のタイミング攻撃: 外部リソースの読み込み時間を用いて、 private data のサイズを明らかにする。たとえば、ギャラリー内の隠し画像の数、ユーザー名が 有効かどうか、などである。例を参照。
-
サイドチャネルタイミング攻撃: 動画解析、スクリプト解析、App Cache 読み取り、 または Cache API(service workers)の使用にかかる時間を用いて、ユーザーを一意に識別したり、 ユーザーの年齢、性別、場所、興味などのプロファイルを作成したりする。 たとえば、ソーシャルネットワークからの ステータス更新を特定の属性(例: 20〜30 歳の女性)に限定できる場合、パーマリンクページのファイルサイズを 用いて、ユーザーが対象属性に含まれるかどうかを判断できる。
これらのシナリオは、50ms しきい値とクロスオリジン境界の尊重、すなわち信頼されていないクロスオリジン オブザーバーにタスクの種類や追加の attribution を表示しないことによって対処される。
5.3. Long Animation Frames API によって公開される追加情報
複数のクロスオリジン文書が同じイベントループを共有できるため、それらは同じフレームシーケンスの一部として レンダリングされ、互いのレンダリング時間に影響を与えることもできる。これにより、これらのタイミングは すでにある程度クロスオリジンで観測可能である。たとえば、animation frame を要求し、それが遅延するかどうかを観測することである。 ただし、長いアニメーションフレームはそれらをより高い忠実度で公開する。これを緩和するために、長いアニメーションフレームは「participating local roots」にのみ報告される。 シーケンスに寄与した作業タスクに関連付けられた文書、またはフレームの一部としてレンダリングされた文書のみが、 長いアニメーションフレームを観測する資格を持ち、その長いアニメーションフレームは、topmost であるか クロスオリジン親を持つ最も近い祖先においてのみ利用可能となる。
5.4. PerformanceScriptTiming
と不透明なスクリプト
PerformanceScriptTiming
はスクリプト実行に関する情報を公開するため、
それ以外では容易に推測できない CORS
cross-origin スクリプトに関する情報を過剰に公開しないようにする必要がある。
そのために、既存の muted errors
boolean を使用し、そのような場合には空の sourceURL
を報告する。