کد مخصوص دستگاه

سیستم بازیابی شامل چندین قلاب برای درج کد خاص دستگاه است تا به‌روزرسانی‌های OTA همچنین می‌توانند بخش‌هایی از دستگاه را غیر از سیستم اندروید (مانند باند پایه یا پردازنده رادیویی) به‌روزرسانی کنند.

بخش ها و نمونه های زیر دستگاه تاردیس تولید شده توسط فروشنده yoyodyne را سفارشی می کند.

نقشه پارتیشن

از اندروید 2.3، این پلتفرم از دستگاه های فلش eMMc و سیستم فایل ext4 که روی آن دستگاه ها اجرا می شود، پشتیبانی می کند. همچنین از دستگاه های فلش دستگاه فناوری حافظه (MTD) و سیستم فایل yaffs2 نسخه های قدیمی تر پشتیبانی می کند.

فایل نقشه پارتیشن توسط TARGET_RECOVERY_FSTAB مشخص شده است. این فایل توسط ابزارهای باینری بازیابی و بسته سازی استفاده می شود. می توانید نام فایل نقشه را در TARGET_RECOVERY_FSTAB در BoardConfig.mk مشخص کنید.

نمونه فایل نقشه پارتیشن ممکن است به شکل زیر باشد:

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

به استثنای /sdcard که اختیاری است، تمام نقاط اتصال در این مثال باید تعریف شوند (دستگاه ها ممکن است پارتیشن های اضافی نیز اضافه کنند). پنج نوع سیستم فایل پشتیبانی شده وجود دارد:

yaffs2
یک سیستم فایل yaffs2 در بالای دستگاه فلش MTD. "device" باید نام پارتیشن MTD باشد و باید در /proc/mtd ظاهر شود.
mtd
یک پارتیشن خام MTD که برای پارتیشن های قابل بوت مانند بوت و بازیابی استفاده می شود. MTD در واقع نصب نشده است، اما نقطه اتصال به عنوان یک کلید برای مکان یابی پارتیشن استفاده می شود. "device" باید نام پارتیشن MTD در /proc/mtd باشد.
ext4
یک سیستم فایل ext4 در بالای دستگاه فلش eMMc. «دستگاه» باید مسیر دستگاه بلوک باشد.
emmc
یک دستگاه بلوک خام eMMc که برای پارتیشن های قابل بوت مانند بوت و بازیابی استفاده می شود. مشابه نوع mtd، eMMc هرگز در واقع نصب نمی شود، اما رشته نقطه اتصال برای مکان یابی دستگاه در جدول استفاده می شود.
vfat
یک سیستم فایل FAT در بالای یک دستگاه بلوک، معمولاً برای ذخیره سازی خارجی مانند کارت SD. دستگاه دستگاه بلوک است. device2 یک دستگاه بلوک دوم است که در صورت عدم موفقیت در نصب دستگاه اصلی (برای سازگاری با کارت های SD که ممکن است با جدول پارتیشن فرمت شده باشند یا نباشند) سعی می کند آن را نصب کند.

همه پارتیشن ها باید در دایرکتوری ریشه نصب شوند (یعنی مقدار نقطه مانت باید با یک اسلش شروع شود و هیچ اسلش دیگری نداشته باشد). این محدودیت فقط برای نصب فایل سیستم در بازیابی اعمال می شود. سیستم اصلی رایگان است که آنها را در هر مکانی نصب کند. دایرکتوری‌های /boot ، /recovery ، و /misc باید از نوع خام (mtd یا emmc) باشند، در حالی که دایرکتوری‌های /system ، /data ، /cache و /sdcard (در صورت وجود) باید از نوع سیستم فایل (yaffs2، ext4 یا vfat).

با شروع Android 3.0، فایل recovery.fstab یک فیلد اختیاری اضافی، گزینه‌ها به دست می‌آورد. در حال حاضر تنها گزینه تعریف شده length است که به شما امکان می دهد به طور صریح طول پارتیشن را مشخص کنید. این طول هنگام قالب‌بندی مجدد پارتیشن استفاده می‌شود (به عنوان مثال، برای پارتیشن داده‌های کاربر در طول عملیات پاک کردن داده/بازنشانی کارخانه، یا برای پارتیشن سیستم در هنگام نصب یک بسته کامل OTA). اگر مقدار طول منفی باشد، با افزودن مقدار طول به اندازه واقعی پارتیشن، اندازه برای قالب‌بندی گرفته می‌شود. به عنوان مثال، تنظیم "length=-16384" به این معنی است که 16k آخرین آن پارتیشن زمانی که آن پارتیشن دوباره فرمت می شود، رونویسی نمی شود. این ویژگی‌هایی مانند رمزگذاری پارتیشن داده‌های کاربر (که در آن ابرداده‌های رمزگذاری در انتهای پارتیشن ذخیره می‌شوند و نباید رونویسی شوند) پشتیبانی می‌کند.

توجه: فیلدهای device2 و option اختیاری هستند و در تجزیه ابهام ایجاد می کنند. اگر ورودی در قسمت چهارم در خط با کاراکتر '/' شروع شود، ورودی دستگاه2 در نظر گرفته می شود. اگر ورودی با کاراکتر '/' شروع نشود، فیلد گزینه در نظر گرفته می شود.

پویانمایی بوت

سازندگان دستگاه این توانایی را دارند که انیمیشن نمایش داده شده هنگام بوت شدن دستگاه اندرویدی را سفارشی کنند. برای انجام این کار، یک فایل .zip بسازید که بر اساس مشخصات در فرمت بوتانیمیشن سازماندهی و قرار گرفته است.

برای دستگاه‌های Android Things ، می‌توانید فایل فشرده شده را در کنسول Android Things آپلود کنید تا تصاویر در محصول انتخابی گنجانده شود.

توجه: این تصاویر باید دستورالعمل‌های برند Android را داشته باشند.

رابط کاربری بازیابی

برای پشتیبانی از دستگاه‌هایی با سخت‌افزارهای مختلف (دکمه‌های فیزیکی، LED، صفحه‌نمایش و غیره)، می‌توانید رابط بازیابی را برای نمایش وضعیت و دسترسی به ویژگی‌های مخفی دستی برای هر دستگاه سفارشی کنید.

هدف شما ساختن یک کتابخانه استاتیک کوچک با چند شیء ++C برای ارائه عملکرد خاص دستگاه است. فایل bootable/recovery/default_device.cpp به طور پیش‌فرض استفاده می‌شود و نقطه شروع خوبی برای کپی کردن هنگام نوشتن نسخه‌ای از این فایل برای دستگاه شما است.

توجه: ممکن است پیامی مبنی بر No Command را در اینجا مشاهده کنید. برای تغییر متن، دکمه روشن/خاموش را نگه دارید و دکمه افزایش صدا را فشار دهید. اگر دستگاه‌های شما هر دو دکمه را ندارند، برای تغییر متن هر دکمه را طولانی فشار دهید.

device/yoyodyne/tardis/recovery/recovery_ui.cpp
#include <linux/input.h>

#include "common.h"
#include "device.h"
#include "screen_ui.h"

توابع هدر و آیتم

کلاس Device به توابعی برای برگرداندن هدرها و مواردی که در منوی بازیابی پنهان ظاهر می شوند نیاز دارد. سرصفحه ها نحوه عملکرد منو را توضیح می دهند (یعنی کنترل هایی برای تغییر/انتخاب آیتم هایلایت شده).

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 };

توجه: خطوط طولانی کوتاه هستند (بدون پیچیدگی)، بنابراین عرض صفحه نمایش دستگاه خود را در نظر داشته باشید.

سفارشی کردن CheckKey

سپس پیاده سازی RecoveryUI دستگاه خود را تعریف کنید. این مثال فرض می‌کند که دستگاه tardis دارای یک صفحه است، بنابراین می‌توانید از ScreenRecoveryUIimplementation داخلی به ارث بری (دستورالعمل‌های دستگاه‌های بدون صفحه را ببینید.) تنها عملکردی که از ScreenRecoveryUI قابل سفارشی‌سازی است CheckKey() است که مدیریت اولیه کلید ناهمزمان را انجام می‌دهد:

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

ثابت های کلیدی

ثابت های KEY_* در linux/input.h تعریف شده اند. CheckKey() بدون توجه به آنچه در بقیه بازیابی اتفاق می افتد فراخوانی می شود: وقتی منو خاموش می شود، زمانی که روشن است، در حین نصب بسته، در حین پاک کردن داده های کاربر و غیره. می تواند یکی از چهار ثابت را برگرداند:

  • تغییر وضعیت . نمایش منو و/یا ورود متن را روشن یا خاموش کنید
  • راه اندازی مجدد بلافاصله دستگاه را راه اندازی مجدد کنید
  • چشم پوشی . این فشار کلید را نادیده بگیرید
  • ENQUEUE . این فشار کلید را در صف قرار دهید تا به طور همزمان مصرف شود (یعنی توسط سیستم منوی بازیابی در صورت فعال بودن نمایشگر)

CheckKey() هر بار که یک رویداد key-down توسط یک رویداد key-up برای همان کلید دنبال می شود فراخوانی می شود. (توالی رویدادهای A-down B-down B-up A-up فقط باعث فراخوانی CheckKey(B) می شود.) CheckKey() می تواند IsKeyPressed() را فراخوانی کند تا بفهمد آیا کلیدهای دیگر پایین نگه داشته می شوند یا خیر. (در توالی بالا از رویدادهای کلیدی، اگر CheckKey(B) IsKeyPressed(A) را صدا می کرد، مقدار true برمی گشت.)

CheckKey() می تواند حالت را در کلاس خود حفظ کند. این می تواند برای تشخیص دنباله کلیدها مفید باشد. این مثال تنظیمات کمی پیچیده‌تر را نشان می‌دهد: صفحه نمایش با نگه داشتن پاور و فشار دادن صدا تغییر می‌کند، و دستگاه را می‌توان با فشار دادن دکمه پاور پنج بار متوالی (بدون کلیدهای مداخله‌ای دیگر) فوراً راه‌اندازی مجدد کرد:

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

هنگام استفاده از تصاویر خود (نماد خطا، انیمیشن نصب، نوارهای پیشرفت) با ScreenRecoveryUI، می توانید متغیر animation_fps را برای کنترل سرعت فریم در ثانیه (FPS) انیمیشن ها تنظیم کنید.

توجه: اسکریپت interlace-frames.py فعلی به شما امکان می دهد اطلاعات animation_fps را در خود تصویر ذخیره کنید. در نسخه های قبلی اندروید لازم بود خودتان animation_fps تنظیم کنید.

برای تنظیم متغیر animation_fps ، تابع ScreenRecoveryUI::Init() را در زیر کلاس خود لغو کنید. مقدار را تنظیم کنید، سپس تابع parent Init() را برای تکمیل مقداردهی اولیه فراخوانی کنید. مقدار پیش فرض (20 FPS) مربوط به تصاویر بازیابی پیش فرض است. هنگام استفاده از این تصاویر، نیازی به ارائه تابع Init() ندارید. برای جزئیات بیشتر در مورد تصاویر، به Recovery UI Images مراجعه کنید.

کلاس دستگاه

پس از اجرای RecoveryUI، کلاس دستگاه خود را تعریف کنید (زیر کلاس از کلاس Device داخلی). باید یک نمونه از کلاس UI شما ایجاد کند و آن را از تابع GetUI() برگرداند:

class TardisDevice : public Device {
  private:
    TardisUI* ui;

  public:
    TardisDevice() :
        ui(new TardisUI) {
    }

    RecoveryUI* GetUI() { return ui; }

شروع ریکاوری

متد StartRecovery() در شروع بازیابی، پس از اولیه سازی UI و پس از تجزیه آرگومان ها، اما قبل از انجام هر گونه اقدامی فراخوانی می شود. پیاده سازی پیش فرض هیچ کاری انجام نمی دهد، بنابراین اگر کاری برای انجام دادن ندارید، نیازی به ارائه آن در زیر کلاس خود ندارید:

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

منوی بازیابی را تامین و مدیریت کنید

سیستم دو روش را برای دریافت لیست خطوط سرصفحه و لیست آیتم ها فراخوانی می کند. در این پیاده سازی، آرایه های ثابت تعریف شده در بالای فایل را برمی گرداند:

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

HandleMenuKey

در مرحله بعد، یک تابع HandleMenuKey() ارائه دهید که با فشار دادن کلید و نمایان شدن منوی فعلی، تصمیم می‌گیرد که چه اقدامی انجام شود:

   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;
    }

این روش یک کد کلیدی (که قبلاً توسط متد CheckKey() شی UI پردازش شده و در صف قرار گرفته است) و وضعیت فعلی نمایان شدن فهرست فهرست/متن را می گیرد. مقدار برگشتی یک عدد صحیح است. اگر مقدار 0 یا بالاتر باشد، به عنوان موقعیت یک آیتم منو در نظر گرفته می شود که بلافاصله فراخوانی می شود (به روش InvokeMenuItem() در زیر مراجعه کنید). در غیر این صورت می تواند یکی از ثابت های از پیش تعریف شده زیر باشد:

  • kHighlightUp . هایلایت منو را به آیتم قبلی منتقل کنید
  • kHighlightDown . هایلایت منو را به مورد بعدی منتقل کنید
  • kInvokeItem . مورد برجسته شده فعلی را فراخوانی کنید
  • kNoAction . با این کلید هیچ کاری نکنید

همانطور که توسط آرگومان قابل مشاهده مشخص است، HandleMenuKey() فراخوانی می شود حتی اگر منو قابل مشاهده نباشد. برخلاف CheckKey() ، زمانی که بازیابی در حال انجام کاری مانند پاک کردن اطلاعات یا نصب یک بسته است، فراخوانی نمی‌شود .

مکانیزم های توپی

اگر دستگاه شما مکانیزم ورودی گوی مانندی دارد (رویدادهای ورودی با نوع EV_REL و کد REL_Y ایجاد می‌کند)، هر زمان که دستگاه ورودی گوی مانند حرکت در محور Y را گزارش کند، بازیابی کلیدهای KEY_UP و KEY_DOWN را ترکیب می‌کند. تنها کاری که باید انجام دهید این است که رویدادهای KEY_UP و KEY_DOWN را روی عملکردهای منو ترسیم کنید. این نگاشت برای CheckKey() اتفاق نمی افتد، بنابراین نمی توانید از حرکات trackball به عنوان محرک برای راه اندازی مجدد یا جابجایی صفحه نمایش استفاده کنید.

کلیدهای اصلاح کننده

برای بررسی اینکه کلیدها به‌عنوان اصلاح‌کننده نگه داشته می‌شوند، متد IsKeyPressed() شی UI خود را فراخوانی کنید. برای مثال، در برخی از دستگاه‌ها با فشار دادن Alt-W در بازیابی، پاک کردن داده‌ها شروع می‌شود، چه منو قابل مشاهده باشد یا نه. شما می توانید اینگونه پیاده سازی کنید:

   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
        }
        ...
    }

توجه: اگر قابل مشاهده نادرست است، بازگرداندن مقادیر ویژه ای که منو را دستکاری می کند (انتقال برجسته، فراخوانی مورد برجسته شده) منطقی نیست زیرا کاربر نمی تواند برجسته را ببیند. با این حال، در صورت تمایل می توانید مقادیر را برگردانید.

InvokeMenuItem

در مرحله بعد، یک متد InvokeMenuItem() ارائه دهید که موقعیت های اعداد صحیح را در آرایه آیتم های بازگردانده شده توسط GetMenuItems() به اکشن ها نگاشت می کند. برای آرایه اقلام در مثال tardis از:

   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;
        }
    }

این متد می تواند هر عضوی از BuiltinAction enum را برگرداند تا به سیستم بگوید آن عمل را انجام دهد (یا اگر می خواهید سیستم هیچ کاری انجام ندهد به عضو NO_ACTION). اینجا مکانی برای ارائه عملکرد بازیابی اضافی فراتر از آنچه در سیستم است است: یک مورد را برای آن در منوی خود اضافه کنید، زمانی که آن آیتم منو فراخوانی شد، آن را در اینجا اجرا کنید و NO_ACTION را برگردانید تا سیستم هیچ کار دیگری انجام ندهد.

BuiltinAction حاوی مقادیر زیر است:

  • NO_ACTION . هیچ کاری نکن
  • راه اندازی مجدد از بازیابی خارج شده و دستگاه را به طور معمول راه اندازی مجدد کنید.
  • APPLY_EXT، APPLY_CACHE، APPLY_ADB_SIDELOAD . بسته به روز رسانی را از مکان های مختلف نصب کنید. برای جزئیات، به Sideloading مراجعه کنید.
  • پاک کردن کش . فقط پارتیشن کش را دوباره فرمت کنید. نیازی به تایید نیست زیرا این نسبتا بی ضرر است.
  • WIPE_DATA . پارتیشن‌های داده‌های کاربری و حافظه پنهان را که به عنوان بازنشانی داده‌های کارخانه نیز شناخته می‌شود، دوباره فرمت کنید. از کاربر خواسته می شود قبل از ادامه این عمل را تأیید کند.

آخرین روش، WipeData() اختیاری است و هر زمان که عملیات پاک کردن داده ها آغاز شود (چه از بازیابی از طریق منو یا زمانی که کاربر انتخاب کرده است بازنشانی داده های کارخانه را از سیستم اصلی انجام دهد) فراخوانی می شود. این متد قبل از پاک شدن اطلاعات کاربر و پارتیشن های کش فراخوانی می شود. اگر دستگاه شما اطلاعات کاربر را در جایی غیر از این دو پارتیشن ذخیره می کند، باید آن را در اینجا پاک کنید. شما باید 0 را برای نشان دادن موفقیت و مقدار دیگری را برای شکست برگردانید، اگرچه در حال حاضر مقدار بازگشتی نادیده گرفته شده است. داده‌های کاربر و پارتیشن‌های کش پاک می‌شوند، چه موفقیت یا شکست را برگردانید.

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

دستگاه درست کن

در نهایت، مقداری boilerplate در انتهای فایل recovery_ui.cpp برای تابع make_device() قرار دهید که نمونه ای از کلاس Device شما را ایجاد و برمی گرداند:

class TardisDevice : public Device {
   // ... all the above methods ...
};

Device* make_device() {
    return new TardisDevice();
}

پس از تکمیل فایل recovery_ui.cpp، آن را ساخته و به بازیابی در دستگاه خود پیوند دهید. در Android.mk، یک کتابخانه ثابت ایجاد کنید که فقط شامل این فایل C++ باشد:

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)

سپس، در پیکربندی برد برای این دستگاه، کتابخانه استاتیک خود را به عنوان مقدار TARGET_RECOVERY_UI_LIB مشخص کنید.

device/yoyodyne/tardis/BoardConfig.mk
 [...]

# device-specific extensions to the recovery UI
TARGET_RECOVERY_UI_LIB := librecovery_ui_tardis

بازیابی تصاویر رابط کاربری

رابط کاربری بازیابی از تصاویر تشکیل شده است. در حالت ایده‌آل، کاربران هرگز با رابط کاربری ارتباط برقرار نمی‌کنند: در طول یک به‌روزرسانی معمولی، تلفن به حالت بازیابی راه‌اندازی می‌شود، نوار پیشرفت نصب را پر می‌کند و بدون ورودی کاربر به سیستم جدید باز می‌گردد. در صورت بروز مشکل به روز رسانی سیستم، تنها اقدام کاربر که می تواند انجام شود تماس با خدمات مشتری است.

رابط فقط تصویر نیاز به محلی سازی را برطرف می کند. با این حال، از اندروید 5.0، به روز رسانی می تواند یک رشته متن (به عنوان مثال "نصب به روز رسانی سیستم...") را همراه با تصویر نمایش دهد. برای جزئیات، به متن بازیابی محلی مراجعه کنید.

اندروید 5.0 و بالاتر

رابط کاربری بازیابی اندروید 5.0 به بعد از دو تصویر اصلی استفاده می کند: تصویر خطا و انیمیشن در حال نصب .

تصویر نشان داده شده در هنگام خطای ota

شکل 1. icon_error.png

تصویر در حین نصب ota نشان داده شده است

شکل 2. icon_installing.png

انیمیشن در حال نصب به صورت یک تصویر PNG منفرد با فریم های مختلف انیمیشن با ردیف در هم آمیخته شده نشان داده می شود (به همین دلیل است که شکل 2 به صورت فشرده به نظر می رسد). به عنوان مثال، برای یک انیمیشن هفت فریم 200x200، یک تصویر 200x1400 ایجاد کنید که در آن اولین فریم ردیف های 0، 7، 14، 21، ... باشد. فریم دوم ردیف های 1، 8، 15، 22، ... است. و غیره. تصویر ترکیبی شامل یک تکه متن است که تعداد فریم های انیمیشن و تعداد فریم در ثانیه (FPS) را نشان می دهد. ابزار bootable/recovery/interlace-frames.py مجموعه‌ای از فریم‌های ورودی را می‌گیرد و آن‌ها را در تصویر ترکیبی لازم مورد استفاده در بازیابی ترکیب می‌کند.

تصاویر پیش‌فرض در تراکم‌های مختلف موجود هستند و در bootable/recovery/res-$DENSITY/images (مثلاً bootable/recovery/res-hdpi/images ) قرار دارند. برای استفاده از یک تصویر ثابت در حین نصب، فقط باید تصویر icon_installing.png را ارائه دهید و تعداد فریم های انیمیشن را روی 0 تنظیم کنید (آیکون خطا متحرک نیست، همیشه یک تصویر ثابت است).

اندروید 4.x و بالاتر

رابط کاربری بازیابی اندروید 4.x و نسخه قبلی از تصویر خطا (نشان داده شده در بالا) و انیمیشن نصب به همراه چندین تصویر همپوشانی استفاده می‌کند:

تصویر در حین نصب ota نشان داده شده است

شکل 3. icon_installing.png

تصویر به عنوان اولین پوشش نشان داده شده است

شکل 4. icon-installing_overlay01.png

تصویر به عنوان پوشش هفتم نشان داده شده است

شکل 5. icon_installing_overlay07.png

در حین نصب، نمایش روی صفحه با رسم تصویر icon_installing.png ساخته می‌شود، سپس یکی از فریم‌های همپوشانی در بالای آن با افست مناسب ترسیم می‌شود. در اینجا، یک کادر قرمز برای برجسته کردن جایی که همپوشانی در بالای تصویر پایه قرار گرفته است قرار داده شده است:

تصویر ترکیبی نصب به اضافه پوشش اول

شکل 6. نصب قاب انیمیشن 1 (icon_installing.png + icon_installing_overlay01.png)

تصویر ترکیبی نصب به اضافه پوشش هفتم

شکل 7. نصب قاب انیمیشن 7 (icon_installing.png + icon_installing_overlay07.png)

فریم‌های بعدی تنها با کشیدن تصویر همپوشانی بعدی در بالای آنچه قبلاً وجود دارد، نمایش داده می‌شوند. تصویر پایه دوباره ترسیم نشده است.

تعداد فریم‌ها در انیمیشن، سرعت مورد نظر، و افست‌های x و y از همپوشانی نسبت به پایه توسط متغیرهای عضو کلاس ScreenRecoveryUI تنظیم می‌شوند. هنگام استفاده از تصاویر سفارشی به جای تصاویر پیش‌فرض، روش Init() را در زیر کلاس خود لغو کنید تا این مقادیر را برای تصاویر سفارشی خود تغییر دهید (برای جزئیات، ScreenRecoveryUI را ببینید). اسکریپت bootable/recovery/make-overlay.py می تواند در تبدیل مجموعه ای از فریم های تصویر به فرم "تصویر پایه + تصاویر همپوشانی" مورد نیاز برای بازیابی، از جمله محاسبه افست های لازم، کمک کند.

تصاویر پیش‌فرض در قسمت bootable/recovery/res/images قرار دارند. برای استفاده از یک تصویر ثابت در حین نصب، فقط باید تصویر icon_installing.png را ارائه دهید و تعداد فریم های انیمیشن را روی 0 تنظیم کنید (آیکون خطا متحرک نیست، همیشه یک تصویر ثابت است).

متن بازیابی محلی

Android 5.x یک رشته متن (به عنوان مثال، "نصب به روز رسانی سیستم...") را همراه با تصویر نمایش می دهد. هنگامی که سیستم اصلی به بازیابی راه اندازی می شود، محلی فعلی کاربر را به عنوان یک گزینه خط فرمان برای بازیابی ارسال می کند. برای نمایش هر پیام، بازیابی شامل یک تصویر ترکیبی دوم با رشته‌های متنی از پیش رندر شده برای آن پیام در هر منطقه است.

تصویر نمونه رشته های متن بازیابی:

تصویر متن بازیابی

شکل 8. متن محلی شده برای پیام های بازیابی

متن بازیابی می تواند پیام های زیر را نمایش دهد:

  • در حال نصب به روز رسانی سیستم...
  • خطا!
  • پاک کردن... (هنگام پاک کردن اطلاعات/بازنشانی به تنظیمات کارخانه)
  • بدون دستور (زمانی که کاربر به صورت دستی وارد بازیابی می شود)

برنامه اندروید در bootable/recovery/tools/recovery_l10n/ بومی سازی یک پیام را ارائه می دهد و تصویر ترکیبی را ایجاد می کند. برای جزئیات استفاده از این برنامه، به نظرات در bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java مراجعه کنید.

هنگامی که کاربر به صورت دستی وارد بازیابی می شود، ممکن است محلی در دسترس نباشد و هیچ متنی نمایش داده نشود. پیام های متنی را برای فرآیند بازیابی حیاتی نکنید.

توجه: رابط پنهانی که پیام های گزارش را نمایش می دهد و به کاربر اجازه می دهد تا اقدامات را از منو انتخاب کند، فقط به زبان انگلیسی در دسترس است.

نوارهای پیشرفت

نوارهای پیشرفت می توانند در زیر تصویر اصلی (یا انیمیشن) ظاهر شوند. نوار پیشرفت با ترکیب دو تصویر ورودی ساخته می شود که باید هم اندازه باشند:

نوار پیشرفت خالی

شکل 9. progress_empty.png

نوار پیشرفت کامل

شکل 10. progress_fill.png

انتهای سمت چپ تصویر پر شده در کنار سمت راست تصویر خالی نمایش داده می شود تا نوار پیشرفت ایجاد شود. موقعیت مرز بین دو تصویر برای نشان دادن پیشرفت تغییر می کند. به عنوان مثال، با جفت تصاویر ورودی بالا، نمایش داده شود:

نوار پیشرفت در 1٪

شکل 11. نوار پیشرفت در 1%>

نوار پیشرفت در 10٪

شکل 12. نوار پیشرفت در 10٪

نوار پیشرفت در 50٪

شکل 13. نوار پیشرفت در 50%

می‌توانید با قرار دادن (در این مثال) در device/yoyodyne/tardis/recovery/res/images نسخه‌های مخصوص دستگاه را از این تصاویر ارائه دهید. نام فایل ها باید با موارد ذکر شده در بالا مطابقت داشته باشد. هنگامی که یک فایل در آن دایرکتوری یافت می شود، سیستم ساخت آن را در اولویت به تصویر پیش فرض مربوطه استفاده می کند. فقط PNG در قالب RGB یا RGBA با عمق رنگ 8 بیت پشتیبانی می شود.

توجه: در Android 5.x، اگر محلی برای بازیابی شناخته شده باشد و یک زبان راست به چپ (RTL) (عربی، عبری و غیره) باشد، نوار پیشرفت از راست به چپ پر می‌شود.

دستگاه های بدون صفحه نمایش

همه دستگاه های اندرویدی صفحه نمایش ندارند. اگر دستگاه شما یک دستگاه بدون هد است یا دارای یک رابط فقط صوتی است، ممکن است لازم باشد سفارشی سازی گسترده تری از رابط کاربری بازیابی انجام دهید. به جای ایجاد یک زیر کلاس از ScreenRecoveryUI، کلاس والد آن RecoveryUI را مستقیماً زیر کلاس قرار دهید.

RecoveryUI دارای روش هایی برای مدیریت یک رابط کاربری سطح پایین تر است، مانند «تغییر صفحه نمایش»، «به روز رسانی نوار پیشرفت»، «نمایش منو»، «تغییر انتخاب منو»، و غیره. برای دستگاه شما شاید دستگاه شما دارای LED هایی باشد که می توانید از رنگ ها یا الگوهای مختلف چشمک زن برای نشان دادن وضعیت استفاده کنید، یا شاید بتوانید صدا را پخش کنید. (شاید اصلاً نمی‌خواهید از یک منو یا حالت «نمایش متن» پشتیبانی کنید؛ می‌توانید با اجرای CheckKey() و HandleMenuKey() که هرگز نمایشگر را روشن نمی‌کنند یا یک آیتم منو را انتخاب نمی‌کنند، از دسترسی به آنها جلوگیری کنید. ، بسیاری از روش‌های RecoveryUI که باید ارائه کنید، می‌توانند فقط خرد خالی باشند.)

برای اطلاع از RecoveryUI به bootable/recovery/ui.h مراجعه کنید تا ببینید چه روش هایی را باید پشتیبانی کنید. RecoveryUI انتزاعی است – برخی از روش‌ها مجازی خالص هستند و باید توسط کلاس‌های فرعی ارائه شوند – اما حاوی کدهایی برای پردازش ورودی‌های کلیدی است. اگر دستگاه شما کلید ندارد یا می خواهید آنها را متفاوت پردازش کنید، می توانید آن را نیز لغو کنید.

به روز رسانی

می توانید با ارائه توابع برنامه افزودنی خود که می توانند از داخل اسکریپت به روز رسانی شما فراخوانی شوند، از کدهای مخصوص دستگاه در نصب بسته به روز رسانی استفاده کنید. در اینجا یک نمونه تابع برای دستگاه تاردیس آمده است:

device/yoyodyne/tardis/recovery/recovery_updater.c
#include <stdlib.h>
#include <string.h>

#include "edify/expr.h"

هر تابع افزونه امضای یکسانی دارد. آرگومان ها نامی هستند که تابع با آن فراخوانی شده است، یک کوکی State* ، تعداد آرگومان های ورودی، و آرایه ای از نشانگرهای Expr* که آرگومان ها را نشان می دهند. مقدار بازگشتی یک 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);
    }

آرگومان های شما در زمانی که تابع شما فراخوانی می شود ارزیابی نشده اند - منطق تابع شما تعیین می کند که کدام یک از آنها و چند بار ارزیابی شوند. بنابراین، می توانید از توابع توسعه برای پیاده سازی ساختارهای کنترلی خود استفاده کنید. برای ارزیابی آرگومان Expr* Call Evaluate() و یک Value* برگردانید. اگر Evaluate() NULL را برمی گرداند، باید منابعی را که در اختیار دارید آزاد کنید و فوراً NULL را برگردانید (این باعث می شود پشته edify لغو شود). در غیر این صورت، شما مالکیت مقدار بازگشتی را به عهده می گیرید و در نهایت مسئول فراخوانی FreeValue() روی آن هستید.

فرض کنید تابع به دو آرگومان نیاز دارد: یک کلید با مقدار رشته و یک تصویر با مقدار blob. شما می توانید استدلال هایی مانند این را بخوانید:

   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;
    }

بررسی NULL و آزاد کردن آرگومان های ارزیابی شده قبلی می تواند برای چندین آرگومان خسته کننده باشد. تابع ReadValueArgs() می تواند این کار را آسان تر کند. به جای کد بالا، می توانید این را بنویسید:

   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() بررسی نوع انجام نمی دهد، بنابراین باید این کار را در اینجا انجام دهید. راحت‌تر است که آن را با یک عبارت if به قیمت تولید یک پیغام خطای کمتر خاص در هنگام شکست انجام دهید. اما ReadValueArgs() ارزیابی هر آرگومان و آزاد کردن همه آرگومان های ارزیابی شده قبلی (و همچنین تنظیم یک پیام خطای مفید) را در صورت شکست هر یک از ارزیابی ها انجام می دهد. می توانید از یک تابع راحت ReadValueVarArgs() برای ارزیابی تعداد متغیر آرگومان استفاده کنید (آرایه ای از Value* را برمی گرداند).

پس از ارزیابی آرگومان ها، کار تابع را انجام دهید:

   // 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 ...

مقدار بازگشتی باید یک آبجکت Value* باشد. مالکیت این شی به تماس گیرنده منتقل می شود. تماس‌گیرنده مالکیت هر داده‌ای را که با این Value* می‌پذیرد - به‌ویژه عضو داده.

در این مثال، شما می خواهید مقدار درست یا نادرست را برای نشان دادن موفقیت برگردانید. این قرارداد را به خاطر بسپارید که رشته خالی نادرست است و تمام رشته های دیگر درست هستند. برای بازگشت باید یک شی Value را با یک کپی malloc'd از رشته ثابت malloc کنید، زیرا تماس گیرنده free() می کند. فراموش نکنید که FreeValue() روی اشیایی که با ارزیابی آرگومان های خود دریافت کرده اید فراخوانی کنید!

   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;
}

تابع راحت StringValue() یک رشته را در یک شیء جدید Value می پیچد. برای نوشتن مختصرتر کد بالا استفاده کنید:

   FreeValue(key);
    FreeValue(image);

    return StringValue(strdup(successful ? "t" : ""));
}

برای قلاب کردن توابع به مفسر edify، تابع Register_ foo را ارائه کنید که foo نام کتابخانه ایستا حاوی این کد است. برای ثبت هر تابع افزونه RegisterFunction() فراخوانی کنید. طبق قرارداد، توابع خاص device . whatever جلوگیری از تضاد با توابع داخلی آینده اضافه شده است.

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

اکنون می توانید makefile را طوری پیکربندی کنید که با کد خود یک کتابخانه استاتیک بسازد. (این همان فایل ساخت مورد استفاده برای سفارشی کردن رابط کاربری بازیابی در بخش قبلی است؛ ممکن است دستگاه شما هر دو کتابخانه ثابت در اینجا تعریف شده باشد.)

device/yoyodyne/tardis/recovery/Android.mk
include $(CLEAR_VARS)
LOCAL_SRC_FILES := recovery_updater.c
LOCAL_C_INCLUDES += bootable/recovery

نام کتابخانه استاتیک باید با نام تابع Register_ libname موجود در آن مطابقت داشته باشد.

LOCAL_MODULE := librecovery_updater_tardis
include $(BUILD_STATIC_LIBRARY)

در نهایت، بیلد ریکاوری را به گونه ای پیکربندی کنید که در کتابخانه شما کشیده شود. کتابخانه خود را به TARGET_RECOVERY_UPDATER_LIBS (که ممکن است شامل چندین کتابخانه باشد، همه آنها ثبت می شوند) اضافه کنید. اگر کد شما به کتابخانه‌های ثابت دیگری بستگی دارد که خودشان افزونه‌های ویرایش نیستند (یعنی تابع Register_ libname ندارند)، می‌توانید آن‌ها را در TARGET_RECOVERY_UPDATER_EXTRA_LIBS فهرست کنید تا بدون فراخوانی تابع ثبت نام (غیر موجود) آن‌ها را به به‌روزرسانی‌کننده پیوند دهید. برای مثال، اگر کد مخصوص دستگاه شما می‌خواهد از zlib برای فشرده‌سازی داده‌ها استفاده کند، libz را در اینجا قرار دهید.

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 +=

اسکریپت های به روز کننده در بسته OTA شما اکنون می توانند عملکرد شما را مانند سایر موارد فراخوانی کنند. برای برنامه ریزی مجدد دستگاه tardis خود، اسکریپت به روز رسانی ممکن است شامل: tardis.reprogram("the-key", package_extract_file("tardis-image.dat")) باشد. این از نسخه تک آرگومان تابع داخلی package_extract_file() استفاده می کند که محتویات یک فایل استخراج شده از بسته به روز رسانی را به عنوان یک لکه برای تولید آرگومان دوم به تابع افزونه جدید برمی گرداند.

تولید بسته OTA

مؤلفه نهایی این است که ابزارهای تولید بسته OTA را در مورد داده های خاص دستگاه خود بدانند و اسکریپت های به روز رسانی را منتشر کنند که شامل تماس هایی با عملکردهای برنامه افزودنی شما می شود.

ابتدا، سیستم ساخت را در مورد لکه‌ای از داده‌های خاص دستگاه مطلع کنید. با فرض اینکه فایل داده شما در device/yoyodyne/tardis/tardis.dat است، موارد زیر را در AndroidBoard.mk دستگاه خود اعلام کنید:

device/yoyodyne/tardis/AndroidBoard.mk
  [...]

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

همچنین می‌توانید به جای آن آن را در Android.mk قرار دهید، اما پس از آن باید با بررسی دستگاه محافظت شود، زیرا همه فایل‌های Android.mk در درخت بدون توجه به اینکه چه دستگاهی ساخته می‌شود، بارگذاری می‌شوند. (اگر درخت شما شامل چندین دستگاه است، فقط می خواهید فایل tardis.dat هنگام ساختن دستگاه tardis اضافه شود.)

device/yoyodyne/tardis/Android.mk
  [...]

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

به دلایل تاریخی به این فایل های رادیویی می گویند. آنها ممکن است هیچ ارتباطی با رادیو دستگاه نداشته باشند (در صورت وجود). آنها به سادگی حباب های مبهم داده ای هستند که سیستم ساخت در فایل های هدف .zip که توسط ابزارهای تولید OTA استفاده می شود کپی می کند. هنگامی که یک ساخت را انجام می دهید، tardis.dat در target-files.zip به عنوان RADIO/tardis.dat ذخیره می شود. می توانید چند بار با add-radio-file تماس بگیرید تا هر تعداد فایلی که می خواهید اضافه کنید.

ماژول پایتون

برای گسترش ابزارهای انتشار، یک ماژول پایتون بنویسید (باید releasetools.py نامگذاری شود) که ابزارها در صورت وجود می توانند آن را فراخوانی کنند. مثال:

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"));""")

یک تابع جداگانه مورد تولید یک بسته OTA افزایشی را کنترل می کند. برای این مثال، فرض کنید فقط زمانی که فایل tardis.dat بین دو بیلد تغییر کرده است باید tardis را دوباره برنامه ریزی کنید.

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"));""")

توابع ماژول

شما می توانید توابع زیر را در ماژول ارائه دهید (فقط آنهایی را که نیاز دارید اجرا کنید).

FullOTA_Assertions()
نزدیک به شروع تولید OTA کامل فراخوانی شد. این مکان خوبی برای اظهار نظر در مورد وضعیت فعلی دستگاه است. دستورات اسکریپتی که تغییراتی را در دستگاه ایجاد می کنند، منتشر نکنید.
FullOTA_InstallBegin()
پس از گذراندن تمام اظهارات در مورد وضعیت دستگاه، اما قبل از ایجاد هرگونه تغییر، فراخوانی شد. می‌توانید دستوراتی را برای به‌روزرسانی‌های خاص دستگاه صادر کنید که باید قبل از تغییر هر چیز دیگری در دستگاه اجرا شوند.
FullOTA_InstallEnd()
در پایان تولید اسکریپت، پس از ارسال دستورات اسکریپت برای به روز رسانی بوت و پارتیشن های سیستم، فراخوانی می شود. همچنین می‌توانید دستورات اضافی را برای به‌روزرسانی‌های خاص دستگاه صادر کنید.
IncrementalOTA_Assertions()
مشابه FullOTA_Assertions() است اما هنگام تولید بسته به روز رسانی افزایشی فراخوانی می شود.
IncrementalOTA_VerifyBegin()
پس از گذراندن همه اظهارات در مورد وضعیت دستگاه، اما قبل از ایجاد هرگونه تغییر، تماس گرفته شد. می‌توانید دستوراتی را برای به‌روزرسانی‌های خاص دستگاه صادر کنید که باید قبل از تغییر هر چیز دیگری در دستگاه اجرا شوند.
IncrementalOTA_VerifyEnd()
در پایان مرحله راستی‌آزمایی فراخوانی می‌شود، زمانی که اسکریپت تأیید فایل‌هایی را که قرار است لمس کند دارای محتوای اولیه مورد انتظار هستند، به پایان رسید. در این مرحله هیچ چیز روی دستگاه تغییر نکرده است. همچنین می‌توانید کدی را برای تأییدهای اضافی مربوط به دستگاه ارسال کنید.
IncrementalOTA_InstallBegin()
پس از فراخوانی فایل‌هایی که باید وصله شوند، تأیید شده است که وضعیت قبل از مورد انتظار را دارند، اما قبل از ایجاد هرگونه تغییری. می‌توانید دستوراتی را برای به‌روزرسانی‌های خاص دستگاه صادر کنید که باید قبل از تغییر هر چیز دیگری در دستگاه اجرا شوند.
IncrementalOTA_InstallEnd()
مشابه بسته OTA کامل خود، این در پایان تولید اسکریپت پس از ارسال دستورات اسکریپت برای به روز رسانی بوت و پارتیشن های سیستم فراخوانی می شود. همچنین می‌توانید دستورات اضافی را برای به‌روزرسانی‌های خاص دستگاه صادر کنید.

توجه: در صورت قطع برق دستگاه، نصب OTA ممکن است از ابتدا مجدداً راه اندازی شود. برای مقابله با دستگاه هایی که این دستورات قبلاً به طور کامل یا جزئی اجرا شده اند، آماده باشید.

توابع را به اشیاء اطلاعاتی منتقل کنید

توابع را به یک شی اطلاعات واحد که حاوی موارد مفید مختلفی است، منتقل کنید:

  • info.input_zip . (فقط OTAهای کامل) شی zipfile.ZipFile برای ورودی target-files .zip.
  • info.source_zip . (فقط OTAهای افزایشی) شی zipfile.ZipFile برای منبع target-files .zip (بیلد از قبل روی دستگاه زمانی که بسته افزایشی در حال نصب است).
  • info.target_zip . (فقط OTA های افزایشی) شی zipfile.ZipFile برای فایل های هدف .zip (بیلد بسته افزایشی روی دستگاه قرار می دهد).
  • info.output_zip . بسته در حال ایجاد؛ یک شی zipfile.ZipFile برای نوشتن باز شد. از common.ZipWriteStr(info.output_zip، نام فایل ، داده ) برای افزودن یک فایل به بسته استفاده کنید.
  • info.script . شی اسکریپت که می توانید دستورات را به آن اضافه کنید. برای خروجی متن به اسکریپت info.script.AppendExtra( script_text ) فراخوانی کنید. اطمینان حاصل کنید که متن خروجی با یک نقطه ویرگول به پایان می رسد تا با دستورات صادر شده پس از آن اجرا نشود.

برای جزئیات در مورد شی اطلاعات، به مستندات بنیاد نرم افزار پایتون برای بایگانی های ZIP مراجعه کنید.

محل ماژول را مشخص کنید

محل اسکریپت releasetools.py دستگاه خود را در فایل BoardConfig.mk خود مشخص کنید:

device/yoyodyne/tardis/BoardConfig.mk
 [...]

TARGET_RELEASETOOLS_EXTENSIONS := device/yoyodyne/tardis

اگر TARGET_RELEASETOOLS_EXTENSIONS تنظیم نشده باشد، به طور پیش‌فرض روی دایرکتوری $(TARGET_DEVICE_DIR)/../common ( device/yoyodyne/common در این مثال) تنظیم می‌شود. بهتر است مکان اسکریپت releasetools.py را به صراحت تعریف کنید. هنگام ساختن دستگاه tardis، اسکریپت releasetools.py در فایل .zip target-files ( META/releasetools.py ) گنجانده می شود.

وقتی ابزارهای انتشار را اجرا می کنید (یا img_from_target_files یا ota_from_target_files )، اسکریپت releasetools.py در target-files .zip، در صورت وجود، بر اسکریپت درخت منبع Android ترجیح داده می شود. همچنین می‌توانید با استفاده از گزینه -s (یا --device_specific ) مسیر برنامه‌های افزودنی خاص دستگاه را که در اولویت قرار می‌گیرد، به صراحت مشخص کنید. این به شما امکان می‌دهد خطاها را تصحیح کنید و تغییراتی را در پسوندهای releasetools ایجاد کنید و آن تغییرات را در فایل‌های هدف قدیمی اعمال کنید.

اکنون، وقتی ota_from_target_files اجرا می کنید، به طور خودکار ماژول مخصوص دستگاه را از فایل .zip target_files برمی دارد و هنگام تولید بسته های OTA از آن استفاده می کند:

./build/make/tools/releasetools/ota_from_target_files \
    -i PREVIOUS-tardis-target_files.zip \
    dist_output/tardis-target_files.zip \
    incremental_ota_update.zip

از طرف دیگر، هنگام اجرای ota_from_target_files ، می‌توانید پسوندهای خاص دستگاه را مشخص کنید.

./build/make/tools/releasetools/ota_from_target_files \
    -s device/yoyodyne/tardis \
    -i PREVIOUS-tardis-target_files.zip \
    dist_output/tardis-target_files.zip \
    incremental_ota_update.zip

توجه: برای فهرست کامل گزینه‌ها، به نظرات ota_from_target_files در build/make/tools/releasetools/ota_from_target_files مراجعه کنید.

مکانیسم بارگذاری جانبی

Recovery دارای مکانیزم sideloading برای نصب دستی بسته به روز رسانی بدون بارگیری آن از طریق هوا توسط سیستم اصلی است. Sideloading برای اشکال زدایی یا ایجاد تغییرات در دستگاه هایی که نمی توان سیستم اصلی را بوت کرد مفید است.

از لحاظ تاریخی، بارگذاری جانبی از طریق بارگذاری بسته‌ها از کارت SD دستگاه انجام شده است. در مورد دستگاهی که بوت نمی شود، بسته را می توان با استفاده از رایانه دیگری روی کارت SD قرار داد و سپس کارت SD را در دستگاه قرار داد. برای قرار دادن دستگاه‌های Android بدون حافظه خارجی قابل جابجایی، بازیابی از دو مکانیسم اضافی برای بارگذاری جانبی پشتیبانی می‌کند: بارگیری بسته‌ها از پارتیشن کش و بارگیری آنها از طریق USB با استفاده از adb.

برای فراخوانی هر مکانیزم بار جانبی، متد Device::InvokeMenuItem() دستگاه شما می تواند مقادیر زیر BuiltinAction را برگرداند:

  • APPLY_EXT . یک بسته به‌روزرسانی را از حافظه خارجی بارگیری کنید (دایرکتوری /sdcard ). Recovery.fstab شما باید نقطه اتصال /sdcard را مشخص کند. این در دستگاه هایی که کارت SD را با یک Symlink to /data (یا برخی از مکانیسم های مشابه) تقلید می کنند قابل استفاده نیست. /data به طور معمول در دسترس بازیابی نیستند زیرا ممکن است رمزگذاری شود. UI Recovery منوی پرونده های .zip را در /sdcard نشان می دهد و به کاربر اجازه می دهد تا یکی را انتخاب کند.
  • Applice_cache . مشابه بارگیری یک بسته از /sdcard به جز اینکه فهرست /cache (که همیشه در دسترس بازیابی است ) استفاده می شود. از سیستم معمولی ، /cache فقط توسط کاربران ممتاز قابل نوشتن است ، و اگر دستگاه قابل بوت نباشد ، دایرکتوری /cache به هیچ وجه نمی توان نوشت (که این مکانیزم ابزار محدود را ایجاد می کند).
  • Apply_adb_sideload . به کاربر اجازه می دهد تا از طریق کابل USB و ابزار توسعه ADB بسته ای را به دستگاه ارسال کند. هنگامی که این مکانیسم فراخوانی می شود ، بازیابی نسخه مینی خود را از ADBD Daemon شروع می کند تا ADB را در یک کامپیوتر میزبان متصل با آن صحبت کند. این نسخه مینی فقط از یک دستور واحد پشتیبانی می کند: adb sideload filename . پرونده نامگذاری شده از دستگاه میزبان به دستگاه ارسال می شود ، که سپس آن را تأیید و نصب می کند دقیقاً مثل اینکه در محل ذخیره محلی بوده است.

چند احتیاط:

  • فقط حمل و نقل USB پشتیبانی می شود.
  • اگر بازیابی شما به طور عادی ADBD را اجرا کند (معمولاً در مورد UserDebug و Eng درست می کند) ، در حالی که دستگاه در حالت Sideload ADB قرار دارد خاموش می شود و هنگامی که ADB Sideload دریافت یک بسته را به پایان رساند ، مجدداً راه اندازی می شود. در حالی که در حالت ADB Sideload ، هیچ دستورات ADB به غیر از کار sideload ( logcat ، reboot ، push ، pull ، shell و غیره وجود ندارد. همه شکست می خورند).
  • شما نمی توانید از حالت Sideload ADB در دستگاه خارج شوید. برای سقط جنین ، می توانید به عنوان بسته ارسال /dev/null (یا هر چیز دیگری که یک بسته معتبر نیست) ارسال کنید و سپس دستگاه نتواند آن را تأیید کرده و روش نصب را متوقف کند. روش CheckKey() همچنان برای KeyPresses فراخوانی خواهد شد ، بنابراین می توانید یک دنباله کلیدی ارائه دهید که دستگاه را مجدداً راه اندازی می کند و در حالت Sideload ADB کار می کند.