前言

关于操作体系而言,图形显现部分是非常重要的一个模块,用来承载用户交互与内容展现,因而本文其实无法对Android的显现体系做非常翔实的剖析,因为如果那样的话或许需求一个系列,而且关于一般开发者而言并没有这样的必要,因而本文首要从View的显现作为切入点来展开显现体系的基本原理以及它的运行机制,力求浅显易懂,协助咱们对它有比较深入的了解。

本文剖析依赖的Android源码版别首要是Android13(或以上)

关于View的显现

  • 关于Android开发者而言,咱们都接触过Android的View的开发,那么一个View是怎么制作并显现到设备的屏幕上呢?

    • 当然是ondraw办法中运用canvas进行制作的,然后把制作出的像素数据传递到显现体系中
  • 那么canvas是什么?从哪里来的呢?

    • canvas咱们称之为画布,经过canvas进行制作操作之后,终究制作的像素数据会烘托到屏幕上;而canvas则是经过Surface调用lockCanvas(rect)锁住制作区域之后取得的。在咱们制作完结之后会开释掉。
  • 那么什么是Surface?

    • 现在,咱们能够说进入正题了,能够了解Surface,关于咱们了解Android呃显现体系非常有协助,因为它是显现体系中的一个关键部分,而且是开发者或许接触到的那个部分。

    • Surface称作外表,但实际是聚集该window所发生的烘托数据,然后一致传递到显现模块中。stackoverflow中有一个关于surface,canvas的概念解说对surface的描绘也很贴切

Android显现体系的基本原理(一)

Android显现体系

咱们先对Android显现体系做一个结构归纳:那便是显现体系是一个多对一的出产消费模型架构的体系,数据出产端是View,camera,Opengl ES等。消费端一般是由surfaceflinger掌控并负责把烘托数据合成为一个帧,并发送到显现控制器(屏幕)。

Android显现体系的基本原理(一)

或许这张图愈加朴实

Android显现体系的基本原理(一)

出产者一般包含:

  • Android View,经过canvas制作发生图画
  • media player 解码视频数据播映
  • Camera 摄像头发生图画
  • Opengl ES

而顾客首要是SurfaceFlinger。

出产者和顾客之间存在一个缓冲行列,用于发送数据和消费数据。可是关于出产者而言,其实并不直接与缓冲行列接触,而是经过Surface,所有的出产者都是经过Surface供给的接口输入烘托数据。或许咱们能够简略的了解,关于数据出产方而言,Surface是烘托数据的聚集地。

接下来咱们以Android view的制作体系为例来看看显现体系中烘托数据是怎么发生而且输入到缓冲行列中的。

烘托数据怎么发生

关于Android View的制作体系,其实指的便是在View Tree中经过onDraw回调,运用canvas逐个进行制作的体系。

@Override
protected void onDraw(Canvas canvas) {
    // Draw the background for this view
    super.onDraw(canvas);
    ...
}

因为前文现已问到了canvas的问题,确定是由Surface发生的,那么接下来问题就转移到Surface身上了,想要弄清楚烘托数据怎么发生,就要先弄懂Surface的创立和运用细节,咱们从代码层面来解说下为什么说Surface是一个重要的结构。

surface的创立进程

上层视角

与Surface随同的类叫SurfaceController,这是要对Surface进行办理的一个类,咱们能够在ViewRootImpl中看到这两个类的目标。而Surface的创立依赖于SurfaceController的创立,因而咱们不得不先剖析SurfaceController的创立进程。

先依次检查Surface和SurfaceController的类的首要结构

public class Surface  implements Parcelable{
...
// 指向cpp层的surface目标
long mNativeObject; // package scope only for SurfaceControl access
...
public void createFrom(SurfaceControl other) {
    ...
    long surfaceControlPtr = other.mNativeObject;
    ...
    long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
    ...
    synchronized (mLock) {
        if (mNativeObject != 0) {
            nativeRelease(mNativeObject);
        }
        setNativeObjectLocked(newNativeObject);
    }
}
// 经过SurfaceControl仿制数据
public void copyFrom(SurfaceControl other) {
    ...
    long surfaceControlPtr = other.mNativeObject;
    ...
    long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);
    updateNativeObject(newNativeObject);
}
}

Surface在Java层的结构中有一个mNativeObject特点,顾名思义便是指cpp层的surface目标,SurfaceController也是类似的状况。

// Handle to an on-screen Surface managed by the system compositor
// 首要用于办理Surface,命名方式也能看出
public final class SurfaceControl implements Parcelable {
public long mNativeObject; // 也有一个cpp层对应的类
// 能够一起创立native层的目标的结构函数
private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
        SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
        String callsite)
                throws OutOfResourcesException, IllegalArgumentException {
     ...
    mName = name;
    mWidth = w;
    mHeight = h;
    mLocalOwnerView = localOwnerView;
    Parcel metaParcel = Parcel.obtain();
    try {
        ...
        // 创立cpp层的SurfaceControl
        mNativeObject = nativeCreate(session, name, w, h, format, flags,
                parent != null ? parent.mNativeObject : 0, metaParcel);
    } finally {
        metaParcel.recycle();
    }
    ...
    mNativeHandle = nativeGetHandle(mNativeObject);
    mCloseGuard.openWithCallSite("release", callsite);
}
/**
 * 仿制SurfaceControl
 */
public void copyFrom(@NonNull SurfaceControl other, String callsite) {
    mName = other.mName;
    mWidth = other.mWidth;
    mHeight = other.mHeight;
    mLocalOwnerView = other.mLocalOwnerView;
    assignNativeObject(nativeCopyFromSurfaceControl(other.mNativeObject), callsite);
}
}

咱们能够在ViewRootImpl中找到mSurface,mSurfaceControl,它们都是是运用默许结构办法创立的目标,像这样触及底层能力的类,一般是有一个cpp层的目标来完结实在的功用和交互的,因而实际上默许结构出来的目标还仅仅一个壳子,因而咱们需求看它的cpp层是何时被创立出来的。

SurfaceControl的创立

// viewrootimpl.java
public final Surface mSurface = new Surface();
private final SurfaceControl mSurfaceControl = new SurfaceControl();
private void performTraversals() {
    ...
    boolean hadSurface = mSurface.isValid();
    ...
    // relayoutWindow终究经过IWindowSession接口走了一个跨进程调用到WMS中
    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
    ...
    surfaceCreated = !hadSurface && mSurface.isValid();
    ...
}
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        boolean insetsPending) throws RemoteException {
    ...
    //跨进程调用,传入mSurfaceControl
    relayoutResult = mWindowSession.relayout(mWindow, params,
            requestedWidth, requestedHeight, viewVisibility,..., mSurfaceControl,...);
    ...
    // 判别mSurfaceControl是否合法
    if (mSurfaceControl.isValid()) {
        if (!useBLAST()) {
            mSurface.copyFrom(mSurfaceControl);
        } else {
            updateBlastSurfaceIfNeeded();
        }
    ...
    ...
    }
}

relayoutWindow终究触发了跨进程调用到WMS.relayoutWindow中。然后进一步骤用了createSurfaceControl办法,创立了一个SurfaceControl

// WindowManagerService.java
// outSurfaceControl 便是ViewRootImpl中传入的SurfaceControl空壳目标
private int createSurfaceControl(SurfaceControl outSurfaceControl, int result,
        WindowState win, WindowStateAnimator winAnimator) {
    ...
    WindowSurfaceController surfaceController;
    ...
        //1, 创立一个WindowSurfaceController
        surfaceController = winAnimator.createSurfaceLocked();
    ...
    if (surfaceController != null) {
         //2, 新创立的surfaceController仿制到外部传入的outSurfaceController
        surfaceController.getSurfaceControl(outSurfaceControl);
    }
    ...
    return result;
}
/*************************************************/
// WindowStateAnimator.java
WindowSurfaceController createSurfaceLocked() {
    ...
    // 创立一个SurfaceController,运用的是前面介绍的能够创立native目标的结构函数
    mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), format,
            flags, this, attrs.type);
    w.setHasSurface(true); // 此刻WindowStateAnimator中就有了surfaceControl(Java层和cpp层都有)
    ...
}

总代码上看,完结逻辑是:WindowStateAnimator先经过结构办法创立一个的SurfaceControl目标,然后经过仿制,把该目标仿制到outSurfaceControl中(也便是ViewRootImpl中mSurfaceControl)。

咱们先看创立SurfaceControl的结构函数所调用的native函数的详情

//frameworks/base/core/jni/android_view_SurfaceControl.cpp
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);
    sp<SurfaceComposerClient> client;
    if (sessionObj != NULL) {
    //获取SurfaceSession(SurfaceFLinger的衔接类,在native层的对应类便是SurfaceComposerClient)
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        client = SurfaceComposerClient::getDefault();
    }
    ...
    sp<SurfaceControl> surface;
    ...
    // 创立surfacecontrol
    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,flags, parentHandle, std::move(metadata));
    ...
    return reinterpret_cast<jlong>(surface.get());
}
// frameworks/native/libs/gui/SurfaceComposerClient.cpp
status_t SurfaceComposerClient::createSurfaceChecked(...) {
  status_t err = mStatus;
  // 调用到远端SurfaceFlinger,同步创立一个Surface
   binder::Status status = mClient->createSurface(std::string(name.c_str()), flags,parentHandle,std::move(metadata),&result);
    if (mStatus == NO_ERROR) {
        ...
        if (err == NO_ERROR) {
            // new一个cpp层的SurfaceControl
            *outSurface = new SurfaceControl(this, result.handle, result.layerId,
                                             toString(result.layerName), w, h, format,
                                             result.transformHint, flags);
        }
    }
    return err;
}
//frameworks/native/services/surfaceflinger/Client.cpp
// 调用到surfaceflinger,创立surface
binder::Status Client::createSurface(const std::string& name, int32_t flags,
                                     const sp<IBinder>& parent, const gui::LayerMetadata& metadata,
                                     gui::CreateSurfaceResult* outResult) {
    // We rely on createLayer to check permissions.
    sp<IBinder> handle;
    LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this), name.c_str(),
                           static_cast<uint32_t>(flags), std::move(metadata));
    args.parentHandle = parent;
    // flinger创立layer(能够视作Surface)
    const status_t status = mFlinger->createLayer(args, *outResult);
    return binderStatusFromStatusT(status);
}

native层的完结逻辑首要是:经过SurfaceComposerClient这个surfaceflinger衔接类,先在远端的surfaceflinger创立一个Surface(实际是Layer),然后再创立一个SurfaceControl目标返回,此刻 SurfaceControl是一个完好目标(既有Java层目标也有cpp层目标)。

接着回到Java层,检查第二步getSurfaceControl的仿制逻辑:


// 仿制给ViewRootImpl中的mSurfaceControl
// WindowSurfaceController.java  
void getSurfaceControl(SurfaceControl outSurfaceControl) {
    // 终究从Java层的copyFrom调用到 cpp层的nativeCopyFromSurfaceControl
   outSurfaceControl.copyFrom(mSurfaceControl,"WindowSurfaceController.getSurfaceControl");
}
/*************************************************/
//frameworks/base/core/jni/android_view_SurfaceControl.cpp
static jlong nativeCopyFromSurfaceControl(JNIEnv* env, jclass clazz, jlong surfaceControlNativeObj) {
    sp<SurfaceControl> surface(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    if (surface == nullptr) {
        return 0;
    }
    // 利用传入的cpp层的surfacecontrol目标创立新的SurfaceControl
    sp<SurfaceControl> newSurface = new SurfaceControl(surface);
    // 调用nativeCreate办法
    newSurface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(newSurface.get());
}

创立了SurfaceControl之后,接着调用getSurfaceControl进行仿制,仿制时会调用nativeCopyFromSurfaceControl这个native办法, 把cpp层的SurfaceControl也一并仿制过来。

WindowStateAnimator中创立了一个完好的SurfaceControl,然后也把自己仿制给ViewRootImpl的SurfaceControl中(无论是Java层仍是native层),至此SurfaceControl的创立进程结束了。

Surface的创立进程

接下来回到ViewRootImpl中,后边的代码履行如下:

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
        boolean insetsPending) throws RemoteException {
    ...
    //跨进程调用,传入mSurfaceControl
    relayoutResult = mWindowSession.relayout(mWindow, params,
            requestedWidth, requestedHeight, viewVisibility,..., mSurfaceControl,...);
    ...
    // 判别mSurfaceControl是否合法
    if (mSurfaceControl.isValid()) {
        if (!useBLAST()) {
            mSurface.copyFrom(mSurfaceControl);
        } else {
            updateBlastSurfaceIfNeeded();
        }
    ...
    ...
    }
}

正常状况下,mSurfaceControl是合法的,接下来无论是useBLAST是否为真,都能够创立Surface。

第一种办法

第一种状况调用copyFrom:

// Surface.java
@UnsupportedAppUsage
public void copyFrom(SurfaceControl other) {
    ...
    long surfaceControlPtr = other.mNativeObject;
    ...
    // 分别传入Surface的native目标句柄和SurfaceControl native目标句柄
    long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);
    // 更新Java层的信息,mNativeObject的句柄
    updateNativeObject(newNativeObject);
}

仿制办法比较简略,便是从SurfaceControl获取一个Surface,然后更新一下自身。咱们重点看一下nativeGetFromSurfaceControl这个native办法的履行逻辑是怎样的。

// frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeGetFromSurfaceControl(JNIEnv* env, jclass clazz,
        jlong nativeObject,
        jlong surfaceControlNativeObj) {
    Surface* self(reinterpret_cast<Surface *>(nativeObject));
    sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
    ...
    ...
    sp<Surface> surface(ctrl->getSurface()); // 调用SurfaceControl.getSurface函数
    ...
    return reinterpret_cast<jlong>(surface.get());
}
/******************************文件分割线******************************************/
// frameworks/native/libs/gui/SurfaceControl.cpp
sp<Surface> SurfaceControl::getSurface()
{
    Mutex::Autolock _l(mLock);
    // 如果是第一次进入,则需求创立Surface,然后被保存在SurfaceControl中
    if (mSurfaceData == nullptr) {
        return generateSurfaceLocked(); // 生成Surface
    }
    // 后边再获取则直接返回
    return mSurfaceData;
}
sp<Surface> SurfaceControl::generateSurfaceLocked()
{
    uint32_t ignore;
    auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
                                 ISurfaceComposerClient::eOpaque);
    mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
                                       flags, mHandle, {}, &ignore);
    //1,创立BLASTBufferQueue,内部同步会创立IGraphicBufferProducer和 IGraphicBufferConsumer
    mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);
    // 2,调用BLASTBufferQueue->getSurface(...)  获取SUrface
    mSurfaceData = mBbq->getSurface(true);
    return mSurfaceData;
}
/******************************文件分割线******************************************/
// frameworks/native/libs/gui/BLASTBufferQueue.cpp
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::lock_guard _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
    // 取得一个Handle,可与SurfaceFlinger通信
        scHandle = mSurfaceControl->getHandle();
    }
    //sp<IGraphicBufferProducer> mProducer 是BLASTBufferQueue内部的一个特点,用来操作出产者数据入队出队
    return new BBQSurface(mProducer, true, scHandle, this);
}

咱们发现创立cpp层面的Surface之前,会先创立一个行列BLASTBufferQueue,而行列内部有出产者操作类(IGraphicBufferProducer)和顾客操作类BufferQueueConsumer,正应了咱们说到的出产消费模型的说法。

创立BBQSurface时,咱们发现IGraphicBufferProducer类型的producer作为结构参数被传入了,这也印证了咱们说的,Surface是出产者烘托数据聚集地。

第二种办法

/******************************文件分割线******************************************/
// ViewRootImpl.java
void updateBlastSurfaceIfNeeded() {
    //此刻mSurfaceControl是合法的
    if (!mSurfaceControl.isValid()) {
        return;
    }
    //第一次进入时mBlastBufferQueue应该是null
    if (mBlastBufferQueue != null && mBlastBufferQueue.isSameSurfaceControl(mSurfaceControl)) {
        mBlastBufferQueue.update(mSurfaceControl,
            mSurfaceSize.x, mSurfaceSize.y,
            mWindowAttributes.format);
        return;
    }
   ...
   ...
   //创立BLASTBufferQueue,这个明显便是第一种创立办法中native层的BLASTBufferQueue的Java层对应类
    // 结构办法终究会创立native层的BLASTBufferQueue
    mBlastBufferQueue = new BLASTBufferQueue(mTag, mSurfaceControl,
            mSurfaceSize.x, mSurfaceSize.y, mWindowAttributes.format);
    mBlastBufferQueue.setTransactionHangCallback(sTransactionHangCallback);
    // 经过BlastBufferQueue创立Surface
    Surface blastSurface = mBlastBufferQueue.createSurface();
    // 更新到surface内部
    mSurface.transferFrom(blastSurface);
}

/******************************文件分割线******************************************/
// frameworks/base/graphics/java/android/graphics/BLASTBufferQueue.java
public final class BLASTBufferQueue {
    // Note: This field is accessed by native code.
    public long mNativeObject; // BLASTBufferQueue native层有对应的目标

    public BLASTBufferQueue(String name, SurfaceControl sc, int width, int height,
            @PixelFormat.Format int format) {
        this(name, true /* updateDestinationFrame */);
        update(sc, width, height, format);
    }

    public BLASTBufferQueue(String name, boolean updateDestinationFrame) {
        // 创立cpp层对应的BLASTBufferQueue
        mNativeObject = nativeCreate(name, updateDestinationFrame);
    }
    ...
    ...
    // nativeGetSurface终究调用到native层的
    public Surface createSurface() {
        return nativeGetSurface(mNativeObject, false /* includeSurfaceControlHandle */);
    }
}

/******************************文件分割线******************************************/
//frameworks/base/core/jni/android_graphics_BLASTBufferQueue.cpp
static jobject nativeGetSurface(JNIEnv* env, jclass clazz, jlong ptr,
                                jboolean includeSurfaceControlHandle) {
    sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
    // 终究仍是调用了BLASTBufferQueue->getSurface(...)
   return android_view_Surface_createFromSurface(env, queue->getSurface(includeSurfaceControlHandle));
}

从上面的截取的代码能够看到即使是先创立Java层的BlastBufferQueue,终究也仍是殊途同归,经过native层的BlastBufferQueue来创立一个Surface。

默许状况下,代码应该是第二种办法创立Surface。

创立阶段出现很多的类,咱们用一个示意图来总结一下他们之间的联系:

Android显现体系的基本原理(一)

android View的制作进程

剖析完了Surface的创立进程之后,咱们再次回到View的制作进程,从View的显现进程中了解Surface的作用。

咱们都知道View的制作需求canvas,而canvas则是经过ViewRootImpl内部的Surface来获取。

//ViewRootImpl.java
// 假定运用cpu制作而不是硬件加速
private boolean drawSoftware(Surface surface,...) {      
    ...
    //获取canvas,dirty是制作区域,一般而言需求更新的childview或许整块contentview显现区域
    canvas = mSurface.lockCanvas(dirty);
    ...
    mView.draw(canvas);//终究调用到onDraw办法
    ...
    // 开释canvas
    surface.unlockCanvasAndPost(canvas);
    ...
}

制作进程能够简略描绘为三步:

  • 经过Surface取得一个有用的Canvas
  • view经过canvas来进行制作
  • Surface开释并发送canvas

咱们能够按照这三部步骤来剖析

取得有用的Canvas

咱们能够先简略看一下Canvas类的状况


public class Canvas extends BaseCanvas {
    protected long mNativeCanvasWrapper;    
    public Canvas() {
            if (!isHardwareAccelerated()) { // 非硬件加速模式下创立mNativeCanvasWrapper
                // 0 means no native bitmap
                mNativeCanvasWrapper = nInitRaster(0);
                mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                        this, mNativeCanvasWrapper);
            } else {
                mFinalizer = null;
            }
        }
        public Canvas(@NonNull Bitmap bitmap) {
            ...
            throwIfCannotDraw(bitmap);
            mNativeCanvasWrapper = nInitRaster(bitmap.getNativeInstance());
            mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                    this, mNativeCanvasWrapper);
            mBitmap = bitmap;
            mDensity = bitmap.mDensity;
        }
        public Canvas(long nativeCanvas) {
            ...
            mNativeCanvasWrapper = nativeCanvas;
            mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                    this, mNativeCanvasWrapper);
            mDensity = Bitmap.getDefaultDensity();
        }
}

canvas因为触及到底层的图画制作,那么和surface相同,在cpp层也有一个对应的类完结底层功用,这个类的句柄便是mNativeCanvasWrapper。


/******************************文件分割线******************************************/
// Surface.java
private final Canvas mCanvas = new CompatibleCanvas();
public Canvas lockCanvas(Rect inOutDirty)
        throws Surface.OutOfResourcesException, IllegalArgumentException {
    synchronized (mLock) {
        ...
        mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
        return mCanvas;
    }
}

public void unlockCanvasAndPost(Canvas canvas) {
    synchronized (mLock) {
            ...
            unlockSwCanvasAndPost(canvas);

    }
}

咱们能够观察到surface获取和开释canvas的办法都调用到了native层面,而canvas经过结构函数创立目标时也会创立一个cpp层的目标并取得句柄。咱们看看canvas的结构

//frameworks/base/libs/hwui/jni/android_graphics_Canvas.cpp
static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
    SkBitmap bitmap;
    if (bitmapHandle != 0) {
        bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);
    }
    return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
}

/******************************文件分割线******************************************/
// frameworks/base/libs/hwui/SkiaCanvas.cpp
Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
    return new SkiaCanvas(bitmap);
}

终究在cpp层创立了SkiaCanvas。此刻传入的SkBitmap引证是空的,没有任何有用信息。

咱们接着往native层看lockCanvas的完结。

static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
        // 获取对应native层的SUrface目标
    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
    ...
    ...
    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 buffer;
    // 1,surface调用lock函数确定一块buffer
    status_t err = surface->lock(&buffer, dirtyRectPtr);
    ...
    ...
    //2,经过Java层的canvas目标初始化一个native层的canvas目标
    graphics::Canvas canvas(env, canvasObj);
    //3,设置buffer,然后canvas把buffer转换为SKBitmap
    canvas.setBuffer(&buffer, static_cast<int32_t>(surface->getBuffersDataSpace()));
    ...
    // 创立一个新的Surface引证。返回到Java层
    sp<Surface> lockedSurface(surface);
    lockedSurface->incStrong(&sRefBaseOwner);
    return (jlong) lockedSurface.get();
}
/******************************文件分割线******************************************/
//frameworks/native/libs/nativewindow/include/android/native_window.h
// ANativeWindow_Buffer数据结构
typedef struct ANativeWindow_Buffer {
    /// The number of pixels that are shown horizontally.
    int32_t width;
    /// The number of pixels that are shown vertically.
    int32_t height;
    /// The number of *pixels* that a line in the buffer takes in
    /// memory. This may be >= width.
    int32_t stride;
    /// The format of the buffer. One of AHardwareBuffer_Format.
    int32_t format;
    /// The actual bits.
    void* bits;
    /// Do not touch.
    uint32_t reserved[6];
} ANativeWindow_Buffer;

lockCanvas首要分为三步:1,请求并确定一块内存,2,获取native层的canvas目标,3把buffer设置进canvas。

咱们先来看第一步的细节:


//frameworks/native/libs/gui/Surface.cpp  ===> surface->lock(...)
status_t Surface::lock(
        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
{
    ANativeWindowBuffer* out;
    int fenceFd = -1;
    // dequeueBuffer 从输入缓冲行列中获取一块内存
    status_t err = dequeueBuffer(&out, &fenceFd);
    if (err == NO_ERROR) {
        //当时请求的图形内存区域作为backBuffer
        sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
        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
        // mPostedBuffer作为正在显现的一块图画区域
        const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
        //其实这儿就触及到SUrface的双缓冲机制 mPostedBuffer/mLockedBuffer两块buffer
        // 这儿要判别是否能够仿制(比较一下backBuffer与frontBuffer)
        const bool canCopyBack = (frontBuffer != nullptr &&
                backBuffer->width  == frontBuffer->width &&
                backBuffer->height == frontBuffer->height &&
                backBuffer->format == frontBuffer->format);
        if (canCopyBack) { // 能够赋值时
            //核算一下不需求重绘的区域
            const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
            if (!copyback.isEmpty()) {
                // 仿制不需求重绘的区域
                copyBlt(backBuffer, frontBuffer, copyback, &fenceFd);
            }
        } else {
            // 设置脏区域的边界
            newDirtyRegion.set(bounds);
            //不能仿制则清理一下原先的数据
            mDirtyRegion.clear();
            Mutex::Autolock lock(mMutex);
            for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
                mSlots[i].dirtyRegion.clear();
            }
        }
        ...
        // 确定
        status_t res = backBuffer->lockAsync(
                GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
                newDirtyRegion.bounds(), &vaddr, fenceFd);
        if (res != 0) {
            err = INVALID_OPERATION;
        } else {
            //请求的这块backBuffer保存为mLockedBuffer
            mLockedBuffer = backBuffer;
            outBuffer->width  = backBuffer->width;
            outBuffer->height = backBuffer->height;
            outBuffer->stride = backBuffer->stride;
            outBuffer->format = backBuffer->format;
            outBuffer->bits   = vaddr;
        }
    }
    return err;
}

获取一块图形制作缓冲区,包含制作所需的一些信息。

第二步,获取native层的SkiaCanvas

//frameworks/base/libs/hwui/apex/include/android/graphics/canvas.h
namespace graphics {
    class Canvas {
    public:
        Canvas(JNIEnv* env, jobject canvasObj) :
                        // 调用ACanvas_getNativeHandleFromJava
                mCanvas(ACanvas_getNativeHandleFromJava(env, canvasObj)),
                mOwnedPtr(false) {}

	}
}

/******************************文件分割线******************************************/
//frameworks/base/libs/hwui/apex/android_canvas.cpp
ACanvas* ACanvas_getNativeHandleFromJava(JNIEnv* env, jobject canvasObj) {
                                //继续调用getNativeCanvas
    return TypeCast::toACanvas(GraphicsJNI::getNativeCanvas(env, canvasObj));
}

/******************************文件分割线******************************************/
//frameworks/base/libs/hwui/jni/Graphics.cpp
...
gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
...
android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
    ...
    // 获取Java层的Canvas mNativeCanvasWrapper的句柄
    jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID);
    if (!canvasHandle) {
        return NULL;
    }
    // 把数值转换为目标
    return reinterpret_cast<android::Canvas*>(canvasHandle);
}

经过从Java层传入的Canvas引证,取得native层创立好的SkiaCanvas。

然后是第三步


frameworks/base/libs/hwui/apex/include/android/graphics/canvas.h
bool setBuffer(const ANativeWindow_Buffer* buffer,
                       int32_t /*android_dataspace_t*/ dataspace) {
            return ACanvas_setBuffer(mCanvas, buffer, dataspace);
 }
 /******************************文件分割线******************************************/
// frameworks/base/libs/hwui/apex/android_canvas.cpp
bool ACanvas_setBuffer(ACanvas* canvas, const ANativeWindow_Buffer* buffer,
                       int32_t /*android_dataspace_t*/ dataspace) {
    SkBitmap bitmap;
    // 把buffer转换为SKBitmap
    bool isValidBuffer = (buffer == nullptr) ? false : convert(buffer, dataspace, &bitmap);
    // 然后把SKBitmap设置进SkiaCanvas中(SKBitmap能够被canvas制作)
    TypeCast::toCanvas(canvas)->setBitmap(bitmap);
    return isValidBuffer;
}
 /******************************文件分割线******************************************/
//frameworks/base/libs/hwui/SkiaCanvas.cpp   setBitmap的完结函数
void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
    // 依据传入的bitmap创立一个SkCanvas,并更新
    mCanvasOwned.reset(new SkCanvas(bitmap));
    mCanvas = mCanvasOwned.get();
    // clean up the old save stack
    mSaveStack.reset(nullptr);
}

把获取的buffer转换为一个SkBitmap,此刻bitmap中有有用信息,然后把Bitmap设置进SkiaCanvas并替换本来的Bitmap,接下来canvas就在这个bitmap上进行制作。

setBuffer既用于设置buffer,也用于解除buffer,后边开释提交canvas时还会运用

经过Canvas进行制作

制作进程首要在发生View的体系中,依据View的需求自行进行制作操作,Java层的部分应当是咱们最了解的部分了。

当然所有的制作API都经过JNI调用到了native层的SkiaCanvas中,然后制作在SKBitmap上。这些都由skia图画制作引擎供给具体完结逻辑。在此咱们不进行深究了(精力有限)

开释并发送Canvas

假定制作区域完结了制作操作,那么接下来便是开释并提交canvas了。Java层经过nativeUnlockCanvasAndPost调用到native层,咱们看其具体完结

//frameworks/base/core/jni/android_view_Surface.cpp
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj) {
        // 找到native层的Surface
    sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
    ...
    //找到native层的SkiaCanvas
    graphics::Canvas canvas(env, canvasObj);
    //SkiaCanvas设置当时buffer为空
    canvas.setBuffer(nullptr, ADATASPACE_UNKNOWN);
    // unlock surface
    status_t err = surface->unlockAndPost();
    ...
}

里面的函数前面大多都讲过, canvas.setBuffer(nullptr,..),nullptr会转换为一个空的skBitmap,然后替换SkiaCanvas里面原有的SkBitmap。相当于让canvas与本来的buffer分离。

// frameworks/native/libs/gui/Surface.cpp
status_t Surface::unlockAndPost()
{
  //surface->lock()时现已保存了一个mLockedBuffer,此刻应该不为null
    if (mLockedBuffer == nullptr) {
        ALOGE("Surface::unlockAndPost failed, no locked buffer");
        return INVALID_OPERATION;
    }
    int fd = -1;
    // 解除确定
    status_t err = mLockedBuffer->unlockAsync(&fd);
    ALOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
    //把这块制作结束的buffer提交到缓冲行列中,等候显现
    err = queueBuffer(mLockedBuffer.get(), fd);
    ...
    // 接着这块buffer就变成了前台已发布的buffer了,这个便是双缓冲机制了
    mPostedBuffer = mLockedBuffer;
    //置空
    mLockedBuffer = nullptr;
    return err;
}

至此,View的制作的具体进程咱们也搞清楚了:ViewRootImp经过Surface从缓冲行列中取得一块可用于制作的buffer,然后把buffer绑定在canvas中,Android View运用该canvas进行制作,发生的烘托数据也终究保存在buffer中,制作结束,经过Surface铲除canvas与buffer的绑定联系,并把buffer发送到缓冲行列中,完结了出产端烘托数据的出产进程。

小结

在烘托数据出产进程中,Surface的低位非常重要,咱们文章开头说到的那些出产者(view/Camera/media player…)都离不开它,Surface供给了操作接口来完结出产端的数据输入进程。在消费端, 大部分状况下是经过SurfaceFlinger把烘托数据的用在屏幕显现来完结消费的。可是也有其他状况,比方也能够被视频编码器进行消费(后续关于Android音视频开发的文章或许会说到)。

总归Surface给图形数据出产者供给了了一个数据输入的标准接口,咱们会在很多的体系模块中看到它的身影。

文章到这儿显现原理差不多只讲到一半,出产消费模型只讲到了出产端,消费端还没有触及,还有缓冲行列的具体操作,这个留在后续文章进行研究。