编译aosp 的辛酸
这几天想编译一个能脱壳的 aosp (Android源码),我进行了如下尝试:
1、用我的Mac(15年15寸的那款,当前MacOS 版本为 10.15.2 (19C57))从6.0 编译到9.0 ,就一个 8.0.0_r2 编译成功了。又是下载 MacOSX10.12.sdk 又是搞 bison 补丁的、乱七八糟
2、后来看aosp官网推荐说Docker 也可以编译,所以抱着试试看的态度,就想搞个Docker 试试,源码里面的Dockerfile,结果 编译镜像的时候报错 groupadd: GID '20' already exists
,从语义上来说,不就是GID 冲突吗,阅读Dockerfile 改掉,改成了3000,镜像倒是编译成功了,但是编译源码各种错误,一个也没成功,据说Mac 下的docker和Linux下的docker还是有区别的。算了搞个Linux吧。
3、VM ware Fusion Mac上的虚拟机,然后里面按照Ubuntu,编译依然出错,经过一番搜索,我发现我解决不了,现在回过头来想想应该是移动硬盘格式化不对,我为了编译Android源码,特意买了个移动硬盘,然后格式化成,区分大小写的 Mac 格式,然后把,7.0,8.0,9.0 的源码下载下来,(https://www.jianshu.com/p/53e590eb237a),然后虚拟机和Mac选择共享目录的方式,现在想想应该用虚拟磁盘的方式就可以了
4、搞个真实的Ubuntu系统吧。。Mac 上安装双系统在移动硬盘
官方推荐编译方式
主要分为这么几步
0、我搞了个移动硬盘,格式化成了ext4格式,如果电脑硬盘够,那就不用移动硬盘了
1、先在Ubuntu 18.04 上下载Android 源码
2、在Ubuntu 18.04 上安装docker,并制作用于编译aosp的镜像
3、启动docker 镜像,映射本地aosp源码目录到docker 目录
源码下载
官网的方式里面,是下载aosp 到 本地磁盘,然后交互模式启动Linux(ubuntu:14.04)的docker镜像,然后把 本地文件夹和 docker Ubuntu 下的文件夹做映射,从而docker Ubuntu能够直接读取本机上的文件。
1、下载 repo 工具:
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
2、建立工作目录:
我用的是移动硬盘来存储aosp源码,并且在Ubuntu下把硬盘挂载到了 ~/Desktop/aosp/
cd ~/Desktop/aosp/
mkdir android-8.0.0_r2
cd android-8.0.0_r2
3、初始化仓库
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest
## 如果提示无法连接到 gerrit.googlesource.com,可以编辑 ~/bin/repo,把 REPO_URL 一行替换成下面的:
## REPO_URL = 'https://gerrit-googlesource.proxy.ustclug.org/git-repo'
如果需要某个特定的 Android 版本(Android 版本列表),可以通过下面的方式指定版本号,如果不指定则代码下载当前最新的代码。
repo init -u git://mirrors.ustc.edu.cn/aosp/platform/manifest -b android-8.0.0_r2
4、步源码树(以后只需执行这条命令来同步)如果中途出现网络错误,可以停止后在执行下面的命令:
repo sync
等待下载吧,漫长的过程。。。
如果想要编译真机的系统还要下载真机对应驱动,对应关系从这两个地址获取 https://source.android.google.cn/setup/start/build-numbers#source-code-tags-and-builds 和 https://developers.google.cn/android/drivers
制作docker镜像
- Ubuntu 是上安装 docker (略)
- docker 的基本命令 && 生成docker 镜像 Dockerfile 的编写方式(略)
- 启动docker
- 打包 docker 对应的Android编译环境的docker镜像
- 官网地址 https://android.googlesource.com/platform/build/+/master/tools/docker 打不开,不要慌,我摘录一下
# 先创建一个文件夹,这个文件夹用于docker打包用,不创建也没关系,为了环境干净而已
$ mkdir docker
# 然后把官网下载的Dockerfile 移动到当前目录下,没有的话可以下载git并配置
# Copy your host gitconfig, or create a stripped down version
# 把当前Mac电脑的git配置copy到当前环境,以便于传递到docker镜像里面用
$ cp ~/.gitconfig gitconfig
# 创建一个 名字叫做 android-build-trusty 的docker 镜像,名字可以随便取
$ docker build --build-arg userid=$(id -u) --build-arg groupid=$(id -g) --build-arg username=$(id -un) -t android-build-trusty .
官网 Dockerfile 摘录入下,<font color=red>这里面的两个url可能因为某些不可抗因素不能访问请自信替换</font>:
jdk 的url可以自己网上找个 open jdk8 的压缩包就行。记住是openjdk8
repo 的地址可以用科大的镜像替换 ,做好能直接访问,替换url之后,需要修改Dockerfile的脚本,把验证hash的地方替换掉。我直接用的官网的。
FROM ubuntu:14.04
ARG userid
ARG groupid
ARG username
RUN apt-get update && apt-get install -y git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip python openjdk-7-jdk
RUN curl -o jdk8.tgz https://android.googlesource.com/platform/prebuilts/jdk/jdk8/+archive/master.tar.gz \
&& tar -zxf jdk8.tgz linux-x86 \
&& mv linux-x86 /usr/lib/jvm/java-8-openjdk-amd64 \
&& rm -rf jdk8.tgz
RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo \
&& echo "d06f33115aea44e583c8669375b35aad397176a411de3461897444d247b6c220 /usr/local/bin/repo" | sha256sum --strict -c - \
&& chmod a+x /usr/local/bin/repo
RUN groupadd -g $groupid $username \
&& useradd -m -u $userid -g $groupid $username \
&& echo $username >/root/username \
&& echo "export USER="$username >>/home/$username/.gitconfig
COPY gitconfig /home/$username/.gitconfig
RUN chown $userid:$groupid /home/$username/.gitconfig
ENV HOME=/home/$username
ENV USER=$username
ENTRYPOINT chroot --userspec=$(cat /root/username):$(cat /root/username) / /bin/bash -i
下面是我修改后的,
FROM ubuntu:14.04
ARG userid
ARG groupid
ARG username
RUN apt-get update && apt-get install -y git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip python openjdk-7-jdk
## 这里
RUN curl -o jdk8.tgz http://weishu.dimensionalzone.com/jdk8-master.tar.gz \
&& tar -zxf jdk8.tgz linux-x86 \
&& mv linux-x86 /usr/lib/jvm/java-8-openjdk-amd64 \
&& rm -rf jdk8.tgz
## 和这里
RUN curl -o /usr/local/bin/repo http://weishu.dimensionalzone.com/repo \
#&& echo "e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5 /usr/local/bin/repo" | sha256sum --strict -c - \
&& chmod a+x /usr/local/bin/repo
RUN groupadd -g $groupid $username \
&& useradd -m -u $userid -g $groupid $username \
&& echo $username >/root/username \
&& echo "export USER="$username >>/home/$username/.gitconfig
COPY gitconfig /home/$username/.gitconfig
RUN chown $userid:$groupid /home/$username/.gitconfig
ENV HOME=/home/$username
ENTRYPOINT chroot --userspec=$(cat /root/username):$(cat /root/username) / /bin/bash -i
开始编译
启动一个docker 实例:
# 配置一个变量,标志 Android 源码的位置,这个路径自己配置,这个就是上面下载的源码的路径
$ export ANDROID_BUILD_TOP=~/Desktop/aosp/android-8.0.0_r2
# docker 启动命令,以交互模式启动docker,
# 并且映射 真机下 $ANDROID_BUILD_TOP 指向的路径 到 docker Ubuntu 下的 /src目录
# 从而在docker Ubuntu 里面访问 /src 就会直接访问真机 下的 $ANDROID_BUILD_TOP
$ docker run -it --rm -v $ANDROID_BUILD_TOP:/src android-build-trusty
理论上来说这时候命令行就进入了docker 内部,这时候的shell 是 Ubuntu的shell了,接下来开始编译:
$ cd /src # ls 一下观察是不是下载的Android源码
# 下面是编译 aosp 的基本命令,和直接编译没啥区别
$ source build/envsetup.sh
# 直接指定编译的版本类型,或者输入 lunch 之后再选则,我编译的是个模拟器 aosp_arm64-eng
$ lunch aosp_arm-eng
$ m -j50
- 7.1.1 7.x 的代码,下载到90%多的时候,特别慢、
- 8.0.0 源码文件在我的机械硬盘上,大概编译了4小时32分,总共有73575 个文件。
- 9.0.0 编译正常,感觉9.0 的docker编译比较快,总体文件没法统计了,我编译了一次因为内存崩溃了,后来再编译可能会使用缓存文件
我500G的硬盘,竟然没法编译完,这三个版本的系统,编译过程提示硬盘空间不足,于是我就把,三个源码的下的 .repo 文件夹都删除了,以后不再更新就是了
错误处理
7.1.1_r20 问题
同 8.0.0_r2 ,
9.0.0_r46
8.0.0_r2
8.0 编译出现如下错误
FAILED: out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack
/bin/bash -c "(mkdir -p out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack.tmpjill.res ) && (unzip -qo prebuilts/sdk/16/android.jar -d out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack.tmpjill.res ) && (find out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack.tmpjill.res -iname \"*.class\" -delete ) && (JACK_VERSION=4.31.CANDIDATE out/host/linux-x86/bin/jack @build/core/jack-default.args -D jack.import.resource.policy=keep-first -D jack.import.type.policy=keep-first -D jack.android.min-api-level=16 --import prebuilts/sdk/16/android.jar --import-resource out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack.tmpjill.res --output-jack out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack ) && (rm -rf out/target/common/obj/JAVA_LIBRARIES/sdk_v16_intermediates/classes.jack.tmpjill.res )"
out/host/linux-x86/bin/jack: line 80: USER: unbound variable
解决方法 :
export USER=$(whoami)
https://blog.csdn.net/RonnyJiang/article/details/55812305?locationNum=15&fps=1
刷机
这时候不用在docker 下了,因为接下来就算文件操作
设置 ANDROID_PRODUCT_OUT 环境变量,就是编译后生成的img文件的路径
adb reboot bootloader
$ fastboot flashall -w