深入淺出 - Android系統移植與平台開發(五)- 編譯Android源碼(轉)


2.3編譯Android源碼

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

2.3.1Android源碼目錄結構

在Android源碼中,按照不同功能代碼被放在不同的目錄下:

 

目錄

描述

bionic

針對Android系統定制的仿生標准C庫、鏈接器等所在目錄,Android系統並沒有使用Linux的glibc庫,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

HAL(Hardware 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

SSH2的server

 oprofile

OProfile是Linux內核支持的一種性能分析機制

 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開發符合SAX的HTML解析器

 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之前,編譯系統需要加載一些編譯腳本命令到環境變量中,通過下面的指令來初始化編譯環境:

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $ sourcebuild/envsetup.sh    

 

在執行完上述命令后,可以通過執行help命令來查看所有加載的命令。

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $ help  
  2. Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:  
  3. - croot:   Changes directory to the top of the tree.  
  4. - m:       Makes from the top of the tree.  
  5. - mm:      Builds all of the modules in the current directory.  
  6. - mmm:     Builds all of the modules in the supplied directories.  
  7. - cgrep:   Greps on all local C/C++ files.  
  8. - jgrep:   Greps on all local Java files.  
  9. - resgrep: Greps on all local res/*.xml files.  
  10. - godir:   Go to the directory containing a file.  
  11.    
  12. Look at the source to view more functions. The complete list is:  
  13. 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

從所有的C,C++文件里查找指定字符串

jgrep

從所有的Java文件里查找指定字符串

 

Ø 選擇編譯選項

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

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $ lunch  
  2. You're building on Linux  
  3.    
  4. generic-eng simulator   
  5. Lunch menu... pick a combo:  
  6.      1. generic-eng  
  7.      2. simulator  
  8. Which would you like? [generic-eng]  

 

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

…接前面終端輸出信息

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. Which would you like? [generic-eng]1 [回車]  
  2. ============================================  
  3. PLATFORM_VERSION_CODENAME=REL  
  4. PLATFORM_VERSION=2.1-update1  
  5. TARGET_PRODUCT=generic  
  6. TARGET_BUILD_VARIANT=eng  
  7. TARGET_SIMULATOR=false  
  8. TARGET_BUILD_TYPE=release  
  9. TARGET_ARCH=arm  
  10. HOST_ARCH=x86  
  11. HOST_OS=linux  
  12. HOST_BUILD_TYPE=release  
  13. BUILD_ID=ERE27  
  14. ============================================  

 

由上面結果可知,當用戶輸入:1或generic-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指令開始編譯目標系統:

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $make  

 

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

 

通過上面的輸出信息可知,Android系統編譯完后,在out/target/product/generic/目錄下產出了三個文件:system.img、ramdisk.img、userdata.img。

 

  • system.img:android系統的文件系統,里面包含了android系統的應用程序(apk),系統用到的各種庫(jar, so)和資源,配置文件(etc目錄下),系統命令(bin,usr/bin, xbin),該映像文件是由out/target/product/generic/system目錄打包生成的,我們可以對這個目錄里的東西進行定制化,比如,你要想讓android系統默認安裝一個應用程序,那么可以將要安裝的apk文件拷貝到out/target/product/generic/system/app目錄下。
  •  userdata.img:用戶數據映像,里面包含有程序安裝信息等,好比如是windows的C:/Program Files/目錄。
  • ramdisk.img:內存磁盤映像。linux內核啟動起來,要掛載一個文件系統作為自己的根文件系統,里面含有Linux內核啟動過程中依賴的一些程序和配置文件。ramdisk.img就是一個最小化的根文件系統,它被加載到內存中作為Android的根文件系統。該映像是由out/target/product/generic/root目錄打包生成的。前面所述的userdata.img和system.img映像,在linux系統啟動起來后掛載到ramdisk.img中的data,system目錄下。

 

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

ROM包文件

說明

android-info.txt

ROM版本及刷寫配置信息

boot.img

Linux內核zImage、ramdisk.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編譯器,為了編譯出針對模擬器的內核(模擬器的CPU為Goldfish),還要配置內核(如果不知道如何配置內核,請讀者閱讀內核裁剪相關資料),為了方便我們編譯Goldfish內核,我們編寫了如下腳本,方便編譯。

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $ cd /home/linux/android/android_source/kernel/goldfish/  
  2. $ vi build_kernel.sh  

 

添加如下內容:

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

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. #!/bin/bash  
  2. export PATH=/home/linux/android/android_source/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH  
  3. export ARCH=arm  
  4. export SUBARCH=arm   
  5. export CROSS_COMPILE=arm-eabi-    
  6. if [ ! –f .config ] ; then  
  7. make goldfish_armv7_defconfig    
  8. fi  
  9. make  

 

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

給腳本加上可執行權限,然后執行該腳本:

 

[cpp]  view plain  copy
 
 在CODE上查看代碼片派生到我的代碼片
  1. $ chmod a+x build_kernel.sh  
  2. $ ./build_kernel.sh  

 

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

 

圖 內核編譯結果

 

轉自:http://blog.csdn.net/mr_raptor/article/details/20934501


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM