Android显示系统非常复杂,从早期版本演化至今有很大的变化和改进,所以从当前的版本直接去查看会很困难。
初学者看到繁多的概念和类会感到无从下手。
这里我们将从实践应用的方式来展开这一系列,试图对Android的显示系统进行窥探。
Android应用通过surface绘图和SurfaceFlinger进行图像数据交互,Java层的surface绘图流程比较繁琐,
这里我们直接通过一个C++程序来得到一个surface来和SurfaceFlinger进行交互,来达到一个直观的效果。
#define LOG_TAG "bindertest" #include <stdio.h> #include <binder/IInterface.h> #include <binder/Parcel.h> #include <binder/IBinder.h> #include <binder/Binder.h> #include <binder/ProcessState.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <iostream> #include <iomanip> #include <unistd.h> //for ALOGD #include <log/log.h> #include <cutils/memory.h> //test socketpair #include <sys/types.h> #include <error.h> #include <errno.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <android/native_window.h> using namespace android; using namespace std; // int main(int argc, char** argv) { //the color is ABGR int color = 0xFF0000FF; //这个用来确定当前屏幕的ARGB显示顺序 if (argc == 2 && argv[1][0] == '1') color = 0xFFFF0000; if (argc == 2 && argv[1][0] == '2') color = 0xFF000000; if (argc == 2 && argv[1][0] == '3') color = 0xFF00FF00; if (argc == 2 && argv[1][0] == '4') color = 0x00FF00FF; if (argc == 2 && argv[1][0] == 'b') color = 0x00000000; if (argc == 2 && argv[1][0] == 'a') color = 0x00FF00FF; // set up the thread-pool sp<ProcessState> proc(ProcessState::self()); ProcessState::self()->startThreadPool(); // create a client to surfaceflinger sp<SurfaceComposerClient> client = new SurfaceComposerClient(); sp<SurfaceControl> surfaceControl = client->createSurface(String8("testDraw"), 160, 240, PIXEL_FORMAT_RGBA_8888, 0); sp<Surface> 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_memset32((uint32_t*)outBuffer.bits, color, bpr*outBuffer.height); surface->unlockAndPost(); cout << "outBuffer.stride = " << outBuffer.stride << ", bytesPerPixel(outBuffer.format) = " << bytesPerPixel(outBuffer.format) << ", outBuffer.height = " << outBuffer.height << endl; IPCThreadState::self()->joinThreadPool(); return 0; }
Android.mk
LOCAL_PATH := $(call my-dir)
#for service
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
service.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libutils \
liblog \
libbinder \
libcutils libskia libui libgui
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_MODULE:= testDraw
include $(BUILD_EXECUTABLE)
这里通过对surface的操作,在应用中获取到了在SurfaceFlinger中分配的内存地址,
写入color值,在界面上进行了显示
ANativeWindow_Buffer outBuffer;
surface->lock(&outBuffer, NULL);
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
android_memset32((uint32_t*)outBuffer.bits, color, bpr*outBuffer.height);
surface->lock(&outBuffer, NULL);这句话是冰山一角,里面有一系列操作,
这篇的目的是对surface有个初步的概念,混个脸熟,所以在这里并不去深入的分析各处理流程,
这个程序的执行结果
在手机上显示160*240的surface
使用我们的老朋友dumpsys来和SurfaceFlinger来个心灵对话,可以看到在SurfaceFlinger中生成了相应的Layer
dumpsys SurfaceFlinger
+ Layer 0x76b8edd000 (testDraw#0)
Region transparentRegion (this=0x76b8edd380, count=1)
[ 0, 0, 0, 0]
Region visibleRegion (this=0x76b8edd010, count=1)
[ 0, 0, 160, 240]
Region surfaceDamageRegion (this=0x76b8edd088, count=1)
[ 0, 0, 0, 0]
layerStack= 0, z= 100000, pos=(0,0), size=( 160, 240), crop=( 0, 0, -1, -1), finalCrop=( 0, 0, -1, -1), isOpaque=0, invalidate=0, dataspace=Default (0), pixelformat=RGBA_8888 alpha=1.000, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00]
client=0x76ba1aa2c0
format= 1, activeBuffer=[ 160x 240: 160, 1], queued-frames=0, mRefreshPending=0
mSecure=0, mProtectedByApp=0, mFiltering=0, mNeedsFiltering=0 mDestroyCalled=0
mTexName=8 mCurrentTexture=0
mCurrentCrop=[0,0,0,0] mCurrentTransform=0
mAbandoned=0
- BufferQueue mMaxAcquiredBufferCount=1 mMaxDequeuedBufferCount=2
mDequeueBufferCannotBlock=0 mAsyncMode=0
default-size=[160x240] default-format=1 transform-hint=00 frame-counter=1
FIFO(0):
this=0x76ba1c9000 (mConsumerName=testDraw#0, mConnectedApi=2, mConsumerUsageBits=2304, mId=19, mPid=8411, producer=[12222:./testDraw], consumer=[8411:/system/bin/surfaceflinger])
Slots:
>[00:0x76bd8407a0] state=ACQUIRED 0x76bd840f80 frame=1 [ 160x 240: 160, 1]
在上面的图片中,你会发现,状态栏(statusbar)覆盖在我们所绘制的图层上面,为什么呢,
查看下dumpsys中打印的信息就清楚了,
Display 0 HWC layers:
-------------------------------------------------------------------------------
Layer name
Z | Comp Type | Disp Frame (LTRB) | Source Crop (LTRB)
-------------------------------------------------------------------------------
com.google.android.googlequicksearch[...]ps.gsa.searchnow.SearchNowActivity#1
21005 | Device | 0 0 720 1280 | 0.0 0.0 720.0 1280.0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
InputMethod#0
22005 | Device | 0 48 720 1280 | 0.0 0.0 720.0 1232.0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
testDraw#0
100000 | Device | 0 0 160 240 | 0.0 0.0 160.0 240.0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
StatusBar#0
181000 | Device | 0 0 720 48 | 0.0 0.0 720.0 48.0
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
我们设置的图层Z-order值是100000
surfaceControl->setLayer(100000)
小于StatusBar的181000,所以181000显示在了最上层
小结:
这篇文章主要是通过一个浅显的例子来加深我们的理解,即应用通过surface进行绘图,SurfaceFlinger管理应用的图层