<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
 <title type="html">닉스로그</title>
 <id>http://cranix.net/atom</id>
 <link rel="alternate" type="text/html" hreflang="ko" href="http://cranix.net/"/>
 <subtitle type="html"></subtitle>
 <updated>2010-03-22T11:41:52+09:00</updated>
 <generator>Textcube.com 2.0 Garnet</generator>
 <entry>
  <title type="html">이클립스에 안드로이드 소스코드 연결하기</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/321"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/321" thr:count="0"/>
  <category term="Android"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/321</id>
  <updated>2010-03-22T00:37:14+09:00</updated>
  <published>2010-03-22T00:37:14+09:00</published>
  <summary type="html"> 들어가며 안드로이드 소스를 분석하다보면 시스템쪽의 java 소스를 봐야할 경우가 많은데 이클립스상에서 따라내려갈 수 없게 되어있어서 불편할때가 많았다. 안드로이드 sdk 에다가 이클립스 소스를 연결하는법을 알아보도록 하자. SDK 에 안드로이드 소스 링크걸기 이클립스에서는 기본적으로 jar 파일에다가 소스 링크걸기를 지원한다. 그런데 안드로이드의 jar 파일은 이 기능이 꺼져있어서 임의로 링크 걸수없게 되있다. 그러나 이클립스에서 안드로이드 프로젝트를 만들어서 android.jar 파일의 Source attachment 부분을 보면 기본적으로 경로가 잡혀있음을 알 수 있다. 결국 해당 경로에 sources 디렉토리를 만들어서 소스를 넣어주면 링크가 된다는 소리다. 그러기 위해서는 소스를 먼저 다운받아야 하는데 아래 글을 참조해서 다운 받기로 하자. android 소스 다운로드 받기&amp;nbsp; 그다음 sdk 를 설치한 경로의 platform/android-7 디렉토리에 다가 심볼릭 링크를 걸어주면 된다. # ln -s eclare_src/ android-sdk-linux_86/platforms/android-7/sources 이클립스가 켜져있다면 F5 를 눌러서 리플래쉬 해 주면 소스를 로딩하는것을 볼 수있다. 이제 원하는 소스를 마음대로 볼 수 있다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/321&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">우분투에 이클립스 ADT 설치하기</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/320"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/320" thr:count="0"/>
  <category term="Android"/>
  <category term="adt"/>
  <category term="Eclipse"/>
  <category term="wst"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/320</id>
  <updated>2010-03-21T16:22:32+09:00</updated>
  <published>2010-03-21T16:22:24+09:00</published>
  <summary type="html"> ADT 업데이트 일단 이클립스의 Help-&amp;gt;Update 로 들어가서 아래 주소를 입력한다. &amp;nbsp;https://dl-ssl.google.com/android/eclipse/ 그런데 설치를 진행하면 아래와같은 오류로 더이상 안되는 경우가 있다. 우분투에서 apt-get 으로 이클립스를 설치했을 경우 기본적인 플러그인만 설치되기때문에 이런 현상이 많이 발생한다. Cannot complete the install because one or more required items could not be found. &amp;nbsp; Software being installed: Android Development Tools 0.9.6.v201002051504-24846 (com.android.ide.eclipse.adt.feature.group 0.9.6.v201002051504-24846) &amp;nbsp; Missing requirement: Android Development Tools 0.9.6.v201002051504-24846 (com.android.ide.eclipse.adt.feature.group 0.9.6.v201002051504-24846) requires &amp;#039;org.eclipse.wst.sse.ui 0.0.0&amp;#039; but it could not be found 해결하기 위해서는 필요한 플러그인을 먼저 설치해주면 된다. 위의 오류에서는 wst 가 필요하다고 하는데 이는 웹관련 툴을 의미하는것으로 ADT 에서 웹관련 툴을 사용하는것으로 판단된다. WST를 설치하기 위해서는 이클립스 업데이트 사이트에 아래 주소를 입력하자. http://download.eclipse.org/releases/galileo &amp;quot;Eclipse Web Developer Tools&amp;quot; 를 찾아서 설치하자. 설치가 다 끝나면 이제다시 ADT 를 설치하면 제대로 설치 될 것이다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/320&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">안드로이드 소스 컴파일 하기</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/319"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/319" thr:count="0"/>
  <category term="Android"/>
  <category term="Android"/>
  <category term="compile"/>
  <category term="ubuntu9.10"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/319</id>
  <updated>2010-03-21T14:05:20+09:00</updated>
  <published>2010-03-21T13:56:41+09:00</published>
  <summary type="html">필요한 라이브러리 설치하기 컴파일 하기위해서 필요한 라이브러리를 한꺼번에 설치하자. # apt-get install git-core gnupg flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl libncurses5-dev zlib1g-dev # apt-get install valgrind 자바 1.5 설치하기 안드로이드는 아직 자바 1.6을 지원하지 않는다. 그래서 1.5 를 설치해야 하는데 문제는 우분투 9.10 에서는 자바 1.5 를 apt-get 으로 설치할수 없다는 것이다. 그래서 아래와 같은 방법이 필요하다. 시스템&amp;gt;관리&amp;gt;소프트웨어 소스를 선택하면 [소프트웨어 소스] 창이 뜬다. 여기서 기타 소프트웨어 탭에서 아래 와 같이 추가해 주자. deb http://kr.archive.ubuntu.com/ubuntu/ jaunty multiverse deb http://kr.archive.ubuntu.com/ubuntu/ jaunty-updates multiverse 창을 닫으면 소프트웨어를 다시 읽는것을 볼 수 있다. 내 컴퓨터 같은경우는 다시 읽다가 거의 다된 시점에서 계속 멈추어 있길래 취소를 눌러주었다. 뭔가 오류가 났지만 상관없이 진행되었다. 다되었으면 apt-get 으로 설치해 보도록 하자. &amp;nbsp;# apt-get install sun-java5-jdk &amp;nbsp;이제 설치되었다면 버젼을 확인해 보자. &amp;nbsp;# java -version &amp;nbsp;만약 1.5 가 아니라면 아래 명령으로 자바 리스트를 확인한후 업데이트 시켜주자. # update-java-alternatives -l java-1.5.0-sun 53 /usr/lib/jvm/java-1.5.0-sun java-6-sun 63 /usr/lib/jvm/java-6-sun # update-java-alternatives -s java-1.5.0-sun &amp;nbsp;만약 자바 버젼을 바꾸는 도중 아래와 같은 메시지를 볼 수도 있을것이다. update-alternatives: error: no alternatives for firefox-javaplugin.so. update-alternatives: error: no alternatives for iceape-javaplugin.so. update-alternatives: error: no alternatives for iceweasel-javaplugin.so. update-alternatives: error: no alternatives for jhat. update-alternatives: error: no alternatives for jrunscript. update-alternatives: error: no alternatives for midbrowser-javaplugin.so. update-alternatives: error: no alternatives for mozilla-javaplugin.so. update-alternatives: error: no alternatives for schemagen. update-alternatives: error: no alternatives for wsgen. update-alternatives: error: no alternatives for wsimport. update-alternatives: error: no alternatives for xjc. update-alternatives: error: no alternatives for xulrunner-1.9-javaplugin.so. update-alternatives: error: no alternatives for xulrunner-javaplugin.so. update-alternatives: error: no alternatives for firefox-javaplugin.so. update-alternatives: error: no alternatives for iceape-javaplugin.so. update-alternatives: error: no alternatives for iceweasel-javaplugin.so. update-alternatives: error: no alternatives for midbrowser-javaplugin.so. update-alternatives: error: no alternatives for mozilla-javaplugin.so. update-alternatives: error: no alternatives for xulrunner-1.9-javaplugin.so. update-alternatives: error: no alternatives for xulrunner-javaplugin.so. 이것은 안드로이드 소스 컴파일과는 관계없지만 다른 어플을 실행하는데 문제가 될 수도 있기 때문에 아래와 같이 sun-java5-plugin 과 sun-java6-plugin 을 설치해 주자. &amp;nbsp;# apt-get install sun-java5-plugin sun-java6-plugin &amp;nbsp; 컴파일 하기 이제 컴파일할 환경은 다 갖추어 졌다. 다운받은 안드로이드 소스에는 크로스 컴파일 환경까지 갖추어져 있다. (안드로이드 소스 다운받는법은 android 소스 다운로드 받기&amp;nbsp;를 참조하자) 그래서 컴파일을 하기위해서는 &amp;quot;build/envsetup.sh&amp;quot; 파일을 환경등록 해주어야 한다. 다운받은 소스의 루트 디렉토리에서 아래와같이 실행해서 환경등록 해주도록 하자. &amp;nbsp;# source build/envsetup.sh 다되었다면 이제 make 를 하면 된다. &amp;nbsp;# make 안드로이드 소스는 최초 컴파일시 시간이 무척오래 걸린다. 사실 -j 옵션으로 스레드를 돌려주면 시간을 약간 줄일 수 있다. 그런데 이 옵션은 최초 컴파일시는 왠만해서 사용하지 않는것이 좋다. 왜냐하면 먼저 컴파일 된 것을 참조하는 구문이 있을수도 있는데 그런곳에서 오류가 나서 컴파일이 멈추어 버리는 현상이 나오기 때문이다. 일단 처음에는 느리더라고 그냥 make 를 쓰자. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/319&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">Android HAL 인터페이스</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/318"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/318" thr:count="0"/>
  <category term="Android"/>
  <category term="Android"/>
  <category term="Hal"/>
  <category term="hardware"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/318</id>
  <updated>2010-03-20T20:17:35+09:00</updated>
  <published>2010-03-20T20:13:37+09:00</published>
  <summary type="html"> 들어가며 안드로이드에는 디바이스 드라이버위에 HAL 계층이 뚜렷하게 존재한다. 이것은 디바이스 드라이버와 유사한 형식으로 구현되며 .so 파일로 저장되어서 동적으로 로딩된다. framebuffer, gps, sensor 등 대부분의 HAL 은 이 인터페이스를 따르는 형태로 구현되어있다. 이번 포스트에서는 이 인터페이스에 대해서 알아보도록 하자. hello HAL 모듈 만들기 안드로이드 HAL 모듈의 헤더 파일은 공개되어 있어야 한다. 그래야지 안드로이드 System 내에서 include &amp;lt;&amp;gt; 형태로 바로 사용할 수 있기 때문이다. 그래서 따로 HAL 헤도 파일을 모아놓은 디렉토리를 제공하는데 &amp;quot;hardware/libhardware/include/hardware&amp;quot; 디렉토리 이다. 먼저 여기에 hellomodule.h 라는 헤더를 만들자. #include &amp;lt;hardware/hardware.h&amp;gt; struct hello_device_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;hw_device_t device; &amp;nbsp;&amp;nbsp; &amp;nbsp;int deviceIdx; &amp;nbsp;// privite 변수 }; struct hello_module_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;hw_module_t common; &amp;nbsp;&amp;nbsp; &amp;nbsp;int maxDeviceIdx; // module 전역변수 }; static int hello_close(struct hw_device_t* device); int hello_open(const hw_module_t* module, const char* name,hw_device_t** device); HAL 모듈에서 쓰는 구조체는 hardware.h 에서 선언되어져 있는 hw_device_t 와 hw_module_t 이다. 먼저 hw_module_t 는 하나의 모듈정보를 담는 변수로서 한번만 생성된다. hw_device_t 구조체는 디바이스를 open 할 때마다 생성되어지는 구조체로서 각 디바이스 하나를 의미한다. 이에대한 내용은 cpp 파일을 보면서 자세히 다뤄보도록 하자. 이제 소스를 구성해야 하는데 소스디렉토리는 &amp;quot;hardware/libhardware/modules&amp;quot; 이다. 일단 이 여기에 hellomodule 라는 디렉토리를 만들고 hellomodule.cpp 파일을 만들도록 하자. #include &amp;lt;hardware/hellomodule.h&amp;gt; #include &amp;lt;stdlib.h&amp;gt; &amp;nbsp; &amp;nbsp; // malloc,memset #include &amp;lt;errno.h&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;// EINVAL #include &amp;lt;cutils/log.h&amp;gt; // LOGI() static struct hw_module_methods_t hello_module_methods = { &amp;nbsp;&amp;nbsp; &amp;nbsp;open: hello_open }; struct hello_module_t HAL_MODULE_INFO_SYM = { &amp;nbsp;&amp;nbsp; &amp;nbsp;common: { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tag: HARDWARE_MODULE_TAG, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;version_major: 1, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;version_minor: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id: &amp;quot;hello&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;name: &amp;quot;hello module&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;author: &amp;quot;cranix&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;methods: &amp;amp;hello_module_methods &amp;nbsp;&amp;nbsp; &amp;nbsp;}, &amp;nbsp;&amp;nbsp; &amp;nbsp;maxDeviceIdx: 0 }; static int hello_close(struct hw_device_t* dev){ &amp;nbsp;&amp;nbsp; &amp;nbsp;LOGI(&amp;quot;hello_close\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp;hello_device_t* ctx = reinterpret_cast&amp;lt;hello_device_t*&amp;gt;(dev); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (ctx) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;free(ctx); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return 0; } int hello_open(const hw_module_t* module,const char* name, hw_device_t** device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;int status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp;hello_device_t *dev; &amp;nbsp;&amp;nbsp; &amp;nbsp;LOGI(&amp;quot;hello_open\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp;hello_module_t* mod = (hello_module_t*)module; &amp;nbsp;&amp;nbsp; &amp;nbsp;dev = (hello_device_t*)malloc(sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp;memset(dev,0,sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp;dev-&amp;gt;device.tag = HARDWARE_DEVICE_TAG; &amp;nbsp;&amp;nbsp; &amp;nbsp;dev-&amp;gt;device.version = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;dev-&amp;gt;device.module = const_cast&amp;lt;hw_module_t*&amp;gt;(module); &amp;nbsp;&amp;nbsp; &amp;nbsp;dev-&amp;gt;device.close = hello_close; &amp;nbsp;&amp;nbsp; &amp;nbsp;dev-&amp;gt;deviceIdx = ++(mod-&amp;gt;maxDeviceIdx); &amp;nbsp;&amp;nbsp; &amp;nbsp;*device = &amp;amp;dev-&amp;gt;device; &amp;nbsp;&amp;nbsp; &amp;nbsp;status = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;return status; } 안드로이드 HAL 인터페이스에 연결하기 위해서는 위와 같이 HAL_MODULE_INFO_SYM 라는 이름의 hw_module_t 형태의 구조체를 선언하고 있어야 한다. 위의 hello_module_t 구조체는 hw_module_t 구조체를 제일 위에 포함하고 있기 때문에 저렇게 써도 무방하다. 위와같이 hello_open 함수를 hw_module_t 구조체에 등록해 주면 안드로이드에서 HAL 을 로드할때 알아서 실행해 준다. hello_open 함수가 해야하는 일은 결과적으로 module 에 해당하는 device 하나를 생성해서 돌려주는 일이다. 위 소스에서는 hello_device_t 구조체를 생성해서 close 에 hello_close 함수를 등록 한다음 deviceIdx 을 module 에서 관리하는 maxDeviceIdx 로 셋팅해 주는 역할을 한다. hello HAL 모듈 make 하기 Android.mk 파일을 아래와 같이 만들자. LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SHARED_LIBRARIES := liblog libcutils LOCAL_SRC_FILES := &amp;nbsp;\ &amp;nbsp;&amp;nbsp; &amp;nbsp;hellomodule.cpp &amp;nbsp; \ &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; LOCAL_MODULE := hellomodule.default LOCAL_CFLAGS:= -DLOG_TAG=\&amp;quot;hellomodule\&amp;quot; include $(BUILD_SHARED_LIBRARY) HAL 모듈은 &amp;quot;/system/lib/hw&amp;quot; 디렉토리에 위치해야 하고 이름은 hellomodule.default.so 로 되어야 하기때문에 위와 같은 형태로 만들어야 한다. 안드로이드 전체를 make 할 때 이 모듈까지 make 하게 해 주려면 &amp;quot;hardware/libhardware/Android.mk&amp;quot; 파일을 수정해야 한다. ... include $(addsuffix /Android.mk, $(addprefix $(LOCAL_PATH)/, \ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;modules/gralloc \ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;modules/hellomodule \ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;)) 위와 같이 &amp;quot;hardware/libhardware/Android.mk&amp;quot; 파일의 제일 아랫쪽에 자신이 만든 모듈의 디렉토리를 명시해 주자. 이제 make 를 실행해서 제대로 에러없이 컴파일 되는지 확인하자. hello HAL 모듈 사용하기 일단 모듈생성이 완료되었다면 사용해 보아야 한다. 그러나 최상위단까지 올려서 사용하기에는 너무 많은 시간이 소요된다. 그래서 생각한 방법이 external 에 테스트용 프로그램을 만들고 adb shell 에서 직접 실행하는 것이다. 그럼 external/hellomoduletest 라는 디렉토리를 만들고 hellomoduletest.c 파일을 작성한다. #include &amp;lt;stdio.h&amp;gt; #include &amp;lt;hardware/hellomodule.h&amp;gt; int main() { &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hello_device_t* device; &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hello_module_t* module; &amp;nbsp;&amp;nbsp; &amp;nbsp;int i; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hw_get_module(&amp;quot;hellomodule&amp;quot;,&amp;amp;module)==0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;hw_get_module ok!\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (i=0;i&amp;lt;5;i++) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (module-&amp;gt;common.methods-&amp;gt;open(module,0,&amp;amp;device)==0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;open ok!-idx:%d\n&amp;quot;,device-&amp;gt;deviceIdx); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;error open device\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (device-&amp;gt;device.close(device)==0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;close ok!-idx:%d\n&amp;quot;,device-&amp;gt;deviceIdx); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;error close device\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printf(&amp;quot;error get module!\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;return 0; } hardware.c 에서 제공하는 hw_get_module 함수를 이용해서 hellomodule 모듈을 동적으로 로딩한다음 해당 모듈에 등록되어진 open 함수를 불러서 device 를 5번 생성한다. 처리가 끝나면 device 의 close 함수를 호출해서 종료한다. 여기서 5번 생성하는 이유는 idx 가 증가하는것을 확인해 보기위해서 이다. 자 이제 다시한번 make 를 해서 에러없이 컴파일 되는것을 확인하자. hello HAL 실행해 보기 에러없이 컴파일이 되었다면 system.img 파일이 생성되었을 것이다. 저 파일을 에뮬레이터에 덮어씌운다음 에뮬레이터를 실행하자. 에뮬레이터가 다 실행되면 adb shell 로 들어와서 다음과같이 입력해보자. &amp;nbsp;# logcat&amp;amp; &amp;nbsp;# hellomoduletest hw_get_module ok! I/hellomodule( &amp;nbsp;211): hello_open open ok!-idx:1 I/hellomodule( &amp;nbsp;211): hello_close close ok!-idx:1 I/hellomodule( &amp;nbsp;211): hello_open open ok!-idx:2 I/hellomodule( &amp;nbsp;211): hello_close close ok!-idx:2 I/hellomodule( &amp;nbsp;211): hello_open open ok!-idx:3 I/hellomodule( &amp;nbsp;211): hello_close close ok!-idx:3 I/hellomodule( &amp;nbsp;211): hello_open open ok!-idx:4 I/hellomodule( &amp;nbsp;211): hello_close close ok!-idx:4 I/hellomodule( &amp;nbsp;211): hello_open open ok!-idx:5 I/hellomodule( &amp;nbsp;211): hello_close close ok!-idx:5 우리가 원하는 대로 device 의 idx 가 1씩 증가하는것을 볼 수 있다. 이런형태로 HAL 을 구성하면 된다. 여기서 hellomoduletest 를 한번 더 실행해 보자 idx 가 1부터 다시시작하는것을 볼 수 있을것이다. 이것은 hw_get_module 함수에서 dlopen 으로 동적로딩 한후 HMI 맵핑만 해주고 바로 dlclose 로 닫아버려서 다시 hw_get_module 이 호출되면 다시 dlopen 이 호출되어 초기값이 들어가기때문에 그렇다. 이러한 형태라면 hw_get_module 함수는 최소한으로 호출하는것이 적절할꺼 같다. 마치며 이와같은 형태라면 리눅스의 디바이스 드라이버와 마찬가지로 상위단에서 어떻게 돌아가는지 상관없이 이 부분 모듈만 짜는것으로 하드웨어 포팅이 가능할수 있을꺼 같다. 그리고 이부분을 분석하다가 알게된건데 SurfaceFlinger 쪽에서 gralloc HAL 을 얻어내기 위해서 hw_get_module 함수를 빈번히 호출하고 있던데 이부분은 부하가 우려된다. 버젼업될 안드로이드에서는 이러한 부분이 수정되었으면 하는 바램이다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/318&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">Surface Flinger</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/316"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/316" thr:count="0"/>
  <category term="Android"/>
  <category term="Android"/>
  <category term="Surface Flinger"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/316</id>
  <updated>2010-03-19T15:53:53+09:00</updated>
  <published>2010-03-19T15:53:53+09:00</published>
  <summary type="html">Surface Flinger 란 무엇인가? frame buffer HAL 은 디바이스 드라이버에서 올라가다가 마지막에 Surface Flinger 와 연결된다. 즉 Surface Flinger 는 frame buffer HAL 위에있는 또다른 추상화 계층이라고 볼 수 있다. 무엇을 추상화 하는지 알아보도록 하자. Surface Flinger 소스분석 먼저 &amp;quot;frameworks/base/libs/surfaceflinger/SurfaceFlinger.h&amp;quot; 파일을 시작점으로 하자. 일단 헤더에 정의된 클래스들과 멤버변수 부터 보자. class Client : public RefBase { public: &amp;nbsp;&amp;nbsp; &amp;nbsp;SharedClient* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ctrlblk; &amp;nbsp;&amp;nbsp; &amp;nbsp;ClientID &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;cid; private: &amp;nbsp;&amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mPid; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mBitmap; &amp;nbsp;&amp;nbsp; &amp;nbsp;SortedVector&amp;lt;uint8_t&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mInUse; &amp;nbsp;&amp;nbsp; &amp;nbsp;Vector&amp;lt; wp&amp;lt;LayerBaseClient&amp;gt; &amp;gt; &amp;nbsp; mLayers; &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;IMemoryHeap&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mCblkHeap; &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;SurfaceFlinger&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mFlinger; } class GraphicsPlane { private: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DisplayHardware* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mHw; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Transform &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTransform; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Transform &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mOrientationTransform; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Transform &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mGlobalTransform; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mOrientation; } class SurfaceFlinger : public BnSurfaceComposer, protected Thread { private: &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable &amp;nbsp; &amp;nbsp; MessageQueue &amp;nbsp; &amp;nbsp;mEventQueue; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable &amp;nbsp; &amp;nbsp; Mutex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mStateLock; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;State &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mCurrentState; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;State &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mDrawingState; &amp;nbsp;&amp;nbsp; &amp;nbsp;volatile &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTransactionFlags; &amp;nbsp;&amp;nbsp; &amp;nbsp;volatile &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTransactionCount; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Condition &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTransactionCV; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mResizeTransationPending; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Tokenizer &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTokens; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DefaultKeyedVector&amp;lt;ClientID, sp&amp;lt;Client&amp;gt; &amp;gt; &amp;nbsp; mClientsMap; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DefaultKeyedVector&amp;lt;SurfaceID, sp&amp;lt;LayerBaseClient&amp;gt; &amp;gt; &amp;nbsp; mLayerMap; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GraphicPlane &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mGraphicPlanes[1]; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mLayersRemoved; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Vector&amp;lt; sp&amp;lt;Client&amp;gt; &amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDisconnectedClients; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;IMemoryHeap&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mServerHeap; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;surface_flinger_cblk_t* &amp;nbsp; &amp;nbsp; mServerCblk; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GLuint &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mWormholeTexName; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mBootTime; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Permission &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mHardwareTest; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Permission &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mAccessSurfaceFlinger; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Permission &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDump; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDirtyRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDirtyRegionRemovedLayer; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mInvalidRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mWormholeRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mVisibleRegionsDirty; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDeferReleaseConsole; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mFreezeDisplay; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mFreezeCount; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mFreezeDisplayTime; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mDebugRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mDebugBackground; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;volatile nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDebugInSwapBuffers; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLastSwapBufferTime; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;volatile nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDebugInTransaction; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;nsecs_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLastTransactionTime; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mBootFinished; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable &amp;nbsp; &amp;nbsp; Barrier &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mReadyToRunBarrier; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;enum { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;eConsoleReleased = 1, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;eConsoleAcquired = 2 &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}; &amp;nbsp;&amp;nbsp; volatile &amp;nbsp; &amp;nbsp; int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mConsoleSignals; &amp;nbsp;&amp;nbsp; volatile &amp;nbsp; &amp;nbsp; int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mSecureFrameBuffer; class SurfaceFlinger::LayerVector { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;private: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; KeyedVector&amp;lt; sp&amp;lt;LayerBase&amp;gt; , size_t&amp;gt; lookup; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Vector&amp;lt; sp&amp;lt;LayerBase&amp;gt; &amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layers; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} } class FreezeLock { private: &amp;nbsp;&amp;nbsp; &amp;nbsp;SurfaceFlinger* mFlinger; } class BClient : public BnSurfaceFlingerClient { private: &amp;nbsp;&amp;nbsp; &amp;nbsp;ClientID &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mId; &amp;nbsp;&amp;nbsp; &amp;nbsp;SurfaceFlinger* &amp;nbsp; &amp;nbsp; mFlinger; &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;IMemoryHeap&amp;gt; &amp;nbsp; &amp;nbsp; mCblk; } 일단 여기서 보이는 것은 SurfaceFlinger 가 LayerVector 를 가지고 있다는 것이다. 이것만 놓고 생각했을때에는 SurfaceFlinger 가 Layer 들을 관리하고 Client 가 생성될때 마다 레이어를 만들어서 나눠줄꺼 같다. 그럼 클라이언트 소스를 약간 보자. Client::Client(ClientID clientID, const sp&amp;lt;SurfaceFlinger&amp;gt;&amp;amp; flinger) &amp;nbsp;&amp;nbsp; &amp;nbsp;: ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger) &amp;nbsp; &amp;nbsp; &amp;nbsp; { &amp;nbsp;&amp;nbsp; &amp;nbsp;const int pgsize = getpagesize(); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&amp;amp;~(pgsize-1)); &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;mCblkHeap = new MemoryHeapBase(cblksize, 0, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;SurfaceFlinger Client control-block&amp;quot;); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;ctrlblk = static_cast&amp;lt;SharedClient *&amp;gt;(mCblkHeap-&amp;gt;getBase()); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (ctrlblk) { // construct the shared structure in-place. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;new(ctrlblk) SharedClient; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;} } status_t Client::bindLayer(const sp&amp;lt;LayerBaseClient&amp;gt;&amp;amp; layer, int32_t id) { &amp;nbsp;&amp;nbsp; &amp;nbsp;ssize_t idx = mInUse.indexOf(id); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (idx &amp;lt; 0) &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return NAME_NOT_FOUND; &amp;nbsp;&amp;nbsp; &amp;nbsp;return mLayers.insertAt(layer, idx); } sp&amp;lt;LayerBaseClient&amp;gt; Client::getLayerUser(int32_t i) const { &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;LayerBaseClient&amp;gt; lbc; &amp;nbsp;&amp;nbsp; &amp;nbsp;ssize_t idx = mInUse.indexOf(uint8_t(i)); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (idx &amp;gt;= 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;lbc = mLayers[idx].promote(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE_IF(lbc==0, &amp;quot;getLayerUser(i=%d), idx=%d is dead&amp;quot;, int(i), int(idx)); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return lbc; } 소스를 보면 Client 에는 레이어를 생성하는 부분은 없다. 결국 레이어는 SurfaceFlinger 에서만 관리하는게 맞는거 같다. 또한 Client 는 레이어를 여러개 가질수 있게 되어있다. bindLayer 함수와 getLayerUser 함수를 보면 알 수 있다. 이것으로 Client 는 SurfaceFlinger 에서 생성되어 사용된다고 판단된다. 그럼 SurfaceFlinger 함수를 약간 보자. sp&amp;lt;ISurfaceFlingerClient&amp;gt; SurfaceFlinger::createConnection() { &amp;nbsp;&amp;nbsp; &amp;nbsp;Mutex::Autolock _l(mStateLock); &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t token = mTokens.acquire(); &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;Client&amp;gt; client = new Client(token, this); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (client-&amp;gt;ctrlblk == 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mTokens.release(token); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;status_t err = mClientsMap.add(token, client); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (err &amp;lt; 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mTokens.release(token); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;BClient&amp;gt; bclient = new BClient(this, token, client-&amp;gt;getControlBlockMemory()); &amp;nbsp;&amp;nbsp; &amp;nbsp;return bclient; } void SurfaceFlinger::destroyConnection(ClientID cid) { &amp;nbsp;&amp;nbsp; &amp;nbsp;Mutex::Autolock _l(mStateLock); &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;Client&amp;gt; client = mClientsMap.valueFor(cid); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (client != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Vector&amp;lt; wp&amp;lt;LayerBaseClient&amp;gt; &amp;gt; layers(client-&amp;gt;getLayers()); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const size_t count = layers.size(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;for (size_t i=0 ; i&amp;lt;count ; i++) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;LayerBaseClient&amp;gt; layer(layers[i].promote()); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (layer != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;purgatorizeLayer_l(layer); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mClientsMap.removeItem(cid); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mDisconnectedClients.add(client); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;setTransactionFlags(eTransactionNeeded); &amp;nbsp;&amp;nbsp; &amp;nbsp;} } SurfaceFlinger 에서 createConnection 과 destroyConnection 으로 Client 를 생성하고 삭제한다. 그런데 왜하필 connection 이라고 썻을까? createClient 라고 하면 안되었을까? 이것은 아마 웹서버와 비슷한 구조로 보인다. 예를들어 SurfaceFlinger 를 하나의 웹서버 라고 보면 Client 는 웹서버에 접속한 하나의 클라이언트 인 것이다. 그래서 connection 이라고 표현되어 있는것이다. 그리고 여기에 BClient 라는 클래스가 생성된다. 소스에서 보면 Client 에서 생성한 ControlBlockMemory 를 얻어와서 BClient 생성하는데 쓰는것을 볼 수 있다. 그럼 소스를 한번 보자. &amp;nbsp;BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp&amp;lt;IMemoryHeap&amp;gt;&amp;amp; cblk) &amp;nbsp;&amp;nbsp; &amp;nbsp;: mId(cid), mFlinger(flinger), mCblk(cblk) { } BClient::~BClient() { &amp;nbsp;&amp;nbsp; &amp;nbsp;// destroy all resources attached to this client &amp;nbsp;&amp;nbsp; &amp;nbsp;mFlinger-&amp;gt;destroyConnection(mId); } sp&amp;lt;IMemoryHeap&amp;gt; BClient::getControlBlock() const { &amp;nbsp;&amp;nbsp; &amp;nbsp;return mCblk; } sp&amp;lt;ISurface&amp;gt; BClient::createSurface( &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ISurfaceFlingerClient::surface_data_t* params, int pid, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DisplayID display, uint32_t w, uint32_t h, PixelFormat format, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t flags) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return mFlinger-&amp;gt;createSurface(mId, pid, params, display, w, h, format, flags); } status_t BClient::destroySurface(SurfaceID sid) { &amp;nbsp;&amp;nbsp; &amp;nbsp;sid |= (mId &amp;lt;&amp;lt; 16); // add the client-part to id &amp;nbsp;&amp;nbsp; &amp;nbsp;return mFlinger-&amp;gt;removeSurface(sid); } status_t BClient::setState(int32_t count, const layer_state_t* states) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return mFlinger-&amp;gt;setClientState(mId, count, states); } 소스가 상당히 짧은데 사실 여기서 하는일은 거의 없다. 그저 SurfaceFlinger 의 함수를 호출하는 일 밖에 없다. 그런데 이 함수를 만든 이유는 무엇일까? 그것은 바로 바인더 통신으로 넘기기 위해서이다. 바인더에 대해선 다음에 알아보자. 그럼 이제 레이어 에 대해서 알아보자 레이어는 client 의 bindLayer 함수에 의해 클라이언트에 추가된다. 이 것을 행하는 소스는 아마 SurfaceFlinger 에 있을것으로 예상되니 SurfaceFlinger.cpp 파일을 열어서 찾아보자. &amp;nbsp;sp&amp;lt;ISurface&amp;gt; SurfaceFlinger::createSurface(ClientID clientId, int pid, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ISurfaceFlingerClient::surface_data_t* params, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DisplayID d, uint32_t w, uint32_t h, PixelFormat format, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t flags) { &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;LayerBaseClient&amp;gt; layer; sp&amp;lt;LayerBaseClient::Surface&amp;gt; surfaceHandle; ... &amp;nbsp;&amp;nbsp; &amp;nbsp;switch (flags &amp;amp; eFXSurfaceMask) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;case eFXSurfaceNormal: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (UNLIKELY(flags &amp;amp; ePushBuffers)) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer = createPushBuffersSurfaceLocked(client, d, id, &amp;nbsp;w, h, flags); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer = createNormalSurfaceLocked(client, d, id, &amp;nbsp;w, h, flags, format); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;case eFXSurfaceBlur: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer = createBlurSurfaceLocked(client, d, id, w, h, flags); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;case eFXSurfaceDim: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer = createDimSurfaceLocked(client, d, id, w, h, flags); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;if (layer != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;setTransactionFlags(eTransactionNeeded); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;surfaceHandle = layer-&amp;gt;getSurface(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (surfaceHandle != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;params-&amp;gt;token = surfaceHandle-&amp;gt;getToken(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;params-&amp;gt;identity = surfaceHandle-&amp;gt;getIdentity(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;params-&amp;gt;width = w; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;params-&amp;gt;height = h; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;params-&amp;gt;format = format; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return surfaceHandle; } 찾아보았으나 bindLayer 는 SurfaceFlinger 에서 호출하지 않는다. 대신 createSurface 함수에서 Layer 를 만들도록 하였다. 만드는 함수가 createXXXXSurfaceLocked 로 되어있으니 그중 가장 Normal 한것을 열어보도록 하자. &amp;nbsp;sp&amp;lt;LayerBaseClient&amp;gt; SurfaceFlinger::createNormalSurfaceLocked( &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const sp&amp;lt;Client&amp;gt;&amp;amp; client, DisplayID display, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t id, uint32_t w, uint32_t h, uint32_t flags, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;PixelFormat&amp;amp; format) { &amp;nbsp;&amp;nbsp; &amp;nbsp;// initialize the surfaces &amp;nbsp;&amp;nbsp; &amp;nbsp;switch (format) { // TODO: take h/w into account &amp;nbsp;&amp;nbsp; &amp;nbsp;case PIXEL_FORMAT_TRANSPARENT: &amp;nbsp;&amp;nbsp; &amp;nbsp;case PIXEL_FORMAT_TRANSLUCENT: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;format = PIXEL_FORMAT_RGBA_8888; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp;case PIXEL_FORMAT_OPAQUE: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;format = PIXEL_FORMAT_RGB_565; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;Layer&amp;gt; layer = new Layer(this, display, client, id); &amp;nbsp;&amp;nbsp; &amp;nbsp;status_t err = layer-&amp;gt;setBuffers(w, h, format, flags); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (LIKELY(err == NO_ERROR)) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer-&amp;gt;initStates(w, h, flags); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;addLayer_l(layer); &amp;nbsp;&amp;nbsp; &amp;nbsp;} else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE(&amp;quot;createNormalSurfaceLocked() failed (%s)&amp;quot;, strerror(-err)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;layer.clear(); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return layer; } 여기서 레이어를 생성한다. 그럼 먼저 Layer.h 파일을 확인하자. class Layer : public LayerBaseClient { private: &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;Surface&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mSurface; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mSecure; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNoEGLImageForSwBuffers; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mFrontBufferIndex; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNeedsBlending; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNeedsDithering; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mPostedDirtyRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;FreezeLock&amp;gt; &amp;nbsp;mFreezeLock; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;PixelFormat &amp;nbsp; &amp;nbsp; mFormat; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// protected by mLock &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;GraphicBuffer&amp;gt; mBuffers[NUM_BUFFERS]; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Texture &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTextures[NUM_BUFFERS]; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;GraphicBuffer&amp;gt; mHybridBuffer; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mWidth; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mHeight; &amp;nbsp;&amp;nbsp; mutable Mutex mLock; } 그럼 Layer 가 초기화 되는부분을 보자. Layer.cpp 파일을 열어보면 아래와 같은 부분이 있다. &amp;nbsp;Layer::Layer(SurfaceFlinger* flinger, DisplayID display, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const sp&amp;lt;Client&amp;gt;&amp;amp; c, int32_t i) &amp;nbsp;&amp;nbsp; &amp;nbsp;: &amp;nbsp; LayerBaseClient(flinger, display, c, i), &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mSecure(false), &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNoEGLImageForSwBuffers(false), &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNeedsBlending(true), &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mNeedsDithering(false) { &amp;nbsp;&amp;nbsp; &amp;nbsp;// no OpenGL operation is possible here, since we might not be &amp;nbsp;&amp;nbsp; &amp;nbsp;// in the OpenGL thread. &amp;nbsp;&amp;nbsp; &amp;nbsp;mFrontBufferIndex = lcblk-&amp;gt;getFrontBuffer(); } 과연 lcbk 가 무엇일까? Layer.h 와 Layer.cpp 에 없다. 그렇다면 상속받은 상위 클래스에 있다는 얘기니까 상위 클래스를 확인해 보자. 먼저 LayerBase.h 파일을 열어보자. class LayerBase : public RefBase { public: &amp;nbsp;&amp;nbsp; &amp;nbsp;static const uint32_t typeInfo; &amp;nbsp;&amp;nbsp; &amp;nbsp;static const char* const typeID; &amp;nbsp;&amp;nbsp; &amp;nbsp;DisplayID &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; dpy; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;contentDirty; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp;visibleRegionScreen; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp;transparentRegionScreen; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp;coveredRegionScreen; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;struct State { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;w; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;h; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;requested_w; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;requested_h; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;z; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint8_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; alpha; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint8_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; flags; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint8_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; reserved[2]; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sequence; &amp;nbsp; // changes when visible regions can change &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tint; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Transform &amp;nbsp; &amp;nbsp; &amp;nbsp; transform; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;transparentRegion; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}; protected: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sp&amp;lt;SurfaceFlinger&amp;gt; mFlinger; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mFlags; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// cached during validateVisibility() &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mTransformed; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mUseLinearFiltering; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mOrientation; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GLfixed &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mVertices[4][2]; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Rect &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mTransformedBounds; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLeft; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTop; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// these are protected by an external lock &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;State &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mCurrentState; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;State &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mDrawingState; &amp;nbsp;&amp;nbsp; &amp;nbsp;volatile &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mTransactionFlags; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// don&amp;#039;t change, don&amp;#039;t need a lock &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mPremultipliedAlpha; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// atomic &amp;nbsp;&amp;nbsp; &amp;nbsp;volatile &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mInvalidate; } class LayerBaseClient : public LayerBase { public: &amp;nbsp;&amp;nbsp; &amp;nbsp;SharedBufferServer* &amp;nbsp; &amp;nbsp; lcblk; private: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mIndex; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable &amp;nbsp; &amp;nbsp; Mutex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLock; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable &amp;nbsp; &amp;nbsp; wp&amp;lt;Surface&amp;gt; &amp;nbsp; &amp;nbsp; mClientSurface; &amp;nbsp;&amp;nbsp; &amp;nbsp;const &amp;nbsp; &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mIdentity; &amp;nbsp;&amp;nbsp; &amp;nbsp;static &amp;nbsp; &amp;nbsp; &amp;nbsp;int32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; sIdentity; } LayerBaseClient 함수에서 SharedBufferServer* 형태로 선언되어 있는것을 알 수있다. 그럼 저 변수가 생성되는 부분을 찾아보자. LayerBase.cpp 파일을 열면 아래 부분이 있다. &amp;nbsp;LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const sp&amp;lt;Client&amp;gt;&amp;amp; client, int32_t i) &amp;nbsp;&amp;nbsp; &amp;nbsp;: LayerBase(flinger, display), lcblk(NULL), client(client), &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;mIndex(i), mIdentity(uint32_t(android_atomic_inc(&amp;amp;sIdentity))) { &amp;nbsp;&amp;nbsp; &amp;nbsp;lcblk = new SharedBufferServer( &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;client-&amp;gt;ctrlblk, i, NUM_BUFFERS, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mIdentity); } 여기서 lcblk 변수를 생성하는데 생성자로 client-&amp;gt;ctrlblk 가 들어간다. 이것은 Client 에서 생성된 메모리인데 아마 이 클래스는 고유의 메모리를 같는것이 아니라 Client 에서 생성된 메모리로 서버 역할을 하는듯 하다. 이부분은 메모리 부분이라 나중에 분석하도록 하겠다. 이제 lcblk 가 어디서 생성되는지 알았으니 다시 Layer 로 돌아가자. 레이어는 생성되고나서 setBuffers 함수가 호출되는것을 볼 수있다. Layer.cpp 파일을 열어서 확인해 보자. &amp;nbsp;status_t Layer::setBuffers( uint32_t w, uint32_t h, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;PixelFormat format, uint32_t flags) { &amp;nbsp;&amp;nbsp; &amp;nbsp;// this surfaces pixel format &amp;nbsp;&amp;nbsp; &amp;nbsp;PixelFormatInfo info; &amp;nbsp;&amp;nbsp; &amp;nbsp;status_t err = getPixelFormatInfo(format, &amp;amp;info); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (err) return err; &amp;nbsp;&amp;nbsp; &amp;nbsp;// the display&amp;#039;s pixel format &amp;nbsp;&amp;nbsp; &amp;nbsp;const DisplayHardware&amp;amp; hw(graphicPlane(0).displayHardware()); &amp;nbsp;&amp;nbsp; &amp;nbsp;PixelFormatInfo displayInfo; &amp;nbsp;&amp;nbsp; &amp;nbsp;getPixelFormatInfo(hw.getFormat(), &amp;amp;displayInfo); &amp;nbsp;&amp;nbsp; &amp;nbsp;const uint32_t hwFlags = hw.getFlags(); &amp;nbsp;&amp;nbsp; &amp;nbsp;mFormat = format; &amp;nbsp;&amp;nbsp; &amp;nbsp;mWidth = w; &amp;nbsp;&amp;nbsp; &amp;nbsp;mHeight = h; &amp;nbsp;&amp;nbsp; &amp;nbsp;mSecure = (flags &amp;amp; ISurfaceComposer::eSecure) ? true : false; &amp;nbsp;&amp;nbsp; &amp;nbsp;mNeedsBlending = (info.h_alpha - info.l_alpha) &amp;gt; 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;mNoEGLImageForSwBuffers = !(hwFlags &amp;amp; DisplayHardware::CACHED_BUFFERS); &amp;nbsp;&amp;nbsp; &amp;nbsp;// we use the red index &amp;nbsp;&amp;nbsp; &amp;nbsp;int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); &amp;nbsp;&amp;nbsp; &amp;nbsp;int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); &amp;nbsp;&amp;nbsp; &amp;nbsp;mNeedsDithering = layerRedsize &amp;gt; displayRedSize; &amp;nbsp;&amp;nbsp; &amp;nbsp;for (size_t i=0 ; i&amp;lt;NUM_BUFFERS ; i++) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mBuffers[i] = new GraphicBuffer(); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;mSurface = new SurfaceLayer(mFlinger, clientIndex(), this); &amp;nbsp;&amp;nbsp; &amp;nbsp;return NO_ERROR; } 일단 mBuffers 에다가 GraphicsBuffer 를 생성해서 채우는데 이게 무엇일까? include 를 보니까 &amp;quot;ui/GraphicsBuffer.h&amp;quot; 파일에서 가져오는거 같다. 일단은 현 디렉토리만 분석중이니 넘어가자. libs 디렉토리와 ui 디렉토리로 나누어 놓은 이유도 있을꺼 같은데 아직은 이유가 무엇인지 알수없다. 그럼 SurfaceLayer 소스를 보기위해 Layer.cpp 파일을 열어서 아래 부분을 찾아보자. Layer::SurfaceLayer::SurfaceLayer(const sp&amp;lt;SurfaceFlinger&amp;gt;&amp;amp; flinger, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;SurfaceID id, const sp&amp;lt;Layer&amp;gt;&amp;amp; owner) &amp;nbsp;&amp;nbsp; &amp;nbsp;: Surface(flinger, id, owner-&amp;gt;getIdentity(), owner) { } Layer::SurfaceLayer::~SurfaceLayer() { } 하는일이 아무것도 없다. 결국 그냥 Surface 를 상속받은 껍데기일 뿐이다. Surface 역시 ui 에 있는데 이제 ui 쪽을 봐야할꺼 같다. 그럼 일단 Surface 를 찾아보도록 하자. ui 쪽은 libs 쪽처럼 헤더가 붙어있는것이 아니고 나누어져 있다. 헤더는 frameworks/base/include/ui 에 있고 소스는 frameworks/base/libs/ui 에 있다. 나누어져 있다는것은 header 를 여기저기서 가져다 쓸수 있게 만들어둔다는 소리다. 그렇다면 ui 는 윗단에서 가져다 쓸 수 있게 만든것이고 libs 는 그 자체로만 쓸수 있게 만들어 놓은거 같다. 그럼 먼저 Surface.h 파일을 열어보자. class SurfaceControl : public RefBase { private: &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;SurfaceComposerClient&amp;gt; &amp;nbsp; mClient; &amp;nbsp;&amp;nbsp; &amp;nbsp;sp&amp;lt;ISurface&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mSurface; &amp;nbsp;&amp;nbsp; &amp;nbsp;SurfaceID &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mToken; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mIdentity; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mWidth; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mHeight; &amp;nbsp;&amp;nbsp; &amp;nbsp;PixelFormat &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mFormat; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;mFlags; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable Mutex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLock; &amp;nbsp;&amp;nbsp; &amp;nbsp;mutable sp&amp;lt;Surface&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mSurfaceData; } class Surface : public EGLNativeBase&amp;lt;android_native_window_t, Surface, RefBase&amp;gt; { private: &amp;nbsp; &amp;nbsp; // constants &amp;nbsp; &amp;nbsp; sp&amp;lt;SurfaceComposerClient&amp;gt; &amp;nbsp; mClient; &amp;nbsp; &amp;nbsp; sp&amp;lt;ISurface&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mSurface; &amp;nbsp; &amp;nbsp; SurfaceID &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mToken; &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mIdentity; &amp;nbsp; &amp;nbsp; PixelFormat &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mFormat; &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mFlags; &amp;nbsp; &amp;nbsp; GraphicBufferMapper&amp;amp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mBufferMapper; &amp;nbsp; &amp;nbsp; SharedBufferClient* &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mSharedBufferClient; &amp;nbsp; &amp;nbsp; // protected by mSurfaceLock &amp;nbsp; &amp;nbsp; Rect &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mSwapRectangle; &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mUsage; &amp;nbsp; &amp;nbsp; // protected by mSurfaceLock. These are also used from lock/unlock &amp;nbsp; &amp;nbsp; // but in that case, they must be called form the same thread. &amp;nbsp; &amp;nbsp; sp&amp;lt;GraphicBuffer&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mBuffers[2]; &amp;nbsp; &amp;nbsp; mutable Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mDirtyRegion; &amp;nbsp; &amp;nbsp; // must be used from the lock/unlock thread &amp;nbsp; &amp;nbsp; sp&amp;lt;GraphicBuffer&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mLockedBuffer; &amp;nbsp; &amp;nbsp; sp&amp;lt;GraphicBuffer&amp;gt; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mPostedBuffer; &amp;nbsp; &amp;nbsp; mutable Region &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mOldDirtyRegion; &amp;nbsp; &amp;nbsp; bool &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mNeedFullUpdate; &amp;nbsp; &amp;nbsp; // query() must be called from dequeueBuffer() thread &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mWidth; &amp;nbsp; &amp;nbsp; uint32_t &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; mHeight; &amp;nbsp; &amp;nbsp; // Inherently thread-safe &amp;nbsp; &amp;nbsp; mutable Mutex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mSurfaceLock; &amp;nbsp; &amp;nbsp; mutable Mutex &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mApiLock; } &amp;nbsp; 그럼 Surface.cpp 파일도 열어보자. Surface::Surface(const sp&amp;lt;SurfaceControl&amp;gt;&amp;amp; surface) &amp;nbsp; &amp;nbsp; : mClient(surface-&amp;gt;mClient), mSurface(surface-&amp;gt;mSurface), &amp;nbsp; &amp;nbsp; &amp;nbsp; mToken(surface-&amp;gt;mToken), mIdentity(surface-&amp;gt;mIdentity), &amp;nbsp; &amp;nbsp; &amp;nbsp; mFormat(surface-&amp;gt;mFormat), mFlags(surface-&amp;gt;mFlags), &amp;nbsp; &amp;nbsp; &amp;nbsp; mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL), &amp;nbsp; &amp;nbsp; &amp;nbsp; mWidth(surface-&amp;gt;mWidth), mHeight(surface-&amp;gt;mHeight) { &amp;nbsp; &amp;nbsp; mSharedBufferClient = new SharedBufferClient( &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mClient-&amp;gt;mControl, mToken, 2, mIdentity); &amp;nbsp; &amp;nbsp; init(); } &amp;nbsp;void Surface::init() { &amp;nbsp; &amp;nbsp; android_native_window_t::setSwapInterval&amp;nbsp; = setSwapInterval; &amp;nbsp; &amp;nbsp; android_native_window_t::dequeueBuffer &amp;nbsp;&amp;nbsp; = dequeueBuffer; &amp;nbsp; &amp;nbsp; android_native_window_t::lockBuffer &amp;nbsp; &amp;nbsp; &amp;nbsp; = lockBuffer; &amp;nbsp; &amp;nbsp; android_native_window_t::queueBuffer &amp;nbsp; &amp;nbsp;&amp;nbsp; = queueBuffer; &amp;nbsp; &amp;nbsp; android_native_window_t::query &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; = query; &amp;nbsp; &amp;nbsp; android_native_window_t::perform &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; = perform; &amp;nbsp; &amp;nbsp; mSwapRectangle.makeInvalid(); &amp;nbsp; &amp;nbsp; DisplayInfo dinfo; &amp;nbsp; &amp;nbsp; SurfaceComposerClient::getDisplayInfo(0, &amp;amp;dinfo); &amp;nbsp; &amp;nbsp; const_cast&amp;lt;float&amp;amp;&amp;gt;(android_native_window_t::xdpi) = dinfo.xdpi; &amp;nbsp; &amp;nbsp; const_cast&amp;lt;float&amp;amp;&amp;gt;(android_native_window_t::ydpi) = dinfo.ydpi; &amp;nbsp; &amp;nbsp; // FIXME: set real values here &amp;nbsp; &amp;nbsp; const_cast&amp;lt;int&amp;amp;&amp;gt;(android_native_window_t::minSwapInterval) = 1; &amp;nbsp; &amp;nbsp; const_cast&amp;lt;int&amp;amp;&amp;gt;(android_native_window_t::maxSwapInterval) = 1; &amp;nbsp; &amp;nbsp; const_cast&amp;lt;uint32_t&amp;amp;&amp;gt;(android_native_window_t::flags) = 0; &amp;nbsp; &amp;nbsp; // be default we request a hardware surface &amp;nbsp; &amp;nbsp; mUsage = GRALLOC_USAGE_HW_RENDER; &amp;nbsp; &amp;nbsp; mNeedFullUpdate = false; } Surface 클래스는 android_native_window_t 구조체를 상속받고 있기 때문에 init 함수에서 해당 구조체를 채워주는 일을 한다. 구조체로 상속할수 있다는것을 첨알았다. 자 이제 더이상 따라갈 수가 없다. 이부분에 대해서는 조금 더 생각해 봐야겠다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/316&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">hello 디바스 드라이버</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/315"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/315" thr:count="0"/>
  <category term="Linux device driver"/>
  <category term="Device Driver"/>
  <category term="hello"/>
  <category term="Linux"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/315</id>
  <updated>2010-03-19T00:12:05+09:00</updated>
  <published>2010-03-18T23:50:12+09:00</published>
  <summary type="html"> hello 디바이스 만들기 프로그래밍 첨하면 아무나 다하는 hello.c를 만들어 보겠다. #include &amp;lt;linux/init.h&amp;gt; #include &amp;lt;linux/module.h&amp;gt; MODULE_LICENSE(&amp;quot;Dual BSD/GPL&amp;quot;); static int __init hello_init(void) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk(KERN_ALERT &amp;quot;Hello, world\n&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0; } static void __exit hello_exit(void) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk(KERN_ALERT &amp;quot;Goodbye, world\n&amp;quot;); } module_init(hello_init); module_exit(hello_exit); 뭐하는 설명 안해도 다 알만한 프로그램이다. 여기서 기존의 프로그램과 다른점은 printf 대신 printk 를 썻다는 것이다. 저 코드들은 커널 에서 실행되기때문에 유저스페이스의 함수를 사용할 수 없다. 그래서 stdio 같은것들을 인클루드 하면 안된다. 모두 커널상의 함수를 사용해야한다. printk 역시 커널 함수로 printf와 거의 유사한 기능을 한다. 중간에 __init 과 __exit 가 좀 수상쩍어 보인다. 이것은 필수는 아니지만 써주는게 좋다. 그 이유는 커널에게 시작할때 한번 끝날때 한번 실행하는 함수라고 알려서 실행되고 바로 메모리에서 삭제하도록 할 수있다. MODULE_LICENSE 는 라이센스를 지정하는 부분인데 이부분이 재미있다. 여기에 들어갈 수 있는 스트링은 아래와 같다. &amp;quot;GPL&amp;quot; &amp;nbsp;, &amp;nbsp;&amp;quot;GPL v2&amp;quot; &amp;nbsp;, &amp;nbsp;&amp;quot;GPL and additional rights&amp;quot; &amp;nbsp;, &amp;nbsp;&amp;quot;Dual BSD/GPL&amp;quot; &amp;nbsp;, &amp;nbsp;&amp;quot;Dual MPL/GPL&amp;quot; &amp;quot;Proprietary&amp;quot; &amp;nbsp;사실 MODULE_LICENSE 는 옵션이다. 그러나 지정하지 않은 모듈을 적재시 &amp;quot;오염 상태&amp;quot; 가 된다. makefile 만들기 KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) obj-m := hello.o default: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;$(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;rm *.ko *.o Module.* modules.* *.mod.c KERNELDIR 에는 커널헤더 경로가 들어가기 때문에 위와 같은 명령을 사용하면 헤더의 경로를 가져올 수 있다. 자 이제 make 를 실행해 보자. root@cranix-desktop:~/work/drivers# make make -C /lib/modules/2.6.31-20-generic-pae/build M=/root/work/drivers modules make[1]: Entering directory `/usr/src/linux-headers-2.6.31-20-generic-pae&amp;#039; &amp;nbsp; CC [M] &amp;nbsp;/root/work/drivers/hello.o &amp;nbsp; Building modules, stage 2. &amp;nbsp; MODPOST 1 modules &amp;nbsp; CC &amp;nbsp; &amp;nbsp; &amp;nbsp;/root/work/drivers/hello.mod.o &amp;nbsp; LD [M] &amp;nbsp;/root/work/drivers/hello.ko make[1]: Leaving directory `/usr/src/linux-headers-2.6.31-20-generic-pae&amp;#039; 위와 같이 나오면 제대로 컴파일 된 것이고 hello.ko 파일이 생겼을 것이다. ko 란 커널 오브젝트의 약자로서 2.6 넘어오면서 커널오브젝트와 다른 오브젝트를 구분하기위해 생긴것이다. hello 디바이스 적재및 삭제 root@cranix-desktop:~/work/drivers# insmod hello.ko root@cranix-desktop:~/work/drivers# lsmod |grep hello hello &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 1052 &amp;nbsp;0 root@cranix-desktop:~/work/drivers# rmmod hello root@cranix-desktop:~/work/drivers# lsmod |grep hello root@cranix-desktop:~/work/drivers# &amp;nbsp; 위와같이 디바이스 드라이버는 insmod 와 rmmod 로 적재와 삭제를 하고 lsmod 로 리스트를 볼 수 있다. 커널로그 보기 분명 적재는 했는데 printk 로 출력한 메시지는 어떻게 볼 수 있을까? root@cranix-desktop:~/work/drivers# dmesg ... ... [ 2747.649737] Hello, world [ 2759.753311] Goodbye, world 메시지가 쭈욱 나오는데 제일 아래보면 원하던 메시지를 볼 수 있을 것이다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/315&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">android frame buffer HAL 분석</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/312"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/312" thr:count="0"/>
  <category term="Android"/>
  <category term="Android"/>
  <category term="frame buffer"/>
  <category term="goldfish"/>
  <category term="Hal"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/312</id>
  <updated>2010-03-18T19:57:30+09:00</updated>
  <published>2010-03-18T19:57:30+09:00</published>
  <summary type="html"> 들어가며 안드로이드에서 frame buffer 를 테스트 하기위해서는 실제 타겟보드가 필요하다. 그러나 타겟보드는 각각 해당 디바이스 드라이버를 작성하는 방법이 다를 뿐더러 구하기도 어렵다. 그래서 여기서는 가장 접근하기 쉬운 goldfish 에뮬레이터의 frame buffer 를 분석해 보도록 하겠다. &amp;nbsp; frame buffer ? 리눅스에서 한 화면을 표현하는 메모리 라고 할 수 있다. &amp;nbsp; 안드로이드에서 frame buffer 안드로이드에서 frame buffer 디바이스는 &amp;quot;/dev/graphics/fb*&amp;quot; 과 같은 형태로 표시된다. 대부분 &amp;quot;fb0&amp;quot; 이 화면에 출력하는 디바이스가 된다. 만약 출력포트가 더 존재한다면 fb1, fb2, fbn ... 이런식으로 늘어나게 된다. 이러한 video 관련 디바이스 드라이버는 안드로이드 커널의 &amp;quot;drivers/video&amp;quot; 디렉토리에 위치한다. &amp;nbsp; goldfish frame buffer device driver 커널 디바이스 소스코드는 &amp;quot;drivers/video/goldfishfb.c&amp;quot; 파일이다. ... ... static struct platform_driver goldfish_fb_driver = { .probe = goldfish_fb_probe, .remove = goldfish_fb_remove, .driver = { .name = &amp;quot;goldfish_fb&amp;quot; } }; static int __init goldfish_fb_init(void) { return platform_driver_register(&amp;amp;goldfish_fb_driver); } &amp;nbsp;void __exit goldfish_fb_exit(void) { platform_driver_unregister(&amp;amp;goldfish_fb_driver); } module_init(goldfish_fb_init); module_exit(goldfish_fb_exit); 위와같이 디바이스 module_init 과 module_exit 함수에 의해 커널에 등록되고 삭제된다. 이를 거치게 되면 &amp;quot;/dev/graphics/fb0&amp;quot; 이 생기게 되고 유저스페이스의 어플리케이션에서 접근 가능하게 된다. 안드로이드 에서의 frame buffer device driver 사용 안드로이드에서 frame buffer device driver 를 사용하는 부분을 찾으려면 &amp;quot;/dev/graphics&amp;quot; 을 가지고 있는 파일을 검색하면 된다. # grep &amp;#039;/dev/graphics&amp;#039; * -R ... hardware/libhardware/modules/gralloc/framebuffer.cpp: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;/dev/graphics/fb%u&amp;quot; system/core/init/devices.c: &amp;nbsp; &amp;nbsp;{ &amp;quot;/dev/graphics/&amp;quot;, &amp;nbsp; &amp;nbsp; 0660, &amp;nbsp; AID_ROOT, &amp;nbsp; &amp;nbsp; &amp;nbsp; AID_GRAPHICS, &amp;nbsp; 1 }, system/core/init/devices.c: &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;base = &amp;quot;/dev/graphics/&amp;quot;; system/core/init/logo.c: &amp;nbsp; &amp;nbsp;fb-&amp;gt;fd = open(&amp;quot;/dev/graphics/fb0&amp;quot;, O_RDWR); system/core/toolbox/rotatefb.c: &amp;nbsp; &amp;nbsp;char *fbdev = &amp;quot;/dev/graphics/fb0&amp;quot;; system/core/adb/framebuffer_service.c: &amp;nbsp; &amp;nbsp;fb = open(&amp;quot;/dev/graphics/fb0&amp;quot;, O_RDONLY); ... 가장 덜 의심가는 &amp;quot;adb/framebuffer_service.c&amp;quot; 파일부터 찾아보자. 이름으로 검색해 보았더니 걸리는 부분은 &amp;quot;adb&amp;quot; 밖에 없다. adb 는 안드로이드 디버그 브릿지의 약자로서 디버그 관련된 것 일테니 일단 용의선상에서 제외한다. rotatefb.c 역시 검색해 봤지만 별다른게 없다. 그냥 혼자 실행되는 파일인것 같다. 그래서 용의선상에서 제외시킨다. init 에 있는 devices.c 파일은 디바이스 노드를 init 시 생성해 주고 uevent 로 오는 핫플러그 디바이스들의 생성도 담당한다. 즉 이 파일은 생성만 할 뿐 관여는 하지 않는다. 그럼 logo.c 파일은 이름만 딱 보아도 로고를 출력해주는 파일일 것이다. 거기에다가 init 에 들어있으니 부팅때 나오는 로고를 출력하는 파일로 예상된다. 역시나 logo.c 파일은 부팅시 이미지 파일을 frame buffer 로 바로 뿌려주는 역할을 한다. 마지막으로 남은것은 &amp;quot;hardware/libhardware/modules/gralloc/framebuffer.cpp&amp;quot; 이다. framebuffer.cpp 에서는 실제로 디바이스를 오픈하는 mapFrameBufferLocked() 함수를 제공한다. &amp;nbsp;int mapFrameBufferLocked(struct private_module_t* module) { &amp;nbsp;&amp;nbsp; &amp;nbsp;// already initialized... &amp;nbsp;&amp;nbsp; &amp;nbsp;if (module-&amp;gt;framebuffer) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;char const * const device_template[] = { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;/dev/graphics/fb%u&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;/dev/fb%u&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0 }; &amp;nbsp;&amp;nbsp; &amp;nbsp;int fd = -1; &amp;nbsp;&amp;nbsp; &amp;nbsp;int i=0; &amp;nbsp;&amp;nbsp; &amp;nbsp;char name[64]; &amp;nbsp;&amp;nbsp; &amp;nbsp;while ((fd==-1) &amp;amp;&amp;amp; device_template[i]) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;snprintf(name, 64, device_template[i], 0); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;fd = open(name, O_RDWR, 0); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;i++; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;if (fd &amp;lt; 0) &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return -errno; &amp;nbsp;&amp;nbsp; &amp;nbsp;... &amp;nbsp;&amp;nbsp; &amp;nbsp;... } mapFrameBufferLocked() 함수는 gralloc.cpp 파일에서 사용하게 된다. 또 gralloc 는 어딘가에서 사용 될꺼다. 이부분에서 더 따라 올라가고 싶었지만 gralloc 의 함수를 제대로 끌어다 쓰는곳을 발견할 수 없었다. 그래서 조금 방식을 바꾸어서 약간 위에서 내려왔다. 일단 framebuffer 는 안드로이드의 surface 쪽에서 쓰인다는 것을 알고 있으니까 surfaceflinger 쪽을 보기로 했다. frameworks/base/libs/surfaceflinger/SurfaceFlinger.cpp 파일을 보자. &amp;nbsp;status_t SurfaceFlinger::readyToRun() { &amp;nbsp;&amp;nbsp; &amp;nbsp;LOGI( &amp;nbsp; &amp;quot;SurfaceFlinger&amp;#039;s main thread ready to run. &amp;quot; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;Initializing graphics H/W...&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp;// we only support one display currently &amp;nbsp;&amp;nbsp; &amp;nbsp;int dpy = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;{ &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// initialize the main display &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GraphicPlane&amp;amp; plane(graphicPlane(dpy)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;DisplayHardware* const hw = new DisplayHardware(this, dpy); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;plane.setDisplayHardware(hw); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; ... 사실 이 파일은 바인더와 관련있기 때문에 상당히 복잡하고 길다. 그러나 readyToRun() 함수를 보게되면 무언가 우리가 원하는게 있는 것을 볼 수 있다. 즉 어디선가 이 함수가 호출되면 &amp;quot;graphincs 하드웨어가 초기화 됩니다&amp;quot; 라는 로그를 뿌리면서 DisplayHardware 를 생성한다. 결국 하드웨어 관련부분은 DIsplayHardware 클래스에서 처리하는걸로 판단된다. frameworks/base/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp 파일을 열어보자 void DisplayHardware::init(uint32_t dpy) { &amp;nbsp;&amp;nbsp; &amp;nbsp;mNativeWindow = new FramebufferNativeWindow(); &amp;nbsp;&amp;nbsp; &amp;nbsp;framebuffer_device_t const * fbDev = mNativeWindow.getDevice(); &amp;nbsp;&amp;nbsp; &amp;nbsp;... 음.. 여기서 또 FramebufferNativeWindow 를 생성한다. 클래스 명에서 수상한 냄새가 물씬 풍긴다. frameworks/base/libs/ui/FramebufferNativeWindow.cpp 파일을 연다. &amp;nbsp;FramebufferNativeWindow::FramebufferNativeWindow() &amp;nbsp;&amp;nbsp; &amp;nbsp;: BASE(), fbDev(0), grDev(0), mUpdateOnDemand(false) { &amp;nbsp;&amp;nbsp; &amp;nbsp;hw_module_t const* module; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &amp;amp;module) == 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int stride; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int err; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;err = framebuffer_open(module, &amp;amp;fbDev); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE_IF(err, &amp;quot;couldn&amp;#039;t open framebuffer HAL (%s)&amp;quot;, strerror(-err)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;err = gralloc_open(module, &amp;amp;grDev); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE_IF(err, &amp;quot;couldn&amp;#039;t open gralloc HAL (%s)&amp;quot;, strerror(-err)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// bail out if we can&amp;#039;t initialize the modules &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!fbDev || !grDev) &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return; &amp;nbsp;&amp;nbsp; &amp;nbsp;... &amp;nbsp;&amp;nbsp; &amp;nbsp;... framebuffer_open 과 gralloc_open 을 찾아보면 &amp;quot;hardware/libhardware/include/hardware/gralloc.h&amp;quot; 파일에 있는것을 알 수있다. 아 결국 다시 gralloc.cpp 와 가까워 진 것을 알 수 있다. 그러나 이것만 가지고 구체적으로 어떻게 접근하는지는 확인 할 수 없다. 더 나가보자. 먼저 gralloc.h 파일을 열어보자. typedef struct alloc_device_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hw_device_t common; &amp;nbsp;&amp;nbsp; &amp;nbsp;... } typedef struct framebuffer_device_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hw_device_t common; &amp;nbsp;&amp;nbsp; &amp;nbsp;... } &amp;nbsp;static inline int gralloc_open(const struct hw_module_t* module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;struct alloc_device_t** device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return module-&amp;gt;methods-&amp;gt;open(module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GRALLOC_HARDWARE_GPU0, (struct hw_device_t**)device); } static inline int gralloc_close(struct alloc_device_t* device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return device-&amp;gt;common.close(&amp;amp;device-&amp;gt;common); } static inline int framebuffer_open(const struct hw_module_t* module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;struct framebuffer_device_t** device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return module-&amp;gt;methods-&amp;gt;open(module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;GRALLOC_HARDWARE_FB0, (struct hw_device_t**)device); } static inline int framebuffer_close(struct framebuffer_device_t* device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;return device-&amp;gt;common.close(&amp;amp;device-&amp;gt;common); } 생각에 module-&amp;gt;methods-&amp;gt;open 함수에서 생성이 이루어 질것같지만 검색해서 나오지는 않는다. 결국 해당 구조체를 생성하는 부분을 찾아보자. 이전 FramebufferNativeWindow.cpp 에서 hw_get_module() 에 의해서 hw_module_t 가 초기화 되는것을 알 수 있는데 이부분을 찾으면 뭔가 나올꺼 같다. 검색해보면 hw_device_t, hw_module_t 구조체는 &amp;quot;hardware/libhardware/include/hardware/hardware.h&amp;quot; 에서 정의하고 있는것을 알 수 있다. 그럼 이 구조체를 초기화 하는 함수인 hw_get_module() 소스를 보기위해 &amp;quot;hardware/libhardware/hardware.c&amp;quot; 파일을 열어보자. &amp;nbsp;int hw_get_module(const char *id, const struct hw_module_t **module) { &amp;nbsp;&amp;nbsp; &amp;nbsp;int status; &amp;nbsp;&amp;nbsp; &amp;nbsp;int i; &amp;nbsp;&amp;nbsp; &amp;nbsp;const struct hw_module_t *hmi = NULL; &amp;nbsp;&amp;nbsp; &amp;nbsp;char prop[PATH_MAX]; &amp;nbsp;&amp;nbsp; &amp;nbsp;char path[PATH_MAX]; &amp;nbsp;&amp;nbsp; &amp;nbsp;/* Loop through the configuration variants looking for a module */ &amp;nbsp;&amp;nbsp; &amp;nbsp;for (i=0 ; i&amp;lt;HAL_VARIANT_KEYS_COUNT+1 ; i++) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (i &amp;lt; HAL_VARIANT_KEYS_COUNT) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (property_get(variant_keys[i], prop, NULL) == 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;continue; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;snprintf(path, sizeof(path), &amp;quot;%s/%s.%s.so&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;HAL_LIBRARY_PATH, id, prop); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;snprintf(path, sizeof(path), &amp;quot;%s/%s.default.so&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;HAL_LIBRARY_PATH, id); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (access(path, R_OK)) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;continue; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* we found a library matching this id/variant */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;break; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;status = -ENOENT; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (i &amp;lt; HAL_VARIANT_KEYS_COUNT+1) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* load the module, if this fails, we&amp;#039;re doomed, and we should not try &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; * to load a different variant. */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = load(id, path, module); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return status; } static int load(const char *id, &amp;nbsp; const char *path, &amp;nbsp; const struct hw_module_t **pHmi) { &amp;nbsp;&amp;nbsp; &amp;nbsp;int status; &amp;nbsp;&amp;nbsp; &amp;nbsp;void *handle; &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hw_module_t *hmi; &amp;nbsp;&amp;nbsp; &amp;nbsp;/* &amp;nbsp;&amp;nbsp; &amp;nbsp; * load the symbols resolving undefined symbols before &amp;nbsp;&amp;nbsp; &amp;nbsp; * dlopen returns. Since RTLD_GLOBAL is not or&amp;#039;d in with &amp;nbsp;&amp;nbsp; &amp;nbsp; * RTLD_NOW the external symbols will not be global &amp;nbsp;&amp;nbsp; &amp;nbsp; */ &amp;nbsp;&amp;nbsp; &amp;nbsp;handle = dlopen(path, RTLD_NOW); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (handle == NULL) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;char const *err_str = dlerror(); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE(&amp;quot;load: module=%s\n%s&amp;quot;, path, err_str?err_str:&amp;quot;unknown&amp;quot;); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;goto done; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;/* Get the address of the struct hal_module_info. */ &amp;nbsp;&amp;nbsp; &amp;nbsp;const char *sym = HAL_MODULE_INFO_SYM_AS_STR; &amp;nbsp;&amp;nbsp; &amp;nbsp;hmi = (struct hw_module_t *)dlsym(handle, sym); &amp;nbsp;&amp;nbsp; &amp;nbsp;if (hmi == NULL) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE(&amp;quot;load: couldn&amp;#039;t find symbol %s&amp;quot;, sym); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;goto done; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;/* Check that the id matches */ &amp;nbsp;&amp;nbsp; &amp;nbsp;if (strcmp(id, hmi-&amp;gt;id) != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGE(&amp;quot;load: id=%s != hmi-&amp;gt;id=%s&amp;quot;, id, hmi-&amp;gt;id); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;goto done; &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;hmi-&amp;gt;dso = handle; &amp;nbsp;&amp;nbsp; &amp;nbsp;/* success */ &amp;nbsp;&amp;nbsp; &amp;nbsp;status = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;done: &amp;nbsp;&amp;nbsp; &amp;nbsp;if (status != 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;hmi = NULL; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (handle != NULL) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dlclose(handle); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;handle = NULL; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;} else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;LOGV(&amp;quot;loaded HAL id=%s path=%s hmi=%p handle=%p&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id, path, *pHmi, handle); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;*pHmi = hmi; &amp;nbsp;&amp;nbsp; &amp;nbsp;return status; } 먼저 윗쪽에 sprintf 함수에 의해 path 문자열이 생성된다. 이것은 결국 &amp;quot;/system/lib/hw/gralloc.default.so&amp;quot; 로 생성된다. 이걸 인자로 load 로 넘겨버리는데 load 로 가보자. 여기에 dlopen,dlclose 그리고 dlsym 부분이 있다. 처음 보는 함수인데 아무리 봐도 시스템콜 이다. 구글링 해봤더니 아래에 잘 정리된 자료가 있다. &amp;nbsp;http://wiki.kldp.org/HOWTO/html/Program-Library-HOWTO/dl-libraries.html 이것들의 역할은 동적 라이브러리를 로딩해서 dlsym 으로 라이브러리의 심볼값을 찾아서 주는것이다. 여기서 심볼값을 찾아 준다는것은 함수나 전역변수의 주소를 돌려준다는 얘기다. 아.. 결국은 &amp;nbsp;HAL 쪽을 so 형태로 만들어서 올린다음에 필요할때만 동적으로 로딩해서 쓰겠다는 의미이다. 내생각에 이부분은 구글에서 HAL 쪽 표준 인터페이스를 정의해 놓은것으로 판단된다. 이부분은 나중에 정확하게 정리해야 할것 같다. 이제 dlsym 함수 호출하는 부분에서 정의한 심볼값을 추적해 보면 계속 따라갈 수 있을꺼 같다. 위 함수에서 dlsym 으로 가져오는 심벌은 HAL_MODULE_INFO_SYM_AS_STR 이다 이것은 &amp;quot;hardware/libhardware/include/hardware/hardware.h&amp;quot; 파일에 정의되어 있고 값은 &amp;quot;HMI&amp;quot; 이다. dlsym 으로 가져온 내용을 hw_module_t 형으로 형변환 했다는것을 미루어 볼때 gralloc.default.so 파일에 HMI 라는 이름으로 hw_module_t 형의 전역변수가 선언되어 있다고 판단된다. 그럼 &amp;quot;/hardware/libhardware/modules/gralloc/gralloc.cpp&amp;quot; 파일을 열어서 확인해 보자. &amp;nbsp;static struct hw_module_methods_t gralloc_module_methods = { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;open: gralloc_device_open }; struct private_module_t HAL_MODULE_INFO_SYM = { &amp;nbsp;&amp;nbsp; &amp;nbsp;base: { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;common: { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tag: HARDWARE_MODULE_TAG, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;version_major: 1, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;version_minor: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;id: GRALLOC_HARDWARE_MODULE_ID, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;name: &amp;quot;Graphics Memory Allocator Module&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;author: &amp;quot;The Android Open Source Project&amp;quot;, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;methods: &amp;amp;gralloc_module_methods &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;registerBuffer: gralloc_register_buffer, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;unregisterBuffer: gralloc_unregister_buffer, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;lock: gralloc_lock, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;unlock: gralloc_unlock, &amp;nbsp;&amp;nbsp; &amp;nbsp;}, &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;framebuffer: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp;flags: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp;numBuffers: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp;bufferMask: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp;lock: PTHREAD_MUTEX_INITIALIZER, &amp;nbsp;&amp;nbsp; &amp;nbsp;currentBuffer: 0, &amp;nbsp;&amp;nbsp; &amp;nbsp;pmem_master: -1, &amp;nbsp;&amp;nbsp; &amp;nbsp;pmem_master_base: 0 }; HAL_MODULE_INFO_SYM 이부분은 쌍따움표를 뺀 HMI 이다. 결국 같은 이름의 전역변수가 있다. 그런데 리턴형이 private_module_t 형이다. 아마도 private_module_t 구조체는 가장 첫 필드에 hw_module_t 형을 가지고 있는듯 하다. &amp;quot;/hardware/libhardware/modules/gralloc/gralloc_priv.h&amp;quot; 파일에 해당 구조체가 선언되어 있는데 아래와 같다. &amp;nbsp;struct private_module_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;gralloc_module_t base; &amp;nbsp;&amp;nbsp; &amp;nbsp;private_handle_t* framebuffer; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t flags; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t numBuffers; &amp;nbsp;&amp;nbsp; &amp;nbsp;uint32_t bufferMask; &amp;nbsp;&amp;nbsp; &amp;nbsp;pthread_mutex_t lock; &amp;nbsp;&amp;nbsp; &amp;nbsp;buffer_handle_t currentBuffer; &amp;nbsp;&amp;nbsp; &amp;nbsp;int pmem_master; &amp;nbsp;&amp;nbsp; &amp;nbsp;void* pmem_master_base; &amp;nbsp;&amp;nbsp; &amp;nbsp;struct fb_var_screeninfo info; &amp;nbsp;&amp;nbsp; &amp;nbsp;struct fb_fix_screeninfo finfo; &amp;nbsp;&amp;nbsp; &amp;nbsp;float xdpi; &amp;nbsp;&amp;nbsp; &amp;nbsp;float ydpi; &amp;nbsp;&amp;nbsp; &amp;nbsp;float fps; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;enum { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;// flag to indicate we&amp;#039;ll post this buffer &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;PRIV_USAGE_LOCKED_FOR_POST = 0x80000000 &amp;nbsp;&amp;nbsp; &amp;nbsp;}; &amp;nbsp; }; 가장 첫 필드가 기대했던 hw_module_t 형이 아니다. 이것은 gralloc_module_t 형의 첫 필드에 hw_module_t 형을 가지고 있을수 있다는 말이니 또 찾아가 보자. &amp;quot;hardware/libhardware/include/hardware/gralloc.h&amp;quot; 파일에 보면 아래와 같은 부분이 있다. typedef struct gralloc_module_t { &amp;nbsp;&amp;nbsp; &amp;nbsp;struct hw_module_t common; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;int (*registerBuffer)(struct gralloc_module_t const* module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;buffer_handle_t handle); &amp;nbsp;&amp;nbsp; &amp;nbsp;int (*unregisterBuffer)(struct gralloc_module_t const* module, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;buffer_handle_t handle); &amp;nbsp;&amp;nbsp; &amp;nbsp;... } galloc_module_t 이제야 찾았다. 이것은 마치 구조체로 상속을 구현한 것과 같은 효과를 가진다. 이제 gralloc.h 에 있던 module-&amp;gt;methods-&amp;gt;open() 함수를 호출하게되면 gralloc_device_open() 함수가 실행 된다는것을 알 수 있다. &amp;quot;hardware/libhardware/modules/gralloc/gralloc.cpp&amp;quot; 파일을 열어보자. &amp;nbsp;int gralloc_device_open(const hw_module_t* module, const char* name, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;hw_device_t** device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;int status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gralloc_context_t *dev; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev = (gralloc_context_t*)malloc(sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* initialize our state here */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memset(dev, 0, sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* initialize the procs */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.tag = HARDWARE_DEVICE_TAG; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.version = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.module = const_cast&amp;lt;hw_module_t*&amp;gt;(module); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.close = gralloc_close; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.alloc &amp;nbsp; = gralloc_alloc; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.free &amp;nbsp; &amp;nbsp;= gralloc_free; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;*device = &amp;amp;dev-&amp;gt;device.common; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp;} else { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = fb_device_open(module, name, device); &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return status; } fb_device_open() 함수를 호출한다. 결국 우리가 처음에 찾았던 framebuffer.cpp 파일로 돌아왔다. &amp;quot;hardware/libhardware/modules/gralloc/framebuffer.cpp&amp;quot; 파일을 열어보자 &amp;nbsp;int fb_device_open(hw_module_t const* module, const char* name, &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;hw_device_t** device) { &amp;nbsp;&amp;nbsp; &amp;nbsp;int status = -EINVAL; &amp;nbsp;&amp;nbsp; &amp;nbsp;if (!strcmp(name, GRALLOC_HARDWARE_FB0)) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;alloc_device_t* gralloc_device; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = gralloc_open(module, &amp;amp;gralloc_device); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (status &amp;lt; 0) &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return status; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* initialize our state here */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;fb_context_t *dev = (fb_context_t*)malloc(sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;memset(dev, 0, sizeof(*dev)); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* initialize the procs */ &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.tag = HARDWARE_DEVICE_TAG; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.version = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.module = const_cast&amp;lt;hw_module_t*&amp;gt;(module); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.common.close = fb_close; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.setSwapInterval = fb_setSwapInterval; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.post &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;= fb_post; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;dev-&amp;gt;device.setUpdateRect = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;private_module_t* m = (private_module_t*)module; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;status = mapFrameBuffer(m); &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (status &amp;gt;= 0) { &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int stride = m-&amp;gt;finfo.line_length / (m-&amp;gt;info.bits_per_pixel &amp;gt;&amp;gt; 3); &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; const_cast&amp;lt;uint32_t&amp;amp;&amp;gt;(dev-&amp;gt;device.flags) = 0; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;uint32_t&amp;amp;&amp;gt;(dev-&amp;gt;device.width) = m-&amp;gt;info.xres; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;uint32_t&amp;amp;&amp;gt;(dev-&amp;gt;device.height) = m-&amp;gt;info.yres; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;int&amp;amp;&amp;gt;(dev-&amp;gt;device.stride) = stride; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;int&amp;amp;&amp;gt;(dev-&amp;gt;device.format) = HAL_PIXEL_FORMAT_RGB_565; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;float&amp;amp;&amp;gt;(dev-&amp;gt;device.xdpi) = m-&amp;gt;xdpi; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;float&amp;amp;&amp;gt;(dev-&amp;gt;device.ydpi) = m-&amp;gt;ydpi; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;float&amp;amp;&amp;gt;(dev-&amp;gt;device.fps) = m-&amp;gt;fps; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;int&amp;amp;&amp;gt;(dev-&amp;gt;device.minSwapInterval) = 1; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const_cast&amp;lt;int&amp;amp;&amp;gt;(dev-&amp;gt;device.maxSwapInterval) = 1; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;*device = &amp;amp;dev-&amp;gt;device.common; &amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;} &amp;nbsp;&amp;nbsp; &amp;nbsp;return status; } static int mapFrameBuffer(struct private_module_t* module) { &amp;nbsp;&amp;nbsp; &amp;nbsp;pthread_mutex_lock(&amp;amp;module-&amp;gt;lock); &amp;nbsp;&amp;nbsp; &amp;nbsp;int err = mapFrameBufferLocked(module); &amp;nbsp;&amp;nbsp; &amp;nbsp;pthread_mutex_unlock(&amp;amp;module-&amp;gt;lock); &amp;nbsp;&amp;nbsp; &amp;nbsp;return err; } mapFrameBuffer 를 호출하고 그 함수 안에서 mapFrameBufferLocked 를 호출하여 마침내 framebuffer 디바이스를 생성하게 된다. 마치며 결국 디바이스 드라이버에서 surfaceflinger 까지 이런식으로 연결되어 있는 것이다. 다음번에는 HAL 인터페이스 부분을 분석해 봐야 겠다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/312&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">android 소스 다운로드 받기</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/314"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/314" thr:count="0"/>
  <category term="Android"/>
  <category term="Android"/>
  <category term="CURL"/>
  <category term="repo"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/314</id>
  <updated>2010-03-21T13:58:36+09:00</updated>
  <published>2010-03-18T10:35:05+09:00</published>
  <summary type="html"> curl 로 repo 스크립트 받기 안드로이드는 수많은 개발자가 참여하는 오픈소스 시스템이다. 이러한 시스템을 관리해주는 유틸은 git 를 사용하는데 그러다 보니 전체 소스가 한꺼번에 관리되지 않는다. 그래서 웹상에 소스를 한꺼번에 다운로드 받을수 있는 스크립트를 작성해 놓고 curl 로 다운받아가게 한 것이다. # apt-get install curl # curl http://android.git.kernel.org/repo &amp;gt;repo # chmod 755 repo 이제 repo 라는 스크립트가 생겼을 것이다. 편하게 하기위해서는 repo 가 있는 디렉토리를 PATH 로 잡아놓으면 된다. &amp;nbsp; &amp;nbsp; repo 를 사용해서 소스받기 repo 는 결국 git 를 사용하기 때문에 git 를 먼저 설치해야 한다. &amp;nbsp;# apt-get install git-core git-core 가 없다면 repo 를 실행했을때 &amp;quot;No such file or directory&amp;quot; 오류가 떨어질 것이다. &amp;nbsp; repo 를 이용해서 다운받으려면 init 과 sync 옵션을 사용하면 된다. # mkdir android_src # cd android_src # repo init -u git://android.git.kernel.org/platform/manifest.git # repo sync repo 를 실행하기 전에 먼저 소스가 저장될 디렉토리를 만들고 그안에서 init 과 sync 작업을 하도록 하자. repo init 옵션은 마지막에 -b (branch) 옵션으로 원하는 버전의 소스를 받을수 있다. 위 처럼 아무것도 안쓴다면 최신버전을 다운받게 된다. 그리고 init 을 실행 할 때 이름, 메일주소 등을 물어보는데 적당히 적어주면 된다. init 작업은 실제로 소스를 다운받지 않기 때문에 빠른 시간안에 끝난다. sync 에서 비로소 소스를 다운받기 때문에 상당히 시간이 걸린다. 인터넷이 빨라도 최소한 한시간은 잡아야 한다. &amp;nbsp; &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/314&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">우분투 셋팅</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/313"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/313" thr:count="0"/>
  <category term="font"/>
  <category term="ubuntu"/>
  <category term="vi"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/313</id>
  <updated>2010-03-22T08:45:21+09:00</updated>
  <published>2010-03-18T00:19:12+09:00</published>
  <summary type="html">들어가며 어제 새벽까지 설치하고 일하러 갔더니 완전 제정신이 아니었다. 오늘은 얼른하고 자야겠다. 일단 오늘 할것을 생각해 보자. &amp;nbsp; 폰트, vim, eclipse, ... 폰트셋팅 처음 우분투 설치할때는 폰트가 맘에든다고 생각했지만, 계속 쓰다보니 별로 맘에 안들었다. 일단 터미널 폰트부터 바꿔보자. 폰트는 한컴에서 만든 네이버사전체와 고정폭 Lucida Sans Typewriter 폰트를 받도록 하자. &amp;nbsp;함초롬체 : http://www.haansoft.com/hnc/event/ham/index.htm &amp;nbsp;네이버사전체 : http://cndic.naver.com/static/fontInstall &amp;nbsp;고정폭 Lucida Sans Typewriter 체 : # apt-get install sun-java6-fonts 다 받았으면 아래와 같이 폰트 디렉토리의 truetype 디렉토리에 회사별로 디렉토리를 만들고 ttf 파일을 이동시키자. 일단 아래와같이 폰트에 디렉토리를 만들고 폰트캐시를 업데이트 하자. &amp;nbsp;# mkdir /usr/share/fonts/truetype/han &amp;nbsp;# mv *.ttf /usr/share/fonts/truetype/han &amp;nbsp;# fc-cache -v 그럼 이제 폰트를 바꿔보자. 시스템전체의 글꼴을 설정하려면 아래 메뉴로 가서 변경하자. &amp;nbsp;시스템 -&amp;gt; 기본설정 -&amp;gt; 모양새 -&amp;gt; 폰트 VI 셋팅 일단 VI 는 먼저 vim 을 설치하도록 하자. 그다음 홈 디렉토리 아래에 .vimrc 파일을 만들고 아래와 같이 저장하자. set autoindent &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;자동 들여쓰기 set cindent &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;quot;C 프로그래밍 할때 자동으로 들여쓰기 set smartindent &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;quot;좀 더 똑똑한 들여쓰기 set nobackup &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;백업파일을 만들지 않는다. set number &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot;라인번호를 출력한다. &amp;quot;폰트 설정 set fenc=utf-8 set fencs=utf-8,cp949,cp932,euc-jp,shift-jis,big5,latin1,ucs-2le set nocp &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;quot; vi 와 호환성을 없애고 vim 만 쓸수있게 filetype on &amp;nbsp;&amp;quot;파일 종류를 자동으로 인식 set ru &amp;quot;커서의 위치를 항상 보이게함 set sc &amp;quot;완성중인 명령을 표시 set background=dark colorscheme elflord filet plugin indent on &amp;quot;파일종류 자동으로 인식 syntax on &amp;quot;알아서 하이라이팅 set title &amp;quot;제목표시 set novisualbell set hlsearch &amp;quot;검색어 하이라이트 set wmnu &amp;quot;탭 누르면 자동완성 가능한 목록 나옴 if has(&amp;quot;gui_running&amp;quot;) &amp;quot;gui 시작이면 시작시 크기 설정 &amp;nbsp;&amp;nbsp; set lines=50 &amp;nbsp;&amp;nbsp; set co=125 endif 참고로 &amp;nbsp;/etc/skel 디렉토리는 사용자가 생성될 때마다 복사하기 때문에 거기에 .vimrc 를 옮겨놓으면 나중에 편해진다. 오픈오피스 글자 깨지는거 수정 오픈오피스를 켰더니 글자가 깨져서 얼마전에 내가 적었던 포스트를 검색해서 수정했다. 이 블로그에서 &amp;quot;오픈오피스&amp;quot; 로 검색하면 나올것이다. 마치며 얼른 하려고 했는데 또 한시가 넘어버렸다.ㅜ 내일은 이클립스 설정이나 해야겠다. &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/313&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
 <entry>
  <title type="html">우분투로 mp6410cs 보드에 안드로이드 포팅하기</title>
  <link rel="alternate" type="text/html" href="http://cranix.net/311"/>
  <link rel="replies" type="application/atom+xml" href="http://cranix.net/atom/discuss/311" thr:count="0"/>
  <category term="Android"/>
  <category term="mp6410cs"/>
  <category term="uboot"/>
  <category term="&#xC6B0;&#xBD84;&#xD22C; &#xB124;&#xD2B8;&#xC6CC;&#xD06C;"/>
  <author>
   <name>크래닉스</name>
  </author>
  <id>http://cranix.net/311</id>
  <updated>2010-03-17T17:26:55+09:00</updated>
  <published>2010-03-17T11:08:51+09:00</published>
  <summary type="html"> 네트워크 설정 네트워크는 공유기를 사용하는 환경을 구성하는게 가장 편하다. 공유기에 호스트컴퓨터와 타겟보드를 연결해 놓고 네트워크 설정을 해 주면된다. &amp;nbsp; &amp;nbsp; 우분투 네트워크 설정 &amp;nbsp; ip 설정은 다음 디렉토리에 있다. 해당 파일에 들어있는 기존의 포멧대로 원하는 eth 를 생성해서 추가하면 된다. # vi /etc/network/interfaces # /etc/init.d/networking restart 그래도 인터넷이 안될텐데 그 이유는 네임서버를 설치하지 않아서 이다. 네임서버 설정은 아래 파일에서 한다. # vi /etc/resolv.conf 네임서버 설정은 리스타트 할 필요 없다. 내생각에 networking 프로세스가 필요할때 위 파일을 읽어가는거 같다. &amp;nbsp; &amp;nbsp; &amp;nbsp; u-boot 올리기 &amp;nbsp; &amp;nbsp; 일단 usb otg 드라이버 설치하고, 타겟 보드를 NOR 모드로 부팅한다. 그다음 DNW 를 실행하고 옵션에서 0x57e00000 으로 설정한후 usbport-&amp;gt;transmit 를 선택해서 u-boot.bin 을 전송한다. 여기서 0x57e00000 에 올린 이유는 삼성 otg mon 이 0 번지부터 들어있기 때문에 겹치지 않는 번지에 올려야 하기 때문이다. &amp;nbsp; 무언가 전송하는 화면이 휙 지나가면 u-boot 가 실행되는것을 볼 수있는데 여기서 재빨리 엔터를 쳐서 프롬프트로 들어간다. &amp;nbsp; 이제부터 u-boot 설정인데 가장먼저 네트워크 설정을 한다. # setenv ipaddr 192.168.0.2 # setenv serverip 192.168.0.4 # saveenv Saving Environment to NAND... Erasing Nand...Writing to Nand... done &amp;nbsp; 네트워크는 설정되어 있을테니 아이피 어드레스는 자기 자신으로 하고, 서버 아이피는 tftp 가 설치되어 있는 서버로 한다. &amp;nbsp; 다음으로 컴파일한 u-boot.bin 을 일단 tftp 로 가져온다. # tftp c0000000 u-boot.bin dm9000 i/o: 0x18000300, id: 0x90000a46 MAC: 00:40:5c:26:0a:5b operating at 100M full duplex mode TFTP from server 192.168.0.4; our IP address is 192.168.0.2 Filename &amp;#039;u-boot.bin&amp;#039;. Load address: 0xc0000000 Loading: ####################################### done Bytes transferred = 196608 (30000 hex) &amp;nbsp;가져온 데이터는 램에 저장되는데 이것을 nand 에 write 한다. # nand erase 0 30000 NAND erase: device 0 offset 0x0, size 0x30000 Erasing at 0x20000 -- 133% complete. OK # nand write c0000000 0 30000 NAND write: device 0 offset 0x0, size 0x30000 &amp;nbsp;196608 bytes written: OK &amp;nbsp; 먼저 우리가 쓰려는 nand 의 0 에서 30000 번지 까지를 erase 하고나서 nand write 명령으로 c0000000 에 올라와 있는 u-boot.bin 이미지를 0 30000 에다가 write 한다. &amp;nbsp; 모두 위 메시지 처럼 나왔다면 제대로 완료된것이다. 이제 타겟보드를 끄고 점퍼를 nand 모드로 셋팅한다음 켜보면 u-boot 가 뜨는것을 볼 수있다. &amp;nbsp; &amp;nbsp; U-Boot 에서 NFS 부팅설정 일단 U-Boot 로 들어가자 nand 모드로 write 한 다음에 바로 부팅하면 환경설정이 모두 초기화 되어있는것을 알 수 있다. 그래서 다시 ip 셋팅을 하자. # setenv ipaddr 192.168.0.2 # setenv serverip 192.168.0.4 # saveenv Saving Environment to NAND... Erasing Nand...Writing to Nand... done &amp;nbsp; 다음은 nfs 설정인데 아래와 같이 하면 된다. # setenv bootargs init=/init root=/dev/nfs rw&amp;nbsp; \ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nfsroot=[호스트IP]:[호스트 nfs root] \ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ip=[타겟IP]:[호스트IP]:[게이트웨이]:[넷마스크]::eth0:off \ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; console=ttySAC0,115200n81 ethaddr=[맥어드레스] # saveenv 여기서 맥어드레스는 printenv 에서 나온 ethaddr 값을 쓰도록 하자. 이제 아래와 같이 쓰면 부팅되게 된다. # tftp c0008000 zImage-2629 # bootm c0008000 &amp;nbsp;이것은 tftp 에서 zImage-2629 이미지를 받아서 c0008000 에 올리고 그 주소를 실행하는 건데 개발환경에서는 매번 치기 귀찮기 때문에 아래와 같이 bootcmd 환경변수로 등록해 주자. &amp;nbsp; # setenv bootcmd &amp;nbsp; tftp c0008000 zImage-2629\;bootm c0008000 # saveenv Saving Environment to NAND... Erasing Nand...Writing to Nand... done &amp;nbsp; 호스트 컴퓨터에서 NFS 설정 이제 호스트 컴퓨터에서 리모트 디렉토리를 만들어 줘야한다. 그러기 위해서는 NFS 설정을 해야하는데 아래 파일을 수정하면 된다. # vi /etc/exports 수정 : /root/rootfs *(rw,no_root_squash,no_all_squash) # /etc/init.d/nfs-kernel-server restart 위와같이 설정하고 재시작이 제대로 되었다면 이제 타겟보드를 재시작 해 보자. 안드로이드를 볼 수 있을것이다. &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://cranix.net/311&quot;&gt;글 전체보기&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</summary>
 </entry>
</feed>
