Usa IPC de Binder

En esta página, se describen los cambios en el controlador de Binder de Android 8. Se proporcionan detalles sobre el uso de IPC de Binder y enumera la política de SELinux requerida.

Cambios en el controlador de Binder

A partir de Android 8, el framework y las HAL de Android se comunican con entre sí mediante Binder. Como esta comunicación aumenta drásticamente, de tráfico, Android 8 incluye varias mejoras diseñadas para mantener IPC de Binder rápido. Los proveedores de SoC y los OEMs deben combinarse directamente de las ramas relevantes de android-4.4, android-4.9 y versiones posteriores de la kernel/common.

Varios dominios de Binder (contextos)

Common 4.4 y versiones posteriores, incluido el upstream

Para dividir de forma clara el tráfico de Binder entre el framework (independiente del dispositivo) y (específico del dispositivo), Android 8 introdujo el concepto de un vinculador. contextual. Cada contexto de Binder tiene su propio nodo de dispositivo y su propio contexto (de servicio). Puedes acceder a Context Manager solo desde el dispositivo al que pertenece y, cuando se pasa un nodo Binder a través de un determinado se puede acceder desde ese mismo contexto solo por otro proceso, por lo tanto, y aislar por completo los dominios entre sí. Para obtener detalles sobre el uso, consulta vndbinder y vndservicemanager.

Dispersión

Common 4.4 y versiones posteriores, incluido el upstream

En las versiones anteriores de Android, se copiaban todos los datos de una llamada a Binder. tres veces:

  • Una vez para serializarlos Parcel en el proceso de llamada
  • Una vez en el controlador de kernel para copiar Parcel en el destino proceso
  • Una vez para anular la serialización de Parcel en el proceso de destino

Android 8 usa dispersión-recopilación para reducir la cantidad de copias de 3 a 1. En lugar de serializar datos en un Parcel primero, los datos permanecen en su original el diseño de memoria y la estructura, y el controlador lo copia de inmediato en el destino el proceso de administración de recursos. Una vez que los datos están en el proceso objetivo, la estructura y la memoria el diseño es el mismo y los datos se pueden leer sin requerir otra copia.

Bloqueo detallado

Common 4.4 y versiones posteriores, incluido el upstream

En versiones anteriores de Android, el controlador de Binder usaba un bloqueo global para proteger contra el acceso simultáneo a estructuras de datos críticas. Si bien había mínimo para el bloqueo, el problema principal era que si un subproceso de baja prioridad obtuvo el candado y se adelantó, esto podría retrasar subprocesos con mayor prioridad necesarios para obtener el mismo bloqueo. Esto provocó bloqueos en la plataforma.

Los intentos iniciales de resolver este problema incluyeron deshabilitar la interrupción mientras manteniendo el candado global. Sin embargo, se trataba más de un truco que de una verdadera solución. y, finalmente, fue rechazada por el upstream y se descartó. Intentos posteriores se enfoca en hacer que el bloqueo sea más detallado, una versión de la cual se ha en dispositivos Pixel desde enero de 2017. Si bien la mayoría de esos cambios fueron se hicieron públicas, se hicieron mejoras sustanciales en versiones posteriores.

Después de identificar problemas pequeños en la implementación de bloqueo detallada, ideó una solución mejorada con una arquitectura de bloqueo diferente y envió los cambios en todas las ramas comunes de kernel. Seguimos probando esto en una gran cantidad de dispositivos diferentes; ya que no conocemos problemas pendientes, esta es la implementación recomendada para el envío de dispositivos con Android 8.

Herencia de prioridad en tiempo real

Common-4.4 y common-4.9 (ascendente próximamente)

El controlador de Binder siempre admitió una herencia de prioridad agradable. Como cada vez más procesos en Android que se ejecutan con prioridad en tiempo real, en algunos casos, ahora tiene sentido que, si un subproceso en tiempo real realiza una llamada a Binder, el en el proceso que controla esa llamada también se ejecuta con prioridad en tiempo real. Para para 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 prioridad de nodos herencia permite que un nodo (objeto de servicio de Binder) especifique un la prioridad con la que se deben ejecutar las llamadas a este nodo. Versiones anteriores de Android ya admitía la herencia de prioridad de nodo con valores agradables, pero En Android 8, se agrega compatibilidad con la herencia de nodos de políticas de programación en tiempo real.

Cambios en el espacio del usuario

Android 8 incluye todos los cambios de espacio del usuario necesarios para trabajar con la versión controlador de Binder en el kernel común con una excepción: el controlador original para inhabilitar la herencia de prioridad en tiempo real /dev/binder usó un ioctl El desarrollo posterior cambió el control de prioridad. la herencia a un método más detallado que sea por modo de Binder (y no por contexto). Por lo tanto, ioctl no está en la rama común de Android y es en nuestros kernels comunes.

El efecto de este cambio es que la herencia de prioridad en tiempo real se inhabilita predeterminado para todos los nodos. El equipo de rendimiento de Android descubrió beneficioso para habilitar la herencia de prioridad en tiempo real para todos los nodos de la hwbinder. Para lograr el mismo efecto, este cambio en el espacio de usuario.

SHAs para kernels comunes

Para obtener los cambios necesarios en el controlador de Binder, sincronízalo con el SHA correspondiente:

  • Común-3.18
    cc8b90c121de ANDROID: binder: no verificas los permisos prioritarios durante el restablecimiento.
  • Común-4.4
    76b376eac7a2 ANDROID: binder: no verifica los permisos prioritarios durante el restablecimiento.
  • Común-4.9
    ecd972d4f9b5 ANDROID: binder: no verificas los permisos prioritarios durante el restablecimiento.

Trabaja con IPC de Binder

Históricamente, los procesos de los proveedores han utilizado comunicación entre procesos de Binder (IPC) para comunicarse. En Android 8, el nodo del dispositivo /dev/binder se vuelve exclusivo de los procesos del framework, lo que significa que los procesos de los proveedores ya no tengan acceso a ellos. Los procesos del proveedor pueden acceder a /dev/hwbinder, pero deben convertir sus interfaces de AIDL para usar HIDL. Para los proveedores que desean continuar usando interfaces de AIDL entre procesos del proveedor, Android admite Binder IPC como que se describe a continuación. En Android 10, el AIDL estable permite procesos para usar /dev/binder y, al mismo tiempo, resolver los problemas de estabilidad garantiza que se resuelvan HIDL y /dev/hwbinder. Cómo usar el canal estable AIDL, consulta AIDL para HAL:

vndbinder

Android 8 admite un nuevo dominio de Binder para servicios de proveedores, a los que se accede con /dev/vndbinder en lugar de /dev/binder. Con la además de /dev/vndbinder, Android ahora tiene los siguientes tres Dominios de IPC:

Dominio de IPC Descripción
/dev/binder IPC entre procesos de framework o apps con interfaces AIDL
/dev/hwbinder IPC entre los procesos del framework y del proveedor con interfaces HIDL
IPC entre procesos de proveedores con interfaces HIDL
/dev/vndbinder La IPC entre los procesos del proveedor con interfaces AIDL

Para que aparezca /dev/vndbinder, asegúrate de que la configuración del kernel Se estableció el elemento CONFIG_ANDROID_BINDER_DEVICES como "binder,hwbinder,vndbinder" (esta es la configuración predeterminada en árboles de kernel común).

Por lo general, los procesos de los proveedores no abren el controlador de Binder directamente, sino con la biblioteca de espacio de usuario libbinder, que abre la controlador de Binder. Agregando un método para ::android::ProcessState() selecciona el controlador de Binder para libbinder. Los procesos de los proveedores deben Llama a este método antes de llamar a ProcessState,. IPCThreadState o antes de realizar llamadas a Binder en general Para usa, realiza la siguiente llamada después de la main() de un proceso de proveedor (cliente y servidor):

ProcessState::initWithDriver("/dev/vndbinder");

vndservicemanager

Anteriormente, los servicios de Binder se registraban con servicemanager. y otros procesos las podrían recuperar. En Android 8, Ahora el framework y la app usan servicemanager exclusivamente procesos y los procesos de los proveedores ya no pueden acceder a ella.

Sin embargo, los servicios de proveedores ahora pueden usar vndservicemanager, un nuevo instancia de servicemanager que usa /dev/vndbinder en lugar de /dev/binder y que se compila a partir de las mismas fuentes que framework servicemanager. Los procesos de los proveedores no necesitan hacer cambios para comunicarse con vndservicemanager; cuando se abre el proceso de un proveedor /dev/vndbinder, las búsquedas de servicios se envían automáticamente a vndservicemanager.

El objeto binario vndservicemanager se incluye en la configuración predeterminada de Android. archivos makefile del dispositivo.

Política de SELinux

Los procesos de proveedores que desean usar la funcionalidad de Binder para comunicarse entre sí necesitan lo siguiente:

  1. Acceso a /dev/vndbinder.
  2. Engancha a Binder {transfer, call} de Binder vndservicemanager
  3. binder_call(A, B) para cualquier dominio A de proveedor que desee llamar en el dominio B del proveedor a través de la interfaz de Binder del proveedor.
  4. Permiso para {add, find} servicios en vndservicemanager

Para cumplir con los requisitos 1 y 2, usa vndbinder_use(). macro:

vndbinder_use(some_vendor_process_domain);

Para cumplir con el requisito 3, se debe usar la binder_call(A, B) del proveedor los procesos A y B que necesitan comunicarse por Binder pueden permanecer en su lugar y no se deben cambiarse de nombre.

Para cumplir con el requisito 4, debes hacer cambios en la forma en que las etiquetas de servicio y las reglas.

Para conocer detalles sobre SELinux, consulta Seguridad mejorada Linux en Android Para obtener detalles sobre SELinux en Android 8.0, consulta SELinux para Android 8.0

Nombres de servicios

Anteriormente, el proveedor procesaba nombres de servicios registrados en un service_contexts y se agregaron las reglas correspondientes para acceder ese archivo. Archivo service_contexts de ejemplo 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 vndservice_contexts archivo en su lugar. Los servicios de proveedores que migran a vndservicemanager (y que ya están en el service_contexts) al nuevo archivo Archivo vndservice_contexts.

Etiquetas de servicio

Anteriormente, las etiquetas de servicio, como u:object_r:atfwd_service:s0 se definieron en un archivo service.te. Ejemplo:

type atfwd_service,      service_manager_type;

En Android 8, debes cambiar el tipo a vndservice_manager_type y mueve la regla al archivo vndservice.te. Ejemplo:

type atfwd_service,      vndservice_manager_type;

reglas de servicemanager

Anteriormente, las reglas concedían acceso a 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, esas 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;