RFC-0177:父項檢視表的焦點觀察器 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 父項檢視畫面的 API,可瞭解焦點在檢視區塊樹狀結構中的移動方式 |
問題 | |
更小鳥 | |
作者 | |
審查人員 | |
提交日期 (年月分) | 2022-06-06 |
審查日期 (年-月-日) | 2022-07-07 |
摘要
這個 RFC 提議採用 API 設計來確保「檢視區塊焦點」可以安全地由一般 UI 用戶端使用樹狀結構,並釐清焦點觀測能力相關安全限制。重點在於確保資訊外洩的最低程度,以及提供優雅的開發人員體驗。
提振精神
為了透過多個元件打造使用者體驗 (圖形、輸入等),UI 用戶端經常設定檢視畫面樹狀結構,透過上層檢視區塊管理一或多個子項檢視畫面,藉此將內容產生工作委派給其他 UI 用戶端。Ermine 系統殼層就是其中一個範例,另一個是 Google 的智慧螢幕。父項檢視畫面的主要責任之一是監控檢視區塊焦點狀態:
- 如要找出父項檢視畫面可能以程式輔助方式將檢視焦點移至子項檢視畫面的時機,
- 舉例來說,如果父項檢視畫面不在檢視區塊樹狀結構的焦點鏈中 (https://fxbug.dev/42168713),父項檢視區塊的要求就會失敗,導致焦點移至子項檢視畫面。
- 如果檢視畫面焦點移至子項檢視畫面,請識別目前顯示焦點的子項。
- 舉例來說,如果使用者以輕觸的方式將焦點移至某個檢視區塊,則父項檢視區塊可能會想以焦點界線裝飾該子檢視區塊,而且需要瞭解發生時間以及子項檢視區塊的身分。
焦點可能會在未經父項檢視畫面介入的情況下變更 (使用者輕觸、卸離檢視畫面等)。父項檢視畫面必須掌握檢視畫面焦點的移動方式,但須遵循全域檢視區塊樹狀結構設定的資訊限制。
此 RFC 提出了「聚焦觀察器」設計,這 (1) 可讓父項檢視區塊正確回應檢視畫面焦點變更;(2) 可以安全使用樹狀結構,以及 (3) 以盡量減少資訊外洩情形的方式改善 Fuchsia View 系統的安全防護機制。
相關人員
講師:
審查者:sanjayc@google.com (工作站)、quiche@google.com (HCI)、neelsa@google.com (HCI)、akbiggs@google.com (Flutter)
諮詢對象:shiveshganju@google.com、fmil@google.com、emircan@google.com、jsankey@google.com
社會化:
此 RFC 與受影響團隊的主管進行社交化。
相關規定
- 盡可能降低焦點的觀測能力
- 取得觀察管道的精細安全性機制
- 納入「合作夥伴」以上層級的 SDK
- 簡化開發人員體驗
設計
本焦點觀察器的核心提案是下列 FIDL 通訊協定。
library fuchsia.ui.observation.focus;
using zx;
protocol ScopedProvider {
Watch() -> (ScopedResponse);
};
type ScopedResponse = table {
1: observation_end zx.time;
2: focused zx.koid;
};
名稱中的「Scoped」表示通訊協定提供範圍限定在 focus.ScopedProvider 用戶端的 View 樹狀結構中或受到限制的焦點資訊。focus.ScopedProvider 用戶端的檢視畫面是這個可觀測檢視區塊的根層級。
observation_end
時間標示了觀察期間的結束時間,這樣用戶端就會知道傳回的焦點是否準確。例如,用戶端可區分相同焦點值的不同回傳結果,前提是在一次觀察期間內有一系列焦點變更返回上一個焦點。
focused
KOID 是檢視畫面參照 KOID,或表示檢視畫面焦點不在 focus.ScopedProvider 用戶端的檢視畫面樹狀結構外的特殊 sentinel 值 ZX_KOID_INVALID
。以下將詳述可能的值和語意。
檢視表拓撲範例
請考慮以下檢視區塊拓撲,其中每個圓圈都代表一個 View,而「U」是 focus.ScopedProvider 的用戶端。
將焦點移至檢視畫面中的檢視畫面
focus.ScopedProvider 的用戶端對全域檢視區塊樹狀結構的可見度有限 (詳情請參閱「安全考量」)。這項作業會發現檢視畫面焦點可能是「在其檢視區塊樹狀結構中」(位於焦點為焦點.ScopedProvider 用戶端的檢視畫面) 或「超出檢視區塊樹狀結構外」,但具體細節只是刻意省略。
當焦點不在 focus.ScopedProvider 用戶端的檢視區塊樹狀結構時,用戶端只會收到通知 (具有 ZX_KOID_INVALID
的已傳送值)。用戶端不會得知新檢視畫面焦點的身分。
Wen 焦點位在 focus.ScopedProvider 用戶端的 View 樹狀結構中,用戶端僅會收到以下資訊:
- 如果焦點位在 focus.ScopedProvider 用戶端的檢視畫面本身,則代表用戶端檢視畫面的 KOID。
- 如果焦點位在客戶檢視畫面的直接子項檢視區塊,則該直接子項檢視畫面的 KOID。
- 如果焦點位於用戶端檢視畫面的間接子項檢視畫面,則直接子項檢視畫面的 KOID,就是該間接子項檢視畫面的祖系。
父項檢視畫面需要知道「何時」有權利在子項之間移動焦點。當檢視區塊焦點位於檢視區塊樹狀結構中時,即可發揮電源。否則,對 fuchsia.ui.views.Focuser.RequestFocus() 一律失敗。
值得注意的是, focus.ScopedProvider 的資訊是疊加在管道上的快照,因此變更焦點的要求可能會與下次快照更新競爭。舉例來說,其中一個快照可能代表焦點位於焦點。ScopedProvider 用戶端的檢視區塊樹狀結構,如果祖系檢視畫面成功要求將焦點變更為這個檢視區塊樹狀結構以外的位置,則將焦點變更為直接子項的要求可能會遭拒。
在這張序列圖中,當焦點移至 U 時都會收到通知,而當焦點完全移出 U 的 View 樹狀結構時,則會通知 U。
向客戶回報的重點價值
focused
是三個值類別之一,其中包含 ZX_KOID_INVALID
Sentinel 值。如果 focused
有效 (亦即不是傳送式),則檢視畫面可任意在其子項檢視畫面之間移動焦點。
具體違規事項如下:
- 如果
focused
為ZX_KOID_INVALID
,表示焦點已離開這個檢視畫面樹狀結構。這種情況可能由許多因素引起。舉例來說,U 的檢視區塊樹狀結構可能與全域檢視區塊樹狀結構連結,但祖系檢視畫面可能已將焦點移至 U 的同層級檢視畫面。或者,U 可能已與全域檢視區塊樹狀結構中斷連線,這表示 U 不再符合保留焦點的資格。或者,U 的祖系本身可能會中斷連線,在此情況下,該祖系的所有子係都無法保留焦點。請參閱聚焦政策一文。 - 如果這是父項的檢視畫面參照 KOID,則父項檢視畫面本身會有焦點。這個使用方法與 fuchsia.ui.views.ViewRefFocused 相同,以便我們淘汰該通訊協定。
- 如果 KOID 無效或父項,則為直接子項的檢視畫面參照 KOID。這個欄位只會提及直接子項,即使聚焦的檢視區塊是直接子項的子系。
在本例中,焦點移至 X,也就是一個低於 U 的子項。焦點觀察器會回報 U 的直接子項,也就是 V。
摘要語意
如果過去觀察期間有多項焦點變更,這個 API 只會傳回最終的焦點。用戶端通常無法處理過去的焦點變更,因此 API 已簡化,只傳回「摘要」。
一般而言,如果懸掛的用戶端透過 Watch 傳遞回呼,聚焦變更將會立即返回用戶端。然而,用戶端也有可能延遲停車。因此,伺服器可能會看見多項焦點的變更,以提供下次回傳的摘要資訊。伺服器也可能會收到大量的焦點變更,因此,視執行緒或工作的排程而定,在多次焦點變更後,可能會取得已停妥的懸掛式回應。
在這些範例中,無論 Watch() 呼叫的時間為何,U 都會收到相同的通知。
狀態變更語意
Watch 呼叫是由個別用戶端的狀態變更所驅動。
- 連線後第一次呼叫時,會立即傳回目前狀態。
- 從一次 Watch 呼叫傳回到下一次智慧手錶呼叫開始之間,如果發生多項狀態變更,下一個手錶呼叫將立即傳回,並顯示最近一次觀察到的變更。
透過等級變更,伺服器只會在發生變更「之後」發生變更時通知用戶端,並忽略手錶呼叫之前的變更。這段期間內,用戶端會錯過焦點變更摘要,因此不適用於預期用途。
根據狀態變更進行實作會增加伺服器實作的負擔,因為伺服器必須追蹤每個觀察器管道最近一次發出的狀態。然而,這可帶來更直覺的開發人員體驗,因為狀態變更對於用戶端 Watch 呼叫與任何聚焦變更之間的排序切換非常有效。舉例來說,視伺服器的執行緒和實作詳細資料而定,智慧手錶呼叫停在伺服器後,可能會在處理回呼之前的過渡期間發生多項焦點變更。
實作
檢視區塊焦點與檢視區塊拓撲的生命週期和維護密切相關。「風景」是檢視畫面管理器元件,因此這個通訊協定就包含在 View 中。
效能
焦點的變更可能會經常發生,但實際上會採「人為調整」的程度。因此,FIDL 呼叫頻率不屬於問題。FIDL 酬載也相當輕巧,而流量控制模式可避免管道發生填充的情況。
人體工學
這個 API 致力於改善前身的 DX。經過簡化的錯誤處理、失真摘要語意以及缺少容器資料類型,應可更輕鬆地採用。
演進
這個 API 旨在用於 OOT 存放區,而伺服器實作則位於 View 平台元件。這個 API 會新增新的 hanging-get 方法,以安全擴展、保留回溯相容性。當所有使用已淘汰方法的存放區更新為較新的方法時,您可以將已淘汰的方法標示為已刪除。
安全性考量
這個 API 會將這個 API 掛鉤至 fuchsia.ui.composition.Flatland.ViewBoundProtocols 表格,進而在建立檢視畫面時,將這個 API 的伺服器端點與與父項檢視畫面相關聯的特定 ViewRef 建立關聯。
API 用戶端無法在其檢視區塊樹狀結構或檢視區塊樹狀結構外要求更多資訊。接收的檢視畫面參照 KOID 資訊的範圍僅限於本身及其直接子項,因此可改善檢視畫面的安全狀態。
焦點竊取
在更寬鬆的系統中,惡意檢視區塊可以僅透過要求,從其他檢視區塊中「竊取」焦點。Fuchsia View 系統的聚焦政策可藉由定義焦點移動的情境和範圍,降低這類情況:只有由祖系檢視畫面授予焦點的檢視畫面才能移動焦點,而且只能將焦點移至其檢視區塊子樹狀結構外,不能在其檢視區塊子樹狀結構外移動。
這項焦點觀察器設計遵循這項焦點政策的限定範圍方法,限制了觀測到的檢視區塊及其直接子項的觀測能力。
KOID 的功能
另一項小幅改善是,焦點觀察器通訊協定會分出子項檢視畫面參照的 KOID,而非檢視畫面副本本身。部分 UI 通訊協定會影響檢視區塊參照,因此傳回 KOID 可降低濫用的可能性。例如,如果 Ermine 的 focus.ScopedProvider 管道端點委派給另一個元件「C」,這是安全委派,因為「C」無法冒用 Ermine 或任何 Ermine 的子檢視畫面處理 KeyboardListener 通訊協定。
一般用途是找出已聚焦的檢視畫面,而檢視畫面的檢視畫面參照 KOID 就足夠。請注意,要求焦點需要即時檢視參照,而不僅是檢視畫面參照的 KOID。用戶端應維護自己的子項檢視畫面參照清單 (亦即透過 Flatland 通訊協定取得),而這些檢視參照可以用於要求焦點。
隱私權注意事項
FocusChainListener 通訊協定則在根層級檢視畫面完整顯示檢視畫面樹狀結構。這個焦點觀測工具通訊協定會刻意限制瀏覽權限範圍,其中可見的檢視畫面樹狀結構是以用戶端檢視畫面本身為根層級。
ViewRefFocused 已限定在用戶端的檢視畫面。這個焦點觀測工具通訊協定只會將用戶端的瀏覽權限延伸至用戶端檢視區塊的直接子項檢視區塊。
因此,我們預期對隱私權的影響微乎其微。
測試
實作項目會有單元測試和平台端整合測試。 此外,就像任何其他可呈現 SDK 的 FIDL 一樣,都會進行 CTF 測試。
說明文件
請前往 fuchsia.dev 參閱使用說明文件指南。
缺點、替代項目和未知
這個 API 不符合所有已知的焦點用途。然而,先前的社會化工作已強調,必須針對不同需求建立單獨的 API。RFC 之後會處理其他「焦點觀察器」API。
優先藝術與參考資料
舊版 FocusChainListener 相關問題
目前,如要觀察跨檢視畫面樹狀結構的檢視焦點動作,只能選擇 fuchsia.ui.focus.FocusChainListener 通訊協定。由於下列問題,此功能已淘汰:
- 這可讓用戶端全面掌握檢視畫面焦點移動位置,進而洩漏平台實作詳細資料。舉例來說,根層級場景中的所有檢視畫面都會顯示在這個焦點鏈結中,讓客戶可以斷言根情境的結構,避免平台內部的實作方式變更。
- 這個範例會提供 fuchsia.ui.views.ViewRef 權杖 (由 Zircon 事件配對物件支援),讓較弱通訊協定的用戶端以另一個檢視畫面的形式呈現。