zoukankan      html  css  js  c++  java
  • 深入浅出

    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

  • 相关阅读:
    从一个集合中查找最大最小的N个元素——Python heapq 堆数据结构
    算法导论第二章小试牛刀
    python网络编程初级
    python基础的几个小练习题
    LeetCode:114_Flatten Binary Tree to Linked List | 将一棵二叉树变成链表的形式 | Medium
    LeetCode:111_Minimum Depth of Binary Tree | 二叉树的最小深度 | Easy
    LeetCode:110_Balanced Binary Tree | 平衡二叉树 | Easy
    LeetCode: 106_Construct Binary Tree from Inorder and Postorder Traversal | 根据中序和后序遍历构建二叉树 | Medium
    mysql中json_object函数的使用?
    mysql中json_remove函数的使用?
  • 原文地址:https://www.cnblogs.com/doctorqbw/p/5438707.html
Copyright © 2011-2022 走看看