2018년 11월 20일 화요일

AOSP build

AOSP build


이 문서는 책 Embedded.Android(2013.3)].Karim.Yaghmour 을 기반으로 Android Open Source Project 빌드 방법을  정리한 것 이다.

빌드 사양



하드웨어 빌드 사양

  • 진저브레드 이상은 64비트 운영체제
  • 저장장치용량은 코드 체크아웃을 위한 100GB, 빌드를 위해 추가 150GB 가 필요 함. 시간 단축을 위해 병렬 빌드를 한다면 추가 여유공간이 필요함.
  • 가상머신을 사용한다면 최소 램 용량은 16GB/swap 이 필요


소프트웨어 빌드 사양

  • Android 6.0 (Marshmallow)이상 - AOSP master: Ubuntu 14.04 (Trusty) 사용
  • Java Development Kit (JDK)의 경우 AOSP:master는 배포되는 소스에 JDK를 포함하므로 추가 설치가 필요없다.
    1. Android 7.0 (Nougat) - Android 8.0 (Oreo): Ubuntu - OpenJDK 8
    2. Android 5.x (Lollipop) - Android 6.0 (Marshmallow): Ubuntu - OpenJDK 7
    3. Ubuntu 15.04이상은 ap-get으로 OpenJDK를 설치하면 되지만, 14.04은 OpenJDK 8 설치가 필요할 경우 지원이 되지않으므로 Ubuntu 15.04의 패키지를 설치를 해야 한다.( 아래 링크를 참조)


툴체인

  • Android 8.0 (oreo) 이상은  Clang/LLVM 을 사용한다. Clang은 AOSP/prebuilt폴더에 포함되어 배포된다.
  • Android NDK 와 레거시 커널 빌드를 위해 AOSP:master 브랜치는 AOSP/prebuilt에 gcc4.9를 포함한다.


우분투 14.04의 경우 필요한 추가적인 빌드 패키지 설치

  • sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev libgl1-mesa-dev libxml2-utils xsltproc unzip


우분투에서 prebuilt에 포함된 OpenJDK8 이용하기

  1. prebuilt에 포함된 JDK를 다른 안드로이드 버젼의 빌드시 사용하기 위해 적당한 디렉토리로 복사한다.
$ sudo cp -rf prebuilts/jdk/jdk8 /usr/lib/jvm/openjdk8


  1. 우분투에 설치된 기존 JDK를 확인한다.
$ sudo update-alternatives --config javac
[sudo] password for paul:
There is only one alternative in link group javac (providing /usr/bin/javac): /usr/lib/jvm/java-7-oracle/bin/javac
설정할 것이 없습니다.


  1. 새로운 java를 우선순위 2로 설정
$ sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/openjdk8/linux-x86/bin/java 2
update-alternatives: using /usr/lib/jvm/openjdk8/linux-x86/bin/java to provide /usr/bin/java (java) in 자동 모드


  1. 새로운 javac 우선순위 2로 설정
$ sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/openjdk8/linux-x86/bin/javac 2
update-alternatives: using /usr/lib/jvm/openjdk8/linux-x86/bin/javac to provide /usr/bin/javac (javac) in 자동 모드


  1. 새로운 javadoc 우선순위 2로 설정
$ sudo update-alternatives --install /usr/bin/javadoc javadoc /usr/lib/jvm/openjdk8/linux-x86/bin/javadoc 2
update-alternatives: using /usr/lib/jvm/openjdk8/linux-x86/bin/javadoc to provide /usr/bin/javadoc (javadoc) in 자동 모드


  1. install 확인
$ sudo update-alternatives --config java
대체 항목 java에 대해 (/usr/bin/java 제공) 2개 선택이 있습니다.

 선택       경로                             우선순위 상태
------------------------------------------------------------
* 0            /usr/lib/jvm/openjdk8/linux-x86/bin/java   2 자동 모드
 1           /usr/lib/jvm/java-7-oracle/jre/bin/java    1 수동 모드
 2           /usr/lib/jvm/openjdk8/linux-x86/bin/java   2 수동 모드

$ java -version
openjdk version "1.8.0_152-android"
OpenJDK Runtime Environment (build 1.8.0_152-android-4163371-1)
OpenJDK 64-Bit Server VM (build 25.152-b1, mixed mode)

repo 설치

  • Git을 이용한 스크립트 파일로 여러개의 Git 저장소를 관리한다.
$ mkdir ~/bin
$ PATH=~/bin:$PATH
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo

소스 다운로드

픽셀, 넥서스

다운로드할 버젼 선택

아래 두 가지 방법으로 다운로드할 버젼의 브랜치를 확인 한 후 소스를 다운로드 한다.


  • 안드로이드 웹을 통한 branch name 확인
아래 사이트를 통해서 구글에서 만드는 픽셀과 넥서스의 소스코드를 다운로드 할 수 있다. 또한 동일 페이지에서 코드네임과 API 버젼 테이블도 같이 제공한다.


  • Repo manifest을 통한 branch name 확인
$ cd manifest
$ git branch -a
 android-9.0.0_r8
* master
 remotes/origin/HEAD -> origin/master
 remotes/origin/adt_23.0.3
 remotes/origin/afw-test-harness-1.5
 remotes/origin/afw-test-harness-2.1
 remotes/origin/afw-test-harness-marshmallow-dev
 remotes/origin/afw-test-harness-nougat-dev
 remotes/origin/android-1.6_r1
 remotes/origin/android-1.6_r1.1
 remotes/origin/android-1.6_r1.2


선택한 버전의 소스 다운로드

-b 옵션을 이용하여 각 버젼에 해당하는 브랜치를 다운로드한다.
$ repo init -u https://android.googlesource.com/platform/manifest -b master
$ repo sync -j24


다른 버전을 추가로 받기

AOSP:master branch를 이미 받은 경우, 다른 버젼을 추가로 다운로드를 한다면,  --reference 옵션으로 master branch 에서 이미 받은 리소스를 참조하여 짧은 시간에 repo sync를 완료할 수 있다.


아래 명령은 master를 참조하여 oreo_r46을 다운로드 한다.
$ repo init -u https://android.googlesource.com/platform/manifest -b android-8.1.0_r46  --reference=~/work/android/aosp-master
$ repo sync -j24


비공개 바이너리 다운받기

그래픽 가속기, GPS등 하드웨어 관련 비공개 라이브러리는 AOSP에 포함되지 않으므로 따로 다운로드 받아야한다.
Google's drivers 에서 픽셀, 넥서스의 비공개 바이너리를 다운로드 받을 수 있다.
  • 다운로드된 파일은 압축된 형태로 빌드파일과 라이브러리를 포함한다. 압축을 풀면 일반적으로 /vendor 디렉토리에 풀린다. 이 파일을 비공개 바이너리의 안드로이드 버전에 해당하는 AOSP에 추가하여 빌드를 하면 된다.

구글외  제품 빌드

  • LG전자
안드로이드 와 리눅스를 다운로드 할 수 있다.
  1. AOSP 소스에 LG소스를 추가해서 빌드를 하도록 되어 있다.
아래는 F800_Nougat_Android_10v 빌드방법 이다.
  1. AOSP:android-7.0.0_r6 소스를 다운로드 하여 F800_Nougat_Android_10v 소스와 merge한다.
  2. $ source build/envsetup.sh
  3. $ lunch aosp_bullhead-userdebug
  4. $ make -j4

  • 삼성전자


빌드

envsetup.sh와 lunch는 명령을 실행한 쉘만 적용되므로 새로운 쉘에서 빌드를 할땐 두 명령을 다시 수행해야 한다.

환경설정

현재 쉘에 빌드에 필요한 환경변수를 설정한다.


$ source build/envsetup.sh


빌드타겟 설정

빌드할 타겟은 BUILD-BUILDTYPE 형태로 표현된다.
  1. BUILD:
  2. BUILDTYPE:
    1. user : 제한된 접근권한이 적용, 제품적용 타겟 빌드시 사용한다.
    2. userdebug : user 타입과 비슷하나 root권한이 적용되고 디버깅이 가능하다.
    3. eng : 추가적인 디버깅 툴이 설치되고, 빌드시 최적화를 제거하여 디버깅을 용이하게 한다.
개발 타겟 빌드시 사용한다.
$ lunch aosp_arm-eng


빌드 수행

빌드시 -j옵션으로 병렬로 수행할 빌드 태스크의 개수를 지정할 수 있다.
예) 2 CPUs, 4 cores per CPU, 2 threads per core 이라면, -j16 ~ j32를 설정한다.  
make -j4


빌드에러

jack server error

에러 메시지
jack-rsc.tmp: Is a directory
Communication error with Jack server (56). Try 'jack-diagnose'
ninja: build stopped: subcommand failed


솔루션
아래 명령으로 jack을 재실행 한다.
$ ./prebuilts/sdk/tools/jack-admin kill-server
$ ./prebuilts/sdk/tools/jack-admin start-server


에러메시지
Out of memory error (version 1.3-rc7 'Douarn' (445000 d7be3910514558d6715ce455ce0861ae2f56925a by android-jack-team@google.com)).
GC overhead limit exceeded.
Try increasing heap size with java option '-Xmx<size>'.
Warning: This may have produced partial or corrupted output.
[ 43% 3920/8934] Compiling SDK Stubs with Jack: out/target/common/obj/JAVA_LIBRARIES/android_system_stubs_current_intermediates/classes.jack
ninja: build stopped: subcommand failed.


솔루션
export JACK_SERVER_VM_ARGUMENTS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4g" ./prebuilts/sdk/tools/jack-admin kill-server
./prebuilts/sdk/tools/jack-admin start-server


빌드설정



보드 변경시 필요한 설정 참조: https://elinux.org/Android_Device#build.2Fbuildspec.mk.default

빌드아키텍쳐

Product Deivce Board 의 개념

Makefile 병함 과정

빌드는 envsetup.sh & lunch 명령의 조합이나 buildspeck.mk파일을 통해서 최종 빌드타겟을 설정한다.
buildspeck.mk 이용시 build/buildspec.mk.default를 참조하여 필요한 환경변수를 설정한 뒤 buildspeck.mk를 루트 디렉토리에 저장하면 된다.
아래는 make 명령시 설정된 타겟과 관련된 환경변수를 보여준다.


============================================
PLATFORM_VERSION_CODENAME=Q
PLATFORM_VERSION=Q
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
TARGET_CPU_VARIANT=generic
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.13.0-79-generic-x86_64-Ubuntu-14.04.4-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=PI
OUT_DIR=out
============================================


  • 타겟 디바이스 설정은 build/make/target/product/, device/*/*/에 존재하는 AndroidProducts.mk에서 시작한다.
  • lunch에서 표시되는 타겟리스트는 master:/device/*/*/AndroidProducts.mk 에서 COMMON_LUNCH_CHOICES와 /device/*/*/vendorsetup.sh 에서 add_lunch_combo()로 추가되는 LUNCH_MENU_CHOICES 에 저장된 리스트를 표시한다.
  • add_lunch_combo()는 /device/*/*/vendorsetup.sh 에서 호출된다.
  • 커널파라미터, 커널로딩 주소, CPU instruction set 등을 결정하는 BoardConfig.mk는 device/*/TARGET_DEVICE/BoardConfig.mk 에 존재한다.


envsetup.sh  

소스 검색, 빌드 타겟 확인 등 여러가지 빌드 설정(lunch) 및 빌드 디버깅 기능을 제공한다. 이 스크립트에서 정의 된 명령은 vendorsetup.sh에서도 사용할 수 있다.
  • 도움말: $ hmm
  • 파일 검색 명령(AndroidProducts.mk)
~/work/android/aosp-master$ godir AndroidProducts.mk
  [1] ./device/generic/arm64
  [2] ./device/generic/armv7-a-neon
  [3] ./device/generic/car
  [4] ./device/generic/mini-emulator-arm64
  [5] ./device/generic/mini-emulator-armv7-a-neon
  [6] ./device/generic/mini-emulator-x86
  [7] ./device/generic/mini-emulator-x86_64
  [8] ./device/generic/qemu
  [9] ./device/generic/uml
 [10] ./device/generic/x86
 [11] ./device/generic/x86_64
 [12] ./device/google/atv/products
 [13] ./device/google/cuttlefish
 [14] ./device/google/marlin
 [15] ./device/google/muskie
 [16] ./device/google/taimen
 [17] ./device/linaro/hikey
 [18] ./device/linaro/poplar
 [19] ./device/sample/products

Select one:


vendorsetup.sh

build/envsetup.sh에 의해 실행되며 주요 기능은 add_lunch_combo()를 이용해 envsetup.sh와 lunch에서 사용할 빌드 타켓을 설정한다.  
  • envsetup.sh에 정의된 모든 함수를 사용할 수 있다.
  • 아래 처럼 호출하면 TARGET_PRODUCT=full_crespo, TARGET_BUILD_VARIANT=userdebug 으로  설정된다.
  • 설치되는 각 모듈은 LOCAL_MODULE_TAGS변수에 user, debug, eng, tests, optional, samples 중 하나로 설정되며 TARGET_BUILD_VARIANT에 설정된 값에 매치되는 모듈이 빌드된다.
add_lunch_combo full_crespo-userdebug


AndroidProducts.mk

빌드 시스템에 전달할 makefile리스트인 PRODUCT_MAKEFILES을 설정한다. 이 파일이 적용시 LOCAL_DIR 외 다른 변수는 설정된 것이 없으므로 다른 변수를 이용한 조건문은 불가능 하다.
  • 아래는 LG전자 bullhead의 설정이다.
PRODUCT_MAKEFILES := \
   $(LOCAL_DIR)/aosp_bullhead.mk \
   $(LOCAL_DIR)/aosp_bullhead_svelte.mk


device/company/*/PRODUCT_MAKEFILE

AndroidProducts.mk에서 작성한 제품별 빌드파일로 제품이름 인스톨 패키지등을 설정한다.
  • PRODUCT_PACKAGES: 추가할 패키지를 지정한다.
  • DEVICE_PACKAGE_OVERLAYS: 기본 패키지 리소스를 기기에 특화된 리소스로 대체한다.
  • PRODUCT_COPY_FILES: 대상 파일시스템에 복사할 파일을 지정한다.
  • PRODUCT_NAME: 사용자에게 노출되는 제품이름
  • PRODUCT_DEVICE: 이 변수와 같은 폴더의 BoardConfig.mk를 적용한다.
  • PRODUCT_MODEL: 사용자에게 노출될 모델이름.
  • vendor prebuilt makefile 추가됨(아래 빨간색 글자 참고).
  • 나머지 변수의 의미 참고: Product Definition Variables
# Get the long list of APNs
PRODUCT_COPY_FILES := device/lge/bullhead/apns-full-conf.xml:system/etc/apns-conf.xml

# Inherit from the common Open Source product configuration
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk)

PRODUCT_NAME := aosp_bullhead
PRODUCT_DEVICE := bullhead
PRODUCT_BRAND := Android
PRODUCT_MODEL := AOSP on BullHead
PRODUCT_MANUFACTURER := LGE
PRODUCT_RESTRICT_VENDOR_FILES := true

PRODUCT_COPY_FILES += device/lge/bullhead/fstab.aosp_bullhead:root/fstab.bullhead

$(call inherit-product, device/lge/bullhead/device.mk)
$(call inherit-product-if-exists, vendor/lge/bullhead/device-vendor.mk)

PRODUCT_PACKAGES += \
   Launcher3 \
   WallpaperPicker


build/core/main.mk

최상단 Makefile에 의해 호출되며 build/core/config.mk, build/core/definitions.mk 등 호출해 빌드에 필요한 변수 설정이나 빌드 템플릿을 설정한다.

build/core/config.mk

  • include $(TOPDIR)buildspec.mk 을 수행하여 빌드타겟 설정을 하며 만약 파일이 없으면 환경변수를 이용한다.
  • include $(BUILD_SYSTEM)/envsetup.mk 을 수행하여 envsetup.sh에서 설정한 환경변수를 적용한다.

build/core/envsetup.mk

아래를 호출하여 빌드 버젼과 빌드 타겟 (eng/user..)을 설정한다.
include $(BUILD_SYSTEM)/version_defaults.mk
include $(BUILD_SYSTEM)/product_config.mk

include $(BUILD_SYSTEM)/version_defaults.mk

아래 다양한 빌드 버젼 변수를 설정한다.
PLATFORM_VERSION
PLATFORM_SDK_VERSION
PLATFORM_VERSION_CODENAME
DEFAULT_APP_TARGET_SDK
BUILD_ID
BUILD_NUMBER
  • include $(BUILD_SYSTEM)/build_id.mk 를 통해 BUILD_ID를 설정한다.
  • BUID_ID가 아래처럼 안드로이드 빌드 아아디로 표시된다.
BUILD_ID=OPM6.171019.030.K1

build/core/Makefile

이 파일을 통해 여러가지 결과물이 생성되며 주요 사항은 아래와 같다.
  • 속성파일들(/default.prop, /system/build.prop) 등
  • 램디스크
  • 부트 이미지(램디스크와 커널 이미지)
  • 공지(NOTICE)파일들:아파치 라이센스 관련 파일
  • OTA 키스토어
  • 복구이미지
  • 시스템 이미지
  • 데이터 파티션 이미지
  • OTA 업데이트 패키지
  • SDK


BoardConfig.mk

각 디바이스에 해당하는 보드설정을 한다.
  • device/*/TARGET_DEVICE/BoardConfig.mk 에 위치한다.
  • TARGET_DEVICE는 AndroidProducts.mk에서 설정한  TARGET_PRODUCT.mk 에서 설정된다.
  • 커널파라미터, 커널로딩 주소,
  • CPU instruction set,
  • sepolicy,
  • 파일시스템 파티션 사이즈 등을 결정한다.

build/buildspec.mk.default

buildspec.mk의 템플릿으로 루트디렉토리에 buildspec.mk로 복사한 후 필요한 설정은 주석을 제거하여 적용이 되도록 수정하면 된다.


Makefile 디버깅

빌드시 GCC 명령 보기

  • make showcommands
  • 표준출력과 표준에러를 파일에 기록; make showcommands 2>&1 | tell build.log

개별 모듈 빌드하기

  • 런처만 빌드: make Launcher2
  • 런처만 초기화: make clean-Launcher2
  • 갱신된 런치를 시스템이미지에 추가: make Launcher2 snod


새로운 기기 추가를 위한 설정

안드로이드 제공 문서 참조: https://source.android.com/setup/develop/new-device


  1. 새로운 기기들의 빌드 파일 리스트를 설정한 파일 AndroidProducts.mk를 생성한다.
$ mkdir -p device/mycompany/mydevice
$ vi device/mycompany/mydevice/AndroidProducts.mk
PRODUCT_MAKEFILES := \
 $(LOCAL_DIR)/full_mydevice.mk


  1. 새로운 제품의 빌드파일을 작성한다. 필요한 경우 inherit-product를 이용해 기존 빌드설정을 추가한다.
PRODUCT_DEVICE에 설정된 이름과 같은 디렉토리의 BoardConfig.mk를 적용하게 된다.
$ vi device/mycompany/mydevice/full_mydevice.mk
$(call inherit-product, $(SRC_TARGET_DIR)/product/full_base.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic/device.mk)

# Overrides
PRODUCT_NAME := full_mydevice
PRODUCT_DEVICE := mydevice
PRODUCT_BRAND := Android
PRODUCT_MODEL := Full Android on mydevice


  1. envsetup.sh와 lunch 메뉴에서 추가한 기기를 표시할 수 있도록  vendorsetup.sh를 작성한다.
$ vi device/mycompany/mydevice/vendorsetup.sh
add_lunch_combo full_mydevice-eng
$ chmod 755 vendorsetup.sh


  1. 새로운 기기의 보드에 해당하는 설정을 BoardConfig.mk에 작성한다.
$ vi device/mycompany/mydevice/vendorsetup.sh


  1. 빌드를 한다. 빌드된 이미지의 내용은 아래 폴더(out/target/product/product-name/에서 확인 할 수 있다.
  • ramdisk.img: /root
  • vendor.img: /vendor
  • system.img: /system
  • userdata.img: /data
  • recovery.img: /recovery


빌드시 커널 폴더 추가하기

  1. 최상위 디렉토리에 커널을 추가한다.
  2. 아래 처럼 vendor폴더 추가 스크립트를 적용하는 스크립트를 작성한다.
#!/bin/bash

# Put here shell variables for your environment
#export JAVA_HOME=/usr/lib/jvm/openjdk8
#export ANDROID_JAVA_HOME=$JAVA_HOME
#export USE_CCACHE=1

LUNCH_MENU=full_bullhead-eng

source build/envsetup.sh
lunch $LUNCH_MENU
source vendor/lge/bullhead//build/envsetup.sh
  1. product envsetup에 커널 빌드 함수를 작성한다.
#!/bin/bash

export TOP=$ANDROID_BUILD_TOP
PATH=$ANDROID_HOST_OUT/bin/:$PATH
DATE=`date +%Y%m%d_%H%M`

CORE_NUM=`grep processor /proc/cpuinfo | awk '{field=$NF};END{print field+1}'`

function kernel_make()
{
   #KERNEL_OUT="$OUT/obj/kernel"

   KERNEL_TC_PREFIX=$TOP/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-
   KERNEL_MAKE="make ARCH=arm CROSS_COMPILE=$KERNEL_TC_PREFIX "

   if [ -z "$1" ] ; then
       KERNEL_TARGET="zImage"
   else
       KERNEL_TARGET=$@
   fi

   pushd $TOP/kernel
   $KERNEL_MAKE -j$CORE_NUM  $KERNEL_TARGET
   popd
}

function build_kernel()
{
   ### kernel ###
   LOGFILE="build_${DATE}_kernel.log"
   kernel_make distclean && \
   kernel_make arndale_android_defconfig && \
   kernel_make 2>&1 | tee ${LOGFILE}
   notify-send ${LOGFILE} "`tail ${LOGFILE}`"
}


루트 디렉토리

  • /acct : cgroup 마운트 디렉토리
  • /cache : 진행중인 다운로드등 임시데이터 저장
  • /charger : 배터리 충전상태를 알려주는 네이티브 앱.
  • /config : configs 마운트 디렉토리
  • /d : /sys/kernel/debug 심볼릭 링크
  • /data : userdata.img 마운트 디렉토리
    • /anr : ANR 트레이스
    • /app : 앱의 기본 설치 디렉토리
    • /app-asec : 암호화된 앱
    • /app-private : forward locking된 앱의 설치 디렉토리
    • /backup : Backup Manager 시스템 서비스가 사용한다.
    • /dalvik-cache : dex바이트코드를 네이티브코드로 변환된 JIT캐시를 저장한다.
    • /data : 각 앱의 홈 디렉토리
    • /dontpanic : dumpstate가 사용, 발생된 패닉의 콘솔 출력과 스레드 상태를 저장한다.
    • /drm : DRM 암호화된 데이터. 포워드 락킹 통제 파일.
    • /local : shell에서 쓰기가 가능한 디렉토리.
    • /mis : wifi, BT, VPN등 잡다한 데이터가 저장된다.
    • /property : 영구적인 시스템 속성
    • /resource-cache: 앱 자원 캐시
    • /radio : 라디오 펌웨어
    • /secure : 암호화된 파일시스템을 사용하는 기기에서 사용하는 사용자 계정정보 저장.
    • /system : 계정 데이터베이스, 설치된 앱 목록 등 모든 시스템에서 사용하는 데이터
    • /tombstones : 네이티브 바이너리가 비정상 종료될 때마다 관련정보를 저장
    • /usr : 다중 사용자 시스템을 위한 사용자별 데이터
  • /dev : tmpfs로 마운트 됨, 장치노트가 생성됨.
  • /etc : /system/etc 심볼릭 링크
  • /mnt : 임시 마운트 디렉토리
  • /proc : procfs 마운트 디렉토리
  • /root : root 사용자 홈 디렉토리, 보통 비어있음
  • /sbin : 리눅스와 달리 ueventd, watchdogd 심볼릭 링크와 charger를 포함  
  • /sdcard : SD카드 마운트 디렉토리
  • /storage : 외부 저장소 마운트 디렉토리
  • /sys : sysfs 마운트 디렉토리
  • /system : system.img 마운트 디렉토리, 읽기 전용
    • /app : AOSP 기본 앱, BUILD_PACKAGE로 빌드된 모듈
    • /bin : AOSP로 빌드된 네이티브 바이너리 및 데몬, BUILD_EXECUTALBE로 빌드된 모듈
    • /etc : 유틸리티 및 데몬에서 사용하는 설정파일
    • /fake-libs : art/libart_fake/README.md 말하길 일부 앱에서 잘못된 구현으로 링크가 필요한 라이브러리.
    • /fake-libs64
    • /fonts : 안드로이드용 폰트
    • /framework: 프레임워크 jar파일
    • /lib : 네이티브 라이브러리, BUILD_SHARED_LIBRARY로 빌드된 모듈
    • /lib64
    • /media : 부트 애니매이션 및 기타 미디어 관련파일
    • /priv-app : signatureOrSystem 권한이 필요한 privileged app. app manifest에서 앱권한을 설정한다.
    • /tts : 텍스트 음성 변환(Text-to-Speech)엔진 관련 파일
    • /usr : 사용자 계정 디렉토리
    • /xbin : tcpdump, strace등 시스템동작에 필요 없지만 빌드된 패키지가 생성한 바이너리
    • /build.prop: 빌드 중 생성된 속성. 부팅시 init이 로드한다.
  • /res : charger 앱의 리소스 파일
  • /vendor : 심볼릭 링크(/ststem/vendor), vendor 독점 바이너리를 포함
  • /init : init 실행파일
  • /init.rc : init 설정파일
  • /ueventd.rc : ueventd 설정파일
  • /default.prop : 기본으로 설정되는 전역속성

init 프로세스

커널이 램디스크를 루트파일시스템으로 마운트를 한 후 램디스크에 포함된 init프로세스를 실행한다.

init프로세스 수행절차

  1. init은 udev의 핫플러그 이벤트 핸들러를 구현하고 있으므로, init이 /sbin/ueventd를 통해 호출이 됐으면 ueventd를 실행한다.
  2. /dev/, /proc, /sys를 생성하고 마운트한다.
  3. /init.rc, /init.기기명.rc를 시스템에 반영한다.
  4. 종료되었거나 재시작이 필요한 서비스를 다시 실행한다.

init.rc

-  전역속성 설정파일
-  문법은 system/core/init/README.md 에서 확인할 수 있다.(번역)
- 실행시 stdout, stderr을 /dev/null로 전달하기 때문에 출력 메시지를 확인하려면 logwrapper를 이용해야 한다.
- /out/../system/defualt.prop에 핵심속성의 기본값을 포함한다. 빌드시 변경하려면 AndroidProducts.mk 에서PRODUCT_PROPERTY_OVERRIDES 를 통해서 변경한다.

ueventd

ueventd는 기본 init.rc가 실행하는 최초의 서비스 중 하나다, 설정파일을 읽어 들여 커널이벤트에 따라 /dev에 노드를 생성한다.
  1. ueventd의 설정파일 문법
/dev/<node>    <mode> <user>    <group>


  1. uevent operation 참조: 쾌도난마, RS

ToolBox

  • init의 전역속성을 제어
    • getprop <key> : 속성 확인
    • setprop <key> <value> : 속성 변경
    • watchprops : 실시간 속성 감시
  • 이벤트 확인 및 전달
    • getevent
    • sendevent /dev/input/event0 1 330 1
  • 서비스 제어
    • start <servicename>
    • stop <servicename> , ex) stop zygote
  • 베이스벤트 프로세서 제어
    • smd


  • ramdisk.img 마운트하기
램디스크 이미지는 압축파일이므로 아래와 같이 압축을 풀면된다. /root 의 내용과 같다.
$ cd /Path/To/Folder/With/ramdisk.cpio.gz/File mkdir temp_directory && cd temp_directory
$ gunzip -c ../ramdisk.img | cpio -idm


기본권한 및 소유권

  • 사용자/그룹 생성 설정
build/tools/fs_config 가 /system/core/include/private/android_filesystem_config.h를 참조하여 설정된다.
  • 디렉토리와 파일권한
    • system/core/libcutils/fs_config.cpp 아래 구조체에 따라 설정된다.
static const struct fs_path_config android_dirs[] = {
   // clang-format off
   { 00770, AID_SYSTEM,       AID_CACHE, 0, "cache" },
   { 00500, AID_ROOT,         AID_ROOT, 0, "config" },
   { 00771, AID_SYSTEM,       AID_SYSTEM, 0, "data/ap
...
static const struct fs_path_config android_files[] = {
   // clang-format off
   { 00644, AID_SYSTEM,    AID_SYSTEM, 0, "data/app/*" },
   { 00644, AID_SYSTEM,    AID_SYSTEM, 0, "data/app-ephemeral/*" },
   { 00644, AID_SYSTEM,    AID_SYSTEM, 0, "data/app-private/*" },
...


모듈 빌드 Android.mk

안드로이드 시스템 각 모듈의 빌드 파일로서  각 모듈을 실행파일 또는 동적 및 정적 라이브러리로 만들 수 있다.


  • Module-Description 변수(LOCAL_XXX)
  • LOCAL_로 시작하는 변수를 통해 동작과 결과물을 조절할 수 있다.
  • 컴파일 결과물 설치위치는 빌드템플릿(BUILD_XXX)따라 정해진다. 설치 위치를 변경하려면 LOCAL_MODULE_PATH를 이용한다.
  • 빌드템플릿과 출력경로
탬플릿
BUILD_EXECUTEABLE
BUILD_JAVA_LIBRARY
BUILD_SHARED_LIBRARY
BUILD_PREBUILT
BUILD_MULTI_PREBUILT
BUILD_PACKAGE
BUILD_KEY_CAHR_MAP
기본출력 경로
/system/bin
/system/framework
/system/lib
LOCAL_MODULE_CLASS/PATH로 설정해야 함
모듈의 유형에 따라 다름
/system/app
/system/usr/keychars


  • 빌드 템플릿(BUILD_XXX)
  • BUILD_STATIC/SHARED_LIBRARY : 빌드타겟용 공유/정적 라이브러리로 빌드한다.
  • BUILD_EXECUTABLE : 빌드타겟용 실행파일로 빌드한다.
  • ...
packages/apps/DeskClock/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_RESOURCE_DIR := packages/apps/DeskClock/res

LOCAL_MODULE_TAGS := optional
LOCAL_SDK_VERSION := current

LOCAL_PACKAGE_NAME := DeskClock
LOCAL_OVERRIDES_PACKAGES := AlarmClock

LOCAL_SRC_FILES := $(call all-java-files-under, src gen)

LOCAL_PROGUARD_FLAG_FILES := ../../../frameworks/support/design/proguard-rules.pro
LOCAL_PROGUARD_FLAG_FILES += ../../../frameworks/support/v7/preference/proguard-rules.pro
LOCAL_PROGUARD_FLAG_FILES += ../../../frameworks/support/v7/recyclerview/proguard-rules.pro
(소스 난독화 툴 프로가드 설정)

LOCAL_STATIC_ANDROID_LIBRARIES := \
       android-support-design \
       android-support-percent \
       android-support-transition \
       android-support-compat \
       android-support-media-compat \
       android-support-v13 \
       android-support-v14-preference \
       android-support-v7-appcompat \
       android-support-v7-gridlayout \
       android-support-v7-preference \
       android-support-v7-recyclerview

LOCAL_USE_AAPT2 := true
(리소스 관리 툴 설정)

include $(BUILD_PACKAGE)


TIPS