Tối ưu hoá các tổ chức buôn bán ma tuý

Trang này thảo luận về những điểm tối ưu hoá mà bạn có thể thực hiện đối với việc triển khai lớp phủ cây thiết bị (DTO), mô tả các hạn chế đối với việc phủ lớp nút gốc và trình bày chi tiết cách định cấu hình lớp phủ nén trong hình ảnh DTBO. Tài liệu này cũng cung cấp hướng dẫn và mã triển khai mẫu.

Dòng lệnh của kernel

Dòng lệnh ban đầu của nhân trong cây thiết bị (DT) nằm trong nút chosen/bootargs. Trình tải khởi động phải nối vị trí này với các nguồn khác của dòng lệnh kernel:

/dts-v1/;

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

DTO không thể nối các giá trị từ DT chính và DT lớp phủ, vì vậy, bạn phải đặt dòng lệnh của hạt nhân của DT chính trong chosen/bootargs và dòng lệnh của hạt nhân của DT lớp phủ trong chosen/bootargs_ext. Sau đó, trình tải khởi động có thể nối các vị trí này và truyền kết quả đến nhân.

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

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

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

libufdt

Mặc dù libfdt mới nhất hỗ trợ DTO, nhưng bạn nên dùng libufdt để triển khai DTO (nguồn AOSP tại platform/system/libufdt). libufdt tạo cấu trúc cây thực (cây thiết bị chưa được làm phẳng hoặc ufdt) từ cây thiết bị được làm phẳng (FDT), vì vậy, nó có thể cải thiện việc hợp nhất hai tệp .dtb từ O(N2) thành O(N), trong đó N là số lượng nút trong cây.

Kiểm thử hiệu suất

Trong thử nghiệm nội bộ của Google, việc sử dụng libufdt trên 2405 .dtb và 283 .dtbo nút DT sẽ tạo ra các kích thước tệp là 70.618 và 8.566 byte sau khi biên dịch. So với chế độ triển khai DTO được chuyển từ FreeBSD (thời gian chạy 124 mili giây), thời gian chạy DTO là 10 mili giây. libufdt

Kiểm thử hiệu suất cho các thiết bị Pixel so với libufdtlibfdt. Số lượng nút cơ sở có hiệu ứng tương tự, nhưng có những điểm khác biệt sau:

  • 500 thao tác lớp phủ (nối hoặc ghi đè) có sự khác biệt về thời gian từ 6 đến 8 lần
  • 1000 thao tác lớp phủ (nối hoặc ghi đè) có sự khác biệt về thời gian từ 8 đến 10 lần

Ví dụ về việc nối số lượng được đặt thành X:

Hình 1. Số lượng nối thêm là X.

Ví dụ về việc ghi đè số lượng được đặt thành X:

Hình 2. Số lượng ghi đè là X.

libufdt được phát triển bằng một số API và cấu trúc dữ liệu libfdt. Khi sử dụng libufdt, bạn phải thêm và liên kết libfdt (tuy nhiên, trong mã, bạn có thể sử dụng API libfdt để vận hành DTB hoặc DTBO).

API DTO libufdt

API chính cho DTO trong libufdt như sau:

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

Tham số main_fdt_header là DT chính và overlay_fdt là vùng đệm chứa nội dung của tệp .dtbo. Giá trị trả về là một vùng đệm mới chứa DT đã hợp nhất (hoặc null trong trường hợp xảy ra lỗi). DT đã hợp nhất được định dạng trong FDT, bạn có thể truyền DT này đến nhân khi khởi động nhân.

Vùng đệm mới từ giá trị trả về được tạo bởi dto_malloc(), bạn nên triển khai vùng đệm này khi chuyển libufdt vào trình tải khởi động. Để biết các cách triển khai tham chiếu, hãy tham khảo sysdeps/libufdt_sysdeps_*.c.

Quy định hạn chế đối với nút gốc

Bạn không thể phủ một nút hoặc thuộc tính mới vào nút gốc của DT chính vì các thao tác phủ phụ thuộc vào nhãn. Vì DT chính phải xác định một nhãn và DT lớp phủ chỉ định các nút sẽ được phủ lên bằng nhãn, nên bạn không thể đặt nhãn cho nút gốc (và do đó không thể phủ nút gốc).

Nhà cung cấp SoC phải xác định khả năng lớp phủ của DT chính; ODM/OEM chỉ có thể thêm hoặc ghi đè các nút bằng nhãn do nhà cung cấp SoC xác định. Để khắc phục vấn đề này, bạn có thể xác định một nút odm trong nút gốc trong DT cơ sở, cho phép tất cả các nút ODM trong DT lớp phủ thêm các nút mới. Ngoài ra, bạn có thể đặt tất cả các nút liên quan đến SoC trong DT cơ sở vào một nút soc trong nút gốc như mô tả dưới đây:

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

Sử dụng lớp phủ nén

Android 9 bổ sung tính năng hỗ trợ sử dụng lớp phủ nén trong hình ảnh DTBO khi dùng phiên bản 1 của tiêu đề bảng DT. Khi sử dụng tiêu đề DTBO phiên bản 1, 4 bit có giá trị nhỏ nhất của trường cờ trong dt_table_entry cho biết định dạng nén của mục 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 */
};

Hiện tại, chúng tôi hỗ trợ các phương thức nén zlibgzip.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 bổ sung tính năng hỗ trợ kiểm thử các lớp phủ nén cho kiểm thử VtsFirmwareDtboVerification để giúp bạn xác minh tính chính xác của ứng dụng lớp phủ.

Triển khai DTO mẫu

Các hướng dẫn sau đây sẽ hướng dẫn bạn cách triển khai mẫu DTO bằng libufdt (mã mẫu bên dưới).

Hướng dẫn về DTO mẫu

  1. Bao gồm các thư viện. Để sử dụng libufdt, hãy thêm libfdt cho các cấu trúc dữ liệu và API:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
  2. Tải DT chính và DT lớp phủ. Tải .dtb.dtbo từ bộ nhớ vào bộ nhớ (các bước chính xác tuỳ thuộc vào thiết kế của bạn). Tại thời điểm này, bạn sẽ có bộ nhớ đệm và kích thước của .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. Lớp phủ DT:
    1. Dùng ufdt_install_blob() để lấy tiêu đề FDT cho DT chính:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. Gọi ufdt_apply_overlay() đến DTO để nhận DT đã hợp nhất ở định dạng FDT:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
    3. Sử dụng merged_fdt để lấy kích thước của dtc_totalsize():
      merged_fdt_size = dtc_totalsize(merged_fdt);
    4. Truyền DT đã hợp nhất để khởi động nhân:
      my_kernel_entry(0, machine_type, merged_fdt);

Mã DTO mẫu

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