aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeidi von Markham <hvm@google.com>2015-03-18 20:51:49 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2015-03-18 20:51:50 +0000
commit647c18c1949f49d979b7357ecd6af832d16ddfec (patch)
treeb8e3d890a2dfd9a77cbd28c075ac6ccaaa663f81
parenteb5ffb0231f3ca6265f0560d7a579154975918d4 (diff)
parent70ec4de9965caf910eb30cac5a5d01231ed70497 (diff)
downloadsource.android.com-647c18c1949f49d979b7357ecd6af832d16ddfec.tar.gz
Merge "Docs: Adding general OTA content, new images Updating with comments from google doc (tbao and xi zhao) Adding reference to options for ota_from_target_files Adding feedback changes Adding 2nd set of feedback changes Adding 3rd set of feedback changes Adding 4th set of feedback changes Breaking content into multiple files, adding block ota, adjusting toc Renamed .jd files, update TOC and document links Adding in dougz's feedback on recovery images, split out 5x vs 4x and earlier Minor text tweaks Fixing merge conflict Adding in dougz's comment Setting 80 column width in all files Adding feedback, moving up one level Adding ota mailing list, cropped localized text image, teaser blub on tech/index, mailing list to community page (includes several edits to meet 80 character column limit) Update mailing list verbiage, added feedback to builtin functions from tbao (in google doc)"
-rw-r--r--src/devices/devices_toc.cs15
-rw-r--r--src/devices/tech/images/composite01.pngbin0 -> 45756 bytes
-rw-r--r--src/devices/tech/images/composite07.pngbin0 -> 45800 bytes
-rw-r--r--src/devices/tech/images/icon_error.pngbin0 -> 19306 bytes
-rw-r--r--src/devices/tech/images/icon_installing.pngbin0 -> 25261 bytes
-rw-r--r--src/devices/tech/images/icon_installing_5x.pngbin0 -> 118562 bytes
-rw-r--r--src/devices/tech/images/icon_installing_overlay01.pngbin0 -> 10095 bytes
-rw-r--r--src/devices/tech/images/icon_installing_overlay07.pngbin0 -> 10062 bytes
-rw-r--r--src/devices/tech/images/installing_text.pngbin0 -> 22516 bytes
-rw-r--r--src/devices/tech/images/ota_size_comparison.pngbin0 -> 25645 bytes
-rw-r--r--src/devices/tech/images/progress_1.pngbin0 -> 119 bytes
-rw-r--r--src/devices/tech/images/progress_10.pngbin0 -> 294 bytes
-rw-r--r--src/devices/tech/images/progress_50.pngbin0 -> 743 bytes
-rw-r--r--src/devices/tech/images/progress_empty.pngbin0 -> 118 bytes
-rw-r--r--src/devices/tech/images/progress_fill.pngbin0 -> 404 bytes
-rw-r--r--src/devices/tech/index.jd92
-rwxr-xr-xsrc/devices/tech/ota/block.jd148
-rwxr-xr-xsrc/devices/tech/ota/device_code.jd1154
-rwxr-xr-xsrc/devices/tech/ota/index.jd160
-rwxr-xr-xsrc/devices/tech/ota/inside_packages.jd288
-rwxr-xr-xsrc/devices/tech/ota/sign_builds.jd269
-rwxr-xr-xsrc/devices/tech/ota/tools.jd133
-rw-r--r--src/source/community/index.jd235
23 files changed, 2386 insertions, 108 deletions
diff --git a/src/devices/devices_toc.cs b/src/devices/devices_toc.cs
index 1c622d6f..6662b9bb 100644
--- a/src/devices/devices_toc.cs
+++ b/src/devices/devices_toc.cs
@@ -259,6 +259,21 @@
</a>
</li>
+ <li class="nav-section">
+ <div class="nav-section-header">
+ <a href="<?cs var:toroot ?>devices/tech/ota/index.html">
+ <span class="en">OTA Updates</span>
+ </a>
+ </div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>devices/tech/ota/tools.html">OTA Tools</a></li>
+ <li><a href="<?cs var:toroot ?>devices/tech/ota/block.html">Block-based OTA</a></li>
+ <li><a href="<?cs var:toroot ?>devices/tech/ota/inside_packages.html">Inside OTA Packages</a></li>
+ <li><a href="<?cs var:toroot ?>devices/tech/ota/device_code.html">Device-Specific Code</a></li>
+ <li><a href="<?cs var:toroot ?>devices/tech/ota/sign_builds.html">Signing Builds for Release</a></li>
+ </ul>
+ </li>
+
<li>
<a href="<?cs var:toroot ?>devices/tech/power.html">
<span class="en">Power</span>
diff --git a/src/devices/tech/images/composite01.png b/src/devices/tech/images/composite01.png
new file mode 100644
index 00000000..3220521e
--- /dev/null
+++ b/src/devices/tech/images/composite01.png
Binary files differ
diff --git a/src/devices/tech/images/composite07.png b/src/devices/tech/images/composite07.png
new file mode 100644
index 00000000..71257343
--- /dev/null
+++ b/src/devices/tech/images/composite07.png
Binary files differ
diff --git a/src/devices/tech/images/icon_error.png b/src/devices/tech/images/icon_error.png
new file mode 100644
index 00000000..cb3d1ab2
--- /dev/null
+++ b/src/devices/tech/images/icon_error.png
Binary files differ
diff --git a/src/devices/tech/images/icon_installing.png b/src/devices/tech/images/icon_installing.png
new file mode 100644
index 00000000..571eb8b0
--- /dev/null
+++ b/src/devices/tech/images/icon_installing.png
Binary files differ
diff --git a/src/devices/tech/images/icon_installing_5x.png b/src/devices/tech/images/icon_installing_5x.png
new file mode 100644
index 00000000..c2c02016
--- /dev/null
+++ b/src/devices/tech/images/icon_installing_5x.png
Binary files differ
diff --git a/src/devices/tech/images/icon_installing_overlay01.png b/src/devices/tech/images/icon_installing_overlay01.png
new file mode 100644
index 00000000..e762d6cb
--- /dev/null
+++ b/src/devices/tech/images/icon_installing_overlay01.png
Binary files differ
diff --git a/src/devices/tech/images/icon_installing_overlay07.png b/src/devices/tech/images/icon_installing_overlay07.png
new file mode 100644
index 00000000..3838a85a
--- /dev/null
+++ b/src/devices/tech/images/icon_installing_overlay07.png
Binary files differ
diff --git a/src/devices/tech/images/installing_text.png b/src/devices/tech/images/installing_text.png
new file mode 100644
index 00000000..11e1d3c9
--- /dev/null
+++ b/src/devices/tech/images/installing_text.png
Binary files differ
diff --git a/src/devices/tech/images/ota_size_comparison.png b/src/devices/tech/images/ota_size_comparison.png
new file mode 100644
index 00000000..9204a90e
--- /dev/null
+++ b/src/devices/tech/images/ota_size_comparison.png
Binary files differ
diff --git a/src/devices/tech/images/progress_1.png b/src/devices/tech/images/progress_1.png
new file mode 100644
index 00000000..aa997d06
--- /dev/null
+++ b/src/devices/tech/images/progress_1.png
Binary files differ
diff --git a/src/devices/tech/images/progress_10.png b/src/devices/tech/images/progress_10.png
new file mode 100644
index 00000000..1ca391a6
--- /dev/null
+++ b/src/devices/tech/images/progress_10.png
Binary files differ
diff --git a/src/devices/tech/images/progress_50.png b/src/devices/tech/images/progress_50.png
new file mode 100644
index 00000000..8a2ac6cb
--- /dev/null
+++ b/src/devices/tech/images/progress_50.png
Binary files differ
diff --git a/src/devices/tech/images/progress_empty.png b/src/devices/tech/images/progress_empty.png
new file mode 100644
index 00000000..72581832
--- /dev/null
+++ b/src/devices/tech/images/progress_empty.png
Binary files differ
diff --git a/src/devices/tech/images/progress_fill.png b/src/devices/tech/images/progress_fill.png
new file mode 100644
index 00000000..becf87bd
--- /dev/null
+++ b/src/devices/tech/images/progress_fill.png
Binary files differ
diff --git a/src/devices/tech/index.jd b/src/devices/tech/index.jd
index a844be8a..62a1f59a 100644
--- a/src/devices/tech/index.jd
+++ b/src/devices/tech/index.jd
@@ -2,7 +2,7 @@ page.title=Android Core Technologies
@jd:body
<!--
- Copyright 2014 The Android Open Source Project
+ Copyright 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -26,35 +26,40 @@ page.title=Android Core Technologies
<p>Welcome to the Android core technologies section of the site. Here you
-can find information on common features useful to people and organizations who are
-looking to modify, contribute to, or port the Android software. This is "under
-the hood" information intended for engineers.</p>
+can find information on common features useful to people and organizations who
+are looking to modify, contribute to, or port the Android software. This is
+"under the hood" information intended for engineers.</p>
<h2 id="accessory-protocol-information">Accessories</h2>
<p>Android devices can connect to hardware accessories, such as audio docks,
-keyboards and custom hardware, through USB or Bluetooth. This document
-describes the Android Open Accessory protocol for accessory hardware builders.</p>
-<p><a href="{@docRoot}accessories/index.html">&raquo; Accessory Protocol Information</a></p>
+keyboards and custom hardware, through USB or Bluetooth. This section
+describes the Android Open Accessory protocol (AOAP) for accessory hardware
+builders.</p>
+<p><a href="{@docRoot}accessories/index.html">&raquo; Accessory Protocol
+Information</a></p>
<h2 id="art-technical-information">ART</h2>
<p>The Android runtime (ART) is the heart of Android. It's a fast, ahead-of-time
-compiled runtime with modern garbage collection designed to scale. Android applications are
-compiled to Dalvik bytecode and run with ART. This section includes
-detailed information such as the Dalvik Executable format specification,
-and design information on the runtime itself.</p>
-<p><a href="{@docRoot}devices/tech/dalvik/index.html">&raquo; ART and Dalvik Information</a></p>
+compiled runtime with modern garbage collection designed to scale.
+Android applications are compiled to Dalvik bytecode and run with ART. This
+section includes detailed information such as the Dalvik Executable format
+specification, and design information on the runtime itself.</p>
+<p><a href="{@docRoot}devices/tech/dalvik/index.html">&raquo; ART and Dalvik
+Information</a></p>
<h2 id="data-usage-technical-information">Data Usage</h2>
-<p>Android's data usage features allow users to understand and control how their
-device uses network data. This document is designed for systems integrators
-and mobile operators, to help explain technical details they should be aware
-of when porting Android to specific devices.</p>
-<p><a href="{@docRoot}devices/tech/datausage/index.html">&raquo; Data Usage Information</a></p>
+<p>Android's data usage features allow users to understand and control how
+their device uses network data. This section is designed for systems
+integrators and mobile operators to help explain technical details they
+should be aware of when porting Android to specific devices.</p>
+<p><a href="{@docRoot}devices/tech/datausage/index.html">&raquo; Data Usage
+Information</a></p>
<h2 id="debugging">Debugging and Tuning</h2>
<p>Android is a large and complex system. This section includes tips and tricks
-about debugging at the platform level.</p>
-<p><a href="{@docRoot}devices/tech/debug/index.html">&raquo; Debugging Information</a></p>
+for debugging at the platform level.</p>
+<p><a href="{@docRoot}devices/tech/debug/index.html">&raquo; Debugging
+Information</a></p>
<h2 id="HAL-technical-information">HAL File Reference</h2>
<p>Android's Hardware Abstraction Layer (HAL) provides the interface between
@@ -63,30 +68,45 @@ files of the HAL.</p>
<p><a href="{@docRoot}devices/halref/files.html">&raquo; HAL Reference</a></p>
<h2 id="kernel-technical-information">Kernel</h2>
-<p>The kernel configuration settings in this document are meant to be used as a base
-for an Android kernel configuration. All devices should have the options in android-base
-configuration enabled.</p>
-<p><a href="{@docRoot}devices/tech/kernel.html">&raquo; Kernel Information</a></p>
+<p>The kernel configuration settings in this section are meant to be used as
+a base for an Android kernel configuration. All devices should have the
+options in android-base configuration enabled.</p>
+<p><a href="{@docRoot}devices/tech/kernel.html">&raquo; Kernel Information</a>
+</p>
<h2 id="lowram-technical-information">Low RAM</h2>
-<p>Android supports devices with limited memory through various optimizations,
+<p>Android supports devices with limited memory through various optimizations
such as improved memory management, reduced system memory, and several
build-time and kernel configuration settings.</p>
-<p><a href="{@docRoot}devices/tech/low-ram.html">&raquo; Low RAM Information</a></p>
+<p><a href="{@docRoot}devices/tech/low-ram.html">&raquo; Low RAM Information</a>
+</p>
+
+<h2 id="ota-technical-information">OTA Updates</h2>
+<p>Android devices in the field can receive and install over-the-air (OTA)
+updates to the system and application software. This section describes the
+structure of update packages and the tools to build them. It is intended for
+developers building OTA updates for new and released Android devices.</p>
+<p><a href="{@docRoot}devices/tech/ota/index.html">&raquo; OTA Information</a>
+</p>
<h2 id="power-technical-information">Power</h2>
-<p>Battery usage statistics are tracked by the framework. This involves keeping track of
-time spent by different device components in different states.</p>
-<p><a href="{@docRoot}devices/tech/power.html">&raquo; Power Information</a></p>
+<p>Battery usage statistics are tracked by the framework. This involves
+keeping track of time spent by different device components in different states.
+</p>
+<p><a href="{@docRoot}devices/tech/power.html">&raquo; Power Information</a>
+</p>
<h2 id="security-technical-information">Security</h2>
<p>Android security comes with a variety of measures, including an application
sandbox, SELinux, dm-verity, encryption, and more.</p>
-<p><a href="{@docRoot}devices/tech/security/index.html">&raquo; Security Information</a></p>
-
-<h2 id="tradefed-test-infrastructure">Trade Federation Testing Infrastructure</h2>
-<p>Trade Federation is a continuous test framework for running tests on Android devices.
-Trade Federation's modularity makes it straightforward to slot into environments with existing build,
-test, and reporting infrastructures.</p>
-<p><a href="{@docRoot}devices/tech/test_infra/tradefed/index.html">&raquo; Trade Federation Testing Infrastructure Overview</a></p>
-
+<p><a href="{@docRoot}devices/tech/security/index.html">&raquo; Security
+Information</a></p>
+
+<h2 id="tradefed-test-infrastructure">Trade Federation Testing Infrastructure
+</h2>
+<p>Trade Federation is a continuous test framework for running tests on
+Android devices. Trade Federation's modularity makes it straightforward to
+slot into environments with existing build, test, and reporting
+infrastructures.</p>
+<p><a href="{@docRoot}devices/tech/test_infra/tradefed/index.html">
+&raquo; Trade Federation Testing Infrastructure Overview</a></p> \ No newline at end of file
diff --git a/src/devices/tech/ota/block.jd b/src/devices/tech/ota/block.jd
new file mode 100755
index 00000000..63129a02
--- /dev/null
+++ b/src/devices/tech/ota/block.jd
@@ -0,0 +1,148 @@
+page.title=Block-Based OTAs
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>You can enable block-based over-the-air (OTA) updates for new devices
+running Android 5.0. OTA is the mechanism by which OEMs remotely update the
+system partition of a device:</p>
+<ul>
+<li><b>Android 5.0</b> and later versions use block OTA updates to ensure that
+each device uses the exact same partition. Instead of comparing individual
+files and computing binary patches, block OTA handles the entire partition as
+one file and computes a single binary patch, ensuring the resultant partition
+contains exactly the intended bits. This allows the device system image to
+achieve the same state via fastboot or OTA.</li>
+<li><b>Android 4.4</b> and earlier versions used file OTA updates, which
+ensured devices contained similar file contents, permissions, and modes, but
+allowed metadata such as timestamps and the layout of the underlying storage
+to vary between devices based on the update method.</li>
+
+</ul>
+<p>Because block OTA ensures that each device uses the same partition, it
+enables the use of dm-verity to cryptographically sign the system partition.
+For details on dm-verity, see
+<a href="{@docRoot}devices/tech/security/secureboot/index.html">Secure Boot</a>.
+</p>
+
+<p class="note"><strong>Note:</strong> You must have a working block OTA
+system before using dm-verity.</p>
+
+<h2 id="Recommendations">Recommendations</h2>
+
+<p>For devices launching with Android 5.0 or later, use block OTA updates in
+the factory ROM. To generate a block-based OTA for subsequent updates, pass
+the <code>--block</code> option to <code>ota_from_target_files</code>.</p>
+
+<p>For devices that launched with Android 4.4 or earlier, use file OTA
+updates. While is it possible to transition devices by sending a full block
+OTA of Android 5.0 or later, it requires sending out a full OTA that is
+significantly larger than an incremental OTA (and is therefore discouraged).
+</p>
+
+<p>Because dm-verity requires bootloader support found only in new devices
+shipping with Android 5.0 or later, you <i>cannot</i> enable dm-verity for
+existing devices.</p>
+
+<p>Developers working on the Android OTA system (the recovery image and the
+scripts that generate OTAs) can keep up with changes by subscribing to the
+<a href="https://groups.google.com/forum/#!forum/android-ota">android-ota@googlegroups.com</a>
+mailing list.</p>
+
+<h2 id="File vs. Block OTAs">File vs. Block OTAs</h2>
+
+<p>During a file-based OTA, Android attempts to change the contents of the
+system partition at the filesystem layer (on a file-by-file basis). The update
+is not guaranteed to write files in a consistent order, have a consistent last
+modified time or superblock, or even place the blocks in the same location on
+the block device. For this reason, file-based OTAs fail on a dm-verity-enabled
+device; after the OTA attempt, the device does not boot.</p>
+<p>During a block-based OTA, Android serves the device the difference between
+the two block images (rather than two sets of files). The update checks a
+device build against the corresponding build server at the block level (below
+the filesystem) using one of the following methods:</p>
+<ul>
+<li><b>Full update</b>. Copying the full system image is simple and makes
+patch generation easy but also generates large images that can make applying
+patches expensive.</li>
+<li><b>Incremental update</b>. Using a binary differ tool generates smaller
+images and makes patch application easy, but is memory-intensive when
+generating the patch itself.</li>
+</ul>
+
+<p class="note"><strong>Note:</strong> <code>adb fastboot</code> places the
+exact same bits on the device as a full OTA, so flashing is compatible with
+block OTA.</p>
+
+<h3 id="Unmodified Systems">Updating unmodified systems</h3>
+
+<p>For devices with <i>unmodified</i> system partitions running Android 5.0,
+the download and install process for a block OTA remains the same as for a
+file OTA. However, the OTA update itself might include one or more of the
+following differences:</p>
+<ul>
+<li><b>Download size</b>. Full block OTA updates are approximately the same
+size as full file OTA updates, and incremental updates can be just a few
+megabytes larger.</p>
+
+<img src="../images/ota_size_comparison.png" alt="comparison of OTA sizes">
+
+<p class="img-caption"><strong>Figure 1.</strong> Compare Nexus 6 OTA sizes
+between Android 5.0 and Android 5.1 releases (varying target build changes)</p>
+
+<p>In general, incremental block OTA updates are larger than incremental file
+OTA updates due to:</p>
+<ul>
+<li><i>Data preservation</i>. Block-based OTAs preserve more data (file
+metadata, dm-verity data, ext4 layout, etc.) than file-based OTA.</li>
+<li><i>Computation algorithm differences</i>. In a file OTA update, if a file
+path is identical in both builds, the OTA package contains no data for that
+file. In a block OTA update, determining little or no change in a file depends
+on the quality of the patch computation algorithm and layout of file data in
+both source and target system.</li>
+</ul>
+</li>
+<li><b>Sensitivity to faulty flash and RAM</b>. If a file is corrupted, a file
+OTA succeeds as long as it doesn't touch the corrupted file, but a block OTA
+fails if it detects any corruption on the system partition.</li>
+</ul>
+
+<h3 id="Modified Systems">Updating modified systems</h3>
+<p>For devices with <i>modified</i> system partitions running Android 5.0:</p>
+<ul>
+<li><b>Incremental block OTA updates fail</b>. A system partition might be
+modified during an <code>adb remount</code> or as a result of malware. File
+OTA tolerates some changes to the partition, such as the addition of files
+that are not part of the source or target build. However, block OTA does not
+tolerate additions to the partition, so users will need to install a full OTA
+overwriting any system partition modifications) or flash a new system image to
+enable future OTAs.</li>
+<li><b>Attempts to change modified files cause update failure</b>. For both
+file and block OTA updates, if the OTA attempts to change a file that has been
+modified, the OTA update fails.</li>
+<li><b>Attempts to access modified files generate errors </b><i>(dm-verity
+only)</i>. For both file and block OTA updates, if dm-verity is enabled and
+the OTA attempts to access modified parts of the system filesystem, the OTA
+generates an error.</li>
+</ul> \ No newline at end of file
diff --git a/src/devices/tech/ota/device_code.jd b/src/devices/tech/ota/device_code.jd
new file mode 100755
index 00000000..8d23674c
--- /dev/null
+++ b/src/devices/tech/ota/device_code.jd
@@ -0,0 +1,1154 @@
+page.title=Device-Specific Code
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>The recovery system includes several hooks for inserting device-specific
+code so that OTA updates can also update parts of the device other than the
+Android system (e.g., the baseband or radio processor).</p>
+<p>The following sections and examples customize the <b>tardis</b> device
+produced by the <b>yoyodyne</b> vendor.</p>
+
+<h2>Partition map</h2>
+<p>As of Android 2.3, the platform supports eMMC flash devices and the ext4
+filesystem that runs on those devices. It also supports Memory Technology Device
+(MTD) flash devices and the yaffs2 filesystem from older releases.</p>
+<p>The partition map file is specified by TARGET_RECOVERY_FSTAB; this file is
+used by both the recovery binary and the package-building tools. You can
+specify the name of the map file in TARGET_RECOVERY_FSTAB in BoardConfig.mk.</p>
+<p>A sample partition map file might look like this:</p>
+
+<p><code>device/yoyodyne/tardis/recovery.fstab</code></p>
+
+<pre>
+# mount point fstype device [device2] [options (3.0+ only)]
+
+/sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0
+/cache yaffs2 cache
+/misc mtd misc
+/boot mtd boot
+/recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery
+/system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096
+/data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata
+</pre>
+
+<p>With the exception of <code>/sdcard</code>, which is optional, all mount
+points in this example must be defined (devices may also add extra partitions).
+There are five supported filesystem types:</p>
+<dl>
+<dt>yaffs2</dt>
+<dd>A yaffs2 filesystem atop an MTD flash device. "device" must be the name of
+the MTD partition and must appear in <code>/proc/mtd</code>.</dd>
+<dt>mtd</dt>
+<dd>A raw MTD partition, used for bootable partitions such as boot and
+recovery. MTD is not actually mounted, but the mount point is used as a key to
+locate the partition. "device" must be the name of the MTD partition in
+<code>/proc/mtd</code>.</dd>
+<dt>ext4</dt>
+<dd>An ext4 filesystem atop an eMMC flash device. "device" must be the path of
+the block device.</dd>
+<dt>emmc</dt>
+<dd>A raw eMMC block device, used for bootable partitions such as boot and
+recovery. Similar to the mtd type, eMMc is never actually mounted, but the
+mount point string is used to locate the device in the table.</dd>
+<dt>vfat</dt>
+<dd>A FAT filesystem atop a block device, typically for external storage such
+as an SD card. The device is the block device; device2 is a second block
+device the system attempts to mount if mounting the primary device fails (for
+compatibility with SD cards which may or may not be formatted with a partition
+table).
+<p>All partitions must be mounted in the root directory (i.e. the mount point
+value must begin with a slash and have no other slashes). This restriction
+applies only to mounting filesystems in recovery; the main system is free to
+mount them anywhere. The directories <code>/boot</code>, <code>/recovery</code>,
+and <code>/misc</code> should be raw types (mtd or emmc), while the
+directories <code>/system</code>, <code>/data</code>, <code>/cache</code>, and
+<code>/sdcard</code> (if available) should be filesystem types (yaffs2, ext4,
+or vfat).</p></dd></dl>
+
+<p>Starting in Android 3.0, the recovery.fstab file gains an additional
+optional field, <i>options</i>. Currently the only defined option is <i>length
+</i>, which lets you explicitly specify the length of the partition.
+This length is used when reformatting the partition (e.g., for the userdata
+partition during a data wipe/factory reset operation, or for the system
+partition during installation of a full OTA package). If the length value is
+negative, then the size to format is taken by adding the length value to the
+true partition size. For instance, setting "length=-16384" means the last 16k
+of that partition will <i>not</i> be overwritten when that partition is
+reformatted. This supports features such as encryption of the userdata
+partition (where encryption metadata is stored at the end of the
+partition that should not be overwritten).</p>
+
+<p class="note"><strong>Note:</strong> The <b>device2</b> and <b>options</b>
+fields are optional, creating ambiguity in parsing. If the entry in the fourth
+field on the line begins with a ‘/' character, it is considered a <b>device2
+</b> entry; if the entry does not begin with a ‘/' character, it is considered
+an <b>options</b> field.</p>
+
+<h2 id="recovery-ui">Recovery UI</h2>
+<p>To support devices with different available hardware (physical buttons,
+LEDs, screens, etc.), you can customize the recovery interface to display
+status and access the manually-operated hidden features for each device.</p>
+<p>Your goal is to build a small static library with a couple of C++ objects
+to provide the device-specific functionality. The file <code>
+<b>bootable/recovery/default_device.cpp</b></code> is used by default, and
+makes a good starting point to copy when writing a version of this file for
+your device.</p>
+
+<p><code>device/yoyodyne/tardis/recovery/recovery_ui.cpp</code></p>
+
+<pre>
+#include &lt;linux/input.h&gt;
+
+#include "common.h"
+#include "device.h"
+#include "screen_ui.h"
+</pre>
+
+
+<h3 id="header-item-functions">Header and item functions</h3>
+<p>The Device class requires functions for returning headers and items that
+appear in the hidden recovery menu. Headers describe how to operate the menu
+(i.e. controls to change/select the highlighted item).</p>
+
+<pre>
+static const char* HEADERS[] = { "Volume up/down to move highlight;",
+ "power button to select.",
+ "",
+ NULL };
+
+static const char* ITEMS[] = {"reboot system now",
+ "apply update from ADB",
+ "wipe data/factory reset",
+ "wipe cache partition",
+ NULL };
+</pre>
+
+<p class="note"><strong>Note:</strong> Long lines are truncated (not wrapped),
+so keep the width of your device screen in mind.</p>
+
+<h3 id="customize-checkkey">Customizing CheckKey</h3>
+<p>Next, define your device's RecoveryUI implementation. This example assumes
+the <b>tardis</b> device has a screen, so you can inherit from the built-in
+ScreenRecoveryUIimplementation (see instructions for
+<a href="#devices-without-screens">devices without a screen</a>.) The only
+function to customize from ScreenRecoveryUI is <code>CheckKey()</code>, which
+does the initial asynchronous key handling:</p>
+
+<pre>
+class TardisUI : public ScreenRecoveryUI {
+ public:
+ virtual KeyAction CheckKey(int key) {
+ if (key == KEY_HOME) {
+ return TOGGLE;
+ }
+ return ENQUEUE;
+ }
+};
+</pre>
+
+
+<h4 id="key-constants">KEY constants</h4>
+<p>The KEY_* constants are defined in <code>linux/input.h</code>.<code>
+CheckKey()</code> is called no matter what is going on in the rest of
+recovery: when the menu is toggled off, when it is on, during package
+installation, during userdata wiping, etc. It can return one of four constants:
+</p>
+
+<ul>
+<li><b>TOGGLE</b>. Toggle the display of the menu and/or text log on or off
+</li>
+<li><b>REBOOT</b>. Immediately reboot the device</li>
+<li><b>IGNORE</b>. Ignore this keypress</li>
+<li><b>ENQUEUE</b>. Enqueue this keypress to be consumed synchronously (i.e.,
+by the recovery menu system if the display is enabled)</li>
+</ul>
+
+<p><code>CheckKey()</code> is called each time a key-down event is followed by
+a key-up event for the same key. (The sequence of events A-down B-down B-up
+A-up results only in <code>CheckKey(B)</code> being called.) <code>CheckKey()
+</code> can call <code>IsKeyPressed()</code>, to find out if other keys are
+being held down. (In the above sequence of key events, if <code>CheckKey(B)
+</code> called <code>IsKeyPressed(A)</code> it would have returned true.)</p>
+<p><code>CheckKey()</code> can maintain state in its class; this can be useful
+to detect sequences of keys. This example shows a slightly more complex
+setup: the display is toggled by holding down power and pressing volume-up,
+and the device can be rebooted immediately by pressing the power button five
+times in a row (with no other intervening keys):</p>
+
+<pre>
+class TardisUI : public ScreenRecoveryUI {
+ private:
+ int consecutive_power_keys;
+
+ public:
+ TardisUI() : consecutive_power_keys(0) {}
+
+ virtual KeyAction CheckKey(int key) {
+ if (IsKeyPressed(KEY_POWER) &amp;&amp; key == KEY_VOLUMEUP) {
+ return TOGGLE;
+ }
+ if (key == KEY_POWER) {
+ ++consecutive_power_keys;
+ if (consecutive_power_keys &gt;= 5) {
+ return REBOOT;
+ }
+ } else {
+ consecutive_power_keys = 0;
+ }
+ return ENQUEUE;
+ }
+};
+</pre>
+
+
+<h3 id="screenrecoveryui">ScreenRecoveryUI</h3>
+<p>When using your own images (error icon, installation animation, progress
+bars) with ScreenRecoveryUI, you might need to set some member variables to
+specify attributes such as the number of frames, speed, and overlay offsets.
+You can set the following variables:</p>
+
+<table>
+<tbody>
+<tr>
+<th>Variable Name</th>
+<th>Purpose</th>
+<th>Release</th>
+</tr>
+<tr>
+<td>animation_fps
+</td>
+<td>speed (in frames per second) of animations
+</td>
+<td>Android 5.x and earlier</td>
+</tr>
+<tr>
+<td>installing_frames
+</td>
+<td>number of frames in the installation animation
+</td>
+<td>Android 4.x and earlier</td>
+</tr>
+<tr>
+<td>install_overlay_offset_x,
+install_overlay_offset_y
+</td>
+<td>offset of the per-frame overlay (relative to the base image) for the
+installation animation
+</td>
+<td>Android 4.x and earlier</td>
+</tr>
+</tbody>
+</table>
+
+<p>To set variables, override the <code>ScreenRecoveryUI::Init()</code>
+function in your subclass. Set the values, then call the <code>parent Init()
+</code> function to complete initialization:</p>
+
+<pre>
+class TardisUI : public ScreenRecoveryUI {
+ ...
+ void Init() {
+ // change the speed at which animations run
+ animation_fps = 30;
+
+ ScreenRecoveryUI::Init();
+ }
+</pre>
+
+<p>The default values correspond to the default recovery images; when using
+these images you don't need to provide an <code>Init()</code> function. For
+details on images, see <a href="#recovery-ui-images">Recovery UI Images</a>.
+</p>
+
+<h3 id="device-class">Device Class</h3>
+<p>After you have a RecoveryUI implementation, define your device class
+(subclassed from the built-in Device class). It should create a single
+instance of your UI class and return that from the <code>GetUI()</code>
+function:</p>
+
+<pre>
+class TardisDevice : public Device {
+ private:
+ TardisUI* ui;
+
+ public:
+ TardisDevice() :
+ ui(new TardisUI) {
+ }
+
+ RecoveryUI* GetUI() { return ui; }
+</pre>
+
+<h3 id="startrecovery">StartRecovery</h3>
+<p>The <code>StartRecovery()</code> method is called at the start of recovery,
+after the UI has been initialized and after the arguments have been parsed,
+but before any action has been taken. The default implementation does nothing,
+so you do not need to provide this in your subclass if you have nothing to do:
+</p>
+
+<pre>
+ void StartRecovery() {
+ // ... do something tardis-specific here, if needed ....
+ }
+</pre>
+
+<h3 id="supply-manage-recovery-menu">Supplying and managing recovery menu</h3>
+<p>The system calls two methods to get the list of header lines and the list
+of items. In this implementation, it returns the static arrays defined at the
+top of the file:</p>
+
+<pre>
+const char* const* GetMenuHeaders() { return HEADERS; }
+const char* const* GetMenuItems() { return ITEMS; }
+</pre>
+
+<h4 id="handlemenukey">HandleMenuKey</h4>
+<p>Next, provide a <code>HandleMenuKey()</code> function, which takes a
+keypress and the current menu visibility, and decides what action to take:</p>
+
+<pre>
+ int HandleMenuKey(int key, int visible) {
+ if (visible) {
+ switch (key) {
+ case KEY_VOLUMEDOWN: return kHighlightDown;
+ case KEY_VOLUMEUP: return kHighlightUp;
+ case KEY_POWER: return kInvokeItem;
+ }
+ }
+ return kNoAction;
+ }
+</pre>
+
+<p>The method takes a key code (which has previously been processed and
+enqueued by the <code>CheckKey()</code> method of the UI object), and the
+current state of the menu/text log visibility. The return value is an integer.
+If the value is 0 or higher, that is taken as the position of a menu item,
+which is invoked immediately (see the <code>InvokeMenuItem()</code> method
+below). Otherwise it can be one of the following predefined constants:</p>
+
+<ul>
+<li><b>kHighlightUp</b>. Move the menu highlight to the previous item</li>
+<li><b>kHighlightDown</b>. Move the menu highlight to the next item</li>
+<li><b>kInvokeItem</b>. Invoke the currently highlighted item</li>
+<li><b>kNoAction</b>. Do nothing with this keypress</li>
+</ul>
+
+<p>As implied by the the visible argument, <code>HandleMenuKey()</code> is
+called even if the menu is not visible. Unlike <code>CheckKey()</code>, it is
+<i>not</i> called while recovery is doing something such as wiping data or
+installing a package—it's called only when recovery is idle and waiting for
+input.</p>
+
+<h4 id="trackball-mechanism">Trackball Mechanisms</h4>
+<p>If your device has a trackball-like input mechanism (generates input events
+with type EV_REL and code REL_Y), recovery synthesizes KEY_UP and KEY_DOWN
+keypresses whenever the trackball-like input device reports motion in the Y
+axis. All you need to do is map KEY_UP and KEY_DOWN events onto menu actions.
+This mapping does <i>not</i> happen for <code>CheckKey()</code>, so you can't
+use trackball motions as triggers for rebooting or toggling the display.</p>
+
+<h4 id="modifier-keys">Modifier Keys</h4>
+<p>To check for keys being held down as modifiers, call the <code>IsKeyPressed()
+</code> method of your own UI object. For example, on some
+devices pressing Alt-W in recovery would start a data wipe whether the menu
+was visible or not. YOu could implement like this:</p>
+
+<pre>
+ int HandleMenuKey(int key, int visible) {
+ if (ui->IsKeyPressed(KEY_LEFTALT) &amp;&amp; key == KEY_W) {
+ return 2; // position of the "wipe data" item in the menu
+ }
+ ...
+ }
+</pre>
+
+<p class="note"><strong>Note:</strong> If <b>visible</b> is false, it doesn't
+make sense to return the special values that manipulate the menu (move
+highlight, invoke highlighted item) since the user can't see the highlight.
+However, you can return the values if desired.</p>
+
+<h4 id="invokemenuitem">InvokeMenuItem</h4>
+<p>Next, provide an <code>InvokeMenuItem()</code> method that maps integer
+positions in the array of items returned by <code>GetMenuItems()</code> to
+actions. For the array of items in the tardis example, use:</p>
+
+<pre>
+ BuiltinAction InvokeMenuItem(int menu_position) {
+ switch (menu_position) {
+ case 0: return REBOOT;
+ case 1: return APPLY_ADB_SIDELOAD;
+ case 2: return WIPE_DATA;
+ case 3: return WIPE_CACHE;
+ default: return NO_ACTION;
+ }
+ }
+</pre>
+
+<p>This method can return any member of the BuiltinAction enum to tell the
+system to take that action (or the NO_ACTION member if you want the system to
+do nothing). This is the place to provide additional recovery functionality
+beyond what's in the system: Add an item for it in your menu, execute it here
+when that menu item is invoked, and return NO_ACTION so the system does nothing
+else.</p>
+<p>BuiltinAction contains the following values:</p>
+<ul>
+<li><b>NO_ACTION</b>. Do nothing.</li>
+<li><b>REBOOT</b>. Exit recovery and reboot the device normally.</li>
+<li><b>APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD</b>. Install an update
+package from various places. For details, see
+<a href="#sideloading">Sideloading</a>.</li>
+<li><b>WIPE_CACHE</b>. Reformat the cache partition only. No confirmation
+required as this is relatively harmless.</li>
+<li><b>WIPE_DATA</b>. Reformat the userdata and cache partitions, also known
+as a factory data reset. The user is asked to confirm this action before
+proceeding.</li>
+</ul>
+<p>The last method, <code>WipeData()</code>, is optional and is called
+whenever a data wipe operation is initiated (either from recovery via the menu
+or when the user has chosen to do a factory data reset from the main system).
+This method is called before the user data and cache partitions are wiped. If
+your device stores user data anywhere other than those two partitions, you
+should erase it here. You should return 0 to indicate success and another
+value for failure, though currently the return value is ignored. The user data
+and cache partitions are wiped whether you return success or failure.</p>
+
+<pre>
+ int WipeData() {
+ // ... do something tardis-specific here, if needed ....
+ return 0;
+ }
+</pre>
+
+<h4 id="make-device">Make Device</h4>
+<p>Finally, include some boilerplate at the end of the recovery_ui.cpp file
+for the <code>make_device()</code> function that creates and returns an
+instance of your Device class:</p>
+
+<pre>
+class TardisDevice : public Device {
+ // ... all the above methods ...
+};
+
+Device* make_device() {
+ return new TardisDevice();
+}
+</pre>
+
+<h3 id="build-link-device-recovery">Build and link to device recovery</h3>
+<p>After completing the recovery_ui.cpp file, built it and link it to recovery
+on your device. In Android.mk, create a static library that contains only this
+C++ file:</p>
+
+<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p>
+
+<pre>
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+LOCAL_C_INCLUDES += bootable/recovery
+LOCAL_SRC_FILES := recovery_ui.cpp
+
+# should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk
+LOCAL_MODULE := librecovery_ui_tardis
+
+include $(BUILD_STATIC_LIBRARY)
+</pre>
+
+<p>Then, in the board configuration for this device, specify your static
+library as the value of TARGET_RECOVERY_UI_LIB.</p>
+
+<pre>
+device/yoyodyne/tardis/BoardConfig.mk
+ [...]
+
+# device-specific extensions to the recovery UI
+TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
+</pre>
+
+
+<h2 id="recovery-ui-images">Recovery UI images</h2>
+<p>The recovery user interface consists images. Ideally, users never interact
+with the UI: During a normal update, the phone boots into recovery, fills the
+installation progress bar, and boots back into the new system without input
+from the user. In the event of a system update problem, the only user action
+that can be taken is to call customer care.</p>
+<p>An image-only interface obviates the need for localization. However, as of
+Android 5.x the update can display a string of text (e.g. "Installing system
+update...") along with the image. For details, see <a href="#recovery-text">
+Localized recovery text</a>.</p>
+
+<h3 id="recovery-5.x">Android 5.x</h3>
+<p>The Android 5.x recovery UI uses two main images: the <b>error</b> image
+and the <b>installing</b> animation.</p>
+
+<table>
+<tbody>
+<tr>
+<td>
+<img src="../images/icon_error.png" alt="image shown during ota error">
+<p class="img-caption"><strong>Figure 1.</strong> icon_error.png</p>
+</td>
+<td>
+<img src="../images/icon_installing_5x.png" alt="image shown during ota install"
+height="275">
+<p class="img-caption"><strong>Figure 2.</strong> icon_installing.png</p>
+</td>
+</tr>
+</tbody>
+</table>
+
+<p>The installing animation is represented as a single PNG image with
+different frames of the animation interlaced by row. For example, for a
+7-frame animation that is 200x200, create a single 200x1400 image where first
+frame is rows 0, 7, 14, 21, ...; the second frame is rows 1, 8, 15, 22, ...;
+etc. The combined image includes a text chunk that indicates the number of
+animation frames. The tool <code>bootable/recovery/interlace-frames.py</code>
+takes a set of input frames and combines them into the necessary composite
+image used by recovery.</p>
+
+<p>Default images are available in different densities and are located in
+<code>bootable/recovery/res-$DENSITY/images</code> (e.g.,
+<code>bootable/recovery/res-hdpi/images</code>). To use a static image during
+installation, you need only provide the icon_installing.png image and set the
+number of frames in the animation to 0 (the error icon is not animated; it is
+always a static image).</p>
+
+
+<h3 id="recovery-4.x">Android 4.x and earlier</h3>
+<p>The Android 4.x and earlier recovery UI uses the <b>error</b> image (shown
+above) and the <b>installing</b> animation plus several overlay images:</p>
+
+<table>
+<tbody>
+<tr>
+<td rowspan="2">
+<img src="../images/icon_installing.png" alt="image shown during ota install">
+<p class="img-caption"><strong>Figure 3.</strong> icon_installing.png</p>
+</td>
+<td>
+<img src="../images/icon_installing_overlay01.png" alt="image shown as first
+overlay">
+<p class="img-caption"><strong>Figure 4.</strong> icon-installing_overlay01.png
+</p>
+</td>
+</tr>
+<tr>
+<td>
+<img src="../images/icon_installing_overlay07.png" alt="image shown as seventh
+overlay">
+<p class="img-caption"><strong>Figure 5.</strong> icon_installing_overlay07.png
+</p>
+</td>
+</tr>
+</tbody>
+</table>
+
+
+<p>During installation, the on-screen display is constructed by drawing the
+icon_installing.png image, then drawing one of the overlay frames on top of it
+at the proper offset. Here, a red box is superimposed to highlight where the
+overlay is placed on top of the base image:</p>
+
+<table style="border-collapse:collapse;">
+<tbody>
+<tr>
+<td><img align="center" src="../images/composite01.png" alt="composite image of
+install plus first overlay">
+<p class="img-caption"><strong>Figure 6.</strong> Installing animation frame 1
+(icon_installing.png + icon_installing_overlay01.png)
+</td>
+<td><img align="center" src="../images/composite01.png" alt="composite image of
+install plus seventh overlay">
+<p class="img-caption"><strong>Figure 7.</strong> Installing animation frame 7
+(icon_installing.png + icon_installing_overlay07.png)
+</td>
+</tr>
+</tbody>
+</table>
+
+<p>Subsequent frames are displayed by drawing <i>only</i> the next overlay
+image atop what's already there; the base image is not redrawn.</p>
+
+<p>The number of frames in the animation, desired speed, and x- and y-offsets
+of the overlay relative to the base are set by member variables of the
+ScreenRecoveryUI class. When using custom images instead of default images,
+override the <code>Init()</code> method in your subclass to change these
+values for your custom images (for details, see <a href="#screenrecoveryui">
+ScreenRecoveryUI</a>). The script <code>bootable/recovery/make-overlay.py
+</code> can assist in converting a set of image frames to the "base image +
+overlay images" form needed by recovery, including computing of the necessary
+offsets.</p>
+
+<p>Default images are located in <code>bootable/recovery/res/images</code>. To
+use a static image during installation, you need only provide the
+icon_installing.png image and set the number of frames in the animation to 0
+(the error icon is not animated; it is always a static image).</p>
+
+
+<h3 id="recovery-text">Localized recovery text</h3>
+<p>Android 5.x displays a string of text (e.g., "Installing system update...")
+along with the image. When the main system boots into recovery it passes the
+user's current locale as a command-line option to recovery. For each message
+to display, recovery includes a second composite image with pre-rendered text
+strings for that message in each locale.</p>
+
+<p>Sample image of recovery text strings:</p>
+
+<img src="../images/installing_text.png" alt="image of recovery text">
+<p class="img-caption"><strong>Figure 8.</strong> Localized text for recovery
+messages</p>
+
+<p>Recovery text can display the following messages:</p>
+<ul>
+<li>Installing system update...</li>
+<li>Error!</li>
+<li>Erasing... (when doing a data wipe/factory reset)</li>
+<li>No command (when a user boots into recovery manually)</li>
+</ul>
+
+<p>The Android app in <code>development/tools/recovery_l10/</code> renders
+localizations of a message and creates the composite image. For details on
+using this app, refer to the comments in <code>development/tools/recovery_l10n/
+src/com/android/recovery_l10n/Main.java</code>.
+
+<p>When a user boots into recovery manually, the locale might not be available
+and no text is displayed. Do not make the text messages critical to the
+recovery process.</p>
+
+<p class="note"><strong>Note:</strong> The hidden interface that displays log
+messages and allows the user to select actions from the menu is available only
+in English.</p>
+
+
+<h2 id="progress-bars">Progress bars</h2>
+<p>Progress bars can appear below the main image (or animation). The progress
+bar is made by combining two input images, which must be of the same size:</p>
+
+<img src="../images/progress_empty.png" alt="empty progress bar">
+<p class="img-caption"><strong>Figure 9.</strong> progress_empty.png</p>
+<img src="../images/progress_fill.png" alt="full progress bar">
+<p class="img-caption"><strong>Figure 10.</strong> progress_fill.png</p>
+
+<p>The left end of the <i>fill</i> image is displayed next to the right end of
+the <i>empty</i> image to make the progress bar. The position of the boundary
+between the two images is changed to indicate the progress. For example, with
+the above pairs of input images, display:</p>
+
+<img src="../images/progress_1.png" alt="progress bar at 1%">
+<p class="img-caption"><strong>Figure 11.</strong> Progress bar at 1%></p>
+<img src="../images/progress_10.png" alt="progress bar at 10%">
+<p class="img-caption"><strong>Figure 12.</strong> Progress bar at 10%</p>
+<img src="../images/progress_50.png" alt="progress bar at 50%">
+<p class="img-caption"><strong>Figure 13.</strong> Progress bar at 50%</p>
+
+<p>You can provide device-specific versions of these images by placing them
+into (in this example) <code>device/yoyodyne/tardis/recovery/res/images</code>
+. Filenames must match the ones listed above; when a file is found in that
+directory, the build system uses it in preference to the corresponding default
+image. Only PNGs in RGB or RGBA format with 8-bit color depth are supported.
+</p>
+
+<p class="note"><strong>Note:</strong> In Android 5.x, if the locale is known
+to recovery and is a right-to-left (RTL) language (Arabic, Hebrew, etc.), the
+progress bar fills from right to left.</p>
+
+
+<h2 id="devices-without-screens">Devices without screens</h2>
+<p>Not all Android devices have screens. If your device is a headless appliance
+or has an audio-only interface, you may need to do more extensive customization
+of recovery UI. Instead of creating a subclass of ScreenRecoveryUI, subclass its
+parent class RecoveryUI directly.</p>
+<p>RecoveryUI has methods for handling a lower-level UI operations such as
+"toggle the display," "update the progress bar," "show the menu," "change the
+menu selection," etc. You can override these to provide an appropriate
+interface for your device. Maybe your device has LEDs where you can use
+different colors or patterns of flashing to indicate state, or maybe you can
+play audio. (Perhaps you don't want to support a menu or the "text display"
+mode at all; you can prevent accessing them with <code>CheckKey()</code> and
+<code>HandleMenuKey()</code> implementations that never toggle the display on
+or select a menu item. In this case, many of the RecoveryUI methods you need
+to provide can just be empty stubs.)</p>
+<p>See <code>bootable/recovery/ui.h</code> for the declaration of RecoveryUI
+to see what methods you must support. RecoveryUI is abstract—some methods are
+pure virtual and must be provided by subclasses—but it does contain the code
+to do processing of key inputs. You can override that too, if your device
+doesn't have keys or you want to process them differently.</p>
+
+<h2 id="updater">Updater</h2>
+<p>You can use device-specific code in the installation of the update package
+by providing your own extension functions that can be called from within your
+updater script. Here's a sample function for the tardis device:</p>
+
+<p><code>device/yoyodyne/tardis/recovery/recovery_updater.c</code></p>
+<pre>
+#include &lt;stdlib.h&gt;
+#include &lt;string.h&gt;
+
+#include "edify/expr.h"
+</pre>
+
+<p>Every extension function has the same signature. The arguments are the name
+by which the function was called, a <code>State*</code> cookie, the number of
+incoming arguments, and an array of <code>Expr*</code> pointers representing
+the arguments. The return value is a newly-allocated <code>Value*</code>.</p>
+
+<pre>
+Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) {
+ if (argc != 2) {
+ return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+ }
+</pre>
+
+<p>Your arguments have not been evaluated at the time your function is
+called—your function's logic determines which of them get evaluated and how
+many times. Thus, you can use extension functions to implement your own
+control structures. <code>Call Evaluate()</code> to evaluate an <code>Expr*
+</code> argument, returning a <code>Value*</code>. If <code>Evaluate()</code>
+returns NULL, you should free any resources you're holding and immediately
+return NULL (this propagates aborts up the edify stack). Otherwise, you take
+ownership of the Value returned and are responsible for eventually calling
+<code>FreeValue()</code> on it.</p>
+
+<p>Suppose the function needs two arguments: a string-valued <b>key</b> and a
+blob-valued <b>image</b>. You could read arguments like this:</p>
+
+<pre>
+ Value* key = EvaluateValue(state, argv[0]);
+ if (key == NULL) {
+ return NULL;
+ }
+ if (key->type != VAL_STRING) {
+ ErrorAbort(state, "first arg to %s() must be string", name);
+ FreeValue(key);
+ return NULL;
+ }
+ Value* image = EvaluateValue(state, argv[1]);
+ if (image == NULL) {
+ FreeValue(key); // must always free Value objects
+ return NULL;
+ }
+ if (image->type != VAL_BLOB) {
+ ErrorAbort(state, "second arg to %s() must be blob", name);
+ FreeValue(key);
+ FreeValue(image)
+ return NULL;
+ }
+</pre>
+
+<p>Checking for NULL and freeing previously evaluated arguments can get tedious
+for multiple arguments. The <code>ReadValueArgs()</code> function can make this
+easier. Instead of the code above, you could have written this:</p>
+
+<pre>
+ Value* key;
+ Value* image;
+ if (ReadValueArgs(state, argv, 2, &amp;key, &amp;image) != 0) {
+ return NULL; // ReadValueArgs() will have set the error message
+ }
+ if (key->type != VAL_STRING || image->type != VAL_BLOB) {
+ ErrorAbort(state, "arguments to %s() have wrong type", name);
+ FreeValue(key);
+ FreeValue(image)
+ return NULL;
+ }
+</pre>
+
+<p><code>ReadValueArgs()</code> doesn't do type-checking, so you must do that
+here; it's more convenient to do it with one <b>if</b> statement at
+the cost of producing a somewhat less specific error message when it fails.
+But <code>ReadValueArgs()</code> does handle evaluating each argument and
+freeing all the previously-evaluated arguments (as well as setting a useful
+error message) if any of the evaluations fail. You can use a <code>
+ReadValueVarArgs()</code> convenience function for evaluating a variable
+number of arguments (it returns an array of <code>Value*</code>).</p>
+
+<p>After evaluating the arguments, do the work of the function:</p>
+
+<pre>
+ // key-&gt;data is a NUL-terminated string
+ // image-&gt;data and image-&gt;size define a block of binary data
+ //
+ // ... some device-specific magic here to
+ // reprogram the tardis using those two values ...
+</pre>
+
+<p>The return value must be a <code>Value*</code> object; ownership of this
+object will pass to the caller. The caller takes ownership of any data pointed
+to by this <code>Value*</code>—specifically the datamember.</p>
+<p>In this instance, you want to return a true or false value to indicate
+success. Remember the convention that the empty string is <i>false</i> and all
+other strings are <i>true</i>. You must malloc a Value object with a malloc'd
+copy of the constant string to return, since the caller will <code>free()
+</code> both. Don't forget to call <code>FreeValue()</code> on the objects you
+got by evaluating your arguments!</p>
+
+<pre>
+ FreeValue(key);
+ FreeValue(image);
+
+ Value* result = malloc(sizeof(Value));
+ result->type = VAL_STRING;
+ result->data = strdup(successful ? "t" : "");
+ result->size = strlen(result->data);
+ return result;
+}
+</pre>
+
+<p>The convenience function <code>StringValue()</code> wraps a string into a
+new Value object. Use to write the above code more succinctly:</p>
+
+<pre>
+ FreeValue(key);
+ FreeValue(image);
+
+ return StringValue(strdup(successful ? "t" : ""));
+}
+</pre>
+
+<p>To hook functions into the edify interpreter, provide the function
+<code>Register_<i>foo</i></code> where <i>foo</i> is the name of the
+static library containing this code. Call <code>RegisterFunction()</code> to
+register each extension function. By convention, name device-specific
+functions <code><i>device</i>.<i>whatever</i></code> to avoid conflicts with
+future built-in functions added.</p>
+
+<pre>
+void Register_librecovery_updater_tardis() {
+ RegisterFunction("tardis.reprogram", ReprogramTardisFn);
+}
+</pre>
+
+<p>You can now configure the makefile to build a static library with your
+code. (This is the same makefile used to customize the recovery UI in the
+previous section; your device may have both static libraries defined here.)</p>
+
+<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p>
+
+<pre>
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := recovery_updater.c
+LOCAL_C_INCLUDES += bootable/recovery
+</pre>
+
+<p>The name of the static library must match the name of the
+<code>Register_<i>libname</i></code> function contained within it.</p>
+
+<pre>
+LOCAL_MODULE := librecovery_updater_tardis
+include $(BUILD_STATIC_LIBRARY)
+</pre>
+
+<p>Finally, configure the build of recovery to pull in your library. Add your
+library to TARGET_RECOVERY_UPDATER_LIBS (which may contain multiple libraries;
+they all get registered). If your code depends on other static libraries that
+are not themselves edify extensions (i.e., they don't have a
+<code>Register_<i>libname</i></code> function), you can list those in
+TARGET_RECOVERY_UPDATER_EXTRA_LIBS to link them to updater without calling
+their (non-existent) registration function. For example, if your
+device-specific code wanted to use zlib to decompress data, you would include
+libz here.</p>
+
+<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p>
+
+<pre>
+ [...]
+
+# add device-specific extensions to the updater binary
+TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis
+TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
+</pre>
+
+<p>The updater scripts in your OTA package can now call your function as any
+other. To reprogram your tardis device, the update script might contain:
+<code>tardis.reprogram("the-key", package_extract_file("tardis-image.dat"))
+</code>. This uses the single-argument version of the built-in function <code>
+package_extract_file()</code>, which returns the contents of a file extracted
+from the update package as a blob to produce the second argument to the new
+extension function.</p>
+
+<h2>OTA package generation</h2>
+<p>The final component is getting the OTA package generation tools to know
+about your device-specific data and emit updater scripts that include calls to
+your extension functions.</p>
+<p>First, get the build system to know about a device-specific blob of data.
+Assuming your data file is in <code>device/yoyodyne/tardis/tardis.dat</code>,
+declare the following in your device's AndroidBoard.mk:</p>
+
+<p><code>device/yoyodyne/tardis/AndroidBoard.mk</code></p>
+<pre>
+ [...]
+
+$(call add-radio-file,tardis.dat)
+</pre>
+
+<p>You could also put it in an Android.mk instead, but then it must to be
+guarded by a device check, since all the Android.mk files in the tree are
+loaded no matter what device is being built. (If your tree includes multiple
+devices, you only want the tardis.dat file added when building the tardis
+device.)</p>
+
+<p><code>device/yoyodyne/tardis/Android.mk</code></p>
+<pre>
+ [...]
+
+# an alternative to specifying it in AndroidBoard.mk
+ifeq (($TARGET_DEVICE),tardis)
+ $(call add-radio-file,tardis.dat)
+endif
+</pre>
+
+<p>These are called radio files for historical reasons; they may have nothing
+to do with the device radio (if present). They are simply opaque blobs of data
+the build system copies into the target-files .zip used by the OTA generation
+tools. When you do a build, tardis.dat is stored in the target-files.zip as
+<code>RADIO/tardis.dat</code>. You can call <code>add-radio-file</code>
+multiple times to add as many files as you want.</p>
+
+<h3 id="python-module">Python module</h3>
+<p>To extend the release tools, write a Python module (must be named
+releasetools.py) the tools can call into if present. Example:</p>
+
+<p><code>device/yoyodyne/tardis/releasetools.py</code></p>
+<pre>
+import common
+
+def FullOTA_InstallEnd(info):
+ # copy the data into the package.
+ tardis_dat = info.input_zip.read("RADIO/tardis.dat")
+ common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat)
+
+ # emit the script code to install this data on the device
+ info.script.AppendExtra(
+ """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
+</pre>
+
+<p>A separate function handles the case of generating an incremental OTA
+package. For this example, suppose you need to reprogram the tardis only when
+the tardis.dat file has changed between two builds.</p>
+<pre>
+def IncrementalOTA_InstallEnd(info):
+ # copy the data into the package.
+ source_tardis_dat = info.source_zip.read("RADIO/tardis.dat")
+ target_tardis_dat = info.target_zip.read("RADIO/tardis.dat")
+
+ if source_tardis_dat == target_tardis_dat:
+ # tardis.dat is unchanged from previous build; no
+ # need to reprogram it
+ return
+
+ # include the new tardis.dat in the OTA package
+ common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat)
+
+ # emit the script code to install this data on the device
+ info.script.AppendExtra(
+ """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
+</pre>
+
+<h4 id="module-functions">Module functions</h4>
+<p>You can provide the following functions in the module (implement only the
+ones you need).</p>
+<dl>
+<dt><code>FullOTA_Assertions()</code></dt>
+<dd>Called near the start of generating a full OTA. This is a good place to
+emit assertions about the current state of the device. Do not emit script
+commands that make changes to the device.</dd>
+<dt><code>FullOTA_InstallBegin()</code></dt>
+<dd>Called after all the assertions about the device state have passed but
+before any changes have been made. You can emit commands for device-specific
+updates that must run before anything else on the device has been changed.</dd>
+<dt><code>FullOTA_InstallEnd()</code></dt>
+<dd>Called at the end of the script generation, after the script commands to
+update the boot and system partitions have been emitted. You can also emit
+additional commands for device-specific updates.</dd>
+<dt><code>IncrementalOTA_Assertions()</code></dt>
+<dd>Similar to <code>FullOTA_Assertions()</code> but called when generating an
+incremental update package.</dd>
+<dt><code>IncrementalOTA_VerifyBegin()</code></dt>
+<dd>Called after all assertions about the device state have passed but before
+any changes have been made. You can emit commands for device-specific updates
+that must run before anything else on the device has been changed.</dd>
+<dt><code>IncrementalOTA_VerifyEnd()</code></dt>
+<dd>Called at the end of the verification phase, when the script has finished
+confirming the files it is going to touch have the expected starting contents.
+At this point nothing on the device has been changed. You can also emit code for
+additional device-specific verifications.</dd>
+<dt><code>IncrementalOTA_InstallBegin()</code></dt>
+<dd>Called after files to be patched have been verified as having the expected
+<i>before</i> state but before any changes have been made. You can emit
+commands for device-specific updates that must run before anything else on the
+device has been changed.</dd>
+<dt><code>IncrementalOTA_InstallEnd()</code></dt>
+<dd>Similar to its full OTA package counterpart, this is called at the end of
+the script generation, after the script commands to update the boot and system
+partitions have been emitted. You can also emit additional commands for
+device-specific updates.</dd>
+</dl>
+
+<p class="note"><strong>Note:</strong> If the device loses power, OTA
+installation may restart from the beginning. Be prepared to cope with devices
+on which these commands have already been run, fully or partially.</p>
+
+<h4 id="pass-functions-to-info">Pass functions to info objects</h4>
+<p>Pass functions to a single info object that contains various useful items:
+</p>
+<ul>
+<li><b>info.input_zip</b>. (Full OTAs only) The <code>zipfile.ZipFile</code>
+object for the input target-files .zip.</li>
+<li><b>info.source_zip</b>. (Incremental OTAs only) The <code>zipfile.ZipFile
+</code> object for the source target-files .zip (the build already on the
+device when the incremental package is being installed).</li>
+<li><b>info.target_zip</b>. (Incremental OTAs only) The <code>zipfile.ZipFile
+</code> object for the target target-files .zip (the build the incremental
+package puts on the device).</li>
+<li><b>info.output_zip</b>. Package being created; a <code>zipfile.ZipFile
+</code> object opened for writing. Use common.ZipWriteStr(info.output_zip,
+<i>filename</i>, <i>data</i>) to add a file to the package.</li>
+<li><b>info.script</b>. Script object to which you can append commands. Call
+<code>info.script.AppendExtra(<i>script_text</i>)</code> to output text into
+the script. Make sure output text ends with a semicolon so it does not run
+into commands emitted afterwards.</li>
+</ul>
+
+<p>For details on the info object, refer to the
+<a href="http://docs.python.org/library/zipfile.html">Python Software Foundation
+documentation for ZIP archives</a>.</p>
+
+<h4 id="specify-module-location">Specify module location</h4>
+<p>Specify the location of your device's releasetools.py script in your
+BoardConfig.mk file:</p>
+
+<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p>
+
+<pre>
+ [...]
+
+TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
+</pre>
+
+<p>If TARGET_RELEASETOOLS_EXTENSIONS is not set, it defaults to the <code>
+$(TARGET_DEVICE_DIR)/../common</code> directory (<code>device/yoyodyne/common
+</code> in this example). It's best to explicitly define the location of the
+releasetools.py script. When building the tardis device, the releasetools.py
+script is included in the target-files .zip file (<code>META/releasetools.py
+</code>).</p>
+<p>When you run the release tools (either <code>img_from_target_files</code>
+or <code>ota_from_target_files</code>), the releasetools.py script in the
+target-files .zip, if present, is preferred over the one from the Android
+source tree. You can also explicitly specify the path to the device-specific
+extensions with the <code>-s</code> (or <code>--device_specific</code>)
+option, which takes the top priority. This enables you to correct errors and
+make changes in the releasetools extensions and apply those changes to old
+target-files.</p>
+<p>Now, when you run <code>ota_from_target_files</code>, it automatically
+picks up the device-specific module from the target_files .zip file and uses
+it when generating OTA packages:</p>
+
+<pre>
+% <b>./build/tools/releasetools/ota_from_target_files \
+ -i PREVIOUS-tardis-target_files.zip \
+ dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
+unzipping target target-files...
+<b>using device-specific extensions from target_files</b>
+unzipping source target-files...
+ [...]
+done.
+</pre>
+
+<p>Alternatively, you can specify device-specific extensions when you run
+<code>ota_from_target_files</code>.</p>
+
+<pre>
+% <b>./build/tools/releasetools/ota_from_target_files \
+ -s device/yoyodyne/tardis \ # specify the path to device-specific extensions
+ -i PREVIOUS-tardis-target_files.zip \
+ dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
+unzipping target target-files...
+<b>loaded device-specific extensions from device/yoyodyne/tardis</b>
+unzipping source target-files...
+ [...]
+done.
+</pre>
+
+<p class="note"><strong>Note:</strong> For a complete list of options, refer
+to the <code>ota_from_target_files</code> comments in <code>
+build/tools/releasetools/ota_from_target_files</code>.</p>
+
+
+<h2 id="sideloading">Sideloading</h2>
+<p>Recovery has a <b>sideloading</b> mechanism for manually installing an
+update package without downloading it over-the-air by the main system.
+Sideloading is useful for debugging or making changes on devices where the
+main system can't be booted.</p>
+<p>Historically, sideloading has been done through loading packages off the
+device's SD card; in the case of a non-booting device, the package can be put
+onto the SD card using some other computer and then the SD card inserted into
+the device. To accommodate Android devices without removable external storage,
+recovery supports two additional mechanisms for sideloading: loading packages
+from the cache partition, and loading them over USB using adb.</p>
+<p>To invoke each sideload mechanism, your device's <code>
+Device::InvokeMenuItem()</code> method can return the following values of
+BuiltinAction:</p>
+
+<ul>
+<li><b>APPLY_EXT</b>. Sideload an update package from external storage (<code>
+/sdcard</code> directory). Your recovery.fstab must define the <code>/sdcard
+</code> mount point. This is not usable on devices that emulate an SD card
+with a symlink to <code>/data</code> (or some similar mechanism). <code>/data
+</code> is typically not available to recovery because it may be encrypted.
+The recovery UI displays a menu of .zip files in <code>/sdcard</code> and
+allows the user to select one.</li>
+<li><b>APPLY_CACHE</b>. Similar to loading a package from <code>/sdcard</code>
+except that the <code>/cache</code> directory (which <i>is</i> always
+available to recovery) is used instead. From the regular system, <code>/cache
+</code> is only writable by privileged users, and if the device isn't bootable
+then the <code>/cache</code> directory can't be written to at all (which makes
+this mechanism of limited utility).</li>
+<li><b>APPLY_ADB_SIDELOAD</b>. Allows user to send a package to the device via
+a USB cable and the adb development tool. When this mechanism is invoked,
+recovery starts up its own mini version of the adbd daemon to let adb on a
+connected host computer talk to it. This mini version supports only a single
+command: <code>adb sideload <i>filename</i></code>. The named file is sent
+from the host machine to the device, which then verifies and installs it just
+as if it had been on local storage.</li>
+</ul>
+
+<p>A few caveats:</p>
+<ul>
+<li>Only USB transport is supported.</li>
+<li>If your recovery runs adbd normally (usually true for userdebug and eng
+builds), that will be shut down while the device is in adb sideload mode and
+will be restarted when adb sideload has finished receiving a package. While in
+adb sideload mode, no adb commands other than <code>sideload</code> work (
+<code>logcat</code>, <code>reboot</code>, <code>push</code>, <code>pull</code>
+, <code>shell</code>, etc. all fail).</li>
+<li>You cannot exit adb sideload mode on the device. To abort, you can send
+<code>/dev/null</code> (or anything else that's not a valid package) as the
+package, and then the device will fail to verify it and stop the installation
+procedure. The RecoveryUI implementation's <code>CheckKey()</code> method
+will continue to be called for keypresses, so you can provide a key sequence
+that reboots the device and works in adb sideload mode.</li>
+</ul> \ No newline at end of file
diff --git a/src/devices/tech/ota/index.jd b/src/devices/tech/ota/index.jd
new file mode 100755
index 00000000..a65418c5
--- /dev/null
+++ b/src/devices/tech/ota/index.jd
@@ -0,0 +1,160 @@
+page.title=OTA Updates
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>Android devices in the field can receive and install over-the-air (OTA)
+updates to the system and application software. Devices have a special
+recovery partition with the software needed to unpack a downloaded update
+package and apply it to the rest of the system.</p>
+<p>This section describes the structure of these packages and the tools
+provided to build them. It is intended for developers who want to
+make the OTA update system work on new Android devices and those who are
+building update packages for use with released devices. OTA updates are
+designed to upgrade the underlying operating system and the read-only apps
+installed on the system partition; these updates do <i>not</i> affect
+applications installed by the user from Google Play.
+</p>
+<p>This section describes the OTA system as of the Android 5.x release. For
+help porting OTA-related code from older releases, see <a href="#migrating">
+Migrating from previous releases</a>.
+</p>
+
+<h2 id="android-device-layout">Android device layout</h2>
+<p>The flash space on an Android device typically contains the following
+partitions.</p>
+
+<dl>
+<dt>boot</dt>
+<dd>Contains the Linux kernel and a minimal root filesystem (loaded into a RAM
+disk). It mounts system and other partitions and starts the runtime located on
+the system partition.</dd>
+<dt>system</dt>
+<dd>Contains system applications and libraries that have source code available
+on Android Open Source Project (AOSP). During normal operation, this partition
+is mounted read-only; its contents change only during an OTA update.</dd>
+<dt>vendor</dt>
+<dd>Contains system applications and libraries that do <em>not</em> have
+source code available on Android Open Source Project (AOSP). During normal
+operation, this partition is mounted read-only; its contents change only
+during an OTA update.</dd>
+<dt>userdata</dt>
+<dd>Stores the data saved by applications installed by the user, etc. This
+partition is not normally touched by the OTA update process.</dd>
+<dt>cache</dt>
+<dd>Temporary holding area used by a few applications (accessing this
+partition requires special app permissions) and for storage of downloaded OTA
+update packages. Other programs use this space with the expectation that files
+can disappear at any time. Some OTA package installations may result in this
+partition being wiped completely.</dd>
+<dt>recovery</dt>
+<dd>Contains a second complete Linux system, including a kernel and the
+special recovery binary that reads a package and uses its contents to update
+the other partitions.</dd>
+<dt>misc</dt>
+<dd>Tiny partition used by recovery to stash some information away about what
+it's doing in case the device is restarted while the OTA package is being
+applied.</dd></dl>
+
+<h2 id="life-ota-update">Life of an OTA update</h2>
+<p>A typical OTA update contains the following steps:</p>
+<ol>
+<li>Device performs regular check in with OTA servers and is notified of the
+availability of an update, including the URL of the update package and a
+description string to show the user.</li>
+<li>Update downloads to a cache or data partition, and its cryptographic
+signature is verified against the certificates in
+<code>/system/etc/security/otacerts.zip</code>. User is prompted to install the
+update.</li>
+<li>Device reboots into recovery mode, in which the kernel and system in the
+recovery partition are booted instead of the kernel in the boot partition.</li>
+<li>Recovery binary is started by init. It finds command-line arguments in
+<code>/cache/recovery/command</code> that point it to the downloaded package.
+</li>
+<li>Recovery verifies the cryptographic signature of the package against the
+public keys in <code>/res/keys</code> (part of the RAM disk contained in the
+recovery partition).</li>
+<li>Data is pulled from the package and used to update the boot, system,
+and/or vendor partitions as necessary. One of the new files left on the system
+partition contains the contents of the new recovery partition.</li>
+<li>Device reboots normally. <ol style="list-style-type:lower-alpha">
+<li>The newly updated boot partition is loaded, and it mounts and starts
+executing binaries in the newly updated system partition.</li>
+<li>As part of normal startup, the system checks the contents of the recovery
+partition against the desired contents (which were previously stored as a file
+in <code>/system</code>). They are different, so the recovery partition is
+reflashed with the desired contents. (On subsequent boots, the recovery
+partition already contains the new contents, so no reflash is necessary.)</li>
+</ol></li>
+</ol>
+<p>The system update is complete!</p>
+
+<h2 id="migrating">Migrating from Previous Releases</h2>
+
+<p>When migrating from Android 2.3/3.0/4.0 release, the major change is the
+conversion of all the device-specific functionality from a set of C functions
+with predefined names to C++ objects. The following table lists the old
+functions and the new methods that serve a roughly equivalent purpose:</p>
+
+<table>
+<tbody>
+<tr>
+<th>C function</th>
+<th>C++ method</th>
+</tr>
+<tr>
+<td>device_recovery_start()</td>
+<td>Device::RecoveryStart()</td>
+</tr>
+<tr>
+<td>device_toggle_display()<br>
+device_reboot_now()<br>
+</td>
+<td>RecoveryUI::CheckKey()<br>
+(also RecoveryUI::IsKeyPressed())<br>
+</td>
+</tr>
+<tr>
+<td>device_handle_key()</td>
+<td>Device::HandleMenuKey()</td>
+</tr>
+<tr>
+<td>device_perform_action()</td>
+<td>Device::InvokeMenuItem()</td>
+</tr>
+<tr>
+<td>device_wipe_data()</td>
+<td>Device::WipeData()</td>
+</tr>
+<tr>
+<td>device_ui_init()</td>
+<td>ScreenRecoveryUI::Init()</td>
+</tr>
+</tbody>
+</table>
+
+<p>Conversion of old functions to new methods should be reasonably
+straightforward. Don't forget to add the new <code>make_device()</code>
+function to create and return an instance of your new Device subclass.</p> \ No newline at end of file
diff --git a/src/devices/tech/ota/inside_packages.jd b/src/devices/tech/ota/inside_packages.jd
new file mode 100755
index 00000000..41b3d5ca
--- /dev/null
+++ b/src/devices/tech/ota/inside_packages.jd
@@ -0,0 +1,288 @@
+page.title=Inside OTA Packages
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>The system builds the updater binary from <code>bootable/recovery/updater
+</code> and uses it in an OTA package.</p>The package itself is a .zip file
+(<code>ota_update.zip</code>, <code>incremental_ota_update.zip</code>) that
+contains the executable binary <code>META-INF/com/google/android/update-binary
+</code>.
+
+<p>Updater contains several builtin functions and an interpreter for an
+extensible scripting language (<b>edify</b>) that supports commands for typical
+update-related tasks. Updater looks in the package .zip file for a script in the
+file <code>META-INF/com/google/android/updater-script</code>.</p>
+
+<p class="note"><strong>Note:</strong> Using the edify script and/or builtin
+functions is not a common activity, but can be helpful if you need to debug the
+update file.</p>
+
+<h2 id="edify-syntax">Edify syntax</h2>
+<p>An edify script is a single expression in which all values are strings.
+Empty strings are <i>false</i> in a Boolean context and all other strings are
+<i>true</i>. Edify supports the following operators (with the usual meanings):
+</p>
+
+<pre>
+(<i>expr</i> )
+ <i>expr</i> <b>+</b> <i>expr</i> # string concatenation, not integer addition
+ <i>expr</i> <b>==</b> <i>expr</i>
+ <i>expr</i> <b>!=</b> <i>expr</i>
+ <i>expr</i> <b>&amp;&amp;</b> <i>expr</i>
+ <i>expr</i> <b>||</b> <i>expr</i>
+ ! <i>expr</i>
+ if <i>expr</i> <b>then</b> <i>expr</i> <b>endif</b>
+ if <i>expr</i> <b>then</b> <i>expr</i> <b>else</b> <i>expr</i> <b>endif</b>
+ <i>function_name</i><b>(</b><i>expr</i><b>,</b> <i>expr</i><b>,</b><i>...</i><b>)</b>
+ <i>expr</i><b>;</b> <i>expr</i>
+</pre>
+
+<p>Any string of the characters <i>a-z, A-Z, 0-9, _, :, /, .</i> that isn't a
+reserved word is considered a string literal. (Reserved words are <b>if else
+</b> then <b>endif.</b>) String literals may also appear in double-quotes;
+this is how to create values with whitespace and other characters not in the
+above set. \n, \t, \", and \\ serve as escapes within quoted strings, as does
+\x<i>##</i>.</p>
+<p>The &amp;&amp; and || operators are short-circuiting; the right side is not
+evaluated if the logical result is determined by the left side. The
+following are equivalent:</p>
+<pre>
+<i>e1</i> <b>&amp;&amp;</b> <i>e2</i>
+<b>if</b> <i>e1</i> <b>then</b> <i>e2</i> <b>endif</b></pre>
+<p>The ; operator is a sequence point; it means to evaluate first the left
+side and then the right side. Its value is the value of the right-side
+expression. A semicolon can also appear after an expression, so the effect
+simulates C-style statements:</p>
+
+<pre>
+<b>prepare();
+do_other_thing("argument");
+finish_up();</b>
+</pre>
+
+<h2 id="builtin-functions">Built-in functions</h2>
+<p>Most update functionality is contained in the functions available for
+execution by scripts. (Strictly speaking these are <i>macros</i> rather than
+<i>functions</i> in the Lisp sense, since they need not evaluate all of their
+arguments.) Unless otherwise noted, functions return <b>true</b> on success
+and <b>false</b> on error. If you want errors to abort execution of the
+script, use the <code>abort()</code> and/or <code>assert()</code> functions.
+The set of functions available in updater can also be extended to provide
+<a href="{@docRoot}devices/tech/ota/device_code.html">device-specific
+functionality</a>.
+
+<dl>
+<dt><code>abort([<i>msg</i>])</code></dt>
+<dd>Aborts execution of the script immediately, with the optional <i>msg</i>.
+If the user has turned on text display, <i>msg</i> appears in the recovery log
+and on-screen.</dd>
+<dt><code>assert(<i>expr</i>[, <i>expr</i>, ...])</code></dt>
+<dd>Evaluates each <i>expr</i> in turn. If any is false, immediately aborts
+execution with the message "assert failed" and the source text of the failed
+expression.</dd>
+<dt><code>apply_patch(<i>src_file</i>, <i>tgt_file</i>, <i>tgt_sha1</i>, <i>
+tgt_size</i>, <i>patch1_sha1</i>, <i>patch1_blob</i>, [...])</code></dt>
+<dd>Applies a binary patch to the <i>src_file</i> to produce the <i>tgt_file
+</i>. If the desired target is the same as the source, pass "-" for <i>tgt_file
+</i>. <i>tgt_sha1</i> and <i>tgt_size</i> are the expected final SHA1 hash and
+size of the target file. The remaining arguments must come in pairs: a SHA1
+hash (a 40-character hex string) and a blob. The blob is the patch to be
+applied whe the source file's current contents have the given SHA1.
+<p>The patching is done in a safe manner that guarantees the target file
+either has the desired SHA1 hash and size, or it is untouched—it will not be
+left in an unrecoverable intermediate state. If the process is interrupted
+during patching, the target file may be in an intermediate state; a copy exists
+in the cache partition so restarting the update can successfully update the
+file.</p>
+<p>Special syntax is supported to treat the contents of Memory Technology
+Device (MTD) partitions as files, allowing patching of raw partitions such as
+boot. To read an MTD partition, you must know how much data you want to read
+since the partition does not have an end-of-file notion. You can use the
+string "MTD:<i>partition</i>:<i>size_1</i>:<i>sha1_1</i>:<i>size_2</i>:<i>
+sha1_2</i>" as a filename to read the given partition. You must specify at
+least one <i>(size, sha-1)</i> pair; you can specify more than one if there
+are multiple possibilities for what you expect to read.</p></dd>
+<dt><code>apply_patch_check(<i>filename</i>, <i>sha1</i>[, <i>sha1</i>, ...])
+</code></dt>
+<dd>Returns true if the contents of <i>filename</i> or the temporary copy in
+the cache partition (if present) have a SHA1 checksum equal to one of the
+given <i>sha1</i> values. <i>sha1</i> values are specified as 40 hex digits.
+This function differs from <code>sha1_check(read_file(<i>filename</i>),
+<i>sha1</i> [, ...])</code> in that it knows to check the cache partition copy,
+so <code>apply_patch_check()</code> will succeed even if the file was corrupted
+by an interrupted <code>apply_patch() update</code>.</dd>
+<dt><code>apply_patch_space(<i>bytes</i>)</code></dt>
+<dd>Returns true if at least <i>bytes</i> of scratch space is available for
+applying binary patches.</dd>
+<dt><code>concat(<i>expr</i>[, <i>expr</i>, ...])</code></dt>
+<dd>Evaluates each expression and concatenates them. The + operator is
+syntactic sugar for this function in the special case of two arguments (but
+the function form can take any number of expressions). The expressions must be
+strings; it can't concatenate blobs.</dd>
+<dt><code>delete([<i>filename</i>, ...])</code></dt>
+<dd>Deletes all the <i>filename</i>s listed. Returns the number of files
+successfully deleted.</dd>
+<dt><code>delete_recursive([<i>dirname</i>, ...])</code></dt>
+<dd>Recursively deletes <i>dirname</i>s and all their contents. Returns the
+number of directories successfully deleted.</dd>
+<dt><code>file_getprop(<i>filename</i>, <i>key</i>)</code></dt>
+<dd>Reads the given <i>filename</i>, interprets it as a properties file (e.g.
+<code>/system/build.prop</code>), and returns the value of the given <i>key</i>
+, or the empty string if <i>key</i> is not present.</dd>
+<dt><code>format(<i>fs_type</i>, <i>partition_type</i>, <i>location</i>, <i>
+fs_size</i>, <i>mount_point</i>)</code></dt>
+<dd>Reformats a given partition. Supported partition types:
+<ul>
+<li>fs_type="yaffs2" and partition_type="MTD". Location must be the name of
+the MTD partition; an empty yaffs2 filesystem is constructed there. Remaining
+arguments are unused.</li>
+<li>fs_type="ext4" and partition_type="EMMC". Location must be the device file
+for the partition. An empty ext4 filesystem is constructed there. If
+<i>fs_size</i> is zero, the filesystem takes up the entire partition. If
+<i>fs_size</i> is a positive number, the filesystem takes the first
+<i>fs_size</i> bytes of the partition. If <i>fs_size</i> is a
+negative number, the filesystem takes all except the last <i>|fs_size|</i>
+bytes of the partition.</li>
+<li>fs_type="f2fs" and partition_type="EMMC". Location must be the device file
+for the partition. <i>fs_size</i> must be a non-negative number. If
+<i>fs_size</i> is zero, the filesystem takes up the entire partition. If
+<i>fs_size</i> is a positive number, the filesystem takes the first
+<i>fs_size</i> bytes of the partition.</li>
+<li>mount_point should be the future mount point for the filesystem.</li></ul>
+</dd>
+<dt><code>getprop(<i>key</i>)</code></dt>
+<dd>Returns the value of system property <i>key</i> (or the empty string, if
+it's not defined). The system property values defined by the recovery
+partition are not necessarily the same as those of the main system. This
+function returns the value in recovery.</dd>
+<dt><code>greater_than_int(<i>a</i>, <i>b</i>)</code></dt>
+<dd>Returns true if and only if (iff) <i>a</i> (interpreted as an integer) is
+greater than <i>b</i> (interpreted as an integer).</dd>
+<dt><code>ifelse(<i>cond</i>, <i>e1</i>[, <i>e2</i>])</code></dt>
+<dd>Evaluates <i>cond</i>, and if it is true evaluates and returns the value
+of <i>e1</i>, otherwise it evaluates and returns <i>e2</i> (if present). The
+"if ... else ... then ... endif" construct is just syntactic sugar for this
+function.</dd>
+<dt><code>is_mounted(<i>mount_point</i>)</code></dt>
+<dd>Returns true iff there is a filesystem mounted at <i>mount_point</i>.</dd>
+<dt><code>is_substring(<i>needle</i>, <i>haystack</i>)</b></code></dt>
+<dd>Returns true iff <i>needle</i> is a substring of <i>haystack</i>.</dd>
+<dt><code>less_than_int(<i>a</i>, <i>b</i>)</code></dt>
+<dd>Returns true iff <i>a</i> (interpreted as an integer) is less than <i>b</i>
+(interpreted as an integer).</dd>
+<dt><code>mount(<i>fs_type</i>, <i>partition_type</i>, <i>name</i>,
+<i>mount_point</i>)</code></dt>
+<dd>Mounts a filesystem of <i>fs_type</i> at <i>mount_point</i>.
+<i>partition_type</i> must be one of:
+<ul>
+<li><b>MTD</b>. Name is the name of an MTD partition (e.g., system, userdata;
+see <code>/proc/mtd</code> on the device for a complete list).</li>
+<li><b>EMMC.</b></li>
+</ul>
+<p>Recovery does not mount any filesystems by default (except the SD card if
+the user is doing a manual install of a package from the SD card); your script
+must mount any partitions it needs to modify.</p></dd>
+<dt><code>package_extract_dir(<i>package_dir</i>, <i>dest_dir</i>)</code></dt>
+<dd>Extracts all files from the package underneath <i>package_dir</i> and
+writes them to the corresponding tree beneath <i>dest_dir</i>. Any existing
+files are overwritten.</dd>
+<dt><code>package_extract_file(<i>package_file</i>[, <i>dest_file</i>])</code>
+</dt>
+<dd>Extracts a single <i>package_file</i> from the update package and writes
+it to <i>dest_file</i>, overwriting existing files if necessary. Without the
+<i>dest_file</i> argument, returns the contents of the package file as a
+binary blob.</dd>
+<dt><code>read_file(<i>filename</i>)</code></dt>
+<dd>Reads <i>filename</i> and returns its contents as a binary blob.</dd>
+<dt><code>rename(<i>src_filename</i>, <i>tgt_filename</i>)</code></dt>
+<dd>Renames <i>src_filename</i> to <i>tgt_filename</i>. It automatically creates
+the necessary directories for the <i>tgt_filename</i>. Example: <code>
+rename("system/app/Hangouts/Hangouts.apk",
+"system/priv-app/Hangouts/Hangouts.apk")</code>.</dd>
+<dt><code>run_program(<i>path</i>[, <i>arg</i>, ...])</code></dt>
+<dd>Executes the binary at <i>path</i>, passing <i>arg</i>s. Returns the
+program's exit status.</dd>
+<dt><code>set_metadata(<i>filename</i>, <i>key1</i>, <i>value1</i>[, <i>key2
+</i>, <i>value2</i>, ...])</code></dt>
+<dd>Sets the keys of the given <i>filename</i> to <i>values</i>. For example:
+<code>set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750,
+"selabel", "u:object_r:system_file:s0", "capabilities", 0x0)</code>.</dd>
+<dt><code>set_metadata_recursive(<i>dirname</i>, <i>key1</i>, <i>value1</i>[,
+<i>key2</i>, <i>value2</i>, ...])</code></dt>
+<dd>Recursively sets the keys of the given <i>dirname</i> and all its children
+to <i>values</i>. For example: <code>set_metadata_recursive("/system", "uid",
+0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel",
+"u:object_r:system_file:s0", "capabilities", 0x0)</code>.</dd>
+<dt><code>set_progress(<i>frac</i>)</code></dt>
+<dd>Sets the position of the progress meter within the chunk defined by the
+most recent <code>show_progress()</code> call. <i>frac</i> must be in the
+range [0.0, 1.0]. The progress meter never moves backwards; attempts to make
+it do so are ignored.</dd>
+<dt><code>sha1_check(<i>blob</i>[, <i>sha1</i>])</code></dt>
+<dd>The <i>blob</i> argument is a blob of the type returned by <code>
+read_file()</code> or the one-argument form of <code>package_extract_file()
+</code>. With no <i>sha1</i> arguments, this function returns the SHA1 hash of
+the blob (as a 40-digit hex string). With one or more <i>sha1</i> arguments,
+this function returns the SHA1 hash if it equals one of the arguments, or the
+empty string if it does not equal any of them.</dd>
+<dt><code>show_progress(<i>frac</i>, <i>secs</i>)</code></dt>
+<dd>Advances the progress meter over the next <i>frac</i> of its length over
+the <i>secs</i> seconds (must be an integer). <i>secs</i> may be 0, in which
+case the meter is not advanced automatically but by use of the <code>
+set_progress()</code> function defined above.</dd>
+<dt><code>sleep(<i>secs</i>)</code></dt>
+<dd>Sleeps for <i>secs</i> seconds (must be an integer).</dd>
+<dt><code>stdout(<i>expr</i>[, <i>expr</i>, ...])</code></dt>
+<dd>Evaluates each expression and dumps its value to stdout. Useful for
+debugging.</dd>
+<dt><code>symlink(<i>target</i>[, <i>source</i>, ...])</code></dt>
+<dd>Creates all <i>source</i>s as symlinks to <i>target</i>.</dd>
+<dt><code>tune2fs(<i>device</i>[, <i>arg</i>, …])</code></dt>
+<dd>Adjusts tunable parameters <i>args</i> on <i>device</i>.</dd>
+<dt><code>ui_print([<i>text</i>, ...])</code></dt>
+<dd>Concatenates all <i>text</i> arguments and prints the result to the UI
+(where it will be visible if the user has turned on the text display).</dd>
+<dt><code>unmount(<i>mount_point</i>)</code></dt>
+<dd>Unmounts the filesystem mounted at <i>mount_point</i>.</dd>
+<dt><code>wipe_block_device(<i>block_dev</i>, <i>len</i>)</code></dt>
+<dd>Wipes the <i>len</i> bytes of the given block device <i>block_dev</i>.</dd>
+<dt><code>wipe_cache()</code></dt>
+<dd>Causes the cache partition to be wiped at the end of a successful
+installation.</dd>
+<dt><code>write_raw_image(<i>filename_or_blob</i>, <i>partition</i>)</code>
+</dt>
+<dd>Writes the image in <i>filename_or_blob</i> to the MTD <i>partition</i>.
+<i>filename_or_blob</i> can be a string naming a local file or a blob-valued
+argument containing the data to write. To copy a file from the OTA package to
+a partition, use:
+<code>write_raw_image(package_extract_file("zip_filename"), "partition_name");
+</code>
+</dd>
+</dl>
+
+<p class="note"><strong>Note:</strong> Prior to Android 4.1, only filenames
+were accepted, so to accomplish this the data first had to be unzipped into a
+temporary local file.</p> \ No newline at end of file
diff --git a/src/devices/tech/ota/sign_builds.jd b/src/devices/tech/ota/sign_builds.jd
new file mode 100755
index 00000000..e9869205
--- /dev/null
+++ b/src/devices/tech/ota/sign_builds.jd
@@ -0,0 +1,269 @@
+page.title=Signing Builds for Release
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>Android uses cryptographic signatures in two places:</p>
+<ol>
+<li>Each .apk file must be signed. Android's Package Manager uses an .apk
+signature in two ways:<ul>
+<li>When an application is replaced, it must be signed by the same key as the
+old application in order to get access to the old application's data.</li>
+<li>If two or more applications want to share a user ID (so they can share
+data, etc.), they must be signed with the same key.</ul></li>
+<li>OTA update packages must be signed with one of the keys expected by the
+system or the installation process will reject them.</ul></li>
+</ol>
+<h2 id="certificates-keys">Certificates and keys</h2>
+<p>Each key comes in two files: the <i>certificate</i>, which has the
+extension .x509.pem, and the <i>private key</i>, which has the extension .pk8.
+The private key should be kept secret and is needed to sign a package. The key
+may itself be protected by a password—a reasonable strategy is to store your
+keys in source control along with the code—but keep them protected by a
+password known only to the people who make final releases. The certificate, in
+contrast, contains only the public half of the key, so it can be distributed
+widely. It is used to verify a package has been signed by the corresponding
+private key.</p>
+<p>The standard Android build uses four keys, all of which reside in <code>
+build/target/product/security</code>:</p>
+
+<dl>
+<dt>testkey</dt>
+<dd>Generic default key for packages that do not otherwise specify a key.</dd>
+<dt>platform</dt>
+<dd>Test key for packages that are part of the core platform.</dd>
+<dt>shared</dt>
+<dd>Test key for things that are shared in the home/contacts process.</dd>
+<dt>media</dt>
+<dd>Test key for packages that are part of the media/download system.</dd></dl>
+
+<p>Individual packages specify one of these keys by setting LOCAL_CERTIFICATE
+in their Android.mk file. (testkey is used if this variable is not set.) You
+can also specify an entirely different key by pathname, e.g.:</p>
+
+<p><code>device/yoyodyne/apps/SpecialApp/Android.mk</code></p>
+<pre>
+ [...]
+
+LOCAL_CERTIFICATE := device/yoyodyne/security/special
+</pre>
+
+<p>Now the build uses the <code>device/yoyodyne/security/special.{x509.pem,pk8}
+</code> key to sign SpecialApp.apk. The build can use only private keys that
+are <i>not </i>password protected.</p>
+
+<h2>Generating keys</h2>
+<p>Android uses 2048-bit RSA keys with public exponent 3. You can generate
+certificate/private key pairs using the openssl tool from
+<a href="http://www.openssl.org/">openssl.org</a>:</p>
+
+<pre>
+# generate RSA key
+% <b>openssl genrsa -3 -out temp.pem 2048</b>
+Generating RSA private key, 2048 bit long modulus
+....+++
+.....................+++
+e is 3 (0x3)
+
+# create a certificate with the public part of the key
+% <b>openssl req -new -x509 -key temp.pem -out releasekey.x509.pem \
+ -days 10000 \
+ -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'</b>
+
+# create a PKCS#8-formatted version of the private key
+% <b>openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt</b>
+
+# securely delete the temp.pem file
+% <b>shred --remove temp.pem</b>
+</pre>
+
+<p>The openssl pkcs8 command given above creates a .pk8 file with <i>no</i>
+password, suitable for use with the build system. To create a .pk8 secured
+with a password (which you should do for all actual release keys), replace the
+<code>-nocrypt</code> argument with <code>-passout stdin</code>; then openssl
+will encrypt the private key with a password read from standard input. No
+prompt is printed, so if stdin is the terminal the program will appear to hang
+when it's really just waiting for you to enter a password. Other values can be
+used for the-passout argument to read the password from other locations; for
+details, see the
+<a href="http://www.openssl.org/docs/apps/openssl.html#PASS_PHRASE_ARGUMENTS">
+openssl documentation</a>.</p>
+<p>The temp.pem intermediate file contains the private key without any kind of
+password protection, so dispose of it thoughtfully when generating release
+keys. In particular, the GNUshred utility may not be effective on network or
+journaled filesystems. You can use a working directory located in a RAM disk
+(such as a tmpfs partition) when generating keys to ensure the intermediates
+are not inadvertently exposed.</p>
+
+<h2 id="sign-apps-for-release">Signing apps for release</h2>
+<p>The first step in preparing a build for release is to sign all the .apk
+files in it, replacing the test keys used by the build system. This is done
+with the <code>sign_target_files_apks</code> script. It takes a target-files
+.zip as input and produces a new target-files .zip in which all the .apks have
+been signed with new keys.</p>
+<p>When you run this script, you must specify on the command line a
+replacement key for each key used in the build. The <code>-k <i>src_key</i>=<i>
+dest_key</i></code> flag specifies key replacements one at a time. The flag
+<code>-d <i>dir</i></code> lets you specify a directory with four keys to
+replace all those in <code>build/target/product/security</code>; it is
+equivalent to using <code>-k</code> four times to specify the mappings:</p>
+
+<pre>
+build/target/product/security/testkey = dir/releasekey
+build/target/product/security/platform = dir/platform
+build/target/product/security/shared = dir/shared
+build/target/product/security/media = dir/media
+</pre>
+
+<p>For the hypothetical tardis product, you need five password-protected keys:
+four to replace the four in <code>build/target/product/security</code>, and
+one to replace the additional <code>keydevice/yoyodyne/security/special</code>
+required by SpecialApp in the example above. If the keys were in the following
+files:</p>
+
+<pre>
+vendor/yoyodyne/security/tardis/releasekey.x509.pem
+vendor/yoyodyne/security/tardis/releasekey.pk8
+vendor/yoyodyne/security/tardis/platform.x509.pem
+vendor/yoyodyne/security/tardis/platform.pk8
+vendor/yoyodyne/security/tardis/shared.x509.pem
+vendor/yoyodyne/security/tardis/shared.pk8
+vendor/yoyodyne/security/tardis/media.x509.pem
+vendor/yoyodyne/security/tardis/media.pk8
+vendor/yoyodyne/security/special.x509.pem
+vendor/yoyodyne/security/special.pk8 # NOT password protected
+vendor/yoyodyne/security/special-release.x509.pem
+vendor/yoyodyne/security/special-release.pk8 # password protected
+</pre>
+
+<p>Then you would sign all the apps like this:</p>
+
+<pre>
+% <b>./build/tools/releasetools/sign_target_files_apks \
+ -d vendor/yoyodyne/security/tardis \
+ -k vendor/yoyodyne/special=vendor/yoyodyne/special-release \
+ -o \ </b># explained in the next section<b>
+ tardis-target_files.zip signed-tardis-target_files.zip</b>
+Enter password for vendor/yoyodyne/security/special-release key&gt;
+Enter password for vendor/yoyodyne/security/tardis/media key&gt;
+Enter password for vendor/yoyodyne/security/tardis/platform key&gt;
+Enter password for vendor/yoyodyne/security/tardis/releasekey key&gt;
+Enter password for vendor/yoyodyne/security/tardis/shared key&gt;
+ signing: Phone.apk (vendor/yoyodyne/security/tardis/platform)
+ signing: Camera.apk (vendor/yoyodyne/security/tardis/media)
+ signing: Special.apk (vendor/yoyodyne/security/special-release)
+ signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey)
+ [...]
+ signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared)
+ signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared)
+rewriting SYSTEM/build.prop:
+ replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys
+ with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys
+ replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
+ with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
+ signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform)
+rewriting RECOVERY/RAMDISK/default.prop:
+ replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys
+ with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys
+ replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
+ with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
+using:
+ vendor/yoyodyne/security/tardis/releasekey.x509.pem
+for OTA package verification
+done.
+</pre>
+
+<p>After prompting the user for passwords for all password-protected keys, the
+script re-signs all the .apk files in the input target .zip with the release
+keys. Before running the command, you can also set the ANDROID_PW_FILE
+environment variable to a temporary filename; the script then invokes your
+editor to allow you to enter passwords for all keys (this may be a more
+convenient way to enter passwords).<p>
+<p><code>sign_target_files_apks</code> also rewrites the build description and
+fingerprint in the build properties files to reflect the fact that this is a
+signed build. The <code>-t</code> flag can control what edits are made to the
+fingerprint. Run the script with <code>-h</code> to see documentation on all
+flags.</p>
+
+<h2 id="sign-ota-packages">Signing OTA packages</h2>
+<p>You need the following components to sign OTA packages:</p>
+<ol>
+<li>Certificates of the keys you want this build to accept.</li>
+<li>Sign the newly-created package with the private key (must correspond to
+the certificate embedded in the current build of any device to which you want
+to send this package).</li>
+</ol>
+<p>To achieve these components:</p>
+<ul>
+<li>The target-files .zip produced by the build sets the OTA certificate to
+the certificate of the test key. Passing the <code>-o</code> flag to <code>
+sign_target_files_apks</code> replaces this key with the release key from your
+build.</li>
+<li>To sign the OTA update package, use the <code>-k</code> option when
+generating it to specify the key. You should give <code>ota_from_target_files
+</code> the <i>signed</i> version of the target-files .zip as well:
+<pre>
+% <b>./build/tools/releasetools/ota_from_target_files \
+ -k vendor/yoyodyne/security/tardis/releasekey \
+ signed-tardis-target_files.zip \
+ signed-ota_update.zip</b>
+unzipping target target-files...
+(using device-specific extensions from target_files)
+Enter password for vendor/yoyodyne/security/tardis/releasekey key&gt;
+done.</pre></li></ul>
+
+<h3 id="signatures-sideloading">Signatures and sideloading</h3>
+<p>Sideloading does not bypass recovery's normal package signature
+verification mechanism—before installing a package, recovery will verify that
+it is signed with one of the private keys matching the public keys stored in
+the recovery partition, just as it would for a package delivered over-the-air.
+</p>
+<p>Update packages received from the main system are typically verified twice:
+once by the main system, using the <code><a href="http://developer.android.com/
+reference/android/os/RecoverySystem.html#verifyPackage">RecoverySystem.
+verifyPackage()</a></code> method in the android API, and then again by
+recovery. The RecoverySystem API checks the signature against public keys
+stored in the main system, in the file <code>/system/etc/security/otacerts.zip
+</code> (by default). Recovery checks the signature against public keys stored
+in the recovery partition RAM disk, in the file <code>/res/keys</code>.</p>
+<p>Normally these two locations store the same set of keys. By adding a key to
+<i>just</i> the recovery set of keys, it's possible to sign packages that can
+be installed only via sideloading (assuming the main system's update download
+mechanism is correctly doing verification against otacerts.zip). You can
+specify extra keys to be included only in recovery by setting the
+PRODUCT_EXTRA_RECOVERY_KEYS variable in your product definition:</p>
+
+<p><code>vendor/yoyodyne/tardis/products/tardis.mk</code></p>
+<pre>
+ [...]
+
+PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
+</pre>
+
+<p>This includes the public key <code>vendor/yoyodyne/security/tardis/sideload.
+x509.pem</code> in the recovery keys file so it can install packages signed
+with it. The extra key is <i>not</i> included in otacerts.zip though, so
+systems that correctly verify downloaded packages do not invoke recovery for
+packages signed with this key.</p> \ No newline at end of file
diff --git a/src/devices/tech/ota/tools.jd b/src/devices/tech/ota/tools.jd
new file mode 100755
index 00000000..1226379e
--- /dev/null
+++ b/src/devices/tech/ota/tools.jd
@@ -0,0 +1,133 @@
+page.title=OTA Package Tools
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>The <a href="https://android.googlesource.com/platform/build/+/master/tools/
+releasetools/ota_from_target_files">ota_from_target_files</a> tool provided in
+<code>build/tools/releasetools</code> can build two types of package: <i>full
+</i> and <i>incremental</i>. The tool takes the <i>target-files</i> .zip file
+produced by the Android build system as input.</p>
+
+<h2 id="full-updates">Full updates</h2>
+<p>A <i>full</i> update is one where the entire final state of the device
+(system, boot, and recovery partitions) is contained in the package. As long
+as the device is capable of receiving the package and booting the recovery
+system, the package can install the desired build regardless of the current
+state of the device.</p>
+<p>Example: Using the release tools to build a full update for the
+hypothetical <b>tardis</b> device:</p>
+
+<pre>
+# first, build the target-files .zip
+% <b>. build/envsetup.sh &amp;&amp; lunch tardis-eng</b>
+% <b>mkdir dist_output</b>
+% <b>make dist DIST_DIR=dist_output</b>
+ [...]
+% <b>ls -l dist_output/*target_files*</b>
+-rw-r----- 1 user eng 69965275 Sep 29 15:51 tardis-target_files.zip
+</pre>
+
+<p>The target-files .zip contains everything needed to construct OTA packages.
+</p>
+
+<pre>
+% <b>./build/tools/releasetools/ota_from_target_files \
+ dist_output/tardis-target_files.zip ota_update.zip</b>
+unzipping target target-files...
+done.
+% <b>ls -l ota_update.zip</b>
+-rw-r----- 1 user eng 62236561 Sep 29 15:58 ota_update.zip
+</pre>
+
+<p>The ota_update.zip is now ready to be sent to test devices (everything is
+signed with the test key). For user devices, generate and use your own private
+keys as detailed in <a href="{@docRoot}devices/tech/ota/sign_builds
+.html">Signing builds for release</a>.
+
+<h2 id="incremental-updates">Incremental updates</h2>
+<p>An <i>incremental</i> update contains a set of binary patches to be applied
+to the data already on the device. This can result in considerably smaller
+update packages:</p>
+<ul>
+<li>Files that have not changed don't need to be included.</li>
+<li>Files that have changed are often very similar to their previous versions,
+so the package need only contain an encoding of the differences between the
+two files.</li></ul>
+<p>You can install the incremental update package only on a device that has
+the old or source build used when constructing the package. To build an
+incremental update, you need the target_files .zip from the previous build
+(the one you want to update <i>from</i>) as well as the target_files .zip from
+the new build.</p>
+
+<pre>
+% <b>./build/tools/releasetools/ota_from_target_files \
+ -i PREVIOUS-tardis-target_files.zip \ </b># make incremental from this older version<b>
+ dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
+unzipping target target-files...
+unzipping source target-files...
+ [...]
+done.
+% <b>ls -l incremental_ota_update.zip</b>
+-rw-r----- 1 user eng 1175314 Sep 29 16:10 incremental_ota_update.zip
+</pre>
+
+<p>This build is very similar to the previous build, and the incremental
+update package is much smaller than the corresponding full update (about 1 MB
+instead of 60 MB).</p>
+<p class="note"><strong>Note:</strong> To generate a
+<a href="{@docRoot}devices/tech/ota/block.html">block-based OTA</a>
+for subsequent updates, pass the <code>--block</code> option to
+<code>ota_from_target_files</code>.</p>
+<p>Distribute an incremental package only to devices running exactly the same
+previous build used as the incremental package's starting point. Attempting to
+install the incremental package on a device with some other build results in
+the recovery error icon. Rebooting the device at this point returns the user
+to the old system; the package verifies the previous state of all the files it
+updates before touching them, so the device should not be left in a half
+upgraded state if this occurs.</p>
+
+<h2 id="update-packages">Update packages</h2>
+<p>An update package (<code>ota_update.zip</code>,
+<code>incremental_ota_update.zip</code>) is a .zip file that contains the
+executable binary <code>META-INF/com/google/android/update-binary</code>. After
+verifying the signature on the package, recovery extracts this binary to
+<code>/tmp</code> and runs it, passing the following arguments:</p>
+<ul>
+<li><b>Update binary API version number</b>. If the arguments passed to the
+update binary change, this number is incremented.</li>
+<li><b>File descriptor of the <i>command pipe</i></b>. The update program can
+use this pipe to send commands back to the recovery binary (mostly for UI
+changes such as indicating progress to the user).</li>
+<li><b>Filename of the update package .zip file</b>.</li>
+</ul>
+<p>A recovery package can use any statically-linked binary as the update
+binary. The OTA package construction tools use the updater program (source in
+<code>bootable/recovery/updater</code>), which provides a simple scripting
+language that can do many installation tasks. You can substitute any other
+binary running on the device.</p>
+<p>For details on the updater binary, edify syntax, and builtin functions, see
+<a href="{@docRoot}devices/tech/ota/inside_packages.html">Inside OTA Packages
+</a>. \ No newline at end of file
diff --git a/src/source/community/index.jd b/src/source/community/index.jd
index 31361ca9..8845469a 100644
--- a/src/source/community/index.jd
+++ b/src/source/community/index.jd
@@ -10,125 +10,213 @@ page.title=Android Community
</div>
<p>Welcome to the Android community!</p>
-<p>The key to any community is, obviously, communication. Like most projects,
-Android communicates via mailing lists. Because Android is an extremely large
+<p>The key to any community is communication. Like most projects, Android
+communicates via mailing lists. Because Android is an extremely large
project with many components, we have many discussion forums, each focusing on
a different topic.</p>
-<p>Please check out the groups below, and join any that seem interesting to
+<p>Check out the groups below and join any that seem interesting to
you. Note that if you're a user looking for help with your Android device,
this page probably isn't for you; you should contact your carrier or retailer
for help with your phone.</p>
-<p>Please note that if you're looking for information about building
-applications for Android, you can find a separate set of groups for those at
-our sister site, developer.android.com: [https://developer.android.com/resources/community-groups.html]</p>
+<p>If you're looking for information about building applications for Android,
+you can find a separate set of groups at our sister site
+<a href="https://developer.android.com/resources/community-groups.html">
+developer.android.com</a>.</p>
<h2 id="open-source-project-discussions">Open Source Project discussions</h2>
<ul>
<li>
-<p><em>android-platform</em>:
- This list is for general discussion about the Android open-source project or the platform technologies.</p>
+<p><em>android-platform</em>:
+This list is for general discussion about the Android open-source project or
+the platform technologies.</p>
<ul>
-<li>Subscribe using Google Groups: <a href="https://groups.google.com/forum/?fromgroups#!forum/android-platform">android-platform</a></li>
-<li>Subscribe via email: <a href="mailto:android-platform+subscribe@googlegroups.com">android-platform</a></li>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-platform">
+android-platform</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-platform+subscribe@googlegroups.com">android-platform
+</a></li>
</ul>
</li>
<li>
<p><em>android-building</em>:
- Subscribe to this list for discussion and help on building the Android source code, and on the build system. If you've just checked out the source code and have questions about how to turn it into binaries, start here.</p>
+Subscribe to this list for discussion and help on building the Android source
+code, and on the build system. If you've just checked out the source code and
+have questions about how to turn it into binaries, start here.</p>
<ul>
-<li>Subscribe using Google Groups: <a href="https://groups.google.com/forum/?fromgroups#!forum/android-building">android-building</a></li>
-<li>Subscribe via email: <a href="mailto:android-building+subscribe@googlegroups.com">android-building</a></li>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-building">
+android-building</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-building+subscribe@googlegroups.com">android-building
+</a></li>
</ul>
</li>
<li>
<p><em>android-porting</em>:
- This list is for developers who want to port Android to a new device. If you're wondering how to combine the Android source code with your hardware, this is the right group for you. Discuss here the specifics of porting Android to individual devices, from obtaining toolchains and merging kernel drivers all the way to configuring or modifying applications for your specific
+This list is for developers who want to port Android to a new device. If
+you're wondering how to combine the Android source code with your hardware,
+this is the right group for you. Discuss here the specifics of porting Android
+to individual devices, from obtaining toolchains and merging kernel drivers
+all the way to configuring or modifying applications for your specific
configuration.</p>
<ul>
-<li>Subscribe using Google Groups: <a href="https://groups.google.com/forum/?fromgroups#!forum/android-porting">android-porting</a></li>
-<li>Subscribe via email: <a href="mailto:android-porting+subscribe@googlegroups.com">android-porting</a></li>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-porting">
+android-porting</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-porting+subscribe@googlegroups.com">android-porting</a>
+</li>
</ul>
</li>
<li>
<p><em>android-contrib</em>:
- This list is for developers who want to contribute code to Android. This is a working list, and is not appropriate for general discussion. We ask that general discussion go to android-platform. Note: contributors to the Android kernel should go to the android-kernel list, below.</p>
+This list is for developers who want to contribute code to Android. This is a
+working list, and is not appropriate for general discussion. We ask that
+general discussion go to android-platform (and contributors to the Android
+kernel should go to android-kernel).</p>
<ul>
-<li>Subscribe using Google Groups: <a href="https://groups.google.com/forum/?fromgroups#!forum/android-contrib">android-contrib</a></li>
-<li>Subscribe via email: <a href="mailto:android-contrib+subscribe@googlegroups.com">android-contrib</a></li>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-contrib">
+android-contrib</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-contrib+subscribe@googlegroups.com">android-contrib</a>
+</li>
</ul>
</li>
<li>
<p><em>android-kernel</em>:
- This list is for deveopers who want to contribute to the Linux kernel that Android devices use. If you've downloaded the kernel code, if you know how to compile it, if you want to write kernel code to specifically support Android,
-this is your place. This group isn't for user-space topics (see android-platform for that), and people will shake their fingers at you and call you naughty if you ask user-space questions here.</p>
+This list is for developers who want to contribute to the Linux kernel used by
+Android devices. If you've downloaded the kernel code, know how to compile it,
+and want to write kernel code to support Android, this is your place. This
+group is <em>not</em> for user-space topics (see android-platform); people
+will shake their fingers at you and call you naughty if you ask user-space
+questions here.</p>
+<ul>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-kernel">
+android-kernel</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-kernel+subscribe@googlegroups.com">android-kernel</a>
+</li>
+</ul>
+<li>
+<p><em>android-ota</em>:
+This list is for developers working on the Android OTA system (the recovery
+image and the scripts that generate OTAs).</p>
<ul>
-<li>Subscribe using Google Groups: <a href="https://groups.google.com/forum/?fromgroups#!forum/android-kernel">android-kernel</a></li>
-<li>Subscribe via email: <a href="mailto:android-kernel+subscribe@googlegroups.com">android-kernel</a></li>
+<li>Subscribe using Google Groups:
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-ota">
+android-ota</a></li>
+<li>Subscribe via email:
+<a href="mailto:android-ota+subscribe@googlegroups.com">android-ota</a></li>
</ul>
</li>
</ul>
-
<h3 id="audience">Audience</h3>
-<p>
-These discussion groups are intended for developers working with the Android platform. Everyone is welcome to join in, provided you follow our community's policies described below. Our users help each other, and many experts post to these groups, including members of the Open Handset Alliance.
-</p>
-<p>
-No topic is off-limits, provided it relates to Android in some way. However, since these are very busy lists, search the archives before posting your question; you may find your question has already been answered.
-</p>
+<p>These discussion groups are intended for developers working with the Android
+platform. Everyone is welcome to join in, provided you follow the community
+policies described below. Our users help each other, and many experts post to
+these groups, including members of the Open Handset Alliance.</p>
+<p>No topic is off-limits, provided it relates to Android in some way. However,
+since these are very busy lists, search the archives before posting your
+question; you may find your question has already been answered.</p>
<h3 id="getting-the-most-from-our-lists">Getting the Most from Our Lists</h3>
<p>Please consider the following before you post to our lists.</p>
<ul>
<li>
-<p><em>Read the <a href="#mailing">Charter for our forums.</a></em> This explains the (few) rules and guidelines for our community.</p>
+<p><em>Read the <a href="#mailing">Charter for our forums.</a></em> This
+explains the (few) rules and guidelines for our community.</p>
</li>
<li>
-<p><em>Search the group archives to see whether your questions have already been discussed.</em> This avoids time-wasting redundant discussions.</p>
+<p><em>Search the group archives to see whether your questions have already
+been discussed.</em> This avoids time-wasting redundant discussions.</p>
</li>
<li>
-<p><em>Use a clear, relevant message subject.</em> This helps everyone, both those trying to answer your question as well as those who may be looking for information in the future.</p>
+<p><em>Use a clear, relevant message subject.</em> This helps everyone, both
+those trying to answer your question as well as those who may be looking for
+information in the future.</p>
</li>
<li>
-<p><em>Give plenty of details in your post.</em> Code or log snippets, pointers to screenshots, and similar details will get better results and make for better discussions. For a great guide to phrasing your questions, read <a href="http://www.catb.org/%7Eesr/faqs/smart-questions.html">How to Ask Questions the Smart Way</a>.</p>
+<p><em>Give plenty of details in your post.</em> Code or log snippets,
+pointers to screenshots, and similar details will get better results and make
+for better discussions. For a great guide to phrasing your questions, read
+<a href="http://www.catb.org/%7Eesr/faqs/smart-questions.html">How to Ask
+Questions the Smart Way</a>.</p>
</li>
</ul>
<h3 id="mailing">Mailing list rules</h3>
-<p>We love simplicity and hate restrictions, so we keep our policies minimal. The rules
-below describe what's expected of subscribers to the Android mailing lists.</h2>
+<p>We love simplicity and hate restrictions, so we keep our policies minimal.
+The rules below describe what's expected of subscribers to the Android mailing
+lists.</h2>
<ul>
- <li><em>Please be friendly</em>: Showing courtesy and respect to others is a vital part of the Android culture, and we expect everyone participating in the Android community to join us in accepting nothing less. Being courteous does not mean we can't constructively disagree with each other, but it does mean that we must be polite when we do so. There's never a reason to be antagonistic or dismissive toward anyone; if you think there is, think again before you post. Mobile development is serious business, but it's also a lot of fun. Let's keep it that way. Let's strive to be one of the friendliest communities in all of open source.
- </li>
- <li><em>Allowed discussion topics</em>: Most of our groups are for technical discussions of Android or users helping each other. Generally we don't put hard restrictions on the topics discussed in the group: as long as the topic is relevant to Android in some way, it's welcome on our groups. We welcome announcements and discussion of products, libraries, publications, and other interesting Android-related news, but please do not cross-post. Post only to the most relevant group for your message. We even welcome (polite!) discussion of articles and ideas critical of Android--after all, we can't improve if we don't listen.
- </li>
- <li><em>Working Lists</em>: Some of our groups are considered "working lists", by which we mean that the list is intended to be used in support of the completion of specific tasks. On these groups, we don't welcome off-topic conversations, and will generally ask you to take general discussions to a different list. Since these are lists where people are trying to get work done, we will be pretty aggressive about keeping the noise level low. We ask that you respect our contributors' time and keep general discussions to appropriate lists.
- </li>
- <li><em>Spam</em>: We hate spam almost as passionately as we love courtesy and respect, so we reserve the right to limit discussions that amount to spam. Outright spam will result in the spammer being immediately and permanently banned from the list.
- </li>
+<li><em>Please be friendly</em>: Showing courtesy and respect to others is a
+vital part of the Android culture, and we expect everyone participating in the
+Android community to join us in accepting nothing less. Being courteous does
+not mean we can't constructively disagree with each other, but it does mean
+that we must be polite when we do so. There's never a reason to be
+antagonistic or dismissive toward anyone; if you think there is, think again
+before you post. Mobile development is serious business, but it's also a lot
+of fun. Let's keep it that way. Let's strive to be one of the friendliest
+communities in all of open source.
+</li>
+<li><em>Allowed discussion topics</em>: Most of our groups are for technical
+discussions of Android or users helping each other. Generally we don't put
+hard restrictions on the topics discussed in the group: as long as the topic
+is relevant to Android in some way, it's welcome on our groups. We welcome
+announcements and discussion of products, libraries, publications, and other
+interesting Android-related news, but please do not cross-post. Post only to
+the most relevant group for your message. We even welcome (polite!) discussion
+of articles and ideas critical of Android&mdash;after all, we can't improve if
+we don't listen.
+</li>
+<li><em>Working Lists</em>: Some of our groups are considered "working lists",
+by which we mean that the list is intended to be used in support of the
+completion of specific tasks. On these groups, we don't welcome off-topic
+conversations, and will generally ask you to take general discussions to a
+different list. Since these are lists where people are trying to get work
+done, we will be pretty aggressive about keeping the noise level low. We ask
+that you respect our contributors' time and keep general discussions to
+appropriate lists.
+</li>
+<li><em>Spam</em>: We hate spam almost as passionately as we love courtesy and
+respect, so we reserve the right to limit discussions that amount to spam.
+Outright spam will result in the spammer being immediately and permanently
+banned from the list.
+</li>
</ul>
-<p>
-The most important rule is friendliness. Remember: disrespect and rudeness are not welcome in our community under any circumstances. We don't have a formal policy on dealing with troublemakers, and we hope we never need one. That said, we do pledge to do our best to be fair, and we will always try to warn someone before banning him or her.
-</p>
-<h3 id="contacting">Contacting the moderators</h3>
-<p>
-If you see anyone being rude, call them out on it. This is your group too, and you don't have to accept someone else being disrespectful just because it wasn't directed at you. Just remember to be polite and courteous yourself! Don't add fuel to the fire.
-</p>
-<p>
-But if you see an outrageous violation, want to report spam, feel very strongly about something, or even if you just want to chat, then contact the mailing list's owners. It's what we're here for!
-</p>
-
+<p>The most important rule is friendliness. Remember: disrespect and rudeness
+are not welcome in our community under any circumstances. We don't have a
+formal policy on dealing with troublemakers, and we hope we never need one.
+That said, we do pledge to do our best to be fair, and we will always try to
+warn someone before banning him or her.</p>
+<h3 id="contacting">Contacting the moderators</h3>
+<p>If you see anyone being rude, call them out on it. This is your group too,
+and you don't have to accept someone else being disrespectful just because it
+wasn't directed at you. Just remember to be polite and courteous yourself!
+Don't add fuel to the fire.</p>
+<p>But if you see an outrageous violation, want to report spam, feel strongly
+about something, or just want to chat, then contact the mailing list owners.
+It's what we're here for!</p>
<h3 id="using-email-with-google-groups">Using email with Google Groups</h3>
-<p>Instead of using the <a href="https://groups.google.com/">Google groups</a> site, you can use your email client of choice to participate in the mailing lists.</p>
-<p>To subscribe to a group without using the Google Groups site, use the link under "subscribe via email" in the lists above.</p>
+<p>Instead of using the <a href="https://groups.google.com/">Google groups</a>
+site, you can use your email client of choice to participate in the mailing
+lists. To subscribe to a group without using the Google Groups site, use the link
+under "subscribe via email" in the lists above.</p>
<p>To set up how you receive mailing list postings by email:</p>
<ol>
<li>
-<p>Sign into the group via the Google Groups site. For example, for the android-platform group you would use [https://groups.google.com/forum/?fromgroups#!forum/android-platform].</p>
+<p>Sign into the group via the Google Groups site. For example, for the
+android-platform group you would use
+<a href="https://groups.google.com/forum/?fromgroups#!forum/android-platform">
+https://groups.google.com/forum/?fromgroups#!forum/android-platform</a>.</p>
</li>
<li>
<p>Click "My membership" on the right side.</p>
@@ -138,33 +226,36 @@ But if you see an outrageous violation, want to report spam, feel very strongly
</li>
</ol>
<h2 id="android-on-irc">Android on IRC</h2>
-<p>We also have a presence on IRC via <a href="http://freenode.net/">freenode</a>.
-We maintain two official IRC channels on <a href="irc://irc.freenode.net/">irc.freenode.net</a> (access via the web
-at <a href="http://webchat.freenode.net/">freenode webchat</a>)</p>
+<p>Android has a presence on IRC via
+<a href="http://freenode.net/">freenode</a>. We maintain two official IRC
+channels on <a href="irc://irc.freenode.net/">irc.freenode.net</a> (access via
+the web at <a href="http://webchat.freenode.net/">freenode webchat</a>)</p>
<ul>
<li>
-<p><a href="irc://irc.freenode.net/android">#android</a> - dedicated to general Android discussion and porting concerns</p>
+<p><a href="irc://irc.freenode.net/android">#android</a> - dedicated to
+general Android discussion and porting concerns</p>
</li>
<li>
<p><a href="irc://irc.freenode.net/android-dev">#android-dev</a> - dedicated to discussion about writing Android applications</p>
</li>
</ul>
-<p>The channels above are official. There are a few other channels the
-community is using, but are not official. These aren't official or officially
-moderated/managed, so you use the channels below at your own risk. The Open
-Handset Alliance doesn't endorse these channels, there's no warranty express
-or implied, and so on. There may be more channels than just these listed.</p>
+<p>The community also uses several <em>unofficial</em> channels that are not not officially moderated or managed. The Open Handset Alliance does not endorse unofficial channels and there's no warranty express or implied, so use them at your own risk. Here's a list of a few unofficial channels (many more may exist):</p>
+
<ul>
<li>
-<p><a href="irc://irc.freenode.net/android-firehose">#android-firehose</a> - displays in real-time the commits to the Android Open Source Project</p>
+<p><a href="irc://irc.freenode.net/android-firehose">#android-firehose</a> -
+displays in real-time the commits to the Android Open Source Project</p>
</li>
<li>
-<p><a href="irc://irc.freenode.net/android-fr">#android-fr</a> - pour discuter d'Android en français</p>
+<p><a href="irc://irc.freenode.net/android-fr">#android-fr</a> - pour discuter
+d'Android en français</p>
</li>
<li>
-<p><a href="irc://irc.freenode.net/android-offtopic">#android-offtopic</a> - for, well, off-topic discussions</p>
+<p><a href="irc://irc.freenode.net/android-offtopic">#android-offtopic</a> -
+for, well, off-topic discussions</p>
</li>
<li>
-<p><a href="irc://irc.freenode.net/android-root">#android-root</a> - for discussion related to off-label uses of hardware</p>
+<p><a href="irc://irc.freenode.net/android-root">#android-root</a> - for
+discussion related to off-label uses of hardware</p>
</li>
-</ul>
+</ul> \ No newline at end of file