Esta página describe los cambios en el controlador de binder en Android 8, proporciona detalles sobre el uso de Binder IPC y enumera la política de SELinux requerida.
Cambios en el controlador de la carpeta
A partir de Android 8, el marco de Android y las HAL ahora se comunican entre sí mediante binder. Dado que esta comunicación aumenta drásticamente el tráfico de Binder, Android 8 incluye varias mejoras diseñadas para mantener la velocidad de Binder IPC. Los proveedores de SoC y los OEM deben fusionarse directamente desde las ramas relevantes de android-4.4, android-4.9 y versiones posteriores del kernel / common project.
Varios dominios de enlace (contextos)
Common-4.4 y superior, incluido upstreamPara dividir limpiamente el tráfico de binder entre el código del marco (independiente del dispositivo) y el del proveedor (específico del dispositivo), Android 8 introdujo el concepto de un contexto de binder . Cada contexto de enlace tiene su propio nodo de dispositivo y su propio administrador de contexto (servicio). Puede acceder al administrador de contexto solo a través del nodo de dispositivo al que pertenece y, al pasar un nodo de enlace a través de un contexto determinado, es accesible desde ese mismo contexto solo por otro proceso, aislando así completamente los dominios entre sí. Para obtener detalles sobre el uso, consulte vndbinder y vndservicemanager .
Dispersar-reunir
Common-4.4 y superior, incluido upstreamEn versiones anteriores de Android, todos los datos de una llamada de carpeta se copiaban tres veces:
- Una vez para serializarlo en un
Parcel
en el proceso de llamada - Una vez en el controlador del kernel para copiar el
Parcel
al proceso de destino - Una vez para anular la serialización del
Parcel
en el proceso de destino
Android 8 utiliza la optimización de dispersión y recopilación para reducir la cantidad de copias de 3 a 1. En lugar de serializar los datos en un Parcel
primero, los datos permanecen en su estructura original y diseño de memoria y el controlador los copia inmediatamente en el proceso de destino. Una vez que los datos están en el proceso de destino, la estructura y el diseño de la memoria son los mismos y los datos se pueden leer sin requerir otra copia.
Bloqueo de grano fino
Common-4.4 y superior, incluido upstreamEn versiones anteriores de Android, el controlador Binder usaba un bloqueo global para proteger contra el acceso concurrente a estructuras de datos críticas. Si bien hubo una contención mínima por el bloqueo, el problema principal era que si un subproceso de baja prioridad obtenía el bloqueo y luego se adelantaba, podría retrasar seriamente los subprocesos de mayor prioridad que necesitaban obtener el mismo bloqueo. Esto provocó un tirón en la plataforma.
Los intentos iniciales de resolver este problema implicaron deshabilitar la preferencia mientras se mantenía el bloqueo global. Sin embargo, esto fue más un truco que una verdadera solución, y finalmente fue rechazado por upstream y descartado. Los intentos posteriores se centraron en hacer que el bloqueo sea más detallado, una versión del cual se ha estado ejecutando en dispositivos Pixel desde enero de 2017. Si bien la mayoría de esos cambios se hicieron públicos, se realizaron mejoras sustanciales en las versiones posteriores.
Después de identificar pequeños problemas en la implementación de bloqueo de grano fino, ideamos una solución mejorada con una arquitectura de bloqueo diferente y enviamos los cambios en todas las ramas comunes del kernel. Seguimos probando esta implementación en una gran cantidad de dispositivos diferentes; Como no tenemos conocimiento de ningún problema pendiente, esta es la implementación recomendada para los dispositivos que se envían con Android 8.
Herencia de prioridad en tiempo real
Common-4.4 y common-4.9 (upstream próximamente)El controlador Binder siempre ha sido compatible con la herencia de prioridad agradable. Como un número cada vez mayor de procesos en Android se ejecutan con prioridad en tiempo real, en algunos casos ahora tiene sentido que si un subproceso en tiempo real realiza una llamada de enlace, el subproceso en el proceso que maneja esa llamada también se ejecute con prioridad en tiempo real. . Para admitir estos casos de uso, Android 8 ahora implementa la herencia de prioridad en tiempo real en el controlador de binder.
Además de la herencia de prioridad a nivel de transacción, la herencia de prioridad de nodo permite que un nodo (objeto de servicio de enlace) especifique una prioridad mínima en la que se deben ejecutar las llamadas a este nodo. Las versiones anteriores de Android ya admitían la herencia de prioridad de nodo con buenos valores, pero Android 8 agrega soporte para la herencia de nodos de políticas de programación en tiempo real.
Cambios en el espacio de usuario
Android 8 incluye todos los cambios en el espacio de usuario necesarios para trabajar con el controlador Binder actual en el kernel común con una excepción: la implementación original para deshabilitar la herencia de prioridad en tiempo real para /dev/binder
usaba un ioctl . El desarrollo posterior cambió el control de la herencia de prioridad a un método más detallado que es por modo de enlace (y no por contexto). Por lo tanto, ioctl no está en la rama común de Android y, en cambio, se envía en nuestros núcleos comunes .
El efecto de este cambio es que la herencia de prioridad en tiempo real está deshabilitada de forma predeterminada para cada nodo. El equipo de rendimiento de Android ha descubierto que es beneficioso habilitar la herencia de prioridades en tiempo real para todos los nodos del dominio hwbinder
. Para lograr el mismo efecto, seleccione este cambio en el espacio de usuario.
SHA para kernels comunes
Para obtener los cambios necesarios en el controlador de carpeta, sincronice con el SHA apropiado:
- Común-3.18
cc8b90c121de ANDROID: binder: no verifique los permisos prio en la restauración. - Común-4.4
76b376eac7a2 ANDROID: binder: no verifique los permisos de prio en la restauración. - Común-4.9
ecd972d4f9b5 ANDROID: binder: no verifique los permisos de prio en la restauración.
Utilizando Binder IPC
Históricamente, los procesos de los proveedores han utilizado la comunicación entre procesos binder (IPC) para comunicarse. En Android 8, el nodo de dispositivo /dev/binder
vuelve exclusivo de los procesos del marco, lo que significa que los procesos del proveedor ya no tienen acceso a él. Los procesos del proveedor pueden acceder a /dev/hwbinder
, pero deben convertir sus interfaces AIDL para usar HIDL. Para los proveedores que desean continuar usando interfaces AIDL entre procesos de proveedores, Android admite Binder IPC como se describe a continuación.
vndbinder
Android 8 admite un nuevo dominio de /dev/vndbinder
para que lo utilicen los servicios de proveedores, al que se accede mediante /dev/vndbinder
lugar de /dev/binder
. Con la adición de /dev/vndbinder
, Android ahora tiene los siguientes tres dominios IPC:
Dominio de IPC | Descripción |
---|---|
/dev/binder | IPC entre procesos de framework / app con interfaces AIDL |
/dev/hwbinder | IPC entre procesos de marco / proveedor con interfaces HIDL IPC entre procesos de proveedores con interfaces HIDL |
/dev/vndbinder | IPC entre proveedores / procesos de proveedores con interfaces AIDL |
Para que aparezca /dev/vndbinder
, asegúrese de que el elemento de configuración del kernel CONFIG_ANDROID_BINDER_DEVICES
esté configurado en "binder,hwbinder,vndbinder"
(este es el valor predeterminado en los árboles comunes del kernel de Android).
Normalmente, los procesos de los proveedores no abren el controlador del binder directamente, sino que se vinculan con la biblioteca del espacio de usuario libbinder
, que abre el controlador del binder. Al agregar un método para ::android::ProcessState()
selecciona el controlador de carpeta para libbinder
. Los procesos del proveedor deben llamar a este método antes de llamar a ProcessState,
IPCThreadState
o antes de realizar cualquier llamada de IPCThreadState
en general. Para usar, coloque la siguiente llamada después del main()
de un proceso de proveedor (cliente y servidor):
ProcessState::initWithDriver("/dev/vndbinder");
vndservicemanager
Anteriormente, los servicios de enlace se registraban con servicemanager
, donde otros procesos podían recuperarlos. En Android 8, servicemanager
ahora es utilizado exclusivamente por procesos de aplicaciones y marcos, y los procesos de proveedores ya no pueden acceder a él.
Sin embargo, los servicios de proveedores ahora pueden usar vndservicemanager
, una nueva instancia de servicemanager
que usa /dev/vndbinder
lugar de /dev/binder
y que se /dev/vndbinder
partir de las mismas fuentes que el framework servicemanager
. Los procesos del proveedor no necesitan realizar cambios para hablar con vndservicemanager
; cuando un proceso de proveedor abre / dev/vndbinder
, las búsquedas de servicios van automáticamente a vndservicemanager
.
El binario vndservicemanager
se incluye en los vndservicemanager
MAKE predeterminados del dispositivo de Android.
Política de SELinux
Los procesos de proveedores que desean utilizar la funcionalidad de enlace para comunicarse entre sí necesitan lo siguiente:
- Acceso a
/dev/vndbinder
. - Binder
{transfer, call}
conecta avndservicemanager
. -
binder_call(A, B)
para cualquier dominio de proveedor A que desee llamar al dominio de proveedor B a través de la interfaz de enlace de proveedor. - Permiso para
{add, find}
servicios envndservicemanager
.
Para cumplir con los requisitos 1 y 2, use la macro vndbinder_use()
:
vndbinder_use(some_vendor_process_domain);
Para cumplir con el requisito 3, binder_call(A, B)
para los procesos del proveedor A y B que necesitan hablar sobre binder pueden permanecer en su lugar y no es necesario cambiar el nombre.
Para cumplir con el requisito 4, debe realizar cambios en la forma en que se manejan los nombres de los servicios, las etiquetas de los servicios y las reglas.
Para obtener detalles sobre SELinux, consulte Linux con seguridad mejorada en Android . Para obtener detalles sobre SELinux en Android 8.0, consulte SELinux para Android 8.0 .
Nombres de servicios
Anteriormente, el proveedor procesaba los nombres de servicios registrados en un archivo service_contexts
y agregaba las reglas correspondientes para acceder a ese archivo. Ejemplo de archivo service_contexts
de device/google/marlin/sepolicy
:
AtCmdFwd u:object_r:atfwd_service:s0 cneservice u:object_r:cne_service:s0 qti.ims.connectionmanagerservice u:object_r:imscm_service:s0 rcs u:object_r:radio_service:s0 uce u:object_r:uce_service:s0 vendor.qcom.PeripheralManager u:object_r:per_mgr_service:s0
En Android 8, vndservicemanager
carga el archivo vndservice_contexts
lugar. Los servicios de proveedores que migran a vndservicemanager
(y que ya están en el archivo service_contexts
antiguo) deben agregarse al archivo nuevo vndservice_contexts
.
Etiquetas de servicio
Anteriormente, las etiquetas de servicio como u:object_r:atfwd_service:s0
se definían en un archivo service.te
. Ejemplo:
type atfwd_service, service_manager_type;
En Android 8, debe cambiar el tipo a vndservice_manager_type
y mover la regla al archivo vndservice.te
. Ejemplo:
type atfwd_service, vndservice_manager_type;
Reglas del administrador de servicios
Anteriormente, las reglas otorgaban acceso a los dominios para agregar o buscar servicios de servicemanager
. Ejemplo:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;
En Android 8, estas reglas pueden permanecer en su lugar y usar la misma clase. Ejemplo:
allow atfwd atfwd_service:service_manager find; allow some_vendor_app atfwd_service:service_manager add;