Brillo: 在RPi 2B/3B上通过fastboot更新系统

在Android设备上,我们可以通过fastboot命令,可以很方便地更新整个系统系统或者是单独的一个分区。在RPi 2B/3B上,我也想实现类似这样的系统更新机制,不需要使用adb命令,通过shell命令进行更新。同时由于RPi 2B/3B由于没有USB slave接口,也就无法像其他的Android设备一样,连接上USB口就可以进行系统更新。

从https://android.googlesource.com/device/pifoundation/rpi3/ 可以看到,官方很快就支持Android/Brillo系统了,也是一个令人很期待的事情。

  • fastboot所支持的数据传输模式

fastboot目前支持这三种数据传输模式:

1. USB - 设备连上电脑,通过fastboot/adb devicesw命令就可以很方便地进行操作

2. TCP -  需要指定设备的名称才能进行操作

3. UDP - 最近才支持的传输模式

毫无疑问通过USB更新最为方便,而通过TCP/UDP更新,设备需要预先设置IP地址,或者是能够自动获取IP地址。你需要知道Android设备的IP地址,进行操作的时候你需要指定设备:

$ fastboot -s tcp:192.168.5.127:5554

NOTE:默认情况下fastboot所使用的TCP/UDP协义的端口号为5554。

  • fastboot更新系统的流程

最常使用的是这几条命令:

1. fastboot flashall

2. fastboot flash boot boot.img

3. fastboot flash system system.img

  • RPi 2B上要实现的模式

1. 分区表信息

由于RPi 3B只能识别MBR分区表,并且第一个分区必须为FAT32文件系统。开机之后,会加载并执行第一个分区中的相关文件,所以第一个分区中的系统为认为是recovery系统,在recovery系统中,我们可以选择要运行的操作系统,recovery系统重启之后就会进入我们所选择的系统。

由参考实现可以看到,在Brillo设备中,分区表基本上所使用的是GPT分区表,并且对于system/data等分区,都会分为a/b两个分区,以便能在无法进入系统时可以选择另外一个分区进入系统进行修复?如果Android系统也使用这种机制,那么得浪费多少空间啊。不知道采用这种机制的意义在哪?

TF card (8GiB) – MBR partition table
Primary
mmcblk0p1
Extended
mmcblk0p5 mmcblk0p6 mmcblk0p7
RECOVERY(384MiB) boot(64MiB) system(256MiB) data(256MiB) OTHER

NOTE:

a. 1MiB = 1024 * 1024 byte

b. 扩展分区中的第一个分区为boot分区,第二个分区为system分区, 第三个分区为data分区

c. 由于编译生成的system image和userdata image的大小为256MiB,所以system与data分区的大小需要大于256MiB

2. 向firewalld service申请开放端口

在recovery系统初始化阶段,/system/etc/init.firewall-setup.sh会关闭所有没有使用到的端口,所以需要通知firewalld service开放我们所需要使用的端口(默认端口号为5554),当然你也可以指定fastbootd的端口号:

# /system/bin/fastbootd --port=31415

在logcat中也有相关的log记录运行的状态:

04-23 03:03:55.893   200   200 I /system/bin/firewalld: Punching hole for TCP port 5554 on interface ''
04-23 03:03:55.889   116   116 I fastbootd: [0423/030355:INFO:fastbootd.cpp(114)] Firewall service is on-line.
04-23 03:03:55.968   116   116 I fastbootd: [0423/030355:INFO:fastbootd.cpp(103)] Successfully opened up port 5554 on interface:

3. 自动重启

RPi 2B/3B开机最开始运行的系统为recovery系统,目的是在其他系统运行时出现问题时,能通过这个系统进行修复。这里也沿用了这种行为,以便我们可以对系统更新时不需要更换TF卡。这里我们设置系统自动重启的时间为在fastbootd Punch TCP hole的8秒之后,这样我们就有机会通过fastboot命令取消重启的操作:只需要fastbootd接收任意一条命令,如:

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 getvar product
product: rpi3b
finished. total time: 0.004s

4. 执行fastboot命令

a. 更新boot和system分区并重启:

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 flashall
target reported max download size of 67108864 bytes
Invalid sparse file format at header magi
--------------------------------------------
Bootloader Version...: 0.1
Baseband Version.....: 
Serial Number........: 
--------------------------------------------
checking product...
OKAY [  0.002s]
sending 'boot' (9080 KB)...
OKAY [  1.018s]
writing 'boot'...
(bootloader) format boot partition ...
(bootloader) mount boot partition ...
(bootloader) extract files to boot partition ...
(bootloader) umount boot partition ...
OKAY [  5.445s]
erasing 'system'...
(bootloader) erase /dev/block/mmcblk0p6:   9/100
(bootloader) erase /dev/block/mmcblk0p6:  19/100
(bootloader) erase /dev/block/mmcblk0p6:  29/100
(bootloader) erase /dev/block/mmcblk0p6:  39/100
(bootloader) erase /dev/block/mmcblk0p6:  49/100
(bootloader) erase /dev/block/mmcblk0p6:  59/100
(bootloader) erase /dev/block/mmcblk0p6:  69/100
(bootloader) erase /dev/block/mmcblk0p6:  79/100
(bootloader) erase /dev/block/mmcblk0p6:  89/100
(bootloader) erase /dev/block/mmcblk0p6:  99/100
(bootloader) erase /dev/block/mmcblk0p6: 100/100
OKAY [  2.398s]
sending sparse 'system' 1/1 (54756 KB)...
OKAY [  5.309s]
writing 'system' 1/1...
OKAY [ 27.006s]
rebooting...

NOTE:

- a. 关于”Invalid sparse file format at header magi” 由于fastbootd支持的最大download size为64MiB, 而system/data image的大小为256MiB, 超过了最大的download size, 需要分批下载,所以fastboot会将system.img/userdata.img转成sparse file, 使得每次下载的数据不 能大于64MiB。

- b. boot.img不能进行分批下载,所以大小不能超过64MiB。

- c. boot分区使用的是FAT32文件系统,在download完boot.img后,会使用newfs_msdos命令将boot分区格式化成FAT32文件系统:

04-23 03:13:52.451   116   116 I newfs_msdos: /system/bin/newfs_msdos: warning, /dev/block/mmcblk0p5 is not a character device
04-23 03:13:52.451   116   116 I newfs_msdos: /system/bin/newfs_msdos: Skipping mount checks
04-23 03:13:52.452   116   116 I newfs_msdos: /dev/block/mmcblk0p5: 129022 sectors in 129022 FAT32 clusters (512 bytes/cluster)
04-23 03:13:52.452   116   116 I newfs_msdos: bps=512 spc=1 res=32 nft=2 mid=0xf0 spt=16 hds=4 hid=0 bsec=131072 bspf=1008 rdcl=2 infs=1 bkbs=2

- d. 在实现过程中也发现了除了在使用fdisk分区时将boot分区标记为FAT32分区,需要使用FAT32文件系统外,还发现不是所有类型的FAT32文件系统都支持,需要指定block size为512字节,否则还是不能开机的:

# /system/bin/newfs_msdos -F 32 -L boot -b 512 -A /dev/block/mmcblk0p5

- c. 看起来fastboot在执行重启命令会失败

b. 可以单独更新boot分区、system分区和data分区:

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 flash boot boot.img
target reported max download size of 67108864 bytes
sending 'boot' (9080 KB)...
OKAY [  1.030s]
writing 'boot'...
(bootloader) format boot partition ...
(bootloader) mount boot partition ...
(bootloader) extract files to boot partition ...
(bootloader) umount boot partition ...
OKAY [  4.185s]
finished. total time: 5.216s

c. 也可以单独去擦除这几个分区:

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 erase data
******** Did you mean to fastboot format this ext4 partition?
erasing 'data'...
(bootloader) erase /dev/block/mmcblk0p7:   9/100
(bootloader) erase /dev/block/mmcblk0p7:  19/100
(bootloader) erase /dev/block/mmcblk0p7:  29/100
(bootloader) erase /dev/block/mmcblk0p7:  39/100
(bootloader) erase /dev/block/mmcblk0p7:  49/100
(bootloader) erase /dev/block/mmcblk0p7:  59/100
(bootloader) erase /dev/block/mmcblk0p7:  69/100
(bootloader) erase /dev/block/mmcblk0p7:  79/100
(bootloader) erase /dev/block/mmcblk0p7:  89/100
(bootloader) erase /dev/block/mmcblk0p7:  99/100
(bootloader) erase /dev/block/mmcblk0p7: 100/100
OKAY [  2.490s]
finished. total time: 2.490s

d. 重启命令:

执行fastboot reboot/fastboot reboot-bootloader后会进入recovery系统

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 reboot

c. 进入Brillo系统

执行fastboot continue命令会重启系统进入Brillo系统

hzak@B85EMU:/local/brillo-m10-dev-rpi3b/out/target/product/rpi3b$ fastboot -s tcp:192.168.5.127 continue
  • 演示模式

如果在recovery分区中存在名为DEMO的文件,则会进入演示模式(fastbootd不会使系统重启)。同时也可以在演示模式下更新系统。

2016_04_29_brillo_m10_dev@rpi2b

编译好的system image可以从这里下载:

https://github.com/brobwind/bin-brillo-m10-dev-rpi3b

相关的代码可以这里下载:

https://github.com/brobwind/brillo-m10-dev-rpi3b

recovery分区的目录结构如下:

RECOVERY(/dev/block/mmcblk0p1)
+-- bcm2709-rpi-2-b.dtb
+-- bcm2710-rpi-3-b.dtb
+-- bootcode.bin
+-- config.txt
+-- COPYING.linux
+-- DEMO
+-- fixup.dat
+-- kernel7.img
+-- LICENCE.broadcom
+-- ramdisk7.img
+-- recovery-rpi-2-b.txt
+-- recovery-rpi-3-b.txt
+-- start.elf
`-- system.img

在 RPi 3B上运行时的kernel log如下:

--------- beginning of kernel
01-01 00:00:00.000     0     0 I         : Initializing cgroup subsys cpuset
01-01 00:00:00.000     0     0 I         : Initializing cgroup subsys cpu
01-01 00:00:00.000     0     0 I         : Initializing cgroup subsys cpuacct
01-01 00:00:00.000     0     0 I         : Linux version 4.1.19-v7+ (hzak@B85RPI) (gcc version 4.9 20150123 (prerelease) (GCC) ) #1 SMP Fri Apr 29 13:25:47 EDT 2016
01-01 00:00:00.000     0     0 I         : CPU: ARMv7 Processor [410fd034] revision 4 (ARMv7), cr=10c5383d
01-01 00:00:00.000     0     0 I         : CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
01-01 00:00:00.000     0     0 I Machine model: Raspberry Pi 3 Model B Rev 1.2
01-01 00:00:00.000     0     0 I cma     : Reserved 8 MiB at 0x3a400000
01-01 00:00:00.000     0     0 I Memory  : Data cache writealloc
01-01 00:00:00.000     0     0 D         : On node 0 totalpages: 241664
01-01 00:00:00.000     0     0 D free_area_init_node: node 0, pgdat 80ea8580, node_mem_map b9bb4000
01-01 00:00:00.000     0     0 D         : Normal zone: 2124 pages used for memmap
01-01 00:00:00.000     0     0 D         : Normal zone: 0 pages reserved
01-01 00:00:00.000     0     0 D         : Normal zone: 241664 pages, LIFO batch:31
01-01 00:00:00.000     0     0 W         : [bcm2709_smp_init_cpus] enter (101480->f3003010)
01-01 00:00:00.000     0     0 W         : [bcm2709_smp_init_cpus] ncores=4
01-01 00:00:00.000     0     0 I PERCPU  : Embedded 11 pages/cpu @baecc000 s21056 r0 d24000 u45056
01-01 00:00:00.000     0     0 D pcpu-alloc: s21056 r0 d24000 u45056 alloc=11*4096
01-01 00:00:00.000     0     0 D pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
01-01 00:00:00.000     0     0 I         : Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 239540
...
  • 相关的参考文档
  1. https://android.googlesource.com/platform/system/core/+/brillo-m10-dev/fastboot/fastboot_protocol.txt

《Brillo: 在RPi 2B/3B上通过fastboot更新系统》有3个想法

  1. 一般的uboot都只支持usb的fastboot,你这个支持ethernet的fastboot有源码么

    1. 有的,fastboot相关代码在https://github.com/brobwind/brillo-m10-dev-rpi3b/tree/master/bsp/fastbootd
      运行在brillo系统上,作为一个service(fastbootd)运行

发表评论

电子邮件地址不会被公开。 必填项已用*标注