From 70ec4de9965caf910eb30cac5a5d01231ed70497 Mon Sep 17 00:00:00 2001 From: Heidi von Markham Date: Fri, 6 Mar 2015 13:15:35 -0800 Subject: Docs: Adding general OTA content, new images Updating with comments from google doc (tbao and xi zhao) Adding reference to options for ota_from_target_files Adding feedback changes Adding 2nd set of feedback changes Adding 3rd set of feedback changes Adding 4th set of feedback changes Breaking content into multiple files, adding block ota, adjusting toc Renamed .jd files, update TOC and document links Adding in dougz's feedback on recovery images, split out 5x vs 4x and earlier Minor text tweaks Fixing merge conflict Adding in dougz's comment Setting 80 column width in all files Adding feedback, moving up one level Adding ota mailing list, cropped localized text image, teaser blub on tech/index, mailing list to community page (includes several edits to meet 80 character column limit) Update mailing list verbiage, added feedback to builtin functions from tbao (in google doc) Bug: 17884100 Change-Id: If162f17180853ef7e0b252f22eb360fb99b58f15 --- src/devices/devices_toc.cs | 15 + src/devices/tech/images/composite01.png | Bin 0 -> 45756 bytes src/devices/tech/images/composite07.png | Bin 0 -> 45800 bytes src/devices/tech/images/icon_error.png | Bin 0 -> 19306 bytes src/devices/tech/images/icon_installing.png | Bin 0 -> 25261 bytes src/devices/tech/images/icon_installing_5x.png | Bin 0 -> 118562 bytes .../tech/images/icon_installing_overlay01.png | Bin 0 -> 10095 bytes .../tech/images/icon_installing_overlay07.png | Bin 0 -> 10062 bytes src/devices/tech/images/installing_text.png | Bin 0 -> 22516 bytes src/devices/tech/images/ota_size_comparison.png | Bin 0 -> 25645 bytes src/devices/tech/images/progress_1.png | Bin 0 -> 119 bytes src/devices/tech/images/progress_10.png | Bin 0 -> 294 bytes src/devices/tech/images/progress_50.png | Bin 0 -> 743 bytes src/devices/tech/images/progress_empty.png | Bin 0 -> 118 bytes src/devices/tech/images/progress_fill.png | Bin 0 -> 404 bytes src/devices/tech/index.jd | 92 +- src/devices/tech/ota/block.jd | 148 +++ src/devices/tech/ota/device_code.jd | 1154 ++++++++++++++++++++ src/devices/tech/ota/index.jd | 160 +++ src/devices/tech/ota/inside_packages.jd | 288 +++++ src/devices/tech/ota/sign_builds.jd | 269 +++++ src/devices/tech/ota/tools.jd | 133 +++ src/source/community/index.jd | 235 ++-- 23 files changed, 2386 insertions(+), 108 deletions(-) create mode 100644 src/devices/tech/images/composite01.png create mode 100644 src/devices/tech/images/composite07.png create mode 100644 src/devices/tech/images/icon_error.png create mode 100644 src/devices/tech/images/icon_installing.png create mode 100644 src/devices/tech/images/icon_installing_5x.png create mode 100644 src/devices/tech/images/icon_installing_overlay01.png create mode 100644 src/devices/tech/images/icon_installing_overlay07.png create mode 100644 src/devices/tech/images/installing_text.png create mode 100644 src/devices/tech/images/ota_size_comparison.png create mode 100644 src/devices/tech/images/progress_1.png create mode 100644 src/devices/tech/images/progress_10.png create mode 100644 src/devices/tech/images/progress_50.png create mode 100644 src/devices/tech/images/progress_empty.png create mode 100644 src/devices/tech/images/progress_fill.png create mode 100755 src/devices/tech/ota/block.jd create mode 100755 src/devices/tech/ota/device_code.jd create mode 100755 src/devices/tech/ota/index.jd create mode 100755 src/devices/tech/ota/inside_packages.jd create mode 100755 src/devices/tech/ota/sign_builds.jd create mode 100755 src/devices/tech/ota/tools.jd diff --git a/src/devices/devices_toc.cs b/src/devices/devices_toc.cs index 1c622d6f..6662b9bb 100644 --- a/src/devices/devices_toc.cs +++ b/src/devices/devices_toc.cs @@ -259,6 +259,21 @@ + +
  • Power diff --git a/src/devices/tech/images/composite01.png b/src/devices/tech/images/composite01.png new file mode 100644 index 00000000..3220521e Binary files /dev/null and b/src/devices/tech/images/composite01.png differ diff --git a/src/devices/tech/images/composite07.png b/src/devices/tech/images/composite07.png new file mode 100644 index 00000000..71257343 Binary files /dev/null and b/src/devices/tech/images/composite07.png differ diff --git a/src/devices/tech/images/icon_error.png b/src/devices/tech/images/icon_error.png new file mode 100644 index 00000000..cb3d1ab2 Binary files /dev/null and b/src/devices/tech/images/icon_error.png differ diff --git a/src/devices/tech/images/icon_installing.png b/src/devices/tech/images/icon_installing.png new file mode 100644 index 00000000..571eb8b0 Binary files /dev/null and b/src/devices/tech/images/icon_installing.png differ diff --git a/src/devices/tech/images/icon_installing_5x.png b/src/devices/tech/images/icon_installing_5x.png new file mode 100644 index 00000000..c2c02016 Binary files /dev/null and b/src/devices/tech/images/icon_installing_5x.png differ diff --git a/src/devices/tech/images/icon_installing_overlay01.png b/src/devices/tech/images/icon_installing_overlay01.png new file mode 100644 index 00000000..e762d6cb Binary files /dev/null and b/src/devices/tech/images/icon_installing_overlay01.png differ diff --git a/src/devices/tech/images/icon_installing_overlay07.png b/src/devices/tech/images/icon_installing_overlay07.png new file mode 100644 index 00000000..3838a85a Binary files /dev/null and b/src/devices/tech/images/icon_installing_overlay07.png differ diff --git a/src/devices/tech/images/installing_text.png b/src/devices/tech/images/installing_text.png new file mode 100644 index 00000000..11e1d3c9 Binary files /dev/null and b/src/devices/tech/images/installing_text.png differ diff --git a/src/devices/tech/images/ota_size_comparison.png b/src/devices/tech/images/ota_size_comparison.png new file mode 100644 index 00000000..9204a90e Binary files /dev/null and b/src/devices/tech/images/ota_size_comparison.png differ diff --git a/src/devices/tech/images/progress_1.png b/src/devices/tech/images/progress_1.png new file mode 100644 index 00000000..aa997d06 Binary files /dev/null and b/src/devices/tech/images/progress_1.png differ diff --git a/src/devices/tech/images/progress_10.png b/src/devices/tech/images/progress_10.png new file mode 100644 index 00000000..1ca391a6 Binary files /dev/null and b/src/devices/tech/images/progress_10.png differ diff --git a/src/devices/tech/images/progress_50.png b/src/devices/tech/images/progress_50.png new file mode 100644 index 00000000..8a2ac6cb Binary files /dev/null and b/src/devices/tech/images/progress_50.png differ diff --git a/src/devices/tech/images/progress_empty.png b/src/devices/tech/images/progress_empty.png new file mode 100644 index 00000000..72581832 Binary files /dev/null and b/src/devices/tech/images/progress_empty.png differ diff --git a/src/devices/tech/images/progress_fill.png b/src/devices/tech/images/progress_fill.png new file mode 100644 index 00000000..becf87bd Binary files /dev/null and b/src/devices/tech/images/progress_fill.png differ diff --git a/src/devices/tech/index.jd b/src/devices/tech/index.jd index a844be8a..62a1f59a 100644 --- a/src/devices/tech/index.jd +++ b/src/devices/tech/index.jd @@ -2,7 +2,7 @@ page.title=Android Core Technologies @jd:body +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    You can enable block-based over-the-air (OTA) updates for new devices +running Android 5.0. OTA is the mechanism by which OEMs remotely update the +system partition of a device:

    +
      +
    • Android 5.0 and later versions use block OTA updates to ensure that +each device uses the exact same partition. Instead of comparing individual +files and computing binary patches, block OTA handles the entire partition as +one file and computes a single binary patch, ensuring the resultant partition +contains exactly the intended bits. This allows the device system image to +achieve the same state via fastboot or OTA.
    • +
    • Android 4.4 and earlier versions used file OTA updates, which +ensured devices contained similar file contents, permissions, and modes, but +allowed metadata such as timestamps and the layout of the underlying storage +to vary between devices based on the update method.
    • + +
    +

    Because block OTA ensures that each device uses the same partition, it +enables the use of dm-verity to cryptographically sign the system partition. +For details on dm-verity, see +Secure Boot. +

    + +

    Note: You must have a working block OTA +system before using dm-verity.

    + +

    Recommendations

    + +

    For devices launching with Android 5.0 or later, use block OTA updates in +the factory ROM. To generate a block-based OTA for subsequent updates, pass +the --block option to ota_from_target_files.

    + +

    For devices that launched with Android 4.4 or earlier, use file OTA +updates. While is it possible to transition devices by sending a full block +OTA of Android 5.0 or later, it requires sending out a full OTA that is +significantly larger than an incremental OTA (and is therefore discouraged). +

    + +

    Because dm-verity requires bootloader support found only in new devices +shipping with Android 5.0 or later, you cannot enable dm-verity for +existing devices.

    + +

    Developers working on the Android OTA system (the recovery image and the +scripts that generate OTAs) can keep up with changes by subscribing to the +android-ota@googlegroups.com +mailing list.

    + +

    File vs. Block OTAs

    + +

    During a file-based OTA, Android attempts to change the contents of the +system partition at the filesystem layer (on a file-by-file basis). The update +is not guaranteed to write files in a consistent order, have a consistent last +modified time or superblock, or even place the blocks in the same location on +the block device. For this reason, file-based OTAs fail on a dm-verity-enabled +device; after the OTA attempt, the device does not boot.

    +

    During a block-based OTA, Android serves the device the difference between +the two block images (rather than two sets of files). The update checks a +device build against the corresponding build server at the block level (below +the filesystem) using one of the following methods:

    + + +

    Note: adb fastboot places the +exact same bits on the device as a full OTA, so flashing is compatible with +block OTA.

    + +

    Updating unmodified systems

    + +

    For devices with unmodified system partitions running Android 5.0, +the download and install process for a block OTA remains the same as for a +file OTA. However, the OTA update itself might include one or more of the +following differences:

    + + +

    Updating modified systems

    +

    For devices with modified system partitions running Android 5.0:

    + \ No newline at end of file diff --git a/src/devices/tech/ota/device_code.jd b/src/devices/tech/ota/device_code.jd new file mode 100755 index 00000000..8d23674c --- /dev/null +++ b/src/devices/tech/ota/device_code.jd @@ -0,0 +1,1154 @@ +page.title=Device-Specific Code +@jd:body + + + +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    The recovery system includes several hooks for inserting device-specific +code so that OTA updates can also update parts of the device other than the +Android system (e.g., the baseband or radio processor).

    +

    The following sections and examples customize the tardis device +produced by the yoyodyne vendor.

    + +

    Partition map

    +

    As of Android 2.3, the platform supports eMMC flash devices and the ext4 +filesystem that runs on those devices. It also supports Memory Technology Device +(MTD) flash devices and the yaffs2 filesystem from older releases.

    +

    The partition map file is specified by TARGET_RECOVERY_FSTAB; this file is +used by both the recovery binary and the package-building tools. You can +specify the name of the map file in TARGET_RECOVERY_FSTAB in BoardConfig.mk.

    +

    A sample partition map file might look like this:

    + +

    device/yoyodyne/tardis/recovery.fstab

    + +
    +# mount point       fstype  device       [device2]        [options (3.0+ only)]
    +
    +/sdcard     vfat    /dev/block/mmcblk0p1 /dev/block/mmcblk0
    +/cache      yaffs2  cache
    +/misc       mtd misc
    +/boot       mtd boot
    +/recovery   emmc    /dev/block/platform/s3c-sdhci.0/by-name/recovery
    +/system     ext4    /dev/block/platform/s3c-sdhci.0/by-name/system length=-4096
    +/data       ext4    /dev/block/platform/s3c-sdhci.0/by-name/userdata
    +
    + +

    With the exception of /sdcard, which is optional, all mount +points in this example must be defined (devices may also add extra partitions). +There are five supported filesystem types:

    +
    +
    yaffs2
    +
    A yaffs2 filesystem atop an MTD flash device. "device" must be the name of +the MTD partition and must appear in /proc/mtd.
    +
    mtd
    +
    A raw MTD partition, used for bootable partitions such as boot and +recovery. MTD is not actually mounted, but the mount point is used as a key to +locate the partition. "device" must be the name of the MTD partition in +/proc/mtd.
    +
    ext4
    +
    An ext4 filesystem atop an eMMC flash device. "device" must be the path of +the block device.
    +
    emmc
    +
    A raw eMMC block device, used for bootable partitions such as boot and +recovery. Similar to the mtd type, eMMc is never actually mounted, but the +mount point string is used to locate the device in the table.
    +
    vfat
    +
    A FAT filesystem atop a block device, typically for external storage such +as an SD card. The device is the block device; device2 is a second block +device the system attempts to mount if mounting the primary device fails (for +compatibility with SD cards which may or may not be formatted with a partition +table). +

    All partitions must be mounted in the root directory (i.e. the mount point +value must begin with a slash and have no other slashes). This restriction +applies only to mounting filesystems in recovery; the main system is free to +mount them anywhere. The directories /boot, /recovery, +and /misc should be raw types (mtd or emmc), while the +directories /system, /data, /cache, and +/sdcard (if available) should be filesystem types (yaffs2, ext4, +or vfat).

    + +

    Starting in Android 3.0, the recovery.fstab file gains an additional +optional field, options. Currently the only defined option is length +, which lets you explicitly specify the length of the partition. +This length is used when reformatting the partition (e.g., for the userdata +partition during a data wipe/factory reset operation, or for the system +partition during installation of a full OTA package). If the length value is +negative, then the size to format is taken by adding the length value to the +true partition size. For instance, setting "length=-16384" means the last 16k +of that partition will not be overwritten when that partition is +reformatted. This supports features such as encryption of the userdata +partition (where encryption metadata is stored at the end of the +partition that should not be overwritten).

    + +

    Note: The device2 and options +fields are optional, creating ambiguity in parsing. If the entry in the fourth +field on the line begins with a ‘/' character, it is considered a device2 + entry; if the entry does not begin with a ‘/' character, it is considered +an options field.

    + +

    Recovery UI

    +

    To support devices with different available hardware (physical buttons, +LEDs, screens, etc.), you can customize the recovery interface to display +status and access the manually-operated hidden features for each device.

    +

    Your goal is to build a small static library with a couple of C++ objects +to provide the device-specific functionality. The file +bootable/recovery/default_device.cpp is used by default, and +makes a good starting point to copy when writing a version of this file for +your device.

    + +

    device/yoyodyne/tardis/recovery/recovery_ui.cpp

    + +
    +#include <linux/input.h>
    +
    +#include "common.h"
    +#include "device.h"
    +#include "screen_ui.h"
    +
    + + +

    Header and item functions

    +

    The Device class requires functions for returning headers and items that +appear in the hidden recovery menu. Headers describe how to operate the menu +(i.e. controls to change/select the highlighted item).

    + +
    +static const char* HEADERS[] = { "Volume up/down to move highlight;",
    +                                 "power button to select.",
    +                                 "",
    +                                 NULL };
    +
    +static const char* ITEMS[] =  {"reboot system now",
    +                               "apply update from ADB",
    +                               "wipe data/factory reset",
    +                               "wipe cache partition",
    +                               NULL };
    +
    + +

    Note: Long lines are truncated (not wrapped), +so keep the width of your device screen in mind.

    + +

    Customizing CheckKey

    +

    Next, define your device's RecoveryUI implementation. This example assumes +the tardis device has a screen, so you can inherit from the built-in +ScreenRecoveryUIimplementation (see instructions for +devices without a screen.) The only +function to customize from ScreenRecoveryUI is CheckKey(), which +does the initial asynchronous key handling:

    + +
    +class TardisUI : public ScreenRecoveryUI {
    +  public:
    +    virtual KeyAction CheckKey(int key) {
    +        if (key == KEY_HOME) {
    +            return TOGGLE;
    +        }
    +        return ENQUEUE;
    +    }
    +};
    +
    + + +

    KEY constants

    +

    The KEY_* constants are defined in linux/input.h. +CheckKey() is called no matter what is going on in the rest of +recovery: when the menu is toggled off, when it is on, during package +installation, during userdata wiping, etc. It can return one of four constants: +

    + + + +

    CheckKey() is called each time a key-down event is followed by +a key-up event for the same key. (The sequence of events A-down B-down B-up +A-up results only in CheckKey(B) being called.) CheckKey() + can call IsKeyPressed(), to find out if other keys are +being held down. (In the above sequence of key events, if CheckKey(B) + called IsKeyPressed(A) it would have returned true.)

    +

    CheckKey() can maintain state in its class; this can be useful +to detect sequences of keys. This example shows a slightly more complex +setup: the display is toggled by holding down power and pressing volume-up, +and the device can be rebooted immediately by pressing the power button five +times in a row (with no other intervening keys):

    + +
    +class TardisUI : public ScreenRecoveryUI {
    +  private:
    +    int consecutive_power_keys;
    +
    +  public:
    +    TardisUI() : consecutive_power_keys(0) {}
    +
    +    virtual KeyAction CheckKey(int key) {
    +        if (IsKeyPressed(KEY_POWER) && key == KEY_VOLUMEUP) {
    +            return TOGGLE;
    +        }
    +        if (key == KEY_POWER) {
    +            ++consecutive_power_keys;
    +            if (consecutive_power_keys >= 5) {
    +                return REBOOT;
    +            }
    +        } else {
    +            consecutive_power_keys = 0;
    +        }
    +        return ENQUEUE;
    +    }
    +};
    +
    + + +

    ScreenRecoveryUI

    +

    When using your own images (error icon, installation animation, progress +bars) with ScreenRecoveryUI, you might need to set some member variables to +specify attributes such as the number of frames, speed, and overlay offsets. +You can set the following variables:

    + + + + + + + + + + + + + + + + + + + + + + + + +
    Variable NamePurposeRelease
    animation_fps +speed (in frames per second) of animations +Android 5.x and earlier
    installing_frames +number of frames in the installation animation +Android 4.x and earlier
    install_overlay_offset_x, +install_overlay_offset_y +offset of the per-frame overlay (relative to the base image) for the +installation animation +Android 4.x and earlier
    + +

    To set variables, override the ScreenRecoveryUI::Init() +function in your subclass. Set the values, then call the parent Init() + function to complete initialization:

    + +
    +class TardisUI : public ScreenRecoveryUI {
    +  ...
    +  void Init() {
    +    // change the speed at which animations run
    +    animation_fps = 30;
    +
    +    ScreenRecoveryUI::Init();
    +  }
    +
    + +

    The default values correspond to the default recovery images; when using +these images you don't need to provide an Init() function. For +details on images, see Recovery UI Images. +

    + +

    Device Class

    +

    After you have a RecoveryUI implementation, define your device class +(subclassed from the built-in Device class). It should create a single +instance of your UI class and return that from the GetUI() +function:

    + +
    +class TardisDevice : public Device {
    +  private:
    +    TardisUI* ui;
    +
    +  public:
    +    TardisDevice() :
    +        ui(new TardisUI) {
    +    }
    +
    +    RecoveryUI* GetUI() { return ui; }
    +
    + +

    StartRecovery

    +

    The StartRecovery() method is called at the start of recovery, +after the UI has been initialized and after the arguments have been parsed, +but before any action has been taken. The default implementation does nothing, +so you do not need to provide this in your subclass if you have nothing to do: +

    + +
    +   void StartRecovery() {
    +       // ... do something tardis-specific here, if needed ....
    +    }
    +
    + +

    Supplying and managing recovery menu

    +

    The system calls two methods to get the list of header lines and the list +of items. In this implementation, it returns the static arrays defined at the +top of the file:

    + +
    +const char* const* GetMenuHeaders() { return HEADERS; }
    +const char* const* GetMenuItems() { return ITEMS; }
    +
    + +

    HandleMenuKey

    +

    Next, provide a HandleMenuKey() function, which takes a +keypress and the current menu visibility, and decides what action to take:

    + +
    +   int HandleMenuKey(int key, int visible) {
    +        if (visible) {
    +            switch (key) {
    +              case KEY_VOLUMEDOWN: return kHighlightDown;
    +              case KEY_VOLUMEUP:   return kHighlightUp;
    +              case KEY_POWER:      return kInvokeItem;
    +            }
    +        }
    +        return kNoAction;
    +    }
    +
    + +

    The method takes a key code (which has previously been processed and +enqueued by the CheckKey() method of the UI object), and the +current state of the menu/text log visibility. The return value is an integer. +If the value is 0 or higher, that is taken as the position of a menu item, +which is invoked immediately (see the InvokeMenuItem() method +below). Otherwise it can be one of the following predefined constants:

    + + + +

    As implied by the the visible argument, HandleMenuKey() is +called even if the menu is not visible. Unlike CheckKey(), it is +not called while recovery is doing something such as wiping data or +installing a package—it's called only when recovery is idle and waiting for +input.

    + +

    Trackball Mechanisms

    +

    If your device has a trackball-like input mechanism (generates input events +with type EV_REL and code REL_Y), recovery synthesizes KEY_UP and KEY_DOWN +keypresses whenever the trackball-like input device reports motion in the Y +axis. All you need to do is map KEY_UP and KEY_DOWN events onto menu actions. +This mapping does not happen for CheckKey(), so you can't +use trackball motions as triggers for rebooting or toggling the display.

    + +

    Modifier Keys

    +

    To check for keys being held down as modifiers, call the IsKeyPressed() + method of your own UI object. For example, on some +devices pressing Alt-W in recovery would start a data wipe whether the menu +was visible or not. YOu could implement like this:

    + +
    +   int HandleMenuKey(int key, int visible) {
    +        if (ui->IsKeyPressed(KEY_LEFTALT) && key == KEY_W) {
    +            return 2;  // position of the "wipe data" item in the menu
    +        }
    +        ...
    +    }
    +
    + +

    Note: If visible is false, it doesn't +make sense to return the special values that manipulate the menu (move +highlight, invoke highlighted item) since the user can't see the highlight. +However, you can return the values if desired.

    + +

    InvokeMenuItem

    +

    Next, provide an InvokeMenuItem() method that maps integer +positions in the array of items returned by GetMenuItems() to +actions. For the array of items in the tardis example, use:

    + +
    +   BuiltinAction InvokeMenuItem(int menu_position) {
    +        switch (menu_position) {
    +          case 0: return REBOOT;
    +          case 1: return APPLY_ADB_SIDELOAD;
    +          case 2: return WIPE_DATA;
    +          case 3: return WIPE_CACHE;
    +          default: return NO_ACTION;
    +        }
    +    }
    +
    + +

    This method can return any member of the BuiltinAction enum to tell the +system to take that action (or the NO_ACTION member if you want the system to +do nothing). This is the place to provide additional recovery functionality +beyond what's in the system: Add an item for it in your menu, execute it here +when that menu item is invoked, and return NO_ACTION so the system does nothing +else.

    +

    BuiltinAction contains the following values:

    + +

    The last method, WipeData(), is optional and is called +whenever a data wipe operation is initiated (either from recovery via the menu +or when the user has chosen to do a factory data reset from the main system). +This method is called before the user data and cache partitions are wiped. If +your device stores user data anywhere other than those two partitions, you +should erase it here. You should return 0 to indicate success and another +value for failure, though currently the return value is ignored. The user data +and cache partitions are wiped whether you return success or failure.

    + +
    +   int WipeData() {
    +       // ... do something tardis-specific here, if needed ....
    +       return 0;
    +    }
    +
    + +

    Make Device

    +

    Finally, include some boilerplate at the end of the recovery_ui.cpp file +for the make_device() function that creates and returns an +instance of your Device class:

    + +
    +class TardisDevice : public Device {
    +   // ... all the above methods ...
    +};
    +
    +Device* make_device() {
    +    return new TardisDevice();
    +}
    +
    + + +

    After completing the recovery_ui.cpp file, built it and link it to recovery +on your device. In Android.mk, create a static library that contains only this +C++ file:

    + +

    device/yoyodyne/tardis/recovery/Android.mk

    + +
    +LOCAL_PATH := $(call my-dir)
    +include $(CLEAR_VARS)
    +
    +LOCAL_MODULE_TAGS := eng
    +LOCAL_C_INCLUDES += bootable/recovery
    +LOCAL_SRC_FILES := recovery_ui.cpp
    +
    +# should match TARGET_RECOVERY_UI_LIB set in BoardConfig.mk
    +LOCAL_MODULE := librecovery_ui_tardis
    +
    +include $(BUILD_STATIC_LIBRARY)
    +
    + +

    Then, in the board configuration for this device, specify your static +library as the value of TARGET_RECOVERY_UI_LIB.

    + +
    +device/yoyodyne/tardis/BoardConfig.mk
    + [...]
    +
    +# device-specific extensions to the recovery UI
    +TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis
    +
    + + +

    Recovery UI images

    +

    The recovery user interface consists images. Ideally, users never interact +with the UI: During a normal update, the phone boots into recovery, fills the +installation progress bar, and boots back into the new system without input +from the user. In the event of a system update problem, the only user action +that can be taken is to call customer care.

    +

    An image-only interface obviates the need for localization. However, as of +Android 5.x the update can display a string of text (e.g. "Installing system +update...") along with the image. For details, see +Localized recovery text.

    + +

    Android 5.x

    +

    The Android 5.x recovery UI uses two main images: the error image +and the installing animation.

    + + + + + + + + +
    +image shown during ota error +

    Figure 1. icon_error.png

    +
    +image shown during ota install +

    Figure 2. icon_installing.png

    +
    + +

    The installing animation is represented as a single PNG image with +different frames of the animation interlaced by row. For example, for a +7-frame animation that is 200x200, create a single 200x1400 image where first +frame is rows 0, 7, 14, 21, ...; the second frame is rows 1, 8, 15, 22, ...; +etc. The combined image includes a text chunk that indicates the number of +animation frames. The tool bootable/recovery/interlace-frames.py +takes a set of input frames and combines them into the necessary composite +image used by recovery.

    + +

    Default images are available in different densities and are located in +bootable/recovery/res-$DENSITY/images (e.g., +bootable/recovery/res-hdpi/images). To use a static image during +installation, you need only provide the icon_installing.png image and set the +number of frames in the animation to 0 (the error icon is not animated; it is +always a static image).

    + + +

    Android 4.x and earlier

    +

    The Android 4.x and earlier recovery UI uses the error image (shown +above) and the installing animation plus several overlay images:

    + + + + + + + + + + + +
    +image shown during ota install +

    Figure 3. icon_installing.png

    +
    +image shown as first
+overlay +

    Figure 4. icon-installing_overlay01.png +

    +
    +image shown as seventh
+overlay +

    Figure 5. icon_installing_overlay07.png +

    +
    + + +

    During installation, the on-screen display is constructed by drawing the +icon_installing.png image, then drawing one of the overlay frames on top of it +at the proper offset. Here, a red box is superimposed to highlight where the +overlay is placed on top of the base image:

    + + + + + + + + +
    composite image of
+install plus first overlay +

    Figure 6. Installing animation frame 1 +(icon_installing.png + icon_installing_overlay01.png) +

    composite image of
+install plus seventh overlay +

    Figure 7. Installing animation frame 7 +(icon_installing.png + icon_installing_overlay07.png) +

    + +

    Subsequent frames are displayed by drawing only the next overlay +image atop what's already there; the base image is not redrawn.

    + +

    The number of frames in the animation, desired speed, and x- and y-offsets +of the overlay relative to the base are set by member variables of the +ScreenRecoveryUI class. When using custom images instead of default images, +override the Init() method in your subclass to change these +values for your custom images (for details, see +ScreenRecoveryUI). The script bootable/recovery/make-overlay.py + can assist in converting a set of image frames to the "base image + +overlay images" form needed by recovery, including computing of the necessary +offsets.

    + +

    Default images are located in bootable/recovery/res/images. To +use a static image during installation, you need only provide the +icon_installing.png image and set the number of frames in the animation to 0 +(the error icon is not animated; it is always a static image).

    + + +

    Localized recovery text

    +

    Android 5.x displays a string of text (e.g., "Installing system update...") +along with the image. When the main system boots into recovery it passes the +user's current locale as a command-line option to recovery. For each message +to display, recovery includes a second composite image with pre-rendered text +strings for that message in each locale.

    + +

    Sample image of recovery text strings:

    + +image of recovery text +

    Figure 8. Localized text for recovery +messages

    + +

    Recovery text can display the following messages:

    + + +

    The Android app in development/tools/recovery_l10/ renders +localizations of a message and creates the composite image. For details on +using this app, refer to the comments in development/tools/recovery_l10n/ +src/com/android/recovery_l10n/Main.java. + +

    When a user boots into recovery manually, the locale might not be available +and no text is displayed. Do not make the text messages critical to the +recovery process.

    + +

    Note: The hidden interface that displays log +messages and allows the user to select actions from the menu is available only +in English.

    + + +

    Progress bars

    +

    Progress bars can appear below the main image (or animation). The progress +bar is made by combining two input images, which must be of the same size:

    + +empty progress bar +

    Figure 9. progress_empty.png

    +full progress bar +

    Figure 10. progress_fill.png

    + +

    The left end of the fill image is displayed next to the right end of +the empty image to make the progress bar. The position of the boundary +between the two images is changed to indicate the progress. For example, with +the above pairs of input images, display:

    + +progress bar at 1% +

    Figure 11. Progress bar at 1%>

    +progress bar at 10% +

    Figure 12. Progress bar at 10%

    +progress bar at 50% +

    Figure 13. Progress bar at 50%

    + +

    You can provide device-specific versions of these images by placing them +into (in this example) device/yoyodyne/tardis/recovery/res/images +. Filenames must match the ones listed above; when a file is found in that +directory, the build system uses it in preference to the corresponding default +image. Only PNGs in RGB or RGBA format with 8-bit color depth are supported. +

    + +

    Note: In Android 5.x, if the locale is known +to recovery and is a right-to-left (RTL) language (Arabic, Hebrew, etc.), the +progress bar fills from right to left.

    + + +

    Devices without screens

    +

    Not all Android devices have screens. If your device is a headless appliance +or has an audio-only interface, you may need to do more extensive customization +of recovery UI. Instead of creating a subclass of ScreenRecoveryUI, subclass its +parent class RecoveryUI directly.

    +

    RecoveryUI has methods for handling a lower-level UI operations such as +"toggle the display," "update the progress bar," "show the menu," "change the +menu selection," etc. You can override these to provide an appropriate +interface for your device. Maybe your device has LEDs where you can use +different colors or patterns of flashing to indicate state, or maybe you can +play audio. (Perhaps you don't want to support a menu or the "text display" +mode at all; you can prevent accessing them with CheckKey() and +HandleMenuKey() implementations that never toggle the display on +or select a menu item. In this case, many of the RecoveryUI methods you need +to provide can just be empty stubs.)

    +

    See bootable/recovery/ui.h for the declaration of RecoveryUI +to see what methods you must support. RecoveryUI is abstract—some methods are +pure virtual and must be provided by subclasses—but it does contain the code +to do processing of key inputs. You can override that too, if your device +doesn't have keys or you want to process them differently.

    + +

    Updater

    +

    You can use device-specific code in the installation of the update package +by providing your own extension functions that can be called from within your +updater script. Here's a sample function for the tardis device:

    + +

    device/yoyodyne/tardis/recovery/recovery_updater.c

    +
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "edify/expr.h"
    +
    + +

    Every extension function has the same signature. The arguments are the name +by which the function was called, a State* cookie, the number of +incoming arguments, and an array of Expr* pointers representing +the arguments. The return value is a newly-allocated Value*.

    + +
    +Value* ReprogramTardisFn(const char* name, State* state, int argc, Expr* argv[]) {
    +    if (argc != 2) {
    +        return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
    +    }
    +
    + +

    Your arguments have not been evaluated at the time your function is +called—your function's logic determines which of them get evaluated and how +many times. Thus, you can use extension functions to implement your own +control structures. Call Evaluate() to evaluate an Expr* + argument, returning a Value*. If Evaluate() +returns NULL, you should free any resources you're holding and immediately +return NULL (this propagates aborts up the edify stack). Otherwise, you take +ownership of the Value returned and are responsible for eventually calling +FreeValue() on it.

    + +

    Suppose the function needs two arguments: a string-valued key and a +blob-valued image. You could read arguments like this:

    + +
    +   Value* key = EvaluateValue(state, argv[0]);
    +    if (key == NULL) {
    +        return NULL;
    +    }
    +    if (key->type != VAL_STRING) {
    +        ErrorAbort(state, "first arg to %s() must be string", name);
    +        FreeValue(key);
    +        return NULL;
    +    }
    +    Value* image = EvaluateValue(state, argv[1]);
    +    if (image == NULL) {
    +        FreeValue(key);    // must always free Value objects
    +        return NULL;
    +    }
    +    if (image->type != VAL_BLOB) {
    +        ErrorAbort(state, "second arg to %s() must be blob", name);
    +        FreeValue(key);
    +        FreeValue(image)
    +        return NULL;
    +    }
    +
    + +

    Checking for NULL and freeing previously evaluated arguments can get tedious +for multiple arguments. The ReadValueArgs() function can make this +easier. Instead of the code above, you could have written this:

    + +
    +   Value* key;
    +    Value* image;
    +    if (ReadValueArgs(state, argv, 2, &key, &image) != 0) {
    +        return NULL;     // ReadValueArgs() will have set the error message
    +    }
    +    if (key->type != VAL_STRING || image->type != VAL_BLOB) {
    +        ErrorAbort(state, "arguments to %s() have wrong type", name);
    +        FreeValue(key);
    +        FreeValue(image)
    +        return NULL;
    +    }
    +
    + +

    ReadValueArgs() doesn't do type-checking, so you must do that +here; it's more convenient to do it with one if statement at +the cost of producing a somewhat less specific error message when it fails. +But ReadValueArgs() does handle evaluating each argument and +freeing all the previously-evaluated arguments (as well as setting a useful +error message) if any of the evaluations fail. You can use a +ReadValueVarArgs() convenience function for evaluating a variable +number of arguments (it returns an array of Value*).

    + +

    After evaluating the arguments, do the work of the function:

    + +
    +   // key->data is a NUL-terminated string
    +    // image->data and image->size define a block of binary data
    +    //
    +    // ... some device-specific magic here to
    +    // reprogram the tardis using those two values ...
    +
    + +

    The return value must be a Value* object; ownership of this +object will pass to the caller. The caller takes ownership of any data pointed +to by this Value*—specifically the datamember.

    +

    In this instance, you want to return a true or false value to indicate +success. Remember the convention that the empty string is false and all +other strings are true. You must malloc a Value object with a malloc'd +copy of the constant string to return, since the caller will free() + both. Don't forget to call FreeValue() on the objects you +got by evaluating your arguments!

    + +
    +   FreeValue(key);
    +    FreeValue(image);
    +
    +    Value* result = malloc(sizeof(Value));
    +    result->type = VAL_STRING;
    +    result->data = strdup(successful ? "t" : "");
    +    result->size = strlen(result->data);
    +    return result;
    +}
    +
    + +

    The convenience function StringValue() wraps a string into a +new Value object. Use to write the above code more succinctly:

    + +
    +   FreeValue(key);
    +    FreeValue(image);
    +
    +    return StringValue(strdup(successful ? "t" : ""));
    +}
    +
    + +

    To hook functions into the edify interpreter, provide the function +Register_foo where foo is the name of the +static library containing this code. Call RegisterFunction() to +register each extension function. By convention, name device-specific +functions device.whatever to avoid conflicts with +future built-in functions added.

    + +
    +void Register_librecovery_updater_tardis() {
    +    RegisterFunction("tardis.reprogram", ReprogramTardisFn);
    +}
    +
    + +

    You can now configure the makefile to build a static library with your +code. (This is the same makefile used to customize the recovery UI in the +previous section; your device may have both static libraries defined here.)

    + +

    device/yoyodyne/tardis/recovery/Android.mk

    + +
    +include $(CLEAR_VARS)
    +LOCAL_SRC_FILES := recovery_updater.c
    +LOCAL_C_INCLUDES += bootable/recovery
    +
    + +

    The name of the static library must match the name of the +Register_libname function contained within it.

    + +
    +LOCAL_MODULE := librecovery_updater_tardis
    +include $(BUILD_STATIC_LIBRARY)
    +
    + +

    Finally, configure the build of recovery to pull in your library. Add your +library to TARGET_RECOVERY_UPDATER_LIBS (which may contain multiple libraries; +they all get registered). If your code depends on other static libraries that +are not themselves edify extensions (i.e., they don't have a +Register_libname function), you can list those in +TARGET_RECOVERY_UPDATER_EXTRA_LIBS to link them to updater without calling +their (non-existent) registration function. For example, if your +device-specific code wanted to use zlib to decompress data, you would include +libz here.

    + +

    device/yoyodyne/tardis/BoardConfig.mk

    + +
    + [...]
    +
    +# add device-specific extensions to the updater binary
    +TARGET_RECOVERY_UPDATER_LIBS += librecovery_updater_tardis
    +TARGET_RECOVERY_UPDATER_EXTRA_LIBS +=
    +
    + +

    The updater scripts in your OTA package can now call your function as any +other. To reprogram your tardis device, the update script might contain: +tardis.reprogram("the-key", package_extract_file("tardis-image.dat")) +. This uses the single-argument version of the built-in function +package_extract_file(), which returns the contents of a file extracted +from the update package as a blob to produce the second argument to the new +extension function.

    + +

    OTA package generation

    +

    The final component is getting the OTA package generation tools to know +about your device-specific data and emit updater scripts that include calls to +your extension functions.

    +

    First, get the build system to know about a device-specific blob of data. +Assuming your data file is in device/yoyodyne/tardis/tardis.dat, +declare the following in your device's AndroidBoard.mk:

    + +

    device/yoyodyne/tardis/AndroidBoard.mk

    +
    +  [...]
    +
    +$(call add-radio-file,tardis.dat)
    +
    + +

    You could also put it in an Android.mk instead, but then it must to be +guarded by a device check, since all the Android.mk files in the tree are +loaded no matter what device is being built. (If your tree includes multiple +devices, you only want the tardis.dat file added when building the tardis +device.)

    + +

    device/yoyodyne/tardis/Android.mk

    +
    +  [...]
    +
    +# an alternative to specifying it in AndroidBoard.mk
    +ifeq (($TARGET_DEVICE),tardis)
    +  $(call add-radio-file,tardis.dat)
    +endif
    +
    + +

    These are called radio files for historical reasons; they may have nothing +to do with the device radio (if present). They are simply opaque blobs of data +the build system copies into the target-files .zip used by the OTA generation +tools. When you do a build, tardis.dat is stored in the target-files.zip as +RADIO/tardis.dat. You can call add-radio-file +multiple times to add as many files as you want.

    + +

    Python module

    +

    To extend the release tools, write a Python module (must be named +releasetools.py) the tools can call into if present. Example:

    + +

    device/yoyodyne/tardis/releasetools.py

    +
    +import common
    +
    +def FullOTA_InstallEnd(info):
    +  # copy the data into the package.
    +  tardis_dat = info.input_zip.read("RADIO/tardis.dat")
    +  common.ZipWriteStr(info.output_zip, "tardis.dat", tardis_dat)
    +
    +  # emit the script code to install this data on the device
    +  info.script.AppendExtra(
    +      """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
    +
    + +

    A separate function handles the case of generating an incremental OTA +package. For this example, suppose you need to reprogram the tardis only when +the tardis.dat file has changed between two builds.

    +
    +def IncrementalOTA_InstallEnd(info):
    +  # copy the data into the package.
    +  source_tardis_dat = info.source_zip.read("RADIO/tardis.dat")
    +  target_tardis_dat = info.target_zip.read("RADIO/tardis.dat")
    +
    +  if source_tardis_dat == target_tardis_dat:
    +      # tardis.dat is unchanged from previous build; no
    +      # need to reprogram it
    +      return
    +
    +  # include the new tardis.dat in the OTA package
    +  common.ZipWriteStr(info.output_zip, "tardis.dat", target_tardis_dat)
    +
    +  # emit the script code to install this data on the device
    +  info.script.AppendExtra(
    +      """tardis.reprogram("the-key", package_extract_file("tardis.dat"));""")
    +
    + +

    Module functions

    +

    You can provide the following functions in the module (implement only the +ones you need).

    +
    +
    FullOTA_Assertions()
    +
    Called near the start of generating a full OTA. This is a good place to +emit assertions about the current state of the device. Do not emit script +commands that make changes to the device.
    +
    FullOTA_InstallBegin()
    +
    Called after all the assertions about the device state have passed but +before any changes have been made. You can emit commands for device-specific +updates that must run before anything else on the device has been changed.
    +
    FullOTA_InstallEnd()
    +
    Called at the end of the script generation, after the script commands to +update the boot and system partitions have been emitted. You can also emit +additional commands for device-specific updates.
    +
    IncrementalOTA_Assertions()
    +
    Similar to FullOTA_Assertions() but called when generating an +incremental update package.
    +
    IncrementalOTA_VerifyBegin()
    +
    Called after all assertions about the device state have passed but before +any changes have been made. You can emit commands for device-specific updates +that must run before anything else on the device has been changed.
    +
    IncrementalOTA_VerifyEnd()
    +
    Called at the end of the verification phase, when the script has finished +confirming the files it is going to touch have the expected starting contents. +At this point nothing on the device has been changed. You can also emit code for +additional device-specific verifications.
    +
    IncrementalOTA_InstallBegin()
    +
    Called after files to be patched have been verified as having the expected +before state but before any changes have been made. You can emit +commands for device-specific updates that must run before anything else on the +device has been changed.
    +
    IncrementalOTA_InstallEnd()
    +
    Similar to its full OTA package counterpart, this is called at the end of +the script generation, after the script commands to update the boot and system +partitions have been emitted. You can also emit additional commands for +device-specific updates.
    +
    + +

    Note: If the device loses power, OTA +installation may restart from the beginning. Be prepared to cope with devices +on which these commands have already been run, fully or partially.

    + +

    Pass functions to info objects

    +

    Pass functions to a single info object that contains various useful items: +

    + + +

    For details on the info object, refer to the +Python Software Foundation +documentation for ZIP archives.

    + +

    Specify module location

    +

    Specify the location of your device's releasetools.py script in your +BoardConfig.mk file:

    + +

    device/yoyodyne/tardis/BoardConfig.mk

    + +
    + [...]
    +
    +TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis
    +
    + +

    If TARGET_RELEASETOOLS_EXTENSIONS is not set, it defaults to the +$(TARGET_DEVICE_DIR)/../common directory (device/yoyodyne/common + in this example). It's best to explicitly define the location of the +releasetools.py script. When building the tardis device, the releasetools.py +script is included in the target-files .zip file (META/releasetools.py +).

    +

    When you run the release tools (either img_from_target_files +or ota_from_target_files), the releasetools.py script in the +target-files .zip, if present, is preferred over the one from the Android +source tree. You can also explicitly specify the path to the device-specific +extensions with the -s (or --device_specific) +option, which takes the top priority. This enables you to correct errors and +make changes in the releasetools extensions and apply those changes to old +target-files.

    +

    Now, when you run ota_from_target_files, it automatically +picks up the device-specific module from the target_files .zip file and uses +it when generating OTA packages:

    + +
    +% ./build/tools/releasetools/ota_from_target_files \
    +    -i PREVIOUS-tardis-target_files.zip \
    +    dist_output/tardis-target_files.zip incremental_ota_update.zip
    +unzipping target target-files...
    +using device-specific extensions from target_files
    +unzipping source target-files...
    +   [...]
    +done.
    +
    + +

    Alternatively, you can specify device-specific extensions when you run +ota_from_target_files.

    + +
    +% ./build/tools/releasetools/ota_from_target_files \
    +    -s device/yoyodyne/tardis \  # specify the path to device-specific extensions
    +    -i PREVIOUS-tardis-target_files.zip \
    +    dist_output/tardis-target_files.zip incremental_ota_update.zip
    +unzipping target target-files...
    +loaded device-specific extensions from device/yoyodyne/tardis
    +unzipping source target-files...
    +   [...]
    +done.
    +
    + +

    Note: For a complete list of options, refer +to the ota_from_target_files comments in +build/tools/releasetools/ota_from_target_files.

    + + +

    Sideloading

    +

    Recovery has a sideloading mechanism for manually installing an +update package without downloading it over-the-air by the main system. +Sideloading is useful for debugging or making changes on devices where the +main system can't be booted.

    +

    Historically, sideloading has been done through loading packages off the +device's SD card; in the case of a non-booting device, the package can be put +onto the SD card using some other computer and then the SD card inserted into +the device. To accommodate Android devices without removable external storage, +recovery supports two additional mechanisms for sideloading: loading packages +from the cache partition, and loading them over USB using adb.

    +

    To invoke each sideload mechanism, your device's +Device::InvokeMenuItem() method can return the following values of +BuiltinAction:

    + + + +

    A few caveats:

    + \ No newline at end of file diff --git a/src/devices/tech/ota/index.jd b/src/devices/tech/ota/index.jd new file mode 100755 index 00000000..a65418c5 --- /dev/null +++ b/src/devices/tech/ota/index.jd @@ -0,0 +1,160 @@ +page.title=OTA Updates +@jd:body + + + +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    Android devices in the field can receive and install over-the-air (OTA) +updates to the system and application software. Devices have a special +recovery partition with the software needed to unpack a downloaded update +package and apply it to the rest of the system.

    +

    This section describes the structure of these packages and the tools +provided to build them. It is intended for developers who want to +make the OTA update system work on new Android devices and those who are +building update packages for use with released devices. OTA updates are +designed to upgrade the underlying operating system and the read-only apps +installed on the system partition; these updates do not affect +applications installed by the user from Google Play. +

    +

    This section describes the OTA system as of the Android 5.x release. For +help porting OTA-related code from older releases, see +Migrating from previous releases. +

    + +

    Android device layout

    +

    The flash space on an Android device typically contains the following +partitions.

    + +
    +
    boot
    +
    Contains the Linux kernel and a minimal root filesystem (loaded into a RAM +disk). It mounts system and other partitions and starts the runtime located on +the system partition.
    +
    system
    +
    Contains system applications and libraries that have source code available +on Android Open Source Project (AOSP). During normal operation, this partition +is mounted read-only; its contents change only during an OTA update.
    +
    vendor
    +
    Contains system applications and libraries that do not have +source code available on Android Open Source Project (AOSP). During normal +operation, this partition is mounted read-only; its contents change only +during an OTA update.
    +
    userdata
    +
    Stores the data saved by applications installed by the user, etc. This +partition is not normally touched by the OTA update process.
    +
    cache
    +
    Temporary holding area used by a few applications (accessing this +partition requires special app permissions) and for storage of downloaded OTA +update packages. Other programs use this space with the expectation that files +can disappear at any time. Some OTA package installations may result in this +partition being wiped completely.
    +
    recovery
    +
    Contains a second complete Linux system, including a kernel and the +special recovery binary that reads a package and uses its contents to update +the other partitions.
    +
    misc
    +
    Tiny partition used by recovery to stash some information away about what +it's doing in case the device is restarted while the OTA package is being +applied.
    + +

    Life of an OTA update

    +

    A typical OTA update contains the following steps:

    +
      +
    1. Device performs regular check in with OTA servers and is notified of the +availability of an update, including the URL of the update package and a +description string to show the user.
    2. +
    3. Update downloads to a cache or data partition, and its cryptographic +signature is verified against the certificates in +/system/etc/security/otacerts.zip. User is prompted to install the +update.
    4. +
    5. Device reboots into recovery mode, in which the kernel and system in the +recovery partition are booted instead of the kernel in the boot partition.
    6. +
    7. Recovery binary is started by init. It finds command-line arguments in +/cache/recovery/command that point it to the downloaded package. +
    8. +
    9. Recovery verifies the cryptographic signature of the package against the +public keys in /res/keys (part of the RAM disk contained in the +recovery partition).
    10. +
    11. Data is pulled from the package and used to update the boot, system, +and/or vendor partitions as necessary. One of the new files left on the system +partition contains the contents of the new recovery partition.
    12. +
    13. Device reboots normally.
        +
      1. The newly updated boot partition is loaded, and it mounts and starts +executing binaries in the newly updated system partition.
      2. +
      3. As part of normal startup, the system checks the contents of the recovery +partition against the desired contents (which were previously stored as a file +in /system). They are different, so the recovery partition is +reflashed with the desired contents. (On subsequent boots, the recovery +partition already contains the new contents, so no reflash is necessary.)
      4. +
    14. +
    +

    The system update is complete!

    + +

    Migrating from Previous Releases

    + +

    When migrating from Android 2.3/3.0/4.0 release, the major change is the +conversion of all the device-specific functionality from a set of C functions +with predefined names to C++ objects. The following table lists the old +functions and the new methods that serve a roughly equivalent purpose:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    C functionC++ method
    device_recovery_start()Device::RecoveryStart()
    device_toggle_display()
    +device_reboot_now()
    +
    RecoveryUI::CheckKey()
    +(also RecoveryUI::IsKeyPressed())
    +
    device_handle_key()Device::HandleMenuKey()
    device_perform_action()Device::InvokeMenuItem()
    device_wipe_data()Device::WipeData()
    device_ui_init()ScreenRecoveryUI::Init()
    + +

    Conversion of old functions to new methods should be reasonably +straightforward. Don't forget to add the new make_device() +function to create and return an instance of your new Device subclass.

    \ No newline at end of file diff --git a/src/devices/tech/ota/inside_packages.jd b/src/devices/tech/ota/inside_packages.jd new file mode 100755 index 00000000..41b3d5ca --- /dev/null +++ b/src/devices/tech/ota/inside_packages.jd @@ -0,0 +1,288 @@ +page.title=Inside OTA Packages +@jd:body + + + +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    The system builds the updater binary from bootable/recovery/updater + and uses it in an OTA package.

    The package itself is a .zip file +(ota_update.zip, incremental_ota_update.zip) that +contains the executable binary META-INF/com/google/android/update-binary +. + +

    Updater contains several builtin functions and an interpreter for an +extensible scripting language (edify) that supports commands for typical +update-related tasks. Updater looks in the package .zip file for a script in the +file META-INF/com/google/android/updater-script.

    + +

    Note: Using the edify script and/or builtin +functions is not a common activity, but can be helpful if you need to debug the +update file.

    + +

    Edify syntax

    +

    An edify script is a single expression in which all values are strings. +Empty strings are false in a Boolean context and all other strings are +true. Edify supports the following operators (with the usual meanings): +

    + +
    +(expr )
    + expr + expr  # string concatenation, not integer addition
    + expr == expr
    + expr != expr
    + expr && expr
    + expr || expr
    + ! expr
    + if expr then expr endif
    + if expr then expr else expr endif
    + function_name(expr, expr,...)
    + expr; expr
    +
    + +

    Any string of the characters a-z, A-Z, 0-9, _, :, /, . that isn't a +reserved word is considered a string literal. (Reserved words are if else + then endif.) String literals may also appear in double-quotes; +this is how to create values with whitespace and other characters not in the +above set. \n, \t, \", and \\ serve as escapes within quoted strings, as does +\x##.

    +

    The && and || operators are short-circuiting; the right side is not +evaluated if the logical result is determined by the left side. The +following are equivalent:

    +
    +e1 && e2
    +if e1 then e2 endif
    +

    The ; operator is a sequence point; it means to evaluate first the left +side and then the right side. Its value is the value of the right-side +expression. A semicolon can also appear after an expression, so the effect +simulates C-style statements:

    + +
    +prepare();
    +do_other_thing("argument");
    +finish_up();
    +
    + +

    Built-in functions

    +

    Most update functionality is contained in the functions available for +execution by scripts. (Strictly speaking these are macros rather than +functions in the Lisp sense, since they need not evaluate all of their +arguments.) Unless otherwise noted, functions return true on success +and false on error. If you want errors to abort execution of the +script, use the abort() and/or assert() functions. +The set of functions available in updater can also be extended to provide +device-specific +functionality. + +

    +
    abort([msg])
    +
    Aborts execution of the script immediately, with the optional msg. +If the user has turned on text display, msg appears in the recovery log +and on-screen.
    +
    assert(expr[, expr, ...])
    +
    Evaluates each expr in turn. If any is false, immediately aborts +execution with the message "assert failed" and the source text of the failed +expression.
    +
    apply_patch(src_file, tgt_file, tgt_sha1, +tgt_size, patch1_sha1, patch1_blob, [...])
    +
    Applies a binary patch to the src_file to produce the tgt_file +. If the desired target is the same as the source, pass "-" for tgt_file +. tgt_sha1 and tgt_size are the expected final SHA1 hash and +size of the target file. The remaining arguments must come in pairs: a SHA1 +hash (a 40-character hex string) and a blob. The blob is the patch to be +applied whe the source file's current contents have the given SHA1. +

    The patching is done in a safe manner that guarantees the target file +either has the desired SHA1 hash and size, or it is untouched—it will not be +left in an unrecoverable intermediate state. If the process is interrupted +during patching, the target file may be in an intermediate state; a copy exists +in the cache partition so restarting the update can successfully update the +file.

    +

    Special syntax is supported to treat the contents of Memory Technology +Device (MTD) partitions as files, allowing patching of raw partitions such as +boot. To read an MTD partition, you must know how much data you want to read +since the partition does not have an end-of-file notion. You can use the +string "MTD:partition:size_1:sha1_1:size_2: +sha1_2" as a filename to read the given partition. You must specify at +least one (size, sha-1) pair; you can specify more than one if there +are multiple possibilities for what you expect to read.

    +
    apply_patch_check(filename, sha1[, sha1, ...]) +
    +
    Returns true if the contents of filename or the temporary copy in +the cache partition (if present) have a SHA1 checksum equal to one of the +given sha1 values. sha1 values are specified as 40 hex digits. +This function differs from sha1_check(read_file(filename), +sha1 [, ...]) in that it knows to check the cache partition copy, +so apply_patch_check() will succeed even if the file was corrupted +by an interrupted apply_patch() update.
    +
    apply_patch_space(bytes)
    +
    Returns true if at least bytes of scratch space is available for +applying binary patches.
    +
    concat(expr[, expr, ...])
    +
    Evaluates each expression and concatenates them. The + operator is +syntactic sugar for this function in the special case of two arguments (but +the function form can take any number of expressions). The expressions must be +strings; it can't concatenate blobs.
    +
    delete([filename, ...])
    +
    Deletes all the filenames listed. Returns the number of files +successfully deleted.
    +
    delete_recursive([dirname, ...])
    +
    Recursively deletes dirnames and all their contents. Returns the +number of directories successfully deleted.
    +
    file_getprop(filename, key)
    +
    Reads the given filename, interprets it as a properties file (e.g. +/system/build.prop), and returns the value of the given key +, or the empty string if key is not present.
    +
    format(fs_type, partition_type, location, +fs_size, mount_point)
    +
    Reformats a given partition. Supported partition types: +
      +
    • fs_type="yaffs2" and partition_type="MTD". Location must be the name of +the MTD partition; an empty yaffs2 filesystem is constructed there. Remaining +arguments are unused.
    • +
    • fs_type="ext4" and partition_type="EMMC". Location must be the device file +for the partition. An empty ext4 filesystem is constructed there. If +fs_size is zero, the filesystem takes up the entire partition. If +fs_size is a positive number, the filesystem takes the first +fs_size bytes of the partition. If fs_size is a +negative number, the filesystem takes all except the last |fs_size| +bytes of the partition.
    • +
    • fs_type="f2fs" and partition_type="EMMC". Location must be the device file +for the partition. fs_size must be a non-negative number. If +fs_size is zero, the filesystem takes up the entire partition. If +fs_size is a positive number, the filesystem takes the first +fs_size bytes of the partition.
    • +
    • mount_point should be the future mount point for the filesystem.
    +
    +
    getprop(key)
    +
    Returns the value of system property key (or the empty string, if +it's not defined). The system property values defined by the recovery +partition are not necessarily the same as those of the main system. This +function returns the value in recovery.
    +
    greater_than_int(a, b)
    +
    Returns true if and only if (iff) a (interpreted as an integer) is +greater than b (interpreted as an integer).
    +
    ifelse(cond, e1[, e2])
    +
    Evaluates cond, and if it is true evaluates and returns the value +of e1, otherwise it evaluates and returns e2 (if present). The +"if ... else ... then ... endif" construct is just syntactic sugar for this +function.
    +
    is_mounted(mount_point)
    +
    Returns true iff there is a filesystem mounted at mount_point.
    +
    is_substring(needle, haystack)
    +
    Returns true iff needle is a substring of haystack.
    +
    less_than_int(a, b)
    +
    Returns true iff a (interpreted as an integer) is less than b +(interpreted as an integer).
    +
    mount(fs_type, partition_type, name, +mount_point)
    +
    Mounts a filesystem of fs_type at mount_point. +partition_type must be one of: +
      +
    • MTD. Name is the name of an MTD partition (e.g., system, userdata; +see /proc/mtd on the device for a complete list).
    • +
    • EMMC.
    • +
    +

    Recovery does not mount any filesystems by default (except the SD card if +the user is doing a manual install of a package from the SD card); your script +must mount any partitions it needs to modify.

    +
    package_extract_dir(package_dir, dest_dir)
    +
    Extracts all files from the package underneath package_dir and +writes them to the corresponding tree beneath dest_dir. Any existing +files are overwritten.
    +
    package_extract_file(package_file[, dest_file]) +
    +
    Extracts a single package_file from the update package and writes +it to dest_file, overwriting existing files if necessary. Without the +dest_file argument, returns the contents of the package file as a +binary blob.
    +
    read_file(filename)
    +
    Reads filename and returns its contents as a binary blob.
    +
    rename(src_filename, tgt_filename)
    +
    Renames src_filename to tgt_filename. It automatically creates +the necessary directories for the tgt_filename. Example: +rename("system/app/Hangouts/Hangouts.apk", +"system/priv-app/Hangouts/Hangouts.apk").
    +
    run_program(path[, arg, ...])
    +
    Executes the binary at path, passing args. Returns the +program's exit status.
    +
    set_metadata(filename, key1, value1[, key2 +, value2, ...])
    +
    Sets the keys of the given filename to values. For example: +set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, +"selabel", "u:object_r:system_file:s0", "capabilities", 0x0).
    +
    set_metadata_recursive(dirname, key1, value1[, +key2, value2, ...])
    +
    Recursively sets the keys of the given dirname and all its children +to values. For example: set_metadata_recursive("/system", "uid", +0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", +"u:object_r:system_file:s0", "capabilities", 0x0).
    +
    set_progress(frac)
    +
    Sets the position of the progress meter within the chunk defined by the +most recent show_progress() call. frac must be in the +range [0.0, 1.0]. The progress meter never moves backwards; attempts to make +it do so are ignored.
    +
    sha1_check(blob[, sha1])
    +
    The blob argument is a blob of the type returned by +read_file() or the one-argument form of package_extract_file() +. With no sha1 arguments, this function returns the SHA1 hash of +the blob (as a 40-digit hex string). With one or more sha1 arguments, +this function returns the SHA1 hash if it equals one of the arguments, or the +empty string if it does not equal any of them.
    +
    show_progress(frac, secs)
    +
    Advances the progress meter over the next frac of its length over +the secs seconds (must be an integer). secs may be 0, in which +case the meter is not advanced automatically but by use of the +set_progress() function defined above.
    +
    sleep(secs)
    +
    Sleeps for secs seconds (must be an integer).
    +
    stdout(expr[, expr, ...])
    +
    Evaluates each expression and dumps its value to stdout. Useful for +debugging.
    +
    symlink(target[, source, ...])
    +
    Creates all sources as symlinks to target.
    +
    tune2fs(device[, arg, …])
    +
    Adjusts tunable parameters args on device.
    +
    ui_print([text, ...])
    +
    Concatenates all text arguments and prints the result to the UI +(where it will be visible if the user has turned on the text display).
    +
    unmount(mount_point)
    +
    Unmounts the filesystem mounted at mount_point.
    +
    wipe_block_device(block_dev, len)
    +
    Wipes the len bytes of the given block device block_dev.
    +
    wipe_cache()
    +
    Causes the cache partition to be wiped at the end of a successful +installation.
    +
    write_raw_image(filename_or_blob, partition) +
    +
    Writes the image in filename_or_blob to the MTD partition. +filename_or_blob can be a string naming a local file or a blob-valued +argument containing the data to write. To copy a file from the OTA package to +a partition, use: +write_raw_image(package_extract_file("zip_filename"), "partition_name"); + +
    +
    + +

    Note: Prior to Android 4.1, only filenames +were accepted, so to accomplish this the data first had to be unzipped into a +temporary local file.

    \ No newline at end of file diff --git a/src/devices/tech/ota/sign_builds.jd b/src/devices/tech/ota/sign_builds.jd new file mode 100755 index 00000000..e9869205 --- /dev/null +++ b/src/devices/tech/ota/sign_builds.jd @@ -0,0 +1,269 @@ +page.title=Signing Builds for Release +@jd:body + + + +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    Android uses cryptographic signatures in two places:

    +
      +
    1. Each .apk file must be signed. Android's Package Manager uses an .apk +signature in two ways:
        +
      • When an application is replaced, it must be signed by the same key as the +old application in order to get access to the old application's data.
      • +
      • If two or more applications want to share a user ID (so they can share +data, etc.), they must be signed with the same key.
    2. +
    3. OTA update packages must be signed with one of the keys expected by the +system or the installation process will reject them.
    4. +
    +

    Certificates and keys

    +

    Each key comes in two files: the certificate, which has the +extension .x509.pem, and the private key, which has the extension .pk8. +The private key should be kept secret and is needed to sign a package. The key +may itself be protected by a password—a reasonable strategy is to store your +keys in source control along with the code—but keep them protected by a +password known only to the people who make final releases. The certificate, in +contrast, contains only the public half of the key, so it can be distributed +widely. It is used to verify a package has been signed by the corresponding +private key.

    +

    The standard Android build uses four keys, all of which reside in +build/target/product/security:

    + +
    +
    testkey
    +
    Generic default key for packages that do not otherwise specify a key.
    +
    platform
    +
    Test key for packages that are part of the core platform.
    +
    shared
    +
    Test key for things that are shared in the home/contacts process.
    +
    media
    +
    Test key for packages that are part of the media/download system.
    + +

    Individual packages specify one of these keys by setting LOCAL_CERTIFICATE +in their Android.mk file. (testkey is used if this variable is not set.) You +can also specify an entirely different key by pathname, e.g.:

    + +

    device/yoyodyne/apps/SpecialApp/Android.mk

    +
    + [...]
    +
    +LOCAL_CERTIFICATE := device/yoyodyne/security/special
    +
    + +

    Now the build uses the device/yoyodyne/security/special.{x509.pem,pk8} + key to sign SpecialApp.apk. The build can use only private keys that +are not password protected.

    + +

    Generating keys

    +

    Android uses 2048-bit RSA keys with public exponent 3. You can generate +certificate/private key pairs using the openssl tool from +openssl.org:

    + +
    +# generate RSA key
    +% openssl genrsa -3 -out temp.pem 2048
    +Generating RSA private key, 2048 bit long modulus
    +....+++
    +.....................+++
    +e is 3 (0x3)
    +
    +# create a certificate with the public part of the key
    +% openssl req -new -x509 -key temp.pem -out releasekey.x509.pem \
    +  -days 10000 \
    +  -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'
    +
    +# create a PKCS#8-formatted version of the private key
    +% openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt
    +
    +# securely delete the temp.pem file
    +% shred --remove temp.pem
    +
    + +

    The openssl pkcs8 command given above creates a .pk8 file with no +password, suitable for use with the build system. To create a .pk8 secured +with a password (which you should do for all actual release keys), replace the +-nocrypt argument with -passout stdin; then openssl +will encrypt the private key with a password read from standard input. No +prompt is printed, so if stdin is the terminal the program will appear to hang +when it's really just waiting for you to enter a password. Other values can be +used for the-passout argument to read the password from other locations; for +details, see the + +openssl documentation.

    +

    The temp.pem intermediate file contains the private key without any kind of +password protection, so dispose of it thoughtfully when generating release +keys. In particular, the GNUshred utility may not be effective on network or +journaled filesystems. You can use a working directory located in a RAM disk +(such as a tmpfs partition) when generating keys to ensure the intermediates +are not inadvertently exposed.

    + +

    Signing apps for release

    +

    The first step in preparing a build for release is to sign all the .apk +files in it, replacing the test keys used by the build system. This is done +with the sign_target_files_apks script. It takes a target-files +.zip as input and produces a new target-files .zip in which all the .apks have +been signed with new keys.

    +

    When you run this script, you must specify on the command line a +replacement key for each key used in the build. The -k src_key= +dest_key flag specifies key replacements one at a time. The flag +-d dir lets you specify a directory with four keys to +replace all those in build/target/product/security; it is +equivalent to using -k four times to specify the mappings:

    + +
    +build/target/product/security/testkey  = dir/releasekey
    +build/target/product/security/platform = dir/platform
    +build/target/product/security/shared   = dir/shared
    +build/target/product/security/media    = dir/media
    +
    + +

    For the hypothetical tardis product, you need five password-protected keys: +four to replace the four in build/target/product/security, and +one to replace the additional keydevice/yoyodyne/security/special +required by SpecialApp in the example above. If the keys were in the following +files:

    + +
    +vendor/yoyodyne/security/tardis/releasekey.x509.pem
    +vendor/yoyodyne/security/tardis/releasekey.pk8
    +vendor/yoyodyne/security/tardis/platform.x509.pem
    +vendor/yoyodyne/security/tardis/platform.pk8
    +vendor/yoyodyne/security/tardis/shared.x509.pem
    +vendor/yoyodyne/security/tardis/shared.pk8
    +vendor/yoyodyne/security/tardis/media.x509.pem
    +vendor/yoyodyne/security/tardis/media.pk8
    +vendor/yoyodyne/security/special.x509.pem
    +vendor/yoyodyne/security/special.pk8           # NOT password protected
    +vendor/yoyodyne/security/special-release.x509.pem
    +vendor/yoyodyne/security/special-release.pk8   # password protected
    +
    + +

    Then you would sign all the apps like this:

    + +
    +% ./build/tools/releasetools/sign_target_files_apks \
    +    -d vendor/yoyodyne/security/tardis \
    +    -k vendor/yoyodyne/special=vendor/yoyodyne/special-release \
    +    -o \    # explained in the next section
    +    tardis-target_files.zip signed-tardis-target_files.zip
    +Enter password for vendor/yoyodyne/security/special-release key>
    +Enter password for vendor/yoyodyne/security/tardis/media key>
    +Enter password for vendor/yoyodyne/security/tardis/platform key>
    +Enter password for vendor/yoyodyne/security/tardis/releasekey key>
    +Enter password for vendor/yoyodyne/security/tardis/shared key>
    +    signing: Phone.apk (vendor/yoyodyne/security/tardis/platform)
    +    signing: Camera.apk (vendor/yoyodyne/security/tardis/media)
    +    signing: Special.apk (vendor/yoyodyne/security/special-release)
    +    signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey)
    +        [...]
    +    signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared)
    +    signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared)
    +rewriting SYSTEM/build.prop:
    +  replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
    +     with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
    +  replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
    +     with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
    +    signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform)
    +rewriting RECOVERY/RAMDISK/default.prop:
    +  replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
    +     with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
    +  replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
    +     with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
    +using:
    +    vendor/yoyodyne/security/tardis/releasekey.x509.pem
    +for OTA package verification
    +done.
    +
    + +

    After prompting the user for passwords for all password-protected keys, the +script re-signs all the .apk files in the input target .zip with the release +keys. Before running the command, you can also set the ANDROID_PW_FILE +environment variable to a temporary filename; the script then invokes your +editor to allow you to enter passwords for all keys (this may be a more +convenient way to enter passwords).

    +

    sign_target_files_apks also rewrites the build description and +fingerprint in the build properties files to reflect the fact that this is a +signed build. The -t flag can control what edits are made to the +fingerprint. Run the script with -h to see documentation on all +flags.

    + +

    Signing OTA packages

    +

    You need the following components to sign OTA packages:

    +
      +
    1. Certificates of the keys you want this build to accept.
    2. +
    3. Sign the newly-created package with the private key (must correspond to +the certificate embedded in the current build of any device to which you want +to send this package).
    4. +
    +

    To achieve these components:

    + + +

    Signatures and sideloading

    +

    Sideloading does not bypass recovery's normal package signature +verification mechanism—before installing a package, recovery will verify that +it is signed with one of the private keys matching the public keys stored in +the recovery partition, just as it would for a package delivered over-the-air. +

    +

    Update packages received from the main system are typically verified twice: +once by the main system, using the RecoverySystem. +verifyPackage() method in the android API, and then again by +recovery. The RecoverySystem API checks the signature against public keys +stored in the main system, in the file /system/etc/security/otacerts.zip + (by default). Recovery checks the signature against public keys stored +in the recovery partition RAM disk, in the file /res/keys.

    +

    Normally these two locations store the same set of keys. By adding a key to +just the recovery set of keys, it's possible to sign packages that can +be installed only via sideloading (assuming the main system's update download +mechanism is correctly doing verification against otacerts.zip). You can +specify extra keys to be included only in recovery by setting the +PRODUCT_EXTRA_RECOVERY_KEYS variable in your product definition:

    + +

    vendor/yoyodyne/tardis/products/tardis.mk

    +
    + [...]
    +
    +PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
    +
    + +

    This includes the public key vendor/yoyodyne/security/tardis/sideload. +x509.pem in the recovery keys file so it can install packages signed +with it. The extra key is not included in otacerts.zip though, so +systems that correctly verify downloaded packages do not invoke recovery for +packages signed with this key.

    \ No newline at end of file diff --git a/src/devices/tech/ota/tools.jd b/src/devices/tech/ota/tools.jd new file mode 100755 index 00000000..1226379e --- /dev/null +++ b/src/devices/tech/ota/tools.jd @@ -0,0 +1,133 @@ +page.title=OTA Package Tools +@jd:body + + + +
    +
    +

    In this document

    +
      +
    +
    +
    + +

    The ota_from_target_files tool provided in +build/tools/releasetools can build two types of package: full + and incremental. The tool takes the target-files .zip file +produced by the Android build system as input.

    + +

    Full updates

    +

    A full update is one where the entire final state of the device +(system, boot, and recovery partitions) is contained in the package. As long +as the device is capable of receiving the package and booting the recovery +system, the package can install the desired build regardless of the current +state of the device.

    +

    Example: Using the release tools to build a full update for the +hypothetical tardis device:

    + +
    +# first, build the target-files .zip
    +% . build/envsetup.sh && lunch tardis-eng
    +% mkdir dist_output
    +% make dist DIST_DIR=dist_output
    +  [...]
    +% ls -l dist_output/*target_files*
    +-rw-r----- 1 user eng  69965275 Sep 29 15:51 tardis-target_files.zip
    +
    + +

    The target-files .zip contains everything needed to construct OTA packages. +

    + +
    +% ./build/tools/releasetools/ota_from_target_files \
    +    dist_output/tardis-target_files.zip ota_update.zip
    +unzipping target target-files...
    +done.
    +% ls -l ota_update.zip
    +-rw-r----- 1 user eng 62236561 Sep 29 15:58 ota_update.zip
    +
    + +

    The ota_update.zip is now ready to be sent to test devices (everything is +signed with the test key). For user devices, generate and use your own private +keys as detailed in Signing builds for release. + +

    Incremental updates

    +

    An incremental update contains a set of binary patches to be applied +to the data already on the device. This can result in considerably smaller +update packages:

    + +

    You can install the incremental update package only on a device that has +the old or source build used when constructing the package. To build an +incremental update, you need the target_files .zip from the previous build +(the one you want to update from) as well as the target_files .zip from +the new build.

    + +
    +% ./build/tools/releasetools/ota_from_target_files \
    +    -i PREVIOUS-tardis-target_files.zip \  # make incremental from this older version
    +    dist_output/tardis-target_files.zip incremental_ota_update.zip
    +unzipping target target-files...
    +unzipping source target-files...
    +   [...]
    +done.
    +% ls -l incremental_ota_update.zip
    +-rw-r----- 1 user eng 1175314 Sep 29 16:10 incremental_ota_update.zip
    +
    + +

    This build is very similar to the previous build, and the incremental +update package is much smaller than the corresponding full update (about 1 MB +instead of 60 MB).

    +

    Note: To generate a +block-based OTA +for subsequent updates, pass the --block option to +ota_from_target_files.

    +

    Distribute an incremental package only to devices running exactly the same +previous build used as the incremental package's starting point. Attempting to +install the incremental package on a device with some other build results in +the recovery error icon. Rebooting the device at this point returns the user +to the old system; the package verifies the previous state of all the files it +updates before touching them, so the device should not be left in a half +upgraded state if this occurs.

    + +

    Update packages

    +

    An update package (ota_update.zip, +incremental_ota_update.zip) is a .zip file that contains the +executable binary META-INF/com/google/android/update-binary. After +verifying the signature on the package, recovery extracts this binary to +/tmp and runs it, passing the following arguments:

    + +

    A recovery package can use any statically-linked binary as the update +binary. The OTA package construction tools use the updater program (source in +bootable/recovery/updater), which provides a simple scripting +language that can do many installation tasks. You can substitute any other +binary running on the device.

    +

    For details on the updater binary, edify syntax, and builtin functions, see +Inside OTA Packages +. \ No newline at end of file diff --git a/src/source/community/index.jd b/src/source/community/index.jd index 31361ca9..8845469a 100644 --- a/src/source/community/index.jd +++ b/src/source/community/index.jd @@ -10,125 +10,213 @@ page.title=Android Community

    Welcome to the Android community!

    -

    The key to any community is, obviously, communication. Like most projects, -Android communicates via mailing lists. Because Android is an extremely large +

    The key to any community is communication. Like most projects, Android +communicates via mailing lists. Because Android is an extremely large project with many components, we have many discussion forums, each focusing on a different topic.

    -

    Please check out the groups below, and join any that seem interesting to +

    Check out the groups below and join any that seem interesting to you. Note that if you're a user looking for help with your Android device, this page probably isn't for you; you should contact your carrier or retailer for help with your phone.

    -

    Please note that if you're looking for information about building -applications for Android, you can find a separate set of groups for those at -our sister site, developer.android.com: [https://developer.android.com/resources/community-groups.html]

    +

    If you're looking for information about building applications for Android, +you can find a separate set of groups at our sister site + +developer.android.com.

    Open Source Project discussions

    -

    Audience

    -

    -These discussion groups are intended for developers working with the Android platform. Everyone is welcome to join in, provided you follow our community's policies described below. Our users help each other, and many experts post to these groups, including members of the Open Handset Alliance. -

    -

    -No topic is off-limits, provided it relates to Android in some way. However, since these are very busy lists, search the archives before posting your question; you may find your question has already been answered. -

    +

    These discussion groups are intended for developers working with the Android +platform. Everyone is welcome to join in, provided you follow the community +policies described below. Our users help each other, and many experts post to +these groups, including members of the Open Handset Alliance.

    +

    No topic is off-limits, provided it relates to Android in some way. However, +since these are very busy lists, search the archives before posting your +question; you may find your question has already been answered.

    Getting the Most from Our Lists

    Please consider the following before you post to our lists.

    Mailing list rules

    -

    We love simplicity and hate restrictions, so we keep our policies minimal. The rules -below describe what's expected of subscribers to the Android mailing lists. +

    We love simplicity and hate restrictions, so we keep our policies minimal. +The rules below describe what's expected of subscribers to the Android mailing +lists.

    -

    -The most important rule is friendliness. Remember: disrespect and rudeness are not welcome in our community under any circumstances. We don't have a formal policy on dealing with troublemakers, and we hope we never need one. That said, we do pledge to do our best to be fair, and we will always try to warn someone before banning him or her. -

    -

    Contacting the moderators

    -

    -If you see anyone being rude, call them out on it. This is your group too, and you don't have to accept someone else being disrespectful just because it wasn't directed at you. Just remember to be polite and courteous yourself! Don't add fuel to the fire. -

    -

    -But if you see an outrageous violation, want to report spam, feel very strongly about something, or even if you just want to chat, then contact the mailing list's owners. It's what we're here for! -

    - +

    The most important rule is friendliness. Remember: disrespect and rudeness +are not welcome in our community under any circumstances. We don't have a +formal policy on dealing with troublemakers, and we hope we never need one. +That said, we do pledge to do our best to be fair, and we will always try to +warn someone before banning him or her.

    +

    Contacting the moderators

    +

    If you see anyone being rude, call them out on it. This is your group too, +and you don't have to accept someone else being disrespectful just because it +wasn't directed at you. Just remember to be polite and courteous yourself! +Don't add fuel to the fire.

    +

    But if you see an outrageous violation, want to report spam, feel strongly +about something, or just want to chat, then contact the mailing list owners. +It's what we're here for!

    Using email with Google Groups

    -

    Instead of using the Google groups site, you can use your email client of choice to participate in the mailing lists.

    -

    To subscribe to a group without using the Google Groups site, use the link under "subscribe via email" in the lists above.

    +

    Instead of using the Google groups +site, you can use your email client of choice to participate in the mailing +lists. To subscribe to a group without using the Google Groups site, use the link +under "subscribe via email" in the lists above.

    To set up how you receive mailing list postings by email:

    1. -

      Sign into the group via the Google Groups site. For example, for the android-platform group you would use [https://groups.google.com/forum/?fromgroups#!forum/android-platform].

      +

      Sign into the group via the Google Groups site. For example, for the +android-platform group you would use + +https://groups.google.com/forum/?fromgroups#!forum/android-platform.

    2. Click "My membership" on the right side.

      @@ -138,33 +226,36 @@ But if you see an outrageous violation, want to report spam, feel very strongly

    Android on IRC

    -

    We also have a presence on IRC via freenode. -We maintain two official IRC channels on irc.freenode.net (access via the web -at freenode webchat)

    +

    Android has a presence on IRC via +freenode. We maintain two official IRC +channels on irc.freenode.net (access via +the web at freenode webchat)

    -

    The channels above are official. There are a few other channels the -community is using, but are not official. These aren't official or officially -moderated/managed, so you use the channels below at your own risk. The Open -Handset Alliance doesn't endorse these channels, there's no warranty express -or implied, and so on. There may be more channels than just these listed.

    +

    The community also uses several unofficial channels that are not not officially moderated or managed. The Open Handset Alliance does not endorse unofficial channels and there's no warranty express or implied, so use them at your own risk. Here's a list of a few unofficial channels (many more may exist):

    + + \ No newline at end of file -- cgit v1.2.3