Android 4.4 Graphic系统详解(1) SurfaceFlinger的启动过程
2015-09-22 10:16
771 查看
init启动SurfaceFlinger
SurfaceFlinger目前的启动方式是做为init进程中的一个Service来启动。
在init中添加如下配置代码:
系统将启动/system/bin/目录下的surfaceflinger bin文件来运行SurfaceFlinger。
关于init.rc的语法问题,我们将有专门的文章展开讨论(TODO)。
我们继续来看下对应的bin文件中的代码,位置在android\frameworks\native\services\surfaceflinger下。
从上面代码中我们看到SF的创建过程主要有四个步骤,我们来逐一分析一下。
其实这个创建过程很简单,无非就是初始化了一些值。从配置中读取了一些值。
需要注意的一点是,SurfaceFlinger实现了三个接口:
BnSurfaceComposer意思是指这个Surface混合的native端,这显然也符合我们对SF功能的认识—-用于Layer的混合处理。
另外,我们会在后面消息的处理一节中单独讲解HWComposer::EventHandler接口的作用。
其实相比SurfaceFlinger的创建,初始化做了更多的工作。
这一过程比较复杂,我们分为几部分来分析:
2.1 EGL初始化
首先SF初始化时,会进行一些EGL的初始化工作。
我们知道EGL是用来管理绘图表面(Drawing surfaces),并且提供了如下的机制
1) 与本地窗口系统进行通信(本地窗口在X-Window下是XDisplay ID,在MS Windows下是Window DC,而在Android平台上EGL是NativeDisplayType)
2) 查找绘图表面可用的类型和配置信息
3) 创建绘图表面
4) 同步OpenGL ES 2.0和其他的渲染API(Open VG、本地窗口系统的绘图命令等)
5) 管理渲染资源,比如材质
eglGetDisplay调用egl_display_t::get_display(dpy)获取(连接)显示设备的句柄。
egl_display_t结构用来存储get_display函数获取的物理显示设备。
这里的EGL_DEFAULT_DISPLAY类型是NativeDisplayType,是一个关联系统物理屏幕的通用数据类型。
每个 EGLDisplay 在使用前都需要通过eglInitialize函数来初始化。初始化 EGLDisplay 的同时,你可以得到系统中 EGL 的实现版本号。
这个整个过程是由平台实现的,我们看不到具体实现代码(libagl里面有一套谷歌的实现,但是非常简单)。
2.2 创建HWComposer
接下来是创建了一个HWComposer,也就是一个负责硬件合成的模块。但是我们也看到上面的注释明确写着,下面可能并没有一个真正的硬件支持。我们来研究下这个HWComposer的创建过程:
2.3 EGL配置
HWC模块创建完成之后,我们继续回到SurfaceFlinger的初始化过程,后面将继续是一些EGL相关的配置:
2.4 display设置
EGL和OpenGL ES的配置设置完毕之后,我们将对display进行设置。
上面这段代码其实涉及到了三个重要的概念,BufferQueue、FrameBufferSurface以及DisplayDevice。
BufferQueue做为Graphic的核心组件,我们在讲解Graphic总体结构时已经有说明,后面会另开专题说明。我们先来看下FrameBufferSurface的实现:
我们使用了BufferQueue来创建了一个FramebufferSurface,显然这个FramebufferSurface是一个消费者。在创建过程我们使用了屏幕的编号和HWC,我们可以猜测这个FBS是和一个屏幕绑定的,而且最终应该也是要通过HWC进行渲染。我们可以理解为这是SF在这个屏幕上使用的帧缓冲区,那么也就是一旦使用SF合成,最后数据应该是合成在了这里面(待验证),然后这里面的数据通过HWC显示在了屏幕上。猜测一下,这个是不是就是抓dump时抓到的那个HWC_FRAMEBUFFER_TARGET?
FBS的创建并没有特别之处,需要留意的是这里设置了MaxBufferCount和MaxAcquiredBufferCount,我们在Graphic总体架构一文中已经提到了设置这两个属性的作用。
DisplayDevice其实是抽象了显示设备,封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。来看下他的创建过程:
这段创建同样相当之长,我们目前只关注这里面创建了一个EGLSurface。我们在前面的文章中曾经提到过这个类,这个实际上就是一个供GLES使用的窗口缓冲区,为GLES提供了一个绘制的地方。
在这个EGLSurface里面是一个Surface,本质上下面还是一个BufferQueue。
渲染这个EGLSurface将导致一个buffer出队渲染入队的过程,lock和unlock过程是通过eglSwapBuffers函数来提供的。
2.5 makeCurrent
看完了上面几个重要概念的讲解,我们继续回到SF的init过程中来。
下面是对主屏幕对应的display进行makeCurrent操作:
注意到这里调用的实际上是DisplayDevice类提供的函数,这也某种程度上说明了我们前面提到的DisplayDevice的作用是:封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。看下这个makeCurrent函数:
这里获取了当前使用的EGLSurface,一旦发现这个Surface发生了改变,就要重新调用eglMakeCurrent函数来设置,这是因为一个线程同时只能有一个EGLSurface作为current。而关于eglMakeCurrent函数的更详尽的说明,我们将在EGL和GLES的章节中给予说明。
2.6 EventThread的创建
再次回到SF的init过程中来:
这段讲了EventThread的创建和使用。EventThread主要用于VSYNC消息的处理,我们同样会单开一个章节来讲解VSYNC的逻辑。
EventControlThread是用来向真实的VSync硬件发命令的,我们这里暂时不展开。
而一旦硬件不能正常发送VSYNC命令时,我们则通过软件方式模拟,我们可以看到这里把模拟的间隔时间设置为16.6ms左右。
2.7 初始化显示设备
终于到了init函数的最后几句话,首先是初始化显示设备。
我们来看初始化显示设备的逻辑:
其中setTransactionState函数在很多地方都会有调用,作用主要是处理上层的各个命令,并根据flag设置event通知Threadloop进行处理,TODO
而onScreenAcquired同样是一个重要的函数,不仅在这里,在屏幕会唤醒时同样会调用。
这里有几个点比较重要,首先是通知HWC,调用了HWC的acquire函数:
接下来,调用了EventThread的onScreenAcquired函数。
这个函数首先判断如果在之前mUseSoftwareVSync被设置为了true,这里需要改回来。而mUseSoftwareVSync这个值其实是在onScreenReleased被设置为true的(也就是说,在屏幕被灭掉之后,就变为软件的VSync,TODO,在屏幕黑掉之后,还有没有绘制或者显示方面的工作?)。
后面这个广播发送的主要作用是唤醒EventThread线程,并打开VSync事件发送器(可以看下waitForEvent函数)。
接下来的resyncToHardwareVsync函数逻辑比较简单,应该就是开启硬件的VSYNC。
最后是调用了repaintEverything函数,这个函数就是发送invalidate消息,请求屏幕刷新。
2.8 开机动画
回到init的过程上来。
播放开机动画我们会专门讲解,这里不再展开。
向Android的ServiceManager进程注册服务是系统的通用逻辑,不再展开,这里就是注册了一个名叫的SurfaceFlinger的服务而已。
在一系列的准备工作之后,终于到了启动SurfaceFlinger的时候。
而这个过程其实异常简单,SF进入死循环中,一直在等待消息的传来。
这样,我们就完整的分析了SF的启动过程,我们将在下一节继续分析SF对消息的处理过程。
init启动SurfaceFlinger
SurfaceFlinger目前的启动方式是做为init进程中的一个Service来启动。
在init中添加如下配置代码:
[cpp] view plaincopy # Set this property so surfaceflinger is not started by system_init setprop system_init.startsurfaceflinger 0 service surfaceflinger /system/bin/surfaceflinger class main user system group graphics drmrpc onrestart restart zygote
系统将启动/system/bin/目录下的surfaceflinger bin文件来运行SurfaceFlinger。
关于init.rc的语法问题,我们将有专门的文章展开讨论(TODO)。
SurfaceFlinger启动过程
我们继续来看下对应的bin文件中的代码,位置在android\frameworks\native\services\surfaceflinger下。[cpp] view plaincopy int main(int argc, char** argv) { // 1.创建surfaceflinger对象 sp<SurfaceFlinger> flinger = new SurfaceFlinger(); // initialize before clients can connect // 2.初始化 flinger->init(); // 3.注册SF服务 sp<IServiceManager> sm(defaultServiceManager()); sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false); // 4.运行程序 flinger->run(); return 0; }
从上面代码中我们看到SF的创建过程主要有四个步骤,我们来逐一分析一下。
1. 创建SF对象
[cpp] view plaincopy SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), mTransactionFlags(0), mTransactionPending(false), mAnimTransactionPending(false), mLayersRemoved(false), mRepaintEverything(0), mRenderEngine(NULL), mBootTime(systemTime()), mVisibleRegionsDirty(false), mHwWorkListDirty(false), mAnimCompositionPending(false), mDebugRegion(0), mDebugFps(0), mDebugDDMS(0), mDebugDisableHWC(0), mDebugDisableTransformHint(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), mLastTransactionTime(0), mBootFinished(false), mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), /* Activity-Activity: */ mProjectionType(ORTHOGRAPHIC_PROJECTION) /* Activity-Activity: Change End*/ // End { ALOGI("SurfaceFlinger is starting"); // debugging stuff... char value[PROPERTY_VALUE_MAX]; property_get("ro.bq.gpu_to_cpu_unsupported", value, "0"); mGpuToCpuSupported = !atoi(value); property_get("debug.sf.showupdates", value, "0"); mDebugRegion = atoi(value); property_get("debug.sf.showfps", value, "0"); mDebugFps = atoi(value); property_get("debug.sf.ddms", value, "0"); mDebugDDMS = atoi(value); if (mDebugDDMS) { if (!startDdmConnection()) { // start failed, and DDMS debugging not enabled mDebugDDMS = 0; } } ALOGI_IF(mDebugRegion, "showupdates enabled"); // ALOGI_IF(mDebugFps, "showfps enabled"); ALOGI_IF(mDebugDDMS, "DDMS debugging enabled"); }
其实这个创建过程很简单,无非就是初始化了一些值。从配置中读取了一些值。
需要注意的一点是,SurfaceFlinger实现了三个接口:
[cpp] view plaincopy class SurfaceFlinger : public BnSurfaceComposer, private IBinder::DeathRecipient, private HWComposer::EventHandler
BnSurfaceComposer意思是指这个Surface混合的native端,这显然也符合我们对SF功能的认识—-用于Layer的混合处理。
另外,我们会在后面消息的处理一节中单独讲解HWComposer::EventHandler接口的作用。
2.初始化
其实相比SurfaceFlinger的创建,初始化做了更多的工作。这一过程比较复杂,我们分为几部分来分析:
2.1 EGL初始化
[cpp] view plaincopy void SurfaceFlinger::init() { ALOGI( "SurfaceFlinger's main thread ready to run. " "Initializing graphics H/W..."); status_t err; Mutex::Autolock _l(mStateLock); // initialize EGL for the default display mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(mEGLDisplay, NULL, NULL); ... }
首先SF初始化时,会进行一些EGL的初始化工作。
我们知道EGL是用来管理绘图表面(Drawing surfaces),并且提供了如下的机制
1) 与本地窗口系统进行通信(本地窗口在X-Window下是XDisplay ID,在MS Windows下是Window DC,而在Android平台上EGL是NativeDisplayType)
2) 查找绘图表面可用的类型和配置信息
3) 创建绘图表面
4) 同步OpenGL ES 2.0和其他的渲染API(Open VG、本地窗口系统的绘图命令等)
5) 管理渲染资源,比如材质
eglGetDisplay调用egl_display_t::get_display(dpy)获取(连接)显示设备的句柄。
egl_display_t结构用来存储get_display函数获取的物理显示设备。
这里的EGL_DEFAULT_DISPLAY类型是NativeDisplayType,是一个关联系统物理屏幕的通用数据类型。
每个 EGLDisplay 在使用前都需要通过eglInitialize函数来初始化。初始化 EGLDisplay 的同时,你可以得到系统中 EGL 的实现版本号。
这个整个过程是由平台实现的,我们看不到具体实现代码(libagl里面有一套谷歌的实现,但是非常简单)。
2.2 创建HWComposer
[cpp] view plaincopy { ... // Initialize the H/W composer object. There may or may not be an // actual hardware composer underneath. mHwc = new HWComposer(this, *static_cast<HWComposer::EventHandler *>(this)); ... }
接下来是创建了一个HWComposer,也就是一个负责硬件合成的模块。但是我们也看到上面的注释明确写着,下面可能并没有一个真正的硬件支持。我们来研究下这个HWComposer的创建过程:
[cpp] view plaincopy HWComposer::HWComposer( const sp<SurfaceFlinger>& flinger, EventHandler& handler) : mFlinger(flinger), mFbDev(0), mHwc(0), mNumDisplays(1), mCBContext(new cb_context), mEventHandler(handler), mDebugForceFakeVSync(false) { for (size_t i =0 ; i<MAX_HWC_DISPLAYS ; i++) { mLists[i] = 0; } //首先是一些和VSYNC有关的信息的初始化 //因为在硬件支持的情况下,VSYNC的功能就是由HWC提供的 for (size_t i=0 ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) { mLastHwVSync[i] = 0; mVSyncCounts[i] = 0; } //根据配置来看是否需要模拟VSYNC消息 char value[PROPERTY_VALUE_MAX]; property_get("debug.sf.no_hw_vsync", value, "0"); mDebugForceFakeVSync = atoi(value); bool needVSyncThread = true; //加载Gralloc中的GRALLOC_HARDWARE_FB0设备,和HWC设备 // Note: some devices may insist that the FB HAL be opened before HWC. int fberr = loadFbHalModule(); loadHwcModule(); if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // close FB HAL if we don't needed it. // FIXME: this is temporary until we're not forced to open FB HAL // before HWC. framebuffer_close(mFbDev); mFbDev = NULL; } // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory. if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) && !mFbDev) { ALOGE("ERROR: failed to open framebuffer (%s), aborting", strerror(-fberr)); abort(); } // these display IDs are always reserved for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { mAllocatedDisplayIDs.markBit(i); } //如果我们有HWC这个硬件设备,那么我们就注册一些HWC的函数 //另外,就不需要使用vsync的进程,因为我们有了硬件支持的VSYNC中断 if (mHwc) { ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER, (hwcApiVersion(mHwc) >> 24) & 0xff, (hwcApiVersion(mHwc) >> 16) & 0xff); if (mHwc->registerProcs) { mCBContext->hwc = this; mCBContext->procs.invalidate = &hook_invalidate; mCBContext->procs.vsync = &hook_vsync; if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) mCBContext->procs.hotplug = &hook_hotplug; else mCBContext->procs.hotplug = NULL; memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero)); mHwc->registerProcs(mHwc, &mCBContext->procs); } // don't need a vsync thread if we have a hardware composer needVSyncThread = false; // always turn vsync off when we start eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0); // the number of displays we actually have depends on the // hw composer version //根据HWC硬件的支持情况,来设置显示屏幕的数量 if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) { // 1.3 adds support for virtual displays mNumDisplays = MAX_HWC_DISPLAYS; } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) { // 1.1 adds support for multiple displays mNumDisplays = NUM_BUILTIN_DISPLAYS; } else { mNumDisplays = 1; } } //如果我们能获取到FB设置,那么我们就从FB设备里面读取一些屏幕相关的I型难洗 if (mFbDev) { ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)), "should only have fbdev if no hwc or hwc is 1.0"); DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]); disp.connected = true; disp.width = mFbDev->width; disp.height = mFbDev->height; disp.format = mFbDev->format; disp.xdpi = mFbDev->xdpi; disp.ydpi = mFbDev->ydpi; if (disp.refresh == 0) { disp.refresh = nsecs_t(1e9 / mFbDev->fps); ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh); } if (disp.refresh == 0) { disp.refresh = nsecs_t(1e9 / 60.0); ALOGW("getting VSYNC period from thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh); } } else if (mHwc) {//否则我们将会从HWC中读取相关配置,打log确认下走哪个分支 // here we're guaranteed to have at least HWC 1.1 for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) { queryDisplayProperties(i); } } // End //显然,如果需要模拟VSync信号的话,我们需要线程来做这个工作 if (needVSyncThread) { // we don't have VSYNC support, we need to fake it //VSyncThread类的实现很简单,无非就是一个计时器而已,定时发送消息而已 //TODO VSYNC专题 mVSyncThread = new VSyncThread(*this); } }
2.3 EGL配置
HWC模块创建完成之后,我们继续回到SurfaceFlinger的初始化过程,后面将继续是一些EGL相关的配置:
[cpp] view plaincopy { ... //首先获取OpenGL ES2.0的配置,在另外一篇文档中,我们提到过从KK之后,SF开始使用ES 2.0 // First try to get an ES2 config err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT, &mEGLConfig); //当然如果获取失败,还是会继续使用1.0,TODO 我们会新开一个专题讲OpengGL if (err != NO_ERROR) { // If ES2 fails, try ES1 err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES_BIT, &mEGLConfig); } if (err != NO_ERROR) { // still didn't work, probably because we're on the emulator... // try a simplified query ALOGW("no suitable EGLConfig found, trying a simpler query"); err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), 0, &mEGLConfig); } if (err != NO_ERROR) { // this EGL is too lame for android LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up"); } // 打印一些配置信息 EGLint r,g,b,a; eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_RED_SIZE, &r); eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_GREEN_SIZE, &g); eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_BLUE_SIZE, &b); eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_ALPHA_SIZE, &a); ALOGI("EGL informations:"); ALOGI("vendor : %s", eglQueryString(mEGLDisplay, EGL_VENDOR)); ALOGI("version : %s", eglQueryString(mEGLDisplay, EGL_VERSION)); ALOGI("extensions: %s", eglQueryString(mEGLDisplay, EGL_EXTENSIONS)); ALOGI("Client API: %s", eglQueryString(mEGLDisplay, EGL_CLIENT_APIS)?:"Not Supported"); ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig); // get a RenderEngine for the given display / config (can't fail) // KK升级一章中我们讲过SF通过RenderEngine来实现了使用不同版本的OpenGL mRenderEngine = RenderEngine::create(mEGLDisplay, mEGLConfig); // retrieve the EGL context that was selected/created //获取ES的上下文,这个是用于SF的上下文 mEGLContext = mRenderEngine->getEGLContext(); // figure out which format we got eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId); LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT, "couldn't create EGLContext"); ... }
2.4 display设置
EGL和OpenGL ES的配置设置完毕之后,我们将对display进行设置。
[cpp] view plaincopy { ... // initialize our non-virtual displays for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) { DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i); // set-up the displays that are already connected if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) { // All non-virtual displays are currently considered secure. bool isSecure = true; createBuiltinDisplayLocked(type); wp<IBinder> token = mBuiltinDisplays[i]; //对于每个display,SF都会创建一个新的BufferQueue sp<BufferQueue> bq = new BufferQueue(new GraphicBufferAlloc()); sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, bq); //最后,用我们创建的这些内容,来创建一个DisplayDevice //它有两个重要的变量,一个是mFrameBufferSurface和mNativeWindow。 //mFrameBufferSurace是FrameBufferSurface类型, //当显示设备不属于VIRTUAL类型的话,则该变量不为空 sp<DisplayDevice> hw = new DisplayDevice(this, type, allocateHwcDisplayId(type), isSecure, token, fbs, bq, mEGLConfig); if (i > DisplayDevice::DISPLAY_PRIMARY) { // FIXME: currently we don't get blank/unblank requests // for displays other than the main display, so we always // assume a connected display is unblanked. ALOGD("marking display %d as acquired/unblanked", i); //这里应该是指非主屏幕的屏幕一旦注册,就长期处于开启状态 hw->acquireScreen(); } mDisplays.add(token, hw); } } ... }
上面这段代码其实涉及到了三个重要的概念,BufferQueue、FrameBufferSurface以及DisplayDevice。
BufferQueue做为Graphic的核心组件,我们在讲解Graphic总体结构时已经有说明,后面会另开专题说明。我们先来看下FrameBufferSurface的实现:
[cpp] view plaincopy FramebufferSurface::FramebufferSurface(HWComposer& hwc, int disp, const sp<IGraphicBufferConsumer>& consumer) : ConsumerBase(consumer), mDisplayType(disp), mCurrentBufferSlot(-1), mCurrentBuffer(0), mHwc(hwc) { mName = "FramebufferSurface"; mConsumer->setConsumerName(mName); mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER); mConsumer->setDefaultBufferFormat(mHwc.getFormat(disp)); mConsumer->setDefaultBufferSize(mHwc.getWidth(disp), mHwc.getHeight(disp)); mConsumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); mConsumer->setMaxAcquiredBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS - 1); }
我们使用了BufferQueue来创建了一个FramebufferSurface,显然这个FramebufferSurface是一个消费者。在创建过程我们使用了屏幕的编号和HWC,我们可以猜测这个FBS是和一个屏幕绑定的,而且最终应该也是要通过HWC进行渲染。我们可以理解为这是SF在这个屏幕上使用的帧缓冲区,那么也就是一旦使用SF合成,最后数据应该是合成在了这里面(待验证),然后这里面的数据通过HWC显示在了屏幕上。猜测一下,这个是不是就是抓dump时抓到的那个HWC_FRAMEBUFFER_TARGET?
FBS的创建并没有特别之处,需要留意的是这里设置了MaxBufferCount和MaxAcquiredBufferCount,我们在Graphic总体架构一文中已经提到了设置这两个属性的作用。
DisplayDevice其实是抽象了显示设备,封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。来看下他的创建过程:
[cpp] view plaincopy DisplayDevice::DisplayDevice( const sp<SurfaceFlinger>& flinger, DisplayType type, int32_t hwcId, bool isSecure, const wp<IBinder>& displayToken, const sp<DisplaySurface>& displaySurface, const sp<IGraphicBufferProducer>& producer, EGLConfig config) : mFlinger(flinger), mType(type), mHwcDisplayId(hwcId), mDisplayToken(displayToken), mDisplaySurface(displaySurface), mDisplay(EGL_NO_DISPLAY), mSurface(EGL_NO_SURFACE), mDisplayWidth(), mDisplayHeight(), mFormat(), mFlags(), mPageFlipCount(), mIsSecure(isSecure), mSecureLayerVisible(false), mScreenAcquired(false), mLayerStack(NO_LAYER_STACK), mOrientation() { mNativeWindow = new Surface(producer, false); ANativeWindow* const window = mNativeWindow.get(); int format; window->query(window, NATIVE_WINDOW_FORMAT, &format); /* * Create our display's surface */ EGLSurface surface; EGLint w, h; EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); surface = eglCreateWindowSurface(display, config, window, NULL); eglQuerySurface(display, surface, EGL_WIDTH, &mDisplayWidth); eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight); mDisplay = display; mSurface = surface; mFormat = format; mPageFlipCount = 0; mViewport.makeInvalid(); mFrame.makeInvalid(); float mFOV = 30.0f; float tangent = tan(PI / 180.0f * mFOV / 2.0f); mDefaultX = -((float) mDisplayWidth / 2.0f); mDefaultY = -((float) mDisplayHeight / 2.0f); mDefaultZ = -(((float) mDisplayHeight / 2.0f) / tangent); /* Activity-Activity: Change End*/ // virtual displays are always considered enabled mScreenAcquired = (mType >= DisplayDevice::DISPLAY_VIRTUAL); // Name the display. The name will be replaced shortly if the display // was created with createDisplay(). switch (mType) { case DISPLAY_PRIMARY: mDisplayName = "Built-in Screen"; break; case DISPLAY_EXTERNAL: mDisplayName = "HDMI Screen"; break; default: mDisplayName = "Virtual Screen"; // e.g. Overlay #n break; } char property[PROPERTY_VALUE_MAX]; int panelOrientation = DisplayState::eOrientationDefault; // Set the panel orientation from the property. property_get("persist.panel.orientation", property, "0"); panelOrientation = atoi(property) / 90; // initialize the display orientation transform. setProjection(panelOrientation, mViewport, mFrame); }
这段创建同样相当之长,我们目前只关注这里面创建了一个EGLSurface。我们在前面的文章中曾经提到过这个类,这个实际上就是一个供GLES使用的窗口缓冲区,为GLES提供了一个绘制的地方。
在这个EGLSurface里面是一个Surface,本质上下面还是一个BufferQueue。
渲染这个EGLSurface将导致一个buffer出队渲染入队的过程,lock和unlock过程是通过eglSwapBuffers函数来提供的。
2.5 makeCurrent
看完了上面几个重要概念的讲解,我们继续回到SF的init过程中来。
下面是对主屏幕对应的display进行makeCurrent操作:
[cpp] view plaincopy { ... // initialize OpenGL ES /* Activity-Activity: */ setProjectionType(ORTHOGRAPHIC_PROJECTION); /* Activity-Activity: Change End*/ // make the GLContext current so that we can create textures when creating Layers // (which may happens before we render something) getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); ... }
注意到这里调用的实际上是DisplayDevice类提供的函数,这也某种程度上说明了我们前面提到的DisplayDevice的作用是:封装了用于渲染的Surface和HWComposer模块等,从而尽可能使得SurfaceFlinger只要和它打交道。看下这个makeCurrent函数:
[cpp] view plaincopy EGLBoolean DisplayDevice::makeCurrent(EGLDisplay dpy, EGLContext ctx) const { EGLBoolean result = EGL_TRUE; EGLSurface sur = eglGetCurrentSurface(EGL_DRAW); if (sur != mSurface) { result = eglMakeCurrent(dpy, mSurface, mSurface, ctx); if (result == EGL_TRUE) { if (mType >= DisplayDevice::DISPLAY_VIRTUAL) eglSwapInterval(dpy, 0); } } setViewportAndProjection(); return result; }
这里获取了当前使用的EGLSurface,一旦发现这个Surface发生了改变,就要重新调用eglMakeCurrent函数来设置,这是因为一个线程同时只能有一个EGLSurface作为current。而关于eglMakeCurrent函数的更详尽的说明,我们将在EGL和GLES的章节中给予说明。
2.6 EventThread的创建
再次回到SF的init过程中来:
[cpp] view plaincopy { ... // start the EventThread sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync, vsyncPhaseOffsetNs, true); mEventThread = new EventThread(vsyncSrc); sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync, sfVsyncPhaseOffsetNs, true); mSFEventThread = new EventThread(sfVsyncSrc); mEventQueue.setEventThread(mSFEventThread); mEventControlThread = new EventControlThread(this); mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY); // set a fake vsync period if there is no HWComposer if (mHwc->initCheck() != NO_ERROR) { mPrimaryDispSync.setPeriod(16666667); } ... }
这段讲了EventThread的创建和使用。EventThread主要用于VSYNC消息的处理,我们同样会单开一个章节来讲解VSYNC的逻辑。
EventControlThread是用来向真实的VSync硬件发命令的,我们这里暂时不展开。
而一旦硬件不能正常发送VSYNC命令时,我们则通过软件方式模拟,我们可以看到这里把模拟的间隔时间设置为16.6ms左右。
2.7 初始化显示设备
终于到了init函数的最后几句话,首先是初始化显示设备。
[cpp] view plaincopy { ... // initialize our drawing state mDrawingState = mCurrentState; // set initial conditions (e.g. unblank default device) initializeDisplays(); ... }
我们来看初始化显示设备的逻辑:
[cpp] view plaincopy void SurfaceFlinger::onInitializeDisplays() { // reset screen orientation and use primary layer stack Vector<ComposerState> state; Vector<DisplayState> displays; DisplayState d; d.what = DisplayState::eDisplayProjectionChanged | DisplayState::eLayerStackChanged; d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]; d.layerStack = 0; d.orientation = DisplayState::eOrientationDefault; d.frame.makeInvalid(); d.viewport.makeInvalid(); displays.add(d); setTransactionState(state, displays, 0); onScreenAcquired(getDefaultDisplayDevice()); const nsecs_t period = getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); mAnimFrameTracker.setDisplayRefreshPeriod(period); property_set("debug.sf.layerdump", "0"); }
其中setTransactionState函数在很多地方都会有调用,作用主要是处理上层的各个命令,并根据flag设置event通知Threadloop进行处理,TODO
而onScreenAcquired同样是一个重要的函数,不仅在这里,在屏幕会唤醒时同样会调用。
[cpp] view plaincopy void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) { ALOGD("Screen acquired, type=%d flinger=%p", hw->getDisplayType(), this); if (hw->isScreenAcquired()) { // this is expected, e.g. when power manager wakes up during boot ALOGD(" screen was previously acquired"); return; } hw->acquireScreen(); int32_t type = hw->getDisplayType(); if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) { // built-in display, tell the HWC getHwComposer().acquire(type); if (type == DisplayDevice::DISPLAY_PRIMARY) { // FIXME: eventthread only knows about the main display right now mEventThread->onScreenAcquired(); resyncToHardwareVsync(true); } } mVisibleRegionsDirty = true; repaintEverything(); }
这里有几个点比较重要,首先是通知HWC,调用了HWC的acquire函数:
[cpp] view plaincopy status_t HWComposer::acquire(int disp) { LOG_FATAL_IF(disp >= VIRTUAL_DISPLAY_ID_BASE); if (mHwc) { return (status_t)mHwc->blank(mHwc, disp, 0); } return NO_ERROR; }
接下来,调用了EventThread的onScreenAcquired函数。
[cpp] view plaincopy void EventThread::onScreenAcquired() { if (mUseSoftwareVSync) { // resume use of h/w vsync mUseSoftwareVSync = false; mCondition.broadcast(); } }
这个函数首先判断如果在之前mUseSoftwareVSync被设置为了true,这里需要改回来。而mUseSoftwareVSync这个值其实是在onScreenReleased被设置为true的(也就是说,在屏幕被灭掉之后,就变为软件的VSync,TODO,在屏幕黑掉之后,还有没有绘制或者显示方面的工作?)。
后面这个广播发送的主要作用是唤醒EventThread线程,并打开VSync事件发送器(可以看下waitForEvent函数)。
接下来的resyncToHardwareVsync函数逻辑比较简单,应该就是开启硬件的VSYNC。
[cpp] view plaincopy void SurfaceFlinger::resyncToHardwareVsync(bool makeAvailable) { Mutex::Autolock _l(mHWVsyncLock); if (makeAvailable) { mHWVsyncAvailable = true; } else if (!mHWVsyncAvailable) { ALOGE("resyncToHardwareVsync called when HW vsync unavailable"); return; } const nsecs_t period = getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY); mPrimaryDispSync.reset(); mPrimaryDispSync.setPeriod(period); if (!mPrimaryHWVsyncEnabled) { mPrimaryDispSync.beginResync(); //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true); mEventControlThread->setVsyncEnabled(true); mPrimaryHWVsyncEnabled = true; } }
最后是调用了repaintEverything函数,这个函数就是发送invalidate消息,请求屏幕刷新。
2.8 开机动画
回到init的过程上来。
[cpp] view plaincopy { ... // start boot animation startBootAnim(); }
播放开机动画我们会专门讲解,这里不再展开。
3.注册SF服务
向Android的ServiceManager进程注册服务是系统的通用逻辑,不再展开,这里就是注册了一个名叫的SurfaceFlinger的服务而已。
4.运行程序
在一系列的准备工作之后,终于到了启动SurfaceFlinger的时候。[cpp] view plaincopy void SurfaceFlinger::run() { do { waitForEvent(); } while (true); } void SurfaceFlinger::waitForEvent() { mEventQueue.waitMessage(); }
而这个过程其实异常简单,SF进入死循环中,一直在等待消息的传来。
总结
这样,我们就完整的分析了SF的启动过程,我们将在下一节继续分析SF对消息的处理过程。
相关文章推荐
- Android关于PopupWindow控件的使用
- Android 5.x新特性之利用Palette获取图片的主题色
- android 快速开发(二)辅助类的使用:加快开发速度
- Android(Lollipop/5.0) Material Design(六) 使用图像
- Android 倒计时CountDownTimer
- 开发笔记
- android 设置系统的时间
- bug整理
- 在线查看android源代码的3种方式
- 2015Android移动开发应用主流菜单模式
- WebRTC知识分享——WebRTC on Android
- android自定义圆形imageview
- Android设备的显示信息
- Android 一个ListView添加多个Adapter
- “The Android NDK cannot be installed into a path with spaces”的解决方法
- Android开发总结笔记 TableLayout(表格布局) 1-1-4
- 由Android想到的事情
- Android--颜色,动画效果xml所在目录
- Android多屏幕适配方案
- android压力测试命令monkey详解