在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不会使系统重启)。同时也可以在演示模式下更新系统。
编译好的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
...
- 相关的参考文档
- https://android.googlesource.com/platform/system/core/+/brillo-m10-dev/fastboot/fastboot_protocol.txt