Cómo agregar un dispositivo nuevo

Usa la información de esta página para crear los archivos makefile para tu dispositivo y producto.

Cada módulo nuevo de Android debe tener un archivo de configuración para dirigir el sistema de compilación con metadatos del módulo, instrucciones de empaquetado y dependencias de tiempo de compilación. Android usa el sistema de compilación Soong. Consulta Cómo compilar Android para obtener más información sobre el sistema de compilación de Android.

Información sobre las capas de compilación

La jerarquía de compilación incluye capas de abstracción que corresponden a la estructura física de un dispositivo. Estas capas se describen en la tabla que aparece a continuación. Cada una de ellas tiene una relación de uno a varios con la que está por encima. Por ejemplo, una arquitectura puede tener varias placas y cada una de ellas puede tener varios productos. Puedes definir un elemento en una capa específica como una especialización de un elemento en la misma capa, lo que elimina la necesidad de copiado y simplifica el mantenimiento.

Capa Ejemplo Descripción
Producto myProduct, myProduct_eu, myProduct_eu_fr, j2, sdk La capa de producto define cuál es la función específica de un producto de envío, como los módulos por compilar, los idiomas compatibles y las diferentes configuraciones regionales. En otras palabras, este es el nombre del producto completo. Las variables específicas del producto se definen en los archivos makefile de definición del producto. Un producto puede heredar la configuración de otras definiciones del producto, lo que simplifica el mantenimiento. Un método común es crear un producto base que contenga las funciones que se aplican a todos los productos y, luego, crear variantes de productos basadas en este. Por ejemplo, si hay dos productos que solo se diferencian por las radios (CDMA versus GSM), estos pueden heredarse del mismo producto base sin una radio definida.
Placa o dispositivo marlin, blueline, coral La capa de placa o dispositivo representa la capa física de plástico del dispositivo (es decir, su diseño industrial). Además, representa el esquema básico de un producto, lo que incluye los periféricos de la placa y su configuración. Los nombres usados son solo códigos para las diferentes opciones de configuración de la placa o del dispositivo.
Arquitectura arm, x86, arm64, x86_64 La capa de arquitectura describe la configuración del procesador y la interfaz binaria de la aplicación (ABI) que se ejecuta en la placa.

Cómo usar variantes de compilación

Cuando compilas un producto en particular, resulta útil realizar pequeñas variantes en la compilación de lanzamiento final. En una definición de módulo, el módulo puede especificar etiquetas con LOCAL_MODULE_TAGS, que pueden ser uno o varios valores optional (valor predeterminado), debug y eng.

Si no se especifica una etiqueta en un módulo (con LOCAL_MODULE_TAGS), el valor predeterminado es optional. Se instala un módulo opcional solo si la configuración del producto con PRODUCT_PACKAGES lo requiere.

Las variantes de compilación definidas actualmente son las siguientes:

Variante Descripción
eng Este es el tipo predeterminado.
  • Instala módulos etiquetados con eng o debug.
  • Instala módulos en función de los archivos de definición del producto, además de los módulos etiquetados.
  • ro.secure=0
  • ro.debuggable=1
  • ro.kernel.android.checkjni=1
  • adb está habilitado de forma predeterminada.
user Es la variante destinada a ser la versión final.
  • Instala módulos etiquetados con user.
  • Instala módulos en función de los archivos de definición del producto, además de los módulos etiquetados.
  • ro.secure=1
  • ro.debuggable=0
  • adb está inhabilitado de forma predeterminada.
userdebug Es igual que user, con las siguientes excepciones:
  • También instala módulos etiquetados con debug.
  • ro.debuggable=1
  • adb está habilitado de forma predeterminada.

Lineamientos para userdebug

Ejecutar compilaciones de userdebug durante las pruebas ayuda a los desarrolladores de dispositivos a comprender el rendimiento y la potencia de las actualizaciones en desarrollo. Para mantener la coherencia entre el usuario y las compilaciones de userdebug, y lograr métricas confiables en las compilaciones que se usan para la depuración, los desarrolladores de dispositivos deben seguir estos lineamientos:

  • La variante userdebug se define como una compilación de usuario con permisos de administrador habilitados, excepto por lo siguiente:
    • Las apps específicas de userdebug que se ejecutan solo a pedido del usuario
    • Las operaciones que se ejecutan solo durante el mantenimiento inactivo (durante la carga o con carga completa), como usar dex2oatd versus dex2oat para compilaciones en segundo plano
  • No incluyas funciones que estén habilitadas o inhabilitadas de forma predeterminada según el tipo de compilación. No se aconseja que los desarrolladores usen ningún tipo de registro que afecte la duración de la batería, como el registro de depuración o el volcado de montón
  • Todas las funciones de depuración que están habilitadas de forma predeterminada en userdebug deben estar claramente definidas y compartirse con todos los desarrolladores que trabajan en el proyecto. Solo debes habilitar las funciones de depuración por tiempo limitado hasta que se solucione el problema que intentas depurar

Cómo personalizar la compilación con superposiciones de recursos

El sistema de compilación de Android usa superposiciones de recursos para personalizar un producto en el tiempo de compilación. Las superposiciones de recursos especifican archivos de recursos que se priorizan sobre los valores predeterminados. Para usarlas, modifica el archivo de compilación del proyecto para establecer el valor PRODUCT_PACKAGE_OVERLAYS en una ruta de acceso relativa a tu directorio de nivel superior. Esta ruta se convierte en una raíz secundaria que se busca junto con la raíz actual cuando el sistema de compilación busca recursos.

Las opciones de configuración que se personalizan con mayor frecuencia se encuentran en el archivo frameworks/base/core/res/res/values/config.xml.

Para configurar una superposición de recursos en este archivo, agrega el directorio de superposiciones al archivo de compilación del proyecto de la siguiente manera:

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

o

PRODUCT_PACKAGE_OVERLAYS := vendor/vendor-name/overlay

Luego, agrega un archivo de superposición al directorio, por ejemplo:

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

Cualquier cadena o array de cadenas que se encuentre en el archivo config.xml de superposición reemplazará a las cadenas que se encuentren en el archivo original.

Cómo compilar un producto

Existen muchas maneras de organizar los archivos fuente en tu dispositivo. Esta es una breve descripción de una manera de organizar una implementación de Pixel.

Para implementar Pixel, se usa una configuración del dispositivo principal llamada marlin. A partir de ella, se crea un producto con un archivo makefile de definición del producto que declara la información específica de este sobre el dispositivo, como el nombre y el modelo. Puedes consultar el directorio device/google/marlin para ver cómo se realizó la configuración.

Cómo escribir archivos makefile de un producto

En los siguientes pasos, se describe cómo configurar los archivos makefile de un producto de manera similar a la línea de productos Pixel:

  1. Crea un directorio device/<company-name>/<device-name> para tu producto. Por ejemplo, device/google/marlin. Este incluirá el código fuente del dispositivo junto con los archivos makefile para compilar.
  2. Crea un archivo makefile device.mk en el que se declaren los archivos y los módulos necesarios para el dispositivo. Si quieres ver un ejemplo, consulta device/google/marlin/device-marlin.mk.
  3. Crea un archivo makefile de definición del producto para crear un producto específico basado en el dispositivo. El siguiente archivo makefile se toma de device/google/marlin/aosp_marlin.mk a modo de ejemplo. Observa que el producto hereda su configuración de los archivos device/google/marlin/device-marlin.mk y vendor/google/marlin/device-vendor-marlin.mk por medio del archivo makefile y, a su vez, declara la información específica del producto, como el nombre, la marca y el 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
    

    Consulta Cómo establecer variables de definición del producto para obtener otras variables específicas del producto que puedes agregar a tus archivos makefile.

  4. Crea un archivo AndroidProducts.mk que apunte a los archivos makefile del producto. En este ejemplo solo se necesita el archivo makefile de la definición del producto. El ejemplo que aparece a continuación es del archivo device/google/marlin/AndroidProducts.mk (que contiene tanto marlin, el dispositivo Pixel, como sailfish, el dispositivo Pixel XL, los cuales comparten gran parte de su configuración):
    PRODUCT_MAKEFILES := \
    	$(LOCAL_DIR)/aosp_marlin.mk \
    	$(LOCAL_DIR)/aosp_sailfish.mk
    
    COMMON_LUNCH_CHOICES := \
    	aosp_marlin-userdebug \
    	aosp_sailfish-userdebug
    
  5. Crea un archivo makefile BoardConfig.mk que contenga las opciones de configuración específicas de la placa. Si quieres ver un ejemplo, consulta device/google/marlin/BoardConfig.mk.
  6. Solo en Android 9 y versiones anteriores, crea un archivo vendorsetup.sh para agregar tu producto (un "combo de almuerzo") a la compilación junto con la una variante de compilación (separados por un guión). Por ejemplo:
    add_lunch_combo <product-name>-userdebug
    
  7. En esta etapa puedes crear más variantes de productos basadas en el mismo dispositivo.

Cómo establecer variables de definición del producto

Las variables específicas del producto se definen en su archivo makefile. En la siguiente tabla, se muestran algunas de las variables incluidas en un archivo de definición del producto.

Variable Descripción Ejemplo
PRODUCT_AAPT_CONFIG Son opciones de configuración de aapt para usar durante la creación de paquetes.
PRODUCT_BRAND Es la marca (por ejemplo, el operador) para la que se customiza el software.
PRODUCT_CHARACTERISTICS Son las características de aapt que permiten agregar recursos específicos de una variante al paquete. tablet, nosdcard
PRODUCT_COPY_FILES Lista de palabras como source_path:destination_path. El archivo de la ruta de acceso de origen debe copiarse en la ruta de acceso de destino cuando se compila este producto. Las reglas para los pasos de copiado se definen en config/makefile.
PRODUCT_DEVICE Nombre del diseño industrial. Este también es el nombre de la placa, y el sistema de compilación lo usa para localizar el archivo BoardConfig.mk. tuna
PRODUCT_LOCALES Es una lista separada por espacios de códigos de idioma de dos letras y pares de códigos de país de dos letras que describen varias opciones de configuración para el usuario, como el idioma de la IU y el formato de la hora, la fecha y la moneda. La primera configuración regional que aparece en el valor PRODUCT_LOCALES se usa como la configuración regional predeterminada del producto. en_GB, de_DE, es_ES y fr_CA
PRODUCT_MANUFACTURER Es el nombre del fabricante. acme
PRODUCT_MODEL Es el nombre visible del usuario final para el producto final.
PRODUCT_NAME Es el nombre visible para el usuario final de todo el producto. Aparece en la pantalla Configuración > Acerca de.
PRODUCT_OTA_PUBLIC_KEYS Es la lista de claves públicas inalámbricas (OTA) del producto.
PRODUCT_PACKAGES Es la lista de los APKs y los módulos para instalar. Contactos del calendario
PRODUCT_PACKAGE_OVERLAYS Indica si se deben usar los recursos predeterminados o se deben agregar superposiciones específicas del producto. vendor/acme/overlay
PRODUCT_SYSTEM_PROPERTIES Es la lista de las tareas de propiedades del sistema en formato "key=value" de la partición del sistema. Las propiedades del sistema de otras particiones se pueden configurar a través de PRODUCT_<PARTITION>_PROPERTIES como en PRODUCT_VENDOR_PROPERTIES de la partición del proveedor. Nombres de partición compatibles: SYSTEM, VENDOR, ODM, SYSTEM_EXT y PRODUCT.

Cómo establecer el idioma predeterminado y el filtro de configuración regional del sistema

Usa esta información para establecer el idioma predeterminado y el filtro de configuración regional del sistema. Luego, habilita el filtro de configuración regional de un tipo de dispositivo nuevo.

Propiedades

Establece el idioma predeterminado y el filtro de configuración regional del sistema usando propiedades dedicadas del sistema:

  • ro.product.locale: Para establecer la configuración regional predeterminada. Se establece inicialmente como la primera configuración regional de la variable PRODUCT_LOCALES. Puedes anular ese valor (si quieres obtener más información, consulta la tabla que figura en Cómo establecer variables de definición del producto).
  • ro.localization.locale_filter: Para establecer un filtro de configuración regional usando una expresión regular aplicada a nombres de configuraciones regionales. Por ejemplo:
    • Filtro inclusivo: ^(de-AT|de-DE|en|uk).* ‒ permite solo alemán (variante de Austria y Alemania), todas las variantes de inglés, y ucraniano.
    • Filtro exclusivo: ^(?!de-IT|es).* ‒ excluye alemán (variante de Italia) y todas las variantes de español.

Cómo habilitar el filtro de configuración regional

Para habilitar el filtro, establece el valor de cadena de propiedad del sistema ro.localization.locale_filter.

Cuando estableces el valor de propiedad del filtro y el idioma predeterminado a través de oem/oem.prop durante la calibración de fábrica, puedes configurar restricciones sin integrar el filtro a la imagen del sistema. Para asegurarte de que estas propiedades se retiren de la partición de OEM, agrégalas a la variable PRODUCT_OEM_PROPERTIES como se indica a continuación:

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

Luego, en producción, los valores reales se escriben en oem/oem.prop para que reflejen los requisitos de destino. Con este enfoque, los valores predeterminados se retienen durante el restablecimiento de la configuración de fábrica, de modo que el usuario vea que la configuración inicial se parece exactamente a una primera configuración.

Cómo configurar ADB_VENDOR_KEYS para que se conecte por USB

La variable de entorno ADB_VENDOR_KEYS permite que los fabricantes de dispositivos accedan a compilaciones depurables (-userdebug y -eng, pero no -user) con adb sin autorización manual. Normalmente, adb genera una clave de autenticación RSA única para cada computadora cliente, que enviará a cualquier dispositivo conectado. Esa es la clave RSA que se muestra en el diálogo de autorización de adb. Como alternativa, puedes compilar claves conocidas en la imagen del sistema y compartirlas con el cliente de adb. Esto es útil para el desarrollo del SO y, en especial, para las pruebas, ya que evita la necesidad de interactuar manualmente con el diálogo de autorización de adb.

Para crear claves de proveedor, una persona (en general, un administrador de lanzamientos) debe hacer lo siguiente:

  1. Genera un par de claves con adb keygen. Para los dispositivos de Google, Google genera un nuevo par de claves con cada versión nueva de SO.
  2. Guarda los pares de claves en algún lugar del árbol de fuentes. Por ejemplo, Google los almacena en vendor/google/security/adb/.
  3. Configura la variante de compilación PRODUCT_ADB_KEYS para que apunte a tu directorio de claves. Para ello, Google agrega un archivo Android.mk en el directorio de claves que dice PRODUCT_ADB_KEYS := $(LOCAL_PATH)/$(PLATFORM_VERSION).adb_key.pub, lo que garantiza que recordemos generar un nuevo par de claves para cada versión de SO.

Este es el archivo makefile que usa Google en el directorio en donde almacenamos nuestros pares de claves registrados de cada lanzamiento:

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 estas claves de proveedor, un ingeniero debe configurar la variable de entorno ADB_VENDOR_KEYS para que apunte al directorio en el que se almacenan los pares de claves. Esto le indica a adb que pruebe esas claves canónicas antes de volver a la clave de host generada que requiere autorización manual. Cuando adb no se puede conectar a un dispositivo no autorizado, el mensaje de error sugerirá que configures ADB_VENDOR_KEYS si aún no lo hiciste.