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