Cómo agregar un nuevo dispositivo

Usa la información de esta página a fin de 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.

Cómo interpretar 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 placa 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 define cuál es la función específica de un producto de envío, como los módulos a 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 frente a 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, el diseño industrial de este). 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 y 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 modificaciones en la compilación final de lanzamiento. En una definición de módulo, el módulo puede especificar etiquetas con LOCAL_MODULE_TAGS, que pueden ser uno o varios valores de optional (valor predeterminado), debug y eng.

Si no se especifica una etiqueta en un módulo (mediante LOCAL_MODULE_TAGS), el valor predeterminado es optional. Se instala un módulo opcional únicamente 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 el valor 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 versiones en desarrollo. A fin de 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 frente a 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 deben 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 al momento de compilarlo. 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 a fin de 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 string o arreglo de strings que se encuentre en el archivo config.xml de superposición reemplazará a las strings 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 esta, 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 del 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 módulos necesarios para el dispositivo. Para ver un ejemplo, consulta device/google/marlin/device-marlin.mk.
  3. Crea un archivo makefile de definición del producto a fin de 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 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. Para 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 el archivo makefile de este. 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 proveedor) para la que se personaliza el software (si corresponde).
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 el archivo 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 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, fr_CA
PRODUCT_MANUFACTURER Es el nombre del fabricante. acme
PRODUCT_MODEL Es el nombre visible ante el usuario final para el producto final.
PRODUCT_NAME Es el nombre visible ante el usuario final para 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) para el producto.
PRODUCT_PACKAGES Es la lista de los APK y módulos para instalar. Son los 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 asignaciones de propiedades del sistema en formato "key=value" para la partición del sistema. Las propiedades del sistema para otras particiones se pueden configurar mediante PRODUCT_<PARTITION>_PROPERTIES como PRODUCT_VENDOR_PROPERTIES para 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 este filtro para un nuevo tipo de dispositivo.

Propiedades

Configura el idioma predeterminado y el filtro de configuración regional del sistema con propiedades dedicadas del sistema:

  • ro.product.locale: Para establecer la configuración regional predeterminada. En un principio, esto se establece en la primera configuración regional de la variable PRODUCT_LOCALES; puedes anular ese valor. (Para obtener más información, consulta la tabla de Cómo establecer variables de definición del producto).
  • ro.localization.locale_filter: Para establecer un filtro de configuración regional mediante una expresión regular aplicada a los nombres de configuración regional. Por ejemplo:
    • Filtro inclusivo: ^(de-AT|de-DE|en|uk).*, que solo permite alemán (variantes de Austria y Alemania), todas las variantes de inglés y ucraniano.
    • Filtro exclusivo: ^(?!de-IT|es).*, que no incluye alemán (variante de Italia) ni todas las variantes de español.

Cómo habilitar el filtro de configuración regional

Para habilitar el filtro, configura el valor ro.localization.locale_filter de la string de propiedad del sistema.

Cuando configuras el valor de la propiedad del filtro y el idioma predeterminado mediante oem/oem.prop durante la calibración de fábrica, puedes configurar restricciones sin crear el filtro en la imagen del sistema. Asegúrate de que estas propiedades se seleccionen de la partición OEM; para ello, 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 reflejar los requisitos de destino. Con este enfoque, los valores predeterminados se conservan durante el restablecimiento de la configuración de fábrica, por lo que la configuración inicial se ve igual que una primera configuración para el usuario.

Cómo configurar ADB_VENDOR_KEYS para que se conecte mediante USB

La variable de entorno ADB_VENDOR_KEYS permite que los fabricantes de dispositivos accedan a compilaciones depurables (-userdebug y -eng, pero no -user) mediante 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, el usuario (generalmente, un administrador de versiones) 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 Google usa en el directorio donde almacenamos nuestros pares de claves registrados de cada versión:

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 a fin de que dirija 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 pueda conectar a un dispositivo no autorizado, un mensaje de error te sugerirá que configures ADB_VENDOR_KEYS si aún no lo hiciste.