Android 复习学习使用Display

SurfaceFlinger源码分析三

2022-08-28  本文已影响0人  梧叶已秋声

写在开头:本文基本算是跟着Android画面显示流程分析(4)这篇过的一遍笔记。

本篇带着下面这2个问题去分析。

Android应用程序是如何请求SurfaceFlinger服务 创建 一个Surface的?
Android应用程序是如何请求SurfaceFlinger服务 渲染 一个Surface的?

先来看第一个问题:
Android应用程序是如何请求SurfaceFlinger服务 创建 一个Surface的?
Activity在显示过程中,会调用requestLayout

//frameworks/base/services/java/com/android/server/WindowManagerService.java
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            long frameNumber, Rect outFrame, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
            SurfaceControl outBLASTSurfaceControl) {
      ......
      try {
          result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
          result, win, winAnimator);
      } catch (Exception e) {
      ......
}


private int createSurfaceControl(SurfaceControl outSurfaceControl,
            SurfaceControl outBLASTSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
    ......
    WindowSurfaceController surfaceController;
    try {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
        surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    if (surfaceController != null) {
        surfaceController.getSurfaceControl(outSurfaceControl);
        ......
    }
    ......
}

SurfaceControl的创建过程,注意这里创建工作是调用winAnimator来完成的,注意下面那句surfaceController.getSurfaceControl会把创建出来的SurfaceControl通过形参outSurfaceControl传出去。

创建了一个WindowSurfaceController,进而再创建SurfaceControll:

//frameworks/base/services/core/java/com/android/server/wm/WindowStateAnimator.java
 WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
    ......
    /*WindowSurfaceController mSurfaceController;*/
    mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), width,
                    height, format, flags, this, windowType, ownerUid);
    ......
}

走到WindowSurfaceController中,这里使用了SurfaceControl.Builder去构造SurfaceControl

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/services/core/java/com/android/server/wm/WindowSurfaceController.java

 WindowSurfaceController(String name, int w, int h, int format,
            int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
     ......
     final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl())
                .setName(name)
                .setBufferSize(w, h)
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, ownerUid)
                .setCallsite("WindowSurfaceController");
     ......
}

看一下Builder ,然后由于需要Parcelable序列化,所以这里实现了Creator<T>接口。

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/core/java/android/view/SurfaceControl.java

  /**
     * Builder class for {@link SurfaceControl} objects.
     *
     * By default the surface will be hidden, and have "unset" bounds, meaning it can
     * be as large as the bounds of its parent if a buffer or child so requires.
     *
     * It is necessary to set at least a name via {@link Builder#setName}
     */
    public static class Builder {
        private SurfaceSession mSession;
        private int mFlags = HIDDEN;
        private int mWidth;
        private int mHeight;
        private int mFormat = PixelFormat.OPAQUE;
        private String mName;
        private WeakReference<View> mLocalOwnerView;
        private SurfaceControl mParent;
        private SparseIntArray mMetadata;
        private String mCallsite = "SurfaceControl.Builder";

        /**
         * Begin building a SurfaceControl with a given {@link SurfaceSession}.
         *
         * @param session The {@link SurfaceSession} with which to eventually construct the surface.
         * @hide
         */
        public Builder(SurfaceSession session) {
            mSession = session;
        }

        /**
         * Begin building a SurfaceControl.
         */
        public Builder() {
        }

        /**
         * Construct a new {@link SurfaceControl} with the set parameters. The builder
         * remains valid.
         */
        @NonNull
        public SurfaceControl build() {
            if (mWidth < 0 || mHeight < 0) {
                throw new IllegalStateException(
                        "width and height must be positive or unset");
            }
            if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
                throw new IllegalStateException(
                        "Only buffer layers can set a valid buffer size.");
            }

            if ((mFlags & FX_SURFACE_MASK) == FX_SURFACE_NORMAL) {
                setBLASTLayer();
            }

            return new SurfaceControl(
                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
                    mLocalOwnerView, mCallsite);
        }

        /**
         * Set a debugging-name for the SurfaceControl.
         *
         * @param name A name to identify the Surface in debugging.
         */
        @NonNull
        public Builder setName(@NonNull String name) {
            mName = name;
            return this;
        }

        /**
         * Set the local owner view for the surface. This view is only
         * valid in the same process and is not transferred in an IPC.
         *
         * Note: This is used for cases where we want to know the view
         * that manages the surface control while intercepting reparenting.
         * A specific example is InlineContentView which exposes is surface
         * control for reparenting as a way to implement clipping of several
         * InlineContentView instances within a certain area.
         *
         * @param view The owner view.
         * @return This builder.
         *
         * @hide
         */
        @NonNull
        public Builder setLocalOwnerView(@NonNull View view) {
            mLocalOwnerView = new WeakReference<>(view);
            return this;
        }

        /**
         * Set the initial size of the controlled surface's buffers in pixels.
         *
         * @param width The buffer width in pixels.
         * @param height The buffer height in pixels.
         */
        @NonNull
        public Builder setBufferSize(@IntRange(from = 0) int width,
                @IntRange(from = 0) int height) {
            if (width < 0 || height < 0) {
                throw new IllegalArgumentException(
                        "width and height must be positive");
            }
            mWidth = width;
            mHeight = height;
            // set this as a buffer layer since we are specifying a buffer size.
            return setFlags(FX_SURFACE_NORMAL, FX_SURFACE_MASK);
        }

        private void unsetBufferSize() {
            mWidth = 0;
            mHeight = 0;
        }

        /**
         * Set the pixel format of the controlled surface's buffers, using constants from
         * {@link android.graphics.PixelFormat}.
         */
        @NonNull
        public Builder setFormat(@PixelFormat.Format int format) {
            mFormat = format;
            return this;
        }

        /**
         * Specify if the app requires a hardware-protected path to
         * an external display sync. If protected content is enabled, but
         * such a path is not available, then the controlled Surface will
         * not be displayed.
         *
         * @param protectedContent Whether to require a protected sink.
         * @hide
         */
        @NonNull
        public Builder setProtected(boolean protectedContent) {
            if (protectedContent) {
                mFlags |= PROTECTED_APP;
            } else {
                mFlags &= ~PROTECTED_APP;
            }
            return this;
        }

        /**
         * Specify whether the Surface contains secure content. If true, the system
         * will prevent the surfaces content from being copied by another process. In
         * particular screenshots and VNC servers will be disabled. This is however
         * not a complete prevention of readback as {@link #setProtected}.
         * @hide
         */
        @NonNull
        public Builder setSecure(boolean secure) {
            if (secure) {
                mFlags |= SECURE;
            } else {
                mFlags &= ~SECURE;
            }
            return this;
        }

        /**
         * Indicates whether the surface must be considered opaque,
         * even if its pixel format is set to translucent. This can be useful if an
         * application needs full RGBA 8888 support for instance but will
         * still draw every pixel opaque.
         * <p>
         * This flag only determines whether opacity will be sampled from the alpha channel.
         * Plane-alpha from calls to setAlpha() can still result in blended composition
         * regardless of the opaque setting.
         *
         * Combined effects are (assuming a buffer format with an alpha channel):
         * <ul>
         * <li>OPAQUE + alpha(1.0) == opaque composition
         * <li>OPAQUE + alpha(0.x) == blended composition
         * <li>OPAQUE + alpha(0.0) == no composition
         * <li>!OPAQUE + alpha(1.0) == blended composition
         * <li>!OPAQUE + alpha(0.x) == blended composition
         * <li>!OPAQUE + alpha(0.0) == no composition
         * </ul>
         * If the underlying buffer lacks an alpha channel, it is as if setOpaque(true)
         * were set automatically.
         * @param opaque Whether the Surface is OPAQUE.
         */
        @NonNull
        public Builder setOpaque(boolean opaque) {
            if (opaque) {
                mFlags |= OPAQUE;
            } else {
                mFlags &= ~OPAQUE;
            }
            return this;
        }

        /**
         * Set the initial visibility for the SurfaceControl.
         *
         * @param hidden Whether the Surface is initially HIDDEN.
         * @hide
         */
        @NonNull
        public Builder setHidden(boolean hidden) {
            if (hidden) {
                mFlags |= HIDDEN;
            } else {
                mFlags &= ~HIDDEN;
            }
            return this;
        }

        /**
         * Set a parent surface for our new SurfaceControl.
         *
         * Child surfaces are constrained to the onscreen region of their parent.
         * Furthermore they stack relatively in Z order, and inherit the transformation
         * of the parent.
         *
         * @param parent The parent control.
         */
        @NonNull
        public Builder setParent(@Nullable SurfaceControl parent) {
            mParent = parent;
            return this;
        }

        /**
         * Sets a metadata int.
         *
         * @param key metadata key
         * @param data associated data
         * @hide
         */
        public Builder setMetadata(int key, int data) {
            if (mMetadata == null) {
                mMetadata = new SparseIntArray();
            }
            mMetadata.put(key, data);
            return this;
        }

        /**
         * Indicate whether an 'EffectLayer' is to be constructed.
         *
         * An effect layer behaves like a container layer by default but it can support
         * color fill, shadows and/or blur. These layers will not have an associated buffer.
         * When created, this layer has no effects set and will be transparent but the caller
         * can render an effect by calling:
         *  - {@link Transaction#setColor(SurfaceControl, float[])}
         *  - {@link Transaction#setBackgroundBlurRadius(SurfaceControl, int)}
         *  - {@link Transaction#setShadowRadius(SurfaceControl, float)}
         *
         * @hide
         */
        public Builder setEffectLayer() {
            mFlags |= NO_COLOR_FILL;
            unsetBufferSize();
            return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
        }

        /**
         * A convenience function to create an effect layer with a default color fill
         * applied to it. Currently that color is black.
         *
         * @hide
         */
        public Builder setColorLayer() {
            unsetBufferSize();
            return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
        }

        private boolean isEffectLayer() {
            return  (mFlags & FX_SURFACE_EFFECT) == FX_SURFACE_EFFECT;
        }

        /**
         * @hide
         */
        public Builder setBLASTLayer() {
            return setFlags(FX_SURFACE_BLAST, FX_SURFACE_MASK);
        }

        /**
         * Indicates whether a 'ContainerLayer' is to be constructed.
         *
         * Container layers will not be rendered in any fashion and instead are used
         * as a parent of renderable layers.
         *
         * @hide
         */
        public Builder setContainerLayer() {
            unsetBufferSize();
            return setFlags(FX_SURFACE_CONTAINER, FX_SURFACE_MASK);
        }

        private boolean isContainerLayer() {
            return  (mFlags & FX_SURFACE_CONTAINER) == FX_SURFACE_CONTAINER;
        }

        /**
         * Set 'Surface creation flags' such as {@link #HIDDEN}, {@link #SECURE}.
         *
         * TODO: Finish conversion to individual builder methods?
         * @param flags The combined flags
         * @hide
         */
        public Builder setFlags(int flags) {
            mFlags = flags;
            return this;
        }

        /**
         * Sets the callsite this SurfaceControl is constructed from.
         *
         * @param callsite String uniquely identifying callsite that created this object. Used for
         *                 leakage tracking.
         * @hide
         */
        public Builder setCallsite(String callsite) {
            mCallsite = callsite;
            return this;
        }

        private Builder setFlags(int flags, int mask) {
            mFlags = (mFlags & ~mask) | flags;
            return this;
        }
    }


    public static final @android.annotation.NonNull Creator<SurfaceControl> CREATOR
            = new Creator<SurfaceControl>() {
        public SurfaceControl createFromParcel(Parcel in) {
            return new SurfaceControl(in);
        }

        public SurfaceControl[] newArray(int size) {
            return new SurfaceControl[size];
        }
    };

build()中调用了

 return new SurfaceControl(
                    mSession, mName, mWidth, mHeight, mFormat, mFlags, mParent, mMetadata,
                    mLocalOwnerView, mCallsite);

然后走到SurfaceControl中的SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,String callsite)

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/core/java/android/view/SurfaceControl.java#1408

  private static native long nativeCreate(SurfaceSession session, String name,
            int w, int h, int format, int flags, long parentObject, Parcel metadata)
            throws OutOfResourcesException;

  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 {
    ......

    mNativeObject = nativeCreate(session, name, w, h, format, flags,
                    parent != null ? parent.mNativeObject : 0, metaParcel);
    ......

}

这里调用后走到JNI中。这里会调用client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,flags, parentHandle, std::move(metadata));

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/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) {
        client = android_view_SurfaceSession_getClient(env, sessionObj);
    } else {
        client = SurfaceComposerClient::getDefault();
    }
    SurfaceControl *parent = reinterpret_cast<SurfaceControl*>(parentObject);
    sp<SurfaceControl> surface;
   ...

    status_t err = client->createSurfaceChecked(String8(name.c_str()), w, h, format, &surface,
                                                flags, parentHandle, std::move(metadata));
   ...

    surface->incStrong((void *)nativeCreate);
    return reinterpret_cast<jlong>(surface.get());
}

走到SurfaceComposerClient::createSurfaceChecked之后,最终调用了mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),&handle, &gbp, &id, &transformHint);

// frameworks/native/libs/gui/SurfaceComposerClient.cpp
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                     PixelFormat format,
                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
                                                     const sp<IBinder>& parentHandle,
                                                     LayerMetadata metadata,
                                                     uint32_t* outTransformHint) {
    sp<SurfaceControl> sur;
    status_t err = mStatus;

    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;

        uint32_t transformHint = 0;
        int32_t id = -1;
        err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
                                     &handle, &gbp, &id, &transformHint);

        if (outTransformHint) {
            *outTransformHint = transformHint;
        }
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            *outSurface =
                    new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags);
        }
    }
    return err;
}

而mClient 在前篇分析过,是onFirstRef的时候初始化,而且是以SurfaceFlinger为参数,创建的一个Client对象,也就是持有SurfaceFlinger

//frameworks/native/libs/gui/SurfaceComposerClient.cpp

void SurfaceComposerClient::onFirstRef() {
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    if (sf != nullptr && mStatus == NO_INIT) {
        sp<ISurfaceComposerClient> conn;
        conn = sf->createConnection();
        if (conn != nullptr) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}
// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() {
    const sp<Client> client = new Client(this);
    return client->initCheck() == NO_ERROR ? client : nullptr;
}

Client::createSurface,会调用mFlinger->createLayer


//frameworks/native/services/surfaceflinger/Client.cpp
class Client : public BnSurfaceComposerClient
{
public:
    explicit Client(const sp<SurfaceFlinger>& flinger);
    ~Client() = default;

    status_t initCheck() const;
   .....
// constant
  sp<SurfaceFlinger> mFlinger;
   .....
}

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/services/surfaceflinger/Client.cpp
status_t Client::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format,
                               uint32_t flags, const sp<IBinder>& parentHandle,
                               LayerMetadata metadata, sp<IBinder>* handle,
                               sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId,
                               uint32_t* outTransformHint) {
    // We rely on createLayer to check permissions.
    return mFlinger->createLayer(name, this, w, h, format, flags, std::move(metadata), handle, gbp,
                                 parentHandle, outLayerId, nullptr, outTransformHint);
}

createLayer具体做了什么呢?

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                     uint32_t h, PixelFormat format, uint32_t flags,
                                     LayerMetadata metadata, sp<IBinder>* handle,
                                     sp<IGraphicBufferProducer>* gbp,
                                     const sp<IBinder>& parentHandle, int32_t* outLayerId,
                                     const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
    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;
    }

    ALOG_ASSERT(parentLayer == nullptr || parentHandle == nullptr,
            "Expected only one of parentLayer or parentHandle to be non-null. "
            "Programmer error?");

    status_t result = NO_ERROR;

    sp<Layer> layer;

    std::string uniqueName = getUniqueLayerName(name.string());

    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
        case ISurfaceComposerClient::eFXSurfaceBufferState: {
            result = createBufferStateLayer(client, std::move(uniqueName), w, h, flags,
                                            std::move(metadata), handle, &layer);
            std::atomic<int32_t>* pendingBufferCounter = layer->getPendingBufferCounter();
            if (pendingBufferCounter) {
                std::string counterName = layer->getPendingBufferCounterName();
                mBufferCountTracker.add((*handle)->localBinder(), counterName,
                                        pendingBufferCounter);
            }
        } break;
        case ISurfaceComposerClient::eFXSurfaceEffect:
            // check if buffer size is set for color layer.
            if (w > 0 || h > 0) {
                ALOGE("createLayer() failed, w or h cannot be set for color layer (w=%d, h=%d)",
                      int(w), int(h));
                return BAD_VALUE;
            }

            result = createEffectLayer(client, std::move(uniqueName), w, h, flags,
                                       std::move(metadata), handle, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceContainer:
            // check if buffer size is set for container layer.
            if (w > 0 || h > 0) {
                ALOGE("createLayer() failed, w or h cannot be set for container layer (w=%d, h=%d)",
                      int(w), int(h));
                return BAD_VALUE;
            }
            result = createContainerLayer(client, std::move(uniqueName), w, h, flags,
                                          std::move(metadata), handle, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }

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

    bool addToRoot = callingThreadHasUnscopedSurfaceFlingerAccess();
    result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer, addToRoot,
                            outTransformHint);
    if (result != NO_ERROR) {
        return result;
    }
    mInterceptor->saveSurfaceCreation(layer);

    setTransactionFlags(eTransactionNeeded);
    *outLayerId = layer->sequence;
    return result;
}
  1. 检查宽高数值是否合法,宽/高不应为负值;

  2. 检查parentLayer/parentHandle,对于我们的应用来说,没有parent,两者都为 null;

  3. 获取一个独一无二的Layer name,即不能有重名的Layer;

  4. 根据flags去创建对应类型的Layer ⇒ createBufferStateLayer or createEffectLayer or createContainerLayer

最后所有在Client中获取到的Layer信息都被封装到一个SurfaceControl对象中,并返回给应用来使用。

//frameworks/native/libs/gui/SurfaceComposerClient.cpp
if (err == NO_ERROR) {
   *outSurface =
       new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags);
}

那么应用侧又是如何拿到这个Layer的操作接口呢?
通过Surface的copyFrom方法从SurfaceControl来创建这个Surface

// frameworks/base/core/java/android/view/ViewRootImpl.java
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
     ......
     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,
                mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
                mPendingDisplayCutout, mPendingMergedConfiguration, 
//这里的mSurfaceControl是从WMS传来的
                mSurfaceControl, mTempInsets, 
                mTempControls, mSurfaceSize, mBlastSurfaceControl);
     ......
     if (mSurfaceControl.isValid()) {
            if (!useBLAST()) {
//通过Surface的copyFrom方法从SurfaceControl来创建这个Surface
                mSurface.copyFrom(mSurfaceControl);
            }
     ......
}

至此,Android应用程序请求SurfaceFlinger服务 创建 一个Surface的流程分析完成。

下面来看看问题二:Android应用程序是如何请求SurfaceFlinger服务 渲染 一个Surface的?这个问题换个更通俗易懂的说法就是:Surface如何通过SurfaceFlinger服务显示到屏幕上。
一般把Surface称为画布,Layer称为图层。
Surface是应用侧创建的,LayerSurfaceFlinger服务端创建的。
前面分析Surface的创建过程中可以看到, WindowManagerService中创建SurfaceControl ,然后实际走到nativeCreate,最终走到了SurfaceFlinger::createLayer,创建Layer,最终调用的是SurfaceFlinger::createLayer,最后所有在Client中获取到的Layer信息都被封装到一个SurfaceControl对象中,并返回给应用来使用,然后通过应用侧通过mSurface.copyFrom(mSurfaceControl);创建Surface
那么拿到Surface对象后怎么就能拿到帧缓冲区的操作接口呢?
关键看下面这两个native 函数。

// frameworks/base/core/java/android/view/Surface.java
public class Surface implements Parcelable {
    ......
  private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
            throws OutOfResourcesException;
    private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
    ......    
}


//frameworks/base/core/jni/android_view_Surface.cpp
static jlong nativeLockCanvas(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj, jobject dirtyRectObj) {
  ...
    status_t err = surface->lock(&buffer, dirtyRectPtr);
  ...
    }

   
static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
        jlong nativeObject, jobject canvasObj) {
   ...
    // unlock surface
    status_t err = surface->unlockAndPost();
    ...
}

这两个native会分别调用dequeueBufferqueueBuffer

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/libs/gui/Surface.cpp
status_t Surface::lock(
        ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds){
     ......
     status_t err = dequeueBuffer(&out, &fenceFd);
     ......
}
int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {
    ATRACE_CALL();
    ......
    status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
    ......
}


status_t Surface::unlockAndPost()
{
   ...
    err = queueBuffer(mLockedBuffer.get(), fd);
   ...
}

int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) {
...
    status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output);
...
 
}

调用dequeueBuffer后,应用拿到了它绘制界面所需的“画布”。
知道了应用是如何拿到“画布”的,接下来我们来看下应用是如何在绘画完一帧后来提交数据的:
performTraversals函数中获取到了操作帧缓冲区的Surface对象,这个Surface对象会通过RenderProxy传递给RenderThread, 一些关健代码如下:
performTraversals里初始化RenderThread时会把Surface对象传过去:

private void performTraversals() {
    ......
    if (mAttachInfo.mThreadedRenderer != null) {
    try {
        hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
        ........
    } 
    ......
}

在ThreadedRenderer的初始化中调用了setSurface,这个setSurface函数会通过JNI调到native层:

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/core/java/android/view/ThreadedRenderer.java

public final class ThreadedRenderer extends HardwareRenderer {
    boolean initialize(Surface surface) throws OutOfResourcesException {
        ......
        setSurface(surface);
        ......
    }

    @Override
    public void setSurface(Surface surface) {
        // TODO: Do we ever pass a non-null but isValid() = false surface?
        // This is here to be super conservative for ViewRootImpl
        if (surface != null && surface.isValid()) {
            super.setSurface(surface);
        } else {
            super.setSurface(null);
        }
    }
}

走到HardwareRenderer中的nSetSurface

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/graphics/java/android/graphics/HardwareRenderer.java
    private static native void nSetSurface(long nativeProxy, Surface window, boolean discardBuffer);

   public void setSurface(@Nullable Surface surface) {
        setSurface(surface, false);
    }

    public void setSurface(@Nullable Surface surface, boolean discardBuffer) {
        if (surface != null && !surface.isValid()) {
            throw new IllegalArgumentException("Surface is invalid. surface.isValid() == false.");
        }
        nSetSurface(mNativeProxy, surface, discardBuffer);
    }
//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz,
        jlong proxyPtr, jobject jsurface, jboolean discardBuffer) {
    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
   ...
    proxy->setSurface(window, enableTimeout);
    ...
}

最终可以看到setSurface是通过RenderProxy这个对象向RenderThread的消息队列中post了一个消息,在这个消息的处理中会调用Context的setSurface, 这里的mContext是CanvasContext.

//RenderProxy.cpp 
void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) {
    ANativeWindow_acquire(window);
    mRenderThread.queue().post([this, win = window, enableTimeout]() mutable {
        mContext->setSurface(win, enableTimeout);
        ANativeWindow_release(win);
    });
}

首先App每次开始绘画都是收到一个vsync信号才会开始绘图,应用是通过Choreographer来感知vsync信号, 在ViewRootImpl里向Choreographer注册一个callback, 每当有vsync信号来时会执行mTraversalRunnable:

//ViewRootImpl.java
 void scheduleTraversals() {
     if (!mTraversalScheduled) {
         ......
         mChoreographer.postCallback(
         Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//注册vsync的回调
         ......
     }
 }
 final class TraversalRunnable implements Runnable {
     @Override
     public void run() {
        doTraversal();//每次vsync到时调用该函数
     }
 }

而doTraversal()主要是调用performTraversals()这个函数,performTraversals里会调用到draw()函数:

//ViewRootImpl.java
 private boolean draw(boolean fullRedrawNeeded) {
     ......
      if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
          ......
          mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);//这里传下去的mView就是DecorView
          ......
      }
     ......
 }

上面的draw()函数进一步调用了ThreadedRenderer的draw:

//ThreadedRenderer.java
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
   ......
   updateRootDisplayList(view, callbacks);
   ......
}
private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
   Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");//这里有个trace,我们可以在systrace中观察到它
   ......
   updateViewTreeDisplayList(view);
   ......
}
private void updateViewTreeDisplayList(View view) {
   ......
   view.updateDisplayListIfDirty();//这里开始调用DecorView的updateDisplayListIfDirty
   ......
}

接下来代码调用到DecorView的基类View.java:

public RenderNode updateDisplayListIfDirty() {
   ......
    final RecordingCanvas canvas = renderNode.beginRecording(width, height);//这里开始displaylist的record
    ......
    draw(canvas);
    ......
    
}

上面的RecordingCanvas就是扮演一个绘图指令的记录员角色,它会将这个View通过draw函数绘制的指令以displaylist形式记录下来,Android里的View和RenderNode是类似的概念,View代表的是实体在空间结构上的存在,而RenderNode代表它在界面呈现上的存在。这样的设计可以让存在和呈现进行分离,便于实现同一存在不同状态下呈现也不同。

在Android的设计里View会对应一个RenderNode, RenderNode里的一个重要数据结构是DisplayList, 每个DisplayList都会包含一系列DisplayListData. 这些DisplayList也会同样以树形结构组织在一起。

当UI线程完成它的绘制工作后,它工作的产物是一堆DisplayListData。UI线程并没有将应用设计的View转换成像素点数据,而是将每个View的绘图指令存入了内存中,我们通常称这些绘图指令为DisplayList。

//RecordingCanvas.h
class DisplayListData final {
    ......
    void drawPath(const SkPath&, const SkPaint&);
    void drawRect(const SkRect&, const SkPaint&);
    void drawRegion(const SkRegion&, const SkPaint&);
    void drawOval(const SkRect&, const SkPaint&);
    void drawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&);
    ......
    template <typename T, typename... Args>
    void* push(size_t, Args&&...);
    ......
    SkAutoTMalloc<uint8_t> fBytes;
    ......
}

当所有的View的displaylist建立完成后,代码走到RenderProxy中,然后走到DrawFrameTask中。

//RenderProxy.cpp 
int RenderProxy::syncAndDrawFrame() {
    return mDrawFrameTask.drawFrame();
}
//DrawFrameTask.cpp

int DrawFrameTask::drawFrame() {
    LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");

    mSyncResult = SyncResult::OK;
    mSyncQueued = systemTime(SYSTEM_TIME_MONOTONIC);
    postAndWait();

    return mSyncResult;
}

void DrawFrameTask::postAndWait() {
    AutoMutex _lock(mLock);
    mRenderThread->queue().post([this]() { run(); });//丢任务到RenderThread线程
    mSignal.wait(mLock);
}

UI线程的工作到此结束,它丢了一个叫DrawFrameTask的任务到RenderThread线程中去,之后画面绘制的工作转移到RenderThread中来。

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp
void DrawFrameTask::run() {
    CanvasContext* context = mContext;
    .....
    dequeueBufferDuration = context->draw();
    .....
}
//CanvasContext.cpp
void CanvasContext::draw() {
    ......
    Frame frame = mRenderPipeline->getFrame();//这句会调用到Surface的dequeueBuffer
    ......
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
                                      mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
                                      &(profiler()));
    ......
    waitOnFences();
    ......
    bool didSwap =
            mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);//这句会调用到Surface的queueBuffer
    ......
}

RenderPipeline,渲染管线。在计算机图形学中,管线就是一系列过程。例如下图就是一个OpenGL 管线。


https://blog.csdn.net/wb175208/article/details/125455294

在这个函数中完成了三个重要的动作,一个是通过getFrame调到了Surface的dequeueBuffer向SurfaceFlinger申请了画布, 第二是通过mRenderPipeline->draw将画面画到申请到的画布上, 第三是通过调mRenderPipeline->swapBuffers把画布提交到SurfaceFlinger去显示。

那么在mRenderPipeline->draw里是如何将displaylist翻译成画布上的像素点颜色的呢?

//http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
                              const LightGeometry& lightGeometry,
                              LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
                              bool opaque, const LightInfo& lightInfo,
                              const std::vector<sp<RenderNode>>& renderNodes,
                              FrameInfoVisualizer* profiler) {
      ......
      renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds, surface, SkMatrix::I());
      ......
 }

renderFrameImpl中会把在UI线程中记录的displaylist重新“绘制”到skSurface中,然后通过SkCanvas将其转化为gl指令, surface->getCanvas()->flush();
所以整体流程为:

首先是UI线程进行measure, layout然后开始draw, 在draw的过程中会建立displaylist树,将每个view应该怎么画记录下来,然后通过RenderProxy把后续任务下达给RenderThread, RenderThread主要完成三个动作,先通过Surface接口向Surfaceflinger申请buffer, 然后通过SkiaOpenGLPipline的draw方法把displaylist翻译成GPU指令, 指挥GPU把指令变成像素点数据, 最后通过swapBuffer把数据提交给SurfaceFlinger, 完成一帧数据的绘制和提交。

应用提交buffer以后SurfaceFlinger会如何处理呢?又是如何提交到HWC Service去合成的呢?
首先响应应用queueBuffer的是一条binder线程, 处理逻辑会走进BufferQueueProducer.cpp。

//BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);
    ......
     if (frameAvailableListener != nullptr) {
        frameAvailableListener->onFrameAvailable(item);
     }
    ......
}

上面的frameAvailableListener是BufferQueueLayer

//BufferQueueLayer.cpp
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
    ......
     mFlinger->signalLayerUpdate();//这里申请一下个vsync-sf信号
    ......
}

只要有layer上帧,那么就会申请下一次的vsync-sf信号, 当vsync-sf信号来时会调用onMessageReceived函数来处理帧数据。

void MessageQueue::Handler::dispatchInvalidate() {
    if ((android_atomic_or(eventMaskInvalidate, &mEventMask) & eventMaskInvalidate) == 0) {
        mQueue.mLooper->sendMessage(this, Message(MessageQueue::INVALIDATE));
    }
}

void MessageQueue::Handler::handleMessage(const Message& message) {
    switch (message.what) {
        case INVALIDATE:
            android_atomic_and(~eventMaskInvalidate, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
        case REFRESH:
            android_atomic_and(~eventMaskRefresh, &mEventMask);
            mQueue.mFlinger->onMessageReceived(message.what);
            break;
    }
}

发送了一个INVALIDATE消息交给SF的onMessageReceive处理。
SF onMessageReceive 处理 INVALIDATE消息

// http://aosp.opersys.com/xref/android-12.0.0_r2/xref/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp#1875
void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
    switch (what) {
        case MessageQueue::INVALIDATE: {
            onMessageInvalidate(vsyncId, expectedVSyncTime);
            break;
        }
        case MessageQueue::REFRESH: {
            onMessageRefresh();
            break;
        }
    }
}

走到SurfaceFlinger::onMessageInvalidate中。

//SurfaceFlinger.cpp
void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
    ATRACE_CALL();
    ......
        refreshNeeded |= handleMessageInvalidate();
    ......
    signalRefresh();//再次向消息队列发送一个消息,消息到达时会调用onMessageRefresh
    ......
}
bool SurfaceFlinger::handleMessageInvalidate() {
    ATRACE_CALL();
    bool refreshNeeded = handlePageFlip();
    ......
}

在handleMessageInvalidate里一个比较重要的函数是handlePageFlip():

bool SurfaceFlinger::handlePageFlip()
{
    ATRACE_CALL();
    ......
    mDrawingState.traverse([&](Layer* layer) {
        if (layer->hasReadyFrame()) {
            frameQueued = true;
            if (layer->shouldPresentNow(expectedPresentTime)) {
                mLayersWithQueuedFrames.push_back(layer);
            } 
            .......
        } 
        ......
    });
    ......
        for (auto& layer : mLayersWithQueuedFrames) {
            if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
                mLayersPendingRefresh.push_back(layer);
            }
            .......
        }
        ......
}

这里可以看出来,handlePageFlip里一个重要的工作是检查所有的Layer是否有新buffer提交,如果有则调用其latchBuffer来处理

//BufferLayer.cpp
bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
                              nsecs_t expectedPresentTime) {
    ATRACE_CALL();
    ......
    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
    ......
}

//BufferQueueLayer.cpp
status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
                                          nsecs_t expectedPresentTime) {
     ......
      status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
                                                      &queuedBuffer, maxFrameNumberToAcquire);
     ......
}

//BufferLayerConsumer.cpp
status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
                                             bool* autoRefresh, bool* queuedBuffer,
                                             uint64_t maxFrameNumber) {
    ATRACE_CALL();
    ......
    status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber);
    ......
}

status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    ......
    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
    ......
}

到这里onMessageReceived中的主要工作结束,在这个函数的处理中,SurfaceFlinger主要是检查每个Layer是否有新提交的buffer, 如果有则调用latchBuffer将每个BufferQueue中的Slot 通过acquireBuffer拿走。 之后拿走的buffer(Slot对应的状态是ACQUIRED状态)会被交由HWC Service处理,这部分是在onMessageRefresh里处理的,然后走到CompositionEngine,再走到Output。

// SurfaceFlinger.cpp
void SurfaceFlinger::onMessageRefresh() {
    ATRACE_CALL();
    ......
    mCompositionEngine->present(refreshArgs);
    ......
}
// CompositionEngine.cpp
void CompositionEngine::present(CompositionRefreshArgs& args) {
    ATRACE_CALL();
    ......
    for (const auto& output : args.outputs) {
        output->present(args);
    }
    ......
}
// Output.cpp
void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
    ATRACE_CALL();
    ......
    updateAndWriteCompositionState(refreshArgs);//告知HWC service有哪些layer要参与合成
    ......
    beginFrame();
    prepareFrame();
    ......
    finishFrame(refreshArgs);
    postFramebuffer();//这里会调用到HWC service的接口去present display合成画面
}
void Output::postFramebuffer() {
    ......
    auto frame = presentAndGetFrameFences();
    ......
}

compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
    compositionengine::Output::FrameFences result;
    if (getState().usesClientComposition) {
        result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
    }
    return result;
}

然后下面就涉及到HWC Service了。这个一般厂商会保密,所以一般没有公开的资料。
沿着代码逻辑学习了应用是如何申请到画布、使用android的View系统如何绘图、绘图完成后如何提交buffer以及buffer提交以及Surfaceflinger如何处理。但本章所述的逻辑均是指通过android的View系统绘图的过程,也可以称其为hwui绘图流程,从上面代码流程可以知道,hwui的绘图流程是被vsync信号触发的,开始于vsync信号到达UI线程调用performTraversals函数, hwui的画面更新是被vsync信号驱动的。

参考链接:
Android图形渲染原理下
Android图形系统(七)-app请求SurfaceFlinger创建Surface过程
Android图形系统(十)-SurfaceFlinger启动及图层合成送显过程
Android应用程序请求SurfaceFlinger服务渲染Surface的过程分析
Android画面显示流程分析(2)
Android画面显示流程分析(4)
Android 12(S) 图像显示系统 - createSurface的流程(五)

上一篇下一篇

猜你喜欢

热点阅读