Android 10 agrega compatibilidad con la interfaz estable de Android Lenguaje de definición (AIDL), una nueva forma de hacer un seguimiento del programa de postulación (API) y la interfaz binaria de aplicación (ABI) proporcionadas por el AIDL interfaces. El AIDL estable funciona igual que el AIDL, pero el sistema de compilación realiza un seguimiento la compatibilidad de la interfaz y hay restricciones sobre lo que puedes hacer:
- Las interfaces se definen en el sistema de compilación con
aidl_interfaces
. - Las interfaces solo pueden contener datos estructurados. Objetos parcelables que representan el tipos preferidos se crean automáticamente según su definición del AIDL y se ordenan y deserializan automáticamente.
- Las interfaces se pueden declarar como estables (compatibles con versiones anteriores). Cuando esta sucede, se realiza un seguimiento de su API y se controla su versión en un archivo junto al AIDL interfaz de usuario.
AIDL estructurado versus estable
El AIDL estructurado se refiere a los tipos definidos completamente en AIDL. Por ejemplo, un la declaración parcelable (un parcelable personalizado) no está estructurado como AIDL. Objetos parcelables con sus campos definidos en el AIDL se denominan parcelables estructurados.
El AIDL estable requiere un AIDL estructurado para que el sistema de compilación y el compilador
pueda comprender si los cambios realizados en objetos parcelables son retrocompatibles.
Sin embargo, no todas las interfaces estructuradas son estables. Para ser estables,
una interfaz debe usar solo tipos estructurados y, además, debe usar los siguientes
las funciones de control de versiones. Por el contrario, una interfaz no es estable si la compilación principal
se usa para compilarlo o si se configura unstable:true
.
Cómo definir una interfaz de AIDL
Una definición de aidl_interface
se ve de la siguiente manera:
aidl_interface {
name: "my-aidl",
srcs: ["srcs/aidl/**/*.aidl"],
local_include_dir: "srcs/aidl",
imports: ["other-aidl"],
versions_with_info: [
{
version: "1",
imports: ["other-aidl-V1"],
},
{
version: "2",
imports: ["other-aidl-V3"],
}
],
stability: "vintf",
backend: {
java: {
enabled: true,
platform_apis: true,
},
cpp: {
enabled: true,
},
ndk: {
enabled: true,
},
rust: {
enabled: true,
},
},
}
name
: Es el nombre del módulo de interfaz del AIDL que identifica de forma única un Interfaz de AIDL.srcs
: Es la lista de archivos de origen del AIDL que componen la interfaz. La ruta Para un tipo de AIDL,Foo
definido en un paquetecom.acme
debe estar en<base_path>/com/acme/Foo.aidl
, donde<base_path>
puede ser cualquier directorio relacionado con el directorio en el que se encuentraAndroid.bp
. En el ejemplo anterior,<base_path>
essrcs/aidl
.local_include_dir
: Es la ruta desde donde comienza el nombre del paquete. Integra corresponde a<base_path>
que se explicó anteriormente.imports
: Es una lista de los módulosaidl_interface
que usa. Si uno de tus Las interfaces de AIDL usan una interfaz o un objeto parcelable de otroaidl_interface
, escribe su nombre aquí. Este puede ser solo el nombre, para consultar las últimas versión o el nombre con el sufijo de la versión (como-V1
) al que se hará referencia una versión específica. Se admite la especificación de una versión desde Android 12versions
: Son las versiones anteriores de la interfaz que son inmovilizado enapi_dir
, a partir de Android 11, lasversions
están inmovilizadas enaidl_api/name
. Si no hay versiones sin actualizar de una interfaz, Esto no debe especificarse y no habrá verificaciones de compatibilidad. Este campo se reemplazó porversions_with_info
para Android 13 y versiones posteriores.versions_with_info
: Lista de tuplas, cada una de las cuales contiene el nombre de un versión sin actualizar y una lista con las importaciones de versiones de otra aidl_interface módulos que importó esta versión de aidl_interface. La definición de la versión V de IFACE de la interfaz del AIDL se encuentra enaidl_api/IFACE/V
Este campo se introdujo en Android 13, y no se debe modificar directamente enAndroid.bp
. El campo es que se agregan o actualizan mediante la invocación de*-update-api
o*-freeze-api
. Además, los camposversions
se migran automáticamente aversions_with_info
. Cuando un usuario invoca a*-update-api
o*-freeze-api
stability
: Es la marca opcional de la promesa de estabilidad de esta interfaz. Esto solo es compatible con"vintf"
. Si no establecesstability
, la compilación verifica que la interfaz sea retrocompatible, a menos Se especificaunstable
. Si no se configura, corresponde a una interfaz con estabilidad dentro de este contexto de compilación (de modo que todos los elementos del sistema, por ejemplo, Por ejemplo, elementos ensystem.img
y particiones relacionadas, o todos los proveedores elementos, por ejemplo, elementos envendor.img
y particiones relacionadas). Sistability
se configura como"vintf"
, lo que corresponde a una promesa de estabilidad: la interfaz debe mantenerse estable mientras se usa.gen_trace
: Es la marca opcional para activar o desactivar el registro. Comienza en En Android 14, el valor predeterminado estrue
paracpp
yjava
backends.host_supported
: La marca opcional que, cuando se establece entrue
, hace que la y las bibliotecas generadas disponibles para el entorno del host.unstable
: Es la marca opcional que se usa para marcar que esta interfaz no funciona. necesitan ser estables. Cuando se establece entrue
, el sistema de compilación no Crea el volcado de API para la interfaz ni requiere que se actualice.frozen
: Es la marca opcional que, cuando se establece entrue
, significa que la interfaz no tiene cambios desde la versión anterior de la interfaz. Esto permite más verificaciones en el tiempo de compilación. Cuando se establece enfalse
, significa que la interfaz está en desarrollo y tiene cambios nuevos, por lo que ejecutarfoo-freeze-api
genera un a la versión nueva y cambiará automáticamente el valor atrue
. Introducida en Android 14.backend.<type>.enabled
: Estas marcas activan o desactivan cada uno de los backends que para el que el compilador de AIDL genera código. Hay cuatro backends compatibles: Java, C++, NDK y Rust. Los backends de Java, C++ y NDK están habilitados de forma predeterminada. Si no se necesita alguno de estos tres backends, se debe inhabilitado explícitamente. Rust está inhabilitado de forma predeterminada hasta que Androidbackend.<type>.apex_available
: Es la lista de nombres de APEX que se generó. biblioteca de stubs disponible.backend.[cpp|java].gen_log
: Es la marca opcional que controla si se realiza lo siguiente: generar un código adicional para recopilar información sobre la transacción.backend.[cpp|java].vndk.enabled
: Es la marca opcional para hacer que esta interfaz. parte de VNDK. El valor predeterminado esfalse
.backend.[cpp|ndk].additional_shared_libraries
: Se introdujo en En Android 14, esta marca agrega dependencias a la bibliotecas nativas. Esta marca es útil conndk_header
ycpp_header
.backend.java.sdk_version
: Es la marca opcional para especificar la versión. del SDK con el que se compila la biblioteca de stubs de Java. El valor predeterminado es"system_current"
No se debe configurar cuandobackend.java.platform_apis
estrue
.backend.java.platform_apis
: La marca opcional que se debe establecer entrue
cuando las bibliotecas generadas deben compilar en la API de la plataforma. en lugar del SDK.
Para cada combinación de versiones y backends habilitados, se usa biblioteca existente. Para obtener información sobre cómo hacer referencia a la versión específica de la biblioteca de stubs Para un backend específico, consulta las Reglas de nombres de módulos.
Cómo escribir archivos AIDL
Las interfaces en AIDL estables son similares a las tradicionales, con el que no tienen permitido usar objetos parcelables no estructurados (porque estos no son estables. consulta Estructurados y estables AIDL). La principal diferencia en el AIDL estable es cómo se definen los objetos parcelables. Anteriormente, se declaraban hacia adelante los objetos parcelables. en (y, por lo tanto, estructurado) de AIDL, los campos parcelables y las variables definidos de manera explícita.
// in a file like 'some/package/Thing.aidl'
package some.package;
parcelable SubThing {
String a = "foo";
int b;
}
Se admite un valor predeterminado (pero no es obligatorio) para boolean
, char
y
float
, double
, byte
, int
, long
y String
. En Android
12. Los valores predeterminados para las enumeraciones definidas por el usuario también se
no es compatible. Cuando no se especifica un valor predeterminado, se usa un valor similar a 0 o vacío.
Las enumeraciones sin un valor predeterminado se inicializan en 0 incluso si hay
no existe un enumerador cero.
Cómo usar bibliotecas de stubs
Después de agregar bibliotecas de stub como dependencia a tu módulo, puedes
puedes incluirlos en tus archivos. Estos son ejemplos de bibliotecas de stubs en la
sistema de compilación (Android.mk
también se puede usar para las definiciones de módulos heredados):
cc_... {
name: ...,
shared_libs: ["my-module-name-cpp"],
...
}
# or
java_... {
name: ...,
// can also be shared_libs if your preference is to load a library and share
// it among multiple users or if you only need access to constants
static_libs: ["my-module-name-java"],
...
}
# or
rust_... {
name: ...,
rustlibs: ["my-module-name-rust"],
...
}
Ejemplo en C++:
#include "some/package/IFoo.h"
#include "some/package/Thing.h"
...
// use just like traditional AIDL
Ejemplo en Java:
import some.package.IFoo;
import some.package.Thing;
...
// use just like traditional AIDL
Ejemplo en Rust:
use aidl_interface_name::aidl::some::package::{IFoo, Thing};
...
// use just like traditional AIDL
Interfaces del control de versiones
La declaración de un módulo con el nombre foo también crea un objetivo en el sistema de compilación
que puedes usar para administrar la API del módulo. Cuando se compila, foo-freeze-api
Agrega una nueva definición de API en api_dir
.
aidl_api/name
, según la versión de Android
agrega un archivo .hash
, que representa la versión recién congelada del
interfaz de usuario. foo-freeze-api también actualiza la propiedad versions_with_info
.
para reflejar la versión adicional y imports
para la versión. Básicamente,
imports
en versions_with_info
se copia del campo imports
. Sin embargo,
se especificó la última versión estable en imports
, en versions_with_info
para el
importar, que no tiene una versión explícita.
Después de especificar la propiedad versions_with_info
, se ejecuta el sistema de compilación
comprobaciones de compatibilidad entre versiones congeladas y también entre la parte superior del árbol (ToT)
y la última versión sin actualizar.
Además, debes administrar la definición de API de la versión de ToT. Cada vez que se crea una API
actualizado, ejecuta foo-update-api para actualizar
aidl_api/name/current
que contiene la definición de la API de la versión ToT.
Para mantener la estabilidad de una interfaz, los propietarios pueden agregar nuevos:
- Métodos hasta el final de una interfaz (o métodos con reglas nuevas series)
- Elementos hasta el final de un elemento parcelable (requiere que se agregue un valor predeterminado para cada uno elemento)
- Valores constantes
- En Android 11, los enumeradores
- En Android 12, los campos al final de una unión
No se permiten otras acciones y nadie más puede modificar una interfaz (de lo contrario, corren el riesgo de colisionar con los cambios que realiza un propietario).
Para probar que todas las interfaces estén bloqueadas antes de lanzarse, puedes compilar con el las siguientes variables de entorno:
AIDL_FROZEN_REL=true m ...
: La compilación requiere todas las interfaces de AIDL estables para se inmovilicen que no tengan ningún campoowner:
especificado.AIDL_FROZEN_OWNERS="aosp test"
: La compilación requiere todas las interfaces de AIDL estables. se inmovilice con el campoowner:
especificado como "aosp" o "probar".
Estabilidad de las importaciones
Actualizar las versiones de importaciones para las versiones congeladas de una interfaz retrocompatible en la capa del AIDL estable. Sin embargo, para actualizarlas, actualizar todos los servidores y clientes que usan una versión anterior de la interfaz y algunas aplicaciones pueden confundirse cuando se mezclan diferentes versiones de tipos. Generalmente, para paquetes de solo tipos o comunes, esto es seguro porque el código necesita que ya están escritas para manejar tipos desconocidos de transacciones de IPC.
En la plataforma de Android, el código android.hardware.graphics.common
es
de este tipo de actualización de versión.
Usa interfaces con control de versiones
Métodos de interfaz
En el tiempo de ejecución, cuando se intentan llamar nuevos métodos en un servidor antiguo, los clientes nuevos un error o una excepción, según el backend.
- El backend
cpp
obtiene::android::UNKNOWN_TRANSACTION
. - El backend
ndk
obtieneSTATUS_UNKNOWN_TRANSACTION
. - El backend
java
obtieneandroid.os.RemoteException
con un mensaje que dice lo siguiente: No se implementó la API.
Si quieres ver estrategias para manejar esto, consulta consultar versiones con los valores predeterminados.
Objetos parcelables
Cuando se agregan campos nuevos a objetos parcelables, los clientes y servidores antiguos los descartan. Cuando los clientes y servidores nuevos reciben objetos parcelables antiguos, los valores predeterminados para los nuevos los campos se completan automáticamente. Esto significa que los valores predeterminados deben ser que se especifica para todos los campos nuevos de un objeto parcelable.
Los clientes no deberían esperar que los servidores usen los campos nuevos, a menos que conozcan servidor implementa la versión que tiene el campo definido (consulta consultar versiones).
Enumeraciones y constantes
Del mismo modo, los clientes y los servidores deben rechazar o ignorar los mensajes no reconocidos valores constantes y enumeradores según corresponda, ya que se pueden agregar más el futuro. Por ejemplo, un servidor no debe anularse cuando recibe un enumerador que no conoce. El servidor debe ignorar el enumerador o mostrará algo para que el cliente sepa que no es compatible en para llevar a cabo esta implementación.
Uniones
Intentar enviar una unión con un campo nuevo falla si el receptor es antiguo y
no conoce el campo. La implementación nunca verá la unión con
el campo nuevo. La falla se ignora si es una
transacción unidireccional; de lo contrario, el error es BAD_VALUE
(para C++ o NDK
backend) o IllegalArgumentException
(para el backend de Java). El error es
si el cliente envía un conjunto de unión al nuevo campo a un
o cuando se trata de un cliente
anterior que recibe la unión de un servidor nuevo.
Administra varias versiones
Un espacio de nombres del vinculador en Android puede tener solo 1 versión de un aidl
específico
interfaz para evitar situaciones en las que los tipos aidl
generados tengan varias
definiciones C++ tiene la regla de una definición que requiere solo una definición.
de cada símbolo.
La compilación de Android genera un error cuando un módulo depende de diferentes
de la misma biblioteca aidl_interface
. El módulo puede depender de
estas bibliotecas directa o indirectamente a través de dependencias de sus
dependencias. Estos errores muestran el gráfico de dependencias del módulo con errores al
las versiones en conflicto de la biblioteca aidl_interface
Todas las
las dependencias deben actualizarse para incluir la misma versión (por lo general, la más reciente)
de estas bibliotecas.
Si muchos módulos diferentes usan la biblioteca de la interfaz, podría ser útil.
para crear cc_defaults
, java_defaults
y rust_defaults
para cualquier grupo de
bibliotecas y procesos que deben usar la misma versión. Al presentar un
en la nueva versión de la interfaz, esos valores predeterminados se pueden actualizar y todos los módulos
que las utilizan se actualizan juntos, lo que garantiza que no usen versiones diferentes
de la interfaz.
cc_defaults {
name: "my.aidl.my-process-group-ndk-shared",
shared_libs: ["my.aidl-V3-ndk"],
...
}
cc_library {
name: "foo",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
cc_binary {
name: "bar",
defaults: ["my.aidl.my-process-group-ndk-shared"],
...
}
Cuando los módulos aidl_interface
importan otros módulos aidl_interface
, se crea
y las dependencias adicionales que requieren
versiones específicas que se usen en conjunto. Esta
puede ser difícil de controlar cuando hay aidl_interface
comunes
los módulos que se importan en varios módulos aidl_interface
que se usan
en los mismos procesos.
Se puede usar aidl_interfaces_defaults
para mantener una definición del
versiones más recientes de dependencias para un aidl_interface
que se pueden actualizar en
un solo lugar, y lo usan todos los módulos de aidl_interface
que quieren importar
esa interfaz común.
aidl_interface_defaults {
name: "android.popular.common-latest-defaults",
imports: ["android.popular.common-V3"],
...
}
aidl_interface {
name: "android.foo",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
aidl_interface {
name: "android.bar",
defaults: ["my.aidl.latest-ndk-shared"],
...
}
Desarrollo basado en marcas
Las interfaces en desarrollo (descongeladas) no se pueden usar en los dispositivos de lanzamiento, ya que no se garantiza que sean retrocompatibles.
El AIDL admite el resguardo en el tiempo de ejecución para estas bibliotecas de interfaces no inmovilizadas a fin de para que el código se escriba en la última versión no inmovilizada y se siga usando en dispositivos de lanzamiento. El comportamiento retrocompatible de los clientes es similar al en el comportamiento existente y, con el resguardo, las implementaciones esos comportamientos. Consulta Usa interfaces con control de versiones.
marca de compilación del AIDL
La marca que controla este comportamiento es RELEASE_AIDL_USE_UNFROZEN
definido en build/release/build_flags.bzl
. true
significa que la versión descongelada de
se usa la interfaz durante el tiempo de ejecución, y false
significa que las bibliotecas de la
Las versiones no inmovilizadas se comportan como la última versión sin actualizar.
Puedes anular la marca true
para
desarrollo local, pero deberá revertirlo a false
antes del lanzamiento. Precio habitual
el desarrollo se realiza con una configuración que tiene la marca establecida en true
.
Matriz de compatibilidad y manifiestos
Los objetos de interfaz de proveedor (objetos VINTF) definen qué versiones se esperan y qué versiones se proporcionan en ambos lados la interfaz del proveedor.
La mayoría de los dispositivos que no son de Cuttlefish se orientan a la matriz de compatibilidad más reciente.
solo después de que se inmovilizan las interfaces, por lo que no hay diferencia en el AIDL
bibliotecas basadas en RELEASE_AIDL_USE_UNFROZEN
.
Matriz
Las interfaces que son propiedad del socio se agregan a interfaces específicas del dispositivo o del producto
de compatibilidad a las que se orienta el dispositivo durante el desarrollo. Entonces, cuando un
se agrega a la matriz de compatibilidad una versión nueva y descongelada de la interfaz
las versiones congeladas anteriores deben permanecer
RELEASE_AIDL_USE_UNFROZEN=false
Puedes manejar esto usando diferentes
archivos de matriz de compatibilidad para diferentes RELEASE_AIDL_USE_UNFROZEN
configuraciones o permitir ambas versiones en un único archivo de matriz de compatibilidad
que se usa en todas las configuraciones.
Por ejemplo, cuando agregues una versión 4 no inmovilizada, usa <version>3-4</version>
.
Cuando la versión 4 esté bloqueada, puedes quitar la versión 3 de la matriz de compatibilidad.
porque la versión sin actualizar 4 se usa cuando RELEASE_AIDL_USE_UNFROZEN
está
false
Manifiestos
En Android 15, se introdujo un cambio en libvintf
en
modificar los archivos de manifiesto en el tiempo de compilación según el valor de
RELEASE_AIDL_USE_UNFROZEN
Los manifiestos y los fragmentos de manifiesto declaran qué versión de una interfaz.
implementa un servicio. Cuando uses la versión más reciente de una interfaz,
el manifiesto debe actualizarse para reflejar esta nueva versión. Cuándo
RELEASE_AIDL_USE_UNFROZEN=false
las entradas del manifiesto se ajustan según
libvintf
para reflejar el cambio en la biblioteca del AIDL generada. La versión
se modifica de la versión descongelada, N
, a
la última versión sin actualizar N - 1
. Por lo tanto, los usuarios no necesitan administrar
manifiestos o fragmentos de manifiestos para cada uno de sus servicios.
Cambios en el cliente de HAL
El código del cliente HAL debe ser retrocompatible con todos los dispositivos congelados admitidos.
versión. Cuando RELEASE_AIDL_USE_UNFROZEN
es false
, los servicios siempre buscan
como la última versión sin actualizar o una anterior (por ejemplo, llamar al nuevo dispositivo desbloqueado)
métodos que muestran UNKNOWN_TRANSACTION
, o los nuevos campos parcelable
tienen su
valores predeterminados). Los clientes del framework de Android deben estar retrocedidos
compatibles con otras versiones anteriores, pero este es un nuevo detalle para
clientes proveedores y clientes de interfaces propiedad de socios.
Cambios en la implementación de HAL
La mayor diferencia en el desarrollo de HAL con el desarrollo basado en marcas es
necesario para que las implementaciones de HAL sean retrocompatibles con el último
versión sin actualizar para que funcione cuando RELEASE_AIDL_USE_UNFROZEN
sea false
.
La consideración de la retrocompatibilidad en las implementaciones y el código del dispositivo es una
ejercicio. Consulta Usa versiones
interfaces de usuario.
Las consideraciones de retrocompatibilidad suelen ser las mismas para el clientes y servidores, y para el código del framework y del proveedor, pero existen diferencias sutiles que debes tener en cuenta, ya que ahora con la implementación de dos versiones que usan el mismo código fuente (la versión actual, versión).
Ejemplo: Una interfaz tiene tres versiones congeladas. La interfaz se actualiza con una
método nuevo. El cliente y el servicio se actualizan para usar la nueva versión 4
biblioteca. Debido a que la biblioteca V4 se basa en una versión no inmovilizada de la
se comporta como la última versión sin actualizar, cuando
RELEASE_AIDL_USE_UNFROZEN
es false
y evita el uso del método nuevo.
Cuando la interfaz está bloqueada, todos los valores de RELEASE_AIDL_USE_UNFROZEN
usan eso.
versión sin actualizar y se puede quitar el código que controla la retrocompatibilidad.
Cuando llames a métodos en devoluciones de llamada, debes manejar correctamente el caso cuando
Se muestra UNKNOWN_TRANSACTION
. Es posible que los clientes implementen dos
de una devolución de llamada según la configuración de lanzamiento, así que no puedes
se da por sentado que el cliente envía la versión más reciente, y es posible que se devuelvan
esto. Esto es similar a cómo los clientes estables de AIDL mantienen
la compatibilidad con los servidores se describe en Cómo usar
interfaces de usuario.
// Get the callback along with the version of the callback
ScopedAStatus RegisterMyCallback(const std::shared_ptr<IMyCallback>& cb) override {
mMyCallback = cb;
// Get the version of the callback for later when we call methods on it
auto status = mMyCallback->getInterfaceVersion(&mMyCallbackVersion);
return status;
}
// Example of using the callback later
void NotifyCallbackLater() {
// From the latest frozen version (V2)
mMyCallback->foo();
// Call this method from the unfrozen V3 only if the callback is at least V3
if (mMyCallbackVersion >= 3) {
mMyCallback->bar();
}
}
Es posible que los campos nuevos en los tipos existentes (parcelable
, enum
, union
)
no existen o contienen sus valores predeterminados cuando RELEASE_AIDL_USE_UNFROZEN
es
false
y los valores de los campos nuevos que un servicio intenta enviar se descartan.
para salir del proceso.
No se pueden enviar los nuevos tipos que se agregan en esta versión no inmovilizada o recibidos a través de la interfaz.
La implementación nunca recibe una llamada de nuevos métodos por parte de ningún cliente cuando
RELEASE_AIDL_USE_UNFROZEN
es false
.
Ten cuidado de usar nuevos enumeradores solo con la versión en la que se presentan. y no a la versión anterior.
Por lo general, usas foo->getInterfaceVersion()
para ver qué versión del control remoto
usa la interfaz de usuario. Sin embargo, con la compatibilidad
con el control de versiones basado en marcas
implementando dos versiones diferentes, así que quizás quieras obtener la versión
la interfaz actual. Puedes hacerlo obteniendo la versión de interfaz del
objeto actual, por ejemplo, this->getInterfaceVersion()
o el otro
métodos para my_ver
. Visita Consulta de la versión de interfaz del control remoto
objeto
para obtener más información.
Nuevas interfaces estables de VINTF
Cuando se agrega un nuevo paquete de interfaz de AIDL, no hay última versión sin actualizar, por lo que
no hay comportamiento al que recurrir cuando RELEASE_AIDL_USE_UNFROZEN
es
false
No uses estas interfaces. Cuando RELEASE_AIDL_USE_UNFROZEN
sea
false
, el administrador de servicios no permitirá que el servicio registre la interfaz
y los clientes no lo encontrarán.
Puedes agregar los servicios de forma condicional según el valor de la
RELEASE_AIDL_USE_UNFROZEN
en el archivo makefile del dispositivo:
ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
PRODUCT_PACKAGES += \
android.hardware.health.storage-service
endif
Si el servicio forma parte de un proceso más grande, por lo que no puedes agregarlo al dispositivo
condicionalmente, puedes verificar si el servicio se declaró con
IServiceManager::isDeclared()
Si se declaró y no se pudo registrar,
a anular el proceso. Si no está declarado, se espera que no se registre.
Cuttlefish como herramienta de desarrollo
Después del congelamiento de VINTF todos los años, ajustamos la compatibilidad con el marco de trabajo.
matrix (FCM) target-level
y el PRODUCT_SHIPPING_API_LEVEL
de Cuttlefish
así que reflejan los dispositivos que
se lanzan con el lanzamiento del próximo año. Ajustamos
target-level
y PRODUCT_SHIPPING_API_LEVEL
para asegurarte de que haya
dispositivo de lanzamiento probado y que cumpla con los nuevos requisitos de los
lanzamiento.
Cuando RELEASE_AIDL_USE_UNFROZEN
es true
, Cuttlefish es
para desarrollar versiones futuras de Android. Se orienta a las aplicaciones de Android
nivel de FCM de la versión y PRODUCT_SHIPPING_API_LEVEL
, lo cual requiere que cumpla con
los requisitos de software del proveedor (VSR) del próximo lanzamiento.
Cuando RELEASE_AIDL_USE_UNFROZEN
es false
, Cuttlefish tiene la configuración
target-level
y PRODUCT_SHIPPING_API_LEVEL
para reflejar un dispositivo de lanzamiento.
En Android 14 y versiones anteriores, esta diferenciación sería
logrado con diferentes ramas de Git que no detectan el cambio a FCM
target-level
, nivel de API de envío o cualquier otro código segmentado para la siguiente
lanzamiento.
Reglas de nomenclatura de módulos
En Android 11, para cada combinación de versiones y
habilitar los backends, se crea automáticamente un módulo de biblioteca de stub. Para recomendar
a un módulo de biblioteca de stub específico para la vinculación, no uses el nombre del
aidl_interface
, pero el nombre del módulo de biblioteca de stub, que es
ifacename-version-backend, donde
ifacename
: Es el nombre del móduloaidl_interface
.version
es cualquiera deVversion-number
para las versiones sin actualizarVlatest-frozen-version-number + 1
para el versión en punta del árbol (aún congelada)
backend
es cualquiera dejava
para el backend de Java,cpp
para el backend de C++,ndk
ondk_platform
para el backend del NDK. El primero es para aplicaciones, La última es para uso de la plataforma hasta Android 13. En Para Android 13 y versiones posteriores, solo usanndk
.rust
para el backend de Rust
Supongamos que hay un módulo con el nombre foo y su última versión es 2, y admite NDK y C++. En este caso, el AIDL genera los siguientes módulos:
- Basado en la versión 1
foo-V1-(java|cpp|ndk|ndk_platform|rust)
- Basado en la versión 2 (la versión estable más reciente)
foo-V2-(java|cpp|ndk|ndk_platform|rust)
- Según la versión de ToT
foo-V3-(java|cpp|ndk|ndk_platform|rust)
En comparación con Android 11:
foo-backend
, que hace referencia a la versión estable más reciente versión se convierte enfoo-V2-backend
foo-unstable-backend
, que hace referencia al ToT versión se convierte enfoo-V3-backend
Los nombres del archivo de salida son siempre los mismos que los nombres de los módulos.
- Basado en la versión 1:
foo-V1-(cpp|ndk|ndk_platform|rust).so
- Basado en la versión 2:
foo-V2-(cpp|ndk|ndk_platform|rust).so
- Según la versión de ToT:
foo-V3-(cpp|ndk|ndk_platform|rust).so
Ten en cuenta que el compilador de AIDL no crea un módulo de versión unstable
.
o un módulo sin control de versiones
para una interfaz de AIDL estable.
A partir de Android 12, el nombre de módulo generado a partir de una
estable de AIDL siempre incluye su versión.
Nuevos métodos de metainterfaz
En Android 10, se agregan varios métodos de metainterfaz para el AIDL estable.
Consulta la versión de la interfaz del objeto remoto
Los clientes pueden consultar la versión y el hash de la interfaz a la que el objeto remoto implementa y compara los valores que se muestran con los valores de la interfaz que usa el cliente.
Ejemplo con el backend cpp
:
sp<IFoo> foo = ... // the remote object
int32_t my_ver = IFoo::VERSION;
int32_t remote_ver = foo->getInterfaceVersion();
if (remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::HASH;
std::string remote_hash = foo->getInterfaceHash();
Ejemplo con el backend ndk
(y ndk_platform
):
IFoo* foo = ... // the remote object
int32_t my_ver = IFoo::version;
int32_t remote_ver = 0;
if (foo->getInterfaceVersion(&remote_ver).isOk() && remote_ver < my_ver) {
// the remote side is using an older interface
}
std::string my_hash = IFoo::hash;
std::string remote_hash;
foo->getInterfaceHash(&remote_hash);
Ejemplo con el backend java
:
IFoo foo = ... // the remote object
int myVer = IFoo.VERSION;
int remoteVer = foo.getInterfaceVersion();
if (remoteVer < myVer) {
// the remote side is using an older interface
}
String myHash = IFoo.HASH;
String remoteHash = foo.getInterfaceHash();
Para lenguaje Java, el lado remoto DEBE implementar getInterfaceVersion()
y
getInterfaceHash()
de la siguiente manera (se usa super
en lugar de IFoo
para evitar
errores de copiar y pegar. La anotación @SuppressWarnings("static")
podría
necesaria para inhabilitar las advertencias, según la configuración de javac
):
class MyFoo extends IFoo.Stub {
@Override
public final int getInterfaceVersion() { return super.VERSION; }
@Override
public final String getInterfaceHash() { return super.HASH; }
}
Esto se debe a que las clases generadas (IFoo
, IFoo.Stub
, etc.) se comparten
entre el cliente y el servidor (por ejemplo, las clases pueden estar en el
la ruta de clase). Cuando se comparten clases, el servidor también se vincula al
a la versión más nueva de las clases, aunque se haya creado con una versión
más reciente de la interfaz. Si esta metainterfaz se implementa en el entorno
esta siempre devuelve la versión más reciente. Sin embargo, si implementas el método
como se muestra arriba, el número de versión de la interfaz está incorporado en el código del servidor.
(porque IFoo.VERSION
es un static final int
que está intercalado cuando se hace referencia a él)
y, por lo tanto, el método puede devolver la versión exacta con la que se compiló el servidor.
Cómo manejar interfaces más antiguas
Es posible que un cliente se haya actualizado con la versión más reciente de un AIDL.
pero el servidor usa la interfaz del AIDL anterior. En esos casos,
Si llamas a un método en una interfaz anterior, se muestra UNKNOWN_TRANSACTION
.
Con un AIDL estable, los clientes tienen más control. En el lado del cliente, puedes establecer una implementación predeterminada en una interfaz de AIDL. Un método en la configuración la implementación solo se invoca cuando el método no se implementa en la aplicación remota (porque se compiló con una versión anterior de la interfaz). Desde los valores predeterminados se establecen globalmente, no se deben usar de grupos diferentes.
Ejemplo en C++ en Android 13 y versiones posteriores:
class MyDefault : public IFooDefault {
Status anAddedMethod(...) {
// do something default
}
};
// once per an interface in a process
IFoo::setDefaultImpl(::android::sp<MyDefault>::make());
foo->anAddedMethod(...); // MyDefault::anAddedMethod() will be called if the
// remote side is not implementing it
Ejemplo en Java:
IFoo.Stub.setDefaultImpl(new IFoo.Default() {
@Override
public xxx anAddedMethod(...) throws RemoteException {
// do something default
}
}); // once per an interface in a process
foo.anAddedMethod(...);
No es necesario que proporciones la implementación predeterminada de todos los métodos en un AIDL.
interfaz de usuario. Métodos que se garantizan la implementación en el lado remoto
(porque sabes que el control remoto está compilado cuando los métodos estaban en la
descripción de la interfaz del AIDL) no es necesario anular en el impl
predeterminado
clase.
Convierte el AIDL existente en AIDL estructurado o estable
Si ya tienes una interfaz de AIDL y un código que la usa, usa el siguiente comando: pasos para convertir la interfaz en una interfaz de AIDL estable.
Identifica todas las dependencias de tu interfaz. Para cada paquete, la de la que depende la interfaz, determina si el paquete se define en un AIDL estable. Si sin definir, el paquete se debe convertir.
Convierte todos los objetos parcelables de tu interfaz en objetos parcelables estables (el los archivos de la interfaz en sí pueden permanecer sin cambios). Hazlo antes del y expresar su estructura directamente en archivos AIDL. Las clases de administración deben que se reescribirán para usar estos nuevos tipos. Esto puede hacerse antes de crear
aidl_interface
(abajo).Crea un paquete
aidl_interface
(como se describió más arriba) que contenga lo siguiente: de tu módulo, sus dependencias y cualquier otra información que necesites. Para que se pueda estabilizar (no solo estructurado), también se necesita un control de versiones. Para obtener más información, consulta Interfaces de control de versiones.