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

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

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

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

/dts-v1/;

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

لا يمكن لملف DTO دمج القيم من ملف DT الرئيسي وملف DT المتراكب، لذا عليك وضع سطر أوامر النواة لملف DT الرئيسي في chosen/bootargs وسطر أوامر النواة لملف DT المتراكب في 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 ملي ثانية)، يبلغ وقت تشغيل libufdtDTO 10 ملي ثانية.

اختبار الأداء على أجهزة 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.

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

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

على مورّدي المنظومة على الرقاقة (SoC) تحديد إمكانية التراكب في شجرة الأجهزة الرئيسية، ولا يمكن للمصنّعين الأصليين للأجهزة أو مصنّعي التصميم الأصليين سوى إضافة أو تجاهل العُقد التي تحمل التصنيفات المحدّدة من قِبل مورّد المنظومة على الرقاقة. كحلّ بديل، يمكنك تحديد عقدة 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);
}