본문 바로가기

개발 개발/Android

Android build system - makefile 기본 빌드 과정

Product설정파일을 통해 환경변수를 설정하여 선택적으로 빌드가능

 PRODUCT_NAME : 제품명

 PRODUCT_DEVICE : 디바이스명

 PRODUCT_LOCALE : 지역정보

 PRODUCT_PACKAGE_OVERLAY : 대체될 resource가 있는 Path

 PRODUCT_PROPERTY_OVERRIDES : 추가될 system property 항목이며 /system/build.prop에 저장됨.

 PRODUCT_PACKAGES : 기본적으로 설치될 app 목록

전체 과정을 간략히 설명하면, TARGET_BUILD_VARIANT에 따라서 System Property와 설치될 모듈을 결정합니다. 그 과정을 Makefile을 따라가면서 확인해 보겠습니다.

   

시작은 open_src폴더 아래 Makefile에서 build/core/main.mk로 이동합니다.

/Makefile

   

아래 build/core/main.mk를 보면 환경변수 TARGET_BUILD_VARIANT에 따라서 System Property를 다르게 설정하고 있습니다.

Part 1 : /build/core/main.mk

   

   

   

TARGET_BUILD_VARIANT 에 따른 동작은 아래와 같습니다. Android.mk의 정의된 LOCAL_MODULE_TAGS를 정의하지 않은 모듈은 기본이 user 태그입니다. 따라서 이전에 eng로 설정되어 있는 모듈들이 설치되지 않은 이유는 명시적으로 eng태그를 설정해 주었기 때문입니다.

TARGET_BUILD_VARIANT

Actions

eng

- Installs modules tagged with: eng, debug, user, and/or development.

- Installs non-APK modules that have no tags specified.

- Installs APKs according to the product definition files, in addition to tagged APKs.

- ro.secure=0

- ro.debuggable=1

- ro.kernel.android.checkjni=1

- adb is enabled by default.

user

- Installs modules tagged with user.

- Installs non-APK modules that have no tags specified.

- Installs APKs according to the product definition files; tags are ignored for APK modules.

- ro.secure=1

- ro.debuggable=0

- adb is disabled by default.

userdebug

The same as user, except:

- Also installs modules tagged with debug.

- ro.debuggable=1

- adb is enabled by default.

   

   

빌 드시 build/tools/findleaves.sh를 사용해서 각 폴더의 첫번째 Android.mk파일을 모두 찾아서 Makefile에 추가합니다. 하위 폴더에 Android.mk파일이 존재하더라도 상위 폴더에 Android.mk가 존재하면 상위 폴더에 있는 Android.mk까지만 찾습니다.

그리고 현재 Product설정파일의 TARGET_DEVICE의 BoardConfig.mk를 포함시킵니다.

   

Part 2 : /build/core/main.mk

   

   

build/tools/findleaves.sh 동작 예제

$find hardware –name "*.mk"

hardware/libhardware/Android.mk

hardware/libhardware/modules/overlay/Android.mk

hardware/libhardware_legacy/Android.mk

hardware/libhardware_legacy/flashlight/Android.mk

hardware/libhardware_legacy/gps/Android.mk

hardware/libhardware_legacy/led/Android.mk

hardware/libhardware_legacy/mount/Android.mk

hardware/libhardware_legacy/power/Android.mk

hardware/libhardware_legacy/qemu/Android.mk

hardware/libhardware_legacy/qemu_tracing/Android.mk

hardware/libhardware_legacy/tests/gpstest/Android.mk

hardware/libhardware_legacy/uevent/Android.mk

hardware/libhardware_legacy/vibrator/Android.mk

hardware/libhardware_legacy/wifi/Android.mk

hardware/ril/libril/Android.mk

hardware/ril/rild/Android.mk

hardware/ril/gpstest/Android.mk

hardware/ril/libsecril-client/Android.mk

hardware/ril/rilclient-test/Android.mk

hardware/ril/secril_multi/Android.mk

hardware/modules/sensors/Android.mk

hardware/msm7k/Android.mk

hardware/msm7k/libaudio/Android.mk

hardware/msm7k/libcamera/Android.mk

hardware/msm7k/libcopybit/Android.mk

hardware/msm7k/librpc/Android.mk

hardware/msm7k/yuv420sp2rgb/Android.mk

   

$ ./build/tools/findleaves.sh hardware Android.mk

hardware/libhardware/Android.mk => 폴더구조의 첫번째 Android.mk만 포함됨

hardware/libhardware_legacy/Android.mk

hardware/modules/sensors/Android.mk

hardware/msm7k/Android.mk

hardware/ril/gpstest/Android.mk

hardware/ril/libril/Android.mk

hardware/ril/libsecril-client/Android.mk

hardware/ril/rilclient-test/Android.mk

hardware/ril/rild/Android.mk

hardware/ril/secril_multi/Android.mk

   

   

   

hardware/msm7k/Android.mk 파일에서 아래와 같이 하위의 Android.mk파일을 상황에 따라서 include를 하여 필요한 모듈만 컴파일하여 추가시킬 때 사용할 수 있습니다. (이것을 사용해서 Samsung의 Open Source쪽 변경 소스 관리를 할 수 있을 것으로 보입니다. )

ifneq ($(filter capella7200, surf, $(TARGET_DEVICE)), )

include $(all-subdir-makefiles)

endif

   

   

설치될 모듈들을 선택하고, LOCAL_OVERRIDES_PACKAGES로 선택된 Package를 항목에서 삭제합니다.

Part 3 : build/core/main.mk

   

   

추가로Android의 모든 Application은 고유한 Key를 사용해서 Signning을 수행해야 합니다. 어떤 Key로 Signning을 할지를 결정은 LOCAL_CERTIFICATE에 기술합니다.

packages/apps/Camera/Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

   

LOCAL_MODULE_TAGS := user

   

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

   

LOCAL_PACKAGE_NAME := Camera

LOCAL_CERTIFICATE := media

#LOCAL_CERTIFICATE := vendor/samsung/products/security/media => 명시적으로 선택가능

   

LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client

   

#include $(BUILD_PACKAGE)

   

# Use the following include to make our test apk.

#include $(call all-makefiles-under,$(LOCAL_PATH))

   

package.mk 파일을 보시면 LOCAL_CERTIFICATE가 설정되지 않으면 testkey가 사용되며, 관련 private와 certificate는 /build/target/product/security/폴더에 있는 key값을 사용합니다.

mkkey.sh => key값을 생성하기 위한 명령어, Samsung Android폰 개발시 고유한 key를 생성해서 출시해야함.

media.pk8

media.x509.pem

platform.pk8

platform.x509.pem

shared.pk8

shared.x509.pem

testkey.pk8

testkey.x509.pem

   

/build/core/package.mk

   





출처 : http://samse.tistory.com/121

Product설정파일을 통해 환경변수를 설정하여 선택적으로 빌드가능
 PRODUCT_NAME : 제품명
 PRODUCT_DEVICE : 디바이스명
 PRODUCT_LOCALE : 지역정보
 PRODUCT_PACKAGE_OVERLAY : 대체될 resource가 있는 Path
 PRODUCT_PROPERTY_OVERRIDES : 추가될 system property 항목이며 /system/build.prop에 저장됨.
 PRODUCT_PACKAGES : 기본적으로 설치될 app 목록

전체 과정을 간략히 설명하면, TARGET_BUILD_VARIANT에 따라서 System Property와 설치될 모듈을 결정합니다그 과정을Makefile을 따라가면서 확인해 보겠습니다.

 

시작은 open_src폴더 아래 Makefile에서 build/core/main.mk로 이동합니다.

/Makefile

### DO NOT EDIT THIS FILE ###

include build/core/main.mk

### DO NOT EDIT THIS FILE ###

 

아래 build/core/main.mk를 보면 환경변수 TARGET_BUILD_VARIANT에 따라서 System Property를 다르게 설정하고 있습니다.

Part 1 : /build/core/main.mk

## user/userdebug ##

 

user_variant := $(filter userdebug user,$(TARGET_BUILD_VARIANT))

enable_target_debugging := true

ifneq (,$(user_variant))

  # Target is secure in user builds.

  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=1

 

  tags_to_install := user

  ifeq ($(user_variant),userdebug)

    # Pick up some extra useful tools

    tags_to_install += debug

  else

    # Disable debugging in plain user builds.

    enable_target_debugging :=

  endif

 

  # TODO: Always set WITH_DEXPREOPT (for user builds) once it works on OSX.

  # Also, remove the corresponding block in config/product_config.make.

  ifeq ($(HOST_OS)-$(WITH_DEXPREOPT_buildbot),linux-true)

    WITH_DEXPREOPT := true

  endif

 

  # Disallow mock locations by default for user builds

  ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=0

 

else # !user_variant

  # Turn on checkjni for non-user builds.

  ADDITIONAL_BUILD_PROPERTIES += ro.kernel.android.checkjni=1

  # Set device insecure for non-user builds.

  ADDITIONAL_DEFAULT_PROPERTIES += ro.secure=0

  # Allow mock locations by default for non user builds

  ADDITIONAL_DEFAULT_PROPERTIES += ro.allow.mock.location=1

endif # !user_variant

 

ifeq (true,$(strip $(enable_target_debugging)))

  # Target is more debuggable and adbd is on by default

  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=1 persist.service.adb.enable=1

  # Include the debugging/testing OTA keys in this build.

  INCLUDE_TEST_OTA_KEYS := true

else # !enable_target_debugging

  # Target is less debuggable and adbd is off by default

  ADDITIONAL_DEFAULT_PROPERTIES += ro.debuggable=0 persist.service.adb.enable=0

endif # !enable_target_debugging

 

## eng ##

 

ifeq ($(TARGET_BUILD_VARIANT),eng)

tags_to_install := user debug eng

# Don't require the setup wizard on eng builds

#eng모드에서 ro.setupwizard.mode property를 뺍니다.

  ADDITIONAL_BUILD_PROPERTIES := $(filter-out ro.setupwizard.mode=%,\

          $(call collapse-pairs, $(ADDITIONAL_BUILD_PROPERTIES)))

endif

 

 

TARGET_BUILD_VARIANT에 따른 동작은 아래와 같습니다.  Android.mk의 정의된 LOCAL_MODULE_TAGS를 정의하지 않은 모듈은 기본이 user 태그입니다따라서 이전에 eng로 설정되어 있는 모듈들이 설치되지 않은 이유는 명시적으로 eng태그를 설정해 주었기 때문입니다.

TARGET_BUILD_VARIANT

Actions

eng

- Installs modules tagged with: eng, debug, user, and/or development.

- Installs non-APK modules that have no tags specified.

- Installs APKs according to the product definition files, in addition to tagged APKs.

- ro.secure=0

- ro.debuggable=1

- ro.kernel.android.checkjni=1

- adb is enabled by default.

user

- Installs modules tagged with user.

- Installs non-APK modules that have no tags specified.

- Installs APKs according to the product definition files; tags are ignored for APK modules.

- ro.secure=1

- ro.debuggable=0

- adb is disabled by default.

userdebug

The same as user, except:

- Also installs modules tagged with debug.

- ro.debuggable=1

- adb is enabled by default.

 

 

빌드시 build/tools/findleaves.sh를 사용해서 각 폴더의 첫번째 Android.mk파일을 모두 찾아서 Makefile에 추가합니다하위 폴더에 Android.mk파일이 존재하더라도 상위 폴더에 Android.mk가 존재하면 상위 폴더에 있는 Android.mk까지만 찾습니다.

그리고 현재 Product설정파일의 TARGET_DEVICE BoardConfig.mk를 포함시킵니다.

 

Part 2 : /build/core/main.mk

# Can't use first-makefiles-under here because

# --mindepth=2 makes the prunes not work.

subdir_makefiles += \

    $(shell build/tools/findleaves.sh --prune="./out" $(subdirs) Android.mk)

 

# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)

# or under vendor/*/$(TARGET_DEVICE).  Search in both places, but

# make sure only one exists.

# Real boards should always be associated with an OEM vendor.

board_config_mk := \

    $(strip $(wildcard \

        $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \

        vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \

    ))

ifeq ($(board_config_mk),)

  $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))

endif

ifneq ($(words $(board_config_mk)),1)

  $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))

endif

include $(board_config_mk)

TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))

board_config_mk :=

 

# Clean up/verify variables defined by the board config file.

TARGET_BOOTLOADER_BOARD_NAME := $(strip $(TARGET_BOOTLOADER_BOARD_NAME))

 

#

# Include all of the makefiles in the system

#

 

ifneq ($(ONE_SHOT_MAKEFILE),)

# We've probably been invoked by the "mm" shell function

# with a subdirectory's makefile.

include $(ONE_SHOT_MAKEFILE)

# Change CUSTOM_MODULES to include only modules that were

# defined by this makefile; this will install all of those

# modules as a side-effect.  Do this after including ONE_SHOT_MAKEFILE

# so that the modules will be installed in the same place they

# would have been with a normal make.

CUSTOM_MODULES := $(sort $(call get-tagged-modules,$(ALL_MODULE_TAGS),))

FULL_BUILD :=

INTERNAL_DEFAULT_DOCS_TARGETS :=

# Stub out the notice targets, which probably aren't defined

# when using ONE_SHOT_MAKEFILE.

NOTICE-HOST-%: ;

NOTICE-TARGET-%: ;

else

include $(subdir_makefiles)

endif

# -------------------------------------------------------------------

# All module makefiles have been included at this point.

# -------------------------------------------------------------------

 

build/tools/findleaves.sh 동작 예제

$find hardware –name “*.mk”

hardware/libhardware/Android.mk

hardware/libhardware/modules/overlay/Android.mk

hardware/libhardware_legacy/Android.mk

hardware/libhardware_legacy/flashlight/Android.mk

hardware/libhardware_legacy/gps/Android.mk

hardware/libhardware_legacy/led/Android.mk

hardware/libhardware_legacy/mount/Android.mk

hardware/libhardware_legacy/power/Android.mk

hardware/libhardware_legacy/qemu/Android.mk

hardware/libhardware_legacy/qemu_tracing/Android.mk

hardware/libhardware_legacy/tests/gpstest/Android.mk

hardware/libhardware_legacy/uevent/Android.mk

hardware/libhardware_legacy/vibrator/Android.mk

hardware/libhardware_legacy/wifi/Android.mk

hardware/ril/libril/Android.mk

hardware/ril/rild/Android.mk

hardware/ril/gpstest/Android.mk

hardware/ril/libsecril-client/Android.mk

hardware/ril/rilclient-test/Android.mk

hardware/ril/secril_multi/Android.mk

hardware/modules/sensors/Android.mk

hardware/msm7k/Android.mk

hardware/msm7k/libaudio/Android.mk

hardware/msm7k/libcamera/Android.mk

hardware/msm7k/libcopybit/Android.mk

hardware/msm7k/librpc/Android.mk

hardware/msm7k/yuv420sp2rgb/Android.mk

 

$ ./build/tools/findleaves.sh hardware Android.mk

hardware/libhardware/Android.mk => 폴더구조의 첫번째 Android.mk만 포함됨

hardware/libhardware_legacy/Android.mk

hardware/modules/sensors/Android.mk

hardware/msm7k/Android.mk

hardware/ril/gpstest/Android.mk

hardware/ril/libril/Android.mk

hardware/ril/libsecril-client/Android.mk

hardware/ril/rilclient-test/Android.mk

hardware/ril/rild/Android.mk

hardware/ril/secril_multi/Android.mk

 

hardware/msm7k/Android.mk 파일에서 아래와 같이 하위의 Android.mk파일을 상황에 따라서 include를 하여 필요한 모듈만 컴파일하여 추가시킬 때 사용할 수 있습니다(이것을 사용해서 Samsung Open Source쪽 변경 소스 관리를 할 수 있을 것으로 보입니다. )

ifneq ($(filter capella7200, surf, $(TARGET_DEVICE)), )

  include $(all-subdir-makefiles)

endif

 

설치될 모듈들을 선택하고, LOCAL_OVERRIDES_PACKAGES로 선택된 Package를 항목에서 삭제합니다.

Part 3 : build/core/main.mk

# -------------------------------------------------------------------

# Figure out our module sets.

 

# Of the modules defined by the component makefiles,

# determine what we actually want to build.

# If a module has the "restricted" tag on it, it

# poisons the rest of the tags and shouldn't appear

# on any list.

Default_MODULES := $(sort $(ALL_DEFAULT_INSTALLED_MODULES) \

                          $(ALL_BUILT_MODULES) \

                          $(CUSTOM_MODULES))

# TODO: Remove the 3 places in the tree that use

# ALL_DEFAULT_INSTALLED_MODULES and get rid of it from this list.

 

ifdef FULL_BUILD

  # The base list of modules to build for this product is specified

  # by the appropriate product definition file, which was included

  # by product_config.make.

  user_PACKAGES := $(call module-installed-files, \

                       $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_PACKAGES))

  ifeq (0,1)

    $(info user packages for $(TARGET_DEVICE) ($(INTERNAL_PRODUCT)):)

    $(foreach p,$(user_PACKAGES),$(info :   $(p)))

    $(error done)

  endif

else

  # We're not doing a full build, and are probably only including

  # a subset of the module makefiles.  Don't try to build any modules

  # requested by the product, because we probably won't have rules

  # to build them.

  user_PACKAGES :=

endif

# Use tags to get the non-APPS user modules.  Use the product

# definition files to get the APPS user modules.

user_MODULES := $(sort $(call get-tagged-modules,user,_class@APPS restricted))

user_MODULES := $(user_MODULES) $(user_PACKAGES)

 

eng_MODULES := $(sort $(call get-tagged-modules,eng,restricted))

debug_MODULES := $(sort $(call get-tagged-modules,debug,restricted))

tests_MODULES := $(sort $(call get-tagged-modules,tests,restricted))

 

ifeq ($(strip $(tags_to_install)),)

$(error ASSERTION FAILED: tags_to_install should not be empty)

endif

modules_to_install := $(sort $(Default_MODULES) \

          $(foreach tag,$(tags_to_install),$($(tag)_MODULES)))

 

# Some packages may override others using LOCAL_OVERRIDES_PACKAGES.

# Filter out (do not install) any overridden packages.

overridden_packages := $(call get-package-overrides,$(modules_to_install))

ifdef overridden_packages

#  old_modules_to_install := $(modules_to_install)

  modules_to_install := \

      $(filter-out $(foreach p,$(overridden_packages),$(p) %/$(p).apk), \

          $(modules_to_install))

endif

 

추가로Android의 모든 Application은 고유한 Key를 사용해서 Signning을 수행해야 합니다어떤 Key Signning을 할지를 결정은 LOCAL_CERTIFICATE에 기술합니다.

packages/apps/Camera/Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

 

LOCAL_MODULE_TAGS := user

 

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

 

LOCAL_PACKAGE_NAME := Camera

LOCAL_CERTIFICATE := media

#LOCAL_CERTIFICATE := vendor/samsung/products/security/media   => 명시적으로 선택가능

 

LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client

 

#include $(BUILD_PACKAGE)

 

# Use the following include to make our test apk.

#include $(call all-makefiles-under,$(LOCAL_PATH))

 

package.mk파일을 보시면 LOCAL_CERTIFICATE가 설정되지 않으면 testkey가 사용되며관련 private certificate /build/target/product/security/폴더에 있는 key값을 사용합니다.

mkkey.sh   => key값을 생성하기 위한 명령어, Samsung Android폰 개발시 고유한 key를 생성해서 출시해야함.

media.pk8

media.x509.pem

platform.pk8

platform.x509.pem

shared.pk8

shared.x509.pem

testkey.pk8

testkey.x509.pem

 

/build/core/package.mk

# Pick a key to sign the package with.  If this package hasn't specified

# an explicit certificate, use the default.

# Secure release builds will have their packages signed after the fact,

# so it's ok for these private keys to be in the clear.

ifeq ($(LOCAL_CERTIFICATE),)

    LOCAL_CERTIFICATE := testkey

endif

# If this is not an absolute certificate, assign it to a generic one.

ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./)

    LOCAL_CERTIFICATE := $(SRC_TARGET_DIR)/product/security/$(LOCAL_CERTIFICATE)

endif

private_key := $(LOCAL_CERTIFICATE).pk8

certificate := $(LOCAL_CERTIFICATE).x509.pem

 

$(LOCAL_BUILT_MODULE): $(private_key) $(certificate) $(SIGNAPK_JAR)

$(LOCAL_BUILT_MODULE): PRIVATE_PRIVATE_KEY := $(private_key)

$(LOCAL_BUILT_MODULE): PRIVATE_CERTIFICATE := $(certificate)

 

PACKAGES.$(LOCAL_PACKAGE_NAME).PRIVATE_KEY := $(private_key)

PACKAGES.$(LOCAL_PACKAGE_NAME).CERTIFICATE := $(certificate)

 

# Define the rule to build the actual package.

$(LOCAL_BUILT_MODULE): $(AAPT) | $(ZIPALIGN)

$(LOCAL_BUILT_MODULE): PRIVATE_JNI_SHARED_LIBRARIES := $(jni_shared_libraries)

$(LOCAL_BUILT_MODULE): $(all_res_assets) $(jni_shared_libraries) $(full_android_manifest)

    @echo "target Package: $(PRIVATE_MODULE) ($@)"

    $(create-empty-package)

    $(add-assets-to-package)

ifneq ($(jni_shared_libraries),)

    $(add-jni-shared-libs-to-package)

endif

ifneq ($(full_classes_jar),)

    $(add-dex-to-package)

endif

    $(sign-package)

    @# Alignment must happen after all other zip operations.

    $(align-package)

 

# Save information about this package

PACKAGES.$(LOCAL_PACKAGE_NAME).OVERRIDES := $(strip $(LOCAL_OVERRIDES_PACKAGES))

PACKAGES.$(LOCAL_PACKAGE_NAME).RESOURCE_FILES := $(all_resources)

 

PACKAGES := $(PACKAGES) $(LOCAL_PACKAGE_NAME)