1. 程式人生 > >Android系統移植與平臺開發(五)- 編譯Android原始碼

Android系統移植與平臺開發(五)- 編譯Android原始碼

2.3編譯Android原始碼

Android原始碼體積非常龐大,由Dalvik虛擬機器、Linux核心、編譯系統、框架程式碼、Android定製C庫、測試套件、系統應用程式等部分組成,在編譯Android原始碼之前,必須要先掌握Android原始碼的組成。

2.3.1Android原始碼目錄結構

Android原始碼中,按照不同功能程式碼被放在不同的目錄下:

目錄

描述

bionic

針對Android系統定製的仿生標準C庫、連結器等所在目錄,Android系統並沒有使用Linuxglibc庫,bioinc C庫針對嵌入式系統做了優化,添加了一些Android特定的函式API

同時大大減少庫的體積,也避免了LGPL版權的問題。

bootable

Android系統引導啟動程式碼,用來引導系統、更新系統、恢復系統。

build

Android的編譯系統目錄,裡面包含大量的Makefile,用來編譯目標系統、Host主機開發環境等。

cts

相容性測試工具目錄。

dalvik

Dalvik虛擬機器,Android系統得以執行的虛擬執行環境。

development

程式開發所需要的模板和工具。

external

Android系統使用的其它開原始碼目錄,如jpeg圖片解碼開源庫、opencore開原始碼等。

frameworks

框架層程式碼,frameworks/base目錄下存放目標系統的框架庫,frameworks/policies/base下存放應用程式框架程式碼。

hardware

HALHardware Abstraction Layer)硬體抽象層程式碼。

kernel

Linux核心目錄,預設下載的Android原始碼裡沒有,需單獨下載。

packages

Android系統級應用程式原始碼目錄,如攝像應用、電話應用等。

prebuilt

主機編譯工具目錄,如arm-linux-gcc交叉系統工具鏈等。

sdk

SDK及模擬器。

system

init程序、藍芽、無線

WIFI工具、uevent程序目錄。

devices

廠商裝置配置目錄,針對不同裝置,由不同的子目錄來分別管理,用來裁剪實現不同裝置上Android目標系統。


external目錄下存放著大量的外部開原始碼: 

外部開源專案

描述

外部開源專案

描述

 aes

AES加密

 libxml2

xml解析庫

 apache-http

網頁伺服器

 make

 asm

 netbeans-visual

 bluez

藍芽相關、協議棧

 netcat

simple Unix utility which reads and writes dataacross network connections

 ccache

 netperf

網路效能測量工具

 clearsilver

 neven

看程式碼和JNI相關

 dbus

低延時、低開銷、高可用性的IPC機制

 opencore

多媒體框架

 dhcpcd

DHCP服務

 openssl

SSL加密相關

 dropbear

SSH2server

 oprofile

OProfileLinux核心支援的一種效能分析機制

 eclipse

 ppp

pppd撥號命令,好像還沒有chat

 elfcopy

複製ELF的工具

 protobuf

a flexible, efficient, automated mechanism for serializing structured data

 elfutils

ELF工具

 qemu

arm模擬器

 embunit

Embedded Unit Project

 safe-iop

functions for performing safe integer operations

 emma

java程式碼覆蓋率統計工具

 sdl

 esd

Enlightened Sound Daemon,將多種音訊流混合在一個裝置上播放

 skia

skia圖形引擎

 expat

Expat is a stream-oriented XML parser

 sonivox

sole MIDI solution for Google Android Mobile Phone Platform

 fdlibm

FDLIBM (Freely Distributable LIBM)

 sqlite

資料庫

 Flex

 srec

Nuance 公司提供的開源連續非特定人語音識別

 freetype

字型庫

 strace

trace工具

 gdata

google的無線資料相關

 swing-worker

 diflib

 swt

 googleclient

google使用者庫

 tagsoup

TagSoup是一個Java開發符合SAXHTML解析器

 icu4c

ICU(International Component for Unicode)C/C++下的版本

 tcpdump

TCP包的軟體

 iptables

防火牆

 tinyxml

TinyXml is a simple, small, C++ XML parser

 Jdiff

generate a report describing the difference between two public Java APIs

 toolchain

 jfreechart

 tremor

I stream and file decoder provides an embeddable,integer-only library

 jpeg

jpeg

 webkit

瀏覽器核心

 kxml2

 wpa_supplicant

無線網絡卡管理

 libffi

libffi is a foreign function interface library.

 yaffs2

yaffs檔案系統

libpcap

網路資料包捕獲函式

zlib

a general purpose data compression library

packages/app目錄下存放著大量系統級應用程式,我們可以拿到這些應用程式程式碼分析、理解,編寫出效率更高,效能更好的應用:

系統應用程式

描述

AlarmClock

鬧鐘

Browser

瀏覽器

Calculator

計算器

Calendar

日曆

Camera

攝像頭

Contacts

聯絡人

Email

郵件

GoogleSearch

Google搜尋

HTML Viewer

瀏覽器附屬介面,被瀏覽器應用呼叫,同時提供儲存記錄功能

IM 

即時通訊,為手機提供訊號傳送、接收、通訊的服務

Launcher

Android的桌面

Mms

彩信業務

Music

音樂播放器

PackageInstaller

應用程式安裝、解除安裝器

Phone

電話應用

Settings

系統設定

SoundRecorder

錄音機

Stk

簡訊接收和傳送

Sync

 同步資料

Updater

 更新

VoiceDialer

語音識別通話


package/providers目錄下存放的是系統級內容提供器(Content Provider): 

系統內容提供器

描述

CalendarProvider

日曆提供器

ContactsProvider  

聯絡人提供器

DownloadProvider

下載管理提供器

DrmProvider

DRM受保護資料儲存服務,建立和更新資料庫時呼叫

GoogleContactsProvider

谷歌聯絡人提供器

GoogleSubscribedFeedsProvider  

Google同步功能

ImProvider

即時通訊提供器

MediaProvider

媒體提供器、提供儲存資料

SettingsProvider

系統設定提供器

SubscribedFeedsProvider

TelephonyProvider  

彩信提供器

2.3.2編譯Android

按照Android官方網站給出的步驟,編譯Android原始碼過程如下:

Ø 初始化編譯環境

在編譯Android之前,編譯系統需要載入一些編譯指令碼命令到環境變數中,通過下面的指令來初始化編譯環境:

$ sourcebuild/envsetup.sh  

在執行完上述命令後,可以通過執行help命令來檢視所有載入的命令。

$ help
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory.
- mmm:     Builds all of the modules in the supplied directories.
- cgrep:   Greps on all local C/C++ files.
- jgrep:   Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- godir:   Go to the directory containing a file.
 
Look at the source to view more functions. The complete list is:
add_lunch_combo cgrep check_product check_variant choosecombo chooseproduct choosetype choosevariant cproj croot findmakefile gdbclient get_abs_build_var getbugreports get_build_var getprebuilt gettop godir help isviewserverstarted jgrep lunch m mm mmm pid printconfig print_lunch_menu resgrep runhat runtest setpaths set_sequence_number set_stuff_for_environment settitle smoketest startviewserver stopviewserver systemstack tapas tracedmdump

常用指令碼命令:

指令碼命令

描述

Help

幫助資訊,列印所有命令

add_lunch_combo

新增新目標編譯項

print_lunch_menu

列印所有目標編譯項

lunch

選擇目標編譯項

m

從原始碼樹頂級目錄向下編譯原始碼,相當於執行make

mm

從當前目錄向下編譯原始碼

mmm

從指定目錄向下編譯原始碼,通常用來編譯某個模組

cgrep

從所有的CC++檔案裡查詢指定字串

jgrep

從所有的Java檔案裡查詢指定字串

Ø 選擇編譯選項

由於Android原始碼是一個開源的系統,然要匹配很多裝置產品,也就是說一個版本的Android原始碼,可以編譯出針對不同產品的系統。通過選擇一個目標編譯項,來決定編譯出針對哪個產品的系統,我們可以通過執行下面的命令來選擇要編譯的目標系統:

$ lunch
You're building on Linux
 
generic-eng simulator 
Lunch menu... pick a combo:
     1. generic-eng
     2. simulator
Which would you like? [generic-eng]

通過lunch命令可知,讓使用者輸入目標編譯項,我們可以選擇編譯項前的數字,也可以直接輸入編譯項的名字。

…接前面終端輸出資訊

Which would you like? [generic-eng]1 [回車]
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=2.1-update1
TARGET_PRODUCT=generic
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=ERE27
============================================

由上面結果可知,當用戶輸入:1generic-eng時,會打印出上面的資訊,這些資訊是Android的編譯系統必須依賴的環境變數,只有設定了這些變數,才能決定Android系統如何編譯,編譯成什麼平臺,編譯成什麼版本。

目標編譯項格式:產品名-版本變數名,目標編譯項可以由使用者新增(見xxx章節),產品名是目標裝置的產品名,由廠商自己定義,generic產品是通用產品,它是Android預設裝置的產品名,它包含了常用的手機的所有功能,自己定義的產品可以繼承generic,並重寫它的功能,達到定製產品的目的(見xxx章節)。

版本變數名由以下幾個組成:

  • eng:工程版本,
  • user:終端使用者版本
  • userdebug:除錯版本
  •  tests:測試版本

其中,eng版本產品其實就是手機行業的工程機,它不是最終銷售的產品,而是產品在定型下線之前放出的一些測試用機器,用於檢測和標準的認證,這些工程機上安裝的系統為eng版本,user是終端使用者機發行版本,userdebug是除錯版本,它比使用者機添加了一些除錯功能,如adb除錯預設開啟等,tests測試版本,該版本會安裝一些測試程式,用於測試系統。

上述四種版本的分類作用,其一:用於區分目標系統裡的所有的應用程式、庫、測試程式等,將它們打上對應的Tags,當選擇一個版本編譯時,擁有對應Tags及低級別的Tags的程式會被編譯安裝到目標裝置上,應用程式Tags的包含關係如下圖:。其二:根據不同的版本,系統會有不同的設定,如adbd在使用者版本里是關閉的,在其它版本中是預設開啟的,ro.secure屬性使用者版本值為1,其它版本為0

 

Ø 編譯原始碼

執行完前面的命令後,我們可以輸入make指令開始編譯目標系統:

$make

編譯的時長與機器的硬體配置有關係,當第一次編譯時一般需要數小時以上。後續編譯,相對快多了,編譯完的效果如下圖所示:

 

通過上面的輸出資訊可知,Android系統編譯完後,在out/target/product/generic/目錄下產出了三個檔案:system.imgramdisk.imguserdata.img

  • system.imgandroid系統的檔案系統,裡面包含了android系統的應用程式(apk),系統用到的各種庫(jar, so)和資源,配置檔案(etc目錄下),系統命令(bin,usr/bin, xbin),該映像檔案是由out/target/product/generic/system目錄打包生成的,我們可以對這個目錄裡的東西進行定製化,比如,你要想讓android系統預設安裝一個應用程式,那麼可以將要安裝的apk檔案拷貝到out/target/product/generic/system/app目錄下
  •  userdata.img:使用者資料映像,裡面包含有程式安裝資訊等,好比如是windowsC:/Program Files/目錄
  • ramdisk.img:記憶體磁碟映像。linux核心啟動起來,要掛載一個檔案系統作為自己的根檔案系統,裡面含有Linux核心啟動過程中依賴的一些程式和配置檔案ramdisk.img就是一個最小化的根檔案系統,它被載入到記憶體中作為Android的根檔案系統。該映像是由out/target/product/generic/root目錄打包生成的。前面所述的userdata.imgsystem.img映像,在linux系統啟動起來後掛載到ramdisk.img中的datasystem目錄下。

其實,Android手機的ROM包(通常為update.zip檔案),就是主要由上述三個映像檔案構成的:

ROM包檔案

說明

android-info.txt

ROM版本及刷寫配置資訊

boot.img

Linux核心zImageramdisk.img

system.img

Android系統映像

userdata.img

使用者資料映像

其它映像

只要我們拿到手機的原始碼,就可以自己編譯出自己的ROM,不過,一般手機廠商不會開源自己產品原始碼,都是第三方愛好者自己下載,修改編譯的,如:業界著名的CM團隊:http://www.cyanogenmod.com/

由於完全編譯Android系統耗時很長,並且Android原始碼由很多模組組成,我們可以通過下面一些編譯命令來減少編譯時間:

編譯命令

說明

make snod

打包生成system.img,不檢查依賴關係

make bootimage

打包生成ramdisk.img 

mmm

指定編譯某個目錄下的模組

上述三個命令經常在我們原始碼開發時使用,希望大家記住。

2.3.3編譯Linux核心

Android使用Linux核心,在原始碼級開發過程中,有時要修改核心程式碼,通常核心程式碼是和目標裝置相關的,我們使用的是模擬器的核心,即使沒有硬體裝置也可以完成實驗。

編譯Android的核心,需要用到交叉編譯器,我們可以直接使用Android原始碼裡自帶的arm-eabi-gcc編譯器,為了編譯出針對模擬器的核心(模擬器的CPUGoldfish),還要配置核心(如果不知道如何配置核心,請讀者閱讀核心裁剪相關資料),為了方便我們編譯Goldfish核心,我們編寫了如下指令碼,方便編譯。

$ cd /home/linux/android/android_source/kernel/goldfish/
$ vi build_kernel.sh

新增如下內容:

@ /home/linux/android/android_source/kernel/goldfish/build_kernel.sh

#!/bin/bash
export PATH=/home/linux/android/android_source/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH
export ARCH=arm
export SUBARCH=arm 
export CROSS_COMPILE=arm-eabi-  
if [ ! –f .config ] ; then
make goldfish_armv7_defconfig  
fi
make

注:當Andorid原始碼目錄發生改變時,要修改PATH的路徑,讓它指向對應的交叉編譯器。

給指令碼加上可執行許可權,然後執行該指令碼:

$ chmod a+x build_kernel.sh
$ ./build_kernel.sh

核心編譯完成如圖x-x所示:

 

x-x 核心編譯結果