تحسين منظمات الاتّجار بالمخدرات

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

سطر أوامر النواة

يقع سطر أوامر النواة الأصلي في شجرة الأجهزة (DT) في العقدة chosen/bootargs. يجب أن يدمج برنامج الإقلاع هذا الموقع مع مصادر أخرى لسطر أوامر النواة:

/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};

لا يمكن لملف DTO دمج القيم من ملف DTO الرئيسي وملف DTO الخاص بالتراكب، لذا يجب وضع سطر أوامر النواة لملف DTO الرئيسي في chosen/bootargs وسطر أوامر النواة لملف DTO الخاص بالتراكب في chosen/bootargs_ext. يمكن لبرنامج Bootloader بعد ذلك ربط هذه المواقع الجغرافية وتمرير النتيجة إلى النواة.

main.dts overlay.dts
/dts-v1/;

/ {
  chosen: chosen {
    bootargs = "...";
  };
};
/dts-v1/;
/plugin/;

&chosen {
  bootargs_ext = "...";
};

libufdt

على الرغم من أنّ أحدث إصدار من libfdt يتوافق مع DTO، يُنصح باستخدام libufdt لتنفيذ DTO (مصدر AOSP على platform/system/libufdt). تنشئ libufdt بنية شجرة حقيقية (شجرة أجهزة غير مسطّحة، أو ufdt) من شجرة الأجهزة المسطّحة (FDT)، وبالتالي يمكنها تحسين دمج ملفَي .dtb من O(N2) إلى O(N)، حيث N هو عدد العُقد في الشجرة.

اختبار الأداء

في الاختبارات الداخلية التي أجرتها Google، يؤدي استخدام libufdt على 2405 عقدة .dtb و283 عقدة .dtbo DT إلى أحجام ملفات تبلغ 70,618 و8,566 بايت بعد التجميع. بالمقارنة مع تنفيذ DTO تم نقله من FreeBSD (وقت التشغيل 124 ملي ثانية)، يبلغ وقت تشغيل DTO 10 ملي ثانية.libufdt

مقارنة نتائج اختبار الأداء على أجهزة Pixel libufdt وlibfdt تتشابه تأثيرات عدد العُقد الأساسية، ولكنها تتضمّن الاختلافات التالية:

  • تتضمّن 500 عملية تراكب (إلحاق أو تجاهل) فرقًا في الوقت يتراوح بين 6 و8 أضعاف
  • تتضمّن 1000 عملية تراكب (إلحاق أو تجاهل) فرقًا في الوقت يتراوح بين 8 و10 أضعاف

مثال مع ضبط عدد مرات الإلحاق على X:

الشكل 1: عدد عمليات الإلحاق هو X.

مثال مع ضبط عدد عمليات الإلغاء على X:

الشكل 2: عدد عمليات التجاوز هو X.

يتم تطوير libufdt باستخدام بعض واجهات برمجة التطبيقات libfdt وهياكل البيانات. عند استخدام libufdt، يجب تضمين libfdt وإضافة رابط إليه (يمكنك استخدام واجهة برمجة التطبيقات libfdt في الرمز البرمجي لتشغيل DTB أو DTBO).

libufdt DTO API

في ما يلي واجهة برمجة التطبيقات الرئيسية لتحويل البيانات من واجهة برمجة التطبيقات إلى كائن نقل البيانات في libufdt:

struct fdt_header *ufdt_apply_overlay(
        struct fdt_header *main_fdt_header,
        size_t main_fdt_size,
        void *overlay_fdt,
        size_t overlay_size);

المَعلمة main_fdt_header هي DT الرئيسية، وoverlay_fdt هي المخزن المؤقت الذي يحتوي على محتويات ملف .dtbo. قيمة الإرجاع هي مخزن مؤقت جديد يحتوي على شجرة الأجهزة المدمجة (أو null في حال حدوث خطأ). يتم تنسيق شجرة الأجهزة المدمجة في شجرة الأجهزة المسطّحة، ويمكنك تمريرها إلى النواة عند بدء تشغيل النواة.

يتم إنشاء المخزن المؤقت الجديد من قيمة الإرجاع بواسطة dto_malloc()، التي يجب تنفيذها عند نقل libufdt إلى برنامج إقلاع. للاطّلاع على عمليات التنفيذ المرجعية، يُرجى الرجوع إلى sysdeps/libufdt_sysdeps_*.c.

القيود المفروضة على العقدة الأساسية

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

على مورّدي المنظومة على الرقاقة (SoC) تحديد إمكانية التراكب في شجرة الجهاز الرئيسية، ولا يمكن لمصنّعي التصميم الأصلي (ODM) أو المصنّعين الأصليين للأجهزة (OEM) سوى إضافة أو تجاهل العُقد التي تحمل تصنيفات يحدّدها مورّد المنظومة على الرقاقة. كحلّ بديل، يمكنك تحديد عقدة odm ضمن العقدة الجذرية في شجرة الأجهزة الأساسية، ما يتيح لجميع عقد ODM في شجرة الأجهزة المتراكبة إضافة عقد جديدة. بدلاً من ذلك، يمكنك وضع جميع العُقد ذات الصلة بنظام SoC في شجرة الأجهزة الأساسية ضمن العقدة soc ضمن العقدة الجذر كما هو موضّح أدناه:

main.dts overlay.dts
/dts-v1/;

/ {
    compatible = "corp,bar";
    ...

    chosen: chosen {
        bootargs = "...";
    };

    /* nodes for all soc nodes */
    soc {
        ...
        soc_device@0: soc_device@0 {
            compatible = "corp,bar";
            ...
        };
        ...
    };

    odm: odm {
        /* reserved for overlay by odm */
    };
};
/dts-v1/;
/plugin/;

/ {
};

&chosen {
    bootargs_ex = "...";
};

&odm {
    odm_device@0 {
        ...
    };
    ...
};

استخدام المحتوى المركّب المضغوط

يضيف نظام التشغيل Android 9 إمكانية استخدام التراكبات المضغوطة في صورة DTBO عند استخدام الإصدار 1 من عنوان جدول DT. عند استخدام الإصدار 1 من عنوان DTBO، تشير وحدات البت الأربع الأقل أهمية في حقل العلامات في dt_table_entry إلى تنسيق الضغط لإدخال DT.

struct dt_table_entry_v1 {
  uint32_t dt_size;
  uint32_t dt_offset;  /* offset from head of dt_table_header */
  uint32_t id;         /* optional, must be zero if unused */
  uint32_t rev;        /* optional, must be zero if unused */
  uint32_t flags;      /* For version 1 of dt_table_header, the 4 least significant bits
                        of 'flags' are used to indicate the compression
                        format of the DT entry as per the enum 'dt_compression_info' */
  uint32_t custom[3];  /* optional, must be zero if unused */
};

يتوفّر حاليًا ضغط zlib وgzip.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

يضيف نظام التشغيل Android 9 إمكانية اختبار التراكبات المضغوطة إلى اختبار VtsFirmwareDtboVerification لمساعدتك في التحقّق من صحة تطبيق التراكب.

مثال على عملية تنفيذ DTO

ترشدك التعليمات التالية خلال عملية تنفيذ نموذجية لـ DTO باستخدام libufdt (الرمز النموذجي أدناه).

عيّنة من تعليمات DTO

  1. تضمين المكتبات لاستخدام libufdt، عليك تضمين libfdt لبُنى البيانات وواجهات برمجة التطبيقات:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
  2. حمِّل جدول بيانات DT الرئيسي وجدول بيانات DT المتراكب. حمِّل .dtb و.dtbo من مساحة التخزين إلى الذاكرة (تعتمد الخطوات الدقيقة على تصميمك). في هذه المرحلة، يجب أن يتوفّر لديك المخزن المؤقت وحجم .dtb/.dtbo:
    main_size = my_load_main_dtb(main_buf, main_buf_size)
    overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);
  3. تراكب أنواع البيانات:
    1. استخدِم ufdt_install_blob() للحصول على عنوان FDT لـ DT الرئيسي:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. اتّصِل بالرقم ufdt_apply_overlay() لتحويل DT إلى FDT بالتنسيق التالي:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
    3. استخدِم merged_fdt للحصول على حجم dtc_totalsize():
      merged_fdt_size = dtc_totalsize(merged_fdt);
    4. مرِّر شجرة الأجهزة المدمجة لبدء تشغيل النواة:
      my_kernel_entry(0, machine_type, merged_fdt);

نموذج رمز DTO

#include <libfdt.h>
#include <ufdt_overlay.h>



{
  struct fdt_header *main_fdt_header;
  struct fdt_header *merged_fdt;

  /* load main dtb into memory and get the size */
  main_size = my_load_main_dtb(main_buf, main_buf_size);

  /* load overlay dtb into memory and get the size */
  overlay_size = my_load_overlay_dtb(overlay_buf, overlay_buf_size);

  /* overlay */
  main_fdt_header = ufdt_install_blob(main_buf, main_size);
  main_fdt_size = main_size;
  merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                  overlay_buf, overlay_size);
  merged_fdt_size = dtc_totalsize(merged_fdt);

  /* pass to kernel */
  my_kernel_entry(0, machine_type, merged_fdt);
}