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
   

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) |