在前面的章节中,简单的分析了android显示系统的框架,我们知道一个应用程序之中,存在一个或者多个buffer用来存放界面的数据,单应用程序构造好这些buffer之后,他会把这些buffer发送给surfaceFlinger,由surfaceFlinger决定在合适的时候把buffer中的数据拷贝到framebuffer,这样才能在屏幕上显示界面。应用程序的buffer需要向surfaceFlinger进行申请。
surfaceFlinger管理着两个驱动程序,一个为ashmem(匿名共享内存),其中应用程序的buffer来自ashmem(匿名共享内存)。同时还管理者多个应用程序发送过来的buffer,由他决定如何把这多个应用程序的数据叠加起来,最终发送给framebuffer。下面我们编写一个Surface测试程序。
Surface测试程序流程编写改程序,最核心的东西就是如何得到buffer,写buffer,最后再提交buffer。 上图的APP是我们的引用程序,存在一个或者多个buf(用来存放界面数据),多个buf合成一个surface(APP的界面)。这些buf是想surfaceFlinger申请的。
编写Surface测试程序流程如下: 1.获得surfacelinger服务 2.创建surface。 3.得到buffer 4.写buffer 5.提交buffer 其中3,4,5是一个循环的过程,如上图中的3个buffer,提交完第一个buf的时候,APP可以构建第二个buf,当第二个构建成功然后提交,紧接着构造第三个buffer,这样进行循环。
Surface测试程序编写从头到尾写一个测试程序是十分困难的,在安卓5.0的源码中android-5.0.2\frameworks\native\services\surfaceflinger\tests\resize目录下存在文件Android.mk,与resize.cpp。我们把其拷贝到RK3399安卓源码7.1,frameworks\native\services\surfaceflinger\tests\APP_0010_Surfacetest(自己创建),并且修改resize.cpp为SurfaceTest.cpp。可惜的是,该测试程序并不能直接使用 mmm命令编译通过。还要做一些修改,修改之后代码如下: SurfaceTest.cpp:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
int main()
{
// set up the thread-pool
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger
sp client = new SurfaceComposerClient();
sp surfaceControl = client->createSurface(String8("resize"),
160, 240, PIXEL_FORMAT_RGB_565, 0);
sp surface = surfaceControl->getSurface();
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
surface->unlockAndPost();
surface->lock(&outBuffer,NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
surface->unlockAndPost();
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setSize(320, 240);
SurfaceComposerClient::closeGlobalTransaction();
IPCThreadState::self()->joinThreadPool();
return 0;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
SurfaceTest.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libui \
libgui \
libbinder
LOCAL_MODULE:= SurfaceTest
LOCAL_MODULE_TAGS := tests
include $(BUILD_EXECUTABLE)
编写完成上面两个文件之后,使用mmm命令编译,然后重新生生system.img烧写到开发板。
启动开发板之后,执行命令SurfaceTest,可以看到屏幕的做上角出现一块绿色的区域。我们把这个版本的代码保存下来为APP_0010_Surfacetest-v1,
下面是我们APP_0010_Surfacetest-v2版本
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
int main()
{
// set up the thread-pool
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger
/*获得SurfaceComposerClient服务*/
sp client = new SurfaceComposerClient();
/*创建Surface*/
sp surfaceControl = client->createSurface(String8("resize"),
160, 240, PIXEL_FORMAT_RGB_565, 0);
sp surface = surfaceControl->getSurface();
SurfaceComposerClient::openGlobalTransaction();
/*设置Z轴高度*/
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
ANativeWindow_Buffer outBuffer;
/*获得这个surface的一个buf*/
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
/*填充buf*/
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
/*提交buf给surfaceflinger,让其显示*/
surface->unlockAndPost();
/*增加一个休眠时间*/
sleep(3);
surface->lock(&outBuffer,NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
surface->lock(&outBuffer,NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setSize(320, 240);
SurfaceComposerClient::closeGlobalTransaction();
IPCThreadState::self()->joinThreadPool();
return 0;
}
编译之后可以看三种颜色以一定时间间隔不停的交换。
最后是编写我们的APP_0010_Surfacetest-v3版本:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
int main()
{
// set up the thread-pool
sp proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create a client to surfaceflinger
/*获得SurfaceComposerClient服务*/
sp client = new SurfaceComposerClient();
/*创建Surface*/
sp surfaceControl = client->createSurface(String8("resize"),
160, 240, PIXEL_FORMAT_RGB_565, 0);
sp surface = surfaceControl->getSurface();
SurfaceComposerClient::openGlobalTransaction();
/*设置Z轴高度*/
surfaceControl->setLayer(100000);
SurfaceComposerClient::closeGlobalTransaction();
ANativeWindow_Buffer outBuffer;
/*获得这个surface的一个buf*/
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
/*填充buf*/
android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
/*提交buf给surfaceflinger,让其显示*/
surface->unlockAndPost();
/*增加一个休眠时间*/
sleep(3);
surface->lock(&outBuffer,NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x07E0, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
surface->lock(&outBuffer,NULL);
android_memset16((uint16_t*)outBuffer.bits, 0x001F, bpr*outBuffer.height);
surface->unlockAndPost();
sleep(3);
for(int i = 0; i lock(&outBuffer,NULL);
printf("%03d buff addr = 0x%x\n",i,(unsigned long)outBuffer.bits);
surface->unlockAndPost();
}
IPCThreadState::self()->joinThreadPool();
return 0;
}
在这个版本中,我们打印了outBuffer.bits的地址,在开发板运行之后,打印信息如下:
000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000
000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000
000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000
000 buff addr = 0x5844000
000 buff addr = 0x5831000
000 buff addr = 0x581e000
000 buff addr = 0x5e87000
......
......
我们可以发现,其使用了四个buf,后面都是重复使用。这样我们知道对于同一个应用程序。他分配了3个buf。
如果我们在上面的程序添加代码 surfaceControl->setLayer(100000),改变其z轴高度,我们可以实现对显示的隐藏或者遮挡。