الرمز الخاص بالجهاز

يشتمل نظام الاسترداد على عدة خطافات لإدخال الرمز الخاص بالجهاز بحيث يمكن الوصول عبر الهواء ويمكن أن تؤدي التحديثات أيضًا إلى تحديث أجزاء من الجهاز غير نظام Android (مثل النطاق الأساسي). أو معالج لاسلكي).

تخصِّص الأقسام والأمثلة التالية جهاز tardis الذي تم إنتاجه من قِبل مورّد yoyodyne

خريطة التقسيم

بدءًا من الإصدار Android 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 أعلى جهاز فلاش MTD. "الجهاز" أن يكون باسم قسم MTD ويجب أن تظهر في /proc/mtd.
هدف
جزء MTD الأولي، يُستخدم في الأقسام القابلة للتشغيل، مثل التشغيل والاسترداد. لا يشمل هذا الشهر إذا كان قد تم تثبيته بالفعل، ولكن يتم استخدام نقطة التثبيت كمفتاح لتحديد موقع القسم. "الجهاز" يجب أن يكون اسمًا لقسم MTD في /proc/mtd.
ext4
يشير ذلك المصطلح إلى نظام ملفات ext4 أعلى جهاز فلاش eMMc. "الجهاز" يجب أن يكون مسار جهاز الحظر.
الإرسال عبر البريد الإلكتروني
جهاز أولي لكتلة eMMc، يُستخدم في الأقسام القابلة للتشغيل، مثل "التشغيل والاسترداد". مشابه لـ نوع mtd، لا يتم تثبيت eMMc أبدًا، ولكن تُستخدم سلسلة نقطة التثبيت لتحديد موقع الجهاز الموجود في الجدول.
ملف vfat
نظام ملفات FAT أعلى جهاز كتلي، وعادةً ما يكون مخزنًا خارجيًا مثل بطاقة SD تشير رسالة الأشكال البيانية الجهاز هو جهاز التخزين الكتلي؛ الجهاز 2 هو جهاز من النوع الثاني يحاول النظام تثبيته إذا تعذُّر تثبيت الجهاز الأساسي (للتوافق مع بطاقات SD التي قد يتعذر أو لا يتم ذلك بتنسيق جدول تقسيم).

يجب تثبيت كل الأقسام في الدليل الجذر (أي يجب أن تكون قيمة نقطة التثبيت تبدأ بشرطة مائلة ولا تحتوي على أي شرطة مائلة أخرى). لا ينطبق هذا القيد إلا على التثبيت. وأنظمة الملفات في عملية الاسترداد؛ فإن النظام الرئيسي مجاني لتثبيتها في أي مكان. الأدلة يجب أن تكون /boot و/recovery و/misc أنواعًا أولية. (mtd أو emmc)، بينما تضم الأدلة /system و/data /cache و/sdcard (إذا كان ذلك متاحًا) يجب أن يكونا نوعي نظام ملفات (yaffs2 أو ext4 أو vfat).

بدءًا من الإصدار Android 3.0، سيحصل ملفrecovery.fstab على حقل اختياري إضافي، الخيارات. الخيار الوحيد المحدد حاليًا هو length ، الذي يتيح لك لتحديد طول القسم. تُستخدَم هذه المدة عند إعادة تنسيق القسم. (على سبيل المثال، لقسم userdata أثناء عملية حجب البيانات/إعادة الضبط على الإعدادات الأصلية، أو جزء النظام أثناء تثبيت حزمة OTA كاملة). إذا كانت قيمة الطول سالبة، ثم يتم تحديد الحجم المطلوب تنسيقه بإضافة قيمة الطول إلى حجم القسم الحقيقي. بالنسبة مثال، تعيين "length=-16384" يعني أن آخر 16 ألف ثانية من هذا القسم لن تكون يتم استبداله عند إعادة تنسيق هذا القسم. ويدعم ذلك ميزات مثل تشفير قسم userdata (حيث يتم تخزين بيانات التشفير في نهاية القسم ).

ملاحظة: إنّ حقلَي device2 وoptions اختياريَين، ما يؤدي إلى إنشاء والغموض في التحليل. إذا كان الإدخال في الحقل الرابع على السطر يبدأ بـ "/" فسيتم اعتباره إدخال device2 ؛ إذا لم يبدأ الإدخال بـ "/" الحرف، فإنه يعتبر حقل خيارات.

الرسوم المتحركة عند بدء التشغيل

يمكن للشركات المصنّعة للأجهزة تخصيص الصور المتحركة التي تظهر عندما يستخدم جهاز Android قيد التشغيل. للقيام بذلك، قم بإنشاء ملف .zip منظمًا وموقعًا وفقًا المواصفات في تنسيق التمهيد:

بالنسبة أجهزة Android Things، يمكنك تحميل الملف المضغوط في وحدة تحكم Android Things لتضمين الصور في المنتج المحدد.

ملاحظة: يجب أن تستوفي هذه الصور إرشادات وضع العلامة التجارية على Android. بالنسبة إلى إرشادات العلامة التجارية، يُرجى الرجوع إلى قسم Android شركاء التسويق المحتوى الرئيسي.

واجهة المستخدم المخصصة لاسترداد الحساب

للتوافق مع الأجهزة التي تتوفّر بها معدّات مختلفة (الأزرار المادية ومصابيح LED والشاشات وما إلى ذلك)، يمكنك تخصيص واجهة الاسترداد لعرض الحالة والوصول إلى واجهة برمجة التطبيقات التي يتم تشغيلها يدويًا الميزات المخفية لكل جهاز.

ويتمثل هدفك في إنشاء مكتبة ثابتة صغيرة تحتوي على كائنات C++ لتوفير بوظيفة خاصة بالجهاز. الملف يتم استخدام bootable/recovery/default_device.cpp بشكل تلقائي، ويحقق أداءً جيدًا نقطة البداية لنسخها عند كتابة نسخة من هذا الملف لجهازك.

ملاحظة: قد تظهر لك رسالة مفادها عدم الطلب هنا. للإيقاف/التفعيل نص، اضغط مع الاستمرار على زر التشغيل أثناء الضغط على زر رفع الصوت. وإذا لم تكن أجهزتك مثبّتة كلا الزرين، اضغط مع الاستمرار على أي زر لتبديل النص.

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

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

وظيفتا العناوين والعناصر

تتطلّب فئة الجهاز دوال لعرض العناوين والعناصر التي تظهر في مجموعة العناوين المخفية. قائمة الاسترداد. تصف العناوين كيفية تشغيل القائمة (أي عناصر التحكم لتغيير/تحديد العنصر المحدد).

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

ملاحظة: يتم اقتطاع الأسطر الطويلة (غير الملتفة)، لذا حافظ على عرض شاشة الجهاز في الاعتبار.

تخصيص مفتاح التحقّق

بعد ذلك، حدد تنفيذ RecoveryUI جهازك. يفترض هذا المثال أن tardis فيه شاشة، لذلك يمكنك اكتساب نسخ من الأجهزة تنفيذ واجهة مستخدم استرداد الشاشة (يُرجى الاطّلاع على التعليمات بشأن الأجهزة التي لا تحتوي على شاشة). إن الدالة الوحيدة بتخصيص من 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() هو بغض النظر عما يحدث في بقية عملية الاسترداد: عندما يتم إيقاف القائمة، وعندما كان قيد التشغيل أو أثناء تثبيت الحزمة أو أثناء مسح بيانات المستخدم أو ما إلى ذلك. يمكن أن يعرض أحد الخيارات الأربعة الثوابت:

  • التبديل. التبديل بين تشغيل أو إيقاف عرض القائمة و/أو سجلّ النص
  • إعادة التشغيل. إعادة تشغيل الجهاز فورًا
  • تجاهل. تجاهل الضغط على المفتاح هذا
  • طلب. ضع الضغط على المفتاح هذا في قائمة انتظار ليتم استخدامه بشكل متزامن (أي من خلال عملية الاسترداد). نظام القائمة إذا كانت الشاشة مُفعَّلة)

يتم استدعاء CheckKey() في كل مرة يتبعها حدث مفتاح لأسفل بعد حدث رئيسي نفس المفتاح. (ينتج عن تسلسل الأحداث A-down B-down B-up A-up فقط في يتم طلب CheckKey(B)). بإمكان "CheckKey() " الاتصال IsKeyPressed()، لمعرفة ما إذا تم الضغط باستمرار على مفاتيح أخرى. (في ما سبق تسلسل الأحداث الرئيسية، إذا استدعى CheckKey(B) IsKeyPressed(A) كانت ستكون صحيحة).

بإمكان 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، يمكنك ضبط المتغيّر animation_fps للتحكّم في السرعة لقطات في الثانية من الصور المتحركة.

ملاحظة: يسمح لك نص interlace-frames.py البرمجي الحالي بما يلي: تخزين معلومات animation_fps في الصورة نفسها في الإصدارات السابقة من كان على Android ضبط animation_fps بنفسك.

لضبط المتغيّر animation_fps، عليك إلغاء ScreenRecoveryUI::Init() في فئتك الفرعية. اضبط القيمة، ثم استدعِ parent Init() لإكمال الإعداد. القيمة التلقائية (20 لقطة في الثانية) مع صور الاسترداد الافتراضية؛ فعند استخدام هذه الصور، لن تحتاج إلى تقديمها دالة Init(). للحصول على تفاصيل حول الصور، راجِع صور واجهة المستخدم المخصّصة لاسترداد الحساب:

فئة الجهاز

بعد الحصول على تنفيذ RecoveryUI، حدد فئة جهازك (المصنفة الفرعية من فئة الجهاز المدمجة). يُفترض أن ينشئ مثيلاً واحدًا لفئة واجهة المستخدم ويعرض من الدالة GetUI():

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

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

    RecoveryUI* GetUI() { return ui; }

بدء الاسترداد

يتم استدعاء طريقة StartRecovery() في بداية عملية الاسترداد، بعد أن تتضمن واجهة المستخدم وبعد تحليل الوسيطات، ولكن قبل اتخاذ أي إجراء تم التقاطها. لا يفعل التنفيذ التلقائي أي تأثير، لذلك لن تحتاج إلى ذكره في إذا لم يكن عليك اتخاذ أي إجراء:

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

توفير قائمة استرداد الحساب وإدارتها

يستدعي النظام طريقتين للحصول على قائمة أسطر العنوان وقائمة العناصر. في هذه الدورة، تُرجع الصفائف الثابتة المحددة في أعلى الملف:

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

مفتاح القائمة المقبض

بعد ذلك، قم بتوفير الدالة 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() لكائن واجهة المستخدم)، والحالة الحالية للقائمة/سجل النص مستوى الرؤية. تكون القيمة المعروضة عددًا صحيحًا. وإذا كانت القيمة 0 أو أعلى، فسيتم اعتبارها موضع عنصر في القائمة، والذي يتم استدعاؤه على الفور (راجع طريقة واحدة (InvokeMenuItem()) أدناه). بخلاف ذلك، يمكن أن يكون أحد الأسباب التالية: الثوابت المحددة مسبقًا:

  • khighlightUp: نقل تمييز القائمة إلى العنصر السابق
  • khighlightDown: نقل تمييز القائمة إلى العنصر التالي
  • kInvokeItem. استدعاء العنصر الذي تم تمييزه حاليًا
  • kNoAction: عدم اتخاذ أي إجراء عند الضغط على مفتاح

وفقًا لما تشير إليه الوسيطة المرئية، يتم استدعاء HandleMenuKey() حتى إذا كانت القائمة غير مرئية. على عكس CheckKey()، لا يتم استدعاؤه أثناء تنفيذ عملية الاسترداد شيء مثل مسح البيانات أو تثبيت حزمة — لا يتم طلبه إلا عندما يكون الاسترداد في وضع الخمول وفي انتظار المدخلات.

آليات كرة التعقّب

إذا كان جهازك يحتوي على آلية إدخال تشبه كرة التعقب (يتم إنشاء أحداث إدخال بالنوع EV_REL والرمز REL_Y)، فإن عملية الاسترداد تجمع بين المفتاحين KEY_UP وKEY_DOWN عند الضغط على جهاز إدخال يشبه كرة التعقب يبلغ عن الحركة في المحور ص. كل ما عليك فعله هو تعيين KEY_UP KEY_DOWN إلى إجراءات القائمة. لا يحدث هذا التعيين مع CheckKey()، لذلك لا يمكنك استخدام حركات كرة التعقب كعوامل تشغيل لإعادة التشغيل أو تبديل الشاشة.

مفاتيح التعديل

للتحقّق من المفاتيح التي يتم الضغط مع الاستمرار عليها كمفاتيح تعديل، يمكنك طلب الطريقة IsKeyPressed() . لكائن واجهة المستخدم الخاص بك. على سبيل المثال، في بعض الأجهزة، قد يؤدي الضغط على 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
        }
        ...
    }

ملاحظة: إذا كانت قيمة visible خاطئة، فلا معنى إرجاع القيمة الخاصة. القيم التي تعالج القائمة (نقل التمييز واستدعاء العنصر المميّز) بما أنّ المستخدم لا يمكنه مشاهدة التمييز. ومع ذلك، يمكنك عرض القيم إذا أردت.

استدعاء عناصر القائمة

بعد ذلك، قدِّم الطريقة 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 لإخبار النظام باتخاذ هذا الإجراء. إجراء (أو عضو NO_ACTION إذا كنت تريد أن يتخذ النظام أي إجراء). هذا هو المكان توفير وظائف استرداد إضافية غير الميزات المتوفرة في النظام: يمكنك إضافة عنصر إلى القائمة، ويمكنك تنفيذها هنا عند استدعاء عنصر القائمة هذا، وعرض NO_ACTION حتى يتمكن النظام لا يفعل أي شيء آخر.

يحتوي BuiltinAction على القيم التالية:

  • NO_ACTION. عدم اتّخاذ أي إجراء:
  • إعادة التشغيل. اخرج من وضع الاسترداد وأعِد تشغيل الجهاز بشكل طبيعي.
  • APPLY_EXT وAPPLY_CACHE وAPPLY_ADB_SIDELOAD. تثبيت حزمة تحديثات من تطبيقات متنوعة مكانًا. ولمعرفة التفاصيل، يُرجى الاطّلاع على مقالة التحميل من مصدر غير معروف.
  • WIPE_CACHE. أعِد تنسيق قسم ذاكرة التخزين المؤقت فقط. ليس هناك تأكيد مطلوب لأنّ ذلك غير ضارة نسبيًا.
  • WIPE_DATA: إعادة تنسيق أقسام بيانات المستخدم وذاكرة التخزين المؤقت، والمعروفة أيضًا باسم بيانات المصنع إعادة تعيين. يُطلب من المستخدم تأكيد هذا الإجراء قبل المتابعة.

الطريقة الأخيرة، WipeData()، هي اختيارية ويتم طلبها عند حجب بيانات البيانات. (إما من الاسترداد عبر القائمة أو عندما يختار المستخدم إجراء إعادة الضبط على الإعدادات الأصلية من النظام الرئيسي). يتم استدعاء هذه الطريقة قبل بيانات المستخدم وذاكرة التخزين المؤقت يتم مسح الأقسام. إذا كان جهازك يخزِّن بيانات المستخدمين في أي مكان آخر بخلاف هذين الاثنين الأقسام، فيجب محوها هنا. يجب عليك إرجاع 0 للإشارة إلى النجاح للإخفاق، على الرغم من أنه يتم حاليًا تجاهل القيمة المعروضة. بيانات المستخدم وذاكرة التخزين المؤقت تُحسَب البيانات سواء نجح الأمر أم فشلت.

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

صنع جهاز

أخيرًا، ضمِّن بعض النصوص النموذجية في نهاية ملفrecovery_ui.cpp في make_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

صور واجهة المستخدم المخصّصة لاسترداد الحساب

تتكوّن واجهة مستخدم الاسترداد من صور. من الناحية المثالية، لا يتفاعل المستخدمون مطلقًا مع واجهة المستخدم: وأثناء التحديث العادي، يبدأ الهاتف في تشغيل الاسترداد، ويملأ شريط تقدم التثبيت، ثم يعود إلى النظام الجديد بدون تدخل من المستخدم. في حالة تشغيل النظام في التحديث، فإن الإجراء الوحيد الذي يمكن للمستخدم اتخاذه هو الاتصال بخدمة العملاء.

إنّ استخدام واجهة تتضمّن صورًا فقط تغنيك عن الحاجة إلى الأقلمة. ومع ذلك، اعتبارًا من الإصدار Android 5.0، يمكن أن يعرض "تحديث" سلسلة من النصوص (مثلاً "جارٍ تثبيت تحديث النظام...") مع الصورة. لمعرفة التفاصيل، يُرجى الاطّلاع على نص الاسترداد المترجَم.

Android 5.0 والإصدارات الأحدث

تستخدم واجهة المستخدم المخصصة لاسترداد الحساب على الإصدار 5.0 من نظام التشغيل Android والإصدارات الأحدث صورتَين رئيسيتَين: صورة الخطأ. وحركة التركيب.

صورة تم عرضها أثناء حدوث خطأ في عبر الهواء

الشكل 1. icon_error.png

صورة تظهر أثناء التثبيت عبر الهواء

الشكل 2. icon_installing.png

ويتم تمثيل الرسم المتحرك لتثبيت الصورة كصورة PNG واحدة بإطارات مختلفة من رسم متحرك متداخل مع الصف (وهذا هو سبب ظهور الشكل 2 مضغوط). على سبيل المثال، بالنسبة إلى رسم متحرك يتكون من سبعة إطارات مقاس 200×200، قم بإنشاء صورة واحدة بحجم 200×1400 حيث يكون الإطار الأول هو الصفوف 0 و7 14، 21، ...؛ الإطار الثاني هو الصفوف 1، 8، 15، 22، ...؛ وما إلى ذلك. تتضمن الصورة المدمجة مقطع نصي يشير إلى عدد إطارات الرسوم المتحركة وعدد الإطارات في الثانية (لقطات في الثانية). تأخذ أداة bootable/recovery/interlace-frames.py مجموعة من إطارات الإدخال وتدمجها في الصورة المُركبة اللازمة التي يستخدمها الاسترداد.

تتوفر الصور التلقائية بكثافة مختلفة وتقع في bootable/recovery/res-$DENSITY/images (مثال: bootable/recovery/res-hdpi/images). لاستخدام صورة ثابتة أثناء التركيب، فأنت تحتاج فقط إلى تقديم صورة icon_installing.png وتعيين عدد الإطارات في الحركة إلى 0 (رمز الخطأ ليس متحركًا؛ إنه دائمًا صورة ثابتة).

Android 4.x والإصدارات الأقدم

تستخدم واجهة المستخدم المخصصة لاسترداد الحسابات الإصدار 4.x من نظام التشغيل Android والإصدارات الأقدم صورة الخطأ (الموضحة أعلاه) رسم متحرك لتثبيت الصورة المتحركة إلى جانب عدة صور متراكبة:

صورة تظهر أثناء التثبيت عبر الهواء

الشكل 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. النص المترجَم لرسائل الاسترداد

يمكن أن يعرض نص الاسترداد الرسائل التالية:

  • جارٍ تثبيت تحديث النظام...
  • خطأ!
  • جارٍ محو البيانات... (عند إجراء مسح بيانات/إعادة تعيين على الإعدادات الأصلية)
  • عدم توفُّر أمر (عند تشغيل المستخدم لعملية الاسترداد يدويًا)

يعرض تطبيق Android في bootable/recovery/tools/recovery_l10n/ باللغات المحلية من الرسالة وينشئ الصورة المركبة. للحصول على تفاصيل عن استخدام هذا التطبيق، يُرجى الرجوع إلى التعليقات في bootable/recovery/tools/recovery_l10n/src/com/android/recovery_l10n/Main.java

عندما يبدأ المستخدم عملية الاسترداد يدويًا، قد لا تكون اللغة متاحة أو لا يتوفر نص المعروضة. لا تجعل الرسائل النصية بالغة الأهمية لعملية الاسترداد.

ملاحظة: الواجهة المخفية التي تعرض رسائل السجل وتسمح للمستخدم وأن الإجراءات المحددة من القائمة متاحة باللغة الإنجليزية فقط.

أشرطة التقدم

وقد تظهر أشرطة التقدّم تحت الصورة الرئيسية (أو الصورة المتحركة). يتم إنشاء شريط التقدم بواسطة الجمع بين صورتَين للإدخال، على أن تكونا بالحجم نفسه:

شريط تقدّم فارغ

الشكل 9.gress_impression.png

شريط التقدّم الكامل

الشكل 10.gress_fill.png

يتم عرض الطرف الأيسر لصورة الملء بجوار الطرف الأيمن من صورة فارغة لإظهار شريط التقدم. موضع الحدود بين الاثنين الصور للإشارة إلى التقدم. على سبيل المثال، باستخدام أزواج صور الإدخال المذكورة أعلاه، العرض:

شريط تقدّم بنسبة %1

الشكل 11. شريط تقدّم على %1

شريط التقدّم عند %10

الشكل 12. شريط تقدّم بنسبة %10

شريط تقدّم بنسبة %50

الشكل 13. شريط تقدّم بنسبة %50

يمكنك تقديم نُسخ خاصة بكل جهاز من هذه الصور عن طريق وضعها في (في هذا مثال) device/yoyodyne/tardis/recovery/res/images . يجب أن تتطابق أسماء الملفات مع الأسماء الواردة أعلاه. عند العثور على ملف في هذا الدليل، نظام التصميم هذا أفضل من الصورة الافتراضية المقابلة. تنسيقات PNG فقط بنموذج أحمر أخضر أزرق أو ويتوفّر التنسيق RGBA مع عمق ألوان 8 بت.

ملاحظة: في الإصدار Android 5.x، إذا كانت اللغة معروفة بالاسترداد من اليمين إلى اليسار (العربية والعبرية وغيرها)، يتم ملء شريط التقدّم من اليمين إلى غادر.

الأجهزة التي لا تحتوي على شاشات

لا تحتوي جميع أجهزة Android على شاشات. إذا كان الجهاز بلا واجهة مستخدم رسومية أو كان يتضمّن التي تعمل بالصوت فقط، قد تحتاج إلى إجراء تخصيص أكثر شمولاً لواجهة المستخدم المخصصة لاسترداد الحساب. بدلاً من ذلك من إنشاء فئة فرعية من ScreenRecoveryUI، فصنفها الرئيسي RecoveryUI مباشرة

تتضمن RecoveryUI طرقًا للتعامل مع عمليات واجهة المستخدم ذات المستوى الأدنى مثل "تبديل العرض" "تحديث شريط التقدم" و"عرض القائمة" و"تغيير تحديد القائمة" وما إلى ذلك. يمكنك تجاوز هذه لتوفير واجهة مناسبة لجهازك. ربما يحتوي جهازك على مصابيح LED حيث يمكنك استخدام ألوان أو أنماط وامضة مختلفة للإشارة إلى الحالة، أو ربما يمكنك لعب الصوت. (ربما لا تريد دعم قائمة أو وضع "عرض النص" على الإطلاق؛ يمكنك منع الوصول إليها باستخدام CheckKey() عمليات تنفيذ HandleMenuKey() التي لا تؤدي مطلقًا إلى تشغيل الشاشة أو اختيار قائمة عنصر واحد. في هذه الحالة، فإن العديد من طرق RecoveryUI التي تحتاج إلى توفيرها يمكن أن تكون فارغة العود).

يمكنك الانتقال إلى bootable/recovery/ui.h للاطّلاع على بيان RecoveryUI لمعرفة الطرق التي يجب عليك دعمها. تُعد RecoveryUI مجرّدة بعض الطرق التي تكون افتراضية بالكامل ويجب توفيرها من خلال — لكنها تحتوي على التعليمات البرمجية للقيام بمعالجة المدخلات الرئيسية. يمكنك إلغاء ذلك أيضًا، إذا لم يكن جهازك يحتوي على مفاتيح أو كنت تريد معالجتها بشكل مختلف.

محدّث

يمكنك استخدام رمز خاص بالجهاز في تثبيت حزمة التحديث من خلال تقديم دوال الإضافات التي يمكن استدعاؤها من داخل النص البرمجي لأداة التحديث. إليك عيّنة لوظيفة جهاز tardis:

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

لم يتم تقييم الوسيطات في وقت استدعاء الدالة، وهي دالة المنطق الذي يتم تقييمه وعدد المرات التي يتم تقييمها. وبالتالي، يمكنك استخدام إضافة الدوال لتنفيذ هياكل التحكم الخاصة بك. Call Evaluate() للتقييم وسيطة Expr* ، مع عرض Value*. إذا Evaluate() القيمة "NULL"، يجب عليك تحرير أي موارد تمتلكها وإرجاع "NULL" (فارغ) على الفور يلغي مكدس edify). بخلاف ذلك، ستحصل على ملكية القيمة التي تم إرجاعها مسئولين عن استدعاء FreeValue() عليه.

لنفترض أنّ الدالة تحتاج إلى وسيطتَين: مفتاح يتضمّن قيمة سلسلة وثنائي القيمة. الصورة. يمكنك قراءة وسيطات مثل هذه:

   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* - عضو البيانات تحديدًا.

في هذه الحالة، تريد إرجاع قيمة صواب أو خطأ للإشارة إلى النجاح. تذكر بأن السلسلة الفارغة هي false وجميع السلاسل الأخرى هي true. إِنْتَ يجب أن لإنشاء كائن قيمة مع نسخة اختبارية للسلسلة الثابتة المراد عرضها، سيُجري المتصل 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() إلى التفاف سلسلة في كائن "قيمة" جديد. استخدمها لكتابة التعليمة البرمجية أعلاه بإيجاز أكثر:

   FreeValue(key);
    FreeValue(image);

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

لجذب الدوال إلى أداة الترجمة الفورية، قدِّم الدالة Register_foo حيث يكون foo هو اسم المكتبة الثابتة التي تحتوي على هذا الرمز. يمكنك طلب RegisterFunction() لتسجيل كل وظيفة من وظائف الإضافات. من اصطلاح، قم بتسمية الدوال الخاصة بالجهاز device.whatever المراد تجنبها مع الدوال المضمنة المستقبلية المضافة.

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

يمكنك الآن تهيئة ملف makefile لإنشاء مكتبة ثابتة باستخدام التعليمة البرمجية. (وهذا هو نفسه 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()، الذي يُرجع محتويات الملف المستخرَج من حزمة التحديث ككائن ثنائي كبير (blob) لإنتاج الوسيطة الثانية إلى دالة الإضافة الجديدة.

إنشاء حزمة عبر اتصال لاسلكي

يتمثل المكون الأخير في الحصول على أدوات إنشاء حزمة 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 فقط عندما يتم تغيير ملف tardis.dat بين بنيين.

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()
يتم استدعاءه بالقرب من بداية إنشاء التحديث عبر الهواء الكامل. هذه فرصة جيدة لإرسال التأكيدات حول الحالة الحالية للجهاز. ولا تصدر أوامر نصوص برمجية تُجري تغييرات على الخاص بك.
FullOTA_InstallBegin()
يتم طلب هذه البيانات بعد تمرير جميع التأكيدات حول حالة الجهاز، ولكن قبل إجراء أي تغييرات صناعة البرامج. يمكنك إصدار أوامر لتثبيت التحديثات الخاصة بالجهاز والتي يجب تشغيلها قبل تم تغيير أي شيء آخر على الجهاز.
FullOTA_InstallEnd()
يتم استدعاؤه في نهاية إنشاء النص البرمجي، بعد أوامر النص البرمجي لتحديث نظام التشغيل إصدار أقسام النظام. يمكنك أيضًا إصدار أوامر إضافية التحديثات الخاصة بالجهاز.
IncrementalOTA_Assertions()
تشبه السمة FullOTA_Assertions() ولكن يتم استدعاؤها عند إنشاء زيادة حزمة التحديث.
IncrementalOTA_VerifyBegin()
يتم طلبه بعد تمرير جميع التأكيدات حول حالة الجهاز، ولكن قبل إجراء أي تغييرات صناعة المحتوى. يمكنك إصدار أوامر لتثبيت التحديثات الخاصة بالجهاز والتي يجب تشغيلها قبل أي إصدار من التطبيق. تم تغيير غير ذلك على الجهاز.
IncrementalOTA_VerifyEnd()
يتم طلبه في نهاية مرحلة إثبات الملكية، عند انتهاء النص البرمجي من تأكيد الملفات التي سيستلمها تتضمن محتويات البدء المتوقعة. في هذه المرحلة، لا شيء على تم تغيير جهازك. يمكنك أيضًا إصدار رمز برمجي خاص عمليات التحقق من المعلنين.
IncrementalOTA_InstallBegin()
يتم طلبه بعد التحقق من احتواء الملفات المطلوب تصحيحها على القيمة المتوقعة قبل إجراء أي تغييرات. يمكنك إصدار أوامر تم تغيير التحديثات الخاصة بالجهاز والتي يجب تشغيلها قبل أي شيء آخر على الجهاز.
IncrementalOTA_InstallEnd()
على غرار نظيرتها الكاملة لحزمة OTA، يسمى هذا في نهاية النص البرمجي بعد تحديث أوامر البرنامج النصي لتحديث أقسام النظام والتشغيل المنبعثة. يمكنك أيضًا إصدار أوامر إضافية للحصول على تحديثات خاصة بالجهاز.

ملاحظة: إذا انقطع مصدر الطاقة عن الجهاز، قد تتم إعادة تشغيل تثبيت الجهاز عبر الهواء من البداية. كن مستعدًا للتعامل مع الأجهزة التي يتم تنفيذ هذه الأوامر عليها بالفعل، كليًا أو جزئيًا.

تمرير الدوال إلى كائنات المعلومات

تمرير الدوال إلى كائن معلومات واحد يحتوي على عناصر مفيدة متنوعة:

  • info.input_zip. (جميع وكالات السفر عبر الإنترنت فقط) الكائن zipfile.ZipFile الخاص بـ إدخال ملفات target-files .zip.
  • info.source_zip. (عبر الهواء الإضافي فقط) الكائن zipfile.ZipFile لـ ملفات المصدر المستهدَفة zip. (الإصدار المتوفّر على الجهاز حاليًا عند تثبيت الحزمة التزايدية قيد التثبيت).
  • info.target_zip. (عبر الهواء الإضافي فقط) الكائن zipfile.ZipFile لـ ملف target-files .zip (إصدار الحزمة التزايدية الذي تضعه على الجهاز).
  • info.output_zip. جارٍ إنشاء الحزمة. تم فتح عنصر zipfile.ZipFile . للكتابة. استخدِم شائع.ZipWriteStr(info.output_zip، وfilename، وdata) لإضافة ملف إلى الحزمة.
  • info.script. كائن النص البرمجي الذي يمكنك إلحاق الأوامر به. اتصل info.script.AppendExtra(script_text) لإخراج نص إلى النص البرمجي. التأكد من انتهاء نص الإخراج بفاصلة منقوطة حتى لا يصل إلى الأوامر الصادرة بعد ذلك.

للحصول على تفاصيل عن عنصر المعلومات، يُرجى الرجوع إلى مستندات Python Software Foundation (مؤسسة برمجيات Python) لأرشيفات 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 (META/releasetools.py ).

عند تشغيل أدوات الإصدار (إما img_from_target_files أو ota_from_target_files)، البرنامج النصي releasetools.py في ملف zip .المستهدف، إذا حاليًا، مفضّلاً على شجرة مصادر Android يمكنك أيضًا تحديد المسار إلى الإضافات الخاصة بالجهاز باستخدام -s (أو --device_specific)، الذي يحتل الأولوية القصوى. يمكّنك هذا من وتصحيح الأخطاء وإجراء تغييرات في إضافات Releasetools وتطبيق هذه التغييرات على الإصدار القديم ملفات الهدف.

والآن، عند تشغيل ota_from_target_files، يحتفظ تلقائيًا وحدة خاصة بالجهاز من ملف target_files .zip وتستخدمها عند إنشاء التحديث عبر الهواء الحزم:

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

آلية التحميل من مصدر غير معروف

تشمل عملية الاسترداد آلية التحميل من مصدر غير معروف لتثبيت حزمة التحديث يدويًا بدون وتنزيله عبر شبكة غير سلكيّة من خلال النظام الرئيسي التحميل من مصدر غير معروف مفيد لتصحيح الأخطاء أو إنشاء التغييرات على الأجهزة التي يتعذر تشغيل النظام الرئيسي عليها.

في السابق، كان يتم التثبيت من مصدر غير معروف من خلال تحميل الحزم خارج بطاقة SD على الجهاز. بوصة في حالة جهاز لا يتم تشغيله، فيمكن وضع الحزمة على بطاقة SD باستخدام أداة الكمبيوتر ثم بطاقة SD التي تم إدخالها في الجهاز. لاستيعاب أجهزة Android التي لا تحتوي وحدة تخزين خارجية قابلة للإزالة، يدعم الاسترداد آليتين إضافيتين للتثبيت من مصدر غير معروف: تحميل الحزم من قسم ذاكرة التخزين المؤقت وتحميلها عبر USB باستخدام adb.

لاستدعاء كل آلية من آليات التحميل من مصدر غير معروف، طريقة Device::InvokeMenuItem() في جهازك عرض القيم التالية لـ BuiltinAction:

  • apply_EXT تحميل حزمة تحديث من وحدة تخزين خارجية من مصدر غير معروف ( /sdcard الدليل). يجب أن يحدّد ملفrecovery.fstab نقطة تثبيت /sdcard . هذا هو لا يمكن استخدامها على الأجهزة التي تحاكي بطاقة SD ذات رابط رمزي إلى /data (أو بعض آلية مماثلة). لا يمكن عادةً استرداد الحساب /data لأنّه أن تكون مشفّرة. تعرض واجهة المستخدم المخصصة لاسترداد الحساب قائمة بملفات .zip في /sdcard تسمح للمستخدم باختيار واحد منها.
  • apply_CACHE. يشبه تحميل حزمة من /sdcard باستثناء أنّ يتم استخدام دليل /cache (متاح دائمًا للاسترداد) بدلاً من ذلك. من النظام العادي، لا يمكن الكتابة من خلال /cache إلا من خلال المستخدمين الحاصلين على الامتيازات، وإذا لم يكن الجهاز قابلاً للتشغيل، لا يمكن كتابة دليل /cache إلى على الإطلاق (مما يجعل هذه الآلية ذات فائدة محدودة).
  • apply_ADB_SIDELOAD يسمح للمستخدم بإرسال طرد إلى الجهاز عبر كابل USB أداة تطوير adb. عند استدعاء هذه الآلية، يبدأ الاسترداد في من البرنامج الخفي لـ adbd للسماح لـ adb على كمبيوتر مضيف متصل بالتحدث إليه. هذه الصورة المصغّرة يتوافق الإصدار مع أمر واحد فقط: adb sideload filename. ويتم إرسال الملف المُسمى من الجهاز المضيف إلى الجهاز، الذي يتأكد بعد ذلك من وتثبّته كما لو كانت على وحدة التخزين المحلية.

بعض المحاذير:

  • لا يتم دعم سوى النقل عبر USB.
  • إذا شغَّلت عملية الاسترداد adbd بشكل طبيعي (عادةً ما يكون ذلك صحيحًا في إصدارات userdebug وeng)، فإن ذلك إيقاف التشغيل عندما يكون الجهاز في وضع التحميل الجانبي من خلال adb، وستتم إعادة تشغيله عند استخدام adb انتهى التحميل الجانبي من تلقي حزمة. أثناء استخدام وضع التحميل الجانبي لـ adb، لا توجد أوامر adb أخرى من sideload عمل ( logcat، reboot، push وpull وshell وما إلى ذلك ففشل كل ذلك).
  • لا يمكنك الخروج من وضع التثبيت الجانبي من adb على الجهاز. للإلغاء، يمكنك إرسال /dev/null (أو أي خدمة أخرى لا تُعدّ حزمة صالحة) على أنّها الحزمة لن يتمكّن الجهاز من التحقّق من ذلك ويوقِف إجراء التثبيت. واجهة RecoveryUI في التنفيذ، سيستمر استدعاء طريقة CheckKey() الخاصة بعمليات الضغط على المفاتيح، لذا يمكنك توفير تسلسل للمفاتيح يُعيد تشغيل الجهاز ويعمل في وضع التثبيت الجانبي من adb.