该系列文章总纲链接:Android GUI系统之SurfaceFlinger 系列文章目录
说明:以下代码分析均在android5.1.1_r3分支上 目录frameworks/native/services/surfaceflinger为root目录
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(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中还有其他的使用案例,大同小异,这里就不再赘述了。