2013년 3월 11일 월요일

android emulator에 kernel module 올리기


안드로이드는 커널로 리눅스를 사용하므로, 리눅스에서와 같이 커널 모듈을 만들어 올림으로써 커널 레벨로의 접근이 가능하다.

안드로이드 에뮬레이터에 커널 모듈을 만들어 올리는 간단한 방법을 기록해 둔다.

안드로이드용 에뮬레이터를 위한 가상 하드웨어의 이름은 goldfish다. 따라서, 이 글에서는 앞으로 안드로이드용 에뮬레이터의 커널을 goldfish 커널이라 부른다.

0. 환경
사용된 기기 / 소프트웨어 버전은 다음과 같다.
ubuntu 12.04 desktop 64bit
git 1.7.9.5

사용된 에뮬레이터의 안드로이드 버전:
4.2.1_r14.2.2 사이 언젠가 sync 해둔 AOSP master branch.

1. goldfish 커널 빌드 & 사용
goldfish 커널은 기본적으로 모듈을 지원하지 않는다.
따라서 커널 소스코드를 받아 모듈을 지원하도록 설정을 수정, 빌드해 올리고 여기에 모듈을 올린다.

1.1. 안드로이드 에뮬레이터 커널 소스 받기
$ git clone https://android.googlesource.com/kernel/goldfish
$ git checkout android-goldfish-2.6.29
(checkout 하는 브랜치는 적당히. $ git branch -r 명령으로 사용 가능한 브랜치를 볼 수 있다)

1.2. prebuilt 소스 받기
크로스 컴파일을 위해 prebuilt 를 받아야 한다.
$ git clone https://android.googlesource.com/platform/prebuilt

1.3. kernel build configuration 설정
리눅스 커널은 빌드 설정을 다양하게 할 수 있으며, 이 정보는 소스코드 디렉토리의 .config 파일에 저장된다. 하지만, 앞서 받아온 소스파일에는 .config가 없다.
아래의 명령으로 goldfish를 위한 기본 설정을 만든다.
$ make goldfish_defconfig

이제 .config 파일이 만들어졌을 것이다.
또는, 다음의 명령으로 이미 돌고 있는 에뮬레이터의 설정을 가져올 수도 있다.

$ adb pull /proc/config.gz
$ gunzip config.gz
$ mv config .config

1.4. MODULE을 지원하는 방식으로 빌드되도록 설정
.config 파일을 열고 다음의 내용을 추가한다.
CONFIG_MODULES=y
CONFIG_MODULES_FORCE_LOAD=y
CONFIG_MODULES_UNLOAD=y
CONFIG_MODULES_FORCE_UNLOAD=y

CONFIG_MODULE_UNLOAD를 설정하지 않으면 모듈을 적재 후 내릴 수가 없다. 유의하자.

1.5. 안드로이드 에뮬레이터 커널 빌드
이건 그냥 s.android.com을 따라하면 되는데... 요약하자면,
$ ARCH=arm CROSS_COMPILE=<path to prebuilt we downloaded above>/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- make -j2
ARCH, CROSS_COMPILE은 따로 export ARCH=arm 과 같은 식으로 하고 마지막에 make만 하는 것도 당연히 가능...
CROSS_COMPILE 에 주는 prebuilt 위치는 앞서 1.2에서 받은 prebuilt임.

빌드가 끝나면 zImage로 커널 이미지가 나옴.

1.6. 에뮬레이터에서 새로 빌드한 커널을 사용
다음의 커맨드로 에뮬레이터가 사용할 커널을 지정 가능.
$ emulator -kernel <path of kernel image>
-show-kernel 과 -verbose 옵션을 추가로 주면 여러모로 편리하다.

2. 안드로이드용 커널 모듈 빌드
이제 안드로이드용 커널 모듈을 만들어보자.
2.1. 커널 모듈 소스코드
다음과 같이 android_module.c 파일을 생성


구체적인 linux kernel module 의 동작 원리는 이 글의 주제가 아니므로 스킵...
위 소스코드는 커널에 적재될 때 "Hello android kernel..." 메세지를, 커널에서 삭제될 때 "Goodbye android kernel..." 라는 메세지를 커널 로그 상에 뱉을 것이다.
실제 동작 코드는 각자의 목적에 맞게 바꾸면 되겠다.


2.2. 커널 모듈 빌드를 위한 Makefile 작성
다음과 같은 내용으로 Makefile을 생성.
4, 7라인의 -C 옵션의 값은 커널 소스가 있는 경로를 나타내야 한다.


2.3. 커널 모듈 빌드
다음과 같이 ARCH, CROSS_COMPILE 환경 변수 설정 후 make 하면 간단하게 끝.
커널 컴파일 할 때와 거의 같다.
$ ARCH=arm CROSS_COMPILE=<path to prebuilt we downloaded above>/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi- make

같은 경로에 android_module.ko가 만들어질 것이다.

3. 커널 모듈 로드
$ adb push android_module.ko /data/
$ adb shell
(이제 android의 shell 위임)
# insmod /data/android_module.ko

dmesg 등의 커맨드로 커널 로그를 확인해 보면 Hello android kernel... 메세지가 보일 것이다.

4. 커널 모듈 언로드
$ adb shell
# rmmod android_module
역시 dmesg 등의 커맨드로 커널 로그를 확인해 보면 Goodbye android kernel... 메세지가 보일 것이다.


* 이 과정대로만 따라할 경우 vermagic에 의해 module load에서 문제를 겪는 경우가 생길 수 있다.
이 경우는 다음 글을 참고하면 된다.
http://dry-kiss.blogspot.kr/2013/07/android-linux-module-vermagic.html


참고 자료:
http://linuxclues.blogspot.kr/2010/05/build-compile-linux-kernel-android.html
http://stackoverflow.com/questions/6282669/how-do-you-create-a-loadable-kernel-module-for-android
http://s.android.com/