大家都知道 Android 4.2 版支持了以前叫做 WIFI Display 的 Miracast. 看了同事轉寄的網路文章 [1], 才知道 Android 連架構都配合 Miracast 做了修改.
首先考量的是, 使用者需要把手機上的畫面輸出到電視上分享給大家, 卻不能讓大家都看見他/她怎麼在鍵盤上按密碼. 所以 surfaceflinger 就不能把虛擬鍵盤或是密碼框的這一層投射出去. 換言之, 把整個 display planes (什麼 V1, V2, OSD1, OSD2, SUB1, SUB2) 都 mix 後才輸出的那張圖, 反而不是可以公開的.
因此, surfaceflinger 裡面就多了個 display device 的抽象層.
DISPLAY_PRIMARY: Android 手機的螢幕
DISPLAY_RXTERNAL: HDMI 設備, 如 TV
DISPLAY_VIRTUAL: WIFI Display, 即 Miracast.
對於 virtual 的裝置, Android 並不準備它的 frame buffer.從下面這段 code 中可以看出, 每一個 Display Device 在產生的時候, 都會參考 state.isVirtualDisplay 是否為真? 進而決定 hw 這個 class 的內容. Miracast 顯然就和 HDMI, 和 local 螢幕不同類. 可見得在 HDMI 以 MHL (Mobile High-Definition Link) 接電視的情況下是允許看到輸入密碼視窗的, 但 Miracast 以 WIFI 無線時不可以顯示.
其中 static_cast< sp<ISurfaceTexture>> 表示指定型別為 sp<ISurfaceTexture>, 也就是 ISurfaceTexture 的 smart pointer. Smart pointer 也是個 pointer, 它有助於在不同的地方 create 和 destroy, 因此可以靈活地運用並減少記憶體丟失 (或曰"洩漏").它的原文是:
Smart pointers ensure we properly destroy an object even if its creation and destruction are widely separated. They make functions simpler and safer by ensuring that no matter how many different exit paths exist, local objects are always cleaned up correctly. They help enforce that exactly one object owns another object at any given time, preventing both leaks and double-frees.[2]
最後 Android 做 composer 的時候, 會對每一種顯示設備 (共 mDisplays.size 種) 檢查是否 dirty (需要更新)? 並且用 hw->canDraw() 判斷能不能畫? 如果不能畫, 連 dirty 也不畫.在 2011 年的時候, 就有人抱怨過 hw->flip 為什麼在 hw->canDraw() 的前面執行 [3]? 導致 Android suspend 的時候都還在 flip. 看來 Android 是從善如流, 改為優先判斷 canDraw() 了.
[REF]