display整體框架

梳理流程和圖形參考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

  1. Activity:是APP與用戶進行交互的入口,一個Activity對應(yīng)著一個窗口(window)芒率,完成用戶的key囤耳、touch事件的相應(yīng)處理和對window生命周期進行管理
  2. Window:window是視圖(view)的容器偶芍,Window有唯一的實現(xiàn)類:PhoneWindow充择。Window受WindowManager統(tǒng)一管理,對window管理通過WindowWtate腋寨,該變量是系統(tǒng)對Window管理的一個封裝類聪铺,與window一一對應(yīng)。
  3. view:視圖萄窜,承載著將要顯示的內(nèi)容铃剔,其中DecorView(頂級視圖)是當(dāng)前Activity的根View,它里面管理著當(dāng)前界面的View樹查刻,包含著標題欄titleBar和內(nèi)容欄contentView键兜。
Activity、Window和view關(guān)系
  1. surface:每個Window對應(yīng)一個surface穗泵,作為View顯示的載體普气,圖形的傳遞通過buffer作為載體,因此surface是對buffer的封裝佃延,對圖形的操作其實就是對suface中buffer的操作现诀。
  2. canvas:畫布夷磕,任何的view都需要畫在surface的canvas上。
  3. SurfaceFlinger:作為一個service仔沿,接收所有的surface作為輸入坐桩,創(chuàng)建layer,把不同的layer進行裁剪等合成操作來顯示封锉。
  4. layer:由surfaceFlinger進行創(chuàng)建绵跷,是surfaceFlinger進行合成的基本單位(一個surface對應(yīng)一個layer),layer其實是一個FrameBuffer(幀buffer)成福,每個FrameBuffer中有兩個GraphicBuffer(圖形buffer碾局,因為Android為了將系統(tǒng)操作buffer和硬件顯示buffer分開,所以設(shè)置了兩個buffer)奴艾,記為FrontBuffer和BackBuffer净当。
不同layer合成顯示

從圖中可以看出,最終顯示在屏幕上的內(nèi)容由多個surface(layer)通過SurfaceFlinger進行合成握侧,surface上中不同的view都畫在surface的canvas上蚯瞧。

  1. choreographer:處于上層嘿期,接收VSync信號品擎,同Vsync配合,統(tǒng)一Android顯示中的動畫备徐、輸入和繪制時機萄传。
  2. 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é):

  1. Android啟動后缕坎,在init.rc解析時創(chuàng)建SurfaceFlinger實例并向serviceManager注冊,啟動SurfaceFlinger服務(wù)篡悟。
  2. Activity在啟動過程中會創(chuàng)建PhoneWindow并且與之建立回調(diào)關(guān)系(用于接收touch等消息)谜叹;在PhoneWindow中創(chuàng)建頂級視圖DecorView匾寝。
  3. Activity調(diào)用函數(shù)setView(),里面有兩個重要的函數(shù):requestlayout()mWindowSession.addtoDisplay()荷腊。后者完成view的添加旗吁、app與surfaceFlinger的服務(wù)的連接;前者完成了view的繪制停局、view畫在surface的canvas上并把surface傳入SurfaceFlinger很钓。
  4. SurfaceFlinger創(chuàng)建layer并將傳入的Surface進行合成,最后將合成后的數(shù)據(jù)通過SurfaceFlinger::postComposition()函數(shù)畫在屏幕上董栽。
  5. 為了讓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生命周期斧拍。

Activity啟動流程

2.1 window的創(chuàng)建 雀扶、View創(chuàng)建和添加

Activity中Window創(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袜漩。

surface創(chuàng)建過程

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到來時開始。

執(zhí)行流程圖
View繪制流程
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跺讯,一起剝皮案震驚了整個濱河市枢贿,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抬吟,老刑警劉巖萨咕,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異火本,居然都是意外死亡危队,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門钙畔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茫陆,“玉大人,你說我怎么就攤上這事擎析〔局眩” “怎么了挥下?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長桨醋。 經(jīng)常有香客問我棚瘟,道長,這世上最難降的妖魔是什么喜最? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任偎蘸,我火速辦了婚禮,結(jié)果婚禮上瞬内,老公的妹妹穿的比我還像新娘迷雪。我一直安慰自己,他們只是感情好虫蝶,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布章咧。 她就那樣靜靜地躺著,像睡著了一般能真。 火紅的嫁衣襯著肌膚如雪赁严。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天舟陆,我揣著相機與錄音误澳,去河邊找鬼。 笑死秦躯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的裆装。 我是一名探鬼主播踱承,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼哨免!你這毒婦竟也來了茎活?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤琢唾,失蹤者是張志新(化名)和其女友劉穎载荔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體采桃,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡懒熙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了普办。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片工扎。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖衔蹲,靈堂內(nèi)的尸體忽然破棺而出肢娘,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布橱健,位于F島的核電站而钞,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拘荡。R本人自食惡果不足惜臼节,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俱病。 院中可真熱鬧官疲,春花似錦、人聲如沸亮隙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽溢吻。三九已至维费,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間促王,已是汗流浹背犀盟。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蝇狼,地道東北人阅畴。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像迅耘,于是被迫代替她去往敵國和親贱枣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354