2011-11-18 13:06:24

 

2011-11-18 13:06:24


SurfaceFlinger的启动过程还是从Zygote说起。Zygote起来后会调用SystemServer.java[frameworks/base/services/java/com/android/server]

里面的main函数,然后调用本地函数init1(),然后调用的是JNI的com_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();
    }

 
 根据属性 system_init.startsurfaceflinger  是否为1 启动这个服务1
 
 
然而,另一方面,有一个可执行文件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函数。

通过可执行文件来启动SurfaceFlinger

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将在下节分析


注意带这个线程类


SurfaceFligner是Android画形化的核心,网上有几篇关于这个C/S系统的分析,着实不错,我在文章最后的参考文章中都列出来 了,

大家可以先看一下那些文章从原理上对SurfaceFlinger系统的分析再看我这篇文章。我这篇文章偏重于具体代码上的实现,

最后汇总成一个小的 应用程序来演示如何与SurfaceFlinger交互,例子中使用的2D图形引擎。

源码在这里:http://code.google.com/p/flying-on-android/

使用的SurfaceFlinger系统可以分为这么几步:建立连接、创建Surface、取得Canvas、绘制、提交Canvas。下面来具体分析一下

Surface 和 Canvas 之间的关系

1、建立连接

这个比较简单,先把示例代码贴上来

1
 session = new SurfaceComposerClient;
代码很简单,具体SurfaceComposerClient如何通过IBinder与SurfaceFlinger通信比较复杂,

可以本文后面列出的“参考文章“当中其它作者的分析。

2、创建Surface

在Java层,View树最后是绘制在Surface上面的,一个Surface对应了SurfaceFlinger中的一个Layer。我们要绘 画,

必须先取得一个Surface并在上面画东西,画完了通过session向SurfaceFlinger一提交,就显示在屏幕上了。

呵。。。似乎只要涉及到代码,都很简单了。

1
2
3
 surfaceControl = session->createSurface(getpid(), 0, display.w, display.h,
 
PIXEL_FORMAT_RGBA_8888);
surfaceControl用来控制Surface属性。

1
 surface = surfaceControl->getSurface();
surface才代表真正的Surface。


创建surface 和 获取 surface

3、取得Canvas

用程序绘制UI,其实就是借助图形引擎提供的点、线、面函数最后形成一个包含像素信息的数组并提交给图形驱动

(Linux上是 FrameBuffer)的过程。现在我们拥有一个Surface,那么就可以取得Surface属性信息并把这些信息提供给图形引擎

(这里是 skia),图形引擎根据这些信息就可以构造出一张Bitmap的形式提供给我们。我们拿到Bitmap是不可以直接在上面绘画的

,还需要把它包装成 Canvas。这样,我们调用Canvas的绘画API时,最终改变了Bitmap的内容。Bitmap的数据都存储在一个二维数组中

,每个数组的元素代 表了一个像素值。看一下关键代码


 surface->lock(&info, &dirtyRegion);//获取Surface属性信息到info当中
 
bitmap.setPixels(info.bits);//构造Bitmap
 
canvas.setBitmapDevice(bitmap);//把Bitmap封装成Canvas
4、绘制

Canvas构造好了,就可以调用drawLine,drawColor等进行绘制了。这里我们做的很简单,只是把整个Canvas渲染成黑色。

1
 canvas->drawColor(0xff000000);
5、提交Canvas

提交过程,实际上就是把Bitmap中的像素数组通过Surface传递给服务端SurfaceFlinger中与我们拥有的这个Surface对应的Layer,并告诉SurfaceFlinger把它渲染到屏幕。一句代码就可以搞定了。

1
 surface->unlockCanvasAndPost();
我自己学习工作时,深刻体会到十篇讲原理的不如一段演示代码来的实在,就把这个过程写成了一个可以编译运行的小程序放到了这里:

如何你对这个话题比较感兴趣,可以把例子下载下来一边看代码一边看这篇文章。只要把它放到/frameworks/base/cmds目录下,

然后 切换到这个模块下运行mm命令,会自动编译成一个名字为flying的程序安装到/system/bin,只要把它复制出来放到机器的/system /bin目录下,然后在通过Shell运行就可以了。

我是在Android2.3下面完成的,其它的系统版本没有试过。

如果只要看效果的话,资源中也包含可执行文件,直接把它复制到/system/bin下面运行即可。

 

如何打开和关闭输入法

一、打开输入法窗口:


 InputMethodManager inputMethodManager = (InputMethodManager)            
 getSystemService(Context.INPUT_METHOD_SERVICE);
 
// 接受软键盘输入的编辑文本或其它视图
 
imm.showSoftInput(submitBt,InputMethodManager.SHOW_FORCED);
二、关闭出入法窗口

 InputMethodManager inputMethodManager = (InputMethodManager)            
getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(OpeListActivity.this.getCurrentFocus().getWindowTok
InputMethodManager.HIDE_NOT_ALWAYS);
//接受软键盘输入的编辑文本或其它视图
 inputMethodManager
 .showSoftInput(submitBt,InputMethodManager.SHOW_FORCED);
三、如果输入法打开则关闭,如果没打开则打开

1
2
3
 InputMethodManager m=(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
 
m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
四、获取输入法打开的状态

1
2
 InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
boolean isOpen=imm.isActive();
isOpen若返回true,则表示输入法打开

好了先介绍这两个技巧。

Tags:  Android SurfaceFlinger 绘图Android 输入法Android-surfaceflinger

 

第二部分 surfaceFlinger_client  与 surfaceflinger之间的数据交流
 surfaceFlinger_client  与 surfaceflinger之间的数据交互主要分成显示数据与控制数据交流。先看下控制数据是怎么交流的。
全局的信息控制块。如下:
我们都是通过ComposerService::getComposerService()这样的方式来获取到SurfaceFlinger对象的指针的。
ComposerService是一个单例类,在构造函数之中可以看到:

    mServerCblkMemory = mComposerService->getCblk();
    mServerCblk = static_cast<surface_flinger_cblk_t volatile *>(
    mServerCblkMemory->getBase());

在SurfaceFlinger.cpp中的实现是创建一个4KB大小的数据块,并且将surface_flinger_cblk_t对象分配到这个4KB的数据块中,
在这个surface_flinger_cblk_t对象中保存中整个系统能显示的长度,宽度,能显示的格式,显示的旋转角度等信息。


其中有个大小为4的数组:display_cblk_t displays[SharedBufferStack::NUM_DISPLAY_MAX];可以这么讲,理论上可以支持4个显示屏,
但是现在基本只使用了第0个数组元素。这就是全局上的控制信息块。我们也可以看到SurfaceComposerClient会使用这个控制块信息向外
提供高宽等信息。如:SurfaceComposerClient::getDisplayInfo (DisplayID dpy, DisplayInfo* info) ,dpy一般都为0,
如果为了开发android的双屏或者多屏显示,这将是需要继续研究下去的。


单个surface控制块:
从第一部分得知,在surfaceFlinger_client中会生成一个Surface对象来封装SurfaceControl。


可以注意到mClient(SurfaceClient::getInstance()) 这个成员变量。 查看代码可以得知SurfaceClient是一个单例类,
也就是说只会存在一个对象在系统之中。 看下它的实现:
将获取到系统中的SurfaceFlinger 对象指针。并且获取到当前SurfaceFlinger_client相关的控制块对象指针。

该控制块是SharedClient类型。再转到该类型中我们可以看到一个其中有一个对象数组:
SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];

NUM_LAYERS_MAX的值是31,没错,这个就是系统中能支持的最多的surface层数。这个算是单个surface的控制信息块。 
  可以具体先看下SharedBufferStack的具体实现。
接下来具体看下SharedClient控制块信息具体是怎么起到一个控制作用的。
 在Surface的init函数中可以看到int32_t token = mClient.getTokenForSurface(mSurface);这行代码是从surfaceflinger
 中查询下mSurface这个Surface在surfaceflinger中的ID值,mSurface则是第一部分当中提到创建的surface。
 在surfaceflinger中的实现中是这样的,首先查询包含ISurface的layer当中是否设置了token,如果设置直接返回,如果没有则从0开始查询哪个值可用(要小于31),找到则设置到layer中,
 我们在这里可以找到一个新的控制块,一个在surfaceflinger中使用的控制块: SharedBufferServer,我们看看这个的实现就知道,
 SharedBufferServer这个跟SharedClient一样,是对同一块内存的封装,其中也包含一个对象数组:
SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];

没错,跟SharedClient中的就是同一个。大家可以这样想,通过第一部分大家都知道了android在绘图时会使用前后两个buffer,
在surfaceflinger_client中会标记哪个是前bufer,哪一个是后buffer,这个标记是在SharedBufferStack中进行的,然后surfaceflinger
则可以根据SharedBufferStack中的标记来使用前buffer进行叠加绘图。而这个token的值就是标记一个surface使用的是
SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ]这个数据中的哪一个元素。这下OK了吧,清晰了些吧?
而在layer中,会把SharedBufferServer封装到自己的mUserClientRef成员变量当中。而在Sruface当中则会把这个封装到SharedBufferClient当中,
SharedBufferClient对象讲拥有一个SharedBufferStack,这个SharedBufferStack对象就是以自己的token为序数的
SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ]数组成员。
在SharedBufferServer还对SharedBufferStack的数据成员做了初始化工作,head成为1, token为分配到token,available为2表明是两个可以使用的buffer。
mBufferList.add(i);mSharedStack->index[i] = i;这两个都会只使用0,1两个值,虽然index数组有16个值。同时buffers数组也一样,
只会使用16个元素中的前两个2个元素。

前文仅了解了overlay HAL的架构,下面继续看看系统层是如何调用Overlay模块。

1、 测试代码

frameworks/base/libs/surfaceflinger/tests/overlays/overlays.cpp提供了一个简单的overlay调用流程,可惜这个测试程序有错误,
    在sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240, PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);
这句话编译不过去,错误在Surface的申请,和overlay无关。

我们来看看这段代码:

int main(int argc, char** argv)
{
    // set up the thread-pool 建立线程池
    sp<ProcessState> proc(ProcessState::self());
    ProcessState::self()->startThreadPool();

    // create a client to surfaceflinger 创建一个SurfaceFlinger client
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
   
    // create pushbuffer surface 创建一个surface,最后那个参数是类型?
    sp<Surface> surface = client->createSurface(getpid(), 0, 320, 240,
            PIXEL_FORMAT_UNKNOWN, ISurfaceComposer::ePushBuffers);

    // get to the isurface 取得isurface接口
    sp<ISurface> isurface = Test::getISurface(surface);
    printf("isurface = %p\n", isurface.get());
   
    // now request an overlay 创建一个overlay
    sp<OverlayRef> ref = isurface->createOverlay(320, 240, PIXEL_FORMAT_RGB_565);
    sp<Overlay> overlay = new Overlay(ref);
   
    /*
     * here we can use the overlay API 创建好overlay后,即可使用overlay的API,这些都对应到overlay HAL的具体实现
     */
   
    overlay_buffer_t buffer;
    overlay->dequeueBuffer(&buffer);
    printf("buffer = %p\n", buffer);
   
    void* address = overlay->getBufferAddress(buffer);
    printf("address = %p\n", address);

    overlay->queueBuffer(buffer);//最重要的操作就是通过queueBuffer将buffer列队

    return 0;
}

2、Android系统创建中Overlay(调用createOverlay)

1)摄像头相关 CameraService.cpp (frameworks\base\camera\libcameraservice)
setPreviewDisplay()、startPreviewMode()
|
setOverlay()
|
creatOverlay()

2)界面相关 ISurface.cpp (frameworks\base\libs\ui)
LayerBaseClient::Surface::onTransact() <--该函数位于LayerBase.cpp,好像是用于ibind进程通讯的函数
|
BnSurface::onTransact() //有5种方式,只有确定有overlay硬件支持时才会调用case CREATE_OVERLAY
|
... ...
switch(code) {
        case REQUEST_BUFFER: {
            CHECK_INTERFACE(ISurface, data, reply);
            int bufferIdx = data.readInt32();
            int usage = data.readInt32();
            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
            return GraphicBuffer::writeToParcel(reply, buffer.get());
        }
        case REGISTER_BUFFERS: {
            CHECK_INTERFACE(ISurface, data, reply);
            BufferHeap buffer;
            buffer.w = data.readInt32();
            buffer.h = data.readInt32();
            buffer.hor_stride = data.readInt32();
            buffer.ver_stride= data.readInt32();
            buffer.format = data.readInt32();
            buffer.transform = data.readInt32();
            buffer.flags = data.readInt32();
            buffer.heap = interface_cast<IMemoryHeap>(data.readStrongBinder());
            status_t err = registerBuffers(buffer);
            reply->writeInt32(err);
            return NO_ERROR;
        } break;
        case UNREGISTER_BUFFERS: {
            CHECK_INTERFACE(ISurface, data, reply);
            unregisterBuffers();
            return NO_ERROR;
        } break;
        case POST_BUFFER: {
            CHECK_INTERFACE(ISurface, data, reply);
            ssize_t offset = data.readInt32();
            postBuffer(offset);
            return NO_ERROR;
        } break;
        case CREATE_OVERLAY: {
            CHECK_INTERFACE(ISurface, data, reply);
            int w = data.readInt32();
            int h = data.readInt32();
            int f = data.readInt32();
            sp<OverlayRef> o = createOverlay(w, h, f);
            return OverlayRef::writeToParcel(reply, o);
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
... ...


3)LayerBuffer.cpp (frameworks\base\libs\surfaceflinger) 这儿其实是createOverlay的实现
sp<OverlayRef> LayerBuffer::SurfaceLayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t format)
|
sp<OverlayRef> LayerBuffer::createOverlay(uint32_t w, uint32_t h, int32_t f)
|
sp<OverlaySource> source = new OverlaySource(*this, &result, w, h, f); //通过OverlaySource来创建overlay

 

LayerBuffer::OverlaySource::OverlaySource()//该函数调用了Overlay HAL的API createOverlay
{
    overlay_control_device_t* overlay_dev = mLayer.mFlinger->getOverlayEngine();//get HAL
    overlay_t* overlay = overlay_dev->createOverlay(overlay_dev, w, h, format);//HAL API

    // enable dithering...
    overlay_dev->setParameter(overlay_dev, overlay, OVERLAY_DITHER, OVERLAY_ENABLE);
//设置参数,初始化OverlayRef类,OverlayRef的构造函数在Overlay.cpp中
    mOverlay = overlay;
    mWidth = overlay->w;
    mHeight = overlay->h;
    mFormat = overlay->format;
    mWidthStride = overlay->w_stride;
    mHeightStride = overlay->h_stride;
    mInitialized = false;
... ...
    *overlayRef = new OverlayRef(mOverlayHandle, channel,mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
}

3、Overlay HAL模块管理
Overlay.cpp (frameworks\base\libs\ui)负责管理overlay HAL,并对HAL的API进行封装

1)打开Overlay HAL模块

Overlay::Overlay(const sp<OverlayRef>& overlayRef)
    : mOverlayRef(overlayRef), mOverlayData(0), mStatus(NO_INIT)
{
    mOverlayData = NULL;
    hw_module_t const* module;
    if (overlayRef != 0) {
        if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
            if (overlay_data_open(module, &mOverlayData) == NO_ERROR) {
                mStatus = mOverlayData->initialize(mOverlayData,
                        overlayRef->mOverlayHandle);
            }
        }
    }
}

数据打开 初始化

2)Overlay HAL的初始化
参考上一段,overlayRef = new OverlayRef(mOverlayHandle, channel,mWidth, mHeight, mFormat, mWidthStride, mHeightStride);

构造函数位于Overlay.cpp
OverlayRef::OverlayRef(overlay_handle_t handle, const sp<IOverlay>& channel,
         uint32_t w, uint32_t h, int32_t f, uint32_t ws, uint32_t hs)
    : mOverlayHandle(handle), mOverlayChannel(channel),
    mWidth(w), mHeight(h), mFormat(f), mWidthStride(ws), mHeightStride(hs),
    mOwnHandle(false)
{
}

3)封装了很多的API,但是没有查到那儿有调用,看来还需要大改框架才能真正将overlay利用起来
比如TI自己写的opencore函数中到时有用到,主要负责视频输出。
Android_surface_output_omap34xx.cpp (hardware\ti\omap3\libopencorehw)

 4、总结
Overlay的输出对象有两种,一种是视频(主要是YUV格式,调用系统的V4L2),
另外一个是ISurface的一些图像数据(RGB格式,直接写framebuffer)

从代码实现角度看,目前Android系统默认并没有使用Overlay功能,虽然提供了Skeleton的Overlay HAL,并对其进行封装,但是上层几乎没有调用到封装的API。
如果要用好Overlay HAL,需要大量修改上层框架,这对视屏播放可能比较重要,可参考TI的Android_surface_output_omap34xx.cpp。
此外Surface实现的Overlay功能和Copybit的功能有部分重复,从TI的代码看主要是实现V4L2的Overlay功能。

 

 

你可能感兴趣的:(2011-11-18 13:06:24)