- Android核心原理與系統級應用高效開發
- 韓超等
- 3056字
- 2018-12-30 05:22:13
2.3 Android編譯的板級支持
Android的開源代碼默認是支持仿真器的。如果需要使用Android的開源代碼支持一個特定的設備,除了具體的代碼實現之外,還需要對Android的編譯系統做出一些更改。這種編譯的板級支持可以作為附加的方式被添加到Android系統之中。
↘ 2.3.1 支持一個板的工作
從Android開源代碼到一個板(特定設備)的支持,變化的部分就是更改部分代碼和增加板級支持目錄。更改完成后,Android編譯系統按照一定的順序進行處理。
Android對特定板的支持的處理流程如圖2-1所示。

圖2-1 Android編譯的板級支持的處理流程
Android對特定板的編譯支持主要分成以下幾個步驟。
● Make的時候傳入TARGET_PRODUCT宏。
● Android的編譯系統根據TARGET_PRODUCT宏找到目標板的配置目錄。
● 在目標板配置目錄中的板級配置文件得到若干配置宏。
● (系統編譯流程)各個模塊根據配置宏進行編譯。
● 處理目標板中的其他特定配置文件。
Android編譯流程主要涉及以下的一些文件。
● buildspec.mk:根目錄中的文件,指定板名稱。
● vendersetup.sh:專用設置文件。
● BoardConfig.mk:板級全局配置。
● AndroidBoard.mk:當前板的特殊配置。
● AndroidProducts.mk:產品的配置。
buildspec.mk和vendersetup.sh兩個文件執行的是同一種功能,也就是目標產品名稱的定義,二者可以取其一(實際上也可以有其他定義方式)。
在make配置后,系統可以開始進行構建。構建的前面就是找到目標產品的配置目錄,并使用其中的幾個文件:BoardConfig.mk中定義的內容可以被系統的每一個部分使用(傳遞到每一個Android.mk);AndroidBoard.mk和AndroidProducts.mk是配置文件,可以引用默認的內容。板級的編譯支持目錄中也可以具有自己的Android.mk文件,與普通的用法類似。
↘ 2.3.2 buildspec.mk文件的作用
將buildspec.mk增加到源代碼TOP目錄,可以完成配置工作。Android在執行make的時候,將找到TOP目錄中的buildspec.mk,取出其中定義的內容進行配置。buildspec.mk的作用實際上就是為了定義幾個宏,作為Make第一步使用的環境變量。
一個buildspec.mk的寫法如下所示:
ifndef TARGET_PRODUCT #TARGET_PRODUCT:=generic Endif ifndef TARGET_BUILD_VARIANT #TARGET_BUILD_VARIANT:=user #TARGET_BUILD_VARIANT:=userdebug #TARGET_BUILD_VARIANT:=eng endif
其中,最重要的一個宏是TARGET_PRODUCT,表示目標產品的名稱;TARGET_BUILD_VARIANT則表示編譯的類型,分成user(用戶模式)、userdebug(用戶調試模式)、eng(工程模式),這個宏將主要影響系統是否具有root權限等方面。
當編譯不進行定義時,或者TARGET_PRODUCT的數值本身就是“generic”,將使用“generic”板(也就是仿真器)的配置,其路徑為:build/target/product。
● 提示:Android的仿真器默認情況下也是ARM體系結構的目標,仿真器QEMU仿真執行了ARM代碼,因此generic目標和實際的產品差別并不大。
當TARGET_PRODUCT宏被正式定義時,將在自定義板的路徑找到名稱為其值的目錄,作為板級編譯支持目錄。可以使用的板級編譯支持目錄有以下兩個。
● device/*/<TARGET_PRODUCT>
● vendor/*/<TARGET_PRODUCT>
其含義為TOP目錄中的device或者vendor目錄中的某個子目錄中的下一級目錄作為板級編譯支持目錄。也就是說板級編譯支持目錄必須是Android三級子目錄,且必須在device或者vendor目錄中,二級子目錄沒有要求,一般是公司的名稱。
兩個產品的板級編譯支持目錄如下所示。
● device/htc/passion/:Nexus One手機(Google和HTC合作出品)。
● device/samsung/crespo/:Nexus S手機(Google和三星合作出品)。
↘ 2.3.3 vendersetup.sh和lunch命令
vendersetup.sh文件可以提供另外一種編譯配置方法,這也是較新版本的Android系統推薦的方法。其職能實際上也是配置幾個宏,作為Make時的環境變量。
在編譯之前,可以使用envsetup.sh腳本進行編譯的配置,配置的過程中,將會調用每一個板的vendersetup.sh文件,內容如下所示:
$ . build/envsetup.sh including device/htc/passion/vendorsetup.sh including device/samsung/crespo/vendorsetup.sh
此時的配置,實際是一個“遍歷”的過程,將會調用device/*/和vendor/*/目錄中每一個板的vendersetup.sh文件。只要板級支持目錄中有vendersetup.sh文件,就會被調用。調用后實際上將為增加系統可以選擇的目標產品,這個影響將在使用lunch命令進行選擇產品時有所體現,內容如下所示:
$ lunch You're building on Linux Lunch menu... pick a combo: 1. generic-eng 2. simulator 3. full_passion-userdebug 4. full_crespo-userdebug Which would you like? [generic-eng] 1 ============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=2.3.4 TARGET_PRODUCT=generic TARGET_BUILD_VARIANT=eng TARGET_SIMULATOR= TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm HOST_ARCH=x86 HOST_OS=linux HOST_BUILD_TYPE=release BUILD_ID=GRJ22 ============================================
在lunch時出現的菜單項目(combo)中,出現了4個選項,可以使用數字進行選擇。從中可見,除了默認的generic-eng和simulator兩個選擇之外,full_passion-userdebug和full_crespo-userdebug就是來自于自定義板級支持的文件。
device/htc/passion/中的vendersetup.sh文件如下所示:
add_lunch_combo full_passion-userdebug
device/samsung/crespo/中的vendersetup.sh文件如下所示:
add_lunch_combo full_crespo-userdebug
其中full_passion和full_crespo也就是所定義的TARGET_PRODUCT宏的名稱。在lunch時選擇了數字后,實際上得到的結果也是設置TARGET_PRODUCT等宏。
↘ 2.3.4 BoardConfig.mk文件的作用
BoardConfig.mk文件是一個平臺全局配置的文件,這些配置的內容可以在各個工程的Android.mk文件中得到。BoardConfig.mk只是進行配置的定義,其中不能包含實際執行的命令。
例如,BoardConfig.mk文件可以進行定義:
BOARD_USES_GENERIC_AUDIO := false
BOARD_USES_GENERIC_AUDIO等宏的數值就可以在每一個編譯文件(Android.mk)中被讀出。
BoardConfig.mk文件中也可以使用-include包含其他的板級配置宏。
例如,device/samsung/crespo/中的BoardConfig.mk文件包含了如下的片斷:
-include vendor/samsung/crespo/BoardConfigVendor.mk TARGET_CPU_ABI := armeabi-v7a # CPU體系結構的二進制格式 BOARD_HAVE_BLUETOOTH := true # 是否具有藍牙 TARGET_NO_BOOTLOADER := true # 是否具有BootLoader TARGET_NO_KERNEL := false # 是否具有Linux內核
BoardConfig.mk文件中既可以使用TARGET_CPU_ABI等編譯系統使用的宏,也可以定義自己使用的宏。
↘ 2.3.5 AndroidProducts.mk文件
AndroidProducts.mk為當前板的配置文件,其中可以使用一些宏定制最終在目標系統中需要的安裝內容。在實際的板級支持過程中,通常需要在AndroidProducts.mk中包含同類文件,進行大部分默認的定義,然后再對不同配置進行覆蓋(Override)定義。
AndroidProducts.mk需要定義幾個宏,用于表示當前產品的信息: PRODUCT_NAME(產品名稱),PRODUCT_DEVICE(產品設備)。
其中build/target/product/目錄中的AndroidProducts.mk是默認的產品配置文件,內容如下所示。
ifneq ($(TARGET_BUILD_APPS),) PRODUCT_MAKEFILES := \ $(LOCAL_DIR)/core.mk \ $(LOCAL_DIR)/generic.mk else PRODUCT_MAKEFILES := \ $(LOCAL_DIR)/core.mk \ $(LOCAL_DIR)/generic.mk \ $(LOCAL_DIR)/generic_x86.mk \ $(LOCAL_DIR)/full.mk \ $(LOCAL_DIR)/sdk.mk \ $(LOCAL_DIR)/sim.mk endif
其中指定的PRODUCT_MAKEFILES實際上就是被其包含的文件。full.mk也在build/target/product/目錄中,其中具有如下內容。
PRODUCT_NAME := full PRODUCT_BRAND := generic PRODUCT_DEVICE := generic PRODUCT_MODEL := Full Android
這里的PRODUCT_NAME等宏的定義也就是產品名稱等信息,這里進行了定義后,在系統中通過部分的函數可以讀取這些信息,并可以提供給程序和用戶。
其中另一個功能是定義系統預安裝的包。例子如下所示:
PRODUCT_PACKAGES := \ OpenWnn \ PinyinIME \ VoiceDialer \ libWnnEngDic \ libWnnJpnDic \ libwnndict
在包被增加到PRODUCT_PACKAGES宏之后,這個包將會被預裝到系統中,作為系統映像的一部分。
系統預裝文件使用PRODUCT_COPY_FILES宏來定義。例子如下所示:
PRODUCT_COPY_FILES := \ development/data/etc/apns-conf.xml:system/etc/apns-conf.xml \ development/data/etc/vold.conf:system/etc/vold.conf
在PRODUCT_COPY_FILES的各項內容中,“:”前面的為源文件,“:”后面的為目標機的文件(為out/target/product/<產品名稱>目錄加上后面的路徑),編譯時將源文件復制為目標文件。如果目標文件的目錄沒有,也會進行自動創建。因此,這是另外一種像目標系統中預裝文件的方法。
另外一個可以定義的內容是系統語言區域的定義,在build/target/product/目錄中的languages_<XXX>.mk文件中進行定義,類似具有如下的內容:
PRODUCT_LOCALES := en_US en_GB fr_FR it_IT de_DE es_ES
這里使用的是ISO 639-1定義的語言碼和ISO 3166-1-alpha-2定義的區域碼。
例如,device/samsung/crespo/中的AndroidProducts.mk文件包含了同目錄的full_crespo.mk文件,full_crespo.mk的主要內容如下所示:
$(call inherit-product, $(SRC_TARGET_DIR)/product/languages_full.mk) $(call inherit-product, device/samsung/crespo/device.mk) $(call inherit-product, $(SRC_TARGET_DIR)/product/full.mk) PRODUCT_NAME := full_crespo PRODUCT_DEVICE := crespo PRODUCT_MODEL := Full Android on Crespo
此時除了PRODUCT_NAME等宏的定義之外,也可以包含其他的同類文件,包含的languages_full.mk和full.mk就是系統默認的文件,在這里被復用,而device.mk是當前目錄中的另外一個文件。
↘ 2.3.6 AndroidBoard.mk文件
AndroidBoard.mk用于板級一些編譯內容的定義,這個文件通常是可選的。AndroidBoard.mk的功能和語法類似一般的Android.mk文件。
例如,build/target/board/generic/中的AndroidBoard.mk文件如下所示:
LOCAL_PATH := $(call my-dir) file := $(TARGET_OUT_KEYLAYOUT)/tuttle2.kl ALL_PREBUILT += $(file) $(file) : $(LOCAL_PATH)/tuttle2.kl | $(ACP) $(transform-prebuilt-to-target) include $(CLEAR_VARS) LOCAL_SRC_FILES := tuttle2.kcm include $(BUILD_KEY_CHAR_MAP)
這里進行了兩個工作:一個是將按鍵布局的文件tuttle2.kl復制到目標系統中,一個是調用BUILD_KEY_CHAR_MAP模板對按鍵字符映像的tuttle2.kcm文件進行編譯處理。由于每一個Android板的輸入設備通常都不同,因此在一個特定設備的構建過程中,按鍵相關的定制處理也是經常需要進行的工作。
AndroidBoard.mk不是必需的,例如,在crespo的配置目錄device/samsung/crespo/中,就沒有AndroidBoard.mk文件,而具有Android.mk文件。
↘ 2.3.7 編譯中的層疊加
在一個Android的板級構建過程中,有一種不更改源代碼文件,而實現構建出不同內容的方法,這就是通過編譯中層疊加(overlay)的機制來實現的。使用這種方式可以基于同樣的源代碼,為了不同的硬件或不同產品構建出不同的系統。
在板級配置目錄中,可以有一個名稱為overlay的子目錄,這個目錄表示的就是一個代碼疊加層。這個overlay目錄對應于Android源代碼的TOP目錄,在編譯的過程中將使用overlay目錄中的內容替換TOP目錄中的內容。
例如,在Nexus S(crespo)的板級配置的目錄device/samsung/crespo/overlay/下面的一個目錄結構如下所示:
device/samsung/crespo/overlay/frameworks/base/core/ `-- res `-- res |-- drawable-hdpi | `-- default_wallpaper.jpg |-- values | `-- config.xml `-- xml `-- power_profile.xml
此時,將把TOP目錄中的frameworks/base/core/res/res/drawable-hdpi中的default_wallpaper.jpg替換成overlay對應目錄的同名文件。這個文件實際上是系統默認的墻紙,由此,進行完如此的定義后,相當于crespo編譯的系統將替換默認的墻紙。
Android系統中很多模塊比較適合使用這種替換方式,例如應用程序包中的資源文件等。尤其值得注意的是,一旦使用overlay進行層替換,原有的源文件將不再起作用。