MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

B2G OS の更新パッケージを作成、適用する

B2G OS ユーザに、端末へのシステムコードのバージョン更新を簡単に許可したい場合、ユーザが利用可能な更新パッケージを作る必要があります。この記事では、異なる更新パッケージを利用できることを一通り見て、パッケージをビルドし、更新をホストし (またシステムが利用可能な更新を取得する方法)、その更新を適用、検証することを取り上げます。

更新パッケージの作成と適用は、4つのステップに分かれます:

  1. ビルドホスト上で、旧バージョンから新バージョンへの差分更新パッケージをビルドする
  2. クライアントにダウンロードする、正しい更新パッケージを見つける
  3. 更新をダウンロードする
  4. 端末上の既存ファイルに更新を適用する

これら各ステップは下記に載っています。

: B2G OS のシステムを更新するのに多くの便利なツールがあって、その場所は b2g/tools/update-toolsです。

Prerequisites

To build and apply updates you must ensure that your build has the updater and associated update tools enabled. By default those are enabled only in userdebug and user variants. You can however force building them by adding the following line to your .userconfig file:

export B2G_UPDATER=1

To sign update packages you will need a Java runtime environment (JRE) or Java software development kit (JDK) installed and the java command available in the default path.

更新の種類

2種類の更新を知るべきです: FOTA (Firmware Over-The-Air) と、 Gecko/Gaia OTA (Over-The-Air)です。これらの違いを見て行きましょう。

FOTA更新

FOTA更新により B2G OSシステム全体を更新できます。FOTAの背後の技術はAndroidプロジェクトと共有されています。FOTA更新を使って変更できる電話機の物理ドライブの場所は、システムパーティションや、カーネルや、モデムのベースバンドや、更新用のリカバリイメージ、あるいは端末のあらゆるファィルを含みます。

B2G OS は特定FOTA クライアントに依存してはいません; つまりインターフェイスはlibrecovery と呼ばれるAPIで抽象化されています。しかしながら、我々は GOTA リカバリクライアント(詳細は下記を見よ) を使うのを推奨し、ここの議論はGOTA の使用を想定します。

FOTA 更新パッケージは主に update.zip で構成されます。このパッケージは下記を含みます。

  • バイナリの差分と、クライアントを新しいソフトウェアバージョンに更新するための新規ファィルのセット
  • 差分と新規ファィルをクライアントに移す場所を管理する"更新スクリプト"
  • 更新パッケージの検証に使われる内部署名

ファィルのフォーマットとセットは、通常のAndroid更新に使われるものと同じで、ただ B2G OS では update.zip パッケージを追加でmar ラッパー(MARはMozilla ARchive の意)でラップします(包みます)。mar ラッパーは追加レベルの検証を許可し、それは下記で説明します。

Gecko/Gaia OTA更新

代わりに、単に B2G OS端末のGecko と Gaia のファィルを更新できて、その仕組みをGecko/Gaia OTA 更新と呼びます。 全てのGecko と Gaia のファィル (コアのGeckoランタイムと端末のユーザインターフェイスを含めて) は端末上の /system/b2g ディレクトリ内にあります。これはOTA更新で変更可能な、唯一のディレクトリです。

Gecko/Gaia OTA更新はデスクトップ版Firefox webブラウザの更新に使われるのと同じ技術を使っています。上記で議論したFOTA update.zip パッケージとよく似ていることに、OTA更新は1つの MAR ファイルで構成され、その中にクライアントを新しいソフトウェアバージョンに更新するのに必要な、差分バイナリと新規ファイルのセットを含んでいます。

Gecko クライアントはダウンロードした複数のMARの統合性を検証し、複数のMARを複数の関係者で署名することができます。

2つの更新テクノロジーがある理由は?

OTA更新はFOTA更新ほど広範囲ではないが、よりユーザフレンドリーで適用が簡単で、必要な更新を行うためにしばしば良いものでしょう。

  • Gecko/Gaia OTA 更新は、B2G OSが通常動作中に"バックグラウンドで"更新できます。これはユーザが電話機を再起動して更新が適用されるのを待つ必要がないため、ずっと良いユーザ体験を提供するでしょう。その代わり、ユーザが電話機を使い続ける中で更新が適用されて、更新が完了した時にユーザはメインのb2gプロセスの再起動に同意する必要があります。これは数秒の問題で、FOTA更新の適用には通常数分かかります。
  • Gecko/Gaia OTA 更新パッケージはFOTA更新パッケージより小さいことが時々あり、いつもではありません; つまり大きくなることはありません。これはユーザが時々、少ないデータをダウンロードできることを意味します。

もちろん、Gecko/Gaia 外のファイルを更新する必要があれば、完全な FOTAパッケージの道を進まないといけません。

続いてパッケージをビルドする処理を検証しましょう。

更新パッケージをビルドする

更新のビルドは、 B2G OS クライアントを、ソフトウェアのバージョンX からより新しい バージョンY に更新するのに要るファイルを生成する処理です。クライアントを更新するのに必要な更新パッケージは、バージョンXバージョンY との間でどのファイルが変更されたかに依存します。

  • /system/b2g 内のファイルだけが変更された場合Gecko/Gaia OTA更新を生成します。
  • /system/b2g 外のいずれかのファイルが変更された場合、FOTA更新を生成します。

差分更新パッケージ(FOTA と Gecko/Gaia OTA更新の両方) を生成するには、我々のツールではバージョンX と バージョンY の完全ビルドが必要です。 完全ビルド とは、クライアントを書き込むのに必要な全ファイルを含んだパッケージのことです。バージョンX の完全ビルド作成時には、バージョンXから更新する将来のバージョンを知っていません。そのために、完全なFOTAパッケージとGecko/Gaia パッケージを、各バージョン毎に作ります。これにより、バージョンX と将来の全バージョンの間で、Gecko/Gaia OTA差分更新や、必要ならばFOTA差分更新のいずれも生成できます。

高レベルで、更新をビルドする処理はこのようになります:

  1. ソフトウェア バージョンX では
    • /system/b2g の中身の完全なGecko/Gaia OTA MAR を生成します。
    • 完全な FOTA ターゲットファイルのzipを作成し、端末のパーティション用に任意で署名します。ターゲットファイルのzip は、以下ではDEVICE-target_files-$VARIANT.$USER.zipで参照される、(SYSTEM/、BOOT/、などの)電話機のディレクトリを更新するファイルを含んだ1つのzipです。完全なFOTAのupdate.zip は複数のターゲットファイルのzipから生成されます。
  2. ソフトウェア バージョンY
    • /system/b2g の中身の完全な Gecko/Gaia OTA MAR を生成します。
    • 完全な FOTA ターゲットファイルのzipを作成し、端末のパーティション用に任意で署名します。ターゲットファイルのzip は、 以下ではDEVICE-target_files-$VARIANT.$USER.zipで参照される、(SYSTEM/、BOOT/、などの)電話機のディレクトリを更新するファイルを含んだ1つのzipです。完全なFOTAのupdate.zip は複数のターゲットファイルのzipから生成されます。
  3. /system/b2g 内のファイルだけが変更された場合、バージョン X から バージョンY への差分Gecko/Gaia OTA更新MARを生成します。
  4. そうでない場合、バージョン X から バージョンY への差分FOTAのupdate.zip を生成します。B2Gクライアントへの配信用に、差分FOTAのupdate.zip MARにラップします。
  5. 配信承諾の必要性に応じて、パッケージを署名します。

下記の節などでは、これらの各ステップを実装するためのB2Gツールの使い方を説明します。

Note: the steps below assume that you have already set up a b2g build environment at the location $b2g. The commands below reference the $b2g/build.sh helper script, but make can also be used.

完全な Gecko/Gaia OTA更新MARを生成する

gecko-update-full ターゲットを実行して、完全な更新MARを、最後に成功したb2g ビルド(例  あなた自身でビルド完了したもの) から生成するには、gecko-update-full ターゲットを実行する必要があります。MAR を $b2g/objdir-gecko/dist/b2g-update/b2g-gecko-update.mar に配置するには、下記コマンドを使います:

$ cd $b2g
$ ./build.sh gecko-update-full
$ cp objdir-gecko/dist/b2g-update/b2g-gecko-update.mar <destination>

Generating a full FOTA update MAR

To generate a full FOTA update MAR from the last successful b2g build (e.g. that you built yourself), you need to invoke the gecko-update-fota-full target. This includes the contents of the entire /system partition. Here are the commands you need:

$ cd $b2g
$ ./build.sh gecko-update-fota-full

This will generate a ZIP file ($PRODUCT_OUT/fota/full/update.zip) and a MAR file ($PRODUCT_OUT/fota-$TARGET_DEVICE-update-full.mar). The ZIP file can be directly used with adb sideload, while the MAR is intended for distribution in the same manner as any other update package.

Generating a FOTA update MAR plus recovery package

As of Firefox OS 2.2 (mid April and beyond) we added a new make target, which can be invoked as follows:

$ cd $b2g
$ ./build.sh gecko-update-fota-fullimg

This is used to produce a recovery package that will dump a set of partitions images. The default set is controlled by the variable B2G_FOTA_FULLIMG_PARTS, defined in gonk-misc/Android.mk (along with most of the other new features seen below.) It's a space-separated string of mountpoint:image instances to include. The default value is "/boot:boot.img /system:system.img /recovery:recovery.img /cache:cache.img".

Along with this we have also introduced some new environment variables to control the production of the two other make targets — gecko-update-fota and gecko-update-fota-full:

  • The first is B2G_FOTA_PARTS, which follows the same syntax pattern as B2G_FOTA_FULLIMG_PARTS. This allows us to produce these update packages but arbitrarily dump partition images along with those, e.g. boot partition, modem firmware, etc.
  • B2G_FOTA_PARTS_FORMAT provides a way to describe a set of partitions that we want formatted during the installation of the recovery package. It's a space-separated list of mount points to make use of during the formatting.
  • We also have two new variables that allow us to wipe caches and/or data during the build procedure:
    • B2G_FOTA_WIPE_DATA
    • B2G_FOTA_WIPE_CACHE

Note: All of these new features heavily rely on having a proper recovery.fstab file provided for the device in question.

Generating a partial Gecko/Gaia FOTA update MAR

A partial FOTA update uses the same mechanism as a full FOTA update, but by default only includes Gecko/Gaia updates like a regular OTA update. Additional files outside of Gecko/Gaia (such as fonts) can also be included.

The rationale for generating a partial FOTA update package is mainly related to licensing issues: when building a complete FOTA update package, the whole system partition (at least) will be included. This may include blobs that you don't have the authorization to redistribute. However, since MAR distribution is useful and Gecko/Gaia themselves are free software, there is no reason we should not be able to distribute them in this manner. A partial FOTA allows you to only update a subset of the system. An OTA update could be used instead in this scenario but it does come at a cost: OTA updates require enough space on the system partition to hold both the existing Gecko/Gaia files as well as the unpacked update files. A partial FOTA update does not suffer from this limitation as it can overwrite the existing files with the updated ones.

To create a partial FOTA update from the last successful b2g build (e.g. that you built yourself), Invoke the gecko-update-fota target with the following commands:

$ cd $b2g
$ ./build.sh gecko-update-fota

This will generate a ZIP file ($PRODUCT_OUT/fota/partial/update.zip) and a MAR file ($PRODUCT_OUT/fota-$TARGET_DEVICE-update.mar). The ZIP file can be directly used with adb sideload, while the MAR is intended for distribution in the same manner as any other update package.

The construction can be controlled with a couple of environment variables, the most useful of which are documented below:

Variable Meaning
$B2G_FOTA_DIRS Space-separated list of directories to include in the update. Defaults to system/b2g.
$TARGET_UPDATE_BINARY Binary used to execute the Edify script inside the package. When none is provided, a pre-built updater binary from ICS is used.
$FOTA_FINGERPRINTS Comma-separated list of Android fingerprints to check against. The use case is to be able to distribute Gecko/Gaia update packages on top of a controlled Gonk base system that we cannot legally distribute. For example, Open C community builds are using this.

Note: A complete set of these variables is defined in the Android.mk file of the gonk-misc repository; note that $FOTA_FINGERPRINTS is used in our update_tools.py tool.

完全な FOTA ターゲットファイルのzipを生成する

Invoke the target-files-package target to build a target files zip that can be used to generate both incremental and full FOTA update packages. The target files zip can also be signed by custom keys to ensure that only FOTA updates from known sources can be installed. After signing target files, all images and updates (also OTA) need to be generated again to catch the inserted keys.

Note: The target files zip is generated in the location out/target/product/$DEVICE/obj/PACKAGING/target_files_intermediates/$DEVICE-target_files-$VARIANT.$USER.zip

The following commands will carry out this step:

$ cd $b2g
$ ./build.sh target-files-package
$ cp out/target/product/$DEVICE/obj/PACKAGING/target_files_intermediates/$DEVICE-target_files-$VARIANT.$USER.zip <destination>

The variable values in the commands listed above should be filled in as follows:

Variable Meaning
$DEVICE Device name for the AOSP product
$VARIANT eng, user, or userdebug
$USER The build username

完全なFOTAターゲットzipファイルに署名する

Proper releases should typically be signed by custom release keys only known to the vendor. Having such keys will prevent FOTA updates where the source is unknown from being installed, hence introducing an extra security layer. For this to work, the images flashed to a device need to include public keys while the updates need to be signed by the corresponding private key. 

The first step is to generate custom keys and store them in a safe place. The Android Open Source Project has a script for generating these keys. For full compatibility, get this script from the branch corresponding to the Gonk version of the device in question. Here is the master branch version.

A couple of keys are needed — create them with the following commands. releasekey is the key to use for signing FOTA update packages.

$ development/tools/make_key releasekey '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
$ development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
$ development/tools/make_key shared '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
$ development/tools/make_key media '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'

With keys present, the target files zip can be signed using the following commands. This will insert the public keys and modify build properties to reflect the fact that it has been signed.

$ cd $b2g
$ ./build/tools/releasetools/sign_target_files_apks \
  --default_key_mappings $RELEASEKEY_FOLDER \
  --replace_ota_keys \
  --signapk_path prebuilts/sdk/tools/lib/signapk.jar \
  $UNSIGNED_TARGET_FILES_ZIP \
  $SIGNED_TARGET_FILES_ZIP

The variable values in the commands listed above should be filled in as follows:

Variable Meaning
$RELEASEKEY_FOLDER The path to the folder containing the custom keys
$UNSIGNED_TARGET_FILES_ZIP The FOTA target files zip to sign.
$SIGNED_TARGET_FILES_ZIP The signed FOTA target files zip to be generated

差分OTA更新MARを生成する

この例では、ソフトウェア バージョンX から バージョンYへの更新を生成すると想定します。 上記の指示からビルドされたソフトウェア バージョンXの完全なGecko/Gaia OTA MAR の場所を、以下では $MAR_X と呼びます。これはビルドサーバ上で /home/build/b2g/versions/X/update.mar のようなパスかもしれません。同様に、バージョンY の完全なMAR$MAR_Y と呼びます。

build-gecko-mar.py のツールは差分Gecko/Gaia OTA更新のMAR を、$MAR_X と$MAR_Y を用いて生成します。ファイルの生成先を$GENERATED_INCREMENTAL_MAR_X_Y と呼びます。このステップでは下記コマンドを使います:

$ cd $b2g
$ ./tools/update-tools/build-gecko-mar.py --from $MAR_X --to $MAR_Y $GENERATED_INCREMENTAL_MAR_X_Y

差分FOTA更新zipを生成する

In this example, we're assuming that we're generating an update from software version X to version Y. The location of the full FOTA target zip built from software version X using the instructions above will be called $TARGET_FILES_X below. This might be a path on a build server like /home/build/b2g/versions/X/target_files.zip. Similarly, the location of the full FOTA target zip built from version Y will be called $TARGET_FILES_Y.

The tool build/tools/releasetools/ota_from_target_files will generate an incremental FOTA update.zip using $TARGET_FILES_X and $TARGET_FILES_Y. We'll call the destination of this intermediate file $INTERMEDIATE_FOTA_UPDATE_FOTA_X_Y.

After this update.zip is generated, the last step is to wrap it in a MAR for delivery to the B2G client. The tool tools/update-tools/build-fota-mar.p does this step. We'll call the destination of this generated file $GENERATED_INCREMENTAL_FOTA_X_Y.

Use the following commands to complete this step:

$ cd $b2g
$ ./build/tools/releasetools/ota_from_target_files -v \
    --incremental_from $TARGET_FILES_X \
    --signapk_path prebuilts/sdk/tools/lib/signapk.jar \
    --package_key $FOTA_SIGNING_KEY \
    $TARGET_FILES_Y \
    $INTERMEDIATE_FOTA_UPDATE_FOTA_X_Y
$ ./tools/update-tools/build-fota-mar.py $INTERMEDIATE_FOTA_UPDATE_FOTA_X_Y --output=$GENERATED_INCREMENTAL_FOTA_X_Y

The variable values in the commands listed above should be filled in as follows:

Variable Meaning
$TARGET_FILES_X The FOTA target files zip for version X
$TARGET_FILES_Y The FOTA target files zip for version Y
$INTERMEDIATE_FOTA_UPDATE_FOTA_X_Y A temporary update.zip to generate a MAR from
$GENERATED_INCREMENTAL_FOTA_X_Y The destination incremental update zip wrapped in a MAR for delivery to clients
$FOTA_SIGNING_KEY Path to the prefix for a private key and public cert for signing the update zip. $FOTA_SIGNING_ZIP.pk8 and $FOTA_SIGNING_ZIP.x509.pem should both exist on the file system. If $TARGET_FILES_X is not signed this option can be omitted; the default testkey will still be picked up. In case $TARGET_FILES_X is a custom release key, refer to the target files zip signing section on how to create it, and don't forget to sign $TARGET_FILES_Y.

更新をホストし、クライアント側で更新をポーリングする

B2G OS クライアントは更新マニフェスト(update.xml)を取得し、読み解くことで、更新をポーリングします。 B2G OS クライアントは特定サーバ(サーバ上の特別に構築されたパスを尋ねます)の更新をポーリングするよう設定されています。クライアントがサーバを尋ねるのに、 HTTPSプロトコルが必要で、しかしながらHTTPもサポートされます。クライアントからポーリングされるサーバとパスは、既存クライアントにポーリングコードを変更する更新を積むことで、変更できます。

下記の例では、server updates.b2g.com に更新がホストされているのを想定します。

クライアントからポーリングされるURLは、通例に下記パラメータを含みます:

パラメータ 説明
PRODUCT_MODEL 端末モデル名。これはB2Gのプロパティデータベース内の ro.product.model の値です。
CHANNEL 更新"チャンネル"。これはテストに役立ちます: 複数のサーバをホストするよう設定でき、例えば、"nightly"と"beta"と"release"のチャンネル。
VERSION クライアントのソフトウェアバージョン。例えば、"18.0.2"。
BUILD_ID タイムスタンプのような ユニークID で、特定ビルド用に構成されます。

Firefox クライアントは構成された更新ホストの値と、実行時にポーリングするURLを構築するこれらの値を使います。構造は下記の通り:

https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%PRODUCT_DEVICE%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml

こうしたURLの実例は下記の通り:

https://aus4.mozilla.org/update/3/B2G/37.0a1/20141214040212/flame/en-US/nightly-b2g37/Boot2Gecko%202.2.0.0-prerelease%20%28SDK%2019%29/default/default/update.xml?force=1

サーバがクライアントのリクエストに対するレスポンスに"404 Not Found"を返した場合、利用できる更新はありません。サーバが"200" とマニフェストファイルを返した場合、利用できる更新がある可能性があります。マニフェストは新規に利用できる、すなわちクライアントが更新しようとするビルドを記述します。マニフェストの例は下記:

<?xml version="1.0"?>
<updates>
  <update type="major" appVersion="19.0" version="19.0" extensionVersion="19.0" buildID="20121210123456"
          licenseURL="http://www.mozilla.com/test/sample-eula.html"
          detailsURL="http://www.mozilla.com/test/sample-details.html">
    <patch type="partial" URL="https://updates.b2g.com/release/unagi1/18.0/20121203123456/update.mar"
           hashFunction="SHA512" hashValue="5111e033875752b7d9b32b4795152dea5ef954cb8a9d4a602dd19a923b464c43521287dcb5781faf3af76e6dc5e8a3dd9c13edea18c1f2c8f3bd89e17d103d6f"
           size="41901319"/>
  </update>
</updates>

これはFirefox ビルドのマニフェスト(詳細はupdates.xml フォーマットFormat を見よ)と同じスキーマです。.マニフェスト内の項目は下記を記述します:

  • クライアント上のユーザインターフェイス表示に使うメタデータ
  • 新規に利用できるバージョンについてのメタデータ
  • 更新パッケージの場所
  • 更新パッケージのダウンロード検証に使うメタデータ

Note: There is a useful update script available at build-update-xml.py, which given a MAR file, builds a Firefox OS update.xml for testing.

Note: The client device or the user may wish to decline an update.

Note:  isOSUpdate="true" is needed for FOTA updates but not for OTA updates.

上記に記述した仕組みを使って、サーバはクライアントのいかなる旧バージョンでも最新バージョンに更新する更新パッケージをホストできます。あるいは、クライアントが一度で更新するべき"直線の更新履歴"だけをホストしているかもしれません。

ビルドサーバと更新ホストの相互作用の詳細は、このドキュメントの説明範囲を超えています。それはプロダクション環境に強く依存しています。我々の Software Update wiki ページにて詳細を見つけることができます。

更新を検証、適用する

After a B2G OS client has successfully polled for an update (handled from within the system), downloaded it, and verified the integrity of the downloaded update package, the final step is to apply the update.

The first step in applying an update is to verify the signatures embedded in the MAR packages (see Generating an incremental FOTA update zip for how these are created). This is done by the B2G OS client itself after checking the integrity of the downloaded package. The code used for this is the same for both FOTA and Gecko/Gaia OTA updates.

Note: It is not the MAR file that gets signed: it's the FOTA zip file that gets bundled into the MAR that's signed by build/tools/releasetools/ota_from_target_file. The signing of the FOTA update works the same as it does on Android; if you just run the script without specifying the key, it will use the developer key at build/target/product/security/testkeys.*. This is ok for testing but when you create a real update you need a secure key — i.e. one that no-one else knows about. The device will also verify that signature before applying the patch, so a device's initial images will need to contain the key as well.

Note: The keys referred to above are found in the Android build systems; we've forked it in our platform_build repo.

After signatures are verified, the process of applying an update diverges between Gecko/Gaia OTA updates and FOTA updates. Let's look at the differences between the two at this point.

Gecko/Gaia OTA更新を適用する

The B2G OS client applies these using the updater binary. This is part of the Gecko distribution and is the same code used to apply updates to desktop Firefox. As described above, the update is applied while the B2G OS client continues to run normally. Users are able to make and receive calls, run apps, browse the web, etc. while updates are being applied.

The specific details of the updater binary are beyond the scope of this document, but it works approximately like so:

  • It makes a copy of the /system/b2g files.
  • It applies binary patches, removes old files, and adds new ones as specified by the MAR file.
  • It restarts the main b2g process so that it uses all the new files.

After the b2g process finishes restarting, the user will be running the new version of the B2G client software.

FOTA更新を適用する

The FOTA client applies these. The Gecko client "hands off" the update to be applied by calling into the librecovery API. What happens after this step is specific to each FOTA client.

In the implementation of librecovery used for the GOTA client, the downloaded update package is staged to be applied and special commands are enqueued for the recovery client. librecovery then reboots the device into recovery mode. The recovery client then runs the update script in the update.zip to update files and partitions as needed. The recovery client may need to reboot multiple times in order to update all files.

After the final reboot, the device will be running the new version of the B2G OS client software.

ドキュメントのタグと貢献者

 このページの貢献者: chrisdavidmills, hamasaki, Uemmra3
 最終更新者: chrisdavidmills,