LoginSignup
5
7

More than 5 years have passed since last update.

Brillo A/B update (2面 firmware update) とは?

Posted at

Overview

Brillo では、a/b update という手法で、firmware updateをします。
A/Bとは、かつてのカセットテープのA面/B面から来ていると思われます。

つまり、表面と裏面を用意して、万一firmware update時に、問題が発生しても、元に戻れるというものです。

その仕組みについて迫ってみたいと思います。

build option

以前の記事 でも書きましたがおさらいしておきます。

device/generic/brillo/brillo_base.mk

# Brillo targets use the A/B updater.
AB_OTA_UPDATER := true

# Do not build Android OTA package.
TARGET_SKIP_OTA_PACKAGE := true

# This is the list of partitions the A/B updater will update. These need to have
# two partitions each in the partition table, with the right suffix used by the
# bootloader, for example "system_a" and "system_b".
AB_OTA_PARTITIONS := \
  boot \
  system

このように、2面でupdateするということは、boot_a, boot_b, system_a, system_b のように、partitionが複数あるということです。

  • bootは、linux kernel image + root file system (ramfs)です。
  • systemは、いわゆる/system以下のイメージで、binやlibなども入っています。

2つは、firmwareの一貫性を保つために必要なので、2つ共に必要です。

面白いのは、AOSP masterでは、

# Carry the public key for update_engine if it's a non-Brillo target that
# uses the AB updater. We use the same key as otacerts but in RSA public key
# format.
ifeq ($(AB_OTA_UPDATER),true)
ifeq ($(BRILLO),)
ALL_DEFAULT_INSTALLED_MODULES += $(TARGET_OUT_ETC)/update_engine/update-payload-key.pub.pem
$(TARGET_OUT_ETC)/update_engine/update-payload-key.pub.pem: $(addsuffix .x509.pem,$(DEFAULT_KEY_CERT_PAIR))
    $(hide) rm -f $@
    $(hide) mkdir -p $(dir $@)
    $(hide) openssl x509 -pubkey -noout -in $< > $@
endif
endif

A/Bで、まぁ、当然ですが、鍵は同じもので署名します。

や、まぁ、当然なのですが、以前のbuild ota toolは使わなくなっています。

# Build OTA tools if not using the AB Updater.
ifneq ($(AB_OTA_UPDATER),true)
$(BUILT_TARGET_FILES_PACKAGE): $(built_ota_tools)
endif

HAL

2面を制御するということは、boot loaderが、適切なboot, systemの組み合わせを選んで起動するということです。

というわけで、update後に、boot loaderへ、適切な面を選択するように、通知しなければいけませんが、それは、HALとして抽象化されています。

~/work/brillo/hardware/libhardware$ git show a13a426a7d44f5bae5398f2ffbaa53800511ae31
commit a13a426a7d44f5bae5398f2ffbaa53800511ae31
Author: Rom Lemarchand <romlem@android.com>
Date:   Fri Aug 14 14:58:21 2015 -0700

    boot: Add a boot_control HAL

    The purpose of the boot control HAL is to communicate with the
    bootloader and set various flags letting the bootloader know which
    partition to boot

    Change-Id: I15178abaaf9ca208b1e5300c9207cedbb7950a88
hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*getNumberSlots)() returns the number of available slots.
+     * For instance, a system with a single set of partitions would return
+     * 1, a system with A/B would return 2, A/B/C -> 3...
+     */
+    unsigned (*getNumberSlots)(struct boot_control_module *module);

A/Bではありますが、3面持つことも可能です。
ここ経由で何面あるのかを返せば良いことになっています。

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*getCurrentSlot)() returns the value letting the system know
+     * whether the current slot is A or B. The meaning of A and B is
+     * left up to the implementer. It is assumed that if the current slot
+     * is A, then the block devices underlying B can be accessed directly
+     * without any risk of corruption.
+     * The returned value is always guaranteed to be strictly less than the
+     * value returned by getNumberSlots. Slots start at 0 and
+     * finish at getNumberSlots() - 1
+     */
+    unsigned (*getCurrentSlot)(struct boot_control_module *module);

現在選択されているslotが何番目かを返せます。

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*markBootSuccessful)() marks the current slot
+     * as having booted successfully
+     *
+     * Returns 0 on success, -errno on error.
+     */
+    int (*markBootSuccessful)(struct boot_control_module *module);

FW update後に、ちゃんと起動できた場合に、systemから呼ばれるので、
bootが成功したので、この面を使うというflagをboot loaderの管理blockに設定することが必要です。

bootloaderは、以後、その確定した面で起動します。
これが呼ばれなかったら、boot loaderは1つ前の面で起動するようにする必要があるということです.

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*setActiveBootSlot)() marks the slot passed in parameter as
+     * the active boot slot (see getCurrentSlot for an explanation
+     * of the "slot" parameter). This overrides any previous call to
+     * setSlotAsUnbootable.
+     * Returns 0 on success, -errno on error.
+     */
+    int (*setActiveBootSlot)(struct boot_control_module *module, unsigned slot);

起動に使うslotを上から設定されますので、boot loaderに設定する必要があります。
通常は、先ほどの (getCurrentSlot() + 1) % (getNumberSlots())の値を設定されるということが、期待されますね。

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*setSlotAsUnbootable)() marks the slot passed in parameter as
+     * an unbootable. This can be used while updating the contents of the slot's
+     * partitions, so that the system will not attempt to boot a known bad set up.
+     * Returns 0 on success, -errno on error.
+     */
+    int (*setSlotAsUnbootable)(struct boot_control_module *module, unsigned slot);

起動失敗時、例えば、dm-verityのfailureが帰ってきた時などに設定するのではないでしょうか。

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*isSlotBootable)() returns if the slot passed in parameter has
+     * booted successfully in the past.
+     * Returns 1 if the slot has booted successfully, 0 if it has not,
+     * and -errno on error.
+     */
+    int (*isSlotBootable)(struct boot_control_module *module, unsigned slot);

setActiveBootSlot()で設定するindexの値が、起動できたものなのかを事前に確認するためのもののようです。

hardware/libhardware/include/hardware/boot_control.h
+    /*
+     * (*getSuffix)() returns the string suffix used by partitions that
+     * correspond to the slot number passed in parameter. The returned string
+     * is expected to be statically allocated and not need to be freed.
+     * Returns NULL if slot does not match an existing slot.
+     */
+    const char* (*getSuffix)(struct boot_control_module *module, unsigned slot);

partitionのA面/B面などを取得するためのもののようです。

このように、HALが用意されているので、HALの実装を用意する必要があります。

update_engine 編に続きます。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7