Dodawanie nowego urządzenia

Skorzystaj z informacji na tej stronie, aby utworzyć pliki makefile dla urządzenia i produktu.

Każdy nowy moduł Androida musi mieć plik konfiguracyjny, który zawiera metadane modułu, zależności czasu kompilacji i instrukcje pakowania. Android korzysta z systemu kompilacji Soong. Więcej informacji o systemie kompilacji Androida znajdziesz w artykule Kompilowanie Androida.

Informacje o warstwach kompilacji

Hierarchia kompilacji obejmuje warstwy abstrakcji odpowiadające fizycznej budowie urządzenia. Warstwy te opisujemy w tabeli poniżej. Każda warstwa jest powiązana z warstwą powyżej relacją jeden do wielu. Na przykład architektura może mieć więcej niż jedną tablicę, a każda tablica może zawierać więcej niż 1 produkt. Możesz zdefiniować element w danej warstwie jako specjalizację elementu w tej samej warstwie, co eliminuje kopiowanie i upraszcza konserwację.

Warstwa Przykład Opis
Produkt myProduct, myProduct_eu, myProduct_eu_fr, j2, sdk Warstwa produktu określa specyfikację funkcji usługi dostawy, np. moduły do utworzenia, obsługiwane regiony i konfigurację dla różnych regionów. Innymi słowy, jest to nazwa produktu jako całości. Zmienne specyficzne dla produktu są zdefiniowane w plikach makefile definicji produktu. Produkt może dziedziczyć definicje innych produktów, co upraszcza zarządzanie. Często stosowaną metodą jest utworzenie produktu podstawowego, który zawiera funkcje mające zastosowanie do wszystkich produktów, a następnie utworzenie wariantów produktu na podstawie tego produktu podstawowego. Na przykład 2 produkty, które różnią się tylko radiem (CDMA i GSM), mogą dziedziczyć po tym samym produkcie bazowym, który nie definiuje radia.
Płyta/urządzenie marlin, blueline, coral Warstwa płyty/urządzenia reprezentuje fizyczną warstwę plastiku na urządzeniu (czyli jego konstrukcję). Ta warstwa przedstawia też schematy produktu. Obejmują one urządzenia peryferyjne na płycie i ich konfigurację. Używane nazwy to tylko kody różnych konfiguracji płyty lub urządzenia.
Łuk arm, x86, arm64, x86_64 Warstwa architektury opisuje konfigurację procesora i interfejs binarny aplikacji (ABI) działający na płycie.

Korzystanie z wariantów kompilacji

Podczas tworzenia wersji na konkretny produkt przydatne są drobne różnice w ostatecznej wersji. W definicji modułu można określić tagi za pomocą parametru LOCAL_MODULE_TAGS, który może zawierać co najmniej 1 wartość z tych: optional (domyślna), debugeng.

Jeśli moduł nie określa tagu (za pomocą LOCAL_MODULE_TAGS), jego tag domyślnie przyjmuje wartość optional. Opcjonalny moduł jest instalowany tylko wtedy, gdy jest wymagany przez konfigurację produktu z PRODUCT_PACKAGES.

Są to obecnie zdefiniowane warianty kompilacji.

Wariant Opis
eng Jest to domyślny wariant.
  • Instaluje moduły oznaczone tagiem eng lub debug.
  • Instaluje moduły zgodnie z plikami definicji produktu, a także moduły oznaczone tagami.
  • ro.secure=0
  • ro.debuggable=1
  • ro.kernel.android.checkjni=1
  • adb jest domyślnie włączona.
user Wariant, który ma być ostateczną wersją.
  • Instaluje moduły oznaczone tagiem user.
  • Instaluje moduły zgodnie z plikami definicji produktu, a także moduły oznaczone tagami.
  • ro.secure=1
  • ro.debuggable=0
  • adb jest domyślnie wyłączona.
userdebug Taka sama cena jak w hotelu user, z tymi wyjątkami:
  • Instaluje też moduły oznaczone tagiem debug.
  • ro.debuggable=1
  • adb jest domyślnie włączona.

Wskazówki dotyczące wersji userdebug

Uruchamianie wersji userdebug w testach pomaga deweloperom urządzeń poznać wydajność i zużycie energii w przypadku wersji w trakcie opracowywania. Aby zachować spójność między wersjami użytkownika i wersjami debugowania użytkownika oraz uzyskać wiarygodne dane w wersjach używanych do debugowania, deweloperzy urządzeń powinni postępować zgodnie z tymi wytycznymi:

  • userdebug to kompilacja użytkownika z włączonym dostępem do roota, z wyjątkiem:
    • aplikacje tylko do debugowania przez użytkownika, które są uruchamiane tylko na żądanie użytkownika;
    • Operacje, które są wykonywane tylko podczas konserwacji w trybie bezczynności (podczas ładowania lub po pełnym naładowaniu), np. używanie dex2oatd zamiast dex2oat do kompilacji w tle.
  • Nie uwzględniaj funkcji, które są domyślnie włączone lub wyłączone w zależności od typu kompilacji. Deweloperzy nie powinni używać żadnej formy rejestrowania, która wpływa na żywotność baterii, np. rejestrowania debugowania lub zrzutu sterty.
  • Wszystkie funkcje debugowania, które są domyślnie włączone w wersji userdebug, powinny być jasno określone i udostępnione wszystkim deweloperom pracującym nad projektem. Funkcje debugowania należy włączać tylko na ograniczony czas, dopóki nie zostanie rozwiązany problem, który próbujesz debugować.

Dostosowywanie kompilacji za pomocą nakładek na zasoby

System kompilacji Androida używa nakładek zasobów do dostosowywania produktu w momencie kompilacji. Nakładki zasobów określają pliki zasobów, które są stosowane na domyślne. Aby używać nakładek zasobów, zmodyfikuj plik kompilacji projektu, aby ustawić PRODUCT_PACKAGE_OVERLAYS na ścieżkę względną względem katalogu najwyższego poziomu. Ta ścieżka staje się katalogiem głównym cienia, który jest przeszukiwany wraz z bieżącym katalogiem głównym, gdy system kompilacji szuka zasobów.

Najczęściej dostosowywane ustawienia znajdują się w pliku frameworks/base/core/res/res/values/config.xml.

Aby skonfigurować nakładkę zasobu w tym pliku, dodaj katalog nakładki do pliku kompilacji projektu, korzystając z jednej z tych metod:

PRODUCT_PACKAGE_OVERLAYS := device/device-implementer/device-name/overlay

lub

PRODUCT_PACKAGE_OVERLAYS := vendor/vendor-name/overlay

Następnie dodaj do katalogu plik nakładki, np.:

vendor/foobar/overlay/frameworks/base/core/res/res/values/config.xml

Wszelkie ciągi znaków lub tablice ciągów znaków znalezione w pliku nakładki config.xml zastępują te znalezione w pliku oryginalnym.

Tworzenie produktu

Pliki źródłowe na urządzeniu możesz porządkować na różne sposoby. Oto krótki opis jednego ze sposobów organizacji wdrożenia Pixela.

Pixel jest wdrażany z konfiguracją urządzenia głównego o nazwie marlin. Na podstawie tej konfiguracji urządzenia tworzony jest produkt z plikiem makefile definicji produktu, który zawiera informacje o urządzeniu, takie jak nazwa i model. Możesz wyświetlić device/google/marlinkatalog, aby zobaczyć, jak to wszystko jest skonfigurowane.

Tworzenie plików makefile produktów

Poniżej znajdziesz opis konfigurowania plików makefile produktów w sposób podobny do tego, w jaki konfigurowane są pliki makefile linii produktów Pixel:

  1. Utwórz katalog device/<company-name>/<device-name> dla swojego produktu. Na przykład: device/google/marlin. Ten katalog będzie zawierać kod źródłowy urządzenia wraz z plikami makefile do jego skompilowania.
  2. Utwórz plik device.mk, który deklaruje pliki i moduły potrzebne na urządzeniu. Przykład znajdziesz w sekcji device/google/marlin/device-marlin.mk.
  3. Utwórz plik makefile definicji produktu, aby utworzyć konkretny produkt na podstawie urządzenia. Poniższy plik makefile pochodzi z device/google/marlin/aosp_marlin.mk. Zwróć uwagę, że produkt dziedziczy z plików device/google/marlin/device-marlin.mkvendor/google/marlin/device-vendor-marlin.mk za pomocą pliku makefile, a także deklaruje informacje specyficzne dla produktu, takie jak nazwa, marka i model.
    # Inherit from the common Open Source product configuration
    $(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
    $(call inherit-product, $(SRC_TARGET_DIR)/product/aosp_base_telephony.mk)
    
    PRODUCT_NAME := aosp_marlin
    PRODUCT_DEVICE := marlin
    PRODUCT_BRAND := Android
    PRODUCT_MODEL := AOSP on msm8996
    PRODUCT_MANUFACTURER := Google
    PRODUCT_RESTRICT_VENDOR_FILES := true
    
    PRODUCT_COPY_FILES += device/google/marlin/fstab.common:$(TARGET_COPY_OUT_VENDOR)/etc/fstab.marlin
    
    $(call inherit-product, device/google/marlin/device-marlin.mk)
    $(call inherit-product-if-exists, vendor/google_devices/marlin/device-vendor-marlin.mk)
    
    PRODUCT_PACKAGES += \
        Launcher3QuickStep \
        WallpaperPicker
    

    Więcej informacji o dodatkowych zmiennych specyficznych dla produktów, które możesz dodać do plików makefile, znajdziesz w artykule Ustawianie zmiennych definicji produktu.

  4. Utwórz plik AndroidProducts.mk, który wskazuje pliki makefile produktu. W tym przykładzie potrzebny jest tylko plik makefile definicji produktu. Poniższy przykład pochodzi z device/google/marlin/AndroidProducts.mk (zawiera zarówno marlina, czyli Pixela, jak i żaglówkę, czyli Pixela XL, które miały podobną konfigurację):
    PRODUCT_MAKEFILES := \
    	$(LOCAL_DIR)/aosp_marlin.mk \
    	$(LOCAL_DIR)/aosp_sailfish.mk
    
    COMMON_LUNCH_CHOICES := \
    	aosp_marlin-userdebug \
    	aosp_sailfish-userdebug
    
  5. Utwórz plik BoardConfig.mk makefile zawierający konfiguracje specyficzne dla płyty. Przykład znajdziesz w sekcji device/google/marlin/BoardConfig.mk.
  6. W przypadku Androida 9 i starszych wersji utwórz plik vendorsetup.sh, aby dodać produkt („zestaw lunchowy”) do kompilacji wraz z wariantem kompilacji oddzielonymi myślnikiem. Na przykład:
    add_lunch_combo <product-name>-userdebug
    
  7. Na tym etapie możesz utworzyć więcej wariantów produktu na podstawie tego samego urządzenia.

Ustawianie zmiennych definicji produktu

Zmienne specyficzne dla produktu są zdefiniowane w pliku makefile produktu. Tabela zawiera niektóre zmienne przechowywane w pliku definicji produktu.

Zmienna Opis Przykład
PRODUCT_AAPT_CONFIG aapt konfiguracji do użycia podczas tworzenia pakietów.
PRODUCT_BRAND Marka (np. operator), dla której oprogramowanie jest dostosowane.
PRODUCT_CHARACTERISTICS aapt charakterystyki, aby umożliwić dodawanie do pakietu zasobów specyficznych dla wariantu. tablet, nosdcard
PRODUCT_COPY_FILES Lista słów podobnych do source_path:destination_path. Podczas tworzenia tego produktu plik znajdujący się w ścieżce źródłowej powinien zostać skopiowany do ścieżki docelowej. Reguły dotyczące kroków kopiowania są zdefiniowane w config/makefile.
PRODUCT_DEVICE Nazwa wzoru przemysłowego. Jest to również nazwa płyty, która jest używana przez system kompilacji do lokalizowania BoardConfig.mk. tuna
PRODUCT_LOCALES Lista par dwuliterowych kodów języka i dwuliterowych kodów kraju oddzielonych spacjami, które opisują kilka ustawień użytkownika, np. język interfejsu oraz formatowanie czasu, daty i waluty. Pierwsze ustawienie regionalne wymienione w PRODUCT_LOCALES jest używane jako domyślne ustawienie regionalne produktu. en_GB, de_DE, es_ES, fr_CA
PRODUCT_MANUFACTURER Nazwa producenta. acme
PRODUCT_MODEL Nazwa produktu końcowego widoczna dla użytkownika.
PRODUCT_NAME Nazwa produktu widoczna dla użytkownika. Wyświetla się na ekranie Ustawienia > Informacje.
PRODUCT_OTA_PUBLIC_KEYS Lista kluczy publicznych OTA (Over-the-Air) dla produktu.
PRODUCT_PACKAGES Lista plików APK i modułów do zainstalowania. Kontakty w Kalendarzu
PRODUCT_PACKAGE_OVERLAYS Określa, czy używać zasobów domyślnych, czy dodawać nakładki specyficzne dla produktu. vendor/acme/overlay
PRODUCT_SYSTEM_PROPERTIES Lista przypisań właściwości systemowych w formacie "key=value" dla partycji systemowej. Właściwości systemowe dla innych partycji można ustawić za pomocą PRODUCT_<PARTITION>_PROPERTIES, tak jak w przypadku partycji dostawcy – PRODUCT_VENDOR_PROPERTIES. Obsługiwane nazwy partycji: SYSTEM, VENDOR, ODM, SYSTEM_EXT i PRODUCT.

Konfigurowanie domyślnego języka systemu i filtra regionalnego

Użyj tych informacji, aby skonfigurować domyślny filtr języka i ustawień regionalnych systemu, a następnie włączyć filtr ustawień regionalnych dla nowego typu urządzenia.

Właściwości

Skonfiguruj zarówno domyślny język, jak i filtr ustawień regionalnych systemu za pomocą specjalnych właściwości systemowych:

  • ro.product.locale: do ustawiania domyślnego regionu. Początkowo jest ona ustawiona na pierwszy język w zmiennej PRODUCT_LOCALES. Możesz zastąpić tę wartość. (Więcej informacji znajdziesz w tabeli Ustawianie zmiennych definicji produktu).
  • ro.localization.locale_filter: do ustawiania filtra języka za pomocą wyrażenia regularnego stosowanego do nazw języków. Na przykład:
    • Filtr uwzględniający: ^(de-AT|de-DE|en|uk).* – zezwala tylko na język niemiecki (warianty austriacki i niemiecki), wszystkie warianty języka angielskiego i język ukraiński.
    • Filtr wykluczający: ^(?!de-IT|es).* – wyklucza język niemiecki (wariant włoski) i wszystkie warianty języka hiszpańskiego.

Włącz filtr języka

Aby włączyć filtr, ustaw wartość ciągu właściwości systemowej ro.localization.locale_filter.

Ustawiając wartość właściwości filtra i język domyślny za pomocą oem/oem.prop podczas kalibracji fabrycznej, możesz skonfigurować ograniczenia bez wbudowywania filtra w obraz systemu. Aby mieć pewność, że te właściwości są pobierane z partycji OEM, dodaj je do zmiennej PRODUCT_OEM_PROPERTIES w sposób podany poniżej:

# Delegation for OEM customization
PRODUCT_OEM_PROPERTIES += \
    ro.product.locale \
    ro.localization.locale_filter

Następnie w środowisku produkcyjnym rzeczywiste wartości są zapisywane w oem/oem.prop, aby odzwierciedlać wymagania docelowe. Dzięki temu podczas przywracania ustawień fabrycznych zachowywane są wartości domyślne, więc początkowe ustawienia wyglądają dla użytkownika dokładnie tak samo jak podczas pierwszej konfiguracji.

Ustawienie zmiennej ADB_VENDOR_KEYS w celu połączenia przez USB

Zmienna środowiskowa ADB_VENDOR_KEYS umożliwia producentom urządzeń uzyskiwanie dostępu do wersji debugowania (–userdebug i –eng, ale nie –user) przez adb bez ręcznej autoryzacji. Zwykle adb generuje niepowtarzalny klucz uwierzytelniania RSA dla każdego komputera klienckiego, który wysyła do każdego podłączonego urządzenia. Jest to klucz RSA widoczny w oknie dialogowym autoryzacji adb. Alternatywnie możesz wbudować znane klucze w obraz systemu i udostępnić je klientowi adb. Jest to przydatne w przypadku tworzenia systemów operacyjnych, a zwłaszcza testowania, ponieważ nie trzeba ręcznie wchodzić w interakcję z oknem autoryzacji adb.

Aby utworzyć klucze dostawcy, jedna osoba (zwykle menedżer wersji) powinna:

  1. Wygeneruj parę kluczy za pomocą adb keygen. W przypadku urządzeń Google generuje nową parę kluczy dla każdej nowej wersji systemu operacyjnego.
  2. Sprawdź pary kluczy w drzewie źródłowym. Google przechowuje je na przykład w vendor/google/security/adb/.
  3. Ustaw zmienną kompilacji PRODUCT_ADB_KEYS tak, aby wskazywała katalog kluczy. Google robi to, dodając do katalogu kluczy plik Android.mk, który zawiera tekst PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub. Dzięki temu pamiętamy, aby generować nową parę kluczy dla każdej wersji systemu operacyjnego.

Oto plik makefile, którego Google używa w katalogu, w którym przechowujemy pary kluczy dla każdej wersji:

PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub

ifeq ($(wildcard $(PRODUCT_ADB_KEYS)),)
  $(warning ========================)
  $(warning The adb key for this release)
  $(warning )
  $(warning   $(PRODUCT_ADB_KEYS))
  $(warning )
  $(warning does not exist. Most likely PLATFORM_VERSION in build/core/version_defaults.mk)
  $(warning has changed and a new adb key needs to be generated.)
  $(warning )
  $(warning Please run the following commands to create a new key:)
  $(warning )
  $(warning   make -j8 adb)
  $(warning   LOGNAME=android-eng HOSTNAME=google.com adb keygen $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
  $(warning )
  $(warning and upload/review/submit the changes)
  $(warning ========================)
  $(error done)
endif

Aby użyć tych kluczy dostawcy, inżynier musi tylko ustawić zmienną środowiskową ADB_VENDOR_KEYS, aby wskazywała katalog, w którym są przechowywane pary kluczy. Dzięki temu adb najpierw spróbuje użyć tych kluczy kanonicznych, a potem wygenerowanego klucza hosta, który wymaga ręcznej autoryzacji. Gdy adb nie może połączyć się z nieautoryzowanym urządzeniem, w komunikacie o błędzie pojawi się sugestia, aby ustawić ADB_VENDOR_KEYS, jeśli nie jest jeszcze ustawiony.