Android GUI系统之SurfaceFlinger(16)MessageBase解读

这篇具有很好参考价值的文章主要介绍了Android GUI系统之SurfaceFlinger(16)MessageBase解读。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录

说明:

  • 关于导读:导读部分主要是方便初学者理解SurfaceFlinger代码中的机制,为后面分析代码打下一个更好的基础,这样就可以把更多的精力放在surfaceFlinger的业务逻辑分析上。
  • 关于代码分支:以下代码分析均在android5.1.1_r3分支上 目录frameworks/native/services/surfaceflinger为root目录

1 MessageBase解读

1.1 源码实现分析

MessageBase源码实现如下:

//头文件部分MessageQueue.h
class MessageBase : public MessageHandler
{
public:
    MessageBase();
    virtual bool handler() = 0;
    void wait() const { barrier.wait(); } //等待handle处理消息
protected:
    virtual ~MessageBase();
private:
    virtual void handleMessage(const Message& message);
    mutable Barrier barrier;
};

//实现部分MessageQueue.cpp
MessageBase::MessageBase(): MessageHandler() {}
MessageBase::~MessageBase() {}
void MessageBase::handleMessage(const Message&) {
    this->handler();
    barrier.open();//处理完消息,打开屏障
};

1.2 理解Barrier机制

C++中的Barrier机制形象解读如下:

当涉及到多线程的同步问题时,这里用一个小故事来形象解读Barrier的原理。假设有一群小朋友在进行一场集体活动,他们需要在一个关键点上同步行动。这个关键点是一个大门,只有当所有小朋友都到达大门时,才能一起进入下一个阶段的活动。

  • 开始时,所有的小朋友都在不同的地方,他们要在指定的时间内集合到大门前。每个小朋友都代表一个线程,他们需要同时到达大门,才能继续进行下一步的活动。
  • 当活动开始时,大门是关闭的,表示屏障状态为关闭(CLOSED)。小朋友们在各自的位置启动,开始向大门前进。每个小朋友到达大门时,他们会等待其他小朋友到达。
  • 当最后一个小朋友到达大门时,屏障状态变为开放(OPENED)。大门打开了,所有小朋友都能看到大门已经开了,他们同时继续通过大门进入下一个阶段的活动。
  • 这个故事中的大门就是 Barrier,它提供了一个同步点,确保所有小朋友(线程)都到达了同一个位置后才能继续进行下一步的活动。当屏障状态为关闭时,小朋友们会等待,直到最后一个小朋友到达,屏障状态变为开放,所有小朋友都能继续执行后续的操作。

通过这个故事,可以更形象地理解 Barrier 的原理,它在多线程环境中起到类似于大门的作用,让线程们在同一个关键点上同步等待,以保证并发操作的正确执行和数据的一致性。
android源码中使用lock和condition机制 构建了一个Barrier的机制,实现如下:

#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>

namespace android {
class Barrier
{
public:
    inline Barrier() : state(CLOSED) { }
    inline ~Barrier() { }

    //释放处于等待状态的线程,将屏障状态设置为开放(OPENED),并唤醒所有等待的线程。
    void open() {
        Mutex::Autolock _l(lock);
        state = OPENED;
        cv.broadcast();
    }

    //重置屏障,将状态设置为关闭(CLOSED),以便 wait() 方法可以将线程阻塞。
    void close() {
        Mutex::Autolock _l(lock);
        state = CLOSED;
    }

    //等待屏障状态变为开放(OPENED)。如果屏障状态为关闭(CLOSED),则线程将在此处阻塞等待,直到 open() 方法被调用。
    void wait() const {
        Mutex::Autolock _l(lock);
        while (state == CLOSED) {
            cv.wait(lock);
        }
    }
private:
    enum { OPENED, CLOSED };
    mutable     Mutex       lock;
    mutable     Condition   cv;
    volatile    int         state;
};
}; // namespace android

#endif // ANDROID_BARRIER_H

根据以上实现,在android的surfaceFlinger中,并没有使用barrier的close操作。那么这是为什么呢?

  • 因为它的设计并不需要在每次使用之前显式地进行关闭。barrier在SurfaceFlinger中被用作线程之间的同步机制,用于控制消息的处理和执行顺序。它的目的是等待其他线程完成一定操作后再继续执行,而不是重复使用。在SurfaceFlinger的消息处理中,barrier被用作同步点,以确保特定操作在特定时机执行。一旦消息处理线程到达barrier,它会等待其他线程(通常是主线程或 GPU 线程)完成特定的操作,然后继续执行。
  • 由于barrier的使用场景是等待其他线程完成操作,而不是重复使用,因此在SurfaceFlinger中的MessageBase中没有使用close()操作进行显式关闭。在每个消息的处理过程中,barrier只需等待其他线程完成操作即可,而无需重置为初始状态。

1.3 SurfaceFlinger中同步/异步消息实现

在MessageBase的代码中handleMessage中每次处理完消息后会执行barrier.open();来打开屏障,而在SurfaceFlinger中把消息放入消息队列时候,如果采用同步操作,等待上一个消息处理完毕,这里的msg的类型就是继承了MessageBase。这里的wait就是MessageBase中的wait实现,调用的就是barrier的wait操作,这样,当上一个消息处理完执行了barrier的open操作,wait操作才会解除阻塞。同步消息方法postMessageSync详细代码如下:

status_t SurfaceFlinger::postMessageSync(const sp<MessageBase>& msg,
        nsecs_t reltime, uint32_t /* flags */) {
    status_t res = mEventQueue.postMessage(msg, reltime);
    if (res == NO_ERROR) {
        msg->wait();
    }
    return res;
}

而对于异步消息操作,则不需要wait操作,因而实现反而简单的多,不需要等待处理结果。异步消息方法postMessageAsync详细代码如下所示:

status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
        nsecs_t reltime, uint32_t /* flags */) {
    return mEventQueue.postMessage(msg, reltime);
}

2 MessageBase在SurfaceFlinger中的用法

2.1 原理说明

这里要注意的是MessageBase是继承MessageHandler的,这意味着执行SurfaceFlinger中的postMessageSync方法时,会将对应的msg放入消息队列当中,等待SurfaceFlinger处理消息并发送回应信号。这里处理消息会直接调用对应MessageBase对象的handleMessage方法,进而执行对应MessageBase对象的handler()方法。

2.2 使用案例参考

上面对MessageBase的机制有了一个具体的了解,接下来看看SurfaceFlinger中一般是怎么使用这个机制的。

2.2.1 Client::createSurface方法实现参考

createSurface 方法主要用于创建surface,具体功能如下:

  • 创建Surface对象:在客户端应用程序中调用createSurface方法时,SurfaceFlinger会创建一个Surface对象,用于表示应用程序中的窗口或图形内容。
  • 配置Surface属性:createSurface方法接受一组参数,用于配置Surface的属性,如宽度、高度、格式等。这些属性决定了Surface的显示特性和渲染方式。
  • 添加到图层层级结构:SurfaceFlinger会将创建的Surface对象添加到图层层级结构中的适当位置。这样,SurfaceFlinger就能够管理多个Surface,并控制它们的显示顺序、位置、透明度等。

这里代码参考了Client.cpp中createSurface方法的实现,如下所示:

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp)
{
    class MessageCreateLayer : public MessageBase {
        SurfaceFlinger* flinger;
        Client* client;
        sp<IBinder>* handle;
        sp<IGraphicBufferProducer>* gbp;
        status_t result;
        const String8& name;
        uint32_t w, h;
        PixelFormat format;
        uint32_t flags;
    public:
        //构造函数实现
        MessageCreateLayer(SurfaceFlinger* flinger,const String8& name, Client* client,
                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
                sp<IBinder>* handle,sp<IGraphicBufferProducer>* gbp)
            : flinger(flinger), client(client),handle(handle), gbp(gbp),
              name(name), w(w), h(h), format(format), flags(flags) {
        }
        status_t getResult() const { return result; }
        //消息处理实现,handle message机制会调用handleMessage方法,进而会调用到handler方法
        virtual bool handler() {
            //这里的flinger指的就是SurfaceFlinger实例,通过构造函数传入
            result = flinger->createLayer(name, client, w, h, format, flags,handle, gbp);
            return true;
        }
    };
    //
    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    mFlinger->postMessageSync(msg);
    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

这里的使用流程简要成两步,说明如下:

  1. 构建一个MessageBase子类MessageCreateLayer,实现MessageCreateLayer的构造方法和handler方法
  2. 创建MessageCreateLayer对象并将msg消息加入消息队列等待处理,msg对应的处理方法为handler。

这里思考一个问题:可以看到Client::createSurface最终是调用了SurfaceFlinger::createLayer方法。那么为什么不直接调用呢?

在给出的代码中,Client::createSurface 方法通过创建一个名为 MessageCreateLayer 的自定义消息类来间接调用 SurfaceFlinger::createLayer 方法,而不是直接调用。这种间接调用的方式有几个目的和好处:

  • 解耦和模块化:通过使用消息的方式进行通信,Client 类和 SurfaceFlinger 类之间的耦合性降低。Client 类只需要创建消息并将其发送给 SurfaceFlinger,而不需要直接依赖于 SurfaceFlinger 的具体实现。这样可以提高代码的灵活性和可维护性。
  • 异步处理:通过使用消息队列和异步处理机制,Client 类可以继续执行后续的操作,而不需要等待 SurfaceFlinger::createLayer 方法的完成。这样可以避免因某个操作阻塞而导致整个应用程序的响应性下降。
  • 线程安全:由于消息队列通常是在多线程环境下使用的,通过将操作封装为消息并由消息处理循环执行,可以确保对 SurfaceFlinger 的访问是线程安全的。这可以避免多个线程同时访问 SurfaceFlinger 导致的竞态条件和数据不一致性。

总结起来,通过间接调用的方式,即通过创建自定义消息并发送给 SurfaceFlinger 的消息队列,Client::createSurface 方法可以实现解耦和模块化、异步处理和线程安全等优势。这样的设计可以提高代码的可维护性和系统的性能。

2.2.2 setActiveConfig方法实现参考

setActiveConfig方法主要用于设置当前显示设备的活动配置。具体功能如下:

  • 切换配置:通过调用该方法,SurfaceFlinger可以切换到指定的配置,将显示设备的输出调整为该配置所定义的特性。这可能包括更改分辨率、刷新率或其他显示参数。
  • 确保兼容性:在切换到新的活动配置之前,setActiveConfig方法会进行一些兼容性检查。例如,它可能会检查新配置是否受支持,是否与其他正在显示的图层兼容等。这有助于确保切换到新配置不会导致显示问题或不稳定的情况。
  • 屏幕重启:在某些情况下,切换活动配置可能需要重新初始化显示设备,这可能会导致屏幕短暂黑屏或重启。setActiveConfig方法会涉及与硬件或底层系统交互,以便正确处理这些情况。

这里代码参考了SurfaceFlinger.cpp中setActiveConfig方法的实现,如下所示:

status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
    class MessageSetActiveConfig: public MessageBase {
        SurfaceFlinger& mFlinger;
        sp<IBinder> mDisplay;
        int mMode;
    public:
        MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
                               int mode) :
            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
        virtual bool handler() {
            Vector<DisplayInfo> configs;
            mFlinger.getDisplayConfigs(mDisplay, &configs);
            if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
                ALOGE("Attempt to set active config = %d for display with %zu configs",
                        mMode, configs.size());
            }
            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
            if (hw == NULL) {
                ALOGE("Attempt to set active config = %d for null display %p",
                        mMode, mDisplay.get());
            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
                ALOGW("Attempt to set active config = %d for virtual display",
                        mMode);
            } else {
                mFlinger.setActiveConfigInternal(hw, mMode);
            }
            return true;
        }
    };
    sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
    postMessageSync(msg);
    return NO_ERROR;
}

这里的使用流程简要成两步,说明如下:

  1. 构建一个MessageBase子类MessageSetActiveConfig,实现MessageSetActiveConfig的构造方法和handler方法,与2.2.1中的createSurface相比handler逻辑相对复杂。
  2. 创建MessageSetActiveConfig对象并将msg消息加入消息队列等待处理,msg对应的处理方法为handler。

当然,在SurfaceFlinger中还有其他的使用案例,大同小异,这里就不再赘述了。文章来源地址https://www.toymoban.com/news/detail-707710.html

到了这里,关于Android GUI系统之SurfaceFlinger(16)MessageBase解读的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何在 Android Framework 中添加自己的系统应用

    创建新的系统应用 要添加自己的系统应用,我们首先需要创建一个新的应用程序。这可以通过 Android Studio 可以很方便地完成。在 Android Studio 中,点击 “File New New Module”,然后在出现的对话框中选择 “Android Library”,并按照向导中的步骤完成创建过程。 添加权限 每个 And

    2024年02月09日
    浏览(42)
  • Android9.0 系统Framework发送通知流程分析

      在android 9.0的系统rom定制化开发中,在systemui中一个重要的内容就是系统通知的展示,在状态栏展示系统发送通知的图标,而在 系统下拉通知栏中展示接收到的系统发送过来的通知,所以说对系统framework中发送通知的流程分析很重要,接下来就来分析下系统 通知从framework到

    2024年02月02日
    浏览(39)
  • 操作系统的“冷板凳”要坐多久?万字长文解读16年开源老兵的坚持

    想知道内核研发是怎样的体验?操作系统的“冷板凳”得坐多久才有春天?本文对话龙蜥社区理事长马涛,畅所欲言聊开源,一起来看看那些开源润物细无声背后的故事以及龙蜥社区运营的道法术。 高门槛的 Linux 内核研发,如何支棱起来? 提问:首先想请马涛聊一聊自己的

    2023年04月09日
    浏览(37)
  • Android Framework最难模块WMS实战作业-手机车机系统开发必备

    0-整体介绍 1-window-container.mp4 窗口层级树实战启动篇 2-displayarea-feature.mp4 窗口层级树源码分析相关 3-displayarea-draw-feature.mp4 窗口层级树绘制实战1 4-displayarea-draw-leaf.mp4 窗口层级树绘制实战2 5-displayarea-draw-leaf-2.mp4 窗口层级树绘制实战3 6-displayarea-surfacelayer.mp4 窗口层级树相关sur

    2024年02月12日
    浏览(46)
  • hal深入剖析之aidl实战-android framework车机车载手机系统开发

    这个是hal工程根目录 接下来要创建aidl的文件存放目录 注意mkdir -p android/hardware/mytest其实就是包名目录,即模块包名就是android.hardware.mytest. 提示:这个如果为了项目的更加好的维护性建议到自己项目目标的vendor下面进行,目前只是为了演示方便,直接在system的hardware下面 创建

    2024年02月19日
    浏览(47)
  • android framework-Pixel3真机系统内置第三方apk实战

    ./make/target/product/mainline_arm64.mk 这个是系统应用的配置 ./make/target/product/handheld_product.mk 这个就是我们要配置的文件 在下面添加我们新增的 1、source build/envset.sh 2、lunch并且选择对应的product 3、make 4、adb devices(检查设备是否连接) 5、adb reboot bootloader(重启设备,进入fastboot状态)

    2024年02月12日
    浏览(59)
  • 深入Android S (12.0) 探索Framework之输入子系统InputReader的流程

    第一篇 深入Android S (12.0) 探索Framework之输入系统IMS的构成与启动 第二篇 深入Android S (12.0) 探索Framework之输入子系统InputReader的流程 上一篇文章深入探索了 Android Framework 的输入系统 IMS 的构成与启动,对 IMS 的重要成员有了初步的理解,然后通过源码对 IMS 的整个启动流程进行

    2024年01月20日
    浏览(43)
  • android多屏触摸相关的详解方案-安卓framework开发手机车载车机系统开发课程

    直播免费视频课程地址:https://www.bilibili.com/video/BV1hN4y1R7t2/ 在做双屏相关需求开发过程中,经常会有对两个屏幕都要求可以正确触摸的场景。但是目前我们模拟器默认创建的双屏其实是没有办法进行触摸的 静态修改方案 使用命令查看display2即副屏的信息情况 adb shell dumpsys d

    2024年02月11日
    浏览(46)
  • Android 系统源码目录frameworks/base/packages和packages/apps下的APP区别

    概要 在 Android Open Source Project (AOSP) 源代码中,frameworks/base/packages 和 packages/apps 目录都包含 Android 系统中的应用程序,但它们在性质和用途上有一些区别: 1,frameworks/base/packages frameworks/base 目录包含 Android 系统的核心框架代码。 frameworks/base/packages子目录包含系统级应用程序或

    2024年02月09日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包