"日常使用的系统是 deepin , 工作中又经常需要编译 Android 系统源码, 在deepin 中编译高版本的 Android 还是可以的,按官方的教程基本没什么问题,但要编译 <= Android5.1 的版本就一堆的问题了。一开始想搞虚拟机来编译,感觉效率还是太低了,刚好最近在学习 ...."

使用 docker 构建 Android 系统编译环境

日常使用的系统是 deepin , 工作中又经常需要编译 Android 系统源码, 在deepin 中编译高版本的 Android 还是可以的,按官方的教程基本没什么问题,但要编译 <= Android5.1 的版本就一堆的问题了。一开始想搞虚拟机来编译,感觉效率还是太低了,刚好最近在学习 docker, 就想是否可以用 docker 来编译 Android呢?网上搜了一下,早就有人这么干了。于是自己也开始折腾了一下, 以下为折腾记录。

以下这些步骤我已经写成 Dockerfile了,如果你懒得看下面这些步骤,直接使用就行。
https://gitee.com/qiushaox/aosp_builder

1. 安装 docker

网上有很多教程都搞得很复杂,其实就一条命令的事:

curl -sSL https://get.docker.com/ | sh

执行完之后试试看

deep@deep-PC:~$ docker version
Client:
 Version:      18.05.0-ce
 API version:  1.37
 Go version:   go1.9.5
 Git commit:   f150324
 Built:        Wed May  9 22:18:05 2018
 OS/Arch:      linux/amd64
 Experimental: false
 Orchestrator: swarm

Server:
 Engine:
  Version:      18.05.0-ce
  API version:  1.37 (minimum version 1.12)
  Go version:   go1.9.5
  Git commit:   f150324
  Built:        Wed May  9 22:16:14 2018
  OS/Arch:      linux/amd64
  Experimental: false
deep@deep-PC:~$

一切正常。

很多 docker 命令都是需要 sudo 来执行的,个人觉得很麻烦,我们可以把自己的用户加入到 docker 组里面,这样就不用每条 docker 命令都要 sudo 了。

sudo usermod -aG docker qiushao

2. 安装基础镜像

google 官方推荐使用 ubuntu 14.04 来进行编译,基本上可以编译所有的 Android系统。我们先拉一个 ubuntu 14.04 镜像回来:

docker pull ubuntu:14.04

然后使用这个镜像启动一个容器:

docker run -it -v ~/data:/home/data ubuntu:14.04 /bin/bash
  • -it 参数表明要进入交互环境
  • -v 参数表示把本地的 ~/data 目录挂载到 docker 容器的 /home/data 目录,这里只是为了方便一会安装 jdk 的时候,可以从宿主机copy jdk 到容器而已。
  • ubuntu:14.04 表示使用哪个镜像
  • /bin/bash 表示容器启动后运行的程序

执行完这个命令之后,我们就会进入一个新创建的容器了,并且有了一个交互环境。
我们可以在里面执行任意ubuntu命令,比如说安装软件,就像一个全新的系统一样。
我们的操作执行完之后, 可以按 ctrl-d 来退出容器。

其实一个容器就像是一个操作系统,我们可以用以下命令来查看宿主机上运行了多少容器

deep@deep-PC:~/soft$ docker container ls --all
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d9bcf2da1d4b        ubuntu:14.04        "/bin/bash"         2 hours ago         Up About an hour                        jolly_goldberg
deep@deep-PC:~/soft$

可以用这个命令来启动/停止容器

docker container start/stop d9bcf2da1d4b

一般来说我们在宿主机重启后是需要用 docker container start 命令来启动容器的。
启动容器之后我们可以执行下面这个命令来进入交互环境,继续完成之前的工作。

docker exec -it d9bcf2da1d4b /bin/bash

你可以理解为启动这个容器里面的一个 shell 进程。

3. 安装编译工具

添加64位系统对32位的支持

  • 检查是否已经支持

    dpkg --print-architecture # 若支持,输出 amd64
    dpkg --print-foreign-architectures # 若支持,输出 i386
    
  • 手动开启支持

    dpkg --add-architecture i386
    apt-get update
    apt-get upgrade
    
  • 安装32位支持库

    apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0
    

添加编译Android源码需要的依赖

apt-get install gcc-multilib g++-multilib build-essential
apt-get install git-core gnupg bison flex gperf pngcrush bc zip curl lzop
apt-get install schedtool libxml2 libxml2-utils xsltproc squashfs-tools
apt-get install libesd0-dev libsdl1.2-dev libwxgtk2.8-dev libswitch-perl
apt-get install libssl1.0.0 libssl-dev lib32readline-gplv2-dev libncurses5-dev

安装 jdk

在宿主机上操作,从 oracle 官网下载 jdk1.6, 放到 ~/data 目录下,因为我们已经把 data 目录挂载到容器了,接下来在容器里面操作

chmod a+x jdk-6u45-linux-x64.bin
./jdk-6u45-linux-x64.bin
mkdir -p /usr/lib/jvm
mv jdk1.6.0_45 /usr/lib/jvm

4.不使用 root 用户进行编译

查看uid,gid

默认情况下,容器是root用户进行登录的,这种情况下编译输出目录out及其子目录是 root 用户权限的。这样我们要在宿主机上修改这个目录的话,就比较麻烦了。我们可以在 docker 里面新创建一个用户,一般来说第一个非 root 用户的 uid 及gid 都是1000, 我们在宿主机上的 uid 和 gid 也是1000。我们可以用这个命令来查看用户的 uid 信息:

deep@deep-PC:~/data/android_source$ id deep  
uid=1000(deep) gid=1000(deep) 组=1000(deep),7(lp),27(sudo),100(users),109(netdev),113(lpadmin),117(scanner),124(sambashare),999(docker)
deep@deep-PC:~/data/android_source$

新建用户

我们在容器里面执行以下命令来创建新用户

useradd -d /home/build -m build
passwd build

然后查看一下新建用户的 uid

id build

发现 build 用户的uid和gid的确也是 1000。linux 的文件权限其实是指定给 uid,gid 的,也就是说只要我们容器里面的 uid 和gid 与宿主机的相同,那我们在容器里面创建的文件在宿主机也是可以随意编辑的。

以指定用户进入容器

当前的容器还是以 root 用户登录的,我们先退出来,然后执行以下命令

docker exec -it -u 1000 479a114fe8a7 /bin/bash

这里 -u 是以指定用户登录的意思,我们指定了以uid 为1000 的用户来进行登录。
登录进去后,发现是 build 用户了, 不是 root 用户了。
我们在 build 用户目录新建一个目录用来挂载 android 源码。

cd 
mkdir android_source

然后再设置 JAVA_HOME, PATH 就行了。

vim .bashrc

加上两行配置

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

至此所需要的编译环境就已经配置完成了。

提交容器保存为镜像

docker commit -m "aosp build env" d9bcf2da1d4b aosp_build:V1.0

使用镜像编译Android系统源码

在宿主机上,创建源码目录 /home/deep/Android/source 目录,并放入Android系统源码。
然后执行以下命令,创建新容器

docker run -it -v /home/deep/Android/source:/home/builder/android_source aosp_build:V1.0 /bin/bash

进入 android 源码目录,就可以按照 android 的标准编译步骤进行编译啦!

cd /home/builder/android_source/aosp_android4.4
source build/envsetup.sh
make -j8

一切正常,一个错误都没有。 goog job!

0     0     0     0     0    
0 回帖