Android应用程序请求Su易做图ceFlinger服务渲染Su易做图ce的过程分析
Android应用程序在请求Su易做图ceFlinger服务渲染一个Su易做图ce之前,首先要将该Su易做图ce作为当前活动的绘图上下文,以便可以使用OpengGL库或者其它库的API来在上面绘制UI,我们以Android系统的开机动画应用程序bootanim为例,来说明这个问题。
从前面Android应用程序请求Su易做图ceFlinger服务创建Su易做图ce的过程分析一文可以知道,Android系统的开机动画应用程序bootanim是在BootAnimation类的成员函数readyToRun中请求Su易做图ceFlinger服务创建Su易做图ce的。这个Su易做图ce创建完成之后,就会被设置为当前活动的绘图上下文,如下所示:
[cpp]
status_t BootAnimation::readyToRun() {
......
// create the native su易做图ce
sp<Su易做图ceControl> control = session()->createSu易做图ce(
getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
......
sp<Su易做图ce> s = control->getSu易做图ce();
......
// initialize opengl and egl
const EGLint attribs[] = {
EGL_DEPTH_SIZE, 0,
EGL_NONE
};
......
EGLConfig config;
EGLSu易做图ce su易做图ce;
EGLContext context;
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);
EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
su易做图ce = eglCreateWindowSu易做图ce(display, config, s.get(), NULL);
context = eglCreateContext(display, config, NULL, NULL);
......
if (eglMakeCurrent(display, su易做图ce, su易做图ce, context) == EGL_FALSE)
return NO_INIT;
......
}
BootAnimation类的成员函数readyToRun首先调用eglGetDisplay和eglInitialize函数来获得和初始化OpengGL库的默认显示屏,接着再调用EGLUtils::selectConfigForNativeWindow函数来获得前面所创建的一个Su易做图ce(由sp<Su易做图ce>指针s来描述)的配置信息。有了这些信息之后,接下来就分别调用eglCreateWindowSu易做图ce和eglCreateContext函数来创建一个适用于OpenGL库使用的绘图表面su易做图ce以及绘图上下文context,最后就可以调用eglMakeCurrent函数来将绘图表面su易做图ce和绘图上下文context设置为当前活动的绘图表面和绘图上下文,这就相当于是将前面请求Su易做图ceFlinger服务创建的一个Su易做图ce设置为当前活动的缓图上下文了。
完成了上述操作之后,Android系统的开机动画应用程序bootanim就可以继续使用OpengGL库的其它API来在当前活动的Su易做图ce上绘制UI了,不过,通过前面Android应用程序请求Su易做图ceFlinger服务创建Su易做图ce的过程分析一文的学习,我们知道,此时Su易做图ceFlinger服务为Android应用程序创建的Su易做图ce只有UI元数据缓冲区,而没有UI数据缓冲区,即还没有图形缓冲区,换句来说,就是还没有可以用来绘制UI的载体。那么,这些用来绘制UI的图形缓冲区是什么时候创建的呢?
从前面Android应用程序与Su易做图ceFlinger服务的关系概述和学习计划一文可以知道,每一个Su易做图ce都有一个对应的UI元数据缓冲区堆栈,这个UI元数据缓冲区堆栈是使用一个SharedBufferStack来描述的,
每一个UI元数据缓冲区都可能对应有一个UI数据缓冲区,这个UI数据缓冲区又可以称为图形缓冲区,它使用一个GraphicBuffer对象来描述。注意,一个UI元数据缓冲区只有第一次被使用时,Android应用程序才会为它创建一个图形缓冲区,因此,我们才说每一个UI元数据缓冲区都可能对应有一个UI数据缓冲区。例如,在图1中,目前只使到了编号为1和2的UI元数据缓冲区,因此,只有它们才有对应的图形缓冲区,而编号为3、4和5的UI元数据缓冲区没有。
Android应用程序渲染一个Su易做图ce的过程大致如下所示:
1. 从UI元数据缓冲区堆栈中得到一个空闲的UI元数据缓冲区;
2. 请求Su易做图ceFlinger服务为这个空闲的UI元数据缓冲区分配一个图形缓冲区;
3. 在图形缓冲区上面绘制好UI之后,即填充好UI数据之后,就将前面得到的空闲UI元数据缓冲区添加到UI元数据缓冲区堆栈中的待渲染队列中去;
4. 请求Su易做图ceFlinger服务渲染前面已经准备好了图形缓冲区的Su易做图ce;
5. Su易做图ceFlinger服务从即将要渲染的Su易做图ce的UI元数据缓冲区堆栈的待渲染队列中找到待渲染的UI元数据缓冲区;
6. Su易做图ceFlinger服务得到了待渲染的UI元数据缓冲区之后,接着再找到在前面第2步为它所分配的图形缓冲区,最后就可以将这个图形缓冲区渲染到设备显示屏上去。
这个过程的第1步、第3步和第5步涉到UI元数据缓冲区堆栈的一些出入栈操作,为了方便后面描述Android应用程序请求Su易做图ceFlinger服务渲染Su易做图ce的过程,我们首先介绍一下UI元数据缓冲区堆栈的一些出入栈操作。
在前面Android应用程序请求Su易做图ceFlinger服务创建Su易做图ce的过程分析一文中,我们分析了用来描述UI元数据缓冲区堆栈的SharedBufferServer和SharedBufferClient类的父类SharedBufferBase,它有一个成员函数waitForCondition,用来等待一个条件得到满足,它定义在文件frameworks/base/include/private/su易做图ceflinger/SharedBufferStack.h中,如下所示:
[cpp]
class SharedBufferBase
{
......
protected:
......
struct ConditionBase {
SharedBufferStack& stack;
inline ConditionBase(SharedBufferBase* sbc)
: stack(*sbc->mSharedStack) { }
virtual ~ConditionBase() { };
virtual bool operator()() const = 0;
virtual const char* name() const = 0;
};
status_t waitForCondition(const ConditionBase& condition);
......
};
SharedBufferBase类的成员函数waitForCondition只有一个参数condition,它的类型为ConditionBase,用来描述一个需要等待满足的条件。ConditionBase类是一个抽象类,我们需要以它来为父类,来实现一个自定义的条件,并且重写操作符号()和成员函数name。接下来,我们分析SharedBufferBase类的成员函数waitForCondition的实现,接着再分析ConditionBase类的一个子类的实现。
SharedBufferBase类的成员函数waitForCondition实现在文件frameworks/base/libs/su易做图ceflinger_client/SharedBufferStack.cpp文件中,如下所示:
[cpp]
status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
{
const SharedBufferStack& stack( *mSharedStack );
SharedClient& client( *mSharedClient );
const nsecs_t TIMEOUT = s2ns(1);
const int identity = mIdentity;
Mutex::Autolock _l(client.lock);
while ((condition()==false) &&
(stack.identity == identity) &&
&n
补充:移动开发 , Android ,