Android SurfaceFlinger 분석

개요

안드로이드는 응용 프로그램에서 만든 메뉴나 다이얼로그 박스, 사용자 인터페이스 구성 요소들을 SurfaceFlinger를 통하여 리눅스 커널에 위치한 LCD 디스플레이 드라이버인 프레임 버퍼 드라이버를 통해 그림을 그리게 됩니다.

Android SurfaceFlinger & FB

안드로이드 GDI의 구조를 이해하기 위해서 하위레벨에서 상위레벨로 접근하여 살펴보도록 하겠습니다.

FrameBuffer

커널 영역에 위치한 프레임 버퍼는 LCD 등의 출력 장치를 위한 디스플레이 하드웨어를 제어하기 위한 디바이스 드라이버입니다. 사용자 영역에서 프레임 버퍼로 그래픽 데이터를 출력 장치에 표시합니다. 프레임 버퍼는 출력장치에 표시될 그래픽 데이터가 가장 마지막으로 보관되며 출력 장치에 같은 해상도의 크기와 픽셀 포멧으로 설정됩니다. 프레임 버퍼의 데이터는 출력장치에서 요구하는 기준에 맞춰 주기적으로 출력 장치에 출력됩니다.

안드로이드에서 /dev/graphics/fb0 형태로 프레임 버퍼 드라이버를 오픈 하여 mmap() 함수를 사용하여 프레임 버퍼에 대한 직접적인 제어를 통해 LCD를 제어할 수 있도록 하고 있습니다.
프레임 버퍼 드라이버는 리눅스 시스템에서 사용자 레벨의 응용 프로그램에서 제어할 수 있도록 만들어진 디바이스 드라이버입니다. 또한 open, mmap과 같은 표준 인터페이스 함수를 통해 이용할 수 있는 구조로 구성되어 있습니다.

FrameBuffer

위 그림에서는 프레임 버퍼 드라이버의 동작 모습을 사용자의 응용 프로그램 관점에서 보여줍니다. 사용자의 응용 프로그램에서 작성한 화면은 프레임 버퍼 드라이버를 거쳐, 프로세서 내부에 있는 LCD 컨트롤러를 통해 LCD에 표시되게 됩니다. 물론 안드로이드 시스템에서는 프로그램을 작성하여 운영할 수 있지만, 앱이나 사용자의 프로세스에서 만들어진 모든 동작들은 SurfaceFlinger를 통해 운영이 됩니다. 즉, 사용자의 응용 프로그램과 프레임 버퍼 드라이버상에 위치하여 관리하게 됩니다. 따라서 프레임 버퍼에 대한 윈리의 이해, SurfaceFlinger에 대한 정확한 동작의 이해가 필요합니다.

프레임 버퍼 드라이버의 일반적인 사항

  • 디바이스 드라이버로써 이식성을 높이기 위해 사용됨 표시장치의 종류가 많고, 이러한 여러 하드웨어를 고려하지 않고 표준화된 인터페이스를 제공하기 위함
  • 통상 /dev/fb0, dev/graphics/fb0 형태로 장치 드라이버가 구성되어 있고 드라이버가 할당한 메모리를 사용자 응용 프로그램에서 사용할 수 있도록 메모리 매핑하여 사용함
  • 사용자 응용 프로그램에서 전송한 프레임 버퍼 데이터를 LCD 드라이버가 수신하여 LCD 컨트롤러를 통해 TFT LCD나 다른 표시 장치에 출력하는 역할을 함

안드로이드 시스템에서 프레임 버퍼 드라이버의 특이사항

  • 기존 리눅스 프레임 버퍼 드라이버에 struct fp_ops와 fb_ pan_display 함수가 추가로 구현되어야 함
  • 실제 프레임 버퍼 크기보다 두 배의 메모리 할당 필요 해당 함수는 프레임 버퍼의 디스플레이 포인터를 옮기는 기능을 제공한다. 즉, 실제 화면보다 넓은 가상 디스플레이를 구현 가능하도록 함
  • 안드로이드 시스템의 프레임 버퍼 드라이버는 고속 처리를 위해 반드시 더블 버퍼링(Double Buffering)을 사용하도록 구성됨

Android 7.0 기준 프레임버퍼(fb)제어

Android 7.0 기준 프레임버퍼(fb)제어는 아래 폴더를 통해 제어 가능합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
rk3328_box:/sys/devices/fb.17/graphics/fb0 # ls -al
total 0
drwxr-xr-x 3 root root 0 1970-01-01 00:00 .
drwxr-xr-x 7 root root 0 1970-01-01 00:00 ..
-rw-rw-r-- 1 root system 4096 1970-01-01 00:00 bcsh
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 bits_per_pixel
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 blank
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 cabc
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 cabc_lut
--w------- 1 root root 4096 1970-01-01 00:33 car_reverse
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 console
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 cursor
-r--r--r-- 1 root root 4096 1970-01-01 00:33 dev
lrwxrwxrwx 1 root root 0 1970-01-01 00:33 device -> ../../../fb.17
-r--r--r-- 1 root root 4096 1970-01-01 00:33 disp_info
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 dsp_buf
-rw-rw-r-- 1 root system 4096 1970-01-01 00:00 dsp_lut
-r--r--r-- 1 root root 4096 1970-01-01 00:33 dsp_mode
-r--r--r-- 1 root root 4096 1970-01-01 00:33 dual_mode
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 dump_buf
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 enable
-rw-r--r-- 1 root root 4096 1970-01-01 00:00 fps
-rw-rw-r-- 1 root system 4096 1970-01-01 00:00 hdr_bt1886eotf
-rw-rw-r-- 1 root system 4096 1970-01-01 00:00 hdr_st2084oetf
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 hwc_lut
-r--r--r-- 1 root root 4096 1970-01-01 00:00 lcdcid
-rw-rw-r-- 1 root system 4096 1970-01-01 00:00 map
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 mode
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 modes
-r--r--r-- 1 root root 4096 1970-01-01 00:33 name
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 overlay
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 pan
-r--r--r-- 1 root root 4096 1970-01-01 00:33 phys_addr
drwxr-xr-x 2 root root 0 1970-01-01 00:00 power
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 rotate
-rw-rw-r-- 1 system graphics 4096 1970-01-01 00:00 scale
-rw-r--r-- 1 root root 4096 1970-01-01 00:00 screen_info
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 state
-r--r--r-- 1 root root 4096 1970-01-01 00:33 stride
lrwxrwxrwx 1 root root 0 1970-01-01 00:33 subsystem -> ../../../../class/graphics
-rw-r--r-- 1 root root 4096 1970-01-01 00:00 uevent
-r--r--r-- 1 root root 4096 1970-01-01 00:33 virt_addr
-rw-r--r-- 1 root root 4096 1970-01-01 00:33 virtual_size
-r--r--r-- 1 root root 4096 1970-01-01 00:00 vsync
-r--r--r-- 1 root root 4096 1970-01-01 00:33 win_property

상기 폴더의 파일을 read 함으로서 fb의 정보를 얻을 수 있습니다.
아래는 screen_info를 read한 것입니다.

1
2
3
4
5
6
rk3328_box:/sys/devices/fb.17/graphics/fb0 # cat screen_info
xres:1920
yres:1080
fps:60
type:6
interlace:0

몇몇 파일은 write 함으로서 fb를 제어할 수 있습니다.

1
2
3
4
5
6
7
rk3328_box:/sys/devices/fb.17/graphics/fb0 # cat scale
xscale=100 yscale=100
left=100 top=100 right=100 bottom=100
rk3328_box:/sys/devices/fb.17/graphics/fb0 # echo xscale=70 > scale
rk3328_box:/sys/devices/fb.17/graphics/fb0 # cat scale
xscale=70 yscale=100
left=70 top=100 right=70 bottom=100

위 명령은 화면의 x축 크기를 70%로 줄인 것입니다.
위 명령을 통해서 화면의 크기가 축소된 것을 확인할 수 있습니다.

SurfaceFlinger

SurfaceFlinger의 역할은 앞에서 앱이나 사용자의 응용 프로그램에서 생성한 화면(여기에서는 Surface라는 용어를 사용함) 합성 관리하는 역할입니다. “Surface+Flinger”의 합성입니다. Surface의 “표면”이라는 의미와 Flinger의 “던지는 사람”이라는 조합으로 SurfaceFlinger 기능을 이 두 단어가 모두 함축하고 있습니다. 즉, 생성된 여러 개의 Surface를 하나의 Surface로 만들고 이 만든 화면을 프레임 버퍼 드라이버와 연계하여 프레임 버퍼로 만들고, LCD 화면에 표시하는 역할을 하는 것입니다.

SurfaceFlinger

Surface는 2D나 3D일 ㅅ 있고, RGB888 또는 RGB565등 다양한 형태의 포멧일 수 있습니다. SurfaceFlinger는 이러한 Surface를 지원하며, Framebuffer에서 원하는 형태의 포멧으로 합성하여 FrameBuffer에 던져줍니다.

SurfaceFlinger 관련 용어

Surface

하나의 화면을 이야기합니다. 일반적인 윈도우 개념으로 생각하면 됩니다. 실제로는 소프트웨어적인 Overlay를 이야기합니다. Surface는 클라이언트쪽(어플리케이션) 입장에서만 사용하는 용어입니다. 서버쪽에서는 실제로 옵션에 따라 적절한 Layer를 생성합니다.

SurfaceComposer

Surface와 SurfaceFlinger와의 연결을 처리하고, 여러가지 Surface로부터 SurfaceFlinger로 전달되는 제어 오퍼레이션을 담당합니다.(연결, 클라이언트로부터 트랜잭션등 처리.)

Surface를 생성할 때는 반드시 SurfaceComposer에 대한 접속 포인트인 SurfaceComposerClient 클래스를 생성한 후에 Surface를 생성합니다.

SurfaceFlinger

클라이언트인 Surface로부터 전달된 데이터를 합성 후 HAL로 전달하는 역할을 하는 안드로이드의 디스플레이 서버입니다. 이 서버는 시작된 후에는 스레드 루프를 돌면서 Surface로부터 데이터가 입력되거나, 화면이 업데이트되어야 하는 경우에 입력된 데이터의 좌표(X,Y,Z축)에 따라 Surface를 합성하고 이를 HAL로 전달해서 LCD 화면에 디스플레이할 수 있도록 제어합니다.

Layer

Surface를 구성하는 클래스로 Surface의 용도의 특성을 결정짓습니다. SurfaceFlinger쪽에서 사용되고 생성되는 클래스틑 LayerBase클래스에서 상속된 Layer, LayerBuffer, LayerDim, LayerBlur의 네종류의 클래스가 생성됩니다.

gralloc

SurfaceFlinger를 구성하는 HAL의 하나로, 그래픽 버퍼용 메모리를 매핑하고 디스플레이 device driver를 제어합니다. 대부분의 칩 벤더에서는 이 부분을 바이너리 형태로 제공해 디버깅하는데 제약사항이 생기는 경우가 많습니다.

Overlay

SurfaceFlinger를 구성하는 HAL의 하나로, LayerBuffer의 하부 구조 중 일부를 담당합니다. 실제로는 일반적으로 표현되는 하드웨어 Overlay를 이야기하며, 주로 멀티미디어 관련 연산에 사용되는 경우가 많습니다.

SurfaceFlinger 관련 소스 리스트

클라이언트

  • frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
  • frameworks/base/core/java/android/view/*

라이브러리

  • frameworks/base/core/jni/android_view_Surface.cpp
  • frameworks/native/libs/gui/Surface.cpp Surface* / ISurface*
  • frameworks/native/services/surfaceflinger/*
공유하기