Android 图形显示系统 SurfaceFlinger 与图像输出

字节流动

共 32385字,需浏览 65分钟

 ·

2022-05-30 16:32

`OpenGL ES`与`EGL`

`OpenGL`

一般OpenGL被认为是一个API(Application Programming Interface, 应用程序编程接口),包含了一系列可以操作图形、图像的函数。然而,OpenGL本身并不是一个API,它仅仅是一个由Khronos组织制定并维护的规范(Specification)。

OpenGL规范严格规定了每个函数该如何执行,以及它们的输出值。至于内部具体每个函数是如何实现的,将由OpenGL库的开发者自行决定

实际的OpenGL库的开发者通常是显卡的生产商

OpenGL ES(OpenGL for Embedded Systems) 是从OpenGL裁剪的定制而来的,去除了一些复杂图元等许多非绝对必要的特性

OpenGL还是很值得学习的,大家可以参考:LearnOpenGL教程的中文翻译

`EGL`

我们知道OpenGL ES定义了一个渲染图形的API,但没有定义窗口系统。

为了让OpenGL ES能够适合各种平台,OpenGL ES需要与一个知道如何通过操作系统创建和访问窗口的库结合使用

Android中的这个库就是EGL。(没有什么问题是不能通过增加一个中间层来解决的,有的话那就再增加一个。。。。。)

整体结构如下(网上盗图):

image

`EGL`的用法

使用EGL绘制的一般步骤如下:

  • 获取 EGL Display 对象:eglGetDisplay()

  • 初始化与 EGLDisplay 之间的连接:eglInitialize()

  • 获取 EGLConfig 对象:eglChooseConfig()

  • 创建 EGLContext 实例:eglCreateContext()

  • 创建 EGLSurface 实例:eglCreateWindowSurface()

  • 连接 EGLContext 和 EGLSurface:eglMakeCurrent()

  • 使用 OpenGL ES API 绘制图形:gl_*()

  • 切换 front buffer 和 back buffer 送显:eglSwapBuffer()

  • 断开并释放与 EGLSurface 关联的 EGLContext 对象:eglRelease()

  • 删除 EGLSurface 对象

  • 删除 EGLContext 对象

  • 终止与 EGLDisplay 之间的连接

`Android`中的封装

前面的章节我们介绍过,无论开发者使用什么渲染API,一切内容都会渲染到Surface

  • 此处的Surface指的是framework/native/libs/gui/Surface.cpp对应的业务逻辑

SurfaceFlinger以消费者的角色获取到显示数据后,会开始进行渲染操作,在过程中也存在一个Surface

  • 定义在framework/native/services/surfaceflinger/RenderEngine/Surface.cpp

  • 这个Surface便是对EGL接口的调用封装,我们看下这个类的定义:

    Surface::Surface(const RenderEngine& engine)
        : mEGLDisplay(engine.getEGLDisplay()), mEGLConfig(engine.getEGLConfig()) {
        ...
    }
    Surface::~Surface() {
        setNativeWindow(nullptr);
    }
    void Surface::setNativeWindow(ANativeWindow* window) {
        ...
        if (mWindow) {
            mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mWindow, nullptr);
        }
    }
    void Surface::swapBuffers() const {
        if (!eglSwapBuffers(mEGLDisplay, mEGLSurface)) {
            ...
        }
    }
    EGLint Surface::queryConfig(EGLint attrib) const {
        EGLint value;
        if (!eglGetConfigAttrib(mEGLDisplay, mEGLConfig, attrib, &value)) {
            value = 0;
        }
        return value;
    }
    EGLint Surface::querySurface(EGLint attrib) const {
        EGLint value;
        if (!eglQuerySurface(mEGLDisplay, mEGLSurface, attrib, &value)) {
            value = 0;
        }
        return value;
    }

接口定义结合上面EGL的知识应该很容易理解,下面我们开始SurfaceFlinger学习吧

`SurfaceFlinger`的启动过程

Android 4.4开始SurfaceFlinger服务运行在一个独立的守护进程中(以前在SystemServer中),这样系统的图像绘制性能会得到一定的提升。frameworks/native/services/surfaceflinger/surfaceflinger.rc中关于SurfaceFlinger的定义如下:

service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    ...

可以看到surfaceflinger放到了core组里,这个组的服务会在系统初始化时启动。SurfaceFlinger启动的入口函数main()代码如下:

int main(intchar**) {
    ...
    // 启动 Gralloc 服务
    startGraphicsAllocatorService();
    // 设置当前Binder服务可连接最大线程数
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    // 通过 startThreadPool 通知 Binder 驱动当前线程已准备完成
    sp ps(ProcessState::self());
    ps->startThreadPool();
    // 初始化 SurfaceFlinger
    sp flinger = new SurfaceFlinger();
    // 调整进程优先级为 PRIORITY_URGENT_DISPLAY
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
    // 调整调度策略,将其设置为前台进程
    // 这两种标志涉及了内核的 完全公平调度算法,感兴趣的同学可以百度一下
    // 在这里的目的是保证 SurfaceFlinger 的较高优先级,方便快速响应更新图像的请求
    set_sched_policy(0, SP_FOREGROUND);
    ...
    // 注册 Service 前的初始化部分
    flinger->init();
    // 注册 SurfaceFlinger 服务
    sp sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
                   IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
    // 注册 GpuService 服务
    sp gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
    // 启动 DisplayService 服务
    startDisplayService(); // dependency on SF getting registered above
    ...
    // run surface flinger in this thread
    flinger->run();
    return 0;
}

main()方法中注释比较详细就不细说了,方法总结下来有三点:

  • 初始化GraphicsAllocatorServiceDisplayServiceGpuService服务

  • set_sched_policysched_setscheduler设置进程优先级

  • SurfaceFlinger对象的初始化以及initrun方法的调用

SurfaceFlinger的初始化过程设计的模块比较多,我们先简单看下类关系图: 

image

`SurfaceFlinger`对象初始化

SurfaceFlinger的类定义如下:

class SurfaceFlinger : public BnSurfaceComposer,
                       public PriorityDumper,
                       private IBinder::DeathRecipient,
                       private HWC2::ComposerCallback
{}
  • BnSurfaceComposer类:类图中该类实现的是ISurfaceComposer接口,而ISurfaceComposer又是一套定义好的Binder

    • `Binder`篇提到过,当出现`Bn*`开头的类就可以把它看做`Binder服务类`了,所以`SurfaceFlinger`这里是作为一个`Binder`服务对象

    • 上一篇在`SurfaceSession`初始化时,`SurfaceComposerClient`对象就是通过`ServiceManager`获取了`SurfaceFlinger`服务

    • 然后通过服务提供的`createConnection()`方法获取了`ISurfaceComposerClient`对象,也就是上面类图中提到的`Client`类

  • HWC2::ComposerCallback类:面向底层硬件状态的监听回调接口,包括

    • `onHotplugReceived`,显示屏热插拔事件回调

    • `onRefreshReceived`,通知刷新的回调

    • `onVsyncReceived`,`VSYNC`信号接收回调

SurfaceFlinger的构造方法如下:

SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) {
    ALOGI("SurfaceFlinger is starting");
    // 初始化 vsync 信号相关的 offset
    vsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::vsyncEventPhaseOffsetNs>(1000000);
    sfVsyncPhaseOffsetNs = getInt64< ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::vsyncSfEventPhaseOffsetNs>(1000000);
    ...
    // 确认主屏幕方向
    V1_1::DisplayOrientation primaryDisplayOrientation =
        getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
            V1_1::DisplayOrientation::ORIENTATION_0);
    switch (primaryDisplayOrientation) {
        case V1_1::DisplayOrientation::ORIENTATION_90:
            mPrimaryDisplayOrientation = DisplayState::eOrientation90;
            break;
        ...
    }
    // 初始化主屏幕的 DispSync 对象,这个对象与 vsync 信号分发有关系
    mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
    ...
    // 读取 Prop 进行一些基础属性的设置
    // 是否启动 HWC 虚拟显示
    property_get("debug.sf.enable_hwc_vds", value, "0");
    mUseHwcVirtualDisplays = atoi(value);
    // 是否开启三级缓冲
    property_get("ro.sf.disable_triple_buffer", value, "1");
    mLayerTripleBufferingDisabled = atoi(value);
    ...
}

构造方法中主要的动作是mPrimaryDispSync.init()操作,余下基本都是对一些变量的初始化。mPrimaryDispSync的类型是DispSync,这个对象主要是对VSYNC信号进行调整,然后转发给appsf,等下完善。

随着SurfaceFlinger对象创建后的初次引用,也会调用到对象的onFirstRef()方法:

void SurfaceFlinger::onFirstRef()
{
    mEventQueue->init(this);
}

方法中执行了MessageQueue对象的init()方法,这个MessageQueueSurfaceFlinger自己定义的消息队列,MessageQueue相关的知识对整个SurfaceFlinger业务逻辑的理解有着关键作用,下面细讲

铺垫内容

了解这部分的内容有助于更好的理解SurfaceFlinger后面的init()run()方法

消息和事件分发-`MessageQueue`

MessageQueueSurfaceFlinger中用与消息和事件分发的对象,先看下主要的成员变量:

class MessageQueue{
    ...
    sp mFlinger;            // 指向 SurfaceFlinger 对象
    sp mLooper;                     // 实现消息机制的 Looper 对象
    android::EventThread* mEventThread;     // 关联的 EventThread 对象
    sp mEvents;
    gui::BitTube mEventTube;
    sp mHandler;                   // 消息处理 Handler
    ...
}

MessageQueue的成员变量中

  • mLooper是一个指向Looper类的指针,它实现了一套完整的消息处理机制

  • mEventThread指向一个EventThread对象,主要作用是分发VSYNC信号

前面提到在SurfaceFlinger中会调用MessageQueue对象的init()方法,代码如下:

void MessageQueue::init(const sp& flinger) {
    mFlinger = flinger;
    mLooper = new Looper(true);
    mHandler = new Handler(*this);
}

init()方法中

  • 创建了Handler对象。此处的HandlerMessageQueue中定义的一个内部类,定义如下:

    class MessageQueue final : public android::MessageQueue {
        class Handler : public MessageHandler {
            enum { eventMaskInvalidate = 0x1, eventMaskRefresh = 0x2, eventMaskTransaction = 0x4 };
            MessageQueue& mQueue;
            int32_t mEventMask;
        ...
        };
    }
    • Handler对象中主要处理三种消息:eventMaskInvalidateeventMaskRefresheventMaskTransaction

  • 创建了Looper对象。关于native层的Looper对象在Android 消息机制中已经介绍过,会通过epoll开启一个消息监听,具体可以看这个直达入口

init()完成后,MessageQueue就可以通过waitMessage()来等待消息,代码如下:

void MessageQueue::waitMessage() {
    do {
        IPCThreadState::self()->flushCommands();
        int32_t ret = mLooper->pollOnce(-1);    // 尝试读取消息,-1 表示永远阻塞
        switch (ret) {
            case Looper::POLL_WAKE:             // poll 被唤醒
            case Looper::POLL_CALLBACK:
                continue;
            case Looper::POLL_ERROR:            // poll 发送错误
                ALOGE("Looper::POLL_ERROR");
                continue;
            case Looper::POLL_TIMEOUT:          // poll 超时
                // timeout (should not happen)
                continue;
            default:
                // should not happen
                ALOGE("Looper::pollOnce() returned unknown status %d", ret);
                continue;
        }
    } while (true);
}

waitMessage()是一个无限循环,它的主要作用是循环调用Looper类的pollOnce()从消息队列中读取消息

需要注意的是waitMessage()中并没有消息的处理过程,而且没有明显的消息处理方法的调用,那么具体的消息处理在哪里?  
消息的处理涉及EventThread类,在MessageQueue中通过setEventThread()方法进行关联,代码如下:

void MessageQueue::setEventThread(android::EventThread* eventThread) {
    if (mEventThread == eventThread) {
        return;
    }
    if (mEventTube.getFd() >= 0) {
        mLooper->removeFd(mEventTube.getFd());
    }
    mEventThread = eventThread;
    // 创建连接
    mEvents = eventThread->createEventConnection();
    mEvents->stealReceiveChannel(&mEventTube);
    // 重点是这个方法
    mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver, this);
}

setEventThread()方法中

  • 先调用了EventThread对象的createEventConnection()方法来创建一个连接

    sp EventThread::createEventConnection() const {
        // 创建 Connection 对象,同时会调用它的 onFirstRef 方法
        return new Connection(const_cast(this));
    }
    // Connection 的构造方法,初始化 BitTube mChannel 对象,并设置 mEventThread
    EventThread::Connection::Connection(EventThread* eventThread)
          : count(-1), mEventThread(eventThread), mChannel(gui::BitTube::DefaultSize) {}
    // Connection 对象的 onFirstRef 方法会将自己添加到 EventThread 中的 mDisplayEventConnections 中
    void EventThread::Connection::onFirstRef() {
        // NOTE: mEventThread doesn't hold a strong reference on us
        mEventThread->registerDisplayEventConnection(this);
    }
    // 将 connection 对象添加到 mDisplayEventConnections 监听集合中
    status_t EventThread::registerDisplayEventConnection(
            const sp& connection) {
        std::lock_guard<std::mutex> lock(mMutex);
        // 添加到 mDisplayEventConnections 集合中
        mDisplayEventConnections.add(connection);
        mCondition.notify_all();
        return NO_ERROR;
    }
    • createEventConnection()方法返回的是一个IDisplayEventConnection对象mEvents

    • EventThread是一个线程类,用于分发VSYNC消息,

    • EventThread内部会维护一个gui::BitTube mChannel用于通信,创建过程如下:

  • 接着通过IDisplayEventConnection对象的stealReceiveChannel()方法

    • 该方法主要是设置mEventTube对象的mReceiveFdmEventTube的类型是BitTube

    • BitTube对象中包含一对FdmReceiveFdmSendFd,初始化时会通过socketpair()创建全双工通信

  • 最后通过Looper类的addFd()方法将mReceiveFd添加到epoll监听列表中,并且传入了MessageQueue::cb_eventReceiver作为事件的回调方法

    int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
        MessageQueue* queue = reinterpret_cast(data);
        return queue->eventReceiver(fd, events);
    }
    int MessageQueue::eventReceiver(int /*fd*/int /*events*/) {
        ssize_t n;
        DisplayEventReceiver::Event buffer[8];
        while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
            for (int i = 0; i < n; i++) {
                if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
                    mHandler->dispatchInvalidate();
                    break;
                }
            }
        }
        return 1;
    }
    • 方法最后会调用mHandler->dispatchInvalidate();方法,这就会涉及到Handler的处理逻辑

    • 回调方法如下:

我们看下Handler中的处理逻辑:

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;
    }
}

调用了SurfaceFlingeronMessageReceived()方法,这里才是真正处理消息的地方,后面细讲这个方法哈

我们先看下EventThread

消息和事件分发-`EventThread`

EventThread的继承关系如下:

class EventThread : public android::EventThread, private VSyncSource::Callback {
}

需要注意的是VSyncSource::Callback类,它提供了一个onVSyncEvent()的回调方法

EventThread的构造方法如下(精简版):

EventThread::EventThread(...){
    ...
    // 创建线程并开始执行,核心业务通过 threadMain() 方法来完成
    mThread = std::thread(&EventThread::threadMain, this);
    // 设置一些线程的名称和优先级
    pthread_setname_np(mThread.native_handle(), threadName);
    ...
    // 设置调度策略为 SP_FOREGROUND
    set_sched_policy(tid, SP_FOREGROUND);
}

构造方法中启动了一个线程,这个线程的执行逻辑在threadMain()方法中:

void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
    std::unique_lock<std::mutex> lock(mMutex);
    // mKeepRunning 只会在析构函数中置为 false
    while (mKeepRunning) {
        DisplayEventReceiver::Event event;
        Vector > signalConnections;
        // 通过 waitForEventLocked() 循环等待事件
        // 方法中会通过 mCondition 对象的 wait() 方法进行等待
        signalConnections = waitForEventLocked(&lock, &event);
        const size_t count = signalConnections.size();
        for (size_t i = 0; i < count; i++) {
            const sp& conn(signalConnections[i]);
            // 通过 postEvent() 将事件通知到到 MessageQueue
            status_t err = conn->postEvent(event);
            ...
        }
    }
}

threadMain()方法中的重点是:

  • waitForEventLocked()方法会循环等待消息(也就是VSYNC信号),并获取到注册的Connection对象列表

  • 当接收到信号后,通过Connection对象的postEvent()将数据发送到MessageQueue

  • 此时MessageQueue中的Looper会检测到数据输入,然后通知回调MessageQueuecb_eventReceiver()方法

信号分发过程

前面讲过VSYNC信号由HWC产生,为了方便接收,HWComposer提供了一个HW2::ComposerCallback用于监听消息

  • 定义如下:

    class ComposerCallback {
     public:
        virtual void onHotplugReceived(...) 0;
        virtual void onRefreshReceived(...) 0;
        virtual void onVsyncReceived(...) 0;
        virtual ~ComposerCallback() = default;
    };
  • 从前面类关系图中可以发现,SurfaceFlinger继承该类,我们重点关注onVsyncReceived()方法

SurfaceFlinger::onVsyncReceived()方法如下:

void SurfaceFlinger::onVsyncReceived(...) {
    ...
    bool needsHwVsync = false;
    { // Scope for the lock
        Mutex::Autolock _l(mHWVsyncLock);
        if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
            // 通过 addResyncSample 来进一步分发信号
            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
        }
    }
    ...
}

onVsyncReceived()方法调用mPrimaryDispSync对象的addResyncSample()方法来进一步分发VSYNC信号

  • mPrimaryDispSync对象的类型是DispSync,这个类比较简单,核心是它的成员变量mThread,类型是DispSyncThread

  • DispSyncThread是一个线程类,在DispSync对象初始化时进行创建,代码如下:

    DispSync::DispSync(const char* name)
      : mName(name), mRefreshSkipCount(0), mThread(new DispSyncThread(name)) {}
  • 前面提到过,在SurfaceFlinger的构造方法中会调用DispSync对象的init()进行DispSyncThread线程的启动

    void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
        ...
        mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
        ...
    }

addResyncSample()方法中最重要的是执行了DispSyncThread对象的updateModel()方法:

    void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
        ... // 省略和 VSYNC 信号相关的一些赋值操作
        // 重点是此处通过 Conditon.signal() 来唤醒 DispSyncThread 线程
        mCond.signal();
    }

DispSyncThread线程的执行函数如下:

    virtual bool threadLoop() {
        ...
        while (true) {
            Vector callbackInvocations;
            nsecs_t targetTime = 0;
            { // Scope for lock
                ...
                if (now < targetTime) {
                    if (targetTime == INT64_MAX) {
                        err = mCond.wait(mMutex);
                    } else {
                        err = mCond.waitRelative(mMutex, targetTime - now);
                    }
                    ...
                }
                now = systemTime(SYSTEM_TIME_MONOTONIC);
                ...
                // 取得 Callback 列表
                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }
            // 通过 fireCallbackInvocations() 调用
            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }
        return false;
    }

threadLoop()中大部分是比较和计算时间,决定是否要发送信号

  • 如果没有信号发送,就会在mCond上等待

    • 这也就是updateModel()中需要调用mCondsignal()来唤醒的原因

  • 当确认需要发送信号时,先通过gatherCallbackInvocationsLocked()获取本次VSYNC信号回调通知的监听对象

    • 这些监听对象都是通过addEventListener()方法进行添加

  • 最后,通过fireCallbackInvocations()方法一次调用列表中所有对象的onDispSyncEvent()方法

    void fireCallbackInvocations(const Vector& callbacks) {
        if (kTraceDetailedInfo) ATRACE_CALL();
        for (size_t i = 0; i < callbacks.size(); i++) {
            callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
        }
    }
    • 查看CallbackInvocation结构就会发现,回调接口的类型是DispSync::Callback

那么SurfaceFlinger中哪几个类实现了DispSync::Callback呢?  
聪明的我们会发现,SurfaceFlinger中的DispSyncSource继承了这个类,而且重点是下面部分的代码:

class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
    ...
    void setVSyncEnabled(bool enable) override {
        Mutex::Autolock lock(mVsyncMutex);
        if (enable) {
            status_t err = mDispSync->addEventListener(mName, mPhaseOffset, static_cast(this));
            ...
        } else {
            status_t err = mDispSync->removeEventListener(static_cast(this));
            ...
        }
        mEnabled = enable;
    }
    ...
private:
    virtual void onDispSyncEvent(nsecs_t when) {
        VSyncSource::Callback* callback;
        ... // 省略 VSYNC 信号处理的一些操作
        callback = mCallback;
        if (callback != nullptr) {
            callback->onVSyncEvent(when);
        }
    }
    ...
}

可以发现:

  • 在调用DispSyncSource对象的setVSyncEnabled()方法时会注册DispSync的事件监听

  • onDispSyncEvent()方法中最终调用了VSyncSource::Callback对象的onVSyncEvent()方法

VSyncSource::Callback对象又是和谁关联呢?  
还记得前面的EventThread么!!!EventThread便是继承了VSyncSource::Callback类,我们看下EventThread中关于onVSyncEvent()方法的实现:

void EventThread::onVSyncEvent(nsecs_t timestamp) {
    std::lock_guard<std::mutex> lock(mMutex);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.notify_all();
}

前面EventThread部分提到过

  • threadMain中的waitForEventLocked()会通过mCondition.wait()等待消息,

  • onVSyncEvent()会通过notify_all()唤醒threadMain处理消息

  • 因此会执行到conn->postEvent(event);方法

  • postEvent()方法会通过BitTube对象将数据发送到MessageQueue

  • 接下来便会触发执行MessageQueuecb_eventReceiver()方法

前面MessageQueue章节提到过,cb_eventReceiver()方法最后会调用的是SurfaceFlingeronMessageReceived()方法,而且消息类型是INVALIDATE

我们看下方法内容:

void SurfaceFlinger::onMessageReceived(int32_t what) {
    switch (what) {
        case MessageQueue::INVALIDATE: {
            ...
            bool refreshNeeded = handleMessageTransaction();
            ...
            break;
        }
        case MessageQueue::REFRESH: {
            handleMessageRefresh();
            break;
        }
    }
}

INVALIDATE消息的处理逻辑比较复杂,我们重点关注的是handleMessageTransaction()方法,它会创建DisplayDevice对象。我们先看下DisplayDevice对象

显示设备的抽象-`DisplayDevice`

DisplayDevice类是显示设备的抽象,当前Android 9中定义了3种显示设备类型:

  • DISPLAY_PRIMARY:主显示设备

  • DISPLAY_EXTERNAL:扩展显示设备,通过HDMI输出的显示信号

  • DISPLAY_VIRTUAL:虚拟显示设备,通过WIFI输出的显示信号

这三种显示设备,第一种是基本配置,另外两种需要硬件支持。关于Display官网有个极其简单的介绍:传送门

SurfaceFlingerDisplayDevice负责与OpenGL ES交互,即使没有任何物理显示设备被检测到,SurfaceFlinger都需要一个DisplayDevice对象才能正常工作

SurfaceFlinger将需要显示的图层Layer通过DisplayDevice对象传递到OpenGL ES中进行合成,合成后再通过HWComposer对象传送到FrameBuffer中显示

DisplayDevice对象中的成员变量Vector< sp > mVisibleLayersSortedByZ;保存了所有需要在本设备中显示的Layer对象

DisplayDevice比较复杂,先简单了解下它的创建流程。前面提到了handleMessageTransaction()方法中会创建DisplayDevice对象,我们看下具体的创建流程:

  • 初步调用流程:handleMessageTransaction()-->handleTransactionLocked()-->processDisplayChangesLocked()

    void SurfaceFlinger::processDisplayChangesLocked() {
        ...
        if (!curr.isIdenticalTo(draw)) {
            ...
            for (size_t i = 0; i < cc; i++) {
                if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                    const DisplayDeviceState& state(curr[i]);
                    sp dispSurface;
                    sp producer;
                    sp bqProducer;
                    sp bqConsumer;
                    // mCreateBufferQueue是一个函数指针,指向的是 BufferQueue::createBufferQueue
                    // 这就很熟悉了,和我们前面分析 Surface 时创建的 BufferQueue 一样
                    mCreateBufferQueue(&bqProducer, &bqConsumer, false);
                    int32_t hwcId = -1;
                    if (state.isVirtualDisplay()) {
                        ... // 省略虚拟屏幕创建的逻辑
                    } else {
                        ...
                        hwcId = state.type;
                        // 创建 FramebufferSurface 用于数据传输
                        dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
                        producer = bqProducer;
                    }
                    const wp& display(curr.keyAt(i));
                    if (dispSurface != nullptr) {
                        // 通过 setupNewDisplayDeviceInternal() 创建 DisplayDevice 对象
                        // 并添加到 mDisplays 集合中
                        mDisplays.add(display, setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface, producer));
                        if (!state.isVirtualDisplay()) {
                            mEventThread->onHotplugReceived(state.type, true);
                        }
                    }
                }
            }
        }
        mDrawingState.displays = mCurrentState.displays;
    }
    sp SurfaceFlinger::setupNewDisplayDeviceInternal(
            const wp& display, int hwcId, const DisplayDeviceState& state,
            const sp& dispSurface, const sp& producer) {
        ...
        // mCreateNativeWindowSurface 也是一个函数指针,执行的是 NativeWindowSurface::create() 方法
        // 该方法利用 IGraphicBufferProducer 生成 NativeWindowSurface 和 NativeWindow 对象
        // 其实也是 EGL 相关的接口调用
        auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
        auto nativeWindow = nativeWindowSurface->getNativeWindow();
        // 通过渲染引擎创建 OpenGL 渲染的目标 EGLSurface
        std::unique_ptr renderSurface = getRenderEngine().createSurface();
        renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
        renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
        // 执行 eglCreateWindowSurface 操作
        renderSurface->setNativeWindow(nativeWindow.get());
        ...
        // 创建 DisplayDevice 对象
        sp hw = new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
                                dispSurface, std::move(renderSurface), displayWidth, displayHeight,
                                hasWideColorGamut, hdrCapabilities,
                                supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
        ...
        return hw;
    }
    • 上面的代码中通过BufferQueue::createBufferQueue创建了consumerproducer对象(这部分和前面讲的BufferQueue的逻辑是相同的)

    • 并基于创建的consumer对象和一个HWComposer对象创建了一个FramebufferSurface对象

    • 最后将上面的对象作为参数通过setupNewDisplayDeviceInternal()方法创建DisplayDevice对象,并添加到mDisplays集合中

DisplayDevice对象创建完成,意味着SurfaceFlinger就可以利用DisplayDevice对象写入图像数据,并通过

  • EGLSurface-->BufferQueue-->FrameBufferSurface-->HWCComposer-->Gralloc

这样一条路径到达显示设备的FrameBuffer

`SurfaceFlinger`的`init()`和`run()`

有了前面的铺垫知识,init()run()就很好理解了

`SurfaceFlinger::init`

void SurfaceFlinger::init() {
    // 创建 app 的 DispSyncSource 和 EventThread
    mEventThreadSource = std::make_unique(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true"app");
    mEventThread = std::make_unique(mEventThreadSource.get(), ..., "appEventThread");
    // 创建 sf 的 DispSyncSource 和 EventThread
    mSfEventThreadSource = std::make_unique(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true"sf");
    mSFEventThread = std::make_unique(mSfEventThreadSource.get(), ..., "sfEventThread");
    // 将 mSFEventThread 与 MessageQueue 进行关联
    mEventQueue->setEventThread(mSFEventThread.get());
    // 将 mSFEventThread 和 mEventThread 添加到 VSYNC 信号调制器中
    mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
    // 创建渲染引擎,主要是选择EGL配置,选择OpenGL版本,创建OpenGL上下文
    getBE().mRenderEngine = RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,...);
    ...
    // 初始化 HWC
    getBE().mHwc.reset( new HWComposer(std::make_unique(getBE().mHwcServiceName)));
    // 注册 HWC 的 Callback 监听
    // VSYNC 信号便会从这里进行回调通知
    getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
    ...
    // 创建 VSYNC 事件接收控制对象,enable=true 表示允许 HWC 产生 VSYNC 信号
    // sufacefinlger 通过这个对象来控制 HWC 是否产生 VSYNC 信号
    mEventControlThread = std::make_unique([this](bool enabled) { setVsyncEnabled(HWC_DISPLAY_PRIMARY, enabled); });
    ...
    // 该方法会通过 MessageQueue 发送一个异步消息
    // 消息处理中会完成 primary DisplayDevice 的创建,并进行 VSYNC 周期的设定
    initializeDisplays();
    ...
    // 根据 PresentFenceIsNotReliable 属性创建 StartPropertySetThread对象
    if (getHwComposer().hasCapability(HWC2::Capability::PresentFenceIsNotReliable)) {
        mStartPropertySetThread = new StartPropertySetThread(false);
    } else {
        mStartPropertySetThread = new StartPropertySetThread(true);
    }
    // 执行 StartPropertySetThread,该线程会通过 setProp 触发开机动画,包括设置以下两个Prop
    // property_set("service.bootanim.exit", "0"); 复位动画退出标记
    // property_set("ctl.start", "bootanim"); 启动开机动画
    if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }
    ...
    ALOGV("Done initializing");
}

init()方法初始化了很多重要的对象:

  • 初始化appsf两组DispSyncSourceEventThread对象

    • 这两个分别代表了`VSYNC`信号的两个消费者:`App`和`SurfaceFlinger`

    • `sf`对应的信号分发逻辑与铺垫知识中的一致,因为是通过`mEventQueue->setEventThread()`来进行的关联

    • `app`的信号分发逻辑等下细看

  • 初始化HWComposer,并通过registerCallback()注册HWC2::ComposerCallback监听

  • 初始化EventControlThread对象,SurfaceFlinger用这个对象来控制HWC是否需要产生VSYNC信号

    • 默认设置为不需要产生`VSYNC`信号

  • 初始化StartPropertySetThread线程,该线程会通过setProp的方式触发开机动画

`SurfaceFlinger::run`

run()方法比较简单:

void SurfaceFlinger::run() {
    do {
        waitForEvent();
    } while (true);
}

方法中执行了一个无限循环来调用waitForEvent(),具体代码如下:

void SurfaceFlinger::waitForEvent() {
    mEventQueue->waitMessage();
}

waitForEvent()方法又调用了MessageQueue对象的waitMessage()方法进入一个无限循环,这个方法在MessageQueue部分中已经介绍过就不细讲啦

所以对于SurfaceFlinger进程来说,执行完run()当前线程就会进入一个无限循环,剩下的业务处理都变成了消息驱动来实现

`App`的绘制通知

SurfaceFlingerinit()方法中初始化了一个appEventThread,在接收到VSYNC信号后,它便会通知到App去进行绘制操作,我们看下这个通知流程

再看`onResume()`

我们已经知道,onResume()方法后才会进行View的显示,这部分体现在ActivityThread中的handleResumeActivity()方法中,代码如下:

    public void handleResumeActivity(...) {
        ...
        // TODO Push resumeArgs into the activity for consideration
        final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        if (r == null) {
            // We didn't actually resume the activity, so skipping any follow-up actions.
            return;
        }
        final Activity a = r.activity;
        ...
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            ...
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        }
        ...
    }

上面performResumeActivity()会回调应用程序的onResume()函数。不过本次我们重点关注的是wm.addView()方法,最后调用到的是WindowManagerGlobal.javaaddView(),代码如下:

    public void addView(...) {
        ...
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
            ...
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

重点是初始化了ViewRootImpl对象,我们看下ViewRootImpl中的setView()方法的调用:

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ...
                requestLayout();
                ...
            }
        }
    }
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    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,整个应用布局的渲染依赖这个对象的发动。

scheduleTraversals()方法中调用了mChoreographer对象的postCallback()方法添加了一个回调对象mTraversalRunnable

mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

mTraversalRunnable回调对象的定义如下:

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

doTraversal内部会调用大名鼎鼎的performTraversal()方法,到这里App就可以进行measure/layout/draw三大流程

那么 mTraversalRunnable对象是在什么时候调用的呢?  
我们带着疑问,先看下应用是如何接收VSYNC信号的

`Choreographer`类

App要求渲染动画或者更新画面布局时都会用到Choreographer,接收VSYNC信号也依赖于Choreographer

在上面的scheduleTraversals()方法中执行了Choreographer对象的postCallback()方法

    mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);

这个方法的含义就是应用程序请求VSYNC信号,接收到VSYNC信号后执行mTraversalRunnable回调

那么接下来我们看下Choreographer如何接收vsync信号

`DisplayEventReceiver`类

应用层可以通过DisplayEventReceiver类用来接收vsync信号,当接收到vsync信号后,会执行DisplayEventReceiver对象的onVsync()方法

DisplayEventReceiver是在AndroidView体系中定义的一个抽象类,对外隐藏的,核心定义如下

public abstract class DisplayEventReceiver {
    ...
    // 用来表示 APP 的 VSYNC 信号源
    public static final int VSYNC_SOURCE_APP = 0;
    public DisplayEventReceiver(Looper looper) {
        this(looper, VSYNC_SOURCE_APP);
    }
    public DisplayEventReceiver(Looper looper, int vsyncSource) {
        ...
        mMessageQueue = looper.getQueue();
        mReceiverPtr = nativeInit(new WeakReference(this), mMessageQueue,
                vsyncSource);
        ...
    }
    private static native long nativeInit(WeakReference receiver,
            MessageQueue messageQueue, int vsyncSource)
;
    private static native void nativeDispose(long receiverPtr);
    private static native void nativeScheduleVsync(long receiverPtr);
    ...
    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
    }
    ...
}

需要关注的是

  • 构造方法中调用了native方法nativeInit()来进行初始化操作

  • 定义了一个onVsync()方法的空实现,当接收到VSYNC信号后便会调用该方法

先看下nativeInit()的实现

static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
        jobject messageQueueObj, jint vsyncSource)
 
{
    sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    ...
    sp receiver = new NativeDisplayEventReceiver(env,
            receiverWeak, messageQueue, vsyncSource);
    status_t status = receiver->initialize();
    ...
}

nativeInit()方法创建了一个NativeDisplayEventReceiver对象,并调用了它的initialize()方法

NativeDisplayEventReceiver继承了DisplayEventDispatcher类,那么我们的重点便是DisplayEventDispatcher,头文件定义如下:

class DisplayEventDispatcher : public LooperCallback {
public:
    DisplayEventDispatcher(const sp& looper,
            ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
    status_t initialize();
    ...
private:
    sp mLooper;
    DisplayEventReceiver mReceiver;
    ...
};

核心实现如下:

DisplayEventDispatcher::DisplayEventDispatcher(const sp& looper,
        ISurfaceComposer::VsyncSource vsyncSource) :
        mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
    ALOGV("dispatcher %p ~ Initializing display event dispatcher."this);
}
status_t DisplayEventDispatcher::initialize() {
    status_t result = mReceiver.initCheck();
    ...
    int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
            thisNULL);
    if (rc < 0) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

在铺垫知识部分已经了解到,如果应用要接收VSYNC信号,需要将其添加到对应的EventThread中,SF中一共创建了两个

  • mSFEventThreadSurfaceFlinger专用的

    • 在`SurfaceFlinger`的`init()`中通过`mEventQueue->setEventThread()`进行关联

    • `setEventThread()`在铺垫部分也介绍过(铺垫内容-消息和事件分发)

  • mEventThread用来通知App

我们知道mEventQueue->setEventThread()关联VSYNC信号的过程主要分为了两步:

  • 创建连接

  • 注册监听

对比DisplayEventDispatcher中我们会发现

  • DisplayEventDispatcherinitialize()中做了一个mLooper->addFd()操作

    • 前面介绍过:Looper类的addFd()方法是将mReceiveFd添加到epoll监听列表

    • 这样,注册监听的部分我们找到了

  • DisplayEventDispatcher中包含一个native层的DisplayEventReceiver对象mReceiver

    DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
        sp sf(ComposerService::getComposerService());
        if (sf != NULL) {
            // createDisplayEventConnection 方法便会调用 mEventThread->createEventConnection() 来创建连接
            // 而 mEventThread 便是 App 的 VSYNC 分发线程
            mEventConnection = sf->createDisplayEventConnection(vsyncSource);
            if (mEventConnection != NULL) {
                mDataChannel = std::make_unique();
                mEventConnection->stealReceiveChannel(mDataChannel.get());
            }
        }
    }
    • native层的DisplayEventReceiver便封装了创建连接的过程,我们需要关注的是构造方法部分

到这里,DisplayEventReceiver便和SurfaceFlinger中的mEventThread建立了联系,当VSYNC信号产生后,SurfaceFlinger便会通过mEventThread通知到DisplayEventReceiver

VSYNC 分发过程已经介绍过了,可以看这里

`FrameDisplayEventReceiver`类

DisplayEventReceiver是一个抽象类,FrameDisplayEventReceiver便是这个类的具体实现,在Choreographer中定义,代码如下:

    private final class FrameDisplayEventReceiver extends DisplayEventReceiver
            implements Runnable 
{
        private boolean mHavePendingVsync;
        private long mTimestampNanos;
        private int mFrame;
        public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
            super(looper, vsyncSource);
        }
        @Override
        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
            // vsync 信号分发时便会回调到这里
            ...
            mTimestampNanos = timestampNanos;
            mFrame = frame;
            Message msg = Message.obtain(mHandler, this);
            msg.setAsynchronous(true);
            // 这里发了一个消息,此处并未主动设置 msg.what,默认值应为 0
            // 0 对应的数值为 MSG_DO_FRAME
            mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
        }
        @Override
        public void run() {
            mHavePendingVsync = false;
            doFrame(mTimestampNanos, mFrame);
        }
    }

上面onVsync会往消息队列放一个消息,通过下面的FrameHandler进行处理:

    private final class FrameHandler extends Handler {
        public FrameHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_DO_FRAME:
                    doFrame(System.nanoTime(), 0);
                    break;
                case MSG_DO_SCHEDULE_VSYNC:
                    doScheduleVsync();
                    break;
                case MSG_DO_SCHEDULE_CALLBACK:
                    doScheduleCallback(msg.arg1);
                    break;
            }
        }
    }

对于MSG_DO_FRAME消息,会执行doFrame()方法,关键代码如下:

    void doFrame(long frameTimeNanos, int frame) {
        ...
        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
        ...
    }

doFrame()方法通过doCallbacks()执行了各种类型的Callback,分为4类:

  • CALLBACK_INPUT : 处理输入事件处理有关

  • CALLBACK_ANIMATION :处理Animation的处理有关

  • CALLBACK_TRAVERSAL : 处理和UI等控件绘制有关

  • CALLBACK_COMMIT :处理Commit相关回调

需要注意的是CALLBACK_TRAVERSAL类型的doCallbacks()

doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

这个方法便会执行前面在scheduleTraversals()方法中添加的mTraversalRunnable回调。而由于CALLBACK_INPUTCALLBACK_ANIMATION会修改View的属性,所以要先于CALLBACK_TRAVERSAL执行

结语

狡辩ING:刚接手新平台比较忙,导致本来清明节计划学习的章节一直拖到现在,好在磕磕绊绊的学习完了

SurfaceFlinger这部分涉及的知识很多,很遗憾深入Android系统(十二)Android图形显示系统系列也仅仅只是记录一些基础知识。

View的绘制部分也并未展开学习,考虑到后面的章节,等了解完整个Android系统知识后再来补充吧(挖坑ING…..)

原文链接: https://juejin.cn/post/6958064165458018317


推荐:

Android 图形系统概述

Android 图形显示系统

全网最全的 Android 音视频和 OpenGL ES 干货,都在这了

浏览 320
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报