「Android」 Surface分析

来源:https://www.cnblogs.com/1996swg/archive/2018/10/26/9834892.html
-Advertisement-
Play Games

本篇針對Surface模塊進行分析,從Java層的Activity創建開始,到ViewRoot、WindowsManagerService,再到JNI層和Native層。 首先推薦一個Android源碼查看的網站:http://androidxref.com/ Surface的創建涉及三個部分: A ...


 本篇針對Surface模塊進行分析,從Java層的Activity創建開始,到ViewRoot、WindowsManagerService,再到JNI層和Native層。

首先推薦一個Android源碼查看的網站:http://androidxref.com/

Surface的創建涉及三個部分:

  1. App 進程
    App需要將自己的內容顯示在屏幕上,所以App負責發起Surface創建請求,創建好Surface後, 就可以直接可以在canvas上畫圖等,最終都會保存到Surface里的buffer里,最後由SurfaceFlinger合成並顯示。

  2. System_Server進程
    主要是其中的WindowManagerService, 負責接收APP請求,向SurfaceFlinger發起具體的請求創建Surface, 且WMS需要創建Surface的輔助管理類,如SurfaceControl。

  3. SurfaceFlinger
    為App進程創建具體的Surface, 在SurfaceFlinger里對應成Layer, 然後負責管理、合成顯示。

 

總體流程(參考《深入理解Android》,源碼較舊):

Surface創建過程:
ActivityThread.java
    調用handleLaunchActivity
        調用handleResumeActivity函數
            addView調用到LocalWindowManager.java的addView函數
                然後調用WindowManagerImpl.java的addView函數
                    創建ViewRoot(分成兩個分支):
                        1、執行ViewRoot的構造函數,創建mSurface(!實現ViewRoot的Surface創建)(創建IWindow)

                        2、調用ViewRoot的setView函數(分成兩個分支):
                            1、setView調用WMS的add函數(IWindowSession)
                                調用WMS的addWindow函數
                                    調用WMS.java::WindowState的attach函數
                                        調用WMS.java::Session的windowAddedLocked函數,創建SurfaceSession(!實現WMS的SurfaceSession創建)
                                            執行SurfaceSession的構造器,調用native函數init
                                                JNI層實現init函數,創建一個SurfaceComposerClient(分成兩步):
                                                    1、SurfaceComposerClient構造函數調用SurfaceFlinger的createConnection(!和SF建立交互通道)
                                                        創建Client(創建共用記憶體)(一個Client最多支持31個顯示層)
                                                            Client構造函數創建SharedClient對象
                                                                SharedClient定義SharedBufferStack數組對象(有31個元素)
                                                        創建BClient(接受客戶端請求,將處理提交給SF)    
                                                    2、再調用_init(初始化SurfaceComposerClient一些成員變數)

                            2、調用requestLayout函數,向ViewRoot發送DO_TRAVERSAL消息
                                調用handleMessage函數
                                    調用performTraversal函數(分成兩個分支):
                                        1、調用ViewRoot的relayoutWindow函數(調用IWindowSession的relayout函數)
                                            調用createSurfaceControl創建一個SurfaceControl
                                                ?在SurfaceComposerClient的createSurface創建一個SurfaceControl(請求端)
                                                    ?SurfaceComposerClient調用createSurface創建一個Surface(SurfaceControl類型)
                                                    ?    調用SurfaceControl的writeToParcel將信息寫入Parcel包中
                                                    ?        在readFromParcel中通過Parcel信息構造一個Surface對象,保存到mSurface
                                                    ?            ViewRoot獲得一個Native的Surface對象

                                            調用WMS.java::Session的relayout函數(!此和上這兩步跨進程)(分成三步):
                                                1、在IWindowSession.adil的Bn端調用onTransact,writeToParcel寫入信息
                                                2、在IWindowSession.adil的Bp端,relayout中傳入outSurface,readFormParcel讀取信息填充outSurface
                                                    
                                                3、調用WMS的relayoutWindow
                                                    》》調用WMS.java::WindowState的createSurfaceLocked,創建本地Surface(SurfaceSession)
                                                    》》調用copyForm,將本地surface信息拷貝到outSurface(即mSurface)
                                        2、調用draw()函數開始繪製(lockCanvas、調用draw、unlockCanvasAndPost)
                                            調用DecorView的draw函數(!實現UI繪製)

 

概述


 

Surface和APP的關係:

  Surface像是UI的畫布,APP就像是在Surface上作畫,通過i使用Skia繪製二維圖像,或是用OpenGL繪製三維圖像,最終APP和Surfacea都要進行交互。

SUrface和SurfaceFlinger(SF)的關係:

  surface向SF提供數據,SF進行混合數據。

Activity的顯示(Java層)


 1、應用程式的顯示和surface有關,而應用程式的外表通過Activity展示的,那麼Activity如何創建的呢?

  App對應的進程,它的入口函數是ActivityThread類的main函數。

  ActivityThread類中有一個handleLaunchActivity函數(創建Activity),代碼如下:

private void handleLaunchActivity(ActivityClientRecord r
    , Intent customIntent
    , String reason) {
    ...
    Activity a = performLaunchActivity(r, customIntent);
    ...
    if (a != null) {
        ...
        handleResumeActivity(r.token
        , false
        , r.isForward
        ,!r.activity.mFinished && !r.startsNotResumed
        , r.lastProcessedSeq, reason);
        //Activity創建成功就往onResume()走了!
        ...
    }
}

 

   這個函數涉及了兩個關鍵函數:

(1)performLaunchActivity
    返回一個activity(即App中的Activity),該方法 創建了Activity:
private Activity performLaunchActivity(ActivityClientRecord r
    , Intent customIntent) {
    ...
 // newActivity函數根據Activity的類名通過Java反射機制創建對應的Activity
    activity = mInstrumentation.newActivity(     
         cl, component.getClassName(), r.intent);
    ...
     Application app = r.packageInfo.makeApplication(false
     , mInstrumentation);
     //在獲取Application
    ...
    activity.attach(appContext
        , this
        , getInstrumentation()
        , r.token
        ,.ident
        , app
        , r.intent
        , r.activityInfo
        , title
        , r.parent
        , r.embeddedID
        , r.lastNonConfigurationInstances
        , config
        ,r.referrer
        , r.voiceInteractor
        , window);
    ...
    if (r.isPersistable()) {
        mInstrumentation.callActivityOnCreate(
          activity, r.state, r.persistentState);
    } else {
        mInstrumentation.callActivityOnCreate(activity, r.state);  //調用Activity的onCreate函數
    }
    ...
}

  因此,performLaunchActivity的作用如下:

  • 根據類名以java反射機制的方法創建一個Activity
  • 調用Activity的onCreate函數,開始Activity 的生命周期
(2)handleResumeActivity
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
            boolean reallyResume) {
        ...

        // 與調用Activity的onResume相關
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        ...
                // PhoneWindow
                r.window = r.activity.getWindow();
                // 獲取Activity的DecorView
                View decor = r.window.getDecorView();
                decor.setVisibility(View.INVISIBLE);
                // WindowManagerImpl,其實就是LocalWindowManager
                ViewManager wm = a.getWindowManager();
                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);   // 將剛纔的dector對象加入到ViewManagerg中
                }

            ...
    }

     

     > 在Activity.java中Activity在onCreate函數中通過setContentView設置UI界面。

  Activity.java部分代碼:

public  void  setContentView(View view) {
  getWindow().setContentView(view);   // 傳入一個view
}

public  Window  getWindow() {
   return mWindow;    //返回一個類型為Window的對象
}

  > 分析出現的兩個和UI相關的類:

Window:一個抽象基類,用於控制頂層視窗的外觀和行為。職能可能是繪製背景、標題欄、預設的按鍵處理等。

     它將作為一個頂層的view加入到Window  Manager中。 

View:一個基本的UI單元,占據屏幕的一塊矩形區域,可用於繪製,能處理事件。(設置的view其實只是DecorView的子view,DecorView還處理了標題欄顯示等一系列操作)

 

也可以看做:

  > 分析addView,wm類型實際上是LocalWindowManager,查看LocalWindowManager.java的addView函數:

public  final void addView(View view , ViewGroup.LayoutParams params) {
      ..............
      mWindowManager.addView(view, params);  // mWindowManager對象實際是WindowManagerImpl類型
}

  接著查看WindowManagerImpl.java類的addView函數:

private void addView(View view, ViewGroup.LayoutParams params, boolean nest)
    {
       ...
      ViewRoot root;
      ...
      root = new ViewRoot(view.getContext());   // 創建viewRoot
      ...
      root.setView(view, wparams, panelParentView);   // view即剛剛介紹的DectorView

 


 

  2、 viewRoot: viewRoot實現了ViewParent介面,ViewParent不處理繪畫,因為它沒有onDraw函數(所以和Android基本繪畫單元的view不太一樣)

//查看ViewRoot.java::ViewRoot定義
public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks    // 從Handler 派生
{
private final Suface mSurface = new Surface(); // 創建了一個Surface 對象
Final W mWindow;
View mView;
}

 

 分析得出ViewRoot的作用:
  • ViewRoot繼承Handler類,能夠處理消息,重寫了handleMessage函數
  • ViewRoot有一個成員變數mSurface,是Surface類型
  • ViewRoot有一個W類型的mWinow和一個View類型的mView變數(W是ViewRoot定義的e靜態內部類 static class W extends IWindow.Stub,將參與和Binder的通信) 

View、DectorView是UI單元,繪畫工作在OnDraw函數中完成。如果onDraw是畫圖過程,那麼畫布就是Surface。

Surface:有一塊Raw Buffer,Surface操作這塊Raw Buffer,Screen Compositor(即SurfaceFlinger)管理這塊Raw Buffer。

結論:

  • ViewRoot的成員變數mSurface(aSurfce類型),他和一塊Raw Buffer有關聯
  • ViewRoot是一個ViewParent,他的子View的繪畫操作,是在畫布Surface上展開的
  • Surface和SurfaceFlinger交互

的setView中,調用的時ViewRoot.java的setView函數:

public void setView(View view, WindowManager.LayoutParams attrs,
            View panelParentView) {
      ...
      ...
    res = sWindowSession.add(mWindow, mWindowAttributes,
                            getHostVisibility(), mAttachInfo.mContentInsets,
                            mInputChannel);
    ...
}

 

 實現了:

  • 保存傳入的View(即DectorView,從ActivityThread層層傳入)
  • 調用requestLayout(往handler中發送一個消息,因為ViewRoot是從handlera派生的,所以這個消息最後會由ViewRoot自己處理)
  • 調用IWindowSession的add函數(一個跨進程的Binder通信,第一個參數是mWindow,他是W類型,由IWindow.stub派生)

 


 

3、requestLayout會向ViewRoot發送一個消息,進入ViewRoot.java的handleMessage函數,調用performTraversals函數。

進入 performTraversals函數: 

private void performTraversals() {
    final View host = mView;   //即最初的DectorView
    ...
  try{
    relayoutResult = relayoutWindow(params, viewVisiblity, insetPending);
} ... host.measure(childWidthMeasureSpec, childHeightMeasureSpec); ... host.layout(
0, 0, host.mMeasuredWidth, host.mMeasuredHeight); ... ... draw(fullRedrawNeeded); ... }

 

(1)relayoutWindow函數:會調用IWindowSession的Relayout函數;

(2)draw函數:從mSurface(Surface)中lock一塊Canvas(畫布),調用DecorView的draw函數,然後交給mView繪畫,最後unlockCanvasAndPost釋放這塊Canvas

 


 

總結:

1、大致涉及的方法、類的大體流程(回車表示前一方法內調用):

ActivityThread.java
    調用handleLaunchActivity
        調用performLaunchActivity函數(創建Activity、調用onCreate)
            onCreate調用setContentView函數設置UI界面,傳入view,返回Window
        調用handleResumeActivity函數
            addView調用到LocalWindowManager.java的addView函數
                然後調用WindowManagerImpl.java的addView函數
                    創建ViewRoot,調用ViewRoot的setView函數

ViewRoot.java(繼承Handler、實現ViewParent)
    構造函數創建一個Surface對象mSurface
    setView函數實現:
        保存傳入的view為mView
        調用requestLayout
        調用IWindowSession的add函數
        WIndowManagerServce.java::session的add函數
          調用WMS.java的addWindow
            調用WMS.java::WIndowState的attach函數
              調用windowAnddedLocked函數並創建一個SurfaceSession對象 
requestLayout(向ViewRoot發送一個消息) 進入ViewRoot.java的handleMessage函數 調用performTraversals函數 調用relayoutWindow函數 調用IWindowSession的Relayout函數 調用draw函數(從mSurface中lock一塊Canvas) 調用DecorView的draw函數,交給mView繪畫 最後unlockCanvasAndPost釋放Canvas

 

2、要點:

(1)整個Activity的繪圖流程就是從mSurface中lock一塊Canvas,然後交給mView去繪畫,最後unlockCanvasAndPost釋放這塊Canvas ;

(2)Activity的頂層view是DecotView,而onCreate函數中setContentView設置的View是這個DecorView的一部分。DecorView是一個FrameLayout類型的ViewGroup;

(3)Activity和UI有關,包含window(真實類型是phoneWIndow)和一個WindowManger(真實類型是LocalWindowManager)對象。這兩個對象控制整個Activity的顯示;

(4)LocalWindowManager使用了WindowManagerImpl.java(其中addView有一個ViewRoot對象)作為最終處理對象;

(5)ViewRoot實現了ViewParent介面,有兩個變數:

    mView,指向Activity頂層UI單元的DecorView

    mSurface,包含一個Canvas

   此外,ViewRoot還通過Binder系統和dWinowManagerService進行跨進程交互;

(6)ViewRoot能夠處理Handler的消息,Activity的顯示就是由ViwRoot在他的performTraversals函數中完成;


 

 

Surface(Java層)


通過上面一節的分析可知:

ViewRoot的構造函數裡面會創建一個Surface;

而ViewRoot通過IWindowSession和WMS交互時,WMS調用的attach函數會構造一個SurfaceSession;

ViewRoot在prformTransval的處理過程中會調用IWindowSession的relayout函數。(WMS由SYsytem_server進程啟動,SF服務也在這個進程中)

 

  兩個部分的Surface看似是毫無關係,但是實際上,在使用createSurfaceLocked() 的時候,會將creaeSurfaceLocked 創建的Surface copy到ViewRoot層的Surface中。也就是這樣,將底層的Surface對象傳到上層,供Activity的界面部分使用,用來繪圖。整個流程大概是:

RootView.relayoutWindow,調用方,調用relayout將mSurface傳進去

->  WindowManagerService.Session.relayout調用外部類對象的relayoutWindow

->  WindowManagerService.relayoutWindow,調用createSurfaceLocked

->  WindowManagerService.createSurfaceLocked(),將SurfaceSession拷貝到創建的新對象Surface

->  outSurface.copyFrom(surface),將本地Surface 的信息(即SurfaceSession)拷貝到outSurface中

最後一步是將WindowManagerService的surface與ViewRoot 的outSurface聯繫起來的關鍵點,outSurface是作為參數,從RootView傳到WindowManagerService的。

ViewRoot其實是通過Binder與WindowManagerService進行跨進程調用通信的。

 


 

 

Surface(JNI層)


 

1、在JNI層,首先被調用的時Surface的無參構造函數,代碼:

// Surface.java
Public Surface() {
 ...
mCanvas = new CompatibleCanvas();  //   CompatibleCanvaso從Canvas類派生
}

 

 Canvas:

  畫圖需要:

  • Bitmap,用於存儲像素(即畫布,可以當作是一塊數據存儲區域);
  • Canvas,用於記載畫圖的動作(例如畫一個矩形),Canvas提供了這些基本操作的繪圖函數;
  • Drawing primitive:繪圖基本元素,例如矩形、圓等;
  • Paint:用來描述h繪畫時使用的顏色、虛實線等;

一般情況下,Canvas會封裝一塊Bitmap。

 

2、SurfaceSession的構造

// SurfaceSession.java
public  SurfaceSession(){
       init();   //這是一個native函數       
}

 

init函數的實現在JNI的android_view_Surface.cpp中:

static void SurfaceSession_init(JNIEnv* env,jobject clazz)
{
     //創建一個SurfaceComposerClient對象
   sp<SurfaceComposerClient> client = new SurfaceComposerClient;
client->incStrong(clazz);
//在Java對象中保存這個client對象的指針,類型為SurfaceComposerClient
   env->SetIntField(clazz, sso.client, (int)client.get());
}

 

 

3、Surface的有參構造函數:

//    Surface.java
    publicSurface(SurfaceSession s,//傳入一個SurfaceSession對象
           int pid, String name, int display, int w, int h, int format, int flags)
       throws OutOfResourcesException {
        ......
       mCanvas = new CompatibleCanvas();
      //又一個native函數,註意傳遞的參數:display以後再說,w,h代表繪圖區域的寬高值
       init(s,pid,name,display,w,h,format,flags);
       mName = name;
    }

 

Surface的init函數實現在JNI層:

static void Surface_init(

        JNIEnv*env, jobject clazz,
       jobject session,
       jint pid, jstring jname, jint dpy, jint w, jint h, jint format, jintflags)
{
   //從SurfaceSession對象中取出之前創建的那個SurfaceComposerClient對象
SurfaceComposerClient* client =
           (SurfaceComposerClient*)env->GetIntField(session, sso.client);

   sp<SurfaceControl> surface;//註意它的類型是SurfaceControl
if (jname == NULL) {
    /*
調用SurfaceComposerClient的createSurface函數,返回的surface是一個
SurfaceControl類型。
*/
       surface = client->createSurface(pid, dpy, w, h, format, flags);
    } else{
      ......
}
   //把這個surfaceControl對象設置到Java層的Surface對象中,對這個函數就不再分析了
   setSurfaceControl(env, clazz, surface);
}

 

 

4、copyForm分析 

上一節中,outSurface.copyFrom(surface),將本地Surface 的信息(即SurfaceSession)拷貝到outSurface中

他是一個native函數,代碼如下:

static void Surface_copyFrom(JNIEnv* env,jobject clazz, jobject other)
{
   //根據JNI函數的規則,clazz是copyFrom的調用對象,而other是copyFrom的參數。
   //目標對象此時還沒有設置SurfaceControl,而源對象在前面已經創建了SurfaceControl
   constsp<SurfaceControl>& surface = getSurfaceControl(env, clazz);
   constsp<SurfaceControl>& rhs = getSurfaceControl(env, other);

if (!SurfaceControl::isSameSurface(surface, rhs)) {
        //把源SurfaceControl對象設置到目標Surface中。
       setSurfaceControl(env, clazz, rhs);
    }
}

 

 

5、writeToParcel和readFromParcel分析

這兩個函數調用發生在ViewRoot調用IWindowSession的relayout函數中,它發生在IWindowSession.adil(通過aidl -l ...編譯成java文件可查看到relayout方法中和onTransactg中)

//  android_view_Surface.cpp
static void Surface_writeToParcel(JNIEnv* env,jobject clazz,
jobject argParcel, jint flags)
{
   Parcel* parcel = (Parcel*)env->GetIntField(argParcel, no.native_parcel);

//clazz就是Surface對象,從這個Surface對象中取出保存的SurfaceControl對象
const sp<SurfaceControl>&control(getSurfaceControl(env, clazz));
/*
把SurfaceControl中的信息寫到Parcel包中,然後利用Binder通信傳遞到對端,
對端通過readFromParcel來處理Parcel包。
*/
   SurfaceControl::writeSurfaceToParcel(control, parcel);

if (flags & PARCELABLE_WRITE_RETURN_VALUE) {

       //lags的值就等於PARCELABLE_WRITE_RETURN_VALUE
       //所以本地Surface對象的SurfaceControl值被置空了
       setSurfaceControl(env, clazz, 0);
    }
}
--------------------- 

//  android_view_Surface.cpp

static void Surface_readFromParcel(
       JNIEnv* env, jobject clazz, jobject argParcel)
{
   Parcel* parcel = (Parcel*)env->GetIntField( argParcel,no.native_parcel);
   //註意下麵定義的變數類型是Surface,而不是SurfaceControl
   const sp<Surface>&control(getSurface(env, clazz));

   //根據服務端傳遞的Parcel包來構造一個新的surface。
   sp<Surface> rhs = new Surface(*parcel);

if (!Surface::isSameSurface(control, rhs)) {
//把這個新surface賦給ViewRoot中的mSurface對象
      setSurface(env,clazz, rhs);
    }
}

 

小結

在JNIe層創建了三個對象:SurfaceComposerClient、SurfceControl、Surface 

大致流程:

(1)創建一個SurfaceComposerClient

(2)調用SurfaceComposerClient的createSurface得到一個SurfceControl對象

(3)調用SurfaceControl的writeToParcel,將一些信息寫入Parcel包中

(4)根據Parcel包的信息z構造一個Surface對象,將其保存到Java層的mSurface中

(5)因此,ViewRoot得到一個Native的Surface對象

 

 Surface和畫圖Canvas:

在ViewRoot的draw()函數裡面(前面有提到),有兩個和Surface相關的函數調用:

  (1)lockCanvas:先獲得一塊存儲區域,然後將它和Canvas綁定到一起,這樣,UI繪畫的結果就記錄在這塊存儲區域里了,如此進Canvas進行UI畫圖就會有畫布了;

  (2)unlockCanvasAndPost:一個native函數,取出Native的Surface對象,調用Surface的unlockAndPost函數。

 

調用流程總結:

   

總結

1、一個Activity一般都會對應到一個Window, 對應了一個DecorView, ViewRoot 
2、ViewRoot中有一個Surface, 就是App可以用於繪製UI的Surface了,在Native層也對應了一個Surface, 在SurfaceFlinger對應的是一個Layer,通過Layer中的Producer可以真正的申請Buffer用於繪製。App中通過Surface中的Canvas的類似lockcanvas介面觸發dequeue buffer流程。 
3、 一個ViewRoot在WMS端對應了一個WindowState, WindowState又通過一系列引用關聯到一個SurfaceControl, Native層也有一個SurfaceControl。這個可以用於控制視窗的一些屬性。 
4、 WMS native層的SurfaceComposerClient與SurfaceFlinger之間通過ISurfaceComposerClient建立聯繫。一個App在SurfaceFlinger端對應了一個Client,用於處理該App layer的創建等請求。

5、當ViewRootImpl請求WMS relayout時,會將ViewSurface中的Surface交給WMS初始化。在WMS中,對應每個WindowState對象,在relayout視窗時,同樣會創建一個Surface,wms中的這個Surface會真正的初始化,然後再將這個WMS Surface複製給ViewRootImpl中的Surface。這麼實現的目的就是保證ViewRootImpl和WMS共用同一個Surface。ViewRootImpl對Surface進行繪製,WMS對這個Surface進行初始化及管理。 

ActivityThread.java
    調用handleLaunchActivity
        調用performLaunchActivity函數(創建Activity、調用onCreate)
            onCreate調用setContentView函數設置UI界面,傳入view,返回Window
        調用handleResumeActivity函數
            addView調用到LocalWindowManager.java的addView函數
                然後調用WindowManagerImpl.java的addView函數
                    創建ViewRoot,調用ViewRoot的setView函數

ViewRoot.java(繼承Handler、實現ViewParent)
    構造函數創建一個Surface對象mSurface
    setView函數實現:
        保存傳入的view為mView
        調用requestLayout
        調用IWindowSession的add函數
        WIndowManagerServce.java::session的add函數
          調用WMS.java的addWindow
            調用WMS.java::WIndowState的attach函數
              調用windowAnddedLocked函數並創建一個SurfaceSession對象 

requestLayout(向ViewRoot發送一個消息)
    進入ViewRoot.java的handleMessage函數
        調用performTraversals函數
            調用relayoutWindow函數
                調用IWindowSession的Relayout函數
            調用draw函數(從mSurface中lock一塊Canvas)
                調用DecorView的draw函數,交給mView繪畫
                最後unlockCanvasAndPost釋放Canvas

 

創建Surface的整體流程:

1.1 viewrootImpl.java

在應用啟動時,會通過WindowManagerGlobal去添加view,添加view時會去創建viewRootImpl,然後進行設置view。

viewRootImpl.setView() —> requestLayout()申請佈局—>scheduleTraversals()—>doTraversal()–>performTraversals()

利用IWindowSession和Session通信,調用relayout,註意,這裡mSurface是ViewRootImpl的成員變數,開始調用了無參的構造函數,IWindowSession.aidl文件中,參數mSurface是被out修飾,用來接受在server端創建Surface,然後再binder返回給ViewRootImpl。

1.2 Session.java

 public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags,
            int flags, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
            Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                outConfig, outSurface);
        return res;
    }

 

1.3 WindowManagerService.java

 public int relayoutWindow(Session session, IWindow client, int seq,
          WindowManager.LayoutParams attrs, int requestedWidth,
          int requestedHeight, int viewVisibility, int flags,
          Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
          Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {

          //新建一個SurfaceControl 
          SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
                  if (surfaceControl != null) {
                      outSurface.copyFrom(surfaceControl);
                      if (SHOW_TRANSACTIONS) Slog.i(TAG,
                              "  OUT SURFACE " + outSurface + ": copied");
                  } else {
                      // For some reason there isn't a surface.  Clear the
                      // caller's object so they see the same state.
                      outSurface.release();
                  }
          }

 


 1.4 WindowStateAnimator.java

首先創建一個SurfaceControl:

SurfaceControl createSurfaceLocked() {

            mSurfaceControl = new SurfaceControl(
                        mSession.mSurfaceSession,
                        attrs.getTitle().toString(),
                        w, h, format, flags);
             }

    public SurfaceControl(SurfaceSession session,
            String name, int w, int h, int format, int flags)
                    throws OutOfResourcesException {
              //session就是SurfaceComposerClient在java層的代表
              //mNativeObject是native層SurfaceControl的指針
    mNativeObject = nativeCreate(session, name, w, h, format, flags);
    }

1.5 android_view_SurfaceControl.cpp

static jint nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags) {
    ScopedUtfChars name(env, nameStr);
    //從上層取到SurfaceComposerClient的指針,還原一個SurfaceComposerClient
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
    //調用createSurface,返回的是一個SurfaceControl對象,註意不是surface
    sp<SurfaceControl> surface = client->createSurface(
            String8(name.c_str()), w, h, format, flags);
    if (surface == NULL) {
        jniThrowException(env, OutOfResourcesException, NULL);
        return 0;
    }
    surface->incStrong((void *)nativeCreate);
    //返回給java層SurfaceControl的指針
    return int(surface.get());
}

 

1.6 SurfaceComposerClient.cpp

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,
                &handle, &gbp);
        //gbp就是surfacefligner中Layer的mBufferQueue的client端(IGraphicBufferProducer) 
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

 

1.7 Client.cpp

通過ISurfaceComposerClient的binder通信,調用服務端對應client對象的方法createSurface()

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp)
{
    /*
     * createSurface must be called from the GL thread so that it can
     * have access to the GL context.
     */

    class MessageCreateLayer : public MessageBase {
        SurfaceFlinger* flinger;
        Client* client;
        sp<IBinder>* handle;
        sp<IGraphicBufferProducer>* gbp;
        status_t result;
        const String8& name;
        uint32_t w, h;
        PixelFormat format;
        uint32_t flags;
    public:
        MessageCreateLayer(SurfaceFlinger* flinger,
                const String8& name, Client* client,
                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
                sp<IBinder>* handle,
                sp<IGraphicBufferProducer>* gbp)
            : flinger(flinger), client(client),
              handle(handle), gbp(gbp),
              name(name), w(w), h(h), format(format), flags(flags) {
        }
        status_t getResult() const { return result; }
        //MessageQueue.cpp 中方法回調MessageBase::handleMessage
        virtual bool handler() {            
            result = flinger->createLayer(name, client, w, h, format, flags,
                    handle, gbp);
            return true;
        }
    };

    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    mFlinger->postMessageSync(msg);
    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

 

 上述可看出,將創建layer消息放入隊列,如下所示:

status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
        nsecs_t reltime, uint32_t /* flags */) {
    status_t res = mEventQueue.postMessage(msg, reltime);
    if (res == NO_ERROR) {
        //阻塞等待消息處理完成
        msg->wait();
    }
    return res;
}

1.8 Layer.cpp

創建layer的消息被處理時,就會回調上述MessageCreateLayer類中的handler方法。handler方法中調用flinger.createLayer(),第一次還會執行Layer.onFirstRef()

status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
    //ALOGD("createLayer for (%d x %d), name=%s", w, h, name.string());
    if (int32_t(w|h) < 0) {
        ALOGE("createLayer() failed, w or h is negative (w=%d, h=%d)",
                int(w), int(h));
        return BAD_VALUE;
    }

    status_t result = NO_ERROR;

    sp<Layer> layer;

    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceDim:
            result = createDimLayer(client,
                    name, w, h, flags,
                    handle, gbp, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }

    if (result != NO_ERROR) {
        return result;
    }

    result = addClientLayer(client, *handle, *gbp, layer);
    if (result != NO_ERROR) {
        return result;
    }

    setTransactionFlags(eTransactionNeeded);
    return result;
}

 

 在執行Layer::onFirstRef()會新建一個緩衝區隊列的消費者與客戶端APP的生產者對應:

void Layer::onFirstRef()
{
    //surfaceflinger中新建一個緩衝區隊列的消費者
    mBufferQueue = new SurfaceTextureLayer(mFlinger);
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mBufferQueue, mTextureName);
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setFrameAvailableListener(this);
    mSurfaceFlingerConsumer->setName(mName);

#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif

    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
    updateTransformHint(hw);
} 

 

Surface(Native層)


(1)FrameBuffer(幀緩衝,存儲圖形、圖像的緩衝):

  Frame:幀,就是指一幅圖像。在屏幕a上看到的一幅圖像就是一幀。

  Buffer:緩衝,就是一段存儲區域(存儲的是幀) 。

(2) PageFlipping(畫面交換),用於圖像、圖形數據的生產和消費

  操作過程:

    1、分配一個能容納兩幀數據的緩衝Buffer,前面一個緩衝叫FrontBuffer,後一個叫BackBuffer;

    2、消費者使用FontBuffer中的舊數據,而生產者使用新數據填充BackBuffer,二者互不幹擾;

    3、當需要更新顯示時,BackBuffer變成oFrontBuffer,FrontBuffer變成BackBuffer。如此迴圈。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 當我們需要對數據做篩選和查詢的時候,往往會涉及到一些限制條件的判斷,今天就分享一個判斷字元串的技巧。 like 相信大家對like的用法肯定都很熟悉了,它可以匹配欄位以某字元串開始,以某字元串結尾,包含有某字元串,用法如下:like '%string',like 'string%',like '%s ...
  • 一、問題 用Eclipse做項目時候報錯 java.sql.SQLException: Incorrect string value: '\xE4\xB8\x80\xE6\xAC\xA1...' for column 'excelName' at row 1。而且就只有這個表的插入有問題。 二、解決 ...
  • 從微信的誕生,到微信公眾號、微信支付,再到小程式,騰訊生態在一次又一次影響用戶行為習慣的同時,也為開發者提供了新的思路和技能發展方向。無可置疑,微信小程式開發浪潮已經來臨,也將在 2018年成為各行業流量紅利的集中爆發入口。 4月28日,騰訊雲聯合 InfoQ舉辦的雲 +社區技術沙龍,以小程式開發實 ...
  • 一.首先檢查我們的代碼: 二.註冊在主活動上的代碼需要補上: 從中我們可以看到我們註冊在XML界面上,<intent-filter>後面的代碼為<action android:name="com.example.lenovo.activitytest.ACTION_START"/>,action中間 ...
  • 任務Runnable定義了一個可以獨立運行的代碼片段,通常用於界面控制項的延遲處理,比如有時為了避免同時占用某種資源造成衝突,有時則是為了反覆間隔刷新界面從而產生動畫效果。運行一個任務也有多種形式,既可在UI線程中調用處理器對象的post或者postDelayed方法,也能另外開啟分線程來執行Runn ...
  • 微信里搜“青少兒書畫”就行了。任何人可以任意發佈自己的寶寶的作品啊。發佈作品方式有2種,一種是電腦登錄網站上用瀏覽器(chrome瀏覽器、opera瀏覽器,firefox瀏覽器等,ie的不行)發佈作品。網址是https://zsj.itdos.com/project/26171另外一種方式是用小程式 ...
  • 註釋以 <!-- 開始並以 --> 結束,例如 <!--註釋內容-->。註釋可以出現在文檔序言中,包括文檔類型定義 (DTD);文檔之後;或文本內容中。 註釋不能出現在屬性值中。 不能出現在標記中。分析器在遇到 > 時,就認為註釋已結束;然後繼續將文檔作為正常的 XML 處理。 因此,字元串 > 不 ...
  • 筆者在進行安卓開發時,發現自己的代碼語法完全沒有問題。尤其是創建intent對象的時候,語法完全是正確的,但是Android Stuidio卻顯示報錯,Intent類顯示為紅色,如圖所示: 代碼如下所示: 利用滑鼠指向Intent編譯器就會顯示: 我相信很多朋友也遇到了這個問題,至於我們該如何解決這 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...