يتضمّن نظام الاسترداد عدة عناصر ربط لإدراج رمز خاص بالجهاز حتى تتمكّن تحديثات OTA أيضًا من تحديث أجزاء من الجهاز غير نظام Android (مثل معالج البث المباشر أو المعالج اللاسلكي).
تخصِّص الأقسام والأمثلة التالية جهاز tardis الذي يُنتجه مورّد yoyodyne.
خريطة التقسيم
اعتبارًا من الإصدار 2.3 من Android، تتيح المنصة استخدام أجهزة فلاش eMMc ونظام الملفات ext4 الذي يعمل على هذه الأجهزة. وهو متوافق أيضًا مع أجهزة الفلاش Memory Technology Device (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 يجب أن يكون "device" هو مسار جهاز التخزين.
- emmc
- جهاز كتلة eMMc غير المُعدَّة، ويُستخدَم للأقسام القابلة للتشغيل، مثل قسم التمهيد وقسم الاسترداد. على غرار نوع mtd، لا يتم تثبيت eMMc مطلقًا، ولكن يتم استخدام سلسلة نقطة التثبيت لتحديد موقع الجهاز في الجدول.
- vfat
-
نظام ملفات FAT على جهاز تخزين بلوكات، وعادةً ما يكون للتخزين الخارجي مثل بطاقة SD DEVICE هو جهاز التخزين، وdevice2 هو جهاز تخزين ثانٍ يحاول النظام تثبيته في حال تعذّر تثبيت الجهاز الأساسي (للتوافق مع بطاقات SD التي قد تتم تنسيقها باستخدام جدول أقسام أو لا تتم تنسيقها).
يجب تركيب جميع الأقسام في الدليل الجذر (أي أنّ قيمة نقطة الربط يجب أن تبدأ بشرطة مائلة ولا تحتوي على أيّ شرطات مائلة أخرى). لا ينطبق هذا القيد إلا على تثبيت أنظمة الملفات في وضع الاسترداد، فالنظام الرئيسي يمكنه تثبيتها في أي مكان. يجب أن تكون الدلائل
/boot
و/recovery
و/misc
من الأنواع الأوّلية (mtd أو emmc)، في حين يجب أن تكون الدلائل/system
و/data
/cache
و/sdcard
(إن توفّرت) من أنواع أنظمة الملفات (yaffs2 أو ext4 أو vfat).
بدءًا من الإصدار 3.0 من Android، يحصل ملف recovery.fstab على حقل اختياري إضافي هو options. الخيار الوحيد المحدّد حاليًا هو الطول ، الذي يتيح لك تحديد طول القسم بشكل صريح. يتم استخدام هذا الطول عند إعادة تنسيق القسم (على سبيل المثال، لقسم userdata أثناء عملية محو البيانات/إعادة الضبط على الإعدادات الأصلية، أو لقسم النظام أثناء تثبيت حزمة OTA كاملة). إذا كانت قيمة الطول سالبة، يتم أخذ الحجم المطلوب تنسيقه من خلال إضافة قيمة الطول إلى حجم القسم الفعلي. على سبيل المثال، يعني ضبط "length=-16384" أنّه لن تتم cima يتيح ذلك ميزات مثل تشفير قسم userdata (حيث يتم تخزين البيانات الوصفية للتشفير في نهاية القسم الذي يجب عدم استبداله).
ملاحظة: حقلَا device2 وoptions اختياريان، ما يؤدي إلى حدوث التباس في التحليل. إذا كان الإدخال في الحقل الرابع على السطر يبدأ بحرف "/" ، يُعتبر إدخال device2. وإذا لم يبدأ الإدخال بحرف "/" ، يُعتبر حقل options.
صورة متحركة لبدء التشغيل
يمكن لصنّاع الأجهزة تخصيص الصورة المتحركة التي تظهر عند التمهيد لجهاز Android. لإجراء ذلك، عليك إنشاء ملف zip .منظَّم ومُحدَّد الموقع وفقًا للمواصفات الواردة في تنسيق bootanimation.
بالنسبة إلى أجهزة Android Things، يمكنك تحميل الملف المضغوط في وحدة تحكّم Android Things لتضمين الصور في المنتج المحدّد.
ملاحظة: يجب أن تستوفي هذه الصور إرشادات علامة Android التجارية. للحصول على إرشادات حول العلامة التجارية، يُرجى الرجوع إلى قسم Android في مركز التسويق التعاوني بين الشركاء (Partner Marketing Hub).
واجهة مستخدم الاسترداد
لتوفير التوافق مع الأجهزة التي تتضمّن أجهزة مختلفة (الأزرار الخارجية ومصابيح 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"
دوال العناصر والروابط
تتطلّب فئة 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 يحتوي على شاشة، لذا يمكنك اكتساب الخصائص من التنفيذ المدمج
ScreenRecoveryUI (اطّلِع على التعليمات الخاصة
بالأجهزة التي لا تحتوي على شاشة). الوظيفة الوحيدة التي يمكن
تخصيصها من ScreenRecoveryUI هي CheckKey()
، التي تُجري المعالجة الأولية
للمفتاح غير المتزامن:
class TardisUI : public ScreenRecoveryUI { public: virtual KeyAction CheckKey(int key) { if (key == KEY_HOME) { return TOGGLE; } return ENQUEUE; } };
ثوابت KEY
يتمّ تحديد الثوابت KEY_* في linux/input.h
.يتم استدعاء CheckKey()
بغض النظر عما يحدث في بقية عملية الاسترداد: عند إيقاف القائمة، عند
تفعيلها، أثناء تثبيت الحزمة، أثناء محو بيانات المستخدم، وما إلى ذلك. ويمكن أن يعرض أحد المتغيّرات الثابتة الأربعة التالية:
- التبديل تفعيل أو إيقاف عرض القائمة و/أو سجلّ النصوص
- إعادة التشغيل: إعادة تشغيل الجهاز على الفور
- تجاهل تجاهُل الضغط على هذا المفتاح
- ENQUEUE إضافة ضغطة المفتاح هذه إلى قائمة الانتظار لاستخدامها بشكل متزامن (أي من خلال نظام قائمة الصعوبات والتعافي في حال كانت الشاشة مفعَّلة)
يتمّ استدعاء CheckKey()
في كلّ مرّة يتبع فيها حدث الضغط على مفتاح حدث رفع الضغط عن المفتاح
نفسه. (لا يؤدي تسلسل الأحداث "أ-للأسفل" و"ب-للأسفل" و"ب-للأعلى" و"أ-للأعلى" إلا إلى 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
عند استخدام صورك الخاصة (رمز الخطأ والمؤثرات الحركية للتثبيت وأشرطة التقدم) مع
ScreenRecoveryUI، يمكنك ضبط المتغيّر animation_fps
للتحكّم في السرعة في
لقطات في الثانية للمؤثرات الحركية.
ملاحظة: يتيح لك نص interlace-frames.py
الحالي
تخزين معلومات animation_fps
في الصورة نفسها. في الإصدارات السابقة من
Android، كان عليك ضبط animation_fps
بنفسك.
لضبط المتغيّر animation_fps
، يمكنك إلغاء دالة
ScreenRecoveryUI::Init()
في الدرجة الفرعية. اضبط القيمة، ثم استخدِم الدالة
parent Init()
لإكمال عملية الإعداد. تتوافق القيمة التلقائية (20 لقطة في الثانية)
مع صور الاسترداد التلقائية. عند استخدام هذه الصور، ليس عليك تقديم
دالة Init()
. لمعرفة تفاصيل عن الصور، يُرجى الاطّلاع على
صور واجهة مستخدم الاسترداد.
فئة الجهاز
بعد تنفيذ RecoveryUI، حدِّد فئة جهازك (الفئة الفرعية من
فئة Device المضمّنة). من المفترض أن يؤدي ذلك إلى إنشاء مثيل واحد لفئة واجهة المستخدم وعرض ذلك
من دالة GetUI()
:
class TardisDevice : public Device { private: TardisUI* ui; public: TardisDevice() : ui(new TardisUI) { } RecoveryUI* GetUI() { return ui; }
StartRecovery
يتمّ استدعاء طريقة StartRecovery()
في بداية عملية الاسترداد، بعد بدء واجهة المستخدم
وبعد تحليل الوسيطات، ولكن قبل اتّخاذ أيّ إجراء. لا يؤدي التنفيذ التلقائي إلى أيّ إجراء، لذا ليس عليك توفير هذا الإجراء في
الدرجة الفرعية إذا لم يكن لديك أيّ إجراء:
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()
طريقة عنصر واجهة المستخدم)، والحالة الحالية لملف سجلّ القائمة/النص. القيمة المعروضة هي عدد صحيح. إذا كانت القيمة 0 أو أعلى، يتم اعتبارها
موضع عنصر قائمة يتم استدعاؤه على الفور (راجِع InvokeMenuItem()
أدناه). بخلاف ذلك، يمكن أن تكون إحدى الثابتات التالية
المحدَّدة مسبقًا:
- kHighlightUp نقل تمييز القائمة إلى العنصر السابق
- kHighlightDown. نقل تمييز القائمة إلى العنصر التالي
- kInvokeItem استدعاء العنصر المميّز حاليًا
- kNoAction عدم اتّخاذ أي إجراء بشأن ضغطة المفتاح هذه
كما هو موضح في الوسيطة visible، يتمّ استدعاء HandleMenuKey()
حتى إذا كانت القائمة
غير مرئية. على عكس CheckKey()
، لا يتم استدعاء هذا الإجراء أثناء تنفيذ عملية الاسترداد
لشيء ما، مثل محو البيانات أو تثبيت حزمة، بل يتم استدعاؤه فقط عندما تكون عملية الاسترداد في وضع السكون
وتنتظر إدخال البيانات.
آليات كرة التتبّع
إذا كان جهازك يحتوي على آلية إدخال تشبه كرة التتبُّع (تُنشئ أحداث إدخال من النوع EV_REL
والرمز REL_Y)، يُنشئ وضع الاسترداد ضغطات المفاتيح KEY_UP وKEY_DOWN كلما رصد
جهاز الإدخال المشابه لكرة التتبُّع حركة في محور Y. ما عليك سوى ربط حدثَي 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
بعد ذلك، قدِّم طريقة 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 إعادة تنسيق قسمَي userdata وcache، ويُعرف ذلك أيضًا باسم إعادة الضبط بحسب بيانات المصنع سيُطلب من المستخدم تأكيد هذا الإجراء قبل المتابعة.
الطريقة الأخيرة، WipeData()
، اختيارية ويتمّ استدعاؤها عند بدء عملية محو بيانات (إمّا من خلال الاسترداد من القائمة أو عندما يختار المستخدم إجراء
عملية إعادة الضبط على الإعدادات الأصلية من النظام الرئيسي). يتم استدعاء هذه الطريقة قبل محو بيانات المستخدمين ومساحة التخزين المؤقت
في الأقسام. إذا كان جهازك يخزِّن بيانات المستخدمين في أي مكان آخر غير هذين القسمين
، عليك محوها هنا. يجب عرض القيمة 0 للإشارة إلى النجاح وقيمة
أخرى للفشل، على الرغم من أنّه يتم حاليًا تجاهل القيمة المعروضة. يتم محو بيانات المستخدمين ومساحة التخزين المؤقت
سواء أرجعت حالة نجاح أو تعذّر.
int WipeData() { // ... do something tardis-specific here, if needed .... return 0; }
علامة جهازك التجارية
أخيرًا، أدرِج بعض النماذج الجاهزة في نهاية ملف 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
صور واجهة مستخدم الاسترداد
تتألف واجهة مستخدِم عملية الاسترداد من صور. من المفترض ألا يتفاعل المستخدمون مع واجهة المستخدم مطلقًا: أثناء التحديث العادي، يتم تشغيل الهاتف في وضع الاسترداد، ويتم ملء شريط التقدّم للتثبيت، ويتم تشغيل الهاتف مرة أخرى في النظام الجديد بدون إدخال أي معلومات من المستخدم. في حال حدوث مشكلة في تحديث النظام، فإنّ الإجراء الوحيد الذي يمكن للمستخدم اتّخاذه هو الاتصال بخدمة عملاء Google.
تغني واجهة الصور فقط عن الحاجة إلى الترجمة. ومع ذلك، اعتبارًا من الإصدار 5.0 من Android، يمكن أن يعرض التحديث سلسلة من النصوص (مثل "جارٍ تثبيت تحديث النظام") مع الصورة. لمعرفة التفاصيل، يُرجى الاطّلاع على نص الاسترداد المترجَم.
الإصدار 5.0 من نظام التشغيل Android والإصدارات الأحدث
تستخدم واجهة مستخدم الاسترداد في الإصدار 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 وما إلى ذلك، وما إلى ذلك. تتضمّن الصورة المجمّعة
مجموعة نصية تشير إلى عدد إطارات الصورة المتحركة وعدد اللقطات في الثانية
(FPS). تأخذ الأداة bootable/recovery/interlace-frames.py
مجموعة من لقطات الإدخال
وتدمجها في الصورة المركبة اللازمة التي تستخدمها عملية الاسترداد.
تتوفّر الصور التلقائية بكثافات مختلفة وتقع فيملف
bootable/recovery/res-$DENSITY/images
(مثل
bootable/recovery/res-hdpi/images
). لاستخدام صورة ثابتة أثناء التثبيت،
ما عليك سوى تقديم الصورة icon_installing.png وضبط عدد اللقطات في
الصورة المتحركة على 0 (رمز الخطأ ليس صورة متحركة، بل هو صورة ثابتة دائمًا).
الإصدار 4.x من Android والإصدارات الأقدم
تستخدم واجهة المستخدم الخاصة بوضع الاسترداد في الإصدار 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: progress_empty.png

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

الشكل 11: شريط التقدم عند نسبة %1>

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

الشكل 13: شريط التقدم عند نسبة %50
يمكنك تقديم نُسخ من هذه الصور مخصّصة للأجهزة من خلال وضعها في (في هذا
المثال) device/yoyodyne/tardis/recovery/res/images
. يجب أن تتطابق أسماء الملفات مع الأسماء المدرَجة أعلاه. وعند العثور على ملف في هذا الدليل، يستخدم
نظام التصميم هذا الملف بدلاً من الصورة التلقائية المقابلة. لا يمكن استخدام سوى ملفات PNG بتنسيق RGB أو
RGBA بدرجة عمق ألوان 8 بت.
ملاحظة: في نظام التشغيل Android 5.x، إذا كانت اللغة معروفة لميزة الاسترداد وكانت من اليمين إلى اليسار (مثل العربية والعبرية وما إلى ذلك)، يملأ شريط التقدم الشاشة من اليمين إلى اليسار.
الأجهزة غير المزوّدة بشاشات
لا تتضمّن بعض أجهزة Android شاشات. إذا كان جهازك جهازًا بدون شاشة أو كان يحتوي على واجهة صوتية فقط، قد تحتاج إلى إجراء تخصيص أكثر شمولاً لواجهة مستخدم الاسترداد. بدلاً من إنشاء فئة فرعية من ScreenRecoveryUI، يمكنك إنشاء فئة فرعية من الفئة الرئيسية RecoveryUI مباشرةً.
تتضمّن RecoveryUI طُرقًا لمعالجة عمليات واجهة المستخدم من المستوى الأدنى، مثل "تبديل الشاشة"،
و"تعديل شريط التقدم"، و"عرض القائمة"، و"تغيير اختيار القائمة"، وما إلى ذلك. ويمكنك إلغاء
هذه الإجراءات لتوفير واجهة مناسبة لجهازك. قد يحتوي جهازك على مصابيح LED
يمكنك استخدام ألوان أو أنماط مختلفة من الوميض للإشارة إلى الحالة، أو قد يكون بإمكانك تشغيل
الصوت. (قد لا تريد توفير قائمة أو وضع "عرض النص" على الإطلاق، ويمكنك
منع الوصول إليهما باستخدام عمليات تنفيذ CheckKey()
و
HandleMenuKey()
التي لا تشغّل العرض أو تختار عنصرًا في القائمة
أبدًا. في هذه الحالة، يمكن أن تكون العديد من طرق RecoveryUI التي تحتاج إلى تقديمها مجرّد نماذج فارغة
(stubs).)
راجِع 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*
cookie، وعدد الوسائط الواردة، وأحد
صفائف مؤشرات 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*
، وتحديدًا العنصر datamember.
في هذه الحالة، تريد عرض قيمة صحيحة أو خطأ للإشارة إلى النجاح. تذكَّر
القاعدة التي تنص على أنّ السلسلة الفارغة هي false وجميع السلاسل الأخرى هي true. عليك
استخدام malloc لإنشاء عنصر Value باستخدام نسخة تم إنشاؤها باستخدام 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 لإنشاء مكتبة ثابتة باستخدام الرمز البرمجي. (هذا هوملف makefile نفسه المستخدَم لتخصيص واجهة مستخدم وضع الاسترداد في القسم السابق. قد يتضمّن جهازك كلاً من مكتبتَي ملف makefile static الثابتتَين المحدّدتَين هنا).
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 (قد يحتوي على مكتبات متعددة، ويتم تسجيلها جميعًا).
إذا كان الرمز يعتمد على مكتبات ثابتة أخرى ليست هي نفسها إضافات edify (أي
لا تتضمّن دالة Register_libname
)، يمكنك إدراجها في
TARGET_RECOVERY_UPDATER_EXTRA_LIBS لربطها بـ updater بدون استدعاء
دالة التسجيل (غير المتوفّرة). على سبيل المثال، إذا كان الرمز البرمجي الخاص بالجهاز يريد استخدام
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 ببياناتك المتعلّقة بالجهاز وإصدار نصوص برمجية لأدوات التحديث تتضمّن طلبات إلى دوال الإضافة.
أولاً، عليك إبلاغ نظام الإنشاء بمجموعة بيانات خاصة بالجهاز. بافتراض أنّ ملف data
الخاص بك في 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
عدة مرات لإضافة أي عدد تريده من الملفات.
وحدة Python
لتوسيع نطاق أدوات الإصدار، اكتب وحدة Python (يجب أن يكون اسمها 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()
- يتمّ استدعاؤه بالقرب من بداية إنشاء تحديث OTA كامل. هذا هو المكان المناسب لإصدار التأكيدات حول الحالة الحالية للجهاز. لا تُرسِل أوامر نصية تُجري تغييرات على الجهاز.
FullOTA_InstallBegin()
- يتمّ استدعاؤه بعد اجتياز جميع الأحكام حول حالة الجهاز ولكن قبل إجراء أيّ تغييرات. يمكنك إصدار أوامر للتحديثات المتعلّقة بالجهاز والتي يجب تنفيذها قبل تغيير أي شيء آخر على الجهاز.
FullOTA_InstallEnd()
- يتمّ استدعاء هذه الوظيفة في نهاية إنشاء النص البرمجي، بعد إصدار أوامر النص البرمجي لتعديل أقسام التمهيد والنظام. يمكنك أيضًا إرسال أوامر إضافية لتلقّي آخر الأخبار المتعلّقة بالأجهزة.
IncrementalOTA_Assertions()
-
مشابهة لـ
FullOTA_Assertions()
ولكن يتمّ استدعاؤها عند إنشاء حزمة تحديث متزايدة. IncrementalOTA_VerifyBegin()
- يتمّ استدعاؤه بعد اجتياز جميع التأكيدات حول حالة الجهاز ولكن قبل إجراء أي تغييرات. يمكنك إصدار أوامر للتحديثات المتعلّقة بالجهاز والتي يجب تنفيذها قبل تغيير أي محتوى آخر على الجهاز.
IncrementalOTA_VerifyEnd()
- يتمّ استدعاء هذه الدالة في نهاية مرحلة التحقّق، عندما ينتهي النصّ البرمجي من التأكّد من أنّملفاته التي سيتمّ تعديلها تتضمّن المحتوى الافتتاحي المتوقّع. في هذه المرحلة، لم يتم إجراء أي تغيير على الجهاز. يمكنك أيضًا إصدار رمز لعمليات التحقّق الإضافية المتعلّقة بالجهاز.
IncrementalOTA_InstallBegin()
- يتمّ استدعاء هذه الوظيفة بعد التحقّق من أنّ الملفات التي سيتمّ تصحيحها في الحالة المتوقعة قبل إجراء أيّ تغييرات. يمكنك إصدار أوامر بشأن التحديثات المتعلّقة بالجهاز والتي يجب تنفيذها قبل تغيير أي شيء آخر على الجهاز.
IncrementalOTA_InstallEnd()
- تمامًا مثل نظيره من حِزم OTA الكاملة، يتمّ استدعاء هذا الإجراء في نهاية عملية إنشاء النص البرمجي، بعد أن يتمّ توجيه أوامر النص البرمجي لتعديل قسمَي التمهيد والنظام. يمكنك أيضًا إصدار أوامر إضافية للتحديثات الخاصة بالأجهزة.
ملاحظة: إذا نفد شحن بطارية الجهاز، قد تتم إعادة تشغيل عملية التثبيت عبر الهواء من البداية. يجب أن تكون مستعدًا للتعامل مع الأجهزة التي سبق أن تم تشغيل هذه الأوامر عليها، سواءً بشكل كامل أو جزئي.
تمرير الدوال إلى عناصر المعلومات
نقْل الدوال إلى عنصر معلومات واحد يحتوي على عناصر مفيدة مختلفة:
-
info.input_zip. (عمليات OTA الكاملة فقط) عنصر
zipfile.ZipFile
لملف zip الذي يحتوي على الملفات المستهدفة التي يتم إدخالها -
info.source_zip. (التحديثات التلقائية المتزايدة فقط) عنصر
zipfile.ZipFile
لملف .zip الخاص بالملف الهدف المصدر (الإصدار المُثبَّت حاليًا على الجهاز عند تثبيت الحزمة المتزايدة) -
info.target_zip. (عمليات التحديث عبر الهواء المتزايدة فقط) عنصر
zipfile.ZipFile
لملف target-files.zip المستهدف (الإصدار الذي تضعه الحزمة المتزايدة على الجهاز) -
info.output_zip. الحزمة قيد الإنشاء، تم فتح عنصر
zipfile.ZipFile
للكتابة. استخدِم common.ZipWriteStr(info.output_zip, filename, data) لإضافة ملف إلى الحزمة. -
info.script. عنصر نص برمجي يمكنك إلحاق الأوامر به استخدِم دالة
info.script.AppendExtra(script_text)
لإخراج النص في النص البرمجي. تأكَّد من أنّ نص الإخراج ينتهي بنقطتَين منقوصتَين كي لا يصادف أوامر يتم بثها بعد ذلك.
للاطّلاع على تفاصيل عن عنصر المعلومات، يُرجى الرجوع إلى مستندات Python Software Foundation حول أرشيفات 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 في ملف target-files
.zip (META/releasetools.py
).
عند تشغيل أدوات الإصدار (إما img_from_target_files
أو
ota_from_target_files
)، يُفضَّل استخدام النص البرمجي releasetools.py في ملف zip .الخاص بالملفّات المستهدَفة، إذا كان
متوفّرًا، بدلاً من النص البرمجي من شجرة مصدر Android. يمكنك أيضًا تحديد مسار الإضافات الخاصة بالأجهزة بشكل صريح باستخدام الخيار -s
(أو
--device_specific
)، والذي يحظى بالأولوية القصوى. يتيح لك ذلك
تصحيح الأخطاء وإجراء تغييرات في إضافات أداة إصدار الأدوات وتطبيق هذه التغييرات على
الملفات المستهدَفة القديمة.
الآن، عند تشغيل ota_from_target_files
، يتم تلقائيًا اختيار الوحدت
الخاصة بالجهاز من ملف target_files .zip واستخدامها عند إنشاء حزم 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
.
آلية التثبيت من مصدر غير معروف
يتضمّن وضع الاسترداد آلية لتحميل التطبيقات من مصدر غير معروف لتثبيت حزمة تحديث يدويًا بدون تنزيلها عبر شبكة الجوّال من خلال النظام الرئيسي. يُعدّ التثبيت من مصدر غير معروف مفيدًا لتصحيح الأخطاء أو إجراء تغييرات على الأجهزة التي لا يمكن فيها تشغيل النظام الرئيسي.
في السابق، كان يتم تحميل التطبيقات من مصدر غير معروف من خلال تحميل الحِزم من بطاقة SD في الجهاز. في حالة عدم التمكّن من تشغيل الجهاز، يمكن وضع الحزمة على بطاقة SD باستخدام جهاز كمبيوتر آخر ثم إدخال بطاقة SD في الجهاز. لتلبية احتياجات أجهزة Android التي لا تتضمّن مساحة تخزين خارجية قابلة للإزالة، تتيح ميزة الاسترداد آليتين إضافيتين للتثبيت من مصدر غير معروف: تحميل الحِزم من قسم ذاكرة التخزين المؤقت وتحميلها عبر USB باستخدام adb.
لتشغيل كل آلية لتحميل التطبيق من مصدر غير معروف، يمكن أن تُعرِض طريقة Device::InvokeMenuItem()
على جهازك القيم التالية لـ BuiltinAction:
-
APPLY_EXT تثبيت حزمة تحديث من مصدر غير معروف من وحدة تخزين خارجية (دليل
/sdcard
) يجب أن يحدِّد ملف recovery.fstab نقطة تثبيت/sdcard
. لا يمكن استخدام هذا الإجراء على الأجهزة التي تحاكي بطاقة SD باستخدام رابط رمزي إلى/data
(أو أي أسلوب مشابه). لا يمكن عادةً استرداد/data
لأنّه قد يكون مشفَّرًا. تعرض واجهة مستخدم الاسترداد قائمة بملفات .zip في/sdcard
ويسمح للمستخدم باختيار ملف واحد. -
APPLY_CACHE يشبه ذلك تحميل حزمة من
/sdcard
باستثناء أنّه يتم استخدام directory/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
(أو أي شيء آخر غير حزمة صالحة) كحزمة، وبعد ذلك سيتعذّر على الجهاز التحقّق منها وسيوقف عملية التثبيت. سيستمر استدعاء طريقةCheckKey()
في تنفيذ RecoveryUI لضغطات المفاتيح، حتى تتمكّن من تقديم تسلسل مفاتيح يؤدي إلى إعادة تشغيل الجهاز ويعمل في وضع تحميل adb الجانبي.