1page.title=Device-Specific Code 2@jd:body 3 4<!-- 5 Copyright 2015 The Android Open Source Project 6 7 Licensed under the Apache License, Version 2.0 (the "License"); 8 you may not use this file except in compliance with the License. 9 You may obtain a copy of the License at 10 11 http://www.apache.org/licenses/LICENSE-2.0 12 13 Unless required by applicable law or agreed to in writing, software 14 distributed under the License is distributed on an "AS IS" BASIS, 15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 See the License for the specific language governing permissions and 17 limitations under the License. 18--> 19 20<div id="qv-wrapper"> 21 <div id="qv"> 22 <h2>In this document</h2> 23 <ol id="auto-toc"> 24 </ol> 25 </div> 26</div> 27 28<p>The recovery system includes several hooks for inserting device-specific 29code so that OTA updates can also update parts of the device other than the 30Android system (e.g., the baseband or radio processor).</p> 31<p>The following sections and examples customize the <b>tardis</b> device 32produced by the <b>yoyodyne</b> vendor.</p> 33 34<h2>Partition map</h2> 35<p>As of Android 2.3, the platform supports eMMC flash devices and the ext4 36filesystem that runs on those devices. It also supports Memory Technology Device 37(MTD) flash devices and the yaffs2 filesystem from older releases.</p> 38<p>The partition map file is specified by TARGET_RECOVERY_FSTAB; this file is 39used by both the recovery binary and the package-building tools. You can 40specify the name of the map file in TARGET_RECOVERY_FSTAB in BoardConfig.mk.</p> 41<p>A sample partition map file might look like this:</p> 42 43<p><code>device/yoyodyne/tardis/recovery.fstab</code></p> 44 45<pre> 46# mount point fstype device [device2] [options (3.0+ only)] 47 48/sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 49/cache yaffs2 cache 50/misc mtd misc 51/boot mtd boot 52/recovery emmc /dev/block/platform/s3c-sdhci.0/by-name/recovery 53/system ext4 /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096 54/data ext4 /dev/block/platform/s3c-sdhci.0/by-name/userdata 55</pre> 56 57<p>With the exception of <code>/sdcard</code>, which is optional, all mount 58points in this example must be defined (devices may also add extra partitions). 59There are five supported filesystem types:</p> 60<dl> 61<dt>yaffs2</dt> 62<dd>A yaffs2 filesystem atop an MTD flash device. "device" must be the name of 63the MTD partition and must appear in <code>/proc/mtd</code>.</dd> 64<dt>mtd</dt> 65<dd>A raw MTD partition, used for bootable partitions such as boot and 66recovery. MTD is not actually mounted, but the mount point is used as a key to 67locate the partition. "device" must be the name of the MTD partition in 68<code>/proc/mtd</code>.</dd> 69<dt>ext4</dt> 70<dd>An ext4 filesystem atop an eMMC flash device. "device" must be the path of 71the block device.</dd> 72<dt>emmc</dt> 73<dd>A raw eMMC block device, used for bootable partitions such as boot and 74recovery. Similar to the mtd type, eMMc is never actually mounted, but the 75mount point string is used to locate the device in the table.</dd> 76<dt>vfat</dt> 77<dd>A FAT filesystem atop a block device, typically for external storage such 78as an SD card. The device is the block device; device2 is a second block 79device the system attempts to mount if mounting the primary device fails (for 80compatibility with SD cards which may or may not be formatted with a partition 81table). 82<p>All partitions must be mounted in the root directory (i.e. the mount point 83value must begin with a slash and have no other slashes). This restriction 84applies only to mounting filesystems in recovery; the main system is free to 85mount them anywhere. The directories <code>/boot</code>, <code>/recovery</code>, 86and <code>/misc</code> should be raw types (mtd or emmc), while the 87directories <code>/system</code>, <code>/data</code>, <code>/cache</code>, and 88<code>/sdcard</code> (if available) should be filesystem types (yaffs2, ext4, 89or vfat).</p></dd></dl> 90 91<p>Starting in Android 3.0, the recovery.fstab file gains an additional 92optional field, <i>options</i>. Currently the only defined option is <i>length 93</i>, which lets you explicitly specify the length of the partition. 94This length is used when reformatting the partition (e.g., for the userdata 95partition during a data wipe/factory reset operation, or for the system 96partition during installation of a full OTA package). If the length value is 97negative, then the size to format is taken by adding the length value to the 98true partition size. For instance, setting "length=-16384" means the last 16k 99of that partition will <i>not</i> be overwritten when that partition is 100reformatted. This supports features such as encryption of the userdata 101partition (where encryption metadata is stored at the end of the 102partition that should not be overwritten).</p> 103 104<p class="note"><strong>Note:</strong> The <b>device2</b> and <b>options</b> 105fields are optional, creating ambiguity in parsing. If the entry in the fourth 106field on the line begins with a ‘/' character, it is considered a <b>device2 107</b> entry; if the entry does not begin with a ‘/' character, it is considered 108an <b>options</b> field.</p> 109 110<h2 id="recovery-ui">Recovery UI</h2> 111<p>To support devices with different available hardware (physical buttons, 112LEDs, screens, etc.), you can customize the recovery interface to display 113status and access the manually-operated hidden features for each device.</p> 114<p>Your goal is to build a small static library with a couple of C++ objects 115to provide the device-specific functionality. The file <code> 116<b>bootable/recovery/default_device.cpp</b></code> is used by default, and 117makes a good starting point to copy when writing a version of this file for 118your device.</p> 119 120<p><code>device/yoyodyne/tardis/recovery/recovery_ui.cpp</code></p> 121 122<pre> 123#include <linux/input.h> 124 125#include "common.h" 126#include "device.h" 127#include "screen_ui.h" 128</pre> 129 130 131<h3 id="header-item-functions">Header and item functions</h3> 132<p>The Device class requires functions for returning headers and items that 133appear in the hidden recovery menu. Headers describe how to operate the menu 134(i.e. controls to change/select the highlighted item).</p> 135 136<pre> 137static const char* HEADERS[] = { "Volume up/down to move highlight;", 138 "power button to select.", 139 "", 140 NULL }; 141 142static const char* ITEMS[] = {"reboot system now", 143 "apply update from ADB", 144 "wipe data/factory reset", 145 "wipe cache partition", 146 NULL }; 147</pre> 148 149<p class="note"><strong>Note:</strong> Long lines are truncated (not wrapped), 150so keep the width of your device screen in mind.</p> 151 152<h3 id="customize-checkkey">Customizing CheckKey</h3> 153<p>Next, define your device's RecoveryUI implementation. This example assumes 154the <b>tardis</b> device has a screen, so you can inherit from the built-in 155ScreenRecoveryUIimplementation (see instructions for 156<a href="#devices-without-screens">devices without a screen</a>.) The only 157function to customize from ScreenRecoveryUI is <code>CheckKey()</code>, which 158does the initial asynchronous key handling:</p> 159 160<pre> 161class TardisUI : public ScreenRecoveryUI { 162 public: 163 virtual KeyAction CheckKey(int key) { 164 if (key == KEY_HOME) { 165 return TOGGLE; 166 } 167 return ENQUEUE; 168 } 169}; 170</pre> 171 172 173<h4 id="key-constants">KEY constants</h4> 174<p>The KEY_* constants are defined in <code>linux/input.h</code>.<code> 175CheckKey()</code> is called no matter what is going on in the rest of 176recovery: when the menu is toggled off, when it is on, during package 177installation, during userdata wiping, etc. It can return one of four constants: 178</p> 179 180<ul> 181<li><b>TOGGLE</b>. Toggle the display of the menu and/or text log on or off 182</li> 183<li><b>REBOOT</b>. Immediately reboot the device</li> 184<li><b>IGNORE</b>. Ignore this keypress</li> 185<li><b>ENQUEUE</b>. Enqueue this keypress to be consumed synchronously (i.e., 186by the recovery menu system if the display is enabled)</li> 187</ul> 188 189<p><code>CheckKey()</code> is called each time a key-down event is followed by 190a key-up event for the same key. (The sequence of events A-down B-down B-up 191A-up results only in <code>CheckKey(B)</code> being called.) <code>CheckKey() 192</code> can call <code>IsKeyPressed()</code>, to find out if other keys are 193being held down. (In the above sequence of key events, if <code>CheckKey(B) 194</code> called <code>IsKeyPressed(A)</code> it would have returned true.)</p> 195<p><code>CheckKey()</code> can maintain state in its class; this can be useful 196to detect sequences of keys. This example shows a slightly more complex 197setup: the display is toggled by holding down power and pressing volume-up, 198and the device can be rebooted immediately by pressing the power button five 199times in a row (with no other intervening keys):</p> 200 201<pre> 202class TardisUI : public ScreenRecoveryUI { 203 private: 204 int consecutive_power_keys; 205 206 public: 207 TardisUI() : consecutive_power_keys(0) {} 208 209 virtual KeyAction CheckKey(int key) { 210 if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) { 211 return TOGGLE; 212 } 213 if (key == KEY_POWER) { 214 ++consecutive_power_keys; 215 if (consecutive_power_keys >= 5) { 216 return REBOOT; 217 } 218 } else { 219 consecutive_power_keys = 0; 220 } 221 return ENQUEUE; 222 } 223}; 224</pre> 225 226 227<h3 id="screenrecoveryui">ScreenRecoveryUI</h3> 228<p>When using your own images (error icon, installation animation, progress 229bars) with ScreenRecoveryUI, you might need to set some member variables to 230specify attributes such as the number of frames, speed, and overlay offsets. 231You can set the following variables:</p> 232 233<table> 234<tbody> 235<tr> 236<th>Variable Name</th> 237<th>Purpose</th> 238<th>Release</th> 239</tr> 240<tr> 241<td>animation_fps 242</td> 243<td>speed (in frames per second) of animations 244</td> 245<td>Android 5.x and earlier</td> 246</tr> 247<tr> 248<td>installing_frames 249</td> 250<td>number of frames in the installation animation 251</td> 252<td>Android 4.x and earlier</td> 253</tr> 254<tr> 255<td>install_overlay_offset_x, 256install_overlay_offset_y 257</td> 258<td>offset of the per-frame overlay (relative to the base image) for the 259installation animation 260</td> 261<td>Android 4.x and earlier</td> 262</tr> 263</tbody> 264</table> 265 266<p>To set variables, override the <code>ScreenRecoveryUI::Init()</code> 267function in your subclass. Set the values, then call the <code>parent Init() 268</code> function to complete initialization:</p> 269 270<pre> 271class TardisUI : public ScreenRecoveryUI { 272 ... 273 void Init() { 274 // change the speed at which animations run 275 animation_fps = 30; 276 277 ScreenRecoveryUI::Init(); 278 } 279</pre> 280 281<p>The default values correspond to the default recovery images; when using 282these images you don't need to provide an <code>Init()</code> function. For 283details on images, see <a href="#recovery-ui-images">Recovery UI Images</a>. 284</p> 285 286<h3 id="device-class">Device Class</h3> 287<p>After you have a RecoveryUI implementation, define your device class 288(subclassed from the built-in Device class). It should create a single 289instance of your UI class and return that from the <code>GetUI()</code> 290function:</p> 291 292<pre> 293class TardisDevice : public Device { 294 private: 295 TardisUI* ui; 296 297 public: 298 TardisDevice() : 299 ui(new TardisUI) { 300 } 301 302 RecoveryUI* GetUI() { return ui; } 303</pre> 304 305<h3 id="startrecovery">StartRecovery</h3> 306<p>The <code>StartRecovery()</code> method is called at the start of recovery, 307after the UI has been initialized and after the arguments have been parsed, 308but before any action has been taken. The default implementation does nothing, 309so you do not need to provide this in your subclass if you have nothing to do: 310</p> 311 312<pre> 313 void StartRecovery() { 314 // ... do something tardis-specific here, if needed .... 315 } 316</pre> 317 318<h3 id="supply-manage-recovery-menu">Supplying and managing recovery menu</h3> 319<p>The system calls two methods to get the list of header lines and the list 320of items. In this implementation, it returns the static arrays defined at the 321top of the file:</p> 322 323<pre> 324const char* const* GetMenuHeaders() { return HEADERS; } 325const char* const* GetMenuItems() { return ITEMS; } 326</pre> 327 328<h4 id="handlemenukey">HandleMenuKey</h4> 329<p>Next, provide a <code>HandleMenuKey()</code> function, which takes a 330keypress and the current menu visibility, and decides what action to take:</p> 331 332<pre> 333 int HandleMenuKey(int key, int visible) { 334 if (visible) { 335 switch (key) { 336 case KEY_VOLUMEDOWN: return kHighlightDown; 337 case KEY_VOLUMEUP: return kHighlightUp; 338 case KEY_POWER: return kInvokeItem; 339 } 340 } 341 return kNoAction; 342 } 343</pre> 344 345<p>The method takes a key code (which has previously been processed and 346enqueued by the <code>CheckKey()</code> method of the UI object), and the 347current state of the menu/text log visibility. The return value is an integer. 348If the value is 0 or higher, that is taken as the position of a menu item, 349which is invoked immediately (see the <code>InvokeMenuItem()</code> method 350below). Otherwise it can be one of the following predefined constants:</p> 351 352<ul> 353<li><b>kHighlightUp</b>. Move the menu highlight to the previous item</li> 354<li><b>kHighlightDown</b>. Move the menu highlight to the next item</li> 355<li><b>kInvokeItem</b>. Invoke the currently highlighted item</li> 356<li><b>kNoAction</b>. Do nothing with this keypress</li> 357</ul> 358 359<p>As implied by the the visible argument, <code>HandleMenuKey()</code> is 360called even if the menu is not visible. Unlike <code>CheckKey()</code>, it is 361<i>not</i> called while recovery is doing something such as wiping data or 362installing a package—it's called only when recovery is idle and waiting for 363input.</p> 364 365<h4 id="trackball-mechanism">Trackball Mechanisms</h4> 366<p>If your device has a trackball-like input mechanism (generates input events 367with type EV_REL and code REL_Y), recovery synthesizes KEY_UP and KEY_DOWN 368keypresses whenever the trackball-like input device reports motion in the Y 369axis. All you need to do is map KEY_UP and KEY_DOWN events onto menu actions. 370This mapping does <i>not</i> happen for <code>CheckKey()</code>, so you can't 371use trackball motions as triggers for rebooting or toggling the display.</p> 372 373<h4 id="modifier-keys">Modifier Keys</h4> 374<p>To check for keys being held down as modifiers, call the <code>IsKeyPressed() 375</code> method of your own UI object. For example, on some 376devices pressing Alt-W in recovery would start a data wipe whether the menu 377was visible or not. YOu could implement like this:</p> 378 379<pre> 380 int HandleMenuKey(int key, int visible) { 381 if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) { 382 return 2; // position of the "wipe data" item in the menu 383 } 384 ... 385 } 386</pre> 387 388<p class="note"><strong>Note:</strong> If <b>visible</b> is false, it doesn't 389make sense to return the special values that manipulate the menu (move 390highlight, invoke highlighted item) since the user can't see the highlight. 391However, you can return the values if desired.</p> 392 393<h4 id="invokemenuitem">InvokeMenuItem</h4> 394<p>Next, provide an <code>InvokeMenuItem()</code> method that maps integer 395positions in the array of items returned by <code>GetMenuItems()</code> to 396actions. For the array of items in the tardis example, use:</p> 397 398<pre> 399 BuiltinAction InvokeMenuItem(int menu_position) { 400 switch (menu_position) { 401 case 0: return REBOOT; 402 case 1: return APPLY_ADB_SIDELOAD; 403 case 2: return WIPE_DATA; 404 case 3: return WIPE_CACHE; 405 default: return NO_ACTION; 406 } 407 } 408</pre> 409 410<p>This method can return any member of the BuiltinAction enum to tell the 411system to take that action (or the NO_ACTION member if you want the system to 412do nothing). This is the place to provide additional recovery functionality 413beyond what's in the system: Add an item for it in your menu, execute it here 414when that menu item is invoked, and return NO_ACTION so the system does nothing 415else.</p> 416<p>BuiltinAction contains the following values:</p> 417<ul> 418<li><b>NO_ACTION</b>. Do nothing.</li> 419<li><b>REBOOT</b>. Exit recovery and reboot the device normally.</li> 420<li><b>APPLY_EXT, APPLY_CACHE, APPLY_ADB_SIDELOAD</b>. Install an update 421package from various places. For details, see 422<a href="#sideloading">Sideloading</a>.</li> 423<li><b>WIPE_CACHE</b>. Reformat the cache partition only. No confirmation 424required as this is relatively harmless.</li> 425<li><b>WIPE_DATA</b>. Reformat the userdata and cache partitions, also known 426as a factory data reset. The user is asked to confirm this action before 427proceeding.</li> 428</ul> 429<p>The last method, <code>WipeData()</code>, is optional and is called 430whenever a data wipe operation is initiated (either from recovery via the menu 431or when the user has chosen to do a factory data reset from the main system). 432This method is called before the user data and cache partitions are wiped. If 433your device stores user data anywhere other than those two partitions, you 434should erase it here. You should return 0 to indicate success and another 435value for failure, though currently the return value is ignored. The user data 436and cache partitions are wiped whether you return success or failure.</p> 437 438<pre> 439 int WipeData() { 440 // ... do something tardis-specific here, if needed .... 441 return 0; 442 } 443</pre> 444 445<h4 id="make-device">Make Device</h4> 446<p>Finally, include some boilerplate at the end of the recovery_ui.cpp file 447for the <code>make_device()</code> function that creates and returns an 448instance of your Device class:</p> 449 450<pre> 451class TardisDevice : public Device { 452 // ... all the above methods ... 453}; 454 455Device* make_device() { 456 return new TardisDevice(); 457} 458</pre> 459 460<h3 id="build-link-device-recovery">Build and link to device recovery</h3> 461<p>After completing the recovery_ui.cpp file, built it and link it to recovery 462on your device. In Android.mk, create a static library that contains only this 463C++ file:</p> 464 465<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p> 466 467<pre> 468LOCAL_PATH := $(call my-dir) 469include $(CLEAR_VARS) 470 471LOCAL_MODULE_TAGS := eng 472LOCAL_C_INCLUDES += bootable/recovery 473LOCAL_SRC_FILES := recovery_ui.cpp 474 475# should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk 476LOCAL_MODULE := librecovery_ui_tardis 477 478include $(BUILD_STATIC_LIBRARY) 479</pre> 480 481<p>Then, in the board configuration for this device, specify your static 482library as the value of TARGET_RECOVERY_UI_LIB.</p> 483 484<pre> 485device/yoyodyne/tardis/BoardConfig.mk 486 [...] 487 488# device-specific extensions to the recovery UI 489TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis 490</pre> 491 492 493<h2 id="recovery-ui-images">Recovery UI images</h2> 494<p>The recovery user interface consists images. Ideally, users never interact 495with the UI: During a normal update, the phone boots into recovery, fills the 496installation progress bar, and boots back into the new system without input 497from the user. In the event of a system update problem, the only user action 498that can be taken is to call customer care.</p> 499<p>An image-only interface obviates the need for localization. However, as of 500Android 5.x the update can display a string of text (e.g. "Installing system 501update...") along with the image. For details, see <a href="#recovery-text"> 502Localized recovery text</a>.</p> 503 504<h3 id="recovery-5.x">Android 5.x</h3> 505<p>The Android 5.x recovery UI uses two main images: the <b>error</b> image 506and the <b>installing</b> animation.</p> 507 508<table> 509<tbody> 510<tr> 511<td> 512<img src="../images/icon_error.png" alt="image shown during ota error"> 513<p class="img-caption"><strong>Figure 1.</strong> icon_error.png</p> 514</td> 515<td> 516<img src="../images/icon_installing_5x.png" alt="image shown during ota install" 517height="275"> 518<p class="img-caption"><strong>Figure 2.</strong> icon_installing.png</p> 519</td> 520</tr> 521</tbody> 522</table> 523 524<p>The installing animation is represented as a single PNG image with 525different frames of the animation interlaced by row. For example, for a 5267-frame animation that is 200x200, create a single 200x1400 image where first 527frame is rows 0, 7, 14, 21, ...; the second frame is rows 1, 8, 15, 22, ...; 528etc. The combined image includes a text chunk that indicates the number of 529animation frames. The tool <code>bootable/recovery/interlace-frames.py</code> 530takes a set of input frames and combines them into the necessary composite 531image used by recovery.</p> 532 533<p>Default images are available in different densities and are located in 534<code>bootable/recovery/res-$DENSITY/images</code> (e.g., 535<code>bootable/recovery/res-hdpi/images</code>). To use a static image during 536installation, you need only provide the icon_installing.png image and set the 537number of frames in the animation to 0 (the error icon is not animated; it is 538always a static image).</p> 539 540 541<h3 id="recovery-4.x">Android 4.x and earlier</h3> 542<p>The Android 4.x and earlier recovery UI uses the <b>error</b> image (shown 543above) and the <b>installing</b> animation plus several overlay images:</p> 544 545<table> 546<tbody> 547<tr> 548<td rowspan="2"> 549<img src="../images/icon_installing.png" alt="image shown during ota install"> 550<p class="img-caption"><strong>Figure 3.</strong> icon_installing.png</p> 551</td> 552<td> 553<img src="../images/icon_installing_overlay01.png" alt="image shown as first 554overlay"> 555<p class="img-caption"><strong>Figure 4.</strong> icon-installing_overlay01.png 556</p> 557</td> 558</tr> 559<tr> 560<td> 561<img src="../images/icon_installing_overlay07.png" alt="image shown as seventh 562overlay"> 563<p class="img-caption"><strong>Figure 5.</strong> icon_installing_overlay07.png 564</p> 565</td> 566</tr> 567</tbody> 568</table> 569 570 571<p>During installation, the on-screen display is constructed by drawing the 572icon_installing.png image, then drawing one of the overlay frames on top of it 573at the proper offset. Here, a red box is superimposed to highlight where the 574overlay is placed on top of the base image:</p> 575 576<table style="border-collapse:collapse;"> 577<tbody> 578<tr> 579<td><img align="center" src="../images/composite01.png" alt="composite image of 580install plus first overlay"> 581<p class="img-caption"><strong>Figure 6.</strong> Installing animation frame 1 582(icon_installing.png + icon_installing_overlay01.png) 583</td> 584<td><img align="center" src="../images/composite01.png" alt="composite image of 585install plus seventh overlay"> 586<p class="img-caption"><strong>Figure 7.</strong> Installing animation frame 7 587(icon_installing.png + icon_installing_overlay07.png) 588</td> 589</tr> 590</tbody> 591</table> 592 593<p>Subsequent frames are displayed by drawing <i>only</i> the next overlay 594image atop what's already there; the base image is not redrawn.</p> 595 596<p>The number of frames in the animation, desired speed, and x- and y-offsets 597of the overlay relative to the base are set by member variables of the 598ScreenRecoveryUI class. When using custom images instead of default images, 599override the <code>Init()</code> method in your subclass to change these 600values for your custom images (for details, see <a href="#screenrecoveryui"> 601ScreenRecoveryUI</a>). The script <code>bootable/recovery/make-overlay.py 602</code> can assist in converting a set of image frames to the "base image + 603overlay images" form needed by recovery, including computing of the necessary 604offsets.</p> 605 606<p>Default images are located in <code>bootable/recovery/res/images</code>. To 607use a static image during installation, you need only provide the 608icon_installing.png image and set the number of frames in the animation to 0 609(the error icon is not animated; it is always a static image).</p> 610 611 612<h3 id="recovery-text">Localized recovery text</h3> 613<p>Android 5.x displays a string of text (e.g., "Installing system update...") 614along with the image. When the main system boots into recovery it passes the 615user's current locale as a command-line option to recovery. For each message 616to display, recovery includes a second composite image with pre-rendered text 617strings for that message in each locale.</p> 618 619<p>Sample image of recovery text strings:</p> 620 621<img src="../images/installing_text.png" alt="image of recovery text"> 622<p class="img-caption"><strong>Figure 8.</strong> Localized text for recovery 623messages</p> 624 625<p>Recovery text can display the following messages:</p> 626<ul> 627<li>Installing system update...</li> 628<li>Error!</li> 629<li>Erasing... (when doing a data wipe/factory reset)</li> 630<li>No command (when a user boots into recovery manually)</li> 631</ul> 632 633<p>The Android app in <code>development/tools/recovery_l10/</code> renders 634localizations of a message and creates the composite image. For details on 635using this app, refer to the comments in <code>development/tools/recovery_l10n/ 636src/com/android/recovery_l10n/Main.java</code>. 637 638<p>When a user boots into recovery manually, the locale might not be available 639and no text is displayed. Do not make the text messages critical to the 640recovery process.</p> 641 642<p class="note"><strong>Note:</strong> The hidden interface that displays log 643messages and allows the user to select actions from the menu is available only 644in English.</p> 645 646 647<h2 id="progress-bars">Progress bars</h2> 648<p>Progress bars can appear below the main image (or animation). The progress 649bar is made by combining two input images, which must be of the same size:</p> 650 651<img src="../images/progress_empty.png" alt="empty progress bar"> 652<p class="img-caption"><strong>Figure 9.</strong> progress_empty.png</p> 653<img src="../images/progress_fill.png" alt="full progress bar"> 654<p class="img-caption"><strong>Figure 10.</strong> progress_fill.png</p> 655 656<p>The left end of the <i>fill</i> image is displayed next to the right end of 657the <i>empty</i> image to make the progress bar. The position of the boundary 658between the two images is changed to indicate the progress. For example, with 659the above pairs of input images, display:</p> 660 661<img src="../images/progress_1.png" alt="progress bar at 1%"> 662<p class="img-caption"><strong>Figure 11.</strong> Progress bar at 1%></p> 663<img src="../images/progress_10.png" alt="progress bar at 10%"> 664<p class="img-caption"><strong>Figure 12.</strong> Progress bar at 10%</p> 665<img src="../images/progress_50.png" alt="progress bar at 50%"> 666<p class="img-caption"><strong>Figure 13.</strong> Progress bar at 50%</p> 667 668<p>You can provide device-specific versions of these images by placing them 669into (in this example) <code>device/yoyodyne/tardis/recovery/res/images</code> 670. Filenames must match the ones listed above; when a file is found in that 671directory, the build system uses it in preference to the corresponding default 672image. Only PNGs in RGB or RGBA format with 8-bit color depth are supported. 673</p> 674 675<p class="note"><strong>Note:</strong> In Android 5.x, if the locale is known 676to recovery and is a right-to-left (RTL) language (Arabic, Hebrew, etc.), the 677progress bar fills from right to left.</p> 678 679 680<h2 id="devices-without-screens">Devices without screens</h2> 681<p>Not all Android devices have screens. If your device is a headless appliance 682or has an audio-only interface, you may need to do more extensive customization 683of recovery UI. Instead of creating a subclass of ScreenRecoveryUI, subclass its 684parent class RecoveryUI directly.</p> 685<p>RecoveryUI has methods for handling a lower-level UI operations such as 686"toggle the display," "update the progress bar," "show the menu," "change the 687menu selection," etc. You can override these to provide an appropriate 688interface for your device. Maybe your device has LEDs where you can use 689different colors or patterns of flashing to indicate state, or maybe you can 690play audio. (Perhaps you don't want to support a menu or the "text display" 691mode at all; you can prevent accessing them with <code>CheckKey()</code> and 692<code>HandleMenuKey()</code> implementations that never toggle the display on 693or select a menu item. In this case, many of the RecoveryUI methods you need 694to provide can just be empty stubs.)</p> 695<p>See <code>bootable/recovery/ui.h</code> for the declaration of RecoveryUI 696to see what methods you must support. RecoveryUI is abstract—some methods are 697pure virtual and must be provided by subclasses—but it does contain the code 698to do processing of key inputs. You can override that too, if your device 699doesn't have keys or you want to process them differently.</p> 700 701<h2 id="updater">Updater</h2> 702<p>You can use device-specific code in the installation of the update package 703by providing your own extension functions that can be called from within your 704updater script. Here's a sample function for the tardis device:</p> 705 706<p><code>device/yoyodyne/tardis/recovery/recovery_updater.c</code></p> 707<pre> 708#include <stdlib.h> 709#include <string.h> 710 711#include "edify/expr.h" 712</pre> 713 714<p>Every extension function has the same signature. The arguments are the name 715by which the function was called, a <code>State*</code> cookie, the number of 716incoming arguments, and an array of <code>Expr*</code> pointers representing 717the arguments. The return value is a newly-allocated <code>Value*</code>.</p> 718 719<pre> 720Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) { 721 if (argc != 2) { 722 return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc); 723 } 724</pre> 725 726<p>Your arguments have not been evaluated at the time your function is 727called—your function's logic determines which of them get evaluated and how 728many times. Thus, you can use extension functions to implement your own 729control structures. <code>Call Evaluate()</code> to evaluate an <code>Expr* 730</code> argument, returning a <code>Value*</code>. If <code>Evaluate()</code> 731returns NULL, you should free any resources you're holding and immediately 732return NULL (this propagates aborts up the edify stack). Otherwise, you take 733ownership of the Value returned and are responsible for eventually calling 734<code>FreeValue()</code> on it.</p> 735 736<p>Suppose the function needs two arguments: a string-valued <b>key</b> and a 737blob-valued <b>image</b>. You could read arguments like this:</p> 738 739<pre> 740 Value* key = EvaluateValue(state, argv[0]); 741 if (key == NULL) { 742 return NULL; 743 } 744 if (key->type != VAL_STRING) { 745 ErrorAbort(state, "first arg to %s() must be string", name); 746 FreeValue(key); 747 return NULL; 748 } 749 Value* image = EvaluateValue(state, argv[1]); 750 if (image == NULL) { 751 FreeValue(key); // must always free Value objects 752 return NULL; 753 } 754 if (image->type != VAL_BLOB) { 755 ErrorAbort(state, "second arg to %s() must be blob", name); 756 FreeValue(key); 757 FreeValue(image) 758 return NULL; 759 } 760</pre> 761 762<p>Checking for NULL and freeing previously evaluated arguments can get tedious 763for multiple arguments. The <code>ReadValueArgs()</code> function can make this 764easier. Instead of the code above, you could have written this:</p> 765 766<pre> 767 Value* key; 768 Value* image; 769 if (ReadValueArgs(state, argv, 2, &key, &image) != 0) { 770 return NULL; // ReadValueArgs() will have set the error message 771 } 772 if (key->type != VAL_STRING || image->type != VAL_BLOB) { 773 ErrorAbort(state, "arguments to %s() have wrong type", name); 774 FreeValue(key); 775 FreeValue(image) 776 return NULL; 777 } 778</pre> 779 780<p><code>ReadValueArgs()</code> doesn't do type-checking, so you must do that 781here; it's more convenient to do it with one <b>if</b> statement at 782the cost of producing a somewhat less specific error message when it fails. 783But <code>ReadValueArgs()</code> does handle evaluating each argument and 784freeing all the previously-evaluated arguments (as well as setting a useful 785error message) if any of the evaluations fail. You can use a <code> 786ReadValueVarArgs()</code> convenience function for evaluating a variable 787number of arguments (it returns an array of <code>Value*</code>).</p> 788 789<p>After evaluating the arguments, do the work of the function:</p> 790 791<pre> 792 // key->data is a NUL-terminated string 793 // image->data and image->size define a block of binary data 794 // 795 // ... some device-specific magic here to 796 // reprogram the tardis using those two values ... 797</pre> 798 799<p>The return value must be a <code>Value*</code> object; ownership of this 800object will pass to the caller. The caller takes ownership of any data pointed 801to by this <code>Value*</code>—specifically the datamember.</p> 802<p>In this instance, you want to return a true or false value to indicate 803success. Remember the convention that the empty string is <i>false</i> and all 804other strings are <i>true</i>. You must malloc a Value object with a malloc'd 805copy of the constant string to return, since the caller will <code>free() 806</code> both. Don't forget to call <code>FreeValue()</code> on the objects you 807got by evaluating your arguments!</p> 808 809<pre> 810 FreeValue(key); 811 FreeValue(image); 812 813 Value* result = malloc(sizeof(Value)); 814 result->type = VAL_STRING; 815 result->data = strdup(successful ? "t" : ""); 816 result->size = strlen(result->data); 817 return result; 818} 819</pre> 820 821<p>The convenience function <code>StringValue()</code> wraps a string into a 822new Value object. Use to write the above code more succinctly:</p> 823 824<pre> 825 FreeValue(key); 826 FreeValue(image); 827 828 return StringValue(strdup(successful ? "t" : "")); 829} 830</pre> 831 832<p>To hook functions into the edify interpreter, provide the function 833<code>Register_<i>foo</i></code> where <i>foo</i> is the name of the 834static library containing this code. Call <code>RegisterFunction()</code> to 835register each extension function. By convention, name device-specific 836functions <code><i>device</i>.<i>whatever</i></code> to avoid conflicts with 837future built-in functions added.</p> 838 839<pre> 840void Register_librecovery_updater_tardis() { 841 RegisterFunction("tardis.reprogram", ReprogramTardisFn); 842} 843</pre> 844 845<p>You can now configure the makefile to build a static library with your 846code. (This is the same makefile used to customize the recovery UI in the 847previous section; your device may have both static libraries defined here.)</p> 848 849<p><code>device/yoyodyne/tardis/recovery/Android.mk</code></p> 850 851<pre> 852include $(CLEAR_VARS) 853LOCAL_SRC_FILES := recovery_updater.c 854LOCAL_C_INCLUDES += bootable/recovery 855</pre> 856 857<p>The name of the static library must match the name of the 858<code>Register_<i>libname</i></code> function contained within it.</p> 859 860<pre> 861LOCAL_MODULE := librecovery_updater_tardis 862include $(BUILD_STATIC_LIBRARY) 863</pre> 864 865<p>Finally, configure the build of recovery to pull in your library. Add your 866library to TARGET_RECOVERY_UPDATER_LIBS (which may contain multiple libraries; 867they all get registered). If your code depends on other static libraries that 868are not themselves edify extensions (i.e., they don't have a 869<code>Register_<i>libname</i></code> function), you can list those in 870TARGET_RECOVERY_UPDATER_EXTRA_LIBS to link them to updater without calling 871their (non-existent) registration function. For example, if your 872device-specific code wanted to use zlib to decompress data, you would include 873libz here.</p> 874 875<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p> 876 877<pre> 878 [...] 879 880# add device-specific extensions to the updater binary 881TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis 882TARGET_RECOVERY_UPDATER_EXTRA_LIBS += 883</pre> 884 885<p>The updater scripts in your OTA package can now call your function as any 886other. To reprogram your tardis device, the update script might contain: 887<code>tardis.reprogram("the-key", package_extract_file("tardis-image.dat")) 888</code>. This uses the single-argument version of the built-in function <code> 889package_extract_file()</code>, which returns the contents of a file extracted 890from the update package as a blob to produce the second argument to the new 891extension function.</p> 892 893<h2>OTA package generation</h2> 894<p>The final component is getting the OTA package generation tools to know 895about your device-specific data and emit updater scripts that include calls to 896your extension functions.</p> 897<p>First, get the build system to know about a device-specific blob of data. 898Assuming your data file is in <code>device/yoyodyne/tardis/tardis.dat</code>, 899declare the following in your device's AndroidBoard.mk:</p> 900 901<p><code>device/yoyodyne/tardis/AndroidBoard.mk</code></p> 902<pre> 903 [...] 904 905$(call add-radio-file,tardis.dat) 906</pre> 907 908<p>You could also put it in an Android.mk instead, but then it must to be 909guarded by a device check, since all the Android.mk files in the tree are 910loaded no matter what device is being built. (If your tree includes multiple 911devices, you only want the tardis.dat file added when building the tardis 912device.)</p> 913 914<p><code>device/yoyodyne/tardis/Android.mk</code></p> 915<pre> 916 [...] 917 918# an alternative to specifying it in AndroidBoard.mk 919ifeq (($TARGET_DEVICE),tardis) 920 $(call add-radio-file,tardis.dat) 921endif 922</pre> 923 924<p>These are called radio files for historical reasons; they may have nothing 925to do with the device radio (if present). They are simply opaque blobs of data 926the build system copies into the target-files .zip used by the OTA generation 927tools. When you do a build, tardis.dat is stored in the target-files.zip as 928<code>RADIO/tardis.dat</code>. You can call <code>add-radio-file</code> 929multiple times to add as many files as you want.</p> 930 931<h3 id="python-module">Python module</h3> 932<p>To extend the release tools, write a Python module (must be named 933releasetools.py) the tools can call into if present. Example:</p> 934 935<p><code>device/yoyodyne/tardis/releasetools.py</code></p> 936<pre> 937import common 938 939def FullOTA_InstallEnd(info): 940 # copy the data into the package. 941 tardis_dat = info.input_zip.read("RADIO/tardis.dat") 942 common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat) 943 944 # emit the script code to install this data on the device 945 info.script.AppendExtra( 946 """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""") 947</pre> 948 949<p>A separate function handles the case of generating an incremental OTA 950package. For this example, suppose you need to reprogram the tardis only when 951the tardis.dat file has changed between two builds.</p> 952<pre> 953def IncrementalOTA_InstallEnd(info): 954 # copy the data into the package. 955 source_tardis_dat = info.source_zip.read("RADIO/tardis.dat") 956 target_tardis_dat = info.target_zip.read("RADIO/tardis.dat") 957 958 if source_tardis_dat == target_tardis_dat: 959 # tardis.dat is unchanged from previous build; no 960 # need to reprogram it 961 return 962 963 # include the new tardis.dat in the OTA package 964 common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat) 965 966 # emit the script code to install this data on the device 967 info.script.AppendExtra( 968 """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""") 969</pre> 970 971<h4 id="module-functions">Module functions</h4> 972<p>You can provide the following functions in the module (implement only the 973ones you need).</p> 974<dl> 975<dt><code>FullOTA_Assertions()</code></dt> 976<dd>Called near the start of generating a full OTA. This is a good place to 977emit assertions about the current state of the device. Do not emit script 978commands that make changes to the device.</dd> 979<dt><code>FullOTA_InstallBegin()</code></dt> 980<dd>Called after all the assertions about the device state have passed but 981before any changes have been made. You can emit commands for device-specific 982updates that must run before anything else on the device has been changed.</dd> 983<dt><code>FullOTA_InstallEnd()</code></dt> 984<dd>Called at the end of the script generation, after the script commands to 985update the boot and system partitions have been emitted. You can also emit 986additional commands for device-specific updates.</dd> 987<dt><code>IncrementalOTA_Assertions()</code></dt> 988<dd>Similar to <code>FullOTA_Assertions()</code> but called when generating an 989incremental update package.</dd> 990<dt><code>IncrementalOTA_VerifyBegin()</code></dt> 991<dd>Called after all assertions about the device state have passed but before 992any changes have been made. You can emit commands for device-specific updates 993that must run before anything else on the device has been changed.</dd> 994<dt><code>IncrementalOTA_VerifyEnd()</code></dt> 995<dd>Called at the end of the verification phase, when the script has finished 996confirming the files it is going to touch have the expected starting contents. 997At this point nothing on the device has been changed. You can also emit code for 998additional device-specific verifications.</dd> 999<dt><code>IncrementalOTA_InstallBegin()</code></dt> 1000<dd>Called after files to be patched have been verified as having the expected 1001<i>before</i> state but before any changes have been made. You can emit 1002commands for device-specific updates that must run before anything else on the 1003device has been changed.</dd> 1004<dt><code>IncrementalOTA_InstallEnd()</code></dt> 1005<dd>Similar to its full OTA package counterpart, this is called at the end of 1006the script generation, after the script commands to update the boot and system 1007partitions have been emitted. You can also emit additional commands for 1008device-specific updates.</dd> 1009</dl> 1010 1011<p class="note"><strong>Note:</strong> If the device loses power, OTA 1012installation may restart from the beginning. Be prepared to cope with devices 1013on which these commands have already been run, fully or partially.</p> 1014 1015<h4 id="pass-functions-to-info">Pass functions to info objects</h4> 1016<p>Pass functions to a single info object that contains various useful items: 1017</p> 1018<ul> 1019<li><b>info.input_zip</b>. (Full OTAs only) The <code>zipfile.ZipFile</code> 1020object for the input target-files .zip.</li> 1021<li><b>info.source_zip</b>. (Incremental OTAs only) The <code>zipfile.ZipFile 1022</code> object for the source target-files .zip (the build already on the 1023device when the incremental package is being installed).</li> 1024<li><b>info.target_zip</b>. (Incremental OTAs only) The <code>zipfile.ZipFile 1025</code> object for the target target-files .zip (the build the incremental 1026package puts on the device).</li> 1027<li><b>info.output_zip</b>. Package being created; a <code>zipfile.ZipFile 1028</code> object opened for writing. Use common.ZipWriteStr(info.output_zip, 1029<i>filename</i>, <i>data</i>) to add a file to the package.</li> 1030<li><b>info.script</b>. Script object to which you can append commands. Call 1031<code>info.script.AppendExtra(<i>script_text</i>)</code> to output text into 1032the script. Make sure output text ends with a semicolon so it does not run 1033into commands emitted afterwards.</li> 1034</ul> 1035 1036<p>For details on the info object, refer to the 1037<a href="http://docs.python.org/library/zipfile.html">Python Software Foundation 1038documentation for ZIP archives</a>.</p> 1039 1040<h4 id="specify-module-location">Specify module location</h4> 1041<p>Specify the location of your device's releasetools.py script in your 1042BoardConfig.mk file:</p> 1043 1044<p><code>device/yoyodyne/tardis/BoardConfig.mk</code></p> 1045 1046<pre> 1047 [...] 1048 1049TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis 1050</pre> 1051 1052<p>If TARGET_RELEASETOOLS_EXTENSIONS is not set, it defaults to the <code> 1053$(TARGET_DEVICE_DIR)/../common</code> directory (<code>device/yoyodyne/common 1054</code> in this example). It's best to explicitly define the location of the 1055releasetools.py script. When building the tardis device, the releasetools.py 1056script is included in the target-files .zip file (<code>META/releasetools.py 1057</code>).</p> 1058<p>When you run the release tools (either <code>img_from_target_files</code> 1059or <code>ota_from_target_files</code>), the releasetools.py script in the 1060target-files .zip, if present, is preferred over the one from the Android 1061source tree. You can also explicitly specify the path to the device-specific 1062extensions with the <code>-s</code> (or <code>--device_specific</code>) 1063option, which takes the top priority. This enables you to correct errors and 1064make changes in the releasetools extensions and apply those changes to old 1065target-files.</p> 1066<p>Now, when you run <code>ota_from_target_files</code>, it automatically 1067picks up the device-specific module from the target_files .zip file and uses 1068it when generating OTA packages:</p> 1069 1070<pre> 1071% <b>./build/tools/releasetools/ota_from_target_files \ 1072 -i PREVIOUS-tardis-target_files.zip \ 1073 dist_output/tardis-target_files.zip incremental_ota_update.zip</b> 1074unzipping target target-files... 1075<b>using device-specific extensions from target_files</b> 1076unzipping source target-files... 1077 [...] 1078done. 1079</pre> 1080 1081<p>Alternatively, you can specify device-specific extensions when you run 1082<code>ota_from_target_files</code>.</p> 1083 1084<pre> 1085% <b>./build/tools/releasetools/ota_from_target_files \ 1086 -s device/yoyodyne/tardis \ # specify the path to device-specific extensions 1087 -i PREVIOUS-tardis-target_files.zip \ 1088 dist_output/tardis-target_files.zip incremental_ota_update.zip</b> 1089unzipping target target-files... 1090<b>loaded device-specific extensions from device/yoyodyne/tardis</b> 1091unzipping source target-files... 1092 [...] 1093done. 1094</pre> 1095 1096<p class="note"><strong>Note:</strong> For a complete list of options, refer 1097to the <code>ota_from_target_files</code> comments in <code> 1098build/tools/releasetools/ota_from_target_files</code>.</p> 1099 1100 1101<h2 id="sideloading">Sideloading</h2> 1102<p>Recovery has a <b>sideloading</b> mechanism for manually installing an 1103update package without downloading it over-the-air by the main system. 1104Sideloading is useful for debugging or making changes on devices where the 1105main system can't be booted.</p> 1106<p>Historically, sideloading has been done through loading packages off the 1107device's SD card; in the case of a non-booting device, the package can be put 1108onto the SD card using some other computer and then the SD card inserted into 1109the device. To accommodate Android devices without removable external storage, 1110recovery supports two additional mechanisms for sideloading: loading packages 1111from the cache partition, and loading them over USB using adb.</p> 1112<p>To invoke each sideload mechanism, your device's <code> 1113Device::InvokeMenuItem()</code> method can return the following values of 1114BuiltinAction:</p> 1115 1116<ul> 1117<li><b>APPLY_EXT</b>. Sideload an update package from external storage (<code> 1118/sdcard</code> directory). Your recovery.fstab must define the <code>/sdcard 1119</code> mount point. This is not usable on devices that emulate an SD card 1120with a symlink to <code>/data</code> (or some similar mechanism). <code>/data 1121</code> is typically not available to recovery because it may be encrypted. 1122The recovery UI displays a menu of .zip files in <code>/sdcard</code> and 1123allows the user to select one.</li> 1124<li><b>APPLY_CACHE</b>. Similar to loading a package from <code>/sdcard</code> 1125except that the <code>/cache</code> directory (which <i>is</i> always 1126available to recovery) is used instead. From the regular system, <code>/cache 1127</code> is only writable by privileged users, and if the device isn't bootable 1128then the <code>/cache</code> directory can't be written to at all (which makes 1129this mechanism of limited utility).</li> 1130<li><b>APPLY_ADB_SIDELOAD</b>. Allows user to send a package to the device via 1131a USB cable and the adb development tool. When this mechanism is invoked, 1132recovery starts up its own mini version of the adbd daemon to let adb on a 1133connected host computer talk to it. This mini version supports only a single 1134command: <code>adb sideload <i>filename</i></code>. The named file is sent 1135from the host machine to the device, which then verifies and installs it just 1136as if it had been on local storage.</li> 1137</ul> 1138 1139<p>A few caveats:</p> 1140<ul> 1141<li>Only USB transport is supported.</li> 1142<li>If your recovery runs adbd normally (usually true for userdebug and eng 1143builds), that will be shut down while the device is in adb sideload mode and 1144will be restarted when adb sideload has finished receiving a package. While in 1145adb sideload mode, no adb commands other than <code>sideload</code> work ( 1146<code>logcat</code>, <code>reboot</code>, <code>push</code>, <code>pull</code> 1147, <code>shell</code>, etc. all fail).</li> 1148<li>You cannot exit adb sideload mode on the device. To abort, you can send 1149<code>/dev/null</code> (or anything else that's not a valid package) as the 1150package, and then the device will fail to verify it and stop the installation 1151procedure. The RecoveryUI implementation's <code>CheckKey()</code> method 1152will continue to be called for keypresses, so you can provide a key sequence 1153that reboots the device and works in adb sideload mode.</li> 1154</ul>