深入浅出 - 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 内核编译结果

你可能感兴趣的:(Android移植)