Android Graphics Framework

Android系统图形框架

Android系统图形框架由下往上主要的包括HAL(HWComposer和Gralloc两个moudle),SurfaceFlinger(BufferQueue的消费者),WindowManagerService(窗口管理者),View(BufferQueue的生产者)四大模块。

  • HAL: 包括HWComposer和Gralloc两个moudle,Android N上由SurfaceFlinger打开,因此在同一进程。 gralloc 用于BufferQueue的内存分配,同时也有fb的显示接口,HWComposer作为合成SurfaceFlinger里面的Layer,并显示(通过gralloc的post函数)
  • SurfaceFlinger也叫LayerFlinger,作为Layer的管理着,同是也是BufferQueue的消费者,当每个Layer的生产者draw完完整的一帧时,会通知SurfaceFlinger,通知的方式采用BufferQueue。
  • WindowManagerService: 作为Window的管理者,掌管着计算窗口大小,窗口切换等任务,同时也会将相应的参数设置给SurfaceFlinger,比如Window的在z-order,和窗口的大小。
  • View: 作为BufferQueue的生产者,没当执行lockCanvas->draw->unlockCanvas,之后会存入一帧数据进入BufferQueue中。
    Android Graphics Framework_第1张图片
    图片.png

1、低级别组件

  • BufferQueue 和 gralloc。
    BufferQueue 将可生成图形数据缓冲区的组件(生产者)连接到接受数据以便进行显示或进一步处理的组件(消费者)。通过供应商专用 HAL 接口实现的 gralloc 内存分配器将用于执行缓冲区分配任务
  • SurfaceFlinger、Hardware Composer 和虚拟显示屏。
    SurfaceFlinger 接受来自多个源的数据缓冲区,然后将它们进行合成并发送到显示屏。Hardware Composer HAL (HWC) 确定使用可用硬件合成缓冲区的最有效的方法,虚拟显示屏使合成输出可在系统内使用(录制屏幕或通过网络发送屏幕)。
  • Surface、Canvas 和 SurfaceHolder。
    Surface 可生成一个通常由 SurfaceFlinger 使用的缓冲区队列。当渲染到 Surface 上时,结果最终将出现在传送给消费者的缓冲区中。Canvas API 提供一种软件实现方法(支持硬件加速),用于直接在 Surface 上绘图(OpenGL ES 的低级别替代方案)。与视图有关的任何内容均涉及到 SurfaceHolder,其 API 可用于获取和设置 Surface 参数(如大小和格式)。
  • EGLSurface 和 OpenGL ES。
    OpenGL ES (GLES) 定义了用于与 EGL 结合使用的图形渲染 API。EGI 是一个规定如何通过操作系统创建和访问窗口的库(要绘制纹理多边形,请使用 GLES 调用;要将渲染放到屏幕上,请使用 EGL 调用)。此页还介绍了 ANativeWindow,它是 Java Surface 类的 C/C++ 等价类,用于通过原生代码创建 EGL 窗口表面。
  • Vulkan。
    Vulkan 是一种用于高性能 3D 图形的低开销、跨平台 API。与 OpenGL ES 一样,Vulkan 提供用于在应用中创建高质量实时图形的工具。Vulkan 的优势包括降低 CPU 开销以及支持 SPIR-V 二进制中间语言。

1.1 Gralloc

gralloc 用于BufferQueue的内存分配,同时也有fb的显示接口

  • gralloc_alloc:用于分配一个显示显示缓冲区,分配好只有会返回缓冲区的handle(缓冲区buffer不会拷贝,所有的操作都是传handle)
static int gralloc_alloc_buffer(alloc_device_t* dev,
        size_t size, int /*usage*/, buffer_handle_t* pHandle)
{
    int err = 0;
    int fd = -1;
    size = roundUpToPageSize(size);

    fd = ashmem_create_region("gralloc-buffer", size);  // 创建匿名共享内存
    if (fd < 0) {
        ALOGE("couldn't create ashmem (%s)", strerror(-errno));
        err = -errno;
    }
    if (err == 0) {
        private_handle_t* hnd = new private_handle_t(fd, size, 0);
        gralloc_module_t* module = reinterpret_cast(
                dev->common.module);
        err = mapBuffer(module, hnd); // 同时将创建好的内存映射进入当前进程,返回handle
        if (err == 0) {
            *pHandle = hnd;
        }
    }
    return err;
}
  • gralloc_free :释放缓冲区内存
  • fb_post :更新fb显示

1.2 BufferQueue

  • BufferQueue 类是 Android 中所有图形处理操作的核心。它的作用很简单:将生成图形数据缓冲区的一方(生产方)连接到接受数据以进行显示或进一步处理的一方(消耗方)。几乎所有在系统中移动图形数据缓冲区的内容都依赖于 BufferQueue。
  • BufferQueue 包含将图像流生产方与图像流消耗方结合在一起的逻辑。图像生产方的一些示例包括由相机 HAL 或 OpenGL ES 游戏生成的相机预览。图像消耗方的一些示例包括 SurfaceFlinger 或显示 OpenGL ES 流的另一个应用,如显示相机取景器的相机应用。
  • BufferQueue 永远不会复制缓冲区内容(移动如此多的数据是非常低效的操作)。相反,缓冲区始终通过句柄进行传递。
  • 生产方和消耗方可以存在于不同的进程中。目前,消耗方始终创建和拥有数据结构。在旧版本的 Android 中,只有生产方才进行 Binder 处理(即生产方可能在远程进程中,但消耗方必须存在于创建队列的进程中)。Android 4.4 和更高版本已发展为更常规的实现。


    Android Graphics Framework_第2张图片
    图片.png

1.3 BufferQueue生产者与消费者分析

当应用add一个window到WMS时,WMS会调用SurfaceFlinger为这个window创建一个BufferQueue,BufferQueue的消费者留在了SurfaceFlinger中,而生产者会返回到View中,View中采用Canvas或者GL绘图,用于消费者

    // 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,
                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingConfiguration,
                mSurface);            
    }

其中的
mWindow即每个应用窗口所创建的window,和ActivityRecord、DecorView一一对应
mSurface即为当前这个Layer的BufferQueue生产者

void Layer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp producer;
    sp consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);
    mProducer = new MonitoredProducer(producer, mFlinger);
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName,
            this);
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setContentsChangedListener(this);
    mSurfaceFlingerConsumer->setName(mName);

#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
#else
    mProducer->setMaxDequeuedBufferCount(2);
#endif

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

createBufferQueue即为创建BufferQueue的地方,同时通过setContentsChangedListener将this注册到消费者中去,当生产者mSurface有新的帧生成后,会通知到Layer中的onFrameAvailable

// Layer.cpp
void Layer::onFrameAvailable(const BufferItem& item) {
    // Add this buffer from our internal queue tracker
    { // Autolock scope
        Mutex::Autolock lock(mQueueItemLock);

        mQueueItems.push_back(item);
        android_atomic_inc(&mQueuedFrames);

        // Wake up any pending callbacks
        mLastFrameNumberReceived = item.mFrameNumber;
        mQueueItemCondition.broadcast();
    }

    mFlinger->signalLayerUpdate();
}

2、 SurfaceFlinger

  • 管理Layer的创建与销毁,同时单个Layer又要接收来自WMS的设置参数(setLayer, setPosition , setSize setAlpha, createLayer, removeLayer等)
  • Layer的可见区域计算,合成Layer
  • 渲染合成图像到fb
  • 管理VSYNC信号
  • 创建BufferQueue用于SurfaceFlinger的缓冲区


    Android Graphics Framework_第3张图片
    图片.png

2.1 创建BufferQueue用于SurfaceFlinger中的缓冲区(非Layer中的BufferQueue)

void SurfaceFlinger::init() {
    for (size_t i=0 ; i token = mBuiltinDisplays[i];

            sp producer;
            sp consumer;
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());  // 创建BufferQueue

            sp fbs = new FramebufferSurface(*mHwc, i,
                    consumer);  // 消费者放入FramebufferSurface
            int32_t hwcId = allocateHwcDisplayId(type);
            sp hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig()); // 生产者是DisplayDevice,本质是合成只有的图像

            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                ALOGD("marking display %zu as acquired/unblanked", i);
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);    
    }
}

2.2 Layer更新

前面讲BufferQueue时,每当Layer中有新的buffer准备好了,一定会通知相应Layer的onFrameAvailable,从而通过signalLayerUpdate通知SurfaceFlinger,这就是开始处理Layer的入口

void SurfaceFlinger::signalLayerUpdate() {
    mEventQueue.invalidate();
}
void MessageQueue::invalidate() {
    mEvents->requestNextVsync();
}

但是onMessageReceived并不会立即收到消息去执行handleMessageTransaction、handleMessageRefresh,而是等到下一个VSYNC信号到来

void SurfaceFlinger::onMessageReceived(int32_t what) {
    ATRACE_CALL();
    switch (what) {
        case MessageQueue::INVALIDATE: {
            bool refreshNeeded = handleMessageTransaction();
            refreshNeeded |= handleMessageInvalidate();
            refreshNeeded |= mRepaintEverything;
            if (refreshNeeded) {
                // Signal a refresh if a transaction modified the window state,
                // a new buffer was latched, or if HWC has requested a full
                // repaint
                signalRefresh();
            }
            break;
        }
        case MessageQueue::REFRESH: {
            handleMessageRefresh();
            break;
        }
    }
}

2.3 VSYNC信号

  • SurfaceFlinger负责在收到的硬件VSYNC信号,通知EventThread,EventThread存放着所有注册过的Connection,只要有Connection存在,就会触发相应的事件,Looper中会响应事件并回调


    Android Graphics Framework_第4张图片
    图片.png
  • Choreographer的VSYNC信号和SurfaceFlinger接收VSYNC信号原理一样,都是通过注册一个Connection监听事件


    Android Graphics Framework_第5张图片
    图片.png

2.4 Layer可见性计算与合成显示

void SurfaceFlinger::handleMessageRefresh() {
    ATRACE_CALL();

    nsecs_t refreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);

    preComposition(); //
    rebuildLayerStacks();  //  计算可见区域,主要的依据就是z-order大的覆盖有重叠区域z-order小的
    setUpHWComposer();
    doDebugFlashRegions();
    doComposition();  // 合成图像,并调用swapBuffers,这样消费者FramebufferSurface就会被回调onFrameAvailable
    postComposition(refreshStartTime);
}

消费者FramebufferSurface收到onFrameAvailable后就会将新的图像post到fb(通过gralloc的post函数)

// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {
    sp buf;
    sp acquireFence;
    status_t err = nextBuffer(buf, acquireFence);
    if (err != NO_ERROR) {
        return;
    }
    err = mHwc.fbPost(mDisplayType, acquireFence, buf);  // 调用gralloc的post
}

3、WindowManagerService框架

Android Graphics Framework_第6张图片
图片.png

职责

  • 计算窗口大小

  • 计算窗口Z轴位置

  • 管理输入法窗口

  • 管理壁纸窗口

  • 执行窗口切换

3.1 addWindow

在Activity的启动中当执行到performLaunchActivity

    // ActivityThread.java
    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        ActivityClientRecord r = mActivities.get(token);
        r = performResumeActivity(token, clearHide, reason);
        if (r != null) {
            final Activity a = r.activity;
            boolean willBeVisible = !a.mStartedActivity;
            if (r.window == null && !a.mFinished && willBeVisible) {
                r.window = r.activity.getWindow(); //  Window指的是PhoneWindow,在performLaunchActivity中attch函数中创建
                View decor = r.window.getDecorView();  // decor是在onCreate中用户主动调用setContentView时创建
                decor.setVisibility(View.INVISIBLE);
                ViewManager wm = a.getWindowManager();  // 实质是ViewManagerImpl
                WindowManager.LayoutParams l = r.window.getAttributes();
                a.mDecor = decor; 
                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  //APP的type都是TYPE_BASE_APPLICATION
                l.softInputMode |= forwardBit;
                if (r.mPreserveWindow) {
                    a.mWindowAdded = true;
                    r.mPreserveWindow = false;
                    // Normally the ViewRoot sets up callbacks with the Activity
                    // in addView->ViewRootImpl#setView. If we are instead reusing
                    // the decor view we have to notify the view root that the
                    // callbacks may have changed.
                    ViewRootImpl impl = decor.getViewRootImpl();
                    if (impl != null) {
                        impl.notifyChildRebuilt();
                    }
                }
                if (a.mVisibleFromClient && !a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);   // 向WindowManagerGlobal中添加当前Activity的DecorView
                }
    }

decor是在onCreate中用户主动调用setContentView时创建
Window指的是PhoneWindow,在performLaunchActivity中attch函数中创建
ActivityClientRecord是在App进程中的和AMS中的ActivityRecord一一对应的对象

WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);

            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }
        root.setView(view, wparams, panelParentView);
    }

可以看出WindowManagerGlobal是管理view(DecorView),ViewRootImpl,参数的管家,他们都是一对一的关系

ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                } 
}

开始向WMS添加当前mWindow(W),mWindow继承于IWindow.Stub,也是个binder的对象,WMS可以通过这个binder回调ViewRootImpl

    WindowManagerService.java
    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
            InputChannel outInputChannel) {
    
            boolean addToken = false;
            WindowToken token = mTokenMap.get(attrs.token);
            AppWindowToken atoken = null;
            boolean addToastWindowRequiresToken = false;
            ...
            WindowState win = new WindowState(this, session, client, token,
                    attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
                    mPolicy.adjustWindowParamsLw(win.mAttrs);   // new 一个新的WindowState
            win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

            res = mPolicy.prepareAddWindowLw(win, attrs);
            if (res != WindowManagerGlobal.ADD_OKAY) {
                return res;
            }

            final boolean openInputChannels = (outInputChannel != null
                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
            if  (openInputChannels) {
                // 创建一个Input的双向进程间管道,并将read端的fd通过outInputChannel返回,用于ViewRootImpl中创建Input的监听Receiver,管道的write端registerInputChannel注册进入了InputDispatcher,然后加入了InputDispatcher线程的Looper,用于发送事件信号
                // 这就成功的建立了InputDispatcher与当前应用ViewRootImpl进程间双向通讯
                win.openInputChannel(outInputChannel);                    
            }
                    
            if (addToken) {
                mTokenMap.put(attrs.token, token);
            }
            win.attach();
            mWindowMap.put(client.asBinder(), win); // 将创建的WindowState存入WMS
            
            if (focusChanged) {
                mInputMonitor.setInputFocusLw(mCurrentFocus, false /*updateInputWindows*/);   // 检查焦点窗口是否发生变化,如果发生了变化就要通知InputDispatcher更新焦点窗口
            }
            mInputMonitor.updateInputWindowsLw(false /*force*/);  // 将WMS中所有的InputWindowHandles都更新到InputDispatcher中去,方便InputDispatcher根据触摸坐标寻找相应的window

3.2 relayoutWindow


ViewRootImpl.java

    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

scheduleTraversals()中利用Choreographer向SurfaceFlinger注册一个vsync信号接收回调,收到回调后会执行performTraversals(),这个函数是对view进行measure,layout,draw的核心函数,当执行performTraversals时发生以下条件事会调用WMS的relayoutWindow,通知WMS window发生的变化

  • 第一次performTraversals调用的时候
  • 当window需要resize(改变尺寸)的时候
  • view可见性发生变化时
  • 其他一些条件
ViewRootImpl.java
private void performTraversals() {
        if (mFirst || windowShouldResize || insetsChanged ||
                viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
            relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
        }
}

3.3 SurfaceFlinger Z order顺序确定

openGlobalTransaction --> setLayer --> closeGlobalTransaction -->closeGlobalTransactionImpl --> setTransactionState --> setClientStateLocked --> mCurrentState.layersSortedByZ.add
layersSortedByZ是一个LayerVector的结构,继承于SortedVector,在add的同时会用二分法则排序插入
Z order 的值越大显示越靠前,但是最终显示的判定还要结合layer的可见区域Region visibleRegion来显示,一般情况可见区域只有Navgation Bar + Status Bar + Activity,有些软件播放视频会全屏,那么Navgation Bar + Status Bar 也就不可见了


    SurfaceComposerClient::openGlobalTransaction();
    control->setLayer(0x40000000);
    SurfaceComposerClient::closeGlobalTransaction();

4、 窗口(Window)的结构

Android Graphics Framework_第7张图片
图片.png

ViewRootImpl是一个虚拟根View,用来控制窗口的渲染,以及用来与WindowManagerService、SurfaceFlinger通信

DecorView是窗口的真正根View,用户在Activity的onCreate中setContentView中创建

ContentView描述窗口的主题风格

4.1 ViewRootImpl

Window的虚拟根View,一个Aactivity对应一个DecorView,对应一个ActivityClientRecord,对应一个ViewRootImpl,ViewRootImpl的作用:

  • 与WMS交互:将window(W:继承于IWindow.Stub)加入到WMS(addToDispaly)

  • 与SurfaceFlinger交互: 因为ViewRootImpl中layout,measure,draw是Surface的的生产者,因此当draw完成以后SurfaceFlinger回取出相应的buffer进行合成显示

  • 注册一个InputEventReceiver :基于WMS返回的InputChannel创建一个Callback,用于监听输入事件mInputEventReceiver一旦被创建,就已经在监听输入事件了

  • performTraversals() : 执行画图三个重要操作measure,layout,draw,主要是在scheduleTraversals()中用Choreographer注册系统刷新下一帧回调。

  • Choreographer:当window有任何改变的时候就会利用Choreographer注册一个vsync信号回调,比如尺寸,参数变化,可见性变化,范围改变,保证显示实时更新

5、参考

SurfaceFlinger Z order顺序确定

你可能感兴趣的:(Android Graphics Framework)