安卓编译简记

qq群里 @随风破浪 编译安卓一星期未果,我之前的开发机上的lichee目录又不小心被覆盖了,所以抽空简单记录下如何在原始sdk的基础上 修改适配,成功编译出可以跑在荔枝派上的安卓系统。

1. 编译环境准备

开发机系统要求

编译安卓需要64位linux系统,推荐ubuntu 1404或者1604, 开发机至少需要4GB内存,40GB硬盘;推荐8GB内存,100GB硬盘以上。 以下是开发过程中目录大小示意:

zp@ubuntu:~/develop$ du -lh --max-depth=1 v1.5.0/
26G v1.5.0/android
6.8G    v1.5.0/lichee
33G v1.5.0/

zp@ubuntu:~/develop$ du -lh --max-depth=1 a13_android4.1_v1.2/
5.2G    a13_android4.1_v1.2/lichee
23G a13_android4.1_v1.2/android4.1
28G a13_android4.1_v1.2/

开发机的CPU配置尽量高,笔者12线程并行编译,配以ssd,首次编译需要45分钟

网友双线程编译,耗时4小时左右。

开发机软件环境

首先安装开发所需要的软件包和一些库。 下面的一些安装包可能有些过时的,遇到版本问题请自行解决。

在线安装 JDK6.0

sudo add-apt-repository "deb http://archive.canonical.com/ lucid partner"
sudo add-apt-repository ppa:ferramroberto/java
sudo apt-get update
sudo apt-get install sun-java6-jdk
sudo update-alternatives --c  onfig java

在线安装编译库

sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev
lib32ncurses5-dev ia32-libs  x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev
g++-multilib mingw32 tofrodos python-markdown libxml2-utils

SDK下载

链接: http://pan.baidu.com/s/1c4gztvE

在SDK目录下 下载以下两个文件

lichee-4.1-v1.2.tar.gz
android4.1-v1.2.tar.gz

这是安卓4.1的SDK,前面的是4.2的SDK,

我手上的4.2 SDK的mali驱动ko和应用层库so版本对不上,换了从4.1里抠出的对应版本的so后,可以勉强启动系统,但是会不定时地出现缓冲队列满的问题导致ANR,所以暂时无法使用

在开发机上新建目录,如a13_android4.1 然后把两个sdk拷入,解压

把lichee对应的目录名改成lichee(即去掉版本号),目录如下所示

zp@ubuntu:~/develop/a13_android4.1_v1.2$ ls
android4.1  lichee

2. lichee编译

lichee是安卓系统的linux内核部分,需要首先编译,进入lichee目录执行:

./build.sh -p a13_nuclear -k 3.0
./build.sh pack

编译错误解析 编译过程中会出错,每个人由于其开发环境以及执行步骤的不同,错误都可能不同,下面以我编译时遇到的错误为例进行解析

  • mali驱动编译出错
make: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali'
/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0
make -C DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump CONFIG=ca8-virtex820-m400-1 BUILD=release KDIR=/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0
make[1]: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump'
make -C /home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0 M=/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump modules
make[2]: Entering directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0'
  CC [M]  /home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump/common/ump_kernel_common.o
arm-none-linux-gnueabi-gcc: directory: No such file or directory
arm-none-linux-gnueabi-gcc: directory": No such file or directory
<command-line>:0:16: warning: missing terminating " character
make[3]: *** [/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump/common/ump_kernel_common.o] Error 1
make[2]: *** [_module_/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump] Error 2
make[2]: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump'
make: *** [build] Error 2
make: Leaving directory `/home/zp/develop/a13_android4.1_v1.2/lichee/linux-3.0/modules/mali'

real    2m35.400s
user    15m36.416s
sys 0m35.740s

进入排除可知是脚本里检查了SVN版本的问题,我们直接忽略SVN版本,将linux-3.0/modules/mali/DX910-SW-99002-r3p1-01rel0/driver/src/devicedrv/ump 目录下的SVN_REV直接赋值为0(在Kbuild和Makefile.common中)

重新编译,仍然是类似的错误,只是换了个目录,于是直接在mali驱动目录下全局搜索SVN_REV,将赋值的地方直接改为0

再重新编译成功

mkdir: created directory ‘/home/zp/develop/a13_android4.1_v1.2/lichee/out’
‘/home/zp/develop/a13_android4.1_v1.2/lichee/u-boot/u-boot.bin’ -> ‘/home/zp/develop/a13_android4.1_v1.2/lichee/out/android/u-boot.bin’
###############################
#         compile success     #
###############################

real    0m51.177s
user    1m1.324s
sys 0m4.736s

3. 安卓编译

进入安卓目录,执行以下命令序列:
source build/envsetup.sh        #导入一些环境变量
lunch       #选择板型,直接选择10. nuclear_evb-eng,以后也直接在上面改
extract-bsp    #将lichee中编译得到的内核镜像和模块拷贝过来
time make -j12 2>&1  | tee log.txt   #编译system.img,这里-j12换成你电脑的线程数(核数*2)。12线程耗时约
pack     #打包成刷机镜像

编译system.img成功的提示:

Creating filesystem with parameters:
    Size: 536870912
    Block size: 4096
    Blocks per group: 32768
    Inodes per group: 8192
    Inode size: 256
    Journal blocks: 2048
    Label: 
    Blocks: 131072
    Block groups: 4
    Reserved block group size: 31
Created filesystem with 1443/32768 inodes and 102168/131072 blocks
+ '[' 0 -ne 0 ']'
Running:  mkuserimg.sh -s out/target/product/nuclear-evb/system out/target/product/nuclear-evb/obj/PACKAGING/systemimage_intermediates/system.img ext4 system 536870912
Install system fs image: out/target/product/nuclear-evb/system.img
out/target/product/nuclear-evb/system.img+out/target/product/nuclear-evb/obj/PACKAGING/recovery_patch_intermediates/recovery_from_boot.p maxsize=548110464 blocksize=4224 total=412271984 reserve=5537664

real    36m1.948s
user    350m4.772s
sys 14m16.936s

pack打包成功的提示:

/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/pctools/linux/eDragonEx//home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/outBuildImg 0
Dragon execute image.cfg SUCCESS !
CPlugin Free lib
CPlugin Free lib
---------image is at-------------

/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/sun5i_android_a13-evb.img

编译错误解析

  1. 注意如果编译时突然中断,则可能出现文件截断的情况,需要先清空out 下子目录中的的obj目录,才好继续编译

例如下面错误就是:

target thumb C++: camera. <= device/softwinner/common/hardware/camera/HALCameraFactory.cpp
In file included from device/softwinner/common/hardware/camera/CameraHardwareDevice.h:26:0,
                 from device/softwinner/common/hardware/camera/HALCameraFactory.cpp:30:
device/softwinner/common/hardware/camera/CameraHardware.h:29:23: fatal error: videodev2.h: No such file or directory
compilation terminated.
make: *** [out/target/product/generic/obj/SHARED_LIBRARIES/camera._intermediates/HALCameraFactory.o] Error 1
make: *** Waiting for unfinished jobs....
  1. 在pack时遇到以下错误(虽然不导致编译失败,但是启动时会造成错误)
fail:/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/out/bootfs/sprite 0 
disk : c
CopyRootToFS(/home/zp/develop/a13_android4.1_v1.2/lichee/tools/pack/out/bootfs)

检查可以发现是lichee/tools/pack/pack中的打包脚本的这句出错: fsbuild bootfs.ini split_xxxx.fex

这个fsbuild在运行时貌似无法打包bootfs的二级目录,不知为何。。有些人却没有反馈有这个问题,应该是个人的环境不同。

由于fsbuild是二进制提供的,只能通过其作用揣测实际功能,经过试验,上面那句可以用以下脚本代替,

基本作用就是构造一个fat文件系统镜像。

dd if=/dev/zero of=bootfs.fex bs=1M count=12
mkfs.vfat bootfs.fex
sudo mount bootfs.fex /mnt
sudo cp -r bootfs/* /mnt
sync
sudo umount /mnt
cat split_xxxx.fex >> bootfs.fex
  1. 分区大小的问题(虽然不导致编译失败,但是启动时会造成错误) 如果往system.img里加入了太多东西,可能导致超出了默认的分区大小(512M),则需要修改默认分区规划

验证system.img的实际大小: simg2img system.img system.bin

如果生成的system.bin大小刚好是512M,并且可以挂载,那就是正常的。 如果大小超过了512M,或者挂载时出错,那么就需要修正分区配置。

配置文件在lichee/tools/pack/chips/sun5i/configs/android/a13-evb/sys_config.fex

修改大小即可。

;------------------------------>nandd, android real rootfs
[partition3]
    class_name  = DISK
    name        = system
    size_hi     = 0
    size_lo     = 524288
    user_type   = 1
    ro          = 0

4. 镜像下载

前面pack打包完成后,会生成sun5i_android_a13-evb.img,这就是刷机镜像

镜像烧录工具是网盘中的PhoenixCard,打开后选择tf卡对应盘符,以及待烧录镜像,选择卡启动,进行烧录

常见烧录错误

偶尔会出现'处理出错'的提示,这时候一般只要重新烧录即可

5. 启动系统的适配过程

通过以上步骤编译的img还是不能在荔枝派上启动的,前面只能算是编译过一遍evb的安卓,需要在荔枝派上启动,还得进行一系列适配工作。

第一次启动(boot1跳转失败)

系统默认串口为UART1,接串口查看信息:

dram size =512
0xffffffff,0xffffffff
super_standby_flag = 0
HELLO! BOOT0 is starting!
boot0 version : 1.5.2
The size of Boot1 is 0x00036000.
Fail in checking boot1.
Ready to disable icache.
Fail in loading Boot1.
Jump to Fel.

可见DDR已被识别,但是加载boot1失败。

这其中的原因是DDR虽然被识别,但是参数配置错误,导致运行出错,所以我们需要先配置正确的DDR参数。

DDR参数记录在sys_config1.fex中,这里不过多解释sys_config1.fex的字段,直接使用之前在debian中适配好的fex文件覆盖

lichee/tools/pack/chips/sun5i/configs/android/a13-evb/sys_config1.fex

然后重新进行安卓编译过程。

编译完成后,可以直接重新烧写完整镜像,也可以只更新uboot和bootfs,后者需要对编译系统比较了解,在此不详细展开。

重新烧录后,可以看到闪过了两个开机画面,说明已经可以启动到linux内核了。

第二次启动(启动介质错误)

按前面修改后,启动会卡在第二张开机画面,查看串口信息:

[   16.009615] init: buffer : /dev/block/nande
[   16.014564] init: do_umount: /data 
[   16.018071] init: do_umount error = Invalid argument
[   17.390045] usb 2-1: device not accepting address 2, error -110
[   17.450200] ehci_irq: port change detect
[   17.454145] ehci_irq: port change detect
[   21.007468] init: buffer : /dev/block/nandh
[   21.012161] init: do_umount: /cache 
[   21.015755] init: do_umount error = Invalid argument
[   21.022007] init: open device error :No such file or directory
[   31.008863] init: buffer : /dev/block/nandi
[   31.013556] init: do_umount: /databk 
[   31.017237] init: do_umount error = Invalid argument
[   31.029268] init: cannot find '/system/bin/sh', disabling 'console'
[   31.035766] init: cannot find '/system/bin/servicemanager', disabling 'servicemanager'
[   31.043742] init: cannot find '/system/bin/vold', disabling 'vold'
[   31.049968] init: cannot find '/system/bin/netd', disabling 'netd'
[   31.056192] init: cannot find '/system/bin/debuggerd', disabling 'debuggerd'
[   31.063282] init: cannot find '/system/bin/rild', disabling 'ril-daemon'
[   31.069987] init: cannot find '/system/bin/surfaceflinger', disabling 'surfaceflinger'
[   31.077943] init: cannot find '/system/bin/app_process', disabling 'zygote'
[   31.084939] init: cannot find '/system/bin/drmserver', disabling 'drm'
[   31.091502] init: cannot find '/system/bin/mediaserver', disabling 'media'
[   31.098387] init: cannot find '/system/bin/dbus-daemon', disabling 'dbus'
[   31.105211] init: cannot find '/system/bin/installd', disabling 'installd'
[   31.112125] init: cannot find '/system/etc/install-recovery.sh', disabling 'flash_recovery'
[   31.120541] init: cannot find '/system/bin/keystore', disabling 'keystore'
[   31.127432] init: cannot find '/system/bin/u3gmonitor', disabling 'u3gmonitor'
[   31.135780] init: cannot find '/system/bin/sh', disabling 'console'

可见是tf卡启动与nand启动的不同造成linux内核挂载根文件系统出错,所以需要修改开机启动脚本,即 *.rc文件

device/softwinner/nuclear-evb/init.sun5i.rc
device/softwinner/nuclear-evb/ueventd.sun5i.rc

将其中的nandX按下面对应关系修改

nanda —— mmcblk0p2
nandb —— mmcblk0p5
nandc —— mmcblk0p6
nandd —— mmcblk0p7
nande —— mmcblk0p8
nandf —— mmcblk0p9
nandg —— mmcblk0p10
nandh —— mmcblk0p11
nandi —— mmcblk0p12

其中有一句挂载剩余空间的替换也对应替换:

#format_userdata /dev/block/nandj NUCLEAR
exec /system/bin/busybox mount -t vfat  /dev/block/mmcblk0p1 /mnt/sdcard

再修改vold.fstab,开机挂载方式,前面两行改成以下,即sd卡0作为sdcard,sd卡2作为外置sd卡

dev_mount       sdcard  /mnt/sdcard     auto    /devices/platform/sunxi-mmc.0/mmc_host
dev_mount       extsd   /mnt/extsd      auto    /devices/platform/sunxi-mmc.2/mmc_host
如果需要修改成sd卡2启动,则还需要修改uboot代码
lichee\u-boot\include\configs中sun5i.a13.h文件中的卡启动定义
#define CONFIG_MMC_SUNXI_SLOT 2

最后修改uboot的环境变量env.cfg(lichee/tools/pack/chips/sun5i/configs/android/default/env.cfg)

将mmc作为启动介质

bootdelay=1
#default bootcmd, will change at runtime according to key press
bootcmd=run setargs_mmc boot_normal#default nand boot
#kernel command arguments
console=ttyS0,115200
nand_root=/dev/system
mmc_root=/dev/mmcblk0p7
init=/init
loglevel=6
#set kernel cmdline if boot.img or recovery.img has no cmdline we will use this
setargs_nand=setenv bootargs console=${console} root=${nand_root} init=${init} loglevel=${loglevel} partitions=${partitions}
setargs_mmc=setenv bootargs console=${console} root=${mmc_root} init=${init} loglevel=${loglevel} partitions=${partitions}
#nand command syntax: sunxi_flash read address partition_name read_bytes
#0x40007800 = 0x40008000(kernel entry) - 0x800(boot.img header 2k)
boot_normal=sunxi_flash read 40007800 boot;boota 40007800
boot_recovery=sunxi_flash read 40007800 recovery;boota 40007800
boot_fastboot=fastboot
#recovery key
recovery_key_value_max=0x13
recovery_key_value_min=0x10
#fastboot key
fastboot_key_value_max=0x8
fastboot_key_value_min=0x2

修改完成后重新编译下安卓

为了省事,可以不下载整个镜像,只更新boot.fex和env.fex(lichee/tools/pack/out下)

在linux下,使用fdisk -l查看tf卡分区:

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1         3448832    15595518     6073343+   b  W95 FAT32   //剩余空间作为u盘
/dev/sdb2   *       73728      106495       16384    6  FAT16  //bootfs,含uboot
/dev/sdb3               1     3448832     1724416   85  Linux extended
/dev/sdb5          106496      139263       16384   83  Linux //env.fex
/dev/sdb6          139264      204799       32768   83  Linux   //boot.fex,含linux内核及ramdisk
/dev/sdb7          204800     1253375      524288   83  Linux   //system分区
/dev/sdb8         1253376     2301951      524288   83  Linux  //data分区
/dev/sdb9         2301952     2334719       16384   83  Linux   //misc分区
/dev/sdb10        2334720     2400255       32768   83  Linux //recovery分区
/dev/sdb11        2400256     2924543      262144   83  Linux  //cache分区
/dev/sdb12        2924544     3448831      262144   83  Linux  //databk分区

所以只需更新两个分区:

root@ubuntu64:/home/zp# dd if=env.fex of=/dev/sdb5
256+0 records in
256+0 records out
131072 bytes (131 kB) copied, 0.097856 s, 1.3 MB/s
root@ubuntu64:/home/zp# dd if=boot.fex of=/dev/sdb6
19916+0 records in
19916+0 records out
10196992 bytes (10 MB) copied, 8.54376 s, 1.2 MB/s
root@ubuntu64:/home/zp# sync

更新之后即可成功进入到安卓系统~

虽然此时可以进入系统,但是很多外设不能运行,这些外设的驱动适配见后面的外设适配解析。