Android Java层UI渲染实现 四 Surface的创建和Vie绘制

在上面几篇中,我们分别看了Context的创建,Window的创建,然后是DecorView的创建,在View的创建那篇中,我们可以看到,在DecorView初始化好了后,会创建subdDecor,然后会用WindowManager调用它的setContentView方法,将创建后了的subDecor传进去,在该方法中,又会它mContentParent调用addView方法,将subDecor添加到mContentParent中,mContentParent就是我们经常提到的Id为id_android_content的布局。这些操作做完后,后面会调用ActivityThread中的handleResumeActivity方法,在该方法中,会调用Activity的onResume方法,然后会将该Activity所关联的DecorView对象关联一个ViewRootImpl对象,是在调用wm.addView(decor, l);的时候,会调用WindowManagerGlobal 的addView方法,在这个方法中创建了一个ViewRootImpl,然后分别将DecorView,VIewRootImpl和WindowMananger.layoutParams保存在数组中,这样就进行了关联,然后调用ViewRootImplsetView方法,将DecorView,WindowMananger.layoutParams传入,将DecorView保存在mAttachInfo中,然后开始第一次布局,然后会调用mWindowSession.addToDisplay增加一个WindowSate对象。

然后我们看看在ViewRootImpl中的第一次布局:

 @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
        //检查当前线程是否是创建ViewRootImpl的线程
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

在上述方法中,会保证当前线程是UI线程,然后调用了scheduleTraversals方法:

 void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            //发送一个屏障消息,让之后的Looper只能处理异步消息
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
			//提醒硬件渲染器一个新的frame要来了
            notifyRendererOfFramePending();
            
            pokeDrawLockIfNeeded();
        }
    }

在上面方法中,调用mChoreographer.postCallback的方法,其中传了一个Runnable类型的参数mTraversalRunnable,最终会调用它的run方法:

final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }

然后调用了doTraversal方法:

void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            //移除屏障,这个屏障的作用是为了保证在有屏障期间
            //只处理用于UI处理的异步消息
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            performTraversals();
            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }

主要调用了performTraversals
这个方法特别特别长,我们就看关键:

View mView;
public final Surface mSurface = new Surface();
boolean mFirst;
boolean mLayoutRequested;
boolean mFullRedrawNeeded;
  
private void performTraversals() {
        
        final View host = mView;
       ... ...
        if (host == null || !mAdded)
            return;
        mIsInTraversal = true;
        mWillDrawSoon = true;
        boolean newSurface = false;
        ... ...
        final int viewVisibility = getHostVisibility();
        ... ...
		
		if (mFirst) {
            mFullRedrawNeeded = true;
            mLayoutRequested = true;
            ... ...
            
        } 		
	  ... ... 		
        boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
        if (layoutRequested) {
            final Resources res = mView.getContext().getResources();
            ... ...
            // Ask host how big it wants to be
            //在里面会调用performMeasure方法
            windowSizeMayChange |= measureHierarchy(host, lp, res,
                    desiredWindowWidth, desiredWindowHeight);
        }
       ... ...



        int relayoutResult = 0;

        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            mForceNextWindowRelayout = false;
           ... ...
            boolean hadSurface = mSurface.isValid();
            try {
                ... ...
                relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);

               ... ...
                if (!hadSurface) {
                    if (mSurface.isValid()) {
                        // If we are creating a new surface, then we need to
                        // completely redraw it.  Also, when we get to the
                        // point of drawing it we will hold off and schedule
                        // a new traversal instead.  This is so we can tell the
                        // window manager about all of the windows being displayed
                        // before actually drawing them, so it can display then
                        // all at once.
                        newSurface = true;
                        mFullRedrawNeeded = true;
                        ... ...
                    }
                }
                ... ...

            } catch (RemoteException e) {
            }
            ... ...

        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
         ... ...

        if (didLayout) {
            performLayout(lp, mWidth, mHeight);
            // By this point all views have been sized and positioned
            ... ...
        }
        ... ...


        mFirst = false;
        ... ...

        boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
        if (!cancelDraw && !newSurface) {

            performDraw();
        } else {
            if (isViewVisible) {
                // Try again
                scheduleTraversals();
            } else if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
                for (int i = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).endChangingAnimations();
                }
                mPendingTransitions.clear();
            }
        }
        mIsInTraversal = false;
    }

在看上面的方法之前,我们先了解一下ViewRootImpl中的这五个成员变量:

  • mView:它的类型为View,但它实际上指向的是一个DecorView对象,用来描述应用程序窗口的顶级视图。
  • mLayoutRequest:是一个布尔变量,用来描述应用程序进程的UI是否需要执行一个UI布局操作
  • mFisrt:一个布尔变量,用来描述UI线程是否第一次处理一个应用程序窗口的UI
  • mFullRedrawNeeded:一个布尔变量,用来描述UI线程是否需要将一个应用程序窗口的全部区域都重新绘制
  • mSurface:它指向一个Java层的Surface对象,用来描述一个应用程序窗口的绘图表面。

当mSurface创建的时候,还没有在C++层关联一个Surface对象,因此,这个时候它秒速的就是一个无效的绘图表面。

然后我们来看上面的方法,在上面的方法中,会先调用measureHierarchy方法,去决定host(DecorView)期望的大小,然后在该方法中,会调用performMeasure
方法,看名字就知道,最终会到View的measure方法中。

接下来,如果是第一次创建,也就是mFirst为true,或者当前正在处理的应用程序窗口的大小发生变量,即windowShouldResize 为true,或者当前正在处理的应用程序窗口的边村发生了变化,或者正在处理的应用程序窗口的可见性发生了变化,或者UI布局参数发生了变量,那么就会调用relayoutWindow方法来请求WindowManagerService重新布局系统中的所有窗口。
WindowManangerService在重新布局系统中的所有窗口的过程中,如果发现窗口还没有一个有效的绘图表面,也就是surface,就会为它创建一个有效的绘图表面:

 private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
        float appScale = mAttachInfo.mApplicationScale;
        boolean restore = false;
        if (params != null && mTranslator != null) {
            restore = true;
            params.backup();
            mTranslator.translateWindowLayout(params);
        }
        if (params != null) {
            if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
            if (mOrigWindowType != params.type) {
                // For compatibility with old apps, don't crash here.
                if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    Slog.w(mTag, "Window type can not be changed after "
                            + "the window is added; ignoring change of " + mView);
                    params.type = mOrigWindowType;
                }
            }
        }
        long frameNumber = -1;
        if (mSurface.isValid()) {
        //得到下一个要退出队列的帧号
            frameNumber = mSurface.getNextFrameNumber();
        }
        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
                mPendingMergedConfiguration, mSurface);
                
      ... ...
        return relayoutResult;
    }

上面代码的核心就是mWindowSession.relayout方法:
这个方法Seesion类中:public class Session extends IWindowSession.Stub implements IBinder.DeathRecipient
也就是说relayout 方法的调用其实是一次IPC调用,它真正的实现是Session类:

 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, Rect outStableInsets, Rect outsets, Rect outBackdropFrame,
            MergedConfiguration mergedConfiguration, Surface outSurface) {
        if (false) Slog.d(TAG_WM, ">>>>>> ENTERED relayout from "
                + Binder.getCallingPid());
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, mRelayoutTag);
        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags,
                outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
                outStableInsets, outsets, outBackdropFrame, mergedConfiguration, outSurface);
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        if (false) Slog.d(TAG_WM, "<<<<<< EXITING relayout to "
                + Binder.getCallingPid());
        return res;
    }

我们可以看到,最终是调用了mService.relayoutWindow,mService是WindowManagerService,在ViewRootImpl创建的时候,会创建Session实例(是通过WindowManagerGlobal,它又通过WindowManagerService)。

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,
                              MergedConfiguration mergedConfiguration, Surface outSurface) {
        int result = 0;
        ... ...
        synchronized(mWindowMap) {
            WindowState win = windowForClientLocked(session, client, false);
            if (win == null) {
                return 0;
            }
            
          ... ...
          
            if (viewVisibility == View.VISIBLE &&
                    (win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
                            || !win.mAppToken.isClientHidden())) {
                Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: viewVisibility_1");
                // We are about to create a surface, but we didn't run a layout yet. So better run
                // a layout now that we already know the right size, as a resize call will make the
                // surface transaction blocking until next vsync and slow us down.
                // TODO: Ideally we'd create the surface after running layout a bit further down,
                // but moving this seems to be too risky at this point in the release.
                if (win.mLayoutSeq == -1) {
                    win.setDisplayLayoutNeeded();
                    mWindowPlacerLocked.performSurfacePlacement(true);
                }
                result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
                        oldVisibility);
                try {
                //创建新的Surface将数据复制给outSurface
                    result = createSurfaceControl(outSurface, result, win, winAnimator);
                } catch (Exception e) {
                    ... ...
                    return 0;
                }
                ... ...
            } 
            
           ... ...
        }
        ... ...
        return result;
    }

在上面的代码中,首先会通过windowForClientLocked方法,得到一个WindowSate对象wim,如果这个对应的WindowSate对象win不存在,那么就说明应用程序进程所请求处理的应用程序窗口不存在,就返回0。
接下来,如果应用程序窗口是可见的,那么就为它创建一个绘图表面:

 private int createSurfaceControl(Surface outSurface, int result, WindowState win,
            WindowStateAnimator winAnimator) {
        if (!win.mHasSurface) {
            result |= RELAYOUT_RES_SURFACE_CHANGED;
        }
        WindowSurfaceController surfaceController;
        try {
            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
            //创建WindowSurfaceController
            surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
        } finally {
            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        }
        if (surfaceController != null) {
        //
            surfaceController.getSurface(outSurface);
            if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  OUT SURFACE " + outSurface + ": copied");
        } else {
            // For some reason there isn't a surface.  Clear the
            // caller's object so they see the same state.
            Slog.w(TAG_WM, "Failed to create surface control for " + win);
            outSurface.release();
        }
        return result;
    }
 void getSurface(Surface outSurface) {
 //将得到的内容数据拷贝到outerSurface中
        outSurface.copyFrom(mSurfaceControl);
    }

在WindowSufaceControl创建的时候,会创建SufaceControl,然后我们通过WindowSufaceControl的实例将新的Surface的数据复制给outSuface。
SurfaceControl在创建的时候,会调用一个Native方法nativeCreate,返回值复制给mNativeObject

 long mNativeObject; // package visibility only for Surface.java access

这个mNativeObject是native层的Surface,在创建native层的SurfaceControl的时候,会创建native层的Surface,将其保存在SurfaceControl中。

sp<Surface> SurfaceControl::createSurface() const
{
    Mutex::Autolock _l(mLock);
    return generateSurfaceLocked();
}


sp<Surface> SurfaceControl::generateSurfaceLocked() const
{
    // This surface is always consumed by SurfaceFlinger, so the
    // producerControlledByApp value doesn't matter; using false.
    mSurfaceData = new Surface(mGraphicBufferProducer, false);
    return mSurfaceData;
}

这样,Surface的创建就完成了。
我们可以总结一下:
在DecorView和ViewRootImpl绑定完了,会调用ViewRootImpl的setView方法,然后就会开启我们的第一次布局。在第一次的布局时候,首先会确定DecorView的大小,然后调用relayoutWindow方法去创建一个有效的视图,在这个方法中,最终会调用WindowManagerSerivce的relayoutWindow方法,在relayoutWindow方法中,会调用createSurfaceControl方法,在这个方法中,先创建Java层的SurfaceControl,然后在创建Java层的SurfaceControl的过程中,会创建Native层SurfaceControl,在创建Native层的SurfaceControl的过程中,会创建Native层的Surface,然后将这个Surface返回,赋值给Java层的SurfaceControl中的mNativeObject中,在Java层测SurfaceControl创建好了后,就调用它的getSurface方法,在ViewRootImpl中,有一个直接建立好了,但是无效的Java层的Surface,然后调用Java层的Surface的copyFrom方法,将Native层的Surface中的数据复制给Java层的Surface,这样Java层的Surface就有效了。

回到ViewRootImpl中的performTraversals方法
会调用创建完Surface后,会调用performLayout方法:

 private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;
        final View host = mView;
        if (host == null) {
            return;
        }
       ... ...
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
            mInLayout = false;
           
                 ... ...
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
        mInLayout = false;
    }

在该方法中,最终会调用DeocrView的layout方法。

performLayout方法调用完后,会调用performDraw方法:

private void performDraw() {
        if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
            return;
        } else if (mView == null) {
            return;
        }
        final boolean fullRedrawNeeded = mFullRedrawNeeded;
        mFullRedrawNeeded = false;
        mIsDrawing = true;
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "draw");
        try {
            draw(fullRedrawNeeded);
        } finally {
            mIsDrawing = false;
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
       
        ... ...
    }

在上面的方法中,最终会调用draw(fullRedrawNeeded)方法:

//ViewRootImpl.java
 private void draw(boolean fullRedrawNeeded) {
        Surface surface = mSurface;
        if (!surface.isValid()) {
            return;
        }
      ... ...
        mAttachInfo.mDrawingTime =
                mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
        if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
            if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
                ... ...
                //使用硬件渲染,比如CPU
                mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
            } else {
            ... ... 
            //使用软件渲染
                if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                    return;
                }
            }
        }
        if (animating) {
            mFullRedrawNeeded = true;
            scheduleTraversals();
        }
    }

可以看到,最后会调用drawSoftware方法:

 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 = mSurface.lockCanvas(dirty);
            ... ...
        } catch (Surface.OutOfResourcesException e) {
            handleOutOfResourcesException(e);
            return false;
        } catch (IllegalArgumentException e) {
          。。。 。。。
            mLayoutRequested = true;    // ask wm for a new surface next time.
            return false;
        }
        try {
            ... ...
            try {
               ... ...
                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 {
            //将它交给SurfaceFlinger服务来渲染
                surface.unlockCanvasAndPost(canvas);
            } catch (IllegalArgumentException e) {
                Log.e(mTag, "Could not unlock surface", e);
                mLayoutRequested = true;    // ask wm for a new surface next time.
                //noinspection ReturnInsideFinallyBlock
                return false;
            }
            if (LOCAL_LOGV) {
                Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost");
            }
        }
        return true;
    }

首先调用了mSurface.lockCanvas(dirty)来创建一块画布:

//SurfaceView.java
 public Canvas lockCanvas(Rect inOutDirty)
            throws Surface.OutOfResourcesException, IllegalArgumentException {
        synchronized (mLock) {
            checkNotReleasedLocked();
            if (mLockedObject != 0) {
                // Ideally, nativeLockCanvas() would throw in this situation and prevent the
                // double-lock, but that won't happen if mNativeObject was updated.  We can't
                // abandon the old mLockedObject because it might still be in use, so instead
                // we just refuse to re-lock the Surface.
                throw new IllegalArgumentException("Surface was already locked");
            }
            mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
            return mCanvas;
        }
    }

可以看到它调用了一个native方法,它是由C++层的nativeLockCanvas来实现的:

//android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
        //得到与Java层Surface对应的C++层的Suface
    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
    if (!isSurfaceValid(surface)) {
        doThrowIAE(env);
        return 0;
    }
    //dirtyRect指向的是一个Java层Rect对象,它描述的是应用程序窗口即将要重绘的一块矩形区域;
    //将它转换成一个C++层次的Rect对象dirtyRectPtr 来表示
    Rect dirtyRect(Rect::EMPTY_RECT);
    Rect* dirtyRectPtr = NULL;
    if (dirtyRectObj) {
        dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
        dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
        dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
        dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
        dirtyRectPtr = &dirtyRect;
    }
    ANativeWindow_Buffer outBuffer;
    //获取图形缓冲区
    status_t err = surface->lock(&outBuffer, dirtyRectPtr);
    if (err < 0) {
        const char* const exception = (err == NO_MEMORY) ?
                OutOfResourcesException :
                "java/lang/IllegalArgumentException";
        jniThrowException(env, exception, NULL);
        return 0;
    }
    //Java层的应用程序窗口是通过Skia图形库在绘制UI的
    SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
                                         convertPixelFormat(outBuffer.format),
                                         outBuffer.format == PIXEL_FORMAT_RGBX_8888
                                                 ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
                                         GraphicsJNI::defaultColorSpace());
    SkBitmap bitmap;
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    bitmap.setInfo(info, bpr);
    if (outBuffer.width > 0 && outBuffer.height > 0) {
        bitmap.setPixels(outBuffer.bits);
    } else {
        // be safe with an empty bitmap.
        bitmap.setPixels(NULL);
    }
    //得到Skia图形库所需要的画布,并将Jjava层的Canvas中的成员变量mNativeCanvas赋值
    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
    nativeCanvas->setBitmap(bitmap);
    if (dirtyRectPtr) {
    //设置裁剪区域
        nativeCanvas->clipRect(dirtyRect.left, dirtyRect.top,
                dirtyRect.right, dirtyRect.bottom, SkClipOp::kIntersect);
    }
    if (dirtyRectObj) {
    
        env->SetIntField(dirtyRectObj, gRectClassInfo.left,   dirtyRect.left);
        env->SetIntField(dirtyRectObj, gRectClassInfo.top,    dirtyRect.top);
        env->SetIntField(dirtyRectObj, gRectClassInfo.right,  dirtyRect.right);
        env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
    }
    // Create another reference to the surface and return it.  This reference
    // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
    // because the latter could be replaced while the surface is locked.
    //创建Surface的另一个引用来替代mNativeObject,mNative是在前面创建的Surface
    sp<Surface> lockedSurface(surface);
    lockedSurface->incStrong(&sRefBaseOwner);
    return (jlong) lockedSurface.get();
}

然后我们来看看是怎么获取图形缓冲区的:

//Surface.cpp
status_t Surface::lock(SurfaceInfo* other, Region* inOutDirtyRegion) {
    ANativeWindow_Buffer outBuffer;
    ARect temp;
    ARect* inOutDirtyBounds = NULL;
    if (inOutDirtyRegion) {
        temp = inOutDirtyRegion->getBounds();
        inOutDirtyBounds = &temp;
    }
    //新的图形缓冲区的信息保存在outBuffer中
    status_t err = SurfaceTextureClient::lock(&outBuffer, inOutDirtyBounds);
   ... ... 
    return err;
}

在上面代码中,我们可以看到是通过SurfaceTextureClient::lock方法来获取图形缓冲区的:

status_t SurfaceTextureClient::lock(
        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
    if (mLockedBuffer != 0) {
        ALOGE("Surface::lock failed, already locked");
        return INVALID_OPERATION;
    }
   ... ...
    ANativeWindowBuffer* out;
    //获取一个新的图形缓冲区
    status_t err = dequeueBuffer(&out);
    ALOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
    if (err == NO_ERROR) {
    	//将out封装为一个GraphicBuffer对象,这样就可以通过它来访问图形缓冲区了
        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
        err = lockBuffer(backBuffer.get());
       ... ...
        if (err == NO_ERROR) {
            const Rect bounds(backBuffer->width, backBuffer->height);
            Region newDirtyRegion;
			 if (inOutDirtyBounds) {
                newDirtyRegion.set(static_cast<Rect const&>(*inOutDirtyBounds));
                newDirtyRegion.andSelf(bounds);
            } else {
                newDirtyRegion.set(bounds);
            }
            // figure out if we can copy the frontbuffer back
            const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
            //判断是否能将前端缓冲区的内容拷贝到后端缓冲区
            const bool canCopyBack = (frontBuffer != 0 &&
                    backBuffer->width  == frontBuffer->width &&
                    backBuffer->height == frontBuffer->height &&
                    backBuffer->format == frontBuffer->format);
            if (canCopyBack) {
                // copy the area that is invalid and not repainted this round
                const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
                if (!copyback.isEmpty())
                    copyBlt(backBuffer, frontBuffer, copyback);
            } else {
                // if we can't copy-back anything, modify the user's dirty
                // region to make sure they redraw the whole buffer
                newDirtyRegion.set(bounds);
                mDirtyRegion.clear();
                Mutex::Autolock lock(mMutex);
                for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
                    mSlots[i].dirtyRegion.clear();
                }
            }
           ... ...
            void* vaddr;
            //重绘脏缓冲区newDirtyRegion
            //并得到了后端缓冲区的地址vaddr
            status_t res = backBuffer->lock(
                    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                    newDirtyRegion.bounds(), &vaddr);
            ALOGW_IF(res, "failed locking buffer (handle = %p)",
                    backBuffer->handle);
             //保存
            mLockedBuffer = backBuffer;
            outBuffer->width  = backBuffer->width;
            outBuffer->height = backBuffer->height;
            outBuffer->stride = backBuffer->stride;
            outBuffer->format = backBuffer->format;
            outBuffer->bits   = vaddr;
        }
    }
    return err;
}

Surface类是一个被称为双缓冲的技术来渲染应用程序窗口的UI的,这种双缓冲技术需要两个图形缓冲区,其中一个为前端缓冲器,另外一个为后端缓冲区。前缓冲区是正在渲染的图形缓冲区,而后端缓冲区是接下来要渲染的图像缓冲区,它们分别为Surface类的成员变量mPostedBuffer和mLockedBuffer所指向的两个GraphicBuffer对象来描述。

可以看到,最终会调用DecorView的draw(Canvas)方法。

接下来我们就看看DecorView的三大绘制过程:
首先DecorView是继承自FrameLayout的,
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks
所以它的是ViewGroup

首先是measure方法,其实这个measure方法,调用的是View.measure,最终会调用onMeasure,这个onMeasure方法在DecorView中重写了,遇到在onMeasure方法的中,会根据widthMode和heightMode来确定DecorView的大小,并创建新的WidthMeasureSpec和HeightMeasureSpec,然后会调用父类的onMeasure方法,DecorView的父类是FrameLayout,因此会调用FrameLayout的onMeasure方法。在该方法中,会根据所有的子View和Padding计算出maxWidth和maxHeight,创建新的widthMeasureSpec和heightMeasureSpec,然后将保存下来,然后循环遍历子View,根据
widthMeasureSpec和heightMeasureSpec以及Padding以及Margin计算出新的childWidthMeasureSpec和childHeightMeasureSpec,然后调用子view的measure方法,重新确定子view的大小。

然后是layout方法:跟上面一样,最终会调用onLayout方法,DeocrView重写了onLayout方法,然后在onLayout方法中,会直接先调用父类的onLayout方法,在父类的onLayout方法,直接调用layoutChildren方法,在该方法中,先确定parentLeft,parentRight,parentTop和parentBottom,然后遍历子View,根据gravity和Marigin确定childLeft,childRight,childTop和childBottom,然后调用child.layout方法确定子View的位置。

然后是draw方法,DecorView重写了draw方法:

 @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (mMenuBackground != null) {
            mMenuBackground.draw(canvas);
        }
    }

可以看到,它直接调用了父类的draw方法,但是FrameLayout中没有实现draw方法,它的父类ViewGroup也没有,因此会到View的draw方法,它主要分为6个步骤

  1. Draw the background
  2. If necessary, save the canvas’ layers to prepare for fading
  3. Draw view’s content
  4. Draw children
  5. If necessary, draw the fading edges and restore layers
  6. Draw decorations (scrollbars for instance)

第一步,画背景:

 if (!dirtyOpaque) {
            drawBackground(canvas);
        }

通常情况下,会跳过第2步和第五步,

第三步:绘制content

 // Step 3, draw the content
            if (!dirtyOpaque) onDraw(canvas);

DecorView中重写了onDraw方法,

@Override
 private final BackgroundFallback mBackgroundFallback = new BackgroundFallback();
    public void onDraw(Canvas c) {
        super.onDraw(c);
        mBackgroundFallback.draw(this, mContentRoot, c, mWindow.mContentParent,
                mStatusColorViewState.view, mNavigationColorViewState.view);
    }

但是在这个方法中,它又直接调用父类的onDraw方法,FrameLayout没有重写它,ViewGroup中也没有重写它,View中是一个空实现,似乎这个没有做什么,然后会调用mBackgroundFallback.draw

BackgroundFallback :
Helper class for drawing a fallback background in framework decor layouts.

去画一个稳定的background。

第四步,画child:

// Step 4, draw the children
        dispatchDraw(canvas);

在ViewGroup中重写了它,在这个方法中,会调用child.draw方法来进行子View的绘制

第六步,绘制装饰(像滚动条之类的)

// Step 6, draw decorations (foreground, scrollbars)
        onDrawForeground(canvas);

在走完DecorView的三大绘制流程后,我们回到ViewRootImpl的drawSoftware方法,在DecorView绘制完了后,会调用surface.unlockCanvasAndPost(canvas);方法,将刚才画好的东西,交给SurfaceFlinger服务来渲染:

static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj) {
    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
    if (!isSurfaceValid(surface)) {
        return;
    }
    // detach the canvas from the surface
    Canvas* nativeCanvas = GraphicsJNI::getNativeCanvas(env, canvasObj);
    nativeCanvas->setBitmap(SkBitmap());
    // unlock surface
    status_t err = surface->unlockAndPost();
    if (err < 0) {
        doThrowIAE(env);
    }
}

可以看到上面主要是通过调用unlockAndPost方法:

//Surface.cpp
status_t Surface::unlockAndPost() {
    return SurfaceTextureClient::unlockAndPost();
}

status_t SurfaceTextureClient::unlockAndPost()
{
    if (mLockedBuffer == 0) {
        ALOGE("Surface::unlockAndPost failed, no locked buffer");
        return INVALID_OPERATION;
    }
    //解锁,在前面的时候,将这个图形缓冲区锁定了,主要是为了获得这个图形缓冲区的地址。
    status_t err = mLockedBuffer->unlock();
    ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
    err = queueBuffer(mLockedBuffer.get());
    ALOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
            mLockedBuffer->handle, strerror(-err));
    mPostedBuffer = mLockedBuffer;
    mLockedBuffer = 0;
    return err;
}

我们知道应用程序当前正在使用的图形缓冲区保存在mLockedBuffer中,在上面方法中通过调用queueBuffer方法,将它交给SurfaceFlinger服务来渲染,queueBuffer函数的作用是向应用程序窗口的待渲染图形缓冲区队列中添加一个一个图形缓冲区,然后再请求SurfaceFlinger服务来渲染这个图形缓冲区。

在请求SurfaceFlinger渲染mLockedBuffer所指向的图形缓冲区后,然后将mLockedBuffer的值赋值给mPostedBuffer ,表示这个图形缓冲器已经变成是正在渲染的图形缓冲区了,也就是前端缓冲区。

总结:

  1. 渲染Android应用程序窗口UI需要经过三步曲:测量,布局,绘制
  2. Android应用程序窗口UI首先是绘制在一块画布上,实际上是绘制在这块画面里面的一个图形缓冲区中,这个图形缓冲区最终会被交给SurfaceFlinger服务,而SurfaceFlinger服务再使用OpenGL图形库API来将这个图形缓冲区渲染到硬件帧缓冲区。

Android Java层UI渲染实现 四 Surface的创建和Vie绘制_第1张图片

参考:https://www.kancloud.cn/alex_wsc/androids/473775

你可能感兴趣的:(android)