梳理流程和圖形參考Stan_Z的博客:
Android圖形系統(tǒng)篇總結(jié):http://www.reibang.com/p/180e1b6d0dcd
Android 系統(tǒng)顯示原理簡介:http://www.reibang.com/p/a978a6250f9e
一衙熔、Android顯示系統(tǒng)整體框架介紹
1.1 顯示系統(tǒng)關(guān)鍵組件:Activity悯搔、window兽肤、view、surface、canvas是鬼、surfaceflinger、layer紫新、Choreographer均蜜、Vsync
- Activity:是APP與用戶進行交互的入口,一個Activity對應(yīng)著一個窗口(window)芒率,完成用戶的key囤耳、touch事件的相應(yīng)處理和對window生命周期進行管理。
- Window:window是視圖(view)的容器偶芍,Window有唯一的實現(xiàn)類:PhoneWindow充择。Window受WindowManager統(tǒng)一管理,對window管理通過WindowWtate腋寨,該變量是系統(tǒng)對Window管理的一個封裝類聪铺,與window一一對應(yīng)。
- view:視圖萄窜,承載著將要顯示的內(nèi)容铃剔,其中DecorView(頂級視圖)是當(dāng)前Activity的根View,它里面管理著當(dāng)前界面的View樹查刻,包含著標題欄titleBar和內(nèi)容欄contentView键兜。
- surface:每個Window對應(yīng)一個surface穗泵,作為View顯示的載體普气,圖形的傳遞通過buffer作為載體,因此surface是對buffer的封裝佃延,對圖形的操作其實就是對suface中buffer的操作现诀。
- canvas:畫布夷磕,任何的view都需要畫在surface的canvas上。
- SurfaceFlinger:作為一個service仔沿,接收所有的surface作為輸入坐桩,創(chuàng)建layer,把不同的layer進行裁剪等合成操作來顯示封锉。
- layer:由surfaceFlinger進行創(chuàng)建绵跷,是surfaceFlinger進行合成的基本單位(一個surface對應(yīng)一個layer),layer其實是一個FrameBuffer(幀buffer)成福,每個FrameBuffer中有兩個GraphicBuffer(圖形buffer碾局,因為Android為了將系統(tǒng)操作buffer和硬件顯示buffer分開,所以設(shè)置了兩個buffer)奴艾,記為FrontBuffer和BackBuffer净当。
從圖中可以看出,最終顯示在屏幕上的內(nèi)容由多個surface(layer)通過SurfaceFlinger進行合成握侧,surface上中不同的view都畫在surface的canvas上蚯瞧。
- choreographer:處于上層嘿期,接收VSync信號品擎,同Vsync配合,統(tǒng)一Android顯示中的動畫备徐、輸入和繪制時機萄传。
- Vsync:讓CPU、GPU和Buffer進行同步的一個信號蜜猾。
1.2 顯示流程概述:
將前面內(nèi)容進行串聯(lián)秀菱,Android應(yīng)用程序的顯示過程包含了兩個部分(應(yīng)用側(cè)繪制、系統(tǒng)側(cè)渲染)蹭睡、兩個機制(進程間通訊機制衍菱、顯示刷新機制)。
應(yīng)用層負責(zé)繪制(UI的測量肩豁、布局脊串,即顯示View的類型和Window對View的布局),系統(tǒng)層負責(zé)渲染(SurfaceFlinger對layer的合成和屏幕上的顯示)清钥;
通過進程間通信(binder)把應(yīng)用層需要繪制的數(shù)據(jù)傳遞給系統(tǒng)層服務(wù)琼锋,系統(tǒng)層服務(wù)通過刷新機制(Vsync、choreography)把數(shù)據(jù)更新到屏幕上祟昭。
顯示流程具體細節(jié):
- Android啟動后缕坎,在init.rc解析時創(chuàng)建SurfaceFlinger實例并向serviceManager注冊,啟動SurfaceFlinger服務(wù)篡悟。
- Activity在啟動過程中會創(chuàng)建PhoneWindow并且與之建立回調(diào)關(guān)系(用于接收touch等消息)谜叹;在PhoneWindow中創(chuàng)建頂級視圖DecorView匾寝。
- Activity調(diào)用函數(shù)setView(),里面有兩個重要的函數(shù):
requestlayout()
和mWindowSession.addtoDisplay()
荷腊。后者完成view的添加旗吁、app與surfaceFlinger的服務(wù)的連接;前者完成了view的繪制停局、view畫在surface的canvas上并把surface傳入SurfaceFlinger很钓。 - SurfaceFlinger創(chuàng)建layer并將傳入的Surface進行合成,最后將合成后的數(shù)據(jù)通過
SurfaceFlinger::postComposition()
函數(shù)畫在屏幕上董栽。 - 為了讓CPU/GPU的合成幀率和Display的刷新率同步码倦,使用了Choreographer,接收Vsync信號锭碳,讓底層與上層進行同步袁稽。
二、Activity創(chuàng)建Window和加載view過程
解決問題:1. Window創(chuàng)建和建立回調(diào)過程擒抛;2. View是如何加載到Window中的
2.0 Activity的啟動
Activity啟動流程參考:一篇文章看明白 Android 從點擊應(yīng)用圖標到界面顯示的過程
在Android啟動后尚卫,點擊app圖標,Launcher進程(就是一個Activity)通過Binder向系統(tǒng)服務(wù)(systemserver)ActivityManagerService(AMS)發(fā)起startActivity()請求欣喧;
PS:Launcher通過PMS來解析AM.xml配置文件得到組件信息折砸,系統(tǒng)啟動后就會啟動Launcher組件,啟動后向PMS查詢所有Action名稱和Category诊胞,為每個Acitivity組件創(chuàng)建快捷圖標暖夭,方便下面點擊啟動。
AMS收到請求后向zygote進程發(fā)送創(chuàng)建進程請求并fork一個新的子進程(app進程)撵孤;進入 app 進程后創(chuàng)建 ActivityThread 類并加載迈着,并調(diào)用 ActivityThread.main() 方法。
ActivityThread.main()通過Binder向AMS發(fā)起attachApplication請求對app進行一些初始化邪码;AMS經(jīng)過一系列準備后向App進程發(fā)送scheduleLaunchActivity請求裕菠,app進程的binder線程(ApplicationThread)收到請求后通過由bindapplication()封裝一些重要的信息,如appinfo闭专、config等handler消息并向主線程發(fā)送LAUNCH_ACTIVITY消息奴潘;
主線程收到啟動activity消息后,執(zhí)行handleLaunchActivity()方法喻圃,通過Instrumentation()(Intrumentation:用來監(jiān)控app和系統(tǒng)之間的交互操作萤彩。)創(chuàng)建Activity,然后調(diào)用Activity.attact().onCreate()方法進入Activity生命周期斧拍。
2.1 window的創(chuàng)建 雀扶、View創(chuàng)建和添加
Activity啟動時會創(chuàng)建Window,從上面可以看出,Activity啟動過程中有重要的函數(shù)ActivityThread.handleLaunchActivity()
愚墓,該函數(shù)中有三個重要的函數(shù)調(diào)用:
handlelaunchactivity()
{
...
windowManagerGlobal.initialize() //獲得 WMS的Binder引用
performLaunchActivity() //創(chuàng)建要啟動的Activity組件予权,創(chuàng)建窗口對象和視圖對象
handleResumeActivity() //將Activity組件進行激活
...
}
第二個函數(shù)performLaunchActivity()
完成了PhoneWindow和View的創(chuàng)建,第三個函數(shù)handleResumeActivity()
負責(zé)將組件進行激活浪册。
看一下window創(chuàng)建函數(shù)performLaunchActivity()
performlaunchActivity()
{
Activity activity = null;
//創(chuàng)建目標Activity對象和app對象
activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
activity.attach(...)
//回調(diào) Activity.onCreate()扫腺,onCreate()里面有setContentView(),我們自己設(shè)計的UI界面
mInstrumentation.callActivityOnCreate(activity, ...);
}
attach(...)
{
mWindow = new phoneWindow() //創(chuàng)建Window村象,PhoneWindow是Window的唯一具體實現(xiàn)類
//設(shè)置回調(diào)函數(shù)笆环,實現(xiàn)了Window的callback接口,這樣Activity就與Window關(guān)聯(lián)起來
mWindow.setCallback(this)
//初始化并且設(shè)置WindowManager厚者,獲取WindowManagerImpl對象躁劣。每一個activity都有一個WM對象。
//mToken是IBinder類型库菲,WMS就是通過這個 IBinder 來管理 Activity 里的 View
mwindow.setWindowManager(...,mToken,...)
//mWindowManager與WMS進行通信账忘,也是WMS識別View屬于哪個Activity的關(guān)鍵
mWindowManager = mWindow.getWindowManager()
}
在performLaunchActivity().attach()
中創(chuàng)建了一個PhoneWindow對象,實現(xiàn)了Window的創(chuàng)建和與Activity的關(guān)聯(lián)熙宇,并且創(chuàng)建了WindowManager(WindowManager 是一個抽象類鳖擒,具體實現(xiàn)是在 WindowManagerImpl 中).由前面已知Window是View的載體,Window將view添加到WMS過程就是由WindowManager實現(xiàn)的烫止。
回調(diào) Activity.onCreate() 后蒋荚,會執(zhí)行 setContentView() 方法將我們寫的 Layout 布局頁面設(shè)置給 Activity,即加載頂級視圖DecorView烈拒。
//Activity.java
public void setContentView()
{
getWindow().setContentView(layoutResID); //window的一個抽象方法 圆裕,實現(xiàn)類是PhoneWindow
initWindowDecorActionBar();
}
// PhoneWindow
public void setContentView(int layoutResID)
{
...
installDecor(); //初始化Decor广鳍,將mContentParent關(guān)聯(lián)到DecorView上
mLayoutInflater.inflate();//填充Layout荆几,將Activity設(shè)置的布局文件,加載到mContentParent中
final Callback cb = getCallback();//通知Activity布局改變
cb.onContentChanged();
...
}
private void installDecor()
{
//根據(jù)不同的 Theme,創(chuàng)建不同的 DecorView赊时,DecorView 是一個 FrameLayout
}
PhoneWindow.setContentView()完成 初始化(創(chuàng)建DecorView對象和mContentParent對象)吨铸、 填充Layout(將Activity布局文件添加到DecorView里)、 通知Activity 進行布局改變祖秒。整個布局加載流程為:創(chuàng)建DecorView诞吱,把xml的View樹解析出來,加到DecorView上竭缝。
創(chuàng)建完成后他們之間沒有關(guān)系和聯(lián)系房维,需要對組件進行激活并建立聯(lián)系,需要將DecorView添加到window上抬纸。ActivityThread.handleLaunchActivity().handleResumeActivity()
函數(shù)調(diào)用performResumeActivity().performResume()
函數(shù)回調(diào)onResume()實現(xiàn)組件的激活咙俩。
//ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
//將Activity數(shù)據(jù)記錄到ActivityClientRecord中,執(zhí)行到 onResume()
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
boolean willBeVisible = !a.mStartedActivity;
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();//定義一個頂級視圖decor
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();// 定義一個ViewManager類型的變量 wm
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);// 將Decor添加到窗口上
}
}
...
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow)
{
...
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//添加視圖,詳見下面分析,
r.activity.makeVisible();
}
}
//resume 完成
if (reallyResume) {
ActivityManagerNative.getDefault().activityResumed(token);
}
} else {
...
}
}
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
通過getWindowManager()
創(chuàng)建的wm的類方法addview()
添加了decorView阿趁,addview()
經(jīng)過多次函數(shù)調(diào)用最終得到類ViewRootImpl的setView()
方法膜蛔,該方法十分重要,是所有工作的起點脖阵,不僅把View添加到window上皂股,而且觸發(fā)了繪制流程,完成了請求SurfaceFlinger創(chuàng)建Surface命黔、View顯示在GraphicFrame上呜呐、建立app與SurfaceFlinger之間的服務(wù)連接等任務(wù)。
//frameworks/base/core/java/android/view/ViewRootImpl.java
public final class ViewRootImpl(View.Context context, Display display)
{
setView();
mChoreographer = Choreographer.getInstance(); // choreographer的啟動和服務(wù)
}
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView)
{
// 把傳進去的DecorView賦值給mView
mView = view;
requestLayout(); // View的繪制流程(PS:在執(zhí)行addview()之前需要將UI布局繪制完成)
//mWindowSession類型是interface WindowSession,在getWindowSession()中實現(xiàn)
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel,
mTempInsets);
//處理觸摸事件回調(diào)
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
}
public static IWindowSession getWindowSession()
{
// 獲取了WMS悍募,openSession返回值是sWindowSession
IWindowManager windowManager = getWindowManagerService()卵史;
// sWindowSession的具體實現(xiàn)在windowManager中。
sWindowSession = windowManager.openSession();
return sWindowSession搜立;
}
// 到這里可以看到以躯, IWindowSession接口真正實現(xiàn)類是Session,它是一個Binder啄踊。
public IWindowSession openSession()
{
Session session = new Session;
}
//frameworks/base/services/core/java/com/android/server/wm/Session.java
class Session(){
final WindowManagerService mService;
addToDisplay()
{
return mService.addWindow()
}
}
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
// addwindow()代碼太多忧设,具體的實現(xiàn)可以看博客中的那張圖
2.2 View的繪制流程
在方法setView()
中requestLayout()實現(xiàn)了View的繪制,從Activity到View繪制的函數(shù)調(diào)用如下圖:
從圖中可以看出颠通,ViewRootImpl.performTraversals()方法是View繪制的執(zhí)行起點址晕。ViewRootImpl則肩負著View的標準三步曲(測量、布局顿锰、繪制)谨垃。
private void performTraversals()
{
//執(zhí)行測量操作
performMeasure(childWidthMeasureSpec,childHeightMeasureSpec);
//執(zhí)行布局操作
performLayout(lp, Width, mHeight);
//執(zhí)行繪制操作
performDraw();
}
實際上硼控,view繪制一共有5個階段刘陶,多了預(yù)測量階段和窗口布局階段:
預(yù)測量階段: 這是繪制的第一個階段,對View樹進行第一次預(yù)測量牢撼,計算View樹的顯示內(nèi)容所需的尺寸(View樹期望的尺寸匙隔,是否滿足不一定)。通過方法measureHierarchy()
實現(xiàn) ( PS: measureHierarchy()
方法最終也是調(diào)用了performMeasure()
方法對View樹進行測量)
窗口布局: 根據(jù)預(yù)測量的結(jié)果熏版,調(diào)用IwindowSession.relayout()來請求WindowManagerService服務(wù)調(diào)整window的大小等屬性并對window重新布局纷责,布局結(jié)果返回給ViewRootImpl,保存在mWinFrame中撼短。
測量過程: 預(yù)測量結(jié)果只是View樹期待的窗口尺寸再膳,具體大小需要WMS的布局(WMS布局的結(jié)果可能不滿足預(yù)測量的期望尺寸,但是View樹必須依據(jù)WMS的布局結(jié)果)曲横。WMS布局結(jié)果出來后喂柒,調(diào)用performMeasure()
對View樹進行最終測量。
開始布局: 在測量階段對窗口中的view進行了最終測量,然后根據(jù)測量結(jié)果胳喷,調(diào)用performLayout()
開始對View樹進行布局湃番。
繪制過程:這是View三部曲的最后一步,確定了window上控件的位置和尺寸后(已經(jīng)完成布局操作)吭露,通過調(diào)用performDraw()
吠撮,最終調(diào)用到 drawBackground(canvas)
方法,實現(xiàn)View的繪制(上面提到過讲竿,所有的View都是畫在Canvas上的)
到這里泥兰,已經(jīng)介紹了Window的創(chuàng)建、View的創(chuàng)建和添加题禀、View的繪制等內(nèi)容鞋诗,應(yīng)用側(cè)工作已經(jīng)完成,還有一個系統(tǒng)側(cè)工作迈嘹。
三削彬、Surface與SurfaceFlinger
在上面提到Window、View的創(chuàng)建和繪制秀仲,這些都是上層的一些操作融痛,那么如何將上層的內(nèi)容顯示到硬件的顯示屏上呢? 這部分將介紹SurfaceFlinger創(chuàng)建Surface、surfaceFlinger合成Layer和送顯過程神僵。
3.0 SurfaceFlinger服務(wù)啟動概述
SurfaceFlinger系統(tǒng)服務(wù)在init階段啟動雁刷,主要實現(xiàn)了Surface的建立、控制保礼、管理等功能沛励,能夠?qū)⒏鞣N應(yīng)用程序的2D、3D surface進行組合炮障。
啟動SurfaceFlinger時在main_surfaceflinger.cpp里 main()中實例化一個SurfaceFlinger目派,第一次實例化會執(zhí)行onFirstRef()創(chuàng)建MessageQueue的對象Handler和消息循環(huán)looper,然后初始化右邊的EGL等內(nèi)容铝阐。HWC代表著硬件顯示設(shè)備址貌,注冊了 VSYNC 信號的回調(diào)。當(dāng)硬件產(chǎn)生VSYNC信號時徘键,則會發(fā)送消息,handler 收到消息進行處理遍蟋。當(dāng) SurfaceFlinger 進程收到 VSync 信號后經(jīng)層層調(diào)用吹害,最終調(diào)用到該對象的 handleMessageRefresh() 方法。
SurfaceFlinger.cpp:
void SurfaceFlinger::handleMessageRefresh()
{
ATRACE_CALL();
preComposition();//處理顯示設(shè)備與 layers 的改變虚青,更新光標
rebuildLayerStacks();//重建所有可見 Layer 列表它呀,根據(jù)Z軸排序
setUpHWComposer();//更新 HWComposer 圖層
doDebugFlashRegions();
doComposition();//生成 OpenGL 紋理圖像
postComposition();//將圖像傳遞到物理屏幕
}
OpenGL:open graphics library,用于渲染2D、3D矢量圖形的纵穿、操作GPU的API下隧,通過驅(qū)動向GPU發(fā)送相關(guān)指令。
EGL:作為 OpenGL 和原生窗口系統(tǒng)之間的橋梁谓媒,用于opengl與本地窗口交互時的中間層淆院,與平臺無關(guān)。具體作用是為openGL指令創(chuàng)建context句惯、繪制目標surface土辩、配置FrameBuffer屬性、Swap提交繪制結(jié)果抢野。
HWC:Hardware Composer HAL (HWC) 是 SurfaceFlinger 用來將 Surface 合成到屏幕拷淘,介于SurfaceFlinger和HAL之間,用于處理部分SurfaceFlinger的合成任務(wù)和產(chǎn)生vsync信號指孤。
3.1 app與SurfaceFlinger服務(wù)連接過程
ViewRootImpl.setView()中mWindowSession.addToDisplay()
實現(xiàn)了app與SurfaceFlinger的連接启涯。
在addToDisplay()方法中執(zhí)行win.attach()(類WindowState的方法attach()),然后在attach()方法中通過mSession.windowaddedlocked()
創(chuàng)建SurfaceSession對象(Session的成員變量SurfaceSession通過windowAddedLocked()方法進行初始化)恃轩,并將Session實例添加到WMS.mSessions中逝嚎,這樣實現(xiàn)了與WMS進行通信。SurfaceSession的創(chuàng)建會調(diào)用JNI中的nativeCreate()
函數(shù)详恼。(從上層到了下層)
//WindowState.java
void attach() {
mSession.windowAddedLocked();
}
//Session.java
void windowAddedLocked() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
// ./frameworks/base/core/java/android/view/SurfaceSession.java
public SurfaceSession()
{
mNativeClient = nativeCreate():
}
下面是app與SurfaceFlinger建立連接的關(guān)鍵點:
在nativeCreate()中創(chuàng)建了SurfaceComposerClinent對象 client补君,作為跟 SurfaceFlinger 通信的代理對象。
并且client被賦值給了mSession(因為調(diào)用的是 mSession.windowAddedLocked())昧互,
//android_view_SurfaceSession.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz)
{
SurfaceComposerClient* client = new SurfaceComposerClient();
}
// 在賦值時挽铁,SurfaceComposerClient類成員函數(shù)onFirstRef將被調(diào)用
// frameworks/native/libs/gui/SurfaceComposerClient.cpp
void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr && mStatus == NO_INIT) {
sp<ISurfaceComposerClient> conn;
conn = sf->createConnection();
if (conn != nullptr) {
mClient = conn;
mStatus = NO_ERROR;
}
}
}
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
return initClient(new Client(this));
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client) {
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
到這里,方法onFirstRef()中創(chuàng)建了sp<ISurfaceComposer> sf和 sp<ISurfaceComposerClient> conn敞掘, 然后 conn賦值給了sp<SurfaceComposerClient> mClient叽掘。sf 獲得了SurfaceFlinger服務(wù)的代理接口(在調(diào)用getComposerService()方法時,會在構(gòu)造函數(shù)中獲得SurfaceFlinge服務(wù)的代理接口玖雁,并且創(chuàng)建一塊匿名共享內(nèi)存更扁,此時sf就有值了),成員函數(shù)createConnection()
建立SurfaceComposerClinet與SurfaceComposer的連接赫冬。
ComposerService作為client與SurfaceFlinger 作為 server進行binder IPC浓镜,獲得SurfaceFlinger創(chuàng)建的Client對象,拿到SurfaceFlinger服務(wù)劲厌;與此同時膛薛,ComposerService創(chuàng)建的Client(server端)與SurfaceComposerClient(client端)又互為binder IPC的兩端。
從代碼中理解补鼻,sf是一個指針哄啄,獲得了CompoesrService雅任,然后sf與SurfaceFlinger創(chuàng)建的Client建立連接;
sf然后返回給conn咨跌,conn是SurfaceComposerClient類型沪么。
3.2 app請求surfaceFlinger創(chuàng)建Surface
在請求建立服務(wù)的過程中,ViewRootImpl.setView()中mWindowSession.addToDisplay()
實現(xiàn)了app與SurfaceFlinger的連接锌半。ViewRootImpl.setView()還有一個重要的函數(shù)requestLayout()
禽车。該函數(shù)實現(xiàn)了surface的創(chuàng)建。
requestLayout()
經(jīng)過多層調(diào)用到WMS.relayoutWindow()方法
//WindowManagerSerview
public int relayoutWindow(..., Surface outSurface)
{
synchroized(mWindowMap)
{
WindowState win = windowForClientLocked();
Surface surface = win.createSurfaceLocked();
if(surface != null) { outSurface.copyForm(surface); ...}
}
}
在WindoManagerService中createSurfaceLocked()
方法new了一個surface(這里是java層的surface)拳喻,并且將創(chuàng)建的內(nèi)容拷貝到outSurface中(ViewRootImpl傳進來的參數(shù))哭当,用作返回給APP使用。
那么創(chuàng)建出來的surface對象是什么樣子呢冗澈?其實surface主要包含三個變量
Surface {
private int mSurfaceControl //保存C++層的一個SurfaceControl對象的地址值
private Canvas mCanvas //描述一塊類型為CompativleCanvas的畫布(Canvas)
private String mName //描述當(dāng)前正在創(chuàng)建的一個繪圖surface的名稱
}
這里的mSurfaeControl是java層的钦勘,控制底層的surface。在類surface 的成員函數(shù)中有名為init()的JNI方法(Surface_init())亚亲,可以創(chuàng)建C++層SurfaceControl對象彻采。
Surface_init{
// 從 SurfaceSession 對象中取出之前創(chuàng)建的那個 SurfaceComposerClient 對象
SurfaceComposerClient* client = (SurfaceComposerClient*) env ->GetIntField(session,sso.client)
sp<SurfaceControl> surface;//注意它的類型是 SurfaceControl
// 調(diào)用SurfaceComposerClient的createsurface函數(shù),這個surface類型是surfacecontrol類型捌归,為WMS服務(wù)
surface = client ->createSurface();
...
//把這個 surfaceControl 對象設(shè)置到 Java 層的 Surface 對象中
setSurfaceControl(env, clazz, surface);
}
在SurfaceComposerClient類型的client中創(chuàng)建surface肛响,在3.1中所描述的,SurfaceComposerClient通過Binder獲取到ComposerService的對象惜索,ComposerService最后到SurfaceFlinger中執(zhí)行createSurface(本地surface)特笋。
在 createSurface 內(nèi)部會使用 Binder 通信將請求發(fā)給 SurfaceFlinger
sp<ISurface>SurfaceFlinger::createSurface()
{
sp<LayerBaseClient> layer;//LayerBaseClient 是 Layer 家族的基類
//LayerBaseClient 的內(nèi)部類,它也叫Surface
sp<LayerBaseClient::Surface> surfaceHandle;
//根據(jù) clientId 找到 createConnection 時加入的那個 Client 對象
sp<Client> client = mClientsMap.valueFor(clientId);
//注意這個 id巾兆,它的值表示 Client 創(chuàng)建的是第幾個顯示層
//同時也表示將使用 SharedBufferStatck 數(shù)組的第 id 個元素
int32_t id = client->generateId(pid);
//根據(jù) flags 參數(shù)來創(chuàng)建不同類型的顯示層
switch(flags & eFXSurfaceMask)
case ...
layer = createNormalSurfaceLocked(client, d, id, w, h, flags, format);
break;
...
//從顯示層對象中取一個ISurface對象賦值給SurfaceHandle
surfaceHandle = layer ->getSurface();
return surfaceHandle;//ISurface 的 Bn 端就是這個對象
}
前面所說猎物,每一個surface對應(yīng)著一個layer,所以createSurface主要是創(chuàng)建了一個layer(可根據(jù)不同的參數(shù)創(chuàng)建不同的layer)角塑,然后layer初始化一些參數(shù)蔫磨。
sp<LayerBaseClient>SurfaceFlinger::createNormalSurfaceLocked()
{
//創(chuàng)建一個 Layer 類型的對象
sp<Layer> layer = new Layer(this, display,client, id);
//設(shè)置 Buffer
status_t err = layer->setBuffers(w, h, format, flags);
if (LIKELY(err == NO_ERROR)) {
//初始化這個新 layer 的一些狀態(tài)
layer->initStates(w, h, flags);
//下面這個函數(shù)把這個 layer 加入到 Z 軸集合中
addLayer_l(layer);
}
...
return layer;
}
在 上面的surfaceHandle = layer ->getSurface();
可以獲取SurfaceFlinger創(chuàng)建的Surface對象,然后該變量返回給sp<SurfaceControl> surface圃伶,這樣surfaceControl就與底層的surfacehandle建立了鏈接堤如,并且能夠控制底層surface。
Surface類成員mClient(SurfaceClient::getInstance())
指向了app進程中的一個SurfaceClient單例窒朋,mSharedBufferClien指向了SharedBufferClient對象
void Surface::init()
{
int32_t token = mClient.getTokenForSurface(mSurface);
mSharedBufferClient = new SharedBufferClient(mClient.getSharedClient(),token,2,mIdentity);
}
// getTokenForSurface()調(diào)用setToken()
status_t Layer::setToken()
{
//new 一個SharedBufferServer
sp<SharedBufferServer> lcblk = new SharedBufferServer();
}
總結(jié):
將APP window繪制在屏幕的載體是Surface搀罢,因此需要在app和底層都創(chuàng)建Surface承載各自的內(nèi)容,并且需要控制變量SurfaceControl炼邀。
APP:在WindoManagerService中創(chuàng)建surface魄揉,并且將創(chuàng)建的內(nèi)容拷貝到outSurface中(ViewRootImpl傳進來的參數(shù)),用作返回給APP使用拭宁,這樣app層的surface與WMS層的Surface就建立了聯(lián)系洛退。此外,app創(chuàng)建的surface與C++層管理一個Surface對象用來繪制APP UI杰标,WMS創(chuàng)建的Surface在C++關(guān)聯(lián)一個SurfaceControl對象兵怯,用來設(shè)置app window屬性。
底層:SurfaceFlinger服務(wù)中創(chuàng)建了surfaceHandle腔剂,這樣surfaceControl就與底層的surfacehandle建立了鏈接媒区,并且能夠控制底層surface。創(chuàng)建Surface過程就是創(chuàng)建Layer掸犬、buffer袜漩。
3.3 app中的view如何畫在surface的canvas上
還是3.2中的requestLayout()函數(shù),一直調(diào)用到drawSoftware(surface,...)
drawSoftware(surface,...)
{
canvas = mSurface.lockCanvas(dirty);#獲取canvas
mView.draw(canvas); #通過Canvas繪制view湾碎,是具體的繪制實現(xiàn)
surface.unlockCanvasAndPost(canvas); #繪制結(jié)束
}
重點看一下mView.draw(canvas).
onDraw(Canvas canvas)
{
canvas.save(); // 坐標系原點宙攻,坐標軸方向等信息
canvas.translate();//開始繪制
}
onDraw()
中的translate()與jni中的native_translate()相關(guān)聯(lián),native_translate()然后調(diào)用SKCanvas.cpp中的translate()介褥,開始由底層SKCanvas來完成真正的繪制工作座掘。
總結(jié):繪制view時,首先獲取一塊存放繪制數(shù)據(jù)的buffer柔滔,然后傳入canvas進行繪制溢陪,繪制其實是調(diào)用底層的SKia引擎進行繪制,包含畫家SKCanvas和畫布SKBitmap睛廊;繪制結(jié)束后調(diào)用unlockCanvasAndPost(canvas)
形真,讓surface通過queueBuffer將數(shù)據(jù)投放到queue中,通知SurfaceFlinger進行使用超全。
3.4 surfaceFlinger合成多個layer
每個Android app都有很多window咆霜,每個window都有自己的UI元數(shù)據(jù),因此不能使用binder在app和surfaceflinger之間傳遞UI數(shù)據(jù)卵迂,因為數(shù)據(jù)量太大裕便,復(fù)制效率不高,所以選擇使用Android os的匿名共享內(nèi)存方案(SharedClient)见咒。
sharedclient 里面有最多31個sharedbufferstack偿衰,每個stack里面有N個buffer(共享緩沖區(qū)堆棧,每一個stack與一個surface對應(yīng)改览,一個surface與一個window對應(yīng))下翎。因此一個app內(nèi)部最多有31個window。
SurfaceFlinger進程是init進程通過Init.rc創(chuàng)建的,然后獨立運行在系統(tǒng)中宝当。創(chuàng)建SurfaceFlinger由main_surfaceflinger.cpp中的main函數(shù)來實現(xiàn)
main {
flinger = new SurfaceFlinger ;# 實例化SurfaceFlinger
sp <SurfaceFlinger> flinger ->init #把實例化的SurfaceFlinger初始化
sp<IServiceManager> sm ->addService() #把SurfaceFlinger注冊到ServiceManager
}
圖層合成就是把多個圖層视事,按照既定的顯示區(qū)域,展現(xiàn)到顯示屏上庆揩。
在創(chuàng)建SurfaceFlinger時會調(diào)用onFirstRef()函數(shù)俐东,然后創(chuàng)建looper對象和handler對象跌穗,handle對象實現(xiàn)消息的接收和根據(jù)消息類型進行圖形處理
handleMessage
{ case INVALIDATE #用于處理Layer或display屬性變化和layer對應(yīng)buffer的更新
..........onMessageReceived()
case REFRESH #表示SurfaceFlinger需要一次合成(Refresh)操作
..........onMessageReceived()
}
onMessageReceived()
{
case MessageQueue::INVALIDATE
.... if layer屬性變化:handleMessageTransation()處理;
.... else buffer更新:handleMessageInvaliate()處理
case MessageQueue::REFRESH
....handleMessageRefresh()處理
}
SurfaceFlinger合成和投遞共有5個步驟:
詳細的內(nèi)容可以參考Android圖形顯示,詳細講了HWC虏辫、SurfaceFlinger合成蚌吸。
3.5 surface顯示過程
在 App 進程中創(chuàng)建 PhoneWindow 后會創(chuàng)建 ViewRoot(ViewRootImpl())。ViewRoot 的創(chuàng)建會創(chuàng)建一個 Surface(ViewRootImpl().requestLayout().createSurfaceLocked())砌庄,這個 Surface 其實是空的羹唠,通過與 WindowManagerService 通信 copyFrom() 一個 NativeSurface。在與 SurfaceFlinger 通信時娄昆,會創(chuàng)建 SharedClient(匿名共享內(nèi)存) 一段共享內(nèi)存佩微,里面存放的是 SharedBufferStack(最多31個) 對應(yīng) SurfaceFlinger 中的 SurfaceLayer ,每個 Layer 其實是一個 FrameBuffer萌焰,每個 FrameBuffer 中有兩個 GraphicBuffer 記作 FrontBuffer 和 BackBuffer哺眯。在 SurfaceFlinger 中 SharedBufferServer 來管理 FrameBuffer。同時在 App 端 copyFrom() 出來 NativeSurface 時會創(chuàng)建一個 SharedBufferClient 與 SharedClient 共享內(nèi)存進行關(guān)聯(lián)杆怕。當(dāng)客戶端 addView() 或者需要更新 View 時族购,會通過 SharedBufferClient 寫入數(shù)據(jù)到 ShareClient 中,SurfaceFlinger 中的 SharedBufferServer 接收到通知會將 FrameBuffer 中的數(shù)據(jù)傳輸?shù)狡聊簧稀?/p>
在SurfaceFlinger和app端分別對應(yīng)Layer對象和Surface對象陵珍,用SharedBufferServer對象和SharedBufferClient來操作寝杖。app想要更新surface時,找到對應(yīng)的SharedBufferClient對象找到它對應(yīng)的SharedBufferStack互纯,從bufferqueue尾部找到一個空閑的buffer瑟幕,然后app請求為這個buffer分配GraphicBuffer,然后把GraphicBuffer返回給app訪問留潦。app得到就寫入UI數(shù)據(jù)并插入到對應(yīng)的SharedBufferStack只盹,然后通知SurfaceFlinger去消費。SurfaceFlinger找到SharedBufferServer對應(yīng)的成員函數(shù)queue去獲得待渲染的buffer兔院。
四殖卑、Vsync與Choreographer
在上面介紹了window的創(chuàng)建、view的繪制(對窗口的測量和繪制)坊萝、surface的創(chuàng)建和關(guān)聯(lián)孵稽、view畫到canvas、將畫好的canvas通過SurfaceFlinger進行合成投遞十偶,如此顯示系統(tǒng)從Activity到屏幕就介紹完畢菩鲜。
但是,如何協(xié)調(diào)CPU/GPU和顯示幀之間的關(guān)系呢惦积。在Android4.1之后增加了Choreographer機制,用于同Vsync機制配合,統(tǒng)一動畫接校、輸入和繪制的時機。
VSYNC是Vertical Synchronized的縮寫狮崩,是一種定時中斷蛛勉,即當(dāng)收到Vsync通知時鹿寻,CPU和GPU立即開始計算數(shù)據(jù)然后寫入buffer中,避免繪制的隨機性董习。Choreographer起調(diào)度作用烈和,將繪制工作統(tǒng)一到VSYNC的某個時間點上爱只,使應(yīng)用的繪制工作有序進行皿淋。引入VSYNC核心目的就是解決刷新不同步的問題;
Choreographer:一個java類恬试,是個消息處理器窝趣,根據(jù)vsync 信號 來計算frame,而計算frame的方式就是處理三種回調(diào)训柴,包括事件回調(diào)哑舒、動畫回調(diào)、繪制回調(diào)幻馁。這三種事件在消息輸入洗鸵、加入動畫、準備繪圖layout 等動作時均會發(fā)給Choreographer仗嗦。收到VSYNC信號時膘滨,調(diào)用用戶設(shè)置的回調(diào)函數(shù),三種類型的回調(diào)為:
CALLBACK_INPUT:優(yōu)先級最高稀拐,與輸入事件有關(guān)火邓;
CALLBACK_ANIMATON:第二優(yōu)先級,與動畫有關(guān)德撬;
CALLBACK_TRAVERSAL:最低優(yōu)先級铲咨,與UI控件繪制有關(guān);
View的onclick蜓洪、onDraw等等都是從Choreographer.doFrame開始執(zhí)行的纤勒;關(guān)于Choreographer可以參考Android Choreographer 源碼分析;
引入Vsync同步機制隆檀,可以使得CPU/GPU和display按照一個規(guī)定時機進行幀制作和顯示摇天。
4.1 Choreographer 啟動
首先介紹Choreographer,其構(gòu)造在ViewRootImpl中
public ViewRootImpl()
{
...
// 這里獲取了Choreographer的實例
mChoreographer = Choreographer.getInstance();
...
}
public static Choreographer getInstance()
{
//sThreadInstance是一個ThreadLocal對象,ThreadLocal 是線程的局部變量刚操, 是每一個線程所單獨持有的
return sThreadInstance.get();
}
private static final ThreadLocal<Choreographer> sThreadInstance = new ThreadLocal<Choreographer>()
{
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
return new Choreographer(looper, VSYNC_SOURCE_APP);
}
}
Choreographer是 線程單例的闸翅。接著我們來看一下
private Choreographer(Looper looper) {
mLooper = looper;
//使用當(dāng)前線程looper創(chuàng)建 mHandler,接受處理消息
mHandler = new FrameHandler(looper);
// 用來接收垂直同步脈沖 vsync菊霜,用來控制系統(tǒng)的同步操作
//可以通過讀取系統(tǒng)屬性debug.choreographer.vsync來獲取
//VSync事件接收器就是FrameDisplayEventReceiver(重要)
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
// 標記上一個frame的渲染
mLastFrameTimeNanos = Long.MIN_VALUE;
// 計算一幀的時間坚冀,Android手機屏幕是60Hz的刷新頻率,就是16ms
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); //屏幕刷新周期
// 初始化callbackQueue鉴逞,ballback隊列將在下一幀開始渲染時回調(diào),創(chuàng)建一個大小為5的數(shù)組
mCallbackQueues = new CallbackQueue[CALLBACK_LAST + 1];
// 初始化回調(diào)任務(wù)鏈表數(shù)組
for (int i = 0; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] = new CallbackQueue();
}
}
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
return initClient(new Client(this));
}
static sp<ISurfaceComposerClient> initClient(const sp<Client>& client)
{
status_t err = client->initCheck();
if (err == NO_ERROR) {
return client;
}
return nullptr;
}
4.2 Choreographer 執(zhí)行流程
Activity啟動 走完onResume方法后记某,會進行window的添加司训。window添加過程會 調(diào)用ViewRootImpl的setView()方法,setView()方法會調(diào)用requestLayout()方法來請求繪制布局液南,requestLayout()方法內(nèi)部又會走到scheduleTraversals()方法壳猜,最后會走到performTraversals()方法,接著到了我們熟知的測量滑凉、布局统扳、繪制三大流程了。所有UI的變化都是走到ViewRootImpl的scheduleTraversals()方法
scheduleTraversals() 到 performTraversals() 畅姊,根據(jù)我們上面的介紹咒钟,在VSync信號到來時才會執(zhí)行繪制,即performTraversals()方法若未。
// ViewRootImpl.java
void scheduleTraversals() {
if (!mTraversalScheduled) {
//此字段保證同時間多次更改只會刷新一次朱嘴,例如TextView連續(xù)兩次setText(),也只會走一次繪制流程
mTraversalScheduled = true;
//添加同步屏障,屏蔽同步消息粗合,保證VSync到來立即執(zhí)行繪制
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//mTraversalRunnable是TraversalRunnable實例萍嬉,最終走到run(),也即doTraversal();
//第一個參數(shù)三種回調(diào)類型隙疚,第二個參數(shù)添加了Runnable壤追,第三個參數(shù)表示是否需要延時
mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
void doTraversal() {
if (mTraversalScheduled)
{
mTraversalScheduled = false;
//移除同步屏障
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
...
//開始三大繪制流程
performTraversals();
...
}
}
在上面的代碼中,scheduleTraversals()調(diào)用了mChoreographer.postCallback()方法甚淡,發(fā)送一個會在下一幀執(zhí)行的回調(diào)大诸,即在下一個VSync到來時會執(zhí)行TraversalRunnable–>doTraversal()—>performTraversals()–>繪制流程。
//輸入事件贯卦,首先執(zhí)行
public static final int CALLBACK_INPUT = 0;
//動畫资柔,第二執(zhí)行
public static final int CALLBACK_ANIMATION = 1;
//插入更新的動畫,第三執(zhí)行
public static final int CALLBACK_INSETS_ANIMATION = 2;
//繪制撵割,第四執(zhí)行
public static final int CALLBACK_TRAVERSAL = 3;
//提交贿堰,最后執(zhí)行,
public static final int CALLBACK_COMMIT = 4;
安排任務(wù)—postCallback
public void postCallback(int callbackType, Runnable action, Object token)
{
postCallbackDelayed(callbackType, action, token, 0);
}
public void postCallbackDelayed()
{
...
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
private void postCallbackDelayedInternal()
{
synchronized (mLock) {
//當(dāng)前時間
final long now = SystemClock.uptimeMillis();
//回調(diào)執(zhí)行時間啡彬,為當(dāng)前時間+延遲時間
final long dueTime = now + delayMillis;
//取對應(yīng)類型的CallbackQueue添加任務(wù)
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
if (dueTime <= now) {
//如果delayMillis = 0s羹与,就是沒有延遲時,duetime == now庶灿,馬上執(zhí)行
scheduleFrameLocked(now);
} else {
//如果有延遲纵搁,發(fā)送有一個msg定時消息,等時間到了再處理往踢,
//最終也是執(zhí)行上面一個步驟腾誉,scheduleFrameLocked(now)
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
此處獲取當(dāng)前時間,然后加上要延遲的時間,作為當(dāng)前Callback的時間點利职,以這個時間點作為標準趣效,把Callback對象添加到mCallbackQueues[callbackType]隊列當(dāng)中.當(dāng)執(zhí)行時間還沒到時,往當(dāng)前的隊列中添加一個Message猪贪,那么通過Handler機制就會進行處理跷敬,此處的mHandler是一個FrameHandler對象
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
執(zhí)行doFrame,即繪制過程,開始渲染下一幀的操作
case MSG_DO_FRAME:
doFrame(System.nanoTime(), 0);
break;
//申請VSYNC信號热押,例如當(dāng)前需要繪制任務(wù)時
case MSG_DO_SCHEDULE_VSYNC:
doScheduleVsync();
break;
//需要延遲的任務(wù)抚太,最終還是執(zhí)行上述兩個事件
case MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break;
}
}
}
如果時間還沒有炊林,會判斷消息澎灸,最后還是會走到下面這個方法:doScheduleCallback().scheduleFrameLocked()
private void scheduleFrameLocked(long now) {
if (!mFrameScheduled) {
mFrameScheduled = true;
//檢查是否使用了Vsync機制候醒,通過檢查系統(tǒng)值進行確定
if (USE_VSYNC) {
//當(dāng)前執(zhí)行的線程绘雁,是否是mLooper所在線程
if (isRunningOnLooperThreadLocked()) {
//請求vsync信號笛粘,最終調(diào)到native層燃逻,native處理后出發(fā)FramedisplayEventReceiver
//的onVsync()回調(diào)谈撒,然后執(zhí)行doFrame()
scheduleVsyncLocked();
} else {
// 若不在致盟,就用mHandler發(fā)送消息到原線程碎税,最后還是調(diào)用scheduleVsyncLocked方法
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(true);//異步
mHandler.sendMessageAtFrontOfQueue(msg);
}
} else {
//如果系統(tǒng)沒有使用VSync機制,則使用異步消息延時執(zhí)行屏幕刷新(4.1后默認開啟)
final long nextFrameTime = Math.max(
mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(true);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
到這里馏锡,F(xiàn)rameHandler的作用很明顯里了:發(fā)送異步消息(因為前面設(shè)置了同步屏障)雷蹂。有延遲的任務(wù)發(fā)延遲消息、不在原線程的發(fā)到原線程杯道、沒開啟VSYNC的直接走 doFrame 方法取執(zhí)行繪制匪煌。
申請和接受VSync
調(diào)用mDisplayEventReceiver的scheduleVsync()方法,mDisplayEventReceiver是Choreographer構(gòu)造方法中創(chuàng)建党巾,是FrameDisplayEventReceiver 的實例萎庭。 FrameDisplayEventReceiver是 DisplayEventReceiver 的子類,DisplayEventReceiver 是一個 abstract class
// mDisplayEventReceiver類變量是在Choreographer的構(gòu)造方法中賦值的
private void scheduleVsyncLocked() {
//申請Vsync信號
mDisplayEventReceiver.scheduleVsync();
}
public void scheduleVsync() {
nativeScheduleVsync(mReceiverPtr);
}
底層的 nativeScheduleVsync()向surfaceflinger服務(wù)注冊齿拂,即在下一次脈沖接受后調(diào)用DisplayEventReceiver的dispatchVsync()方法驳规。(每次調(diào)用只有一次dispatchVsync()方法回調(diào))
底層向應(yīng)用層發(fā)送VSYNC信號,java層通過dispatchVsync()接受署海,最后的回調(diào)在FrameDisplayEventReceiver()的onVsync()中
private final class FrameDisplayEventReceiver extends DisplayEventReceiver
implements Runnable {
private boolean mHavePendingVsync;
private long mTimestampNanos;
private int mFrame;
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
super(looper, vsyncSource);
}
@Override
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
scheduleVsync();
return;
}
mTimestampNanos = timestampNanos;
mFrame = frame;
//將本身作為runnable傳入msg吗购, 發(fā)消息后 會走run(),即doFrame()砸狞,也是異步消息
Message msg = Message.obtain(mHandler, this);
msg.setAsynchronous(true);
//此處的mHandler為FrameHandler
mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
@Override
public void run() {
mHavePendingVsync = false;
doFrame(mTimestampNanos, mFrame);
}
}
onVsync()方法通過FrameHandler向主線程looper發(fā)送callback消息捻勉,當(dāng)looper執(zhí)行到該消息時調(diào)用run()方法,然后調(diào)用doFrame()刀森。然后doFrame()在Vsync事件到來時順序執(zhí)行CallbackQueue隊列中注冊的回調(diào)踱启,調(diào)用doCallbacks().CallbackRecord對應(yīng)的run()方法。
void doFrame(long frameTimeNanos, int frame) {
...
try {
// 按類型順序 執(zhí)行任務(wù)
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
mFrameInfo.markAnimationsStart();
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos);
mFrameInfo.markPerformTraversalsStart();
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
void doCallbacks(int callbackType, long frameTimeNanos) {
CallbackRecord callbacks;
synchronized (mLock) {
final long now = System.nanoTime();
// 根據(jù)指定的類型CallbackkQueue中查找到達執(zhí)行時間的CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now / TimeUtils.NANOS_PER_MS);
try {
// 迭代執(zhí)行隊列所有任務(wù)
for (CallbackRecord c = callbacks; c != null; c = c.next) {
// 回調(diào)CallbackRecord的run,其內(nèi)部回調(diào)Callback的run
c.run(frameTimeNanos);
}
} finally {
synchronized (mLock) {
mCallbacksRunning = false;
do {
final CallbackRecord next = callbacks.next;
//回收CallbackRecord
recycleCallbackLocked(callbacks);
callbacks = next;
} while (callbacks != null);
}
}
}
//上面主要內(nèi)容就是取對應(yīng)任務(wù)類型的隊列禽捆,遍歷隊列執(zhí)行所有任務(wù)
//執(zhí)行任務(wù)是 CallbackRecord的 run 方法:
private static final class CallbackRecord {
...
@UnsupportedAppUsage
public void run(long frameTimeNanos) {
if (token == FRAME_CALLBACK_TOKEN) {
// 通過postFrameCallback 或 postFrameCallbackDelayed笙什,會執(zhí)行這里
((FrameCallback)action).doFrame(frameTimeNanos);
} else {
//取出Runnable執(zhí)行run()
((Runnable)action).run();
}
}
}
前面看到mChoreographer.postCallback傳的token是null,所以取出action胚想,就是Runnable琐凭,執(zhí)行run()。這里的action就是 ViewRootImpl 發(fā)起的繪制任務(wù)mTraversalRunnable了浊服,那么這樣整個邏輯就閉環(huán)了.
run()方法被執(zhí)行统屈,所以doTraversal()被執(zhí)行,調(diào)用performTraversals開啟View的繪制流程牙躺。
4.3 Choreographer小結(jié)
使用Choreographer的postCallback()愁憔、postFrameCallback() 作用理解:發(fā)送任務(wù) 存隊列中,監(jiān)聽VSync信號孽拷,當(dāng)前VSync到來時 會使用mHandler發(fā)送異步message吨掌,這個message的Runnable就是隊列中的所有任務(wù)。
參考博客:Android屏幕刷新機制—VSync脓恕、Choreographer 全面理解膜宋!
VSYNC,這個具體指啥炼幔?在屏幕刷新中如何工作的秋茫?
答:當(dāng)掃描完一個屏幕后,設(shè)備需要重新回到第一行以進入下一次的循環(huán)乃秀,此時會出現(xiàn)的vertical sync pulse(垂直同步脈沖)來保證雙緩沖在最佳時間點才進行交換肛著。并且Android4.1后 CPU/GPU的繪制是在VSYNC到來時開始。