IT_etc/Android Porting

[펌] Android Porting On Real Target/ko

JJun ™ 2010. 10. 6. 10:49

----------------------------------------------------------------------------------------------

출처: http://wiki.kldp.org/wiki.php/AndroidPortingOnRealTarget/ko

----------------------------------------------------------------------------------------------

 


 

1 Introduction


구글은 안드로이드가 운영체제, 미들웨어 그리고 중요 프로그램을 포함하는 임베디드 디바이스를 위한 소프트웨어 스택이라고 설명합니다. 이 문서는 구글 안드로이드 아키텍처에 대해 설명하고 실제 하드웨어에 포팅하는 절차를 설명합니다. 설명은 안드로이드 에뮬레이터의 m3 SDK 버전에 기초해서 설명합니다.

여러분이 커널 패치, 패치의 거부 해결, 램디스크 이미지 만들기, 리눅스 커널 자체에 대한 충분한 지식을 가지고 있다면 이 아티클은 쉬울 것입니다.

2 Copyright and Acknowledgements


이 문서의 소유권은 Kwangwoo Lee <Kwangwoo.lee@gmailREMOVETHIS.com> 에게 있습니다. 이 문서에 대한 복사, 배포, 수정에 대한 권리는 GNU Free Documentation License 를 따릅니다.

번역은 양정석(dasomoli@gmailREMOVETHIS.com) 이 하였습니다만, 이상한 곳이 있다면 가차없이 수정해 주세요. :) 원문 : http://wiki.kldp.org/wiki.php/AndroidPortingOnRealTarget

3 안드로이드 아키텍처의 요약 분석


3.1 안드로이드 커널


안드로이드 커널의 가장 큰 차이점은 ARM EABI(Embedded Application Binary Interface)와 OpenBinder IPC(Inter Process Communication)를 사용한다는 것입니다. 여러분이 ARM EABI를 지원하는 커널을 컴파일하려면, ARM EABI를 지원하기 위한 툴체인(toolchains)을 새로 빌드하여야 합니다.

안드로이드 SDK는 Qemu를 사용하여 goldfish 아키텍처를 에뮬레이션합니다. alsa는 안드로이드의 오디오를 위해서 사용됩니다. goldfish 아키텍처 디렉토리의 audio.c 파일을 보고, 드라이버는 안드로이드 시스템 상의 오디오를 위한 /dev/eac를 사용합니다. 또한 RTC(Real Time Clock) 장치는 /dev/rtc0를 통해 사용됩니다.

다음 파트들은 주된 차이점을 설명합니다:

3.1.1 ARM EABI


EABI는 ARM사(ARM Ltd.)에 의한 새로운 "임베디드" ABI입니다. 그 차이는 데비안 위키에 정리되어 있습니다.

  • FPU를 쓰거나 쓰지 않는, 빠른 실수 연산(floating point) 성능
  • soft 와 hardfloat 코드의 혼용 가능
  • 이전에 사용되어지던 것과 같이 구조체 팩킹(packing)이 고통스럽지 않습니다.
  • 다른 툴들과의 더 나은 호환성(compatibility)
  • 더 효율적인 syscall 관례(convention). (http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=3105/4)

long ftruncate64(unsigned int fd, loff_t length); 의 예:
기존 ABI:
- put fd into r0 (fd를 r0로 넣음)
- put length into r1-r2 (길이를 r1-r2로 넣음)
- 커널 호출을 위해서 "swi #(0x900000 + 194)" 사용.
새로운 ARM EABI:
- put fd into r0 (fd를 r0로 넣음)
- put length into r2-r3 (skipping over r1) (길이를 r2-r3로 넣음. r1은 무시)
- put 194 into r7 (194를 r7로 넣음)
- use "swi 0" to call the kernel (커널을 호출하기 위해서 "swi 0" 사용)

안드로이드는 EABI 커널 기능을 사용합니다. CONFIG_AEABI 와 CONFIG_OABI_COMPAT의 커널 옵션을
활성화 하세요. 여러분은 다음과 같은 실행 바이너리의 차이를 볼 수 있습니다:

  • 기존 ABI
$ arm-softfloat-linux-gnu-objdump -x t7-demo | grep private
private flags = 202: [APCS-32] [FPA float format] [software FP] [has entry point]
$ file t7-demo
t7-demo: ELF 32-bit LSB executable, ARM, version 1 (ARM), 
for GNU/Linux 2.4.3, dynamically linked (uses shared libs), 
for GNU/Linux 2.4.3, stripped

  • ARM EABI
$ arm-softfloat-linux-gnueabi-objdump -x t7-demo  | grep private
private flags = 4000002: [Version4 EABI] [has entry point]
$ file t7-demo
t7-demo: ELF 32-bit LSB executable, ARM, version 1 (SYSV), 
for GNU/Linux 2.6.14, dynamically linked (uses shared libs), 
for GNU/Linux 2.6.14, stripped


ARM 아키텍처를 위한 ABI가 무엇인가요? ARM EABI와 같은 건가요?

ARM 아키텍처의 ABI는 ARM와 (CodeSourcery를 포함하는) 그 파트너들에 의해 개발된 어떻게 컴파일러와 어셈블러와 링커와 다른 비슷한 툴들이 Object 파일과 실행 파일을 생성해야만 하는지를 설명하는 표준입니다. ARM 아키텍처의 ABI를 정확히 구현한 툴들은 상호 운용(interoperate)될 수 있습니다:예를 들면, 다른 툴체인에서 빌드된 Object 파일과 또 다른 툴체인에서 빌드된 Object파일이 양 쪽의 컴파일러가 ARM 아키텍처의 ABI를 사용한다면 함께 합쳐질 수 있습니다. "ARM EABI"는 ARM 아키텍처 ABI의 또다른 이름입니다.

3.1.2 OpenBinder


OpenBinder는 객체지향(object-oriented) 운영체제 환경을 제공합니다. 전통적인 커널에 호스팅(to be hosted)되어지도록 설계되었습니다. 이 프로젝트는 BeOS 다음번 생성의 일부로 Be. Inc에서 시작되었고, Cobalt 시스템의 코어 부분으로 PalmSource에 구현이 완료되었습니다. 그 것은 시스템이 Application에 지향보다는 컴포넌트 아키텍처에 지향적이고, 프로세스 간의 IPC, 스레드풀, 메모리 관리와 클린 업(clean up) 기능을 바인더 Obejct의 참조의 끝에서 제공합니다. 바닐라(vanilla) 커널은 OpenBinder IPC 메카니즘을 가지고 있지 않으므로, 여러분은 커널에 패치하여야 합니다. OpenBinder는 시스템의 스레드 관리를 /dev/binder를 통해서 제공합니다. 그 것이 안드로이드가 스레드 라이브러리를 제공하지 않는 이유입니다.

커널 패치 후에, 여러분은 /drivers/binder/에서 바인더를 위한 파일을 볼 수 있을 것입니다.

3.1.3 프레임 버퍼


기본적인 프레임 버퍼 드라이버는 이미 구현되어져 있어야만 합니다. 그 후에 여러분은 여러분의 아키텍처 드라이버와 goldfish 드라이버 간의 차이를 구현해야 할 것입니다.

goldfish 아키텍처의 프레임 버퍼 드라이버는 struct fp_ops의 fb_pan_display 함수를 지원합니다. 그 것은 실제 프레임 크기보다 두 배의 메모리가 할당되어야 함을 의미합니다.

  • 프레임 버퍼 정보 초기화
struct fb_info *fbinfo;
...
fbinfo->fix.ypanstep	= 1;
fbinfo->var.yres_virtual    = gm->lcd.yres * 2;
fbinfo->fix.smem_len        =	(gm->lcd.xres *
                                gm->lcd.yres *
                                gm->lcd.bpp / 8) * 2;

  • 프레임 버퍼 메모리 할당
struct mvfb_info *fbi;
...
fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE);
fbi->map_cpu  = dma_alloc_writecombine(fbi->dev, fbi->map_size,
                                       &fbi->map_dma, GFP_KERNEL);

  • fb_pan_display 함수 후킹 구현
static int mvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb)
{
...
}
static struct fb_ops mvfb_ops = {
        .owner		= THIS_MODULE,
        .fb_check_var	= mvfb_check_var,
        .fb_set_par	= mvfb_set_par,	
        .fb_setcolreg	= mvfb_setcolreg,
        .fb_blank	= mvfb_blank,
        .fb_pan_display = mvfb_pan_display,
        .fb_fillrect	= cfb_fillrect,
        .fb_copyarea	= cfb_copyarea,
        .fb_imageblit	= cfb_imageblit,
        .fb_mmap	= mvfb_mmap,	
};

그 디바이스 파일은 /dev/graphics/fb0에 위치해 있습니다.

3.1.4 입력 장치


안드로이드는 사용자 입력을 위한 이벤트 디바이스를 사용합니다. 거기에는 키패드와 쿼티2(qwerty2) 키보드와 마우스와 같은 세가지 디바이스가 있습니다. 쿼티2(qwerty2) 키보드와 마우스는 보통 디바이스입니다. 그래서 마우스 디바이스를 대체하는 키패드와 터치스크린을 설명하겠습니다.

안드로이드 쉘에서 /proc/bus/input/{devices,handlers}를 cat 하면, 안드로이드에서 사용되는 디바이스들을 볼 수 있습니다.
$ adb shell
# cat /proc/bus/input/devices
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="goldfish-events-keyboard"
P: Phys=
S: Sysfs=/class/inut/input0
U: Uniq=
H: Handlers=kbd mouse0 event0
...
#
# cat /proc/bus/input/handlers
N: Number=0 Name=kbd
N: Number=1 Name=mousedev Minor=32
N: Number=2 Name=evdev Minor=64
#

  • 키패드
Qemu는 goldfish-events-keyboard를 에뮬레이트합니다. 그 것은 이벤트 디바이스(/dev/input/event0)를
사용하는 키패드입니다. 그래서 여러분은 이벤트 디바이스로부터 실제 활성화된 안드로이드 프로그램으로
전달되어지는 키 이벤트의 종류와 값을 알 수 있습니다. 그렇게 하기 위해서 event0 디바이스를 cat으로 읽고
파일로 그 출력을 재지정(redirect)합니다. 만약 에뮬레이터 상의 키 버튼이 눌리고 떼어지면 그 출력 값이
저장될 것입니다.
그 출력 형식은 input_event 구조체 입니다. 그래서 각 event의 출력은 시간을 위한 8 바이트, 타입을 위한
2 바이트, 코드를 위한 2 바이트, 값을 위한 4바이트로 총 16 바이트입니다. 리눅스 커널 소스 코드의 Documentation/input 디렉토리의 입력 이벤트 디바이스(input event device)에 관한 input.txt를 읽고,
input-programming.txt를 읽으세요.
struct input_event {
        struct timeval time;
        unsigned short type;
        unsigned short code;
        unsigned int value;
};

Tiger7 개발 보드는 그 고유의 scancode 테이블을 가집니다. 다음은 개발보드의 키 레이아웃과 scancode 테이블과 안드로이드 키 코드를 보입니다:
/*
 *  Key Layout       Scancode Table
 *
 *   1  2  3        0x1  0x10  0x100
 *   4  5  6        0x2  0x20  0x200
 *   7  8  9        0x4  0x40  0x400
 *   *  0  #        0x8  0x80  0x800
 */
static unsigned short android_keycode[] = {
        /*
         *  0x66 0x67 0x9e	Home  Up   Back
         *  0x69 0xe8 0x6a	Left  Ok   Right
         *  0xe7 0x6c 0x6b	Send  Down Hangup
         *  0xe5		Menu       just_distinction_for_private
         */
        KEY_HOME,         KEY_UP,       KEY_BACK,
        KEY_LEFT,         KEY_REPLY,    KEY_RIGHT,
        KEY_SEND,         KEY_DOWN,     KEY_END,
        KEY_KBDILLUMDOWN, KEY_RESERVED, KEY_PLAY
};

에뮬레이터에는 전원(power) 버튼이 있습니다. 그러나 출력 값을 얻기 위해서 무시했습니다.

키패드의 인터럽트가 감지(caught)되면 위 테이블의 안드로이드의 키 코드로 scancode를 변환하고 사용자 공간(user space) 프로그램으로 이벤트를 보냅니다.
...
keycode = translate_keycode(scancode);
...
input_event(keydev->input, EV_KEY, keycode, KEY_PRESSED);
or
input_event(keydev->input, EV_KEY, keycode, KEY_RELEASED);
...

고정밀도 타이머 - hrtimer는 키패드 debounce를 줄이기 위해서 사용되었습니다.

  • 터치 스크린

포인팅 디바이스를 위한 이벤트 인터페이스를 지원하는 터치스크린 드라이버를 갖고 있다면, 잘 동작할 것입니다. 그렇지 않다면, 다른 포인팅 디바이스를 사용하거나 구현해야 합니다. 다행스럽게도 개발보드는 이미 안드로이드 포팅을 시작하기 전에 만들어진 터치스크린 드라이버 - drivers/input/touchscreen/tsc2007.c -가 구현되어 있었습니다. 여러분 고유의 드라이버를 구현하기 위해서는 drivers/input/touchscreen/ 의 드라이버와 Documentation/input/의 텍스트 파일을 참고하세요.
여기 개발 보드 상의 /proc/bus/input/{devices,handlers}의 출력이 있습니다.
# cat /proc/bus/input/devices
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="MVT7 KEYPAD"
P: Phys=
S: Sysfs=/class/input/input0
U: Uniq=
H: Handlers=kbd event0 evbug
B: EV=f
...
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="TSC2007 Touchscreen"
P: Phys=0-0090/input0
S: Sysfs=/class/input/input1
U: Uniq=
H: Handlers=event1 evbug
B: EV=b
B: KEY=400 0 0 0 0 0 0 0 0 0 0
B: ABS=1000003
# cat /proc/bus/input/handlers
N: Number=0 Name=kbd
N: Number=1 Name=evdev Minor=64
N: Number=2 Name=evbug

결과에서 보는 것과 같이, 프로그램 계층(application layer)에서 키패드는 /dev/input/event0를 사용하고, 터치스크린 인터페이스는 /dev/input/event1를 사용합니다.

3.1.5 Low Memory Killer


리눅스 커널은 프로세스의 요청을 위한 할당을 위해서 남은 메모리가 없는 상황을 위한 OOM(Out of Memory) 킬러를 가지고 있습니다. 그 것은 모든 프로세스를 시험하고 어떤 제약으로 점수를 매깁니다. 최고 점수의 init을 제외한 프로세스는 죽여집니다.

안드로이드의 Low Memory Killer는 OOM 킬러와 약간 다릅니다. 그 것은 그룹의 중요성에 따라 프로세스를 분류하고 가장 낮은 그룹의 프로세스를 죽입니다. 그 것은 시스템을 최종 사용자(end user) 관점에서 안정적이게 만듭니다. 예를 들면, UI 프로세스 - foreground process -는 최종 사용자에게 가장 중요한 프로세스입니다. 그래서 프로세스를 지키는 것은 다른 background 프로세스의 삶을 지키는 것보다 더 안정적으로 보이는 것을 살립니다.

커널 패치 후에 CONFIG_LOW_MEMORY_KILLER 를 활성화하세요.

3.1.6 안드로이드 로거(Android Logger)


여러분이 이 기능을 활성화하면 /dev/log/main를 통해 안드로이드에 관한 유용한 정보를 볼 수 있습니다. main, events, radio 같은 /dev/log 상의 세가지 디바이스 파일이 있습니다. /dev/log/radio 파일은 안드로이드 시스템 상의 모뎀과 ril 데몬 - rild - 에 관련된 것을 보여줍니다.

이 로거를 활성화할때, 시스템 성능은 시스템 상에서 약간 느려집니다. 이 기능을 사용하기 위해서 CONFIG_ANDROID_LOGGER를 활성화하세요.

3.1.7 안드로이드 파워(Android power)


안드로이드 파워는 디바이스 상의 배터리 관리과 전원 관리에 관련된 파일 시스템 상의 inotify 기능과 같은 서브시스템을 위한 것입니다. 그 것은 안드로이드 시스템의 init 바이너리를 통해 안드로이드를 시작하기 위해서 필요합니다. 그러나 runtime 바이너리는 안드로이드의 수동 시작 상에서 안드로이드 파워에 따르는 어떤 파일 - /sys/android_power/acruire_partial_wake_lock - 을 찾고 시작에 실패합니다. 사용하기 위해서는 CONFIG_ANDROID_POWER 옵션을 활성화시키세요.

3.1.8 Panic Timeout


개발 보드 상의 안드로이드 시작을 위해서 필요없습니다. CONFIG_PANIC_TIMEOUT 를 원하는 값으로 설정하세요.

3.2 안드로이드 루트 파일 시스템


안드로이드 에뮬레이터는 tools/lib/images디렉토리 상에 3개의 기본 이미지를 가집니다.

  • ramdisk.img
  • system.img
  • userdata.img

ramdisk.img 은 gzip으로 압축된 cpio 파일입니다. 램디스크 이미지는 매우 작고, 설정 파일과 init과 recovery 같은 실행파일을 포함합니다. init 파일은 정식 System V init은 아닙니다. 그 것은 안드로이드를 위해 만들어졌고, 안드로이드 시스템을 시작하기 위한 특별한 것을 수행합니다.

system.img 와 userdata.img 는 VMS Alpha 실행파일입니다. system.img와 userdata.img 는 루트 파일 시스템 상의 /system 과 /data 디렉토리의 내용을 가집니다. 그들은 NAND 디바이스 상에 yaffs2 파일 시스템으로 맵핑되어 있습니다. /dev/block/mtdblock0 는 /system 이고, /dev/block/mtdblock1 은 /data 입니다.

/system 디렉토리는 라이브러리와 기본 시스템 패키지(*.apk)를 가지고 있습니다. /data 디렉토리는 타임존, 캐쉬, ApiDemos.apk 패키지를 가지고 있습니다.

주 서비스는 zygote(/system/bin/app_process), runtime(/system/bin/runtime), 그리고 dbus(/system/bin/dbus-daemon) 입니다. 여러분은 안드로이드 램디스크 상의 /etc/init.rc 파일을 볼 수 있습니다.

...
zygote {
    exec /system/bin/app_process
    args {
        0 -Xzygote
        1 /system/bin
        2 --zygote
    }
    autostart 1
}
runtime {
    exec /system/bin/runtime
    autostart 1
}
...
dbus {
    exec /system/bin/dbus-daemon
    args.0 --system
    args.1 --nofork
    autostart 1
}
...

3.3 안드로이드 패키지의 라이센스


tools/lib/images/NOTICE 는 패키지 리스트와 각 라이브러리의 라이센스를 포함하고 있습니다.
라이센스 표는 2008 Korea Android Summit에서 임근식 씨의 발표로부터 게시되었습니다.

Open Source License
Linux Kernel GPL
NetBSD C Library BSD
DBUS GPL2
OpenBinder (core) GPL2
YAFFS2 GPL
SQLite GPL2
Webkit BSD (including LGPL)
WebCore LGPL
SDL LGPL
SGL Google(Skia)
OpenGL SGI OpenGL (BSD/MPL)


4 ARM EABI를 지원하는 툴체인


툴체인은 시스템 개발에 사용되어지는 툴들을 말합니다. C/C++ 컴파일러, 링커, 라이브러리, binutils와 기타 다른 것들을 포함합니다. 안드로이드 커널과 시스템은 EABI 지원을 필요로 합니다. 그래서 기존 툴체인은 안드로이드 시스템을 만드는데 호환되지 않습니다.

4.1 툴체인 빌드하기


더 쉽게 삶을 살기 위해서, Dan Kegel에 의한 crosstool-0.43 스크립트(http://www.kegel.com/crosstool/ )를 사용했습니다. 불행히도 그 것은 eabi 툴체인을 빌드하기 위한 지원을 하지 않습니다. 그래서 Khem Raj의 a glibc 2.5+ nptl build for arm softfloat eabi patch (http://sources.redhat.com/ml/crossgcc/2006-12/msg00076.html )를 적용했습니다.
$./arm-softfloat-eabi.sh

네트워크가 연결되어 있다면, 스크립트가 gcc 4.1.1 과 glibc 2.5을 사용해서 툴체인을 다운로드하고 빌드해 줄 겁니다.

4.2 다른 툴체인


Codesourcery 툴체인을 사용하지 않았습니다만, 그들은 그 것이 안드로이드 시스템 빌드를 위해서 잘 동작할 것이라고 말하고 있습니다.


5 커널


실제 하드웨어 상에 안드로이드포팅하는 것은 Benno (http://benno.id.au )에 의해서 시작되었습니다.
여러분은 그의 블로그에서 유용한 정보를 볼 수 있습니다. 그의 블로그는 pre-compiled static binaries를
링크합니다. 그것은 안드로이드 시스템 디버깅에 매우 유용합니다. 여러분 역시, static build busybox와
strace 바이너리를 빌드할 수 있지만, 갖다 쓰는 게 더 좋을 겁니다.

여러분은 안드로이드 커널과 바닐라 커널 2.6.23 버전 사이의 차이를 포함한 패치 파일을 얻을 수 있습니다. 그 것은 그것들 사이의 모든 차이를 가집니다. 그래서 여러분은 그것들의 일부를 추출할 필요가 있고,
여러분의 시스템 아키텍처를 위한 여러분 고유의 패치를 만들 수 있습니다.

예를 들면, 안드로이드 커널은 그 고유의 yaffs 파일 시스템 패치를 가집니다. 여러분의 아키텍처상에서
여러분 고유의 yaffs 나 jffs2 같은 어떤 다른 파일 시스템을 가진다면, yaffs 패치의 일부를 제거해야 합니다.
안드로이드 커널이 에뮬레이트하는 qemu 상의 ARM 아키텍처의 goldfish 아키텍처는 여러분의 아키텍처의 일부가 될 필요가 없습니다. 제거 될 수 있습니다.

안드로이드 커널은 ARMv5 명령을 에뮬레이트합니다. 그래서 ARM926EJ-S (ARMv5TEJ)는 작업하기
매우 좋을 겁니다.

5.1 커널 패치


Benno 는 openmoko의 NEO1973 디바이스로 작업했습니다. 그래서 그는 그 것을 위한 패치 파일을 만들었습니다. http://benno.id.au/blog/2007/11/21/android-neo1973 에서 원본 패치 파일을 얻고, android.diff를 사용했습니다. 그 것은 goldfish, qemu, yaffs 그리고 안드로이드에 특정적인 부분에 관한 전부를 가지고 있습니다.

여러분은 직접 패치 파일을 편집하고 제거할 수 있습니다. goldfish와 qemu에 특정적인 부분을 제외한 binder, 안드로이드 파워, 안드로이드 로거, low memory 킬러를 포함하는 패치를 만든 후에 바닐라 리눅스 커널 2.6.23을 얻고, 그 걸로 패치하세요.

여러분이 2.6.24.1 버전 리눅스 커널을 사용한다면 안드로이드 파워에 관련된 부분이 동작을 위해서 비활성화 되거나 적절히 고쳐져야 합니다.

5.2 .config


  • 필수적인 부분
...
CONFIG_PANIC_TIMEOUT=0
CONFIG_AEABI=y
CONFIG_OABI_COMPAT=y
CONFIG_BINDER=y
CONFIG_LOW_MEMORY_KILLER=y
...

  • 필요에 따른 부분
...
# CONFIG_ANDROID_GADGET is not set
# CONFIG_ANDROID_RAM_CONSOLE is not set
# CONFIG_ANDROID_POWER is not set
# CONFIG_ANDROID_LOGGER is not set
...

6 루트 파일 시스템


루트 파일 시스템은 램 상의 기본 램디스크 이미지, NAND dev0 (/dev/block/mtdblock0) 그리고, NAND dev1 (/dev/block/mtdblock1)의 자료 이미지, 세가지 부분으로 제작되어 있습니다. MTD 디바이스는 yaffs2 파일 시스템을 가지고 각각은 안드로이드 에뮬레이터 상에서 64MiB 용량을 가집니다.

추출된 system 과 data 디렉토리는 실제 존재하는 NAND 디바이스 상에 복사되었고, 그들은 실제 하드웨어에서 동작시키기 위해서 --bind 옵션으로 마운트되어졌습니다.

6.1 에뮬레이터에서 램디스크 이미지 얻기


1. tools/lib/images/ramdisk.img에서 ramdisk 이미지를 unpack
$ gzip -cd ramdisk.img > ramdisk
$ cpio -iv -F ramdisk

cpio 는 현재 작업중인 디렉토리상에 파일과 디렉토리를 푼다.

2. 램디스크의 내용 목록

data
dev
etc
etc/default.prop
etc/firmware
etc/firmware/brf6150.bin
etc/firmware/brf6300.bin
etc/hcid.conf
etc/hosts
etc/init.gprs-pppd
etc/init.rc
etc/init.ril
etc/init.testmenu
etc/ppp
etc/ppp/chap-secrets
etc/ppp/ip-down
etc/ppp/ip-up
etc/qemu-init.sh
etc/system.conf
etc/system.d
etc/system.d/bluez-hcid.conf
etc/usbd.conf
init
proc
sbin
sbin/recovery
sys
system
tmp
var
var/run

6.2 에뮬레이터에서 data와 system 디렉토리 얻기



data와 system 디렉토리를 얻기 위해서 여러분은 busybox 바이너리를 static 컴파일하여야 합니다. 컴파일된 바이너리는 http://benno.id.au/blog/2007/11/14/android-busybox 에서 얻거나, 여러분 고유의 바이너리를 만들 수 있습니다.

1. 안드로이드 에뮬레이터를 실행시키세요.

2. 에뮬레이터 안에 static 컴파일된 busybox를 넣으세요.
# adb push busybox .

3. 안드로이드 쉘을 실행시키세요.
# adb shell

4. busybox로 tarball을 만드세요.
# chmod +x /busybox
# busybox tar -c /data.tar /data
# busybox tar -c /system.tar /system
# exit

5. 에뮬레이터에서 tarball을 추출하세요.
# adb pull /data.tar .
# adb pull /system.tar .

추출 명령은 종종 실패합니다. 성공적으로 될 때까지 계속 실행하세요.
 
 

6.3 존재하는 램디스크 이미지로 안드로이드 시스템을 통합하기


여러분의 아키텍처의 램디스크는 여러분의 작업을 조금 더 쉽게 만듭니다. system과 data 디렉토리를 제외한 안드로이드 램디스크의 내용을 여러분 고유의 램디스크로 복사하세요. 그리고 그냥 system과 data 디렉토리의 마운트 지점을 만드세요. 마운트 지점은 나중에 bind 옵션으로 사용될 수 있습니다. 안드로이드 램디스크 이미지의 init 바이너리는 시스템을 시작하기 위한 중요 바이너리이고, 그것은 /etc/init.rc 파일 상에서 설정 파일을 읽습니다.

/etc/init.rc를 편집하고 qemu 부분을 주석으로 만드세요.
...
startup {
        ...
#       qemu-init {
#           exec /etc/qemu-init.sh
#       }
}
...

run.sh 스크립트를 만드세요. /dev/block/mtdblock5는 실제 NAND 디바이스의 mtd 파티션이고, 그 것은 /mnt 상에 마운트되어 집니다. data와 system 디렉토리는 이미 mtdblock5 상에 복사되어져 있습니다.
그래서 그 스크립트는 아래와 같이 / 상의 각 디렉토리의 바인드 마운팅(bind mounting)을 보입니다.
여러분의 보드 설정에 따라 스크립트를 고치세요.
#!/bin/sh
mount -t yaffs /dev/block/mtdblock5 /mnt
mount --bind /mnt/data   /data
mount --bind /mnt/system /system
# data folder is owned by system user on emulator. Fix 777 to other.
chmod 777 /data
#chmod 777 /system
export PATH=/system/sbin:/system/bin:/sbin/usr/local/bin
export LD_LIBRARY_PATH=/system/lib
export ANDROID_BOOTLOGO=1
export ANDROID_ROOT=/system
export ANDROID_ASSETS=/system/app
export EXTERNAL_STORAGE=/sdcard
export ANDROID_DATA=/data
export DRM_CONTENT=/data/drm/content
/init &

터치스크린을 위한 필요에 따른 설정 - TSLib.
...
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export LD_PRELOAD=/lib/libts.so:/lib/ts/pthres.so
...

6.4 System 과 data 디렉토리


system 과 data 디렉토리의 내용은 이미 mtdblock5에 이미 복사되어져 있습니다. 여러분은 여러분 고유의 방법으로 복사하셔야 합니다. 그것을 사용하기 위해서 저는 루트 디렉토리상에 바인드 마운팅(bind mounting)을 선택했습니다. 바인드 마운팅은 이미 존재하는 디렉토리를 새로운 마운트 포인트로 마운트하는 기술입니다.

6.5 실행과 디버그


이제 커널과 램디스크와 자료 디렉토리 - data와 system -이 준비되었습니다.
빨간 사일런 눈을 볼 시간입니다. 여러분의 통합된 시스템을 부팅하고 나서 run.sh를 루트 디렉토리에서
실행하세요.
# cd /
# . /android/run.sh
yaffs: dev is 32505861 name is "mtdblock5"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.5, "mtdblock5"
yaffs: auto selecting yaffs2
# init: HOW ARE YOU GENTLEMEN
init: reading config file
init: device init
init: mtd partition -1,
init: mtd partition 0, "l1boot"
init: mtd partition 1, "u-boot"
init: mtd partition 2, "params"
init: mtd partition 3, "kernel"
init: mtd partition 4, "ramdisk"
init: mtd partition 5, "rootfs"
sh: can't access tty; job control turned off
# binder_open(c394bcc8 c3c731a0) (pid 1577) got c3e48000
binder_open(c394bcc8 c3cd8dc0) (pid 1616) got c319f000
binder_open(c394bcc8 c3cd8ac0) (pid 1673) got c3d10000
binder_open(c394bcc8 c3cd8940) (pid 1680) got c0e19000
binder_open(c394bcc8 c3cd88c0) (pid 1691) got c2fa0000
binder_open(c394bcc8 c3d174a0) (pid 1592) got c25b8000
binder_release(c394bcc8 c3cd88c0) (pid 1691) pd c2fa0000
#

  • /dev 상에 eac 디바이스 파일을 만들지 마세요. 그 것은 qemu상의 오디오를 위한 것입니다. 만약 있다면 시작 절차(start up sequence)는 사운드 디바이스에 어떤 데이터를 쓰는 것을 끝마치기 위해서 영원히 기다릴 것입니다.
  • 수동 시작(manual startup) 대신에 안드로이드 init 바이너리를 사용하세요. 수동 시작은 안드로이드 패치가 필요합니다. 그 경우 시작 절차는 /sys/android_power/acquire_partial_wake_lock에 접근하고 기다릴 것입니다.

안드로이드 시스템을 디버깅하기 위해서 http://benno.id.au/blog/2007/11/18/android-runtime-strace 의 static 컴파일된 strace 바이너리를 사용하고, 안드로이드를 수동으로 실행하세요.

#!/bin/sh
# set environment variables above example
...
/system/bin/app_process -Xzygote /system/bin --zygote &
/system/bin/dbus-daemon --system &
/system/bin/runtime

다음 예제는 수동 시작 절차를 보여줍니다. /system/bin/runtime 바이너리 상에서 strace를 사용하세요.

./strace -ff -F -tt -s 200 -o /tmp/strace runtime

6.6 스크린샷


recvfrom(4, "add@/devices/virtual/misc/networ"..., 1024, 0, NULL, NULL) = 144
mknod("/dev/network_latency", S_IFCHR|0600, makedev(10, 58)) = 0
chown32("/dev/network_latency", 0, 0)   = 0
recvfrom(4, 0xbee2b72a, 1024, 0, 0, 0)  = -1 EAGAIN (invain)
getdents64(8, /* 5 entries */, 4200)    = 136
getdents64(8, /* 0 entries */, 4200)    = 0
close(8)                                = 0
SYS_305(0x7, 0x27f3b, 0x24000, 0, 0x28e98) = 8
SYS_305(0x8, 0x1b6ec, 0x20001, 0, 0x28e98) = 9
write(9, "add\n", 4)                    = 4
close(9)                                = 0
recvfrom(4, "add@/devices/virtual/misc/networ"..., 1024, 0, NULL, NULL) = 150
mknod("/dev/network_throughput", S_IFCHR|0600, makedev(10, 57)) = 0
chown32("/dev/network_throughput", 0, 0) = 0
recvfrom(4, 0xbee2b72a, 1024, 0, 0, 0)  = -1 EAGAIN (Resource temporarily unavailable)
getdents64(8, /* 5 entries */, 4200)    = 136
getdents64(8, /* 0 entries */, 4200)    = 0
close(8)                                = 0
getdents64(7, /* 0 entries */, 4200)    = 0
close(7)                                = 0
SYS_305(0x6, 0x26f13, 0x24000, 0, 0x27e18) = 7
SYS_305(0x7, 0x1b6ec, 0x20001, 0, 0x27e18) = -1 ENOENT (No such file or directory)
getdents64(7, /* 3 entries */, 4200)    = 80
SYS_305(0x7, 0x27e6b, 0x24000, 0, 0xffffffff) = 8
SYS_305(0x8, 0x1b6ec, 0x20001, 0, 0x28e98) = 9
write(9, "add\n", 4)                    = 4
close(9)                                = 0
recvfrom(4, "add@/devices/virtual/sound/timer"..., 1024, 0, NULL, NULL) = 128
mknod("/dev/timer", S_IFCHR|0600, makedev(116, 33)) = 0
chown32("/dev/timer", 0, 0)             = 0
recvfrom(4, 0xbee2b72a, 1024, 0, 0, 0)  = -1 EAGAIN (Resource temporarily unavailable)
getdents64(8, /* 5 entries */, 4200)    = 136
getdents64(8, /* 0 entries */, 4200)    = 0
close(8)                                = 0
getdents64(7, /* 0 entries */, 4200)    = 0
close(7)                                = 0
getdents64(6, /* 0 entries */, 4200)    = 0
close(6)                                = 0
getdents64(5, /* 0 entries */, 4200)    = 0
close(5)                                = 0

7 애플리케이션 개발


안드로이드 애플리케이션은 XML 레이아웃과 자바 문법을 사용합니다만, 자바는 아닙니다. 왜냐하면 그들은 그들 고유의 가상 머신 - dalvik - 과 dex 파일 형식을 위한 컴파일러를 사용하기 때문입니다. 그리고 Home.apk, Phone.apk, ApiDemos.apk 등 과 같이 apk로 이름붙여진 패키지를 사용합니다.

apk 파일은 ZIP 압축파일이고 네 가지 부분을 가집니다.

  • AndroidManifest.xml
  • classes.dex
  • resources.arsc
  • res 디렉토리

Dex 파일 형식은 http://www.retrodev.com/android/dexformat.html 에 설명되어져 있습니다.
그리고 그 파일들의 내용과 디렉토리는 언젠가 구글이 설명할 겁니다. 현재는 설명되지 않았습니다.
우리는 단지 그렇게 추측할 뿐입니다.
안드로이드 SDK는 *.apk 파일을 생성할 것입니다.

7.1 이클립스(Eclipse) 통합개발환경(IDE) 설치하기


http://code.google.com/android/intro/installing.html 의 설치 절차를 따르세요.

1. http://www.eclipse.org/downloads/ 의 (JDT와 WST 플러그인이 포함된)Eclipse IDE for Java developer


3. Apache Ant를 포함하는 eclipse plugin인 ADT (Android Development Tools)

7.2 샘플 애플리케이션을 빌드하고 실행하기


1. 샘플 프로젝트를 열고 빌드

2. 에뮬레이터 상에서 샘플 애플리케이션 실행

7.3 스크린샷


8 에필로그


안드로이드 시스템은 데비안, 레드햇, 수세나 기타 등과 같은 모바일 환경을 위한 새로운 종류의 리눅스 기반의 배포판이 될 것으로 보입니다. 그들은 오픈소스 세상의 리눅스 커널과 많은 다른 라이브러리를 사용할 뿐입니다. 그들은 현재 3D 가속화를 OpenGL-ES 라이브러리에 기반한 소프트웨어를 제공합니다. 그러나 그들은 그를 위한 하드웨어 가속의 기본 프로세서 상에서 개발하고 있습니다. 그 하드웨어 가속은 추후의 빠른 UI 렌더링 효과를 위해 필수적입니다.

SDK 상의 안드로이드 시스템은 실제 하드웨어 상에 포팅하는 것은 완벽하지 않습니다. 왜냐하면, 라이브러리와 클래스에 관련된 어떤 디바이스 - 예를 들면, 카메라 -는 아직 구현되지 않았고, 사용자에게 공개되지 않았습니다. 그 것은 아직 개발 단계에 있는 것으로 보입니다. 그래서 구글의 전체 포팅 킷을 기다리는 것이 더 나을 것 같습니다.

그 전에, 우리는 안드로이드 시스템의 사업 모델을 살펴봐야만 합니다. 그 것은 약간 빠른 CPU 성능을 필요로 하기 때문에 운송 판매사는 싼 기본 프로세서(RF 부분)와 멀티미디어 코프로세서(co-processor)가 필요할 겁니다. 멀티미디어 기능을 포함하는 기본 프로세서는 매우 비싸기 때문입니다.

9 링크와 참조