第1章 建立Android系统开发环境

在开始研究Android系统之前,需要预先准备好系统开发需要的各种资源:包括操作系统、各种开发工具以及Android源码等。本章将介绍这些资源的获取途径和安装方法。

在阅读本书前,读者需要掌握一些必要的技能。Android应用使用Java语言开发,底层使用C/C++开发,因此,掌握Java语言和C/C++语言是进行Android系统开发的必要条件。Android运行在Linux内核(从标准的Linux内核修改移植而来)之上,但是,开发Android系统组件并不需要读者拥有特别高深的Linux系统知识,只要掌握基本的Linux命令和常识就够了。但是,如果希望成为优秀的系统开发者,深入理解Linux内核还是非常有必要的。

Android系统开发的目的是制作Android系统软件,例如,手机或Pad的ROM,或者增加、修改Android的系统模块,因此,在学习开始前,读者最好能拥有一台可以更新自制ROM的Android手机,如果是Google的开发机就更合适了。Google的开发机对用户的限制最小,能方便地编译出手机的ROM。如果没有合适的手机,使用自己编译的模拟器也是一种替代方案。

1.1 安装操作系统

Google推荐使用64位Ubuntu操作系统开发Android。Ubuntu是一款优秀的Linux桌面操作系统,每年4月和10月固定发行两个版本。其中偶数年的4月发行的版本作为TLS版本。TLS版本的含义是长期支持版,可以得到3年的升级支持。

计算机主板厂家通常不会提供Linux驱动,对于新发布的主板,Ubuntu可能会无法识别主板上集成的一些硬件模块,特别是网卡。但是,Ubuntu有强大的社区支持,笔者遇到类似问题时,都是在网上搜索,然后自己编译安装驱动,这是使用Ubuntu前需要注意的问题。

1.1.1 安装方式的选择

Ubuntu有两种安装方式,在PC上直接安装或者安装在虚拟机中。

通常,专业的Android系统开发大多会选择直接安装在PC上,这是因为专业开发经常需要编译Android系统,对计算机性能要求比较高。如果只是为了学习和分析Android系统,在Windows中安装一个Ubuntu虚拟机也是不错的方法。读者可以根据自己的需要来选择。

比较流行的虚拟机软件有两种:Oracle公司的VirtualBox和VMWare公司的VMWare套件。比较而言,后者的功能更强大、稳定,但是需要收费,前者则可以免费使用。

1.1.2 下载和安装Ubuntu

Ubuntu可以从其官方网站免费下载,地址是www.ubuntu.org。编写本书时,笔者使用的Ubuntu版本是64位的14.04。Ubuntu的安装过程比较简单,就不介绍了。安装完成后可以将Ubuntu的软件源切换成国内的镜像,这样下载安装各种软件包的速度将大大提高。

更改软件源的方法是:依次点击“System Settings”→“Software & Updates”→“Ubuntu Software”,然后在“Download from”右侧的列表中选择“Others”,再在弹出的对话框中寻找China条目,找到后选择一个镜像地址(例如mirrors.sohu.com)就可以了,如图1.1所示。

▲图1.1 镜像的地址

Ubuntu14.04以前的版本在选择新的软件源后还需要通过命令更新本地存储的软件包索引信息后才可以使用,命令如下。

      # sudo apt-get update

命令开始执行后会从新的服务器上下载最新的软件包列表。

Ubuntu14.04在更新软件源后会要求输入密码,然后自动更新本地的软件包索引信息,不需要再手动输入命令更新。

笔者使用的Ubuntu是英文版,读者如果希望使用中文版,可以下载安装中文语言包。

1.1.3 使用Ubuntu遇到的问题

Ubuntu每年会发布两个版本,但是不要太着急升级到最新的版本,新版本有时会有一些兼容性问题,更新前最好上网查一查是否有影响Android开发的问题存在。以前就发生过Ubuntu 12.10无法编译Android的问题,原因是新版本搭载的gcc 4.7不能编译当时的Android代码。不过Ubuntu有一个很有用的特性,就是能同时安装一个软件的不同版本,因此,解决的办法就是再安装一个旧版本的gcc4.4。

在Ubuntu上安装4.4版本的gcc和g++的命令是:

      #sudo apt-get install gcc-4.4 g++-4.4 g++-4.4-multilib gcc-4.4-multilib
      #sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.4 50
      #sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.4 50

配置选择版本的命令是:

      # sudo update-alternatives --config g++
      # sudo update-alternatives --config gcc

一般而言,Google会在新的Android版本里解决类似的问题,但是旧版本还是会存在问题。如果需要同时维护几个版本的Android系统,需要使用上面的方法来安装多个版本的gcc。

1.2 安装开发包

Android系统的编译需要依赖一些第三方的开发包和工具,包括Oracle的JDK(以前属于Sun公司)。大部分的软件包都能通过apt-get来安装和升级,非常方便,但是JDK不能通过这种方式安装,只能从Oracle的官方网站下载软件包手动安装。从Android 5.0开始,Google支持使用OpendJDK 1.7来编译Android,因此,我们又可以使用apt-get快速地安装编译环境。对于Android 5.0以前的代码,还是需要使用Oracle的JDK 1.6来编译。

1.2.1 安装JDK 1.6

JDK 1.6的安装过程如下。

(1)下载安装包。

首先在Oracle的官网上注册账号,完成后就可以下载JDK了。下载的版本要选择JDK 1.6for64位Linux版本,最新的JDK 1.6的子版本号是45,文件名是jdk-6u45-linux-x64.bin,下载地址是:

      http://www.oracle.com/technetwork/java/javase/downloads/java-archive-downloads-javas
      e6-419409.html#jdk-6u45-oth-JPR

(2)下载完成后修改下载文件的属性为可执行,命令如下:

      # chmod +x jdk-6u45-linux-x64.bin

(3)执行下载的bin文件,这将创建包含JDK文件的目录jdk1.6.0_45:

      # ./jdk-6u45-linux-x64.bin

(4)在Linux系统的/usr/lib目录下创建子目录jvm:

      # sudo mkdir /usr/lib/jvm

(5)移动第三步中展开的文件目录到jvm目录下:

      # sudo mv jdk1.6.0_45 /usr/lib/jvm

(6)修改环境变量。

如果只是针对当前用户,修改~/.bashrc文件就可以了,在文件结尾处加入下面的内容:

      export JAVA_HOME=/usr/lib/jvm/jdk1.6.0_45
      export JRE_HOME=/usr/lib/jvm/jdk1.6.0_45/jre
      export CLASSPATH=$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH
      export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

(7)最后用下面的命令测试:

      # java  -version

如果出现如图1.2所示的信息就表示安装成功了。

▲图1.2 安装成功界面

1.2.2 安装OpenJDK 1.7

从Android 5.0开始,使用OpenJDK 1.7作为Java开发环境,它的安装命令是:

      $ sudo apt-get install openjdk-7-jdk
      $ sudo update-alternatives --config java
      $ sudo update-alternatives --config javac

1.2.3 安装编译需要的开发包

Google指定的安装包列表可以在Android的官方网站上查到。这个列表会随着Android版本变化而调整,安装新的开发环境时最好到Android的官方网站上下载这个列表,地址是:

      http://source.android.com/source/initializing.html

对于Android 4.0及以上版本,包括Android 5.0,在Ubuntu 12.04及以上版本需要安装下列开发包。

      # sudo apt-get install git gnupg flex bison gperf build-essential \
      zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev \
      libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 \
      libgl1-mesa-dev g++-multilib mingw32 tofrodos \
      python-markdown libxml2-utils xsltproc zlib1g-dev:i386

注意

如果使用的Ubuntu版本是14.04,还需要先安装dpkg-dev,否则上面的安装会失败,具体命令如下:

      # sudo apt-get install dpkg-dev

对于Ubuntu 14.04版本,只要安装下面的包应该就可以了:

      sudo apt-get install bison g++-multilib git gperf libxml2-utils

1.3 安装一些有用的工具

在开发和学习Android的过程中,一些辅助工具会非常有用,下面介绍几种必备的工具。另外还有一些有用的小工具,在后面的章节中会穿插介绍。

1.3.1 安装Android SDK

编译Android的源码并不需要Android SDK,但是Android SDK中附带了很多有用的工具,如adb、ddms、hierarchyviewer等,都是进行Android系统开发调试必须用到的。

Android SDK需要从Android的官方网站中下载,下载解压缩后可以将SDK目录下的platform_tools和tools两个子目录的路径加入到Ubuntu的PATH环境变量中,方便以后使用。

1.3.2 安装Android Studio

Android Studio是Google用来代替Eclipse的集成开发工具,它是Google基于著名的IntelliJ IDEA修改而来。IntelliJ IDEA是付费软件,但是Android Studio可以免费使用。到目前为止,Android Studio最新的版本是0.8.14。

系统级别的软件开发使用Android Studio或Eclipse的目的并不是用来生成APK文件。主要原因是使用这种集成开发工具书写Java代码更加方便快捷,开发效率能成倍提高,但是系统级别的Java开发会用到很多Android的内部类,这些类在SDK中不存在,因此,使用Android Studio时会报错。解决的方法是从Android的源码编译结果中找到对应的系统类库,添加到Android Studio的项目依赖库中就可以了。需要注意的是,这种方式只是用来解决编译问题,最后产生的APK文件并不能直接使用。

Android Studio可以从Android官网中下载。

1.3.3 安装Source Insight

SourceInsight是Windows平台上优秀的源码分析工具,目前最新的版本是3.50.0072。读者可以从其官方网站www.sourceinsight.com下载。

SourceInsight是分析Android源码的利器。如果遇到本书中介绍的一些函数不知道在哪个文件中,使用SourceInsight能很方便地搜索出来。Android的源码非常庞大,制作SourceInsigh项目时,不用把源码目录下所有文件都添加进去,特别是prebuilts目录下的文件,这样能加快检索速度。

1.3.4 安装比较工具Meld

在系统开发过程中,经常需要对比不同的版本,进行合并操作等。笔者在Linux下使用的工具是Meld。Meld可以通过如下命令安装:

      # sudo apt-get install meld

1.4 下载源码

对于国内的开发者而言,下载Android的源码从来不是一件简单的事。因为一些原因,目前国内已经不能访问Android的源码网站了,最近好像连Android的官方网站也访问不了。对公司而言这不是难题,因为很多公司都有国外的VPN账号或者海外服务器。笔者下载Android的源码就是通过亚马逊的云服务器完成的。只要有国内大型银行的信用卡帐号,就可以在亚马逊平台上免费开通一个EC2服务器(免费使用期一年)。亚马逊提供的带宽差不多有一个G,不到半个小时就能下载完所有源码,去掉.repo目录后打包的Android 5.0源码大概有6GB左右(比Android 4.4的压缩代码包大了近2GB)。虽然下载代码到云服务器非常快,但是从国外的服务器下载到本地还需要10多个小时。

需要注意的是:亚马逊提供的试用服务器虽然免费,但也有限制条件。首先是流量,流入云服务器的流量是免费的,但是流出的流量每月只有15GB是免费的,超出的部分需要收费,因此,不要通过在云服务器上建代理的方式下载源码,这样将会消耗掉20GB以上的流量。其次,免费的EC2服务器缺省的存储空间比较小,无法下载完所有源码,创建服务器时要注意扩大存储空间,扩大的空间也会按时间收取少量费用,下载完成后尽快关闭服务器,以免产生过多费用。

亚马逊的云服务器可以免费试用一年,如果使用得当,每个月的免费流量至少可以下载两套完整的Android源码。而且亚马逊的云服务器可以按小时租用,即使免费时间使用完了,租十几个小时的时间来下载源码所花费的费用也非常小,个人完全可以承受。

1.4.1 Git and Repo简介

Git最初是Linus Torvalds为了帮助管理Linux内核开发编写的一个开放源码的版本控制软件。Git功能强大,很适合分布式开发,但是它的命令比较艰涩难懂,新手学习起来有一定的困难。Repo是Google开发的一个脚本文件,只是在Git基础上封装了一层,用来简化Git下载Android源码的过程。如果只需要下载Android源码,可以不用深入学习Git,了解Repo的使用方法就可以了(下载Kernel的源码还是要用到Git命令)。如果希望能够自由,有选择性地下载源码,就需要系统学习Git的使用方法。介绍Git的书籍有很多,本书就不涉及了,这里只介绍Repo的使用方法。

首先通过curl下载Repo的最新版本,具体命令如下:

      curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo

下载完Repo脚本后,使用下面的命令修改文件的属性为“可执行”:

      # chmod a+x ~/bin/repo

Repo的用法很简单,下面是最常用的几个命令。

(1)Repo help命令。

格式为Repo help [ command ]。例如“repo help init”将显示init命令的参数和用法。

(2)Repo init命令。

Repo init命令可以有很多参数,-u参数用来初始化软件仓库,例如:

      repo init -u git://android.git.kernel.org/platform/manifest.git

-b参数来指定某个分支,不指定则默认为master分支,例如:

      repo init -u git://android.git.kernel.org/platform/manifest.git -b android5.0.1

init命令其他的一些参数不太常用,这里就不介绍了。

(3)Repo sync命令。

Repo sync命令用来同步代码。可以使用-j参数来启动多个线程同时下载,例如:

      repo sync -j4

这条命令将会使用8个线程来同时下载。

1.4.2 源码版本历史

Android源码版本历史如表1.1所示。

表1.1 Android版本代号和版本编号对照表

表1.1摘自Android的官方网站。从表1.1可以看到Android版本的发展历程。Android对重大的升级都赋予了一个代号,有趣的是每个代号都是一种甜点的名称,Android 5.0的代号是Lollipop“棒棒糖”,而且名称的首字母按照字母顺序排列。Android的很多版本都是昙花一现,立即就被新版本代替了,市场上使用其开发的手机很少。所有版本中,比较著名的是Android 1.5, Android 2.1, Android 2.3和Android 4.2,市场上使用这些版本的设备比较常见。

除了大的版本外,每个版本可能还会有好几个分支,每个分支就是一个小的升级版本,主要是修复Bug和小范围的功能调整。

1.4.3 下载Android源码

在下载代码前,需要知道版本的分支名。通过Repo可以查看所有分支名,例如:

      # repo init -u https://android.googlesource.com/platform/manifest

运行结果如图1.3所示,从里面可以找到需要下载的分支名,例如:android-5.0.0_r1。

▲图1.3 运行的结果

注意

Repo的init指令运行后会在当前目录下创建一个隐藏目录.repo。重新执行init指令前必须先删除这个隐藏目录,否则执行会失败。

下载源码的命令序列如下:

      # mkdir android5.0
      # cd android5.0
      # repo init -u https://android.googlesource.com/platform/manifest -b android-5.0.0_r1
      # repo sync

如果需要通过代理服务器下载,可以使用下面的命令来设置Linux的环境变量:

      # export HTTP_PROXY = http://<user_id>:<password>@<proxy_server>:<proxy_port>
      # export HTTPS_PROXY = http://<user_id>:<password>@<proxy_server>:<proxy_port>

1.4.4 下载Kernel源码

Android的源码包中没有包含Kernel的源码,虽然Android的代码是通用的,但是每种设备的Kernel代码都有比较大的差异。和PC比较,手机的主板并没有一个兼容标准,不同的厂家即使使用同一种解决方案,最后生产的主板也有很大差异。Google的手机设备是不同的厂家代工生产的,使用的芯片解决方案也不相同。到目前为止,Google所有设备的Kernel源码都放在下面这些Git库中,可以用Git的clone命令复制一份到本地:

      # git clone https://android.googlesource.com/kernel/common.git
      # git clone https://android.googlesource.com/kernel/exynos.git
      # git clone https://android.googlesource.com/kernel/goldfish.git
      # git clone https://android.googlesource.com/kernel/msm.git
      # git clone https://android.googlesource.com/kernel/omap.git
      # git clone https://android.googlesource.com/kernel/samsung.git
      # git clone https://android.googlesource.com/kernel/tegra.git

其中goldfish.git是模拟器的内核代码库。

这些Git库的分类基于芯片解决方案,因此,只需要下载自己手机对应的Git库就可以了。例如,笔者曾经使用的Galaxy Nuxes手机是由三星代工的,所用的方案是omap,需要clone的Git库就是omap.git。

通常大家熟知的是设备的代号,例如Nexus 5、Nexus 7等,但是Google的同一款设备可能会有多个型号,不同型号的主板功能也有区别,Kernel可能一样也可能不一样。

表1.2是Google所有设备型号,Kernel位置和Kernel源码仓库的对照表。

表1.2 Google设备和kernel对照表

通过表1.2可以很容易地找到Google设备对应的Git库。clone完成后还需要使用Git的checkout命令“检出”代码。checkout命令需要用“分支名称”作为参数,“分支名称”可以通过Git的branch命令查到,例如:

      # git branch -a

这条命令将列出所有分支,知道了分支名后,就可以使用checkout命令来检出代码了,如下所示:

      # git checkout branch_name

在Android的源码中,通常会包含有某个Android手机的Kernel文件,如果需要下载和这个Kernel文件对应的源码版本(这样下载的源码版本和某款具体的设备更加匹配),可以通过下面的方法进行。

下面以Nexus 7(grouper)为例介绍如何下载它的Kernel文件对应的源码。

首先,输入下面的命令:

      # cd android                    // 进入下载好的Android源码根目录
      # cd device/asus/grouper        // 进入Kernel image所在目录
      # git log kernel                // 查看Kernel的提交记录

最后一条命令会显示以下内容:

      commit e39a27e473b7ffe1aedf85f4f005d0be7d8a7a9e
      Author: The Android Open Source Project <initial-contribution@android.com>
      Date:   Wed Oct 30 10:59:08 2013 -0700
          Snapshot to f4f5f74b6273db81d4091632ad7cec1fc290e0f2
      commit 4a0eb239e802bc20c2d2101217170879440b8e99
      Author: The Android Open Source Project <initial-contribution@android.com>
      Date:   Wed Oct 30 10:52:08 2013 -0700
          Snapshot to 6cfc880236a05b22f25353b22132f1ea64a56dee
      commit 954cdaf3b1671ccf49d42cd605e94b2b20d90e89
      Author: Ed Tam <etam@google.com>
      Date:   Tue Jun 11 23:58:25 2013 -0700
          grouper: update kernel prebuilt
          1e8b3d8 ashmem: avoid deadlock between read and mmap calls
          Bug: 9261835
          Change-Id: Ib81a9419dfd1659520306011d0be37e6ffacec6f
      :debug2: client_check_window_change: changed
      debug2: channel 0: request window-change confirm 0

这是Google的工程师对Nexus 7(grouper)的Kernel image文件的提交记录,其中就记录了image文件对应的Kernel源码的分支。在这个例子里是“1e8b3d8”。知道了分支名,就可以开始下载Kernel的源码了。使用如下命令完成:

# git clone https://android.googlesource.com/kernel/tegra.git

# cd tegra

# git checkout le8b3d8

整个过程看上去有点难,其实明白原理就不是太难了。可能读者会问,我的手机不是Google出品的,怎么才能得到Kernel的源码呢?Android的Kernel源于Linux,根据Linux的开源协议,所有Android设备的Kernel源码也需要公开。一般大型公司都会遵守这个协议,读者只要到相应公司的网站上搜索,通常可以找到。