该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录
说明:
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();//处理完消息,打开屏障
- };
C++中的Barrier机制形象解读如下:
当涉及到多线程的同步问题时,这里用一个小故事来形象解读Barrier的原理。假设有一群小朋友在进行一场集体活动,他们需要在一个关键点上同步行动。这个关键点是一个大门,只有当所有小朋友都到达大门时,才能一起进入下一个阶段的活动。
通过这个故事,可以更形象地理解 Barrier 的原理,它在多线程环境中起到类似于大门的作用,让线程们在同一个关键点上同步等待,以保证并发操作的正确执行和数据的一致性。
android源码中使用lock和condition机制 构建了一个Barrier的机制,实现如下:
- #include
- #include
- #include
-
- 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操作。那么这是为什么呢?
在MessageBase的代码中handleMessage中每次处理完消息后会执行barrier.open();来打开屏障,而在SurfaceFlinger中把消息放入消息队列时候,如果采用同步操作,等待上一个消息处理完毕,这里的msg的类型就是继承了MessageBase。这里的wait就是MessageBase中的wait实现,调用的就是barrier的wait操作,这样,当上一个消息处理完执行了barrier的open操作,wait操作才会解除阻塞。同步消息方法postMessageSync详细代码如下:
- status_t SurfaceFlinger::postMessageSync(const sp
& 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
& msg, - nsecs_t reltime, uint32_t /* flags */) {
- return mEventQueue.postMessage(msg, reltime);
- }
这里要注意的是MessageBase是继承MessageHandler的,这意味着执行SurfaceFlinger中的postMessageSync方法时,会将对应的msg放入消息队列当中,等待SurfaceFlinger处理消息并发送回应信号。这里处理消息会直接调用对应MessageBase对象的handleMessage方法,进而执行对应MessageBase对象的handler()方法。
上面对MessageBase的机制有了一个具体的了解,接下来看看SurfaceFlinger中一般是怎么使用这个机制的。
createSurface 方法主要用于创建surface,具体功能如下:
这里代码参考了Client.cpp中createSurface方法的实现,如下所示:
- status_t Client::createSurface(
- const String8& name,
- uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
- sp
* handle, - sp
* gbp) - {
- class MessageCreateLayer : public MessageBase {
- SurfaceFlinger* flinger;
- Client* client;
- sp
* handle; - sp
* 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
* handle,sp* 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
msg = new MessageCreateLayer(mFlinger.get(), - name, this, w, h, format, flags, handle, gbp);
- mFlinger->postMessageSync(msg);
- return static_cast
( msg.get() )->getResult(); - }
这里的使用流程简要成两步,说明如下:
这里思考一个问题:可以看到Client::createSurface最终是调用了SurfaceFlinger::createLayer方法。那么为什么不直接调用呢?
在给出的代码中,Client::createSurface 方法通过创建一个名为 MessageCreateLayer 的自定义消息类来间接调用 SurfaceFlinger::createLayer 方法,而不是直接调用。这种间接调用的方式有几个目的和好处:
总结起来,通过间接调用的方式,即通过创建自定义消息并发送给 SurfaceFlinger 的消息队列,Client::createSurface 方法可以实现解耦和模块化、异步处理和线程安全等优势。这样的设计可以提高代码的可维护性和系统的性能。
setActiveConfig方法主要用于设置当前显示设备的活动配置。具体功能如下:
这里代码参考了SurfaceFlinger.cpp中setActiveConfig方法的实现,如下所示:
- status_t SurfaceFlinger::setActiveConfig(const sp
& display, int mode) { - class MessageSetActiveConfig: public MessageBase {
- SurfaceFlinger& mFlinger;
- sp
mDisplay; - int mMode;
- public:
- MessageSetActiveConfig(SurfaceFlinger& flinger, const sp
& disp, - int mode) :
- mFlinger(flinger), mDisplay(disp) { mMode = mode; }
- virtual bool handler() {
- Vector
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
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
msg = new MessageSetActiveConfig(*this, display, mode); - postMessageSync(msg);
- return NO_ERROR;
- }
这里的使用流程简要成两步,说明如下:
当然,在SurfaceFlinger中还有其他的使用案例,大同小异,这里就不再赘述了。