本文轉載自:java
一般產品廠商在拿到Android源碼後會在android源碼基礎上進行定製修改,以匹配適應本身的產品,從本節開始,咱們從最原始的Android源碼系統裏一步一步定製出本身的Android系統。本節主要內容包含:根據Android源碼,添加新產品編譯項,定製系統啓動界面和文字,定製系統啓動動畫和聲音,定製系統桌面。linux
Android系統的源代碼是一個邏輯結構很是獨立工程,在一套Android源碼中能夠編譯出多個產品映像,在須要編譯某一個產品系統時,只要經過lunch命令選擇產品編譯項便可。本節咱們介紹如何在Android源碼中建立新產品編譯項並定製編譯出該產品系統。android
在建立新產品編譯項時,要先了解下面幾個概念:vim
Ø 目標產品:具體指某個最終用戶買到的Android設備,如:iPhone5,樂PhoneS2,小米手機等。架構
Ø 產品系列:開發手機的團隊一般由同一團隊打造,在研發出一款產品後,每每要繼續在其基礎上研發出新產品,新產品每每是在老產品的硬件或軟件基礎上作一些升級,這些產品們就是一個產品系列。好比:聯想的樂Phone系列手機包含:樂PhoneS1和樂PhoneS2,他們同屬於一個系列。框架
Ø 目標設備:目標設備能夠理解爲手機主板,它是指手機設備硬件配置信息的集合體,每一個手機產品都有設備硬件配置,一個設備硬件配置可能被不一樣產品使用,同一手機有高配置版本和低配置版本,如樂PhoneS2有512M RAM、8G Flash容量版本和1G RAM 、16G Flash容量版本。ide
在Android編譯系統中,每一個編譯項編譯出一個產品系統,每一個目標產品都對應一個目標設備,一個產品系列包含多個不一樣的產品,一個目標設備可能被多個產品配置使用。函數
由前面描述可知,同一系列的新老產品之間能夠存在「繼承關係」,新產品是老產品的「子產品」,老產品是新產品的「父產品」,子產品能夠複用父產品的特性,還能夠重寫、擴展父產品。如:老產品不支持NFC近距離通訊技術,新產品支持NFC技術。一樣,設備主板間也存在「繼承關係」。佈局
圖x-x 產品、設備與編譯項關係圖動畫
如圖x-x所示,某一產品系列包含3個產品,2個目標設備,其中產品2繼承了產品1,產品2 使用了設備2,它是基於產品1所使用的設備1的升級。產品3使用了和產品2同樣的設備2,他們硬件配置同樣,可是卻不是同一產品,3個不一樣產品都對應一個產品編譯項。
在Android編譯系統中,產品編譯項相關配置文件都在device/<廠商名>/目錄下。廠商的產品列表由AndroidProducts.mk文件定義,目標產品信息由<產品名>.mk定義,目標設備信息由BoardConfig.mk和AndroidBoard.mk定義。建立新產品的編譯項就是建立上述幾個mk文件的過程。
1. 建立廠商目錄
不一樣的手機廠商對應device/下不一樣目錄,在廠商目錄下放置該廠商的產品相關信息,咱們廠商名定義爲mycompany。
$ cd ~/android/android_source
$ mkdir device/mycompany
2. 在廠商目錄下建立設備目錄
定義設備名爲myphone。
$ mkdir device/mycompany/myphone
3. 添加新產品編譯項配置文件,該配置文件在執行source build/envsetup.sh時,被加載執行
$ vim device/mycompany/myphone/vendorsetup.sh
在vendorsetup.sh文件時添加下面一條命令,用於向編譯系統添加編譯項,新添加的產品名爲:myproduct,編譯類型爲eng。
add_lunch_combo myproduct-eng
注:add_lunch_combo命令是build/envsetup.sh腳本中定義的函數,表示將一個新產品編譯項添加到lunch菜單裏。
4. 建立產品列表配置文件AndroidProducts.mk
AndroidProducts.mk文件用於定義當前廠商所擁有的全部產品列表,每一個產品都對應一個配置文件:
$ vimdevice/mycompany/myphone/AndroidProducts.mk
在產品列表配置文件中添加以下內容:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/full_product.mk
注:PRODUCT_MAKEFILES變量用於保存全部產品配置信息列表,$(LOCAL_DIR)表示當前目錄,full_product.mk表示某一款產品的配置文件。
5. 配置full_product.mk文件,定義產品的配置信息,添加以下內容:
include build/target/product/languages_full.mk
include build/target/product/full.mk
# Discard inherited values and use our owninstead.
PRODUCT_NAME := myproduct
PRODUCT_DEVICE := myphone
產品配置也能夠和Java中的類同樣被繼承,經過inclulde命令能夠將指定的文件包含進來,而後在後面能夠對裏面的內容進行重寫。通常而言不一樣的產品產品名和設備名都不同,在full_product.mk中對繼承的full.mk中的產品名和設備名進行重寫:PRODUCT_NAME爲myproduct,PRODUCT_DEVICE爲myphone。
在full_product.mk文件中繼承的languages_full.mk內容以下:
@build/target/product/languages_full.mk
PRODUCT_LOCALES := en_US fr_FR it_IT es_ES de_DEnl_NL cs_CZ pl_PL ja_JP zh_TW zh_CN ru_RU ko_KR nb_NO es_US da_DK el_GR tr_TRpt_PT pt_BR rm_CH sv_SE bg_BG ca_ES en_GB fi_FI hr_HR hu_HU in_ID iw_IL lt_LTlv_LV ro_RO sk_SK sl_SI sr_RS uk_UA vi_VN tl_PH
該配置文件裏表示的是當前產品系統裏默認支持的本地語言,由上述配置信息可知,它基本包含了Android所支持的全部語言包。
@build/target/product/full.mk
PRODUCT_PACKAGES := \
OpenWnn \
PinyinIME \
VoiceDialer\
libWnnEngDic \
libWnnJpnDic \
libwnndict
# Additional settings used in all AOSP builds
PRODUCT_PROPERTY_OVERRIDES := \
keyguard.no_require_sim=true \
ro.com.android.dateformat=MM-dd-yyyy \
ro.com.android.dataroaming=true \
ro.ril.hsxpa=1 \
ro.ril.gprsclass=10
PRODUCT_COPY_FILES := \
development/data/etc/apns-conf.xml:system/etc/apns-conf.xml \
development/data/etc/vold.conf:system/etc/vold.conf
# Pick up some sounds - stick with the shortlist to save space
# on smaller devices.
$(call inherit-product,frameworks/base/data/sounds/OriginalAudio.mk)
# Get the TTS language packs
$(call inherit-product-if-exists,external/svox/pico/lang/all_pico_languages.mk)
# Get a list of languages. We use the small listto save space
# on smaller devices.
$(call inherit-product,build/target/product/languages_small.mk)
$(call inherit-product,build/target/product/generic.mk)
# Overrides
PRODUCT_NAME := full
PRODUCT_BRAND := generic
PRODUCT_DEVICE := generic
PRODUCT_MODEL := Full Android
繼承的full.mk文件內容比較多,咱們將主要的一些變量列出如表x-x所示。
變量名 |
做用 |
使用方式 |
PRODUCT_PACKAGES |
系統預置的模塊列表,不只僅只是Android應用程序,還能夠包含庫,可執行程序等 |
直接將系統中要安裝的模塊名以空格隔開列出 |
PRODUCT_PROPERTY_OVERRIDES |
系統設置的屬性值 |
將全部預設的屬性以空格隔開列出,屬性格式爲:key-value |
PRODUCT_COPY_FILES |
要拷貝的文件 |
將文件列表拷貝到文件系統中,文件格式爲:源文件:目標文件 |
PRODUCT_NAME |
產品名 |
該產品名要和編譯項中產品名一致 |
PRODUCT_BRAND |
產品品牌 |
|
PRODUCT_DEVICE |
產品對應的設備名 |
該名字要和產品設備主板配置文件(BoardConfig.mk)所在目錄名一致 |
PRODUCT_MODEL |
|
|
總結:咱們本身定義的full_product產品繼承了build/target/product/目錄下的full.mk和languages_full.mk,full.mk文件是Android系統定義的一個「通用產品」,languages_full.mk文件是所有語言包配置文件,這樣,本身的產品full_product就具備了通用產品的特色而且支持所有語言包。
6. 定義目標產品對應的設備配置文件AndroidBoard.mk和BoardConfig.mk
一樣的道理,咱們能夠繼承使用通用設備配置文件:build/target/board/generic/目錄下的AndroidBoard.mk和BoardConfig.mk文件。
Ø 建立AndroidBoard.mk和BoardConfig.mk文件
$ touch AndroidBoard.mk BoardConfig.mk
Ø 添加AndoridBoard.mk的內容以下:
@ device/mycompany/myphone/AndroidBoard.mk
include build/target/board/generic/AndroidBoard.mk
「繼承」的父AndroidBoard.mk,其內容:
@build/target/board/generic/AndroidBoard.mk
LOCAL_PATH := $(call my-dir)
file := $(TARGET_OUT_KEYLAYOUT)/tuttle2.kl # Linux內核按鍵碼佈局文件
ALL_PREBUILT += $(file)
$(file) : $(LOCAL_PATH)/tuttle2.kl | $(ACP)
$(transform-prebuilt-to-target)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := tuttle2.kcm # Android按鍵碼映射文件
include $(BUILD_KEY_CHAR_MAP)
其實build/target/board/generic/AndroidBoard.mk文件裏只是拷貝了按鍵映射文件和默認系統屬性文件,咱們能夠將其內容直接拷貝到device/mycompany/myphone/AndroidBoard.mk中。
Ø 添加BoardConfig.mk的內容以下:
@ device/mycompany/myphone/BoardConfig.mk
includebuild/target/board/generic/BoardConfig.mk
「繼承」的父BoardConfig.mk內容:
@build/target/board/generic/BoardConfig.mk
# config.mk
#
# Product-specific compile-time definitions.
#
# The generic product target doesn't have anyhardware-specific pieces.
TARGET_NO_BOOTLOADER := true # 當前設備是否沒有Bootloader
TARGET_NO_KERNEL := true # 當前設備是否沒有linux內核
TARGET_CPU_ABI := armeabi # 當前設備支持的目標架構
HAVE_HTC_AUDIO_DRIVER := true # 是否使用HTC的音頻驅動
BOARD_USES_GENERIC_AUDIO := true # 是否使用通用音頻技術
# no hardware camera
USE_CAMERA_STUB := true # 是否使用攝像頭Stub
經過BoardConfig.mk的信息可知,其實該文件就是定義了一些設備硬件相關的一些變量,這些變量用來裁剪系統的功能,決定Android系統可運行的體系構架。
7. 根據須要定義產品默認屬性和鍵值信息
Android系統的屬性服務相似於Windows的註冊表,記錄着系統的一些設置信息,咱們能夠在新產品中預約義一些屬性值來設置本身產品。在Android編譯系統中,屬性都保存在xxx.prop文件中,在build/target/board/generic/system.prop中定義了默認的屬性,咱們能夠在它基礎上進行修改。
複製屬性文件:
$ cp build/target/board/generic/system.prop device/mycompany/myphone/
在Android系統中,底層使用Linux內核來接收來自按鍵硬件上報的鍵值信息,上層處理用戶按鍵的是Android的框架,兩者之間經過兩個鍵值佈局文件來進行鍵值的映射。
Ø Keylayout文件:按鍵佈局文件,以kl後綴命名,該文件用來定義按鍵驅動裏上報的鍵值號(數字)和Linux內核中經過event事件上報的鍵值(字符)之間的映射關係。kl文件要放在/system/usr/keylayout/目錄下或/data/usr/keylayout/目錄下。
Ø KeyCharMap文件:鍵值字符映射文件,以kcm後綴命名,它用來將Linux內核上報來的鍵值(字符)進行轉換,轉換成Android系統裏能夠識別的鍵盤碼或組合按鍵。kcm文件要放在/system/usr/keychars/目錄下或/data/usr/keychars/目錄下。
上述兩個按鍵映射文件使用按鍵驅動名做爲其文件名,若是沒有驅動名對應的佈局文件,則使用/system/usr/keylayout/qwerty.kl和/system/usr/keychars/qwerty.kcm做爲默認的按鍵映射文件。這兩個文件名都經過AndroidBoard.mk文件負責拷貝和安裝。
若是咱們要使用模擬器做爲目標設備,只須要將源碼build/target/board/generic/目錄裏的tuttole2.kl和tuttle2.kcm拷貝到AndroidBoard.mk所在的目錄中便可。
$ cp build/target/board/generic/tuttle2.kl device/mycompany/myphone/tuttle2.kl
$ cp build/target/board/generic/tuttle2.kcm device/mycompany/myphone/tuttle2.kcm
若是想要自定義系統的物理按鍵與Android系統的按鍵映射關係,則須要在tuttle2.kl和tuttle2.kcm的基礎上進行修改,而後再修改AndroidBoard.mk的內容:
$ cp build/target/board/generic/tuttle2.kl device/mycompany/myphone/<按鍵驅動名>.kl
$ cp build/target/board/generic/tuttle2.kcm device/mycompany/myphone/<按鍵驅動名>.kcm
修改device/mycompany/myphone/AndroidBoard.mk文件:
LOCAL_PATH := $(call my-dir)
file := $(TARGET_OUT_KEYLAYOUT)/<按鍵驅動名>.kl # Linux內核按鍵碼佈局文件
ALL_PREBUILT += $(file)
$(file) : $(LOCAL_PATH)/<按鍵驅動名>.kl | $(ACP)
$(transform-prebuilt-to-target)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := <按鍵驅動名>.kcm # Android按鍵碼映射文件
include $(BUILD_KEY_CHAR_MAP)
注:kcm文件最終被編譯系統的key_char_map.mk編譯成xxx.kcm.bin的二進制形式,這是由於每一個Android應用程序都要加載該按鍵映射文件,爲了加快讀取速度刻意而爲之的。
建立新產品編譯項時建立的目錄與文件結構以下:
device/mycompany/ # 廠商目錄
└── vendorsetup.sh # 添加編譯項命令文件
└── myphone/ # 設備名目錄
├── AndroidBoard.mk # 設備屬性和鍵值映射配置文件
├── AndroidProducts.mk # 產品列表文件
├── BoardConfig.mk # 設備硬件配置及目標架構配置文件
├── full_product.mk # 目標產品配置文件
├── system.prop # 系統默認屬性配置文件
├── tuttle2.kcm # Android系統鍵值映射文件
├── tuttle2.kl # Linux內核按鍵佈局文件
確認上述目錄和文件建立沒有問題了,執行Android編譯步驟:sourcebuild/envsetup.sh,lunch選擇myproduct-eng編譯項。
若是看到以下信息,說明咱們已經添加新產品成功。
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.3.6
TARGET_PRODUCT=myproduct
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=GRK39F
============================================
8. 常見問題
Ø 問題1: lunch菜單裏沒有出現myproduct編譯項
緣由及解決方法:在執行lunch以前,要執行source build/envsetup.sh命令,確認vendorsetup.sh文件存在及其內容正確無誤。
Ø 問題2:選擇完lunch菜單裏的編譯項後,出錯:
*** No matches for product"myproduct". Stop.
** Don't have a product spec for:'myproduct'
** Do you have the right repo manifest?
緣由及解決方法:編譯系統找不到用戶選擇的編譯項裏的myproduct產品,確認AndroidProducts.mk文件裏列出了myproduct產品的配置文件full_product.mk,而且full_product.mk文件中PRODUCT_NAME變量的值爲產品名:myproduct
Ø 問題3:選擇完lunch菜單裏的編譯項後,出錯:
*** No config file found for TARGET_DEVICEmyphone. Stop.
** Don't have a product spec for:'myproduct'
** Do you have the right repo manifest?
緣由及解決方法:編譯系統找不到myproduct產品對應的設備myphone,確認myproduct產品的配置文件full_product.mk中PRODUCT_DEVICE變量的值爲產品名:myphone,而且在device/mycompany/目錄下建立了myphone的設備目錄,在該目錄下存在BoardConfig.mk文件。
Android系統是一個徹底開源的系統,咱們能夠經過修改Linux內核代碼和Android源碼,定製具備獨特創意的產品系統,對於產品同質化很是嚴重的移動市場, Android系統的細節個性化定製也可讓用戶眼前一亮。另外,一些產品明確要求要修改或增長一些個性化,如:默認的Android系統開機界面是一個黃嘴的小企鵝,在Android系統啓動過程當中是一個ANDROID字樣的動畫效果,廠商通常都要求本身產品開機界面是廠商Logo,開機動畫是一個能動態、鮮明表現公司活力的動畫效果,咱們從本節開始介紹定製產品系統的實現技術。
在整個開機過程當中,屏幕上會出現三次內容,如圖x-x 所示:
Ø Linux啓動時畫面,一般是個黃嘴的小企鵝
Ø Android系統init進程啓動階段畫面,是「ANDROID」文字字樣
Ø Android系統啓動階段動畫,是滾動的ANDROID動畫
圖 x-x 開機界面與Android動畫
【實驗背景知識】
Android的開機動畫是由Linux本地守護程序bootanimation專門控制實現的,其代碼在:frameworks/base/cmds/bootanimation/目錄下,修改Android開機動畫有兩種方式:
Ø 蒙板圖片替換:
替換frameworks/base/core/res/assets/images/目錄下的兩個圖片文件:android-logo-mask.png和android-logo-shine.png。android-logo-mask.png是鏤空濛板圖片,android-logo-shine.png是鏤空濛板後面的閃光png圖片。兩個圖片經過疊加移動來達到動畫效果。
Ø 逐幀動畫替換:
在/data/local/或/system/media/目錄建立bootanimation.zip文件,該壓縮包文件裏存放有逐幀動畫及控制腳本。
【實驗組成】
本實驗分爲兩部分:蒙板圖片替換實驗和逐幀動畫替換實驗。
【實驗內容】
分析Android系統的兩種開機動畫實現方式,製做並替換開機動畫,最終在Android模擬器中運行定製開機動畫的系統。
【實驗目的】
經過實驗,瞭解Android系統的兩種開機動畫實現方式,掌握如何定製產品的開機動畫,並在Android模擬器中,運行定製開機動畫的Android系統。
【實驗平臺】
擁有Android源碼編譯環境的Ubuntu操做系統(能夠在Windows系統中虛擬Ubuntu系統)。
【蒙板圖片替換實驗步驟】
1. 使用PhotoShop等圖像處理軟件製做一張背景爲黑色,中間鏤空的png格式的圖片,命名爲:android-logo-mask.png,如圖x-x所示。
圖x-x 製做鏤空動畫
2. 將android-logo-mask.png拷貝到frameworks/base/core/res/assets/images/目錄下替換Android默認的圖片,爲了防止源碼不編譯圖片資源,將圖片時間戳更新一下。
$ cp android-logo-mask.png ~/android/android_source/frameworks/base/core/res/assets/images/
$ touch ~/android/android_source/frameworks/base/core/res/assets/images/android-logo-mask.png
3. 從新編譯Android的系統資源包framework-res.apk
$ source build/envsetup.sh
$ lunch generic-eng
$ mmm frameworks/base/core/res/
4. 生成新的system.img
$ make snod
5. 啓動Android模擬器,實驗效果如圖x-x所示。
$ ./run_emulator.sh
圖x-x 定製開機動畫效果
【逐幀動畫替換實驗步驟】
1. 在/data/local/或/system/media/目錄建立bootanimation.zip文件
若是放在/data/local目錄下,不須要編譯Android源碼,直接經過adb命令或文件管理軟件拷貝到目錄下便可,若是集成進Android系統中,則須要放在/system/media/目錄下,這時要從新編譯生成system.img映像。
bootanimation.zip文件是直接由幾個文件打包生成的,打包的格式是ZIP,打包時的壓縮方式選擇爲存儲。
圖x-x 壓縮文件方式
bootanimation.zip文件打包前的結構爲:
表x-x bootanimation.zip壓縮包文件結構
文件 |
說明 |
desc.txt |
動畫屬性描述文件 |
part0/ |
第一階段動畫圖片的目錄 |
part1/ |
第二階段動畫圖片的目錄 |
其中part0和part1中的動畫圖片相似於電影膠片,兩張圖片之間變化較小,他們以固定的速度顯示,從而產生動畫效果,圖片的大小和圖片顯示的時間控制由desc.txt文件說明。
desc.txt文件內容爲:
480 250 15
p 1 0 part0
p 0 10 part1
desc.txt文件的格式爲:
|
數據及說明 |
|||
圖片屬性 |
320(圖片寬) |
320(圖片高) |
15(每秒顯示幀數) |
無 |
第一階段動畫屬性 |
P(默寫標誌符) |
1(循環次數爲1 ) |
0(進入該階段的間隔時間) |
part0(該階段圖片存放目錄) |
第二階段動畫屬性 |
p(默寫標誌符) |
0(無限循環) |
10(進入該階段的間隔時間) |
part1(該階段圖片存放目錄) |
注:
標識符:p 是必須的。
循環次數:指該目錄中圖片循環顯示的次數,0表示本階段無限循環。
每秒顯示幀數:就是每秒顯示的圖片數量,決定每張圖片顯示的時間。
階段切換間隔時間:指的是該階段結束後間隔多長時間顯示下一階段的圖片,其單位是每張圖片顯示的時間。
對應圖片目錄:就是該階段動畫的系列圖片,以圖片文件目錄的順序顯示動畫,並且圖片的格式必需要爲PNG。
因爲逐幀動畫不太方便製作,咱們直接使用光盤中:章節實驗/第四章定製系統開機動畫/bootanimation.zip文件做爲演示。
2. 若是bootanimation.zip放到/system/media/目錄下,則從新編譯生成system.img
$ source build/envsetup.sh
$ lunch generic-eng
$ make snod
3. 啓動Android模擬器,查看動畫效果,如圖x-x和x-x所示。
$ ./run_emulator.sh
圖x-x 第一階段開機動畫
圖x-x 第二階段開機動畫
結論:經過實驗看出,當咱們使用逐幀動畫時,蒙板動畫就不播放了,這是由於Android系統只能使用一種啓動動畫方式,先判斷是否使用了逐幀動畫,若是沒有使用逐幀動畫時,才使用默認的蒙板動畫。