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 cách tối ưu hoá mà bạn có thể thực hiện cho 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 che phủ nút gốc và chi tiết cách định cấu hình lớp phủ nén trong hình ảnh DTBO. Công cụ này cũng cung cấp các mẫu mã và hướng dẫn triển khai.

Dòng lệnh kernel

Dòng lệnh kernel ban đầu 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 thuộc tính này với nhau vị trí bằng 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à lớp phủ DT, vì vậy bạn phải đặt dòng lệnh kernel của DT chính vào chosen/bootargs và dòng lệnh nhân của lớp phủ DT trong chosen/bootargs_ext. Sau đó, trình tải khởi động có thể nối các thông số này vị trí và truyền kết quả đến nhân.

main.dts lớp phủ.dts
/dts-v1/;

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

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

libufdt

Trong khi những giá trị mới nhất libfdt hỗ trợ DTO, bạn nên sử dụng libufdt để triển khai DTO (Nguồn AOSP (Dự án nguồn mở Android) tại platform/system/libufdt). libufdt xây dựng một cấu trúc cây thực (cây thiết bị không được làm phẳng, hoặc ufdt) từ cây thiết bị đã làm phẳng (FDT), nhờ đó, công cụ này có thể cải thiện hợp nhất hai tệp .dtb từ O(N2) với O(N, trong đó N là phần tử số nút trong cây.

Kiểm thử hiệu suất

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

Kết quả kiểm tra hiệu suất cho thiết bị Pixel so sánh libufdtlibfdt. Số lượng nút cơ sở hiệu ứng tương tự nhau, nhưng bao gồm những điểm khác biệt sau:

  • 500 thao tác lớp phủ (nối hoặc ghi đè) hoạt động có thời gian gấp 6 đến 8 lần mức chênh lệch
  • 1000 thao tác lớp phủ (nối hoặc ghi đè) có thời gian từ 8 đến 10 lần mức chênh lệch

Ví dụ về số lượng thêm được đặt thành X:

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

Ví dụ về trường hợp số lượng ghi đè đượ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à dữ liệu libfdt cấu trúc. Khi sử dụng libufdt, bạn phải bao gồm và liên kết libfdt (tuy nhiên, trong mã của mình, bạn có thể sử dụng libfdt API để vận hành DTB hoặc DTBO).

API DTO libufdt

Sau đây là API chính cho DTO trong 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);

Tham số main_fdt_header là DT chính và overlay_fdt là vùng đệm chứa nội dung của .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 URL này đến hạt nhân khi khởi động hạt nhân.

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

Các 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 bởi vì các thao tác lớp phủ đều dựa vào nhãn. Vì DT chính phải xác định và lớp phủ DT sẽ gán các nút cần phủ nhãn, bạn không thể cung cấp nhãn cho nút gốc (và do đó không thể phủ lên nút gốc nút).

Nhà cung cấp hệ thống SoC phải xác định khả năng bao phủ của DT chính; ODM/OEM chỉ có thể thêm hoặc ghi đè các nút có nhãn do nhà cung cấp SoC xác định. Là một để giải quyết sự cố này, bạn có thể xác định 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 bên dưới nút gốc như mô tả bên dưới:

main.dts lớp phủ.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 {
        ...
    };
    ...
};

Dùng lớp phủ nén

Android 9 hỗ trợ thêm việc sử dụng lớp phủ nén trong hình ảnh DTBO khi sử dụng phiên bản 1 của tiêu đề bảng DT. Khi sử dụng tiêu đề DTBO v1, 4 bit có ý nghĩa nhỏ nhất của trường cờ trong dt_table_entry cho biết định dạng nén của mục nhập 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ợ định dạng nén zlibgzip.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 bổ sung tính năng hỗ trợ cho việc kiểm thử tệp nén lớp phủ cho thử nghiệm 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 một ví dụ về cách triển khai DTO với libufdt (mã mẫu bên dưới).

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

  1. Bao gồm thư viện. Để sử dụng libufdt, hãy thêm libfdt cho cấu trúc dữ liệu và API:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
    
  2. Tải DT chính và lớp phủ DT. Tải .dtb.dtbo từ dung lượng lưu trữ sang 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ó vùng đệm và dung lượng .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. Sử 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 để lấy DT đã hợp nhất trong FDT định dạng:
      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);
}