Adicionar um novo dispositivo

Use as informações apresentadas nesta página para criar os makefiles para seu dispositivo e produto.

Cada novo módulo do Android precisa ter um arquivo de configuração para direcionar o sistema de build com metadados do módulo, dependências de tempo de compilação e instruções de empacotamento. O Android usa o sistema de build Soong (link em inglês). Consulte Criar para o Android para mais informações sobre o sistema de build do Android.

Compreender as camadas de build

A hierarquia de build inclui as camadas de abstração que correspondem à composição física de um dispositivo. Essas camadas são descritas na tabela abaixo. Cada camada se relaciona com aquela acima em um relacionamento um para muitos. Por exemplo, uma arquitetura pode ter mais de uma placa, e cada placa pode ter mais de um produto. Você pode definir um elemento em uma determinada camada como uma especialização de um elemento na mesma camada, o que elimina a cópia e simplifica a manutenção.

Camada Exemplo Descrição
Produto myProduct, myProduct_eu, myProduct_eu_fr, j2, sdk A camada de produto define a especificação de recursos de um produto de venda, como os módulos a serem criados, as localidades aceitas e a configuração de várias localidades. Em outras palavras, esse é o nome do produto geral. Variáveis específicas de produto são definidas nos makefiles de definição do produto. Um produto pode ter heranças de outras definições de produtos, o que simplifica a manutenção. Um método comum é criar um produto base contendo recursos aplicáveis a todos os produtos e, em seguida, criar variantes do produto com base nele. Por exemplo, dois produtos que diferem apenas nos rádios (CDMA versus GSM) podem herdar do mesmo produto base que não define um rádio.
Placa/dispositivo marlin, blueline, coral A camada de placa/dispositivo representa a camada física de plástico no dispositivo (ou seja, o design industrial do dispositivo). Essa camada também representa o esquema cru de um produto. Isso inclui os periféricos na placa e sua configuração. Os nomes usados são meramente códigos para diferentes configurações de placa/dispositivo.
Arch arm, x86, arm64, x86_64 A camada de arquitetura descreve a configuração do processador e a Interface binária de aplicativo (ABI) em execução na placa.

Usar variantes de build

Ao criar um produto específico, é conveniente ter pequenas variantes no build de lançamento. Em uma definição, o módulo pode especificar tags com LOCAL_MODULE_TAGS, que podem ser um ou mais valores de optional (padrão), debug e eng.

Se um módulo não especificar uma tag (por LOCAL_MODULE_TAGS), a tag será optional por padrão. Um módulo opcional será instalado somente se for exigido pela configuração do produto com PRODUCT_PACKAGES.

Estas são as variantes de build definidas atualmente:

Variante Descrição
eng Esta é a variação padrão.
  • Instala os módulos marcados com eng ou debug.
  • Instala módulos de acordo com os arquivos de definição do produto, além dos módulos marcados.
  • ro.secure=0
  • ro.debuggable=1
  • ro.kernel.android.checkjni=1
  • adb está ativado por padrão.
user A variante escolhida para ser a versão final.
  • Instala os módulos marcados com user.
  • Instala módulos de acordo com os arquivos de definição do produto, além dos módulos marcados.
  • ro.secure=1
  • ro.debuggable=0
  • adb está desativado por padrão.
userdebug O mesmo que user, com estas exceções:
  • Instala módulos marcados com debug também.
  • ro.debuggable=1
  • adb está ativado por padrão.

Diretrizes de userdebug

A execução de builds userdebug nos testes ajuda os desenvolvedores de dispositivos a entenderem o desempenho e a potência das versões em desenvolvimento. Para manter a consistência entre os builds de usuário e de userdebug e para receber métricas confiáveis em builds usados para depuração, os desenvolvedores de dispositivos devem seguir estas diretrizes:

  • userdebug deve ser definido como um build de usuário com acesso raiz ativado, exceto:
    • Apps somente para userdebug que são executados apenas sob demanda pelo usuário.
    • Operações que são executadas apenas durante a manutenção ociosa (no carregador/totalmente carregado), por exemplo, o uso de dex2oatd versus dex2oat para compilações em segundo plano.
  • Não deve haver recursos que dependam do tipo de build para serem ativados por padrão ou não. Não é recomendável que os desenvolvedores usem qualquer forma de registro que afete a vida útil da bateria, como o log de depuração ou o despejo de heap.
  • Quaisquer recursos de depuração ativados por padrão no userdebug precisam ser claramente definidos e compartilhados com todos os desenvolvedores que trabalham no projeto. Recomendamos ativar recursos de depuração somente por tempo limitado, até que o problema que você está tentando depurar seja resolvido.

Personalizar o build com sobreposições de recursos

O sistema de build do Android usa sobreposições de recursos para personalizar um produto durante o build. As sobreposições de recursos especificam arquivos de recursos aplicados sobre os padrões. Para usar sobreposições de recursos, modifique o arquivo de build do projeto para definir o PRODUCT_PACKAGE_OVERLAYS como um caminho relativo para seu diretório de nível superior. Esse caminho se torna uma raiz paralela pesquisada junto à raiz atual quando o sistema de build procura recursos.

As configurações mais personalizadas com mais frequência estão contidas no arquivo frameworks/base/core/res/res/values/config.xml.

Para configurar uma sobreposição de recurso nesse arquivo, adicione o diretório da sobreposição ao arquivo de build do projeto usando:

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

ou

PRODUCT_PACKAGE_OVERLAYS := vendor/vendor-name/overlay

Em seguida, adicione um arquivo de sobreposição ao diretório, por exemplo:

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

Todas as strings ou matrizes de string encontradas no arquivo de sobreposição config.xml substituem as encontradas no arquivo original.

Criar um produto

É possível organizar os arquivos de origem do dispositivo de maneiras diferentes. Veja uma breve descrição de uma maneira de organizar uma implementação do Pixel.

O Pixel é implementado com uma configuração de dispositivo principal chamada marlin. Com base nessa configuração de dispositivo, um produto é criado com um makefile de definição de produto que declara informações específicas do produto sobre o dispositivo, por exemplo, o nome e o modelo. Consulte o diretório device/google/marlin para saber como tudo isso está configurado.

Criar makefiles de produto

As etapas abaixo descrevem como configurar makefiles de produtos de maneira semelhante à linha de produtos do Pixel:

  1. Crie um diretório device/<company-name>/<device-name> para o produto. Por exemplo, device/google/marlin. Esse diretório conterá o código-fonte do seu dispositivo e os makefiles para criá-los.
  2. Crie um makefile device.mk que declare os arquivos e módulos necessários para o dispositivo. Veja um exemplo em: device/google/marlin/device-marlin.mk.
  3. Crie um makefile de definição de produto para criar um produto específico com base no dispositivo. O makefile a seguir foi retirado de device/google/marlin/aosp_marlin.mk como exemplo. Observe que o produto é herdado dos arquivos device/google/marlin/device-marlin.mk e vendor/google/marlin/device-vendor-marlin.mk pelo makefile, além de declarar as informações específicas do produto, como nome, marca e modelo.
    # 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
    

    Consulte Como definir variáveis de definição de produto para ver outras variáveis específicas do produto que podem ser adicionadas aos seus makefiles.

  4. Crie um arquivo AndroidProducts.mk que aponte para os makefiles do produto. Neste exemplo, apenas o makefile de definição do produto é necessário. O exemplo abaixo é de device/google/marlin/AndroidProducts.mk, que contém o Pixel (marlin) e o Pixel XL (sailfish) que compartilharam a maioria das configurações:
    PRODUCT_MAKEFILES := \
    	$(LOCAL_DIR)/aosp_marlin.mk \
    	$(LOCAL_DIR)/aosp_sailfish.mk
    
    COMMON_LUNCH_CHOICES := \
    	aosp_marlin-userdebug \
    	aosp_sailfish-userdebug
    
  5. Crie um makefile BoardConfig.mk contendo as configurações específicas da placa. Veja um exemplo em: device/google/marlin/BoardConfig.mk.
  6. Apenas para o Android 9 e versões anteriores, crie um arquivo vendorsetup.sh para adicionar seu produto (um "lunch combo") ao build com uma variante de build separada por um traço. Exemplo:
    add_lunch_combo <product-name>-userdebug
    
  7. Nesse ponto, você pode criar mais variantes de produtos com base no mesmo dispositivo.

Estabelecer variáveis de definição de produto

Variáveis específicas de produto são definidas no makefile do produto. A tabela mostra algumas das variáveis mantidas em um arquivo de definição de produto.

Variável Descrição Exemplo
PRODUCT_AAPT_CONFIG Configurações de aapt a serem usadas ao criar pacotes.
PRODUCT_BRAND A marca (por exemplo, operadora) para a qual o software é personalizado.
PRODUCT_CHARACTERISTICS Características do aapt para permitir a inclusão de recursos específicos da variante em um pacote. tablet, nosdcard
PRODUCT_COPY_FILES Lista de palavras como source_path:destination_path. O arquivo no caminho de origem precisa ser copiado para o caminho de destino ao criar esse produto. As regras para as etapas de cópia são definidas em config/makefile.
PRODUCT_DEVICE Nome do design industrial. Esse também é o nome da placa, e o sistema de build o utiliza para localizar o BoardConfig.mk. tuna
PRODUCT_LOCALES Uma lista separada por espaço de código de idioma de duas letras, pares de códigos de país de duas letras que descrevem várias configurações para o usuário, por exemplo, o idioma da interface e a formatação de data, hora e moeda. A primeira localidade listada em PRODUCT_LOCALES é usada como a padrão do produto. en_GB, de_DE, es_ES, fr_CA
PRODUCT_MANUFACTURER Nome do fabricante. acme
PRODUCT_MODEL Nome visível para o usuário final do produto final.
PRODUCT_NAME Nome visível para o usuário final do produto geral. Aparece na tela Configurações > Sobre.
PRODUCT_OTA_PUBLIC_KEYS Lista de chaves públicas Over the Air (OTA) para o produto.
PRODUCT_PACKAGES Lista dos APKs e módulos a serem instalados. Contatos do calendário
PRODUCT_PACKAGE_OVERLAYS Indica se os recursos padrão precisam ser usados ou se alguma sobreposição específica do produto precisa ser adicionada. vendor/acme/overlay
PRODUCT_SYSTEM_PROPERTIES Lista das atribuições de propriedades do sistema no formato "key=value" para a partição do sistema. As propriedades do sistema para outras partições podem ser definidas por meio de PRODUCT_<PARTITION>_PROPERTIES, como em PRODUCT_VENDOR_PROPERTIES para a partição do fornecedor. Nomes de partição com suporte: SYSTEM, VENDOR, ODM, SYSTEM_EXT e PRODUCT.

Configurar o filtro de localidade e o idioma padrão do sistema

Use essas informações para configurar o filtro de localidade e o idioma padrão do sistema e, em seguida, ative o filtro de localidade para um novo tipo de dispositivo.

Propriedades

Configure o idioma padrão e o filtro de localidade do sistema usando propriedades de sistema dedicadas:

  • ro.product.locale: para definir a localidade padrão. Inicialmente, essa propriedade é definida como a primeira localidade na variável PRODUCT_LOCALES e é possível substituir esse valor. Para mais informações, consulte a tabela Definir variáveis de definição de produto.
  • ro.localization.locale_filter: para definir um filtro de localidade, usando uma expressão regular aplicada a nomes de localidade. Por exemplo:
    • Filtro incluso: ^(de-AT|de-DE|en|uk).*: permite apenas o alemão (variantes da Áustria e da Alemanha), todas as variantes inglesas do inglês e ucraniano.
    • Filtro exclusivo, ^(?!de-IT|es).*: exclui o alemão (variante da Itália) e todas as variantes do espanhol.

Ativar o filtro de localidade

Para ativar o filtro, defina o valor da string da propriedade do sistema ro.localization.locale_filter.

Ao definir o valor da propriedade de filtro e o idioma padrão com oem/oem.prop durante a calibração de fábrica, você pode configurar restrições sem colocar o filtro na imagem do sistema. Confira se as propriedades foram selecionadas da partição do OEM ao as adicionar à variável PRODUCT_OEM_PROPERTIES, conforme indicado abaixo:

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

Em seguida, os valores reais são gravados na oem/oem.prop para refletir os requisitos de destino na produção. Nessa abordagem, os valores padrão são mantidos durante a redefinição de fábrica. As configurações iniciais se parecem exatamente com a primeira configuração do usuário.

Definir ADB_VENDOR_KEYS para conexão por USB

A variável de ambiente ADB_VENDOR_KEYS permite que os fabricantes de dispositivos acessem os builds depuráveis (-userdebug e -eng, mas não -user) por adb sem autorização manual. Normalmente, o adb gera para cada computador cliente uma chave de autenticação RSA exclusiva que será enviada para qualquer dispositivo conectado. Essa é a mesma chave RSA mostrada na caixa de diálogo de autorização do adb. Como alternativa, você pode criar chaves conhecidas na imagem do sistema e compartilhá-las com o cliente adb. Isso é útil no desenvolvimento do SO, especialmente em testes, porque evita a necessidade de interação manual com a caixa de diálogo de autorização do adb.

Para criar chaves de fornecedores, uma pessoa (geralmente um gerente de versão) precisa fazer o seguinte:

  1. Gerar um par de chaves usando adb keygen. Para dispositivos do Google, um novo par de chaves é gerado para cada nova versão do SO.
  2. Fazer check-in de pares de chaves, em algum lugar na árvore de origem. O Google as armazena em vendor/google/security/adb/, por exemplo.
  3. Definir as PRODUCT_ADB_KEYS da variável de build para apontar para o diretório de chaves. Para fazer isso, o Google adiciona um arquivo Android.mk no diretório de chaves que diz PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub, ajudando a garantir a geração de um novo par de chaves para cada versão do SO.

Veja o makefile que o Google usa no diretório em que armazenamos nossos pares de chaves com check-in para cada versão:

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

Para usar essas chaves de fornecedor, um engenheiro só precisa definir a variável de ambiente ADB_VENDOR_KEYS de modo que aponte para o diretório em que os pares de chaves são armazenados. Isso instrui o adb a testar essas chaves canônicas antes de recorrer à chave de host gerada que requer autorização manual. Quando adb não conseguir se conectar a um dispositivo não autorizado, a mensagem de erro sugerirá que você defina ADB_VENDOR_KEYS, se ainda não estiver definido.