SurfaceFlinger的启动过程


转载于:http://blog.chinaunix.net/uid-22935566-id-3528798.html


分类: Android平台

文章出处:http://danielwood.cublog.cn
作者:Daniel Wood

 

SurfaceFlinger的启动过程还是从Zygote说起。Zygote起来后会调用SystemServer.java[frameworks/base/services/java/com/android/server]里面的main函数,然后调用本地函数init1(),然后调用的是JNIcom_android_server_SystemServer.cpp里面的android_server_SystemServer_init1函数。


static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
    system_init();
}


然后调用

System_init.cpp[frameworks/base/cmds/system_server/library]system_init函数,通过获取属性字段system_init.startsurfaceflinger,如果字段值为1,那么就在这里启动surfaceflinger


char propBuf[PROPERTY_VALUE_MAX];

property_get("system_init.startsurfaceflinger", propBuf, "1");

 

if (strcmp(propBuf, "1") == 0) {
        // Start the SurfaceFlinger
        SurfaceFlinger::instantiate();
    }



然而,另一方面,有一个可执行文件surfaceflinger,由目录framework/base/cmds/surfaceflinger编译产生,目录下的主要文件main_surfaceflinger.cpp里面就一个main函数:


int main(int argc, char** argv)
{
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    LOGI("ServiceManager: %p", sm.get());
    SurfaceFlinger::instantiate();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}


以上两者都会调用SurfaceFlinger.cpp文件的instantiate函数。


void SurfaceFlinger::instantiate() {
    defaultServiceManager()->addService(
            String16("SurfaceFlinger"), new SurfaceFlinger());
}


如果你想在可执行文件中启动SurfaceFlinger,那么你可以在init.rc文件中增加类似如下语句:


service surfaceflinger /system/bin/surfaceflinger
    user root
    onrestart restart zygote
    disabled


当然你也必须设置属性字段system_init.startsurfaceflinger为0,这个工作可以在init.rc中完成。

setprop system_init.startsurfaceflinger 0


 

 

surfaceflinger构造函数调用init()函数【surfaceflinger.cpp】,init函数主要打印"SurfaceFlinger is starting"的Log信息,并且对一些debug属性进行配置。

surfaceflinger构造函数调用readyToRun函数【surfaceflinger.cpp】,至于为什么会调用readyToRun函数(并没有显式的调用语句),主要是因为surfaceflinger是一个线程类,必须实现并会调用如下两个函数:一是readyToRun(),该函数定义了线程循环前需要初始化的内容;二是threadLoop(),每个线程都必须实现,该函数定义了线程执行的内容,如果该函数返回true,线程会继续调用threadLoop(),如果返回false,线程将退出。-->选自参考文献。

关于readyToRun将在下节分析

 

 

SurfaceFlinger启动过程分析(二)

上节说到SurfaceFlinger的readyToRun函数。先来看看它的代码:
(Google Android 2.2)
SurfaceFlinger.cpp

status_t SurfaceFlinger::readyToRun()
{
    LOGI( "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");
    // we only support one display currently
    int dpy = 0;
    {
        // initialize the main display
        GraphicPlane& plane(graphicPlane(dpy));
        
DisplayHardware* const hw = new DisplayHardware(this, dpy);
        plane.setDisplayHardware(hw);
    }
    // create the shared control-block
    mServerHeap = new MemoryHeapBase(4096,
            MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");
    LOGE_IF(mServerHeap==0, "can't create shared memory dealer");
    
    mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());
    LOGE_IF(mServerCblk==0, "can't get to shared control block's address");   
    new(mServerCblk) surface_flinger_cblk_t;
    // initialize primary screen
    // (other display should be initialized in the same manner, but
    // asynchronously, as they could come and go. None of this is supported
    // yet).
    const GraphicPlane& plane(graphicPlane(dpy));
    const DisplayHardware& hw = plane.displayHardware();
    const uint32_t w = hw.getWidth();
    const uint32_t h = hw.getHeight();
    const uint32_t f = hw.getFormat();
    hw.makeCurrent();
    // initialize the shared control block

    mServerCblk->connected |= 1<<dpy;
    display_cblk_t* dcblk = mServerCblk->displays + dpy;
    memset(dcblk, 0, sizeof(display_cblk_t));
    dcblk->= plane.getWidth();
    dcblk->= plane.getHeight();
    dcblk->format = f;
    dcblk->orientation = ISurfaceComposer::eOrientationDefault;
    dcblk->xdpi = hw.getDpiX();
    dcblk->ydpi = hw.getDpiY();
    dcblk->fps = hw.getRefreshRate();
    dcblk->density = hw.getDensity();
    asm volatile ("":::"memory");
    // Initialize OpenGL|ES

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glPixelStorei(GL_PACK_ALIGNMENT, 4); 
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnable(GL_SCISSOR_TEST);
    glShadeModel(GL_FLAT);
    glDisable(GL_DITHER);
    glDisable(GL_CULL_FACE);

    const uint16_t g0 = pack565(0x0F,0x1F,0x0F);
    const uint16_t g1 = pack565(0x17,0x2f,0x17);
    const uint16_t textureData[4] = { g0, g1, g1, g0 };
    glGenTextures(1, &mWormholeTexName);
    glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0,
            GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData);
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(0, w, h, 0, 0, 1);
   LayerDim::initDimmer(this, w, h);
    mReadyToRunBarrier.open();
    /*
     * We're now ready to accept clients...
     */

    // start boot animation
    property_set("ctl.start", "bootanim");   
    return NO_ERROR;
}

调用readyToRun函数用于初始化整个显示系统。


 readyToRun()调用过程如下[这部分摘自网上资料]: 


(1)执行new DisplayHardware(this,dpy),通过DisplayHardware初始化Framebuffer、EGL并获取OpenGL ES信息。 

(2)创建共享的内存控制块。 

(3)将EGL与当前屏幕绑定。 

(4)初始化共享内存控制块。 

(5)初始化OpenGL ES。 

(6)显示开机动画。

上面的六点作为阅读代码的提纲及参考,下面对照代码进行分析:

(1)创建一个DisplayHardware,通过它的init函数去初始化Framebuffer、EGL并获取OpenGL ES信息。 

DisplayHardware.cpp[frameworks/base/libs/surfaceflinger/displayhardware]


 

DisplayHardware::DisplayHardware(
        const sp<SurfaceFlinger>& flinger,
        uint32_t dpy)
    : DisplayHardwareBase(flinger, dpy)
{
    
init(dpy);
}


init函数的代码狠长,我们一块一块,一句一句地分析:

void DisplayHardware::init(uint32_t dpy)
{
    mNativeWindow = new FramebufferNativeWindow();

    ...


首先亮相的是第一句(如上),new一个FramebufferNativeWindow。
FramebufferNativeWindow构造函数的代码也不少,我们去掉一些次要的代码,挑重要的关键的说:

FramebufferNativeWindow::FramebufferNativeWindow() 
    : BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false)
{
    hw_module_t const* module;
    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
        int stride;
        int err;
        err = framebuffer_open(module, &fbDev);
        LOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
        
        err = gralloc_open(module, &grDev);
        LOGE_IF(err, "couldn't open gralloc HAL (%s)", strerror(-err));
        // bail out if we can't initialize the modules
        if (!fbDev || !grDev)
            return;        
        mUpdateOnDemand = (fbDev->setUpdateRect != 0);       
        // initialize the buffer FIFO
        mNumBuffers = 2;
        mNumFreeBuffers = 2;
        mBufferHead = mNumBuffers-1;
        buffers[0] = new NativeBuffer(
                fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
        buffers[1] = new NativeBuffer(
                fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);

        
        err = grDev->alloc(grDev,
                fbDev->width, fbDev->height, fbDev->format, 
                GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);
        LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s",fbDev->width,fbDev->height, strerror(-err));

        err = grDev->alloc(grDev,
                fbDev->width, fbDev->height, fbDev->format, 
                GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);

        LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",fbDev->width,fbDev->height, strerror(-err));
...
    } else {
        LOGE("Couldn't get gralloc module");
    }

    ...

}


  关键的代码都被我高亮了,从最后一行的else的LOGE中可以看出这里主要是获得gralloc这个模块。模块ID定义在:gralloc.h[hardware/libhardware/include/hardware]

#define GRALLOC_HARDWARE_MODULE_ID "gralloc"


ps:有时候代码中的log狠有用,可以帮助我们读懂代码,而且logcat也是我们调试代码的好东西。
    首先打开framebuffer和gralloc这两个模块
framebuffer_open gralloc_open 这两个接口在 gralloc.h 里面定义

static inline int framebuffer_open(const struct hw_module_t* module, 
        struct framebuffer_device_t** device) {
    return module->methods->open(module, 
            GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device);
}
static inline int gralloc_open(const struct hw_module_t* module, 
        struct alloc_device_t** device) {
    return module->methods->open(module, 
            GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device);
}


两者指定的是gralloc.cpp中同一个函数gralloc_device_open,但是用的是不同的设备名,函数名和设备名分别在gralloc.cpp和gralloc.h中定义。

gralloc.h[hardware/libhardware/include/hardware]

#define GRALLOC_HARDWARE_FB0 "fb0"
#define GRALLOC_HARDWARE_GPU0 "gpu0"

gralloc.cpp[hardware/libhardware/modules/gralloc]
static struct hw_module_methods_t gralloc_module_methods = {
        open: gralloc_device_open
};


gralloc.cpp[hardware/libhardware/modules/gralloc]

int gralloc_device_open(const hw_module_t* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
        gralloc_context_t *dev;
        dev = (gralloc_context_t*)malloc(sizeof(*dev));
        /* initialize our state here */
        memset(dev, 0, sizeof(*dev));
        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = gralloc_close;
        dev->device.alloc = gralloc_alloc;
        dev->device.free = gralloc_free;
        *device = &dev->device.common;
        status = 0;
    } else {
        status = fb_device_open(module, name, device);
    }
    return status;
}


gralloc_device_open函数通过设备名字来进行相关的初始化工作。打开framebuffer则调用fb_device_open函数。fb_device_open函数定义在framebuffer.cpp中。

int fb_device_open(hw_module_t const* module, const char* name,
        hw_device_t** device)
{
    int status = -EINVAL;
    if (!strcmp(name, GRALLOC_HARDWARE_FB0)) {
        alloc_device_t* gralloc_device;
        status = gralloc_open(module, &gralloc_device);
        if (status < 0)
            return status;
        /* initialize our state here */
        fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev));
        memset(dev, 0, sizeof(*dev));
        /* initialize the procs */
        dev->device.common.tag = HARDWARE_DEVICE_TAG;
        dev->device.common.version = 0;
        dev->device.common.module = const_cast<hw_module_t*>(module);
        dev->device.common.close = fb_close;
        dev->device.setSwapInterval = fb_setSwapInterval;
        dev->device.post = fb_post;
        dev->device.setUpdateRect = 0;

        private_module_t* m = (private_module_t*)module;
        status = mapFrameBuffer(m);
        if (status >= 0) {
             
...
            *device = &dev->device.common;
        }
    }
    return status;
}

    fb_device_open函数是framebuffer.cpp里面的函数它会再次调用gralloc_open函数,调用gralloc_open并没有什么实际的用途,只是检测模块的正确性,感觉这句话没有必要,还是我哪里理解错了???因为gralloc_device这个变量在后面都没有用到啊。

哈哈,经过测试,把以下几句注释掉,然后make,烧到手机上,手机基本功能仍旧正常,看来这几句代码狠有可能是没有什么特别用处的。


alloc_device_t* gralloc_device;
status = gralloc_open(module, &gralloc_device);
if (status < 0)
   return status;


    然后调用mapFrameBuffer函数,就是将显示缓冲区映射到用户空间,这样在用户空间就可以直接对显示缓冲区进行读写操作。mapFrameBuffer函数的主体功能是在mapFrameBufferLocked函数里面完成的。

关于mapFrameBuffer函数,在下节讲解。


SurfaceFlinger启动过程分析(三)

内存映射对于framebuffer来说非常重要,因为通常用户是不能直接操作物理地址空间的(也就是物理内存?),然而通过mmap映射之后,将framebuffer的物理地址空间映射到用户空间的一段虚拟地址中,用户就可以通过操作这段虚拟内存而间接操作framebuffer了,你在那段虚拟内存中画了图,相应的图就会显示到屏幕上。
——这段是自己的理解,有错必究!
下面是framebuffer.cpp中的mapFrameBufferLocked函数。

int mapFrameBufferLocked(struct private_module_t* module)
{
    // already initialized...
    if (module->framebuffer) {
        return 0;
    }        
    char const * const device_template[] = {
            "/dev/graphics/fb%u",
            "/dev/fb%u",
            0 };

    int fd = -1;
    int i=0;
    char name[64];
    while ((fd==-1) && device_template[i]) {
        snprintf(name, 64, device_template[i], 0);
        fd = open(name, O_RDWR, 0);
        i++;
    }
    if (fd < 0)
        return -errno;

    struct fb_fix_screeninfo finfo;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;
    struct fb_var_screeninfo info;
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
        return -errno;
    info.reserved[0] = 0;
    info.reserved[1] = 0;
    info.reserved[2] = 0;
    info.xoffset = 0;
    info.yoffset = 0;
    info.activate = FB_ACTIVATE_NOW;
    /*
     * Explicitly request 5/6/5
     */

    info.bits_per_pixel = 16;
    info.red.offset = 11;
    info.red.length = 5;
    info.green.offset = 5;
    info.green.length = 6;
    info.blue.offset = 0;
    info.blue.length = 5;
    info.transp.offset = 0;
    info.transp.length = 0;

    /*
     * Request NUM_BUFFERS screens (at lest 2 for page flipping)
     */

    info.yres_virtual = info.yres * NUM_BUFFERS;
    uint32_t flags = PAGE_FLIP;
    if (ioctl(fd, FBIOPUT_VSCREENINFO, &info) == -1) {
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
        LOGW("FBIOPUT_VSCREENINFO failed, page flipping not supported");
    }
    if (info.yres_virtual < info.yres * 2) {
        // we need at least 2 for page-flipping
        info.yres_virtual = info.yres;
        flags &= ~PAGE_FLIP;
        LOGW("page flipping not supported (yres_virtual=%d, requested=%d)",
                info.yres_virtual, info.yres*2);
    }
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
        return -errno;
    int refreshRate = 1000000000000000LLU /
    (
            uint64_t( info.upper_margin + info.lower_margin + info.yres )
            * ( info.left_margin + info.right_margin + info.xres )
            * info.pixclock
    );
    if (refreshRate == 0) {
        // bleagh, bad info from the driver
        refreshRate = 60*1000; // 60 Hz
    }
    if (int(info.width) <= 0 || int(info.height) <= 0) {
        // the driver doesn't return that information
        // default to 160 dpi
        info.width = ((info.xres * 25.4f)/160.0f + 0.5f);
        info.height = ((info.yres * 25.4f)/160.0f + 0.5f);
    }
    float xdpi = (info.xres * 25.4f) / info.width;
    float ydpi = (info.yres * 25.4f) / info.height;
    float fps = refreshRate / 1000.0f;
    LOGI( "using (fd=%d)/n"
            "id = %s/n"
            "xres = %d px/n"
            "yres = %d px/n"
            "xres_virtual = %d px/n"
            "yres_virtual = %d px/n"
            "bpp = %d/n"
            "r = %2u:%u/n"
            "g = %2u:%u/n"
            "b = %2u:%u/n",
            fd,
            finfo.id,
            info.xres,
            info.yres,
            info.xres_virtual,
            info.yres_virtual,
            info.bits_per_pixel,
            info.red.offset, info.red.length,
            info.green.offset, info.green.length,
            info.blue.offset, info.blue.length
    );

    LOGI( "width = %d mm (%f dpi)/n"
            "height = %d mm (%f dpi)/n"
            "refresh rate = %.2f Hz/n",
            info.width, xdpi,
            info.height, ydpi,
            fps
    );
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;
    if (finfo.smem_len <= 0)
        return -errno;
    module->flags = flags;
    module->info = info;
    module->finfo = finfo;
    module->xdpi = xdpi;
    module->ydpi = ydpi;
    module->fps = fps;
    /*
     * map the framebuffer
     */

    int err;
    size_t fbSize = 
roundUpToPageSize(finfo.line_length * info.yres_virtual);//对齐页
    module->framebuffer = new private_handle_t(dup(fd), fbSize, 0);

    module->numBuffers = info.yres_virtual / info.yres;
    module->bufferMask = 0;

    void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if (vaddr == MAP_FAILED) {
        LOGE("Error mapping the framebuffer (%s)", strerror(errno));
        return -errno;
    }
    module->framebuffer->base = intptr_t(vaddr);
    memset(vaddr, 0, fbSize);
    return 0;
}

这个函数就是和驱动相关的调用,其实结合驱动去看代码是很有意思的,把一路都打通了。
该函数首先通过open函数打开设备结点。
"/dev/graphics/fb%u"和"/dev/fb%u",如果前一个顺利打开的话,那么就不打开第二个。我的Log显示打开的是第一个设备结点/dev/graphics/fb%u。
    然后通过ioctl读取设备的固定参数(FBIOGET_FSCREENINFO)和可变参数(FBIOGET_VSCREENINFO)。
【kernel部分的代码在drivers/video/fbmem.c中。】
    然后对可变参数进行修改,通过ioctl设置(FBIOPUT_VSCREENINFO)显示屏的可变参数。
    设置好以后再ioctl-FBIOGET_VSCREENINFO获得可变参数,然后在log上打出显示屏的各个参数设置,也就是我们开机看到的一长串log。

I/gralloc ( 1620): using (fd=8) 
I/gralloc ( 1620): id = truly-ILI9327 
I/gralloc ( 1620): xres = 240 px 
I/gralloc ( 1620): yres = 400 px 
I/gralloc ( 1620): xres_virtual = 240 px 
I/gralloc ( 1620): yres_virtual = 800 px 
I/gralloc ( 1620): bpp = 16 
I/gralloc ( 1620): r = 11:
I/gralloc ( 1620): g = 5:
I/gralloc ( 1620): b = 0:
I/gralloc ( 1620): width = 38 mm (160.421051 dpi) 
I/gralloc ( 1620): height = 64 mm (158.750000 dpi) 
I/gralloc ( 1620): refresh rate = 60.00 Hz

    然后通过mmap完成对显示缓存区的映射。这样mapFrameBufferLocked函数的任务算是完成了。
好了,以上所讲的只是(1)中的第一句话而已
Displayhardware.cpp中的init函数。

mNativeWindow = new FramebufferNativeWindow();

SurfaceFlinger启动过程分析(四)

在加载完framebuffer和gralloc模块之后,我们来看FramebufferNativeWindow构造函数中的代码:


buffers[0] = new NativeBuffer(
                fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
buffers[1] = new NativeBuffer(
                fbDev->width, fbDev->height, fbDev->format, GRALLOC_USAGE_HW_FB);
        
        err = grDev->alloc(grDev,
                fbDev->width, fbDev->height, fbDev->format, 
                GRALLOC_USAGE_HW_FB, &buffers[0]->handle, &buffers[0]->stride);

        LOGE_IF(err, "fb buffer 0 allocation failed w=%d, h=%d, err=%s", fbDev->width,fbDev->height, strerror(-err));
        err = grDev->alloc(grDev,
                fbDev->width, fbDev->height, fbDev->format, 
                GRALLOC_USAGE_HW_FB, &buffers[1]->handle, &buffers[1]->stride);

        LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s",fbDev->width,fbDev->height, strerror(-err));



    该构造函数中关键的就剩下这四句高亮代码了,这四句也是framebuffer双缓存机制的关键。
    首先新建了两个NativeBuffer,然后通过grDev为它们分配内存空间。这个grDev就是上面gralloc_open的gralloc设备模块。
grDev - >alloc这个函数在gralloc_device_open函数里面指定了是gralloc.cpp中的gralloc_alloc函数。


dev->device.alloc = gralloc_alloc;


    为两个缓冲区分配完内存之后,FramebufferNativeWindow构造函数的事情就算完了。下面继续看DisplayHardware.cpp中init函数接下去的代码。


DisplayHardware.cpp

if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
        overlay_control_open(module, &mOverlayEngine);
    }
// initialize EGL

...


接下去就获得overlay模块,前提是你的设备支持overlay。
然后就初始化EGL。

DisplayHardware.cpp


EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, NULL, NULL);
    eglGetConfigs(display, NULL, 0, &numConfigs);

    EGLConfig config;
    status_t err = EGLUtils::selectConfigForNativeWindow(
            display, attribs, mNativeWindow.get(), &config);

eglGetDisplay是EGL用来获取物理屏幕句柄的函数。返回的是EGLDisplay,代表一个物理显示设备。调用这个函数进入的是egl.cpp[frameworks/base/opengl/libs/egl]




EGLDisplay eglGetDisplay(NativeDisplayType display)
{
    uint32_t index = uint32_t(display);
    if (index >= NUM_DISPLAYS) {
        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
    }

    if (egl_init_drivers() == EGL_FALSE) {
        return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
    }   
    EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
    return dpy;
}

它会调用egl_init_drivers去初始化设备。


egl_init_drivers->egl_init_drivers_locked
下面简单贴一下egl_init_drivers_locked代码:


EGLBoolean egl_init_drivers_locked()
{
    if (sEarlyInitState) {
        // initialized by static ctor. should be set here.
        return EGL_FALSE;
    }
    // get our driver loader
    Loader& loader(Loader::getInstance());
cnx = &gEGLImpl[IMPL_SOFTWARE];
    if (cnx->dso == 0) {
cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
        if (cnx->dso) {
            EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
            LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
            d->disp[IMPL_SOFTWARE].dpy = dpy; 
            if (dpy == EGL_NO_DISPLAY) {
                loader.close(cnx->dso);
                cnx->dso = NULL;
            }
        }
    }

    cnx = &gEGLImpl[IMPL_HARDWARE];
    if (cnx->dso == 0) {
         
...
        } else {
            LOGD("3D hardware acceleration is disabled");
        }
    }
    return EGL_TRUE;
}



egl_init_drivers_locked() 函数的作用就是填充 gEGLImpl[IMPL_SOFTWARE] gEGLImpl[IMPL_ HARDWARE] 两个数组项。达到通过 gEGLImpl[IMPL_SOFTWARE] gEGLImpl[IMPL_ HARDWARE] 两个数组项就可以调用 libGLES_android.so 库中所有函数的目的

cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];



上面这两句代码的作用是引用赋值,在loader . open完以后
cnx - >hooks[GLESv1_INDEX]会被赋值,而相对应的
gHooks [GLESv1_INDEX ] [IMPL_SOFTWARE ]也会被赋值。

Loader的构造函数先从/system/lib/egl/egl.cfg中读取配置,如果不存在,那就选用默认配置。


Loader::Loader()
{
    char line[256];
    char tag[256];
    FILE* cfg = fopen("/system/lib/egl/egl.cfg", "r");
    if (cfg == NULL) {
        // default config
        LOGD("egl.cfg not found, using default config");
        gConfig.add( entry_t(0, 0, "android") );
    } else {
        while (fgets(line, 256, cfg)) {
            int dpy;
            int impl;
            if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) {
                //LOGD(">>> %u %u %s", dpy, impl, tag);
                gConfig.add( entry_t(dpy, impl, tag) );
            }
        }
        fclose(cfg);
    }
}


默认的配置为(0, 0, "android")并把它放在gConfig中,以备在调用Loader.open的时候使用。

void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx)
{
    /*
     * TODO: if we don't find display/0, then use 0/0
     * (0/0 should always work)
     */
   
    void* dso;
    char path[PATH_MAX];
    int index = int(display);
    driver_t* hnd = 0;
    const char* const format = "/system/lib/egl/lib%s_%s.so";   
    char const* tag = 
getTag(index, impl);
    if (tag) {
        snprintf(path, PATH_MAX, format, "GLES", tag);
        dso = load_driver(path, cnx, EGL | GLESv1_CM | GLESv2);
        if (dso) {
            hnd = new driver_t(dso);
        } else {
            // Always load EGL first
            snprintf(path, PATH_MAX, format, "EGL", tag);
            dso = load_driver(path, cnx, EGL);
            if (dso) {
                hnd = new driver_t(dso);
                // TODO: make this more automated
                snprintf(path, PATH_MAX, format, "GLESv1_CM", tag);
                hnd->set( load_driver(path, cnx, GLESv1_CM), GLESv1_CM );
                snprintf(path, PATH_MAX, format, "GLESv2", tag);
                hnd->set( load_driver(path, cnx, GLESv2), GLESv2 );
            }
        }
    }
    LOG_FATAL_IF(!index && !impl && !hnd, 
            "couldn't find the default OpenGL ES implementation "
            "for default display");    
    return (void*)hnd;
}

      


      Loader::open 这个函数首先去加载 /system/lib/egl/libGLES_android.so ,如果加载成功,那么对 EGL | GLESv1_CM | GLESv2 三个函数库,进行初始化。如果加载不成功,那么就加载 libEGL_android.so libGLESv1_CM_android.so libGLESv2_android.so 这三个库 ,事实上我们的 /system/lib/egl 目录下面只有 libGLES_android.so 这一个库,所以加载 libGLES_android.so 库。

PslibEGL.so libGLESv1_CM.so libGLESv2.so三个库在/system/lib目录下面。

下面简单地分析下EGL的配置。首先在Loader的构造函数中获取了EGL的配置信息0, 0, "android",然后把它放在一个结构体中,这个结构体名为entry_t,定义如下


struct entry_t {
        entry_t() { }
        entry_t(int dpy, int impl, const char* tag);
        int dpy;
        int impl;
        String8 tag;
};


随后在Loader::open中调用getTag(index, impl),其实为getTag(0, 0)。所以getTag返回的是字符串android


const char* Loader::getTag(int dpy, int impl)
{
    const Vector<entry_t>& cfgs(gConfig); 
    const size_t c = cfgs.size();
    for (size_t i=; i<; i++) {
        if (dpy == cfgs[i].dpy)
            if (impl == cfgs[i].impl)
                return cfgs[i].tag.string();
    }
    return 0;
}


现在有了库的路径path = /system/lib/egl/libGLES_android.so通过load_driver函数来加载函数库。


Loader::load_driver

 


void *Loader::load_driver(const char* driver_absolute_path,
        egl_connection_t* cnx, uint32_t mask)
{
    if (access(driver_absolute_path, R_OK)) {
        // this happens often, we don't want to log an error

        return 0;
    }//加载libGLES_android.so

void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
    if (dso == 0) {
        const char* err = dlerror();
        LOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
        return 0;
    }
    LOGD("loaded %s", driver_absolute_path);
    if (mask & EGL) {//加载EGL函数库

        getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
        LOGE_IF(!getProcAddress, 
                "can't find eglGetProcAddress() in %s", driver_absolute_path);
        egl_t* egl = &cnx->egl;//把函数赋值到cnx->egl中

        __eglMustCastToProperFunctionPointerType* curr =
            (__eglMustCastToProperFunctionPointerType*)egl;
        char const * const * api = egl_names;
        while (*api) {
            char const * name = *api;
            __eglMustCastToProperFunctionPointerType f = 
                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
            if (== NULL) {
                // couldn't find the entry-point, use eglGetProcAddress()

                f = getProcAddress(name);
                if (== NULL) {
                    f = (__eglMustCastToProperFunctionPointerType)0;
                }
            }
            *curr++ = f;
            api++;
        }
    }
    if (mask & GLESv1_CM) {//加载GLESv1_CM函数库

        init_api(dso, gl_names,
            (__eglMustCastToProperFunctionPointerType*)
                &cnx->hooks[GLESv1_INDEX]->gl,
            getProcAddress);
    }
    if (mask & GLESv2) {//加载GLESv2函数库

      init_api(dso, gl_names,
            (__eglMustCastToProperFunctionPointerType*)
                &cnx->hooks[GLESv2_INDEX]->gl,
            getProcAddress);
    }
    return dso;
}



通过系统调用 dlopen 打开一个动态链接库。 以下是百度百科对 dlopen 的解释:

dlopen()
  功能:打开一个动态链接库 
  包含头文件: 
  #include <dlfcn.h> 
  函数定义: 
  void * dlopen( const char * pathname, int mode ); 
  函数描述: 
  在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。使用dlclose()来卸载打开的库。


然后通过dlsym函数获得指向函数地址指针。 以下是百度百科对 dlsym 的解释:

dlsym()的函数原型是 
  void* dlsym(void* handle,const char* symbol) 
  该函数在<dlfcn.h>文件中。 
  handle是由dlopen打开动态链接库后返回的指针,symbol就是要求获取的函数的名称,函数返回值是void*,指向函数的地址,供调用使用。

dlsym首先去得到eglGetProcAddress的函数指针,这个函数的原型:void (*eglGetProcAddress(const char *procname)) ();

该函数的作用是返回由procname指定的扩展函数地址。

下面综述一下load_driver函数所做的工作:首先通过dlopen加载libGLES_android.so库,库所在路径为/system/lib/egl/libGLES_android.so,然后从libGLES_android.so库中提取EGL的各个API函数的地址放到cnx->egl中,从libGLES_android.so获取GLESv1_CMAPI保存到cnx->hooks[GLESv1_INDEX]->gl中,从libGLES_android.so获取GLESv1_CMAPI保存到cnx->hooks[GLESv2_INDEX]->gl

提取EGLAPI地址的方法是首先通过dlsym函数获得一个获取函数地址的函数eglGetProcAddress的地址,然后遍历EGLAPI所在文件frameworks/base/opengl/libs/EGL/egl_entries.in。先通过dlsym获取各个API地址,如果返回NULL再利用eglGetProcAddress去获得,如果依旧为空就把函数地址赋值为0;提取GLESv1_CMGLESv1_CM库中函数地址方法和提取EGL差不多,只是他们的函数文件保存在frameworks/base/opengl/libs/entries.in中。还有它们把函数地址复制给了cnx->hooks[GLESv1_INDEX]->glcnx->hooks[GLESv2_INDEX]->gl

 

等加载完库以后在libs/egl/egl.cpp里面的egl_init_drivers_locked就通过cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);调用eglGetDisplay函数,其实就是调用libGLES_android.so里面的eglGetDisplay函数,libGLES_android.so库是由目录frameworks/base/opengl/libagl生成的,所以libGLES_android.so里面的eglGetDisplay函数是文件libagl/egl.cpp里面的。

其实libs/egl/egl.cpp中的函数,大多是调用libGLES_android.so库里面的,是对其的一种封装,也就是说调用libagl/egl.cpp文件里面的同名函数,如eglGetDisplayeglCreateWindowSurfaceeglCreateContext等。因为libGLES_android.so库是由rameworks/base/opengl/libagl目录生成。

SurfaceFlingerSurfaceFlinger SurfaceFlinger SurfaceFlinger SurfaceFlinger SurfaceFlingerSurfaceFlinger 服务是在 服务是在 服务是在 SystemSystemSystemSystemSystem 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 进程启动的,并且负责统一管理设备帧缓冲区。 SurfaceFlingerSurfaceFlinger SurfaceFlinger SurfaceFlinger SurfaceFlinger SurfaceFlingerSurfaceFlinger 服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件服务在启动的过程, 会创建两个线其一用来监控制台事件而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 而另外一个线程用来渲染系统的 UI 。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值