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

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

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

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

/dts-v1/;

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

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

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

  • تختلف مدة تنفيذ 500 عملية تراكب (إضافية أو إلغاء) من 6 إلى 8 أضعاف مقارنةً بعمليات الإضافة.
  • تختلف مدّة تنفيذ 1,000 عملية تراكب (إلحاق أو إلغاء) من 8 إلى 10 أضعاف مقارنةً بعمليات الإضافة.

مثال مع ضبط عدد العناصر المُلحَقة على X:

الشكل 1: عدد عمليات الإضافة هو X.

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

الشكل 2: عدد القيم التي تم إلغاؤها هو X.

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

واجهة برمجة تطبيقات libufdt DTO

في ما يلي واجهة برمجة التطبيقات الرئيسية التي تؤدي إلى DTO في 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. القيمة المعروضة هي ذاكرة تخزين مؤقتة جديدة تحتوي على جدول DT المدمج (أو null في حال حدوث خطأ). يتم تنسيق DT المدمج في FDT، والذي يمكنك تمريره إلى النواة عند بدء تشغيلها.

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

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

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

على مورّدي المنظومة على الرقاقة تحديد إمكانية التراكب لملف DT الرئيسي، ولا يمكن لمصنّعي الأجهزة الأصليين أو المصنّعين المحدّدين فقط إلحاق العقد أو إلغاء ربطها بتصنيفات يحدّدها مورّد المنظومة على الرقاقة. كحل بديل، يمكنك تحديد عقدة odm ضمن العقدة الجذر في DT الأساسية، ما يتيح لجميع عقد ODM في DT المتراكبة إضافة عقد جديدة. بدلاً من ذلك، يمكنك وضع جميع العقد ذات الصلة بوحدة المعالجة المركزية (SoC) في DT الأساسية في node 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 لجدول البيانات الرئيسي:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. يُرجى الاتصال برقم ufdt_apply_overlay() في فريق DTO للحصول على جدول بيانات مبيعات مدمج بتنسيق 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. نقْل ملف DT المدمج لبدء تشغيل النواة:
      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);
}