《深入理解Android卷 I》- 第八章 - Surface- 讀書筆記-part2

1 Surface有關(guān)流程梳理

  • ViewRootImpl的字段中有一個Surface類型的mSurface咆霜,直接調(diào)用了無參的構(gòu)造函數(shù)創(chuàng)建继准。final Surface mSurface = new Surface();

  • ViewRootImplsetView()函數(shù)中北苟,通過了IWindowSession跨進程與WindowManagerService中的Session交互闪朱,調(diào)用了IWindowSession.addToDisplay()函數(shù)薛匪。

    調(diào)用流程:

    frameworks/base/services/core/java/com/android/server/wm/Session.java

    @Override
        public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
                int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets,
                Rect outOutsets, InputChannel outInputChannel) {
              //WindowManagerService.addWindow
            return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                    outContentInsets, outStableInsets, outOutsets, outInputChannel);
        }
    

    frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    public int addWindow(Session session, IWindow client, int seq,
                WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
                Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
                InputChannel outInputChannel) {
           ...//
    
            synchronized(mWindowMap) {
               ...//
                boolean addToken = false;
                WindowToken token = mTokenMap.get(attrs.token);
                AppWindowToken atoken = null;
                if (token == null) {
                    ...//
                    token = new WindowToken(this, attrs.token, -1, false);
                    addToken = true;
                      ..//
                }
             ..//
               WindowState win = new WindowState(this, session, client, token, attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
              ..//
               //重要的函數(shù)
              win.attach();
              ...//
            }
            if (reportNewConfig) {
                sendNewConfiguration();
            }
            Binder.restoreCallingIdentity(origId);
    
            return res;
        }
    
    

    frameworks/base/services/core/java/com/android/server/wm/WindowState.java

    void attach() {
          //Session
        mSession.windowAddedLocked();
    }
    

    frameworks/base/services/core/java/com/android/server/wm/Session.java

    void windowAddedLocked() {
            if (mSurfaceSession == null) {
              //創(chuàng)建了一個SurfaceSeesion對象
                mSurfaceSession = new SurfaceSession();
               
                mService.mSessions.add(this);
                if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                    mService.dispatchNewAnimatorScaleLocked(this);
                }
            }
            mNumWindow++;
        }
    
    • ViewRootImplperformTransval()的處理過程中會調(diào)用relayoutWindow(),最后是調(diào)用的IWindowSessionrelayout()函數(shù)捐川。
    • ViewRootImpl調(diào)用SurfacelockCanvas(),得到一塊畫布。
    • ViewRootImpl調(diào)用SurfaceunlockCanvasAndPost(),釋放畫布逸尖。

2 surface的轉(zhuǎn)化

通過梳理古沥,在performTransval()中會與WindowManagerServic交互

frameworks/base/services/core/java/com/android/server/wm/Session.java

ublic 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, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
            Configuration outConfig, Surface outSurface) {
      
        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                outStableInsets, outsets, outBackdropFrame, outConfig, outSurface);
     
        return res;
    }

這個函數(shù)本身沒有任何實際操作,實際操作對象時WindowManagerService

frameworks/base/services/core/java/com/android/server/wm/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, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
            Configuration outConfig, Surface outSurface) {
        ...//

        long origId = Binder.clearCallingIdentity();
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
           ...//

            if (viewVisibility == View.VISIBLE &&
                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
                result = relayoutVisibleWindow(outConfig, result, win, winAnimator, attrChanges,
                        oldVisibility);
                try {
                  //創(chuàng)建sufaceControl
                    result = createSurfaceControl(outSurface, result, win, winAnimator);
                } catch (Exception e) {
                   ...//
                }
               ..//
            }
        return result;
    }

7.0的源碼這部分非常復(fù)雜娇跟,就光一個本地的surface對象的創(chuàng)建都找了天才找到岩齿,而且還是多層封裝

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

private int createSurfaceControl(Surface outSurface, int result, WindowState win,
            WindowStateAnimator winAnimator) {
        if (!win.mHasSurface) {
            result |= RELAYOUT_RES_SURFACE_CHANGED;
        }
        //創(chuàng)建WindowSurfaceController對象
        WindowSurfaceController surfaceController = winAnimator.createSurfaceLocked();
        if (surfaceController != null) {
            //這里面才是原書中的copyFrom()
            surfaceController.getSurface(outSurface);          
        } else {
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            outSurface.release();
        }
        return result;
    }
void getSurface(Surface outSurface) {
    outSurface.copyFrom(mSurfaceControl);
}

然而還是沒有找到surface的創(chuàng)建,那么一定是在surfaceController對中了苞俘。

frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java

WindowSurfaceController createSurfaceLocked() {
        final WindowState w = mWin;
        if (w.hasSavedSurface()) {
            return mSurfaceController;
        }
        if (mSurfaceController != null) {
            return mSurfaceController;
        }
        w.setHasSurface(false);
        ..//
        // We may abort, so initialize to defaults.
        mLastSystemDecorRect.set(0, 0, 0, 0);
        mHasClipRect = false;
        mClipRect.set(0, 0, 0, 0);
        mLastClipRect.set(0, 0, 0, 0);
        try{
            ...//
            //創(chuàng)建WindowSurfaceController實例
            mSurfaceController = new WindowSurfaceController(mSession.mSurfaceSession,
                    attrs.getTitle().toString(),
                    width, height, format, flags, this);

            w.setHasSurface(true);

           
        } catch (OutOfResourcesException e) {
            mService.reclaimSomeSurfaceMemoryLocked(this, "create", true);
            mDrawState = NO_SURFACE;
            return null;
        } catch (Exception e) {
            mDrawState = NO_SURFACE;
            return null;
        }

        // Start a new transaction and apply position & offset.
        final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
        mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
        mLastHidden = true;

        return mSurfaceController;
    }

真是深啊盹沈,繼續(xù)看下去

frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java

public WindowSurfaceController(SurfaceSession s,
            String name, int w, int h, int format, int flags, WindowStateAnimator animator) {
        mAnimator = animator;

        mSurfaceW = w;
        mSurfaceH = h;

        title = name;

        // For opaque child windows placed under parent windows,
        // we use a special SurfaceControl which mirrors commands
        // to a black-out layer placed one Z-layer below the surface.
        // This prevents holes to whatever app/wallpaper is underneath.
        //如果是childwindow那么進這個分支,里面最終還是會穿件一個surfaceControl對象
        if (animator.mWin.isChildWindow() &&
                animator.mWin.mSubLayer < 0) {
            mSurfaceControl = new SurfaceControlWithBackground(s,
                    name, w, h, format, flags);
        } else if (DEBUG_SURFACE_TRACE) {
            mSurfaceControl = new SurfaceTrace(
                    s, name, w, h, format, flags);
        } else {
          //關(guān)注這個
            mSurfaceControl = new SurfaceControl(
                    s, name, w, h, format, flags);
        }
    }

frameworks/base/services/core/java/com/android/server/wm/SurfaceControl.java

  public SurfaceControl(SurfaceSession session,
            String name, int w, int h, int format, int flags)
                    throws OutOfResourcesException {
      ...//
        
        mName = name;
        //創(chuàng)建本地surface對象
        mNativeObject = nativeCreate(session, name, w, h, format, flags);
        if (mNativeObject == 0) {
            throw new OutOfResourcesException(
                    "Couldn't allocate SurfaceControl native object");
        }
        mCloseGuard.open("release");
    }

現(xiàn)在終于找到了苗胀。繼續(xù)返回原書中襟诸。

WindowManagerService中創(chuàng)建的本地surface瓦堵,然后將信息拷貝到outSurface中,也就是ViewRootImpl中的Surface

2.1 JNI層

原書中提及了Surface的構(gòu)造歌亲,7.0代碼中Surface的操作應(yīng)該都移到了native中菇用,無參構(gòu)造中什么都沒做,就是默認的構(gòu)造函數(shù)陷揪。

SurfaceSession的構(gòu)造惋鸥,在前面的梳理過程中知道,在調(diào)用WindowManagerService.addWindow()中悍缠,創(chuàng)建了一個SurfaceSession對象卦绣。采用new的方式創(chuàng)建。

frameworks/base/core/java/android/view/SurfaceSession.java

public SurfaceSession() {
  //調(diào)用native函數(shù)
        mNativeClient = nativeCreate();
}

frameworks/base/core/jni/android_view_SurfaceSession.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz) {
    //創(chuàng)建了一個SurfaceComposerClient
    SurfaceComposerClient* client = new SurfaceComposerClient();
    client->incStrong((void*)nativeCreate);
    return reinterpret_cast<jlong>(client);
}

2.1.1 Surface JNI

WindowManagerService.relayoutWindow()過程中飞蚓,創(chuàng)建SurfaceControl對象時滤港,同時創(chuàng)建了一個nativeSurfaceControl對象

frameworks/base/core/jni/android_view_SurfaceContrl.cpp

static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags) {
    ScopedUtfChars name(env, nameStr);
  //先創(chuàng)建了一個SurfaceComposerClient
    sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
  //通過SurfaceComposerClient創(chuàng)建native SurfaceControl
    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);
    return reinterpret_cast<jlong>(surface.get());
}

2.1.2 copyFrom

在創(chuàng)建好nativeSurfaceControl后面,調(diào)用了SurfaceController.getSurface(),SurfaceController里保存了一個JAVA層的SurfaceControl,JAVA層的SurfaceControl持有native層的SurfaceControl.

傳入的的Surface調(diào)用copyFrom()方法趴拧,參數(shù)是SurfaceControl,我們知道溅漾,在client端也就是在viewRootImpl里面創(chuàng)建的Surface對象什么都沒做,要使用draw就必須要關(guān)聯(lián)nativeSurface才能在屏幕上有圖像著榴。

frameworks/core/java/android/view/Surface.java

 public void copyFrom(SurfaceControl other) {
        ..//
        long surfaceControlPtr = other.mNativeObject;
        ...///
         //創(chuàng)建了一個native surface
        long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);

        synchronized (mLock) {
            if (mNativeObject != 0) {
                nativeRelease(mNativeObject);
            }
            //這個函數(shù)中做了Java層也native層關(guān)聯(lián)
            setNativeObjectLocked(newNativeObject);
        }
    }

frameworks/core/java/android/view/Surface.java

private void setNativeObjectLocked(long ptr) {
        if (mNativeObject != ptr) {
            if (mNativeObject == 0 && ptr != 0) {
                mCloseGuard.open("release");
            } else if (mNativeObject != 0 && ptr == 0) {
                mCloseGuard.close();
            }
          //保存本地surface對象
            mNativeObject = ptr;
            mGenerationId += 1;
            if (mHwuiContext != null) {
                mHwuiContext.updateSurface();
            }
        }
    }

通過上面的操作就將本身沒有什么作用的ViewRootImpl中的Surface填充了數(shù)據(jù)添履。就可以使用draw相關(guān)的調(diào)用了。

當然脑又,最后還是通過binder通信交換數(shù)據(jù)暮胧,通過Parcelable接口的readFromParcelwriteFromParcel.

3 Surface和圖畫

通過與WindowManagerService交互,構(gòu)造好了Surface,記下來就進入了draw的流程问麸,在perfromTraversals()代碼走到了performDraw()往衷,最后去到了drawSoftware()

frameworks/base/core/java/android/view/ViewRootImpl.java

private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty) {

        // Draw with software renderer.
        final Canvas canvas;
        try {
            final int left = dirty.left;
            final int top = dirty.top;
            final int right = dirty.right;
            final int bottom = dirty.bottom;
            //得到一個canvas
            canvas = mSurface.lockCanvas(dirty);

            // The dirty rectangle can be modified by Surface.lockCanvas()
            //noinspection ConstantConditions
            if (left != dirty.left || top != dirty.top || right != dirty.right
                    || bottom != dirty.bottom) {
                attachInfo.mIgnoreDirtyState = true;
            }

            // TODO: Do this in native
            canvas.setDensity(mDensity);
        } catch (Surface.OutOfResourcesException e) {
            handleOutOfResourcesException(e);
            return false;
        } catch (IllegalArgumentException e) {
            Log.e(mTag, "Could not lock surface", e);
            // Don't assume this is due to out of memory, it could be
            // something else, and if it is something else then we could
            // kill stuff (or ourself) for no reason.
            mLayoutRequested = true;    // ask wm for a new surface next time.
            return false;
        }

        try {

            // If this bitmap's format includes an alpha channel, we
            // need to clear it before drawing so that the child will
            // properly re-composite its drawing on a transparent
            // background. This automatically respects the clip/dirty region
            // or
            // If we are applying an offset, we need to clear the area
            // where the offset doesn't appear to avoid having garbage
            // left in the blank areas.
            if (!canvas.isOpaque() || yoff != 0 || xoff != 0) {
                canvas.drawColor(0, PorterDuff.Mode.CLEAR);
            }

            dirty.setEmpty();
            mIsAnimating = false;
            mView.mPrivateFlags |= View.PFLAG_DRAWN;

            try {
                canvas.translate(-xoff, -yoff);
                if (mTranslator != null) {
                    mTranslator.translateCanvas(canvas);
                }
                canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);
                attachInfo.mSetIgnoreDirtyState = false;
                //繪制方法調(diào)用
                mView.draw(canvas);

                drawAccessibilityFocusedDrawableIfNeeded(canvas);
            } finally {
                if (!attachInfo.mSetIgnoreDirtyState) {
                    // Only clear the flag if it was not set during the mView.draw() call
                    attachInfo.mIgnoreDirtyState = false;
                }
            }
        } finally {
            try {
                //釋放canvas
                surface.unlockCanvasAndPost(canvas);
            } catch (IllegalArgumentException e) {
                mLayoutRequested = true;    // ask wm for a new surface next time.
                //noinspection ReturnInsideFinallyBlock
                return false;
            }
        }
        return true;
    }

這里就看出來了。軟件方式繪制口叙,就是通過surface lock一塊區(qū)域炼绘,然后調(diào)用Viewdraw方法繪制,最后釋放這個區(qū)域妄田。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俺亮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疟呐,更是在濱河造成了極大的恐慌脚曾,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件启具,死亡現(xiàn)場離奇詭異本讥,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門拷沸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來色查,“玉大人,你說我怎么就攤上這事撞芍⊙砹耍” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵序无,是天一觀的道長验毡。 經(jīng)常有香客問我,道長帝嗡,這世上最難降的妖魔是什么晶通? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮哟玷,結(jié)果婚禮上狮辽,老公的妹妹穿的比我還像新娘。我一直安慰自己碗降,他們只是感情好隘竭,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讼渊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪尊剔。 梳的紋絲不亂的頭發(fā)上爪幻,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音须误,去河邊找鬼挨稿。 笑死,一個胖子當著我的面吹牛京痢,可吹牛的內(nèi)容都是我干的奶甘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼祭椰,長吁一口氣:“原來是場噩夢啊……” “哼臭家!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起方淤,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤钉赁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后携茂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體你踩,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了带膜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吩谦。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膝藕,靈堂內(nèi)的尸體忽然破棺而出式廷,到底是詐尸還是另有隱情,我是刑警寧澤束莫,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布懒棉,位于F島的核電站,受9級特大地震影響览绿,放射性物質(zhì)發(fā)生泄漏策严。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一饿敲、第九天 我趴在偏房一處隱蔽的房頂上張望妻导。 院中可真熱鬧,春花似錦怀各、人聲如沸倔韭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寿酌。三九已至,卻和暖如春硕蛹,著一層夾襖步出監(jiān)牢的瞬間醇疼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工法焰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留秧荆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓埃仪,卻偏偏與公主長得像乙濒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卵蛉,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容