B2G OS ユーザに、端末へのシステムコードのバージョン更新を簡単に許可したい場合、ユーザが利用可能な更新パッケージを作る必要があります。この記事では、異なる更新パッケージを利用できることを一通り見て、パッケージをビルドし、更新をホストし (またシステムが利用可能な更新を取得する方法)、その更新を適用、検証することを取り上げます。
更新パッケージの作成と適用は、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差分更新のいずれも生成できます。
高レベルで、更新をビルドする処理はこのようになります:
- ソフトウェア バージョンX では
/system/b2g
の中身の完全なGecko/Gaia OTAMAR
を生成します。- 完全な FOTA ターゲットファイルのzipを作成し、端末のパーティション用に任意で署名します。ターゲットファイルのzip は、以下では
DEVICE-target_files-$VARIANT.$USER.zip
で参照される、(SYSTEM/、
BOOT/、などの)
電話機のディレクトリを更新するファイルを含んだ1つのzipです。完全なFOTAのupdate.zip
は複数のターゲットファイルのzipから生成されます。
- ソフトウェア バージョンY では
/system/b2g
の中身の完全な Gecko/Gaia OTAMAR
を生成します。- 完全な FOTA ターゲットファイルのzipを作成し、端末のパーティション用に任意で署名します。ターゲットファイルのzip は、
以下ではDEVICE-target_files-$VARIANT.$USER.zip
で参照される、(SYSTEM/、
BOOT/、などの)
電話機のディレクトリを更新するファイルを含んだ1つのzipです。完全なFOTAのupdate.zip
は複数のターゲットファイルのzipから生成されます。
/system/b2g
内のファイルだけが変更された場合、バージョン X から バージョンY への差分Gecko/Gaia OTA更新MAR
を生成します。- そうでない場合、バージョン X から バージョンY への差分FOTAの
update.zip
を生成します。B2Gクライアントへの配信用に、差分FOTAのupdate.zip
をMARにラップします。
- 配信承諾の必要性に応じて、パッケージを署名します。
下記の節などでは、これらの各ステップを実装するための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 asB2G_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/[email protected]' $ development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]' $ development/tools/make_key shared '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]' $ development/tools/make_key media '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/[email protected]'
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="https://www.mozilla.com/test/sample-eula.html" detailsURL="https://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.