Optymalizacja organizacji zajmujących się handlem narkotykami

Na tej stronie omawiamy optymalizacje, które możesz wprowadzić w implementacji nakładek drzewa urządzeń, opisujemy ograniczenia dotyczące nakładania na węzeł główny oraz wyjaśniamy, jak skonfigurować skompresowane nakładki w obrazie DTBO. Znajdziesz tu też przykładowe instrukcje implementacji i kod.

Wiersz poleceń jądra

Oryginalny wiersz poleceń jądra w drzewie urządzeń (DT) znajduje się w węźle chosen/bootargs. Program rozruchowy musi połączyć tę lokalizację z innymi źródłami wiersza poleceń jądra systemu:

/dts-v1/;

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

Nakładki drzewa urządzeń nie mogą łączyć wartości z głównego drzewa urządzeń i nakładki drzewa urządzeń, dlatego wiersz poleceń jądra głównego drzewa urządzeń musisz umieścić w chosen/bootargs i wiersz poleceń jądra nakładki drzewa urządzeń w chosen/bootargs_ext. Program rozruchowy może następnie połączyć te lokalizacje i przekazać wynik do jądra systemu (operacyjnego).

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

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

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

libufdt

Choć najnowsze libfdt obsługuje nakładki drzewa urządzeń, do ich wdrożenia zalecamy użycie zasady libufdt (Źródło AOSP: platform/system/libufdt). libufdt tworzy prawdziwą strukturę drzewa (niespłaszczone drzewo urządzeń, lub ufdt) z płaskiego drzewa urządzeń (FDT), aby poprawić połączenie dwóch plików .dtb z zakresu O(N2) do O(N), gdzie N określa liczbę węzłów w drzewie.

Testowanie wydajności

W testach wewnętrznych Google użycie libufdt na 2405 .dtb i 283 .dtbo węzłach drzewa urządzeń powoduje, że rozmiary plików po kompilacji wynoszą 70 618 i 8566 bajtów. W porównaniu z implementacją nakładek drzewa urządzeń przeniesioną z FreeBSD (czas działania 124 ms) czas działania nakładek drzewa urządzeń libufdt wynosi 10 ms.

W testach wydajności na urządzeniach Pixel porównano libufdt i libfdt. Liczba węzłów bazowych ma podobny wpływ, ale obejmuje te różnice:

  • 500 operacji nakładania (dołączania lub zastępowania) ma 6–8-krotną różnicę czasu .
  • 1000 operacji nakładania (dołączania lub zastępowania) ma 8–10-krotną różnicę czasu .

Przykład z liczbą dołączania ustawioną na X:

Rysunek 1. Liczba dołączania wynosi X.

Przykład z liczbą zastępowania ustawioną na X:

Rysunek 2. Liczba zastępowania wynosi X.

libufdt jest opracowywana przy użyciu niektórych interfejsów API i struktur danych libfdt. Gdy używasz libufdt, musisz dołączyć i połączyć libfdt (jednak w kodzie możesz używać interfejsu API libfdt do obsługi DTB lub DTBO).

Interfejs API nakładek drzewa urządzeń libufdt

Główny interfejs API nakładek drzewa urządzeń w libufdt jest taki:

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

Parametr main_fdt_header to główne drzewo urządzeń, a overlay_fdt to bufor zawierający zawartość pliku .dtbo. Wartość zwracana to nowy bufor zawierający scalone drzewo urządzeń (lub null w przypadku błędu). Scalone drzewo urządzeń jest sformatowane w FDT, które możesz przekazać do jądra podczas jego uruchamiania.

Nowy bufor z wartości zwracanej jest tworzony przez dto_malloc(), który należy zaimplementować podczas portowania libufdt do programu rozruchowego. Implementacje referencyjne znajdziesz w sysdeps/libufdt_sysdeps_*.c.

Ograniczenia dotyczące węzła głównego

Nie możesz nałożyć nowego węzła ani właściwości na węzeł główny głównego drzewa urządzeń ponieważ operacje nakładania opierają się na etykietach. Główne drzewo urządzeń musi definiować etykietę , a nakładka drzewa urządzeń przypisuje etykiety do węzłów, które mają zostać nałożone, dlatego nie możesz przypisać etykiety do węzła głównego (a tym samym nie możesz nałożyć węzła głównego ).

Dostawcy układów SOC muszą zdefiniować możliwość nakładania na główne drzewo urządzeń. Producenci ODM/OEM mogą tylko dołączać lub zastępować węzły z etykietami zdefiniowanymi przez dostawcę układów SOC. Aby obejść ten problem, możesz zdefiniować węzeł odm pod węzłem głównym w podstawowym drzewie urządzeń, co umożliwi wszystkim węzłom ODM w nakładce drzewa urządzeń dodawanie nowych węzłów. Możesz też umieścić wszystkie węzły związane z układem SOC w podstawowym drzewie urządzeń w soc węźle pod węzłem głównym, jak opisano poniżej:

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

Używanie skompresowanych nakładek

Android 9 dodaje obsługę używania skompresowanych nakładek w obrazie DTBO, gdy używasz wersji 1 nagłówka tabeli DT. Gdy używasz nagłówka DTBO w wersji 1, 4 najmniej znaczące bity pola flagi w dt_table_entry wskazują format kompresji wpisu 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 */
};

Obecnie obsługiwane są kompresje zlib i gzip.

enum dt_compression_info {
    NO_COMPRESSION,
    ZLIB_COMPRESSION,
    GZIP_COMPRESSION
};

Android 9 dodaje obsługę testowania skompresowanych nakładek do testu VtsFirmwareDtboVerification, aby pomóc Ci sprawdzić poprawność aplikacji nakładki.

Przykładowa implementacja nakładek drzewa urządzeń

Poniżej znajdziesz instrukcje przykładowej implementacji nakładek drzewa urządzeń za pomocą libufdt (przykładowy kod poniżej).

Przykładowe instrukcje dotyczące nakładek drzewa urządzeń

  1. Dołącz biblioteki. Aby używać libufdt, dołącz libfdt dla struktur danych i interfejsów API:
    #include <libfdt.h>
    #include <ufdt_overlay.h>
  2. Wczytaj główne drzewo urządzeń i nakładkę drzewa urządzeń. Wczytaj .dtb i .dtbo z pamięci do pamięci (dokładne kroki zależą od Twojego projektu). W tym momencie, powinny być dostępne bufor i rozmiar .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. Nałóż drzewa urządzeń:
    1. Użyj ufdt_install_blob(), aby pobrać nagłówek FDT dla głównego drzewa urządzeń:
      main_fdt_header = ufdt_install_blob(main_buf, main_size);
      main_fdt_size = main_size;
    2. Wywołaj ufdt_apply_overlay() do nakładek drzewa urządzeń, aby uzyskać scalone drzewo urządzeń w formacie FDT format:
      merged_fdt = ufdt_apply_overlay(main_fdt_header, main_fdt_size,
                                      overlay_buf, overlay_size);
    3. Użyj merged_fdt, aby uzyskać rozmiar dtc_totalsize():
      merged_fdt_size = dtc_totalsize(merged_fdt);
    4. Przekaż scalone drzewo urządzeń, aby uruchomić jądro:
      my_kernel_entry(0, machine_type, merged_fdt);

Przykładowy kod nakładek drzewa urządzeń

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