D-Bus (abreviatura de " Desktop Bus " [4] ) es un mecanismo de middleware orientado a mensajes que permite la comunicación entre múltiples procesos que se ejecutan simultáneamente en la misma máquina. [5] [6] D-Bus fue desarrollado como parte del proyecto freedesktop.org , iniciado por el desarrollador de GNOME Havoc Pennington para estandarizar los servicios proporcionados por los entornos de escritorio Linux como GNOME y KDE . [7] [8] [ enlace roto ]
El proyecto freedesktop.org también desarrolló una biblioteca de software libre y de código abierto llamada libdbus, como implementación de referencia de la especificación. Esta biblioteca no debe confundirse con D-Bus, ya que también existen otras implementaciones de la especificación D-Bus, como GDBus (GNOME), [9] QtDBus ( Qt /KDE), [10] dbus-java [11] y sd-bus (parte de systemd ). [12]
D-Bus es un mecanismo de comunicación entre procesos (IPC) diseñado inicialmente para reemplazar los sistemas de comunicación de componentes de software utilizados por los entornos de escritorio Linux GNOME y KDE ( CORBA y DCOP respectivamente). [13] [14] Los componentes de estos entornos de escritorio normalmente se distribuyen en muchos procesos, cada uno de los cuales proporciona solo unos pocos servicios (normalmente uno) . Estos servicios pueden ser utilizados por aplicaciones cliente normales o por otros componentes del entorno de escritorio para realizar sus tareas. [15]
D-Bus proporciona una abstracción de bus de software que reúne todas las comunicaciones entre un grupo de procesos a través de un único canal virtual compartido. [6] Los procesos conectados a un bus no saben cómo está implementado internamente, pero la especificación de D-Bus garantiza que todos los procesos conectados al bus puedan comunicarse entre sí a través de él. D-Bus incurre en una pérdida de rendimiento de al menos 2,5 veces en comparación con el IPC uno a uno. [16]
Los entornos de escritorio Linux aprovechan las funciones de D-Bus al crear instancias de múltiples buses, en particular: [17] [6] [18]
Un proceso puede conectarse a cualquier número de buses, siempre que se le haya concedido acceso a ellos. En la práctica, esto significa que cualquier proceso de usuario puede conectarse al bus del sistema y a su bus de sesión actual, pero no a los buses de sesión de otro usuario, o incluso a un bus de sesión diferente que pertenezca al mismo usuario. Esta última restricción puede cambiar en el futuro si todas las sesiones de usuario se combinan en un único bus de usuario. [19]
D-Bus proporciona funcionalidad adicional o simplifica las existentes a las aplicaciones, incluyendo el intercambio de información, la modularidad y la separación de privilegios . Por ejemplo, la información sobre una llamada de voz entrante recibida a través de Bluetooth o Skype puede ser propagada e interpretada por cualquier reproductor de música que se esté ejecutando en ese momento, que puede reaccionar silenciando el volumen o pausando la reproducción hasta que finalice la llamada. [20]
D-Bus también se puede utilizar como marco para integrar diferentes componentes de una aplicación de usuario. Por ejemplo, una suite ofimática puede comunicarse a través del bus de sesión para compartir datos entre un procesador de textos y una hoja de cálculo .
Cada conexión a un bus se identifica en el contexto de D-Bus mediante lo que se denomina un nombre de bus . [5] Un nombre de bus consta de dos o más cadenas de letras, dígitos, guiones y guiones bajos separados por puntos: un nombre de dominio inverso . Un ejemplo de un nombre de bus válido es org.freedesktop.NetworkManager
. [6]
Cuando un proceso establece una conexión a un bus, el bus asigna a la conexión un nombre de bus especial llamado nombre de conexión único . [18] [6] Los nombres de bus de este tipo son inmutables (se garantiza que no cambiarán mientras exista la conexión) y, lo que es más importante, no se pueden reutilizar durante la vida útil del bus. [5] [18] [6] Esto significa que ninguna otra conexión a ese bus tendrá asignado nunca un nombre de conexión único, incluso si el mismo proceso cierra la conexión al bus y crea uno nuevo. Los nombres de conexión únicos son fácilmente reconocibles porque comienzan con el carácter de dos puntos, que de otro modo estaría prohibido. [18] [6] Un ejemplo de un nombre de conexión único es :1.1553
(los caracteres después de los dos puntos no tienen un significado particular [18] ).
Un proceso puede solicitar nombres de bus adicionales para su conexión, [18] siempre que el nombre solicitado no esté siendo utilizado por otra conexión al bus. En el lenguaje de D-Bus, cuando se asigna un nombre de bus a una conexión, se dice que la conexión posee el nombre de bus. [5] [18] En ese sentido, un nombre de bus no puede ser propiedad de dos conexiones al mismo tiempo, pero, a diferencia de los nombres de conexión únicos, estos nombres se pueden reutilizar si están disponibles: un proceso puede reclamar un nombre de bus liberado, intencionalmente o no, por otro proceso. [5] [6]
La idea detrás de estos nombres de bus adicionales, comúnmente llamados nombres conocidos , es proporcionar una forma de referirse a un servicio utilizando un nombre de bus preestablecido. [18] [6] Por ejemplo, el servicio que informa la hora y fecha actuales en el bus del sistema se encuentra en el proceso cuya conexión posee el nombre de bus org.freedesktop.timedate1 , independientemente de qué proceso sea.
Los nombres de bus se pueden utilizar como una forma sencilla de implementar aplicaciones de instancia única (las segundas instancias detectan que el nombre de bus ya está tomado). [18] También se pueden utilizar para rastrear el ciclo de vida de un proceso de servicio, ya que el bus envía una notificación cuando se libera un nombre de bus debido a la finalización de un proceso. [18]
Debido a su concepción original como reemplazo de varios sistemas de comunicaciones orientados a componentes, D-Bus comparte con sus predecesores un modelo de objetos en el que expresar la semántica de las comunicaciones entre clientes y servicios. Los términos utilizados en el modelo de objetos de D-Bus imitan los utilizados por algunos lenguajes de programación orientados a objetos . Eso no significa que D-Bus esté de alguna manera limitado a los lenguajes OOP; de hecho, la implementación más utilizada ( libdbus ) está escrita en C , un lenguaje de programación procedimental .
En D-Bus, un proceso ofrece sus servicios exponiendo objetos . Estos objetos tienen métodos que pueden ser invocados y señales que el objeto puede emitir. [18] Los métodos y las señales se denominan colectivamente miembros del objeto. [5] Cualquier cliente conectado al bus puede interactuar con un objeto utilizando sus métodos, haciendo solicitudes u ordenando al objeto que realice acciones. [18] Por ejemplo, un cliente puede consultar un objeto que representa un servicio de tiempo utilizando un método que devuelve la fecha y hora actuales. Un cliente también puede escuchar las señales que emite un objeto cuando su estado cambia debido a ciertos eventos, generalmente relacionados con el servicio subyacente. Un ejemplo sería cuando un servicio que administra dispositivos de hardware, como controladores USB o de red, señala un evento de "nuevo dispositivo de hardware agregado". Los clientes deben indicarle al bus que están interesados en recibir ciertas señales de un objeto en particular, ya que un bus D-Bus solo pasa señales a aquellos procesos con un interés registrado en ellas. [6]
Un proceso conectado a un bus D-Bus puede solicitarle que exporte tantos objetos D-Bus como desee. Cada objeto se identifica mediante una ruta de objeto , una cadena de números, letras y guiones bajos separados y precedidos por el carácter de barra, llamada así por su semejanza con las rutas del sistema de archivos Unix . [5] [18] La ruta del objeto la selecciona el proceso solicitante y debe ser única en el contexto de esa conexión de bus. Un ejemplo de una ruta de objeto válida es /org/kde/kspread/sheets/3/cells/4/5
. [18] Sin embargo, no se exige (pero tampoco se desaconseja) formar jerarquías dentro de las rutas de objetos. [6] La convención de nombres particular para los objetos de un servicio depende completamente de los desarrolladores de dicho servicio, pero muchos desarrolladores eligen asignarles un espacio de nombres utilizando el nombre de dominio reservado del proyecto como prefijo (por ejemplo, /org/kde ). [18]
Cada objeto está inextricablemente asociado a la conexión de bus particular donde fue exportado y, desde el punto de vista de D-Bus, sólo vive en el contexto de dicha conexión. Por lo tanto, para poder utilizar un determinado servicio, un cliente debe indicar no sólo la ruta del objeto que proporciona el servicio deseado, sino también el nombre del bus bajo el cual el proceso de servicio está conectado al bus. [5] Esto a su vez permite que varios procesos conectados al bus puedan exportar diferentes objetos con rutas de objeto idénticas de forma inequívoca.
Una interfaz especifica miembros (métodos y señales) que se pueden usar con un objeto. [18] Es un conjunto de declaraciones de métodos (incluyendo sus parámetros de paso y retorno) y señales (incluyendo sus parámetros) identificados por un nombre separado por puntos que se asemeja a la notación de interfaces del lenguaje Java . [18] [6] Un ejemplo de un nombre de interfaz válido es org.freedesktop.Introspectable
. [6] A pesar de su similitud, los nombres de interfaz y los nombres de bus no deben confundirse. Un objeto D-Bus puede implementar varias interfaces, pero al menos debe implementar una, proporcionando soporte para cada método y señal definidos por él. La combinación de todas las interfaces implementadas por un objeto se denomina tipo de objeto . [5] [18]
Al utilizar un objeto, es una buena práctica que el proceso cliente proporcione el nombre de la interfaz del miembro además del nombre del miembro, pero solo es obligatorio cuando existe una ambigüedad causada por nombres de miembros duplicados disponibles en diferentes interfaces implementadas por el objeto [5] [18] ; de lo contrario, el miembro seleccionado no está definido o es erróneo. Por otro lado, una señal emitida siempre debe indicar a qué interfaz pertenece.
La especificación D-Bus también define varias interfaces estándar que los objetos pueden querer implementar además de sus propias interfaces. [17] Aunque técnicamente son opcionales, la mayoría de los desarrolladores de servicios D-Bus eligen admitirlas en sus objetos exportados, ya que ofrecen características adicionales importantes a los clientes D-Bus, como la introspección . [6] Estas interfaces estándar son: [17] [6]
La especificación D-Bus define una serie de operaciones de bus administrativas (denominadas "servicios de bus") que se deben realizar utilizando el objeto /org/freedesktop/DBus que reside en el nombre de bus org.freedesktop.DBus . [17] Cada bus reserva este nombre de bus especial para sí mismo y administra cualquier solicitud realizada específicamente a esta combinación de nombre de bus y ruta de objeto. Las operaciones administrativas proporcionadas por el bus son las definidas por la interfaz del objeto org.freedesktop.DBus . Estas operaciones se utilizan, por ejemplo, para proporcionar información sobre el estado del bus, [5] o para administrar la solicitud y liberación de nombres de bus conocidos adicionales . [17] [6]
D-Bus fue concebido como un sistema de comunicación entre procesos genérico y de alto nivel. Para lograr tales objetivos, las comunicaciones D-Bus se basan en el intercambio de mensajes entre procesos en lugar de "bytes sin procesar". [5] [18] Los mensajes D-Bus son elementos discretos de alto nivel que un proceso puede enviar a través del bus a otro proceso conectado. Los mensajes tienen una estructura bien definida (incluso los tipos de datos transportados en su carga útil están definidos), lo que permite al bus validarlos y rechazar cualquier mensaje mal formado. En este sentido, D-Bus se acerca más a un mecanismo RPC que a un mecanismo IPC clásico, con su propio sistema de definición de tipos y su propio marshaling . [5]
El bus admite dos modos de intercambio de mensajes entre un cliente y un proceso de servicio [5] :
Cada mensaje D-Bus consta de un encabezado y un cuerpo. [18] El encabezado está formado por varios campos que identifican el tipo de mensaje, el remitente, así como la información necesaria para entregar el mensaje a su destinatario (nombre del bus de destino, ruta del objeto, nombre del método o señal, nombre de la interfaz, etc.). [18] [17] El cuerpo contiene la carga útil de datos que el proceso receptor interpreta, por ejemplo, los argumentos de entrada o salida. Todos los datos están codificados en un formato binario bien conocido llamado formato wire que admite la serialización de varios tipos, como números enteros y de punto flotante, cadenas, tipos compuestos, etc., [17] también conocido como marshaling .
La especificación D-Bus define el protocolo de comunicación por cable : cómo crear los mensajes D-Bus que se intercambiarán entre procesos dentro de una conexión D-Bus. Sin embargo, no define el método de transporte subyacente para entregar estos mensajes.
La mayoría de las implementaciones de D-Bus existentes siguen la arquitectura de la implementación de referencia. Esta arquitectura consta de dos componentes principales: [5]
La biblioteca libdbus (o su equivalente) utiliza internamente un mecanismo IPC nativo de nivel inferior para transportar los mensajes D-Bus requeridos entre los dos procesos en ambos extremos de la conexión D-Bus. La especificación D-Bus no establece qué mecanismos de transporte IPC en particular deberían estar disponibles para su uso, ya que es la biblioteca de comunicaciones la que decide qué métodos de transporte admite. Por ejemplo, en sistemas operativos tipo Unix como Linux, libdbus normalmente utiliza sockets de dominio Unix como el método de transporte subyacente, pero también admite sockets TCP . [5] [18]
Las bibliotecas de comunicaciones de ambos procesos deben estar de acuerdo en el método de transporte seleccionado y también en el canal particular utilizado para su comunicación. Esta información está definida por lo que D-Bus llama una dirección . [6] [18] Los sockets de dominio Unix son objetos del sistema de archivos , y por lo tanto pueden identificarse por un nombre de archivo, por lo que una dirección válida sería unix:path=/tmp/.hiddensocket
. [5] [17] Ambos procesos deben pasar la misma dirección a sus respectivas bibliotecas de comunicaciones para establecer la conexión D-Bus entre ellos. Una dirección también puede proporcionar datos adicionales a la biblioteca de comunicaciones en forma de key=value
pares separados por comas. [6] [17] De esta manera, por ejemplo, puede proporcionar información de autenticación a un tipo específico de conexión que la admita.
Cuando se utiliza un demonio de bus de mensajes como dbus-daemon para implementar un bus D-Bus, todos los procesos que quieran conectarse al bus deben conocer la dirección de bus , la dirección mediante la cual un proceso puede establecer una conexión D-Bus con el proceso de bus de mensajes central. [5] [18] En este escenario, el demonio de bus de mensajes selecciona la dirección de bus y los procesos restantes deben pasar ese valor a sus bibliotecas libdbus o equivalentes correspondientes. dbus-daemon define una dirección de bus diferente para cada instancia de bus que proporciona. Estas direcciones se definen en los archivos de configuración del demonio.
Dos procesos pueden utilizar una conexión D-Bus para intercambiar mensajes directamente entre ellos, [22] pero esta no es la forma en la que D-Bus está normalmente pensado para ser utilizado. La forma habitual es siempre utilizar un demonio de bus de mensajes (es decir, dbus-daemon ) como punto central de comunicaciones con el que cada proceso debe establecer su conexión D-Bus punto a punto. Cuando un proceso (cliente o servicio) envía un mensaje D-Bus, el proceso de bus de mensajes lo recibe en primera instancia y lo entrega al destinatario apropiado. El demonio de bus de mensajes puede verse como un concentrador o enrutador encargado de hacer llegar cada mensaje a su destino repitiéndolo a través de la conexión D-Bus al proceso destinatario. [18] El proceso destinatario se determina por el nombre del bus de destino en el campo de encabezado del mensaje, [17] o por la información de suscripción a señales mantenida por el demonio de bus de mensajes en el caso de mensajes de propagación de señales. [6] El demonio de bus de mensajes también puede producir sus propios mensajes como respuesta a ciertas condiciones, como un mensaje de error a un proceso que envió un mensaje a un nombre de bus inexistente. [18]
dbus-daemon mejora el conjunto de características que ya proporciona D-Bus con funcionalidad adicional. Por ejemplo, la activación de servicios permite el inicio automático de servicios cuando es necesario, cuando la primera solicitud a cualquier nombre de bus de dicho servicio llega al demonio de bus de mensajes. [5] De esta manera, los procesos de servicio no necesitan iniciarse durante la etapa de inicialización del sistema o inicialización del usuario ni necesitan consumir memoria u otros recursos cuando no se utilizan. Esta característica se implementó originalmente utilizando ayudantes setuid , [23] pero hoy en día también puede proporcionarse mediante el marco de activación de servicios de systemd . [ cita requerida ] La activación de servicios es una característica importante que facilita la gestión del ciclo de vida del proceso de los servicios (por ejemplo, cuándo debe iniciarse o detenerse un componente de escritorio). [18]
D-Bus fue iniciado en 2002 por Havoc Pennington, Alex Larsson ( Red Hat ) y Anders Carlsson. [8] La versión 1.0, considerada API estable, fue lanzada en noviembre de 2006. [24] [25]
Fuertemente influenciado por el sistema DCOP usado por las versiones 2 y 3 de KDE , D-Bus ha reemplazado a DCOP en la versión KDE 4. [25] [26] Una implementación de D-Bus soporta la mayoría de los sistemas operativos POSIX , y existe un puerto para Windows . Es usado por Qt 4 y posteriormente por GNOME . En GNOME ha reemplazado gradualmente la mayoría de las partes del mecanismo Bonobo anterior . También es usado por Xfce .
Uno de los primeros en adoptar esta tecnología fue la capa de abstracción de hardware (hoy en día obsoleta) . HAL utilizaba D-Bus para exportar información sobre el hardware que se había añadido o eliminado de la computadora. [8]
El uso de D-Bus se está expandiendo de manera constante más allá del alcance inicial de los entornos de escritorio para cubrir una cantidad cada vez mayor de servicios del sistema. Por ejemplo, el demonio de red NetworkManager , la pila de bluetooth BlueZ y el servidor de sonido PulseAudio usan D-Bus para proporcionar parte o la totalidad de sus servicios. systemd usa el protocolo de cable D-Bus para la comunicación entre systemctl y systemd, y también está promoviendo los daemons de sistema tradicionales para los servicios D-Bus, como logind . [27] Otro gran usuario de D-Bus es Polkit , cuyo demonio de autoridad de políticas se implementa como un servicio conectado al bus del sistema. [28]
Aunque existen varias implementaciones de D-Bus, la más utilizada es la implementación de referencia libdbus , desarrollada por el mismo proyecto freedesktop.org que diseñó la especificación. Sin embargo, libdbus es una implementación de bajo nivel que nunca fue pensada para ser utilizada directamente por los desarrolladores de aplicaciones, sino como una guía de referencia para otras reimplementaciones de D-Bus (como las incluidas en las bibliotecas estándar de los entornos de escritorio o en los enlaces de lenguajes de programación ). El propio proyecto freedesktop.org recomienda a los autores de aplicaciones que "utilicen uno de los enlaces o implementaciones de nivel superior" en su lugar. [29] El predominio de libdbus como la implementación de D-Bus más utilizada provocó que los términos "D-Bus" y "libdbus" se utilizaran a menudo indistintamente, lo que generaba confusión. [ cita requerida ]
GDBus [9] es una implementación de D-Bus basada en flujos GIO incluidos en GLib , que pretende ser utilizada por GTK+ y GNOME . GDBus no es un contenedor de libdbus, sino una reimplementación completa e independiente de la especificación y el protocolo D-Bus. [30] MATE Desktop [31] y Xfce (versión 4.14), que también se basan en GTK+ 3, también utilizan GDBus. [ cita requerida ]
En 2013, el proyecto systemd reescribió libdbus en un esfuerzo por simplificar el código, [32] pero también resultó en un aumento significativo del rendimiento general de D-Bus. En las pruebas de referencia preliminares, BMW descubrió que la biblioteca D-Bus de systemd aumentó el rendimiento en un 360%. [33] En la versión 221 de systemd , lanzada en 2015, la API sd-bus se declaró estable. [34]
kdbus fue un proyecto que tenía como objetivo reimplementar D-Bus como un mecanismo de comunicación entre procesos de igual a igual mediado por el núcleo . Además de las mejoras de rendimiento, kdbus tendría ventajas que surgen de otras características del núcleo Linux , como espacios de nombres y auditoría, [33] [37] seguridad a partir de la mediación del núcleo, cierre de condiciones de carrera y permitir que D-Bus se use durante el arranque y apagado (según lo necesite systemd). [38] La inclusión de kdbus en el núcleo Linux resultó controvertida, [39] y se abandonó a favor de BUS1, como una comunicación entre procesos más genérica . [40]
Se han desarrollado varios enlaces de lenguaje de programación para D-Bus, [41] como los de Java , C# , Ruby , Rust y Perl . [ cita requerida ]
Uno de los desarrollos más importantes que surgieron del escritorio Linux es el Bus de escritorio (D-Bus), un sistema de paso de mensajes. D-Bus es importante porque sirve como un mecanismo de comunicación entre procesos que permite que las aplicaciones de escritorio se comuniquen entre sí [...].
D-Bus [...] está diseñado para usarse como una capa intermedia unificada debajo de los principales entornos de escritorio gratuitos.
Para el caso de uso dentro de la sesión de escritorio, los escritorios GNOME y KDE tienen una experiencia previa significativa con diferentes soluciones de IPC como CORBA y DCOP. D-Bus se basa en esa experiencia y está cuidadosamente diseñado para satisfacer las necesidades de estos proyectos de escritorio en particular.
D-Bus se creó inicialmente para reemplazar el modelo de componentes similar a CORBA que subyace al entorno de escritorio GNOME. De manera similar a DCOP (que utiliza KDE), D-Bus está destinado a convertirse en un componente estándar de los principales entornos de escritorio libres para GNU/Linux y otras plataformas.
Estamos trabajando para trasladar las cosas a un bus de usuario real, del cual solo hay uno por usuario en un sistema, independientemente de cuántas veces ese usuario inicie sesión.
También existen algunas reimplementaciones del protocolo D-Bus para lenguajes como C#, Java y Ruby. Estas no utilizan la implementación de referencia de libdbus.
Está construido sobre un marco general de paso de mensajes uno a uno, que puede ser utilizado por dos aplicaciones cualesquiera para comunicarse directamente (sin pasar por el demonio del bus de mensajes).
Desde el inicio de systemd, ha sido el sistema IPC en el que expone sus interfaces.
La implementación de bajo nivel no está diseñada principalmente para que la utilicen los autores de aplicaciones. En cambio, es una base para vincular a los autores y una referencia para las reimplementaciones. Si puede hacerlo, se recomienda que utilice uno de los enlaces o implementaciones de nivel superior.
dbus-glib utiliza la implementación de referencia de libdbus, GDBus no. En cambio, se basa en flujos GIO como capa de transporte y tiene su propia implementación para la configuración y autenticación de la conexión D-Bus.