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 muerto ]
El proyecto freedesktop.org también desarrolló una biblioteca de software gratuita y de código abierto llamada libdbus, como implementación de referencia de la especificación. Esta biblioteca no debe confundirse con D-Bus en sí, 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 GNOME y KDE Linux ( 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 , generalmente uno . Estos servicios pueden ser utilizados por aplicaciones cliente habituales 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 se implementa internamente, pero la especificación 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 respecto al 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 otorgado 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 propiedad del 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 la existente a las aplicaciones, incluido 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 actualmente en funcionamiento, 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 autobús se identifica en el contexto de D-Bus mediante el llamado nombre de autobús . [5] El nombre de un bus consta de dos o más cadenas de letras, dígitos, guiones y guiones bajos separados por puntos. 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 ese nombre de conexión único, incluso si el mismo proceso cierra la conexión al bus y crea una nueva. 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 es propietaria del nombre del 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 pueden reutilizarse si están disponibles: un proceso puede reclamar un nombre de bus liberado— intencionalmente o no, mediante otro proceso. [5] [6]
La idea detrás de estos nombres de autobuses adicionales, comúnmente llamados nombres conocidos , es proporcionar una manera de referirse a un servicio utilizando un nombre de autobús 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 del bus org.freedesktop.timedate1 , independientemente de qué proceso sea.
Los nombres de los autobuses se pueden utilizar como una forma sencilla de implementar aplicaciones de instancia única (las segundas instancias detectan que el nombre del bus ya está en uso). [18] También se puede utilizar para rastrear el ciclo de vida de un proceso de servicio, ya que el bus envía una notificación cuando se publica un nombre de bus debido a la terminació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 D-Bus imitan los utilizados por algunos lenguajes de programación orientados a objetos . Eso no significa que D-Bus esté limitado de alguna manera 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 invocarse y señales que el objeto puede emitir. [18] Los métodos y señales se denominan colectivamente miembros del objeto. [5] Cualquier cliente conectado al bus puede interactuar con un objeto utilizando sus métodos, realizando solicitudes o ordenando al objeto que realice acciones. [18] Por ejemplo, un cliente puede consultar un objeto que representa un servicio horario 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 que tienen 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 diagonal, llamado así por su parecido 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 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 los objetos. [6] La convención de nomenclatura particular para los objetos de un servicio depende totalmente de los desarrolladores de dicho servicio, pero muchos desarrolladores optan por asignarles un espacio de nombres utilizando el nombre de dominio reservado del proyecto como prefijo (por ejemplo, /org/kde ). [18]
Cada objeto está indisolublemente 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 sin ambigüedades.
Una interfaz especifica miembros (métodos y señales) que se pueden utilizar con un objeto. [18] Es un conjunto de declaraciones de métodos (incluidos sus parámetros de paso y retorno) y señales (incluidos 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 las interfaces y los nombres de los buses no deben confundirse. Un objeto D-Bus puede implementar varias interfaces, pero al menos debe implementar una, brindando soporte para cada método y señal definido por él. La combinación de todas las interfaces implementadas por un objeto se denomina tipo de objeto . [5] [18]
Cuando se utiliza un objeto, es una buena práctica que el proceso del 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. Una señal emitida, por el contrario, 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 es opcional, la mayoría de los desarrolladores de servicios D-Bus optan por admitirlos 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 administrativas del bus (llamadas "servicios de bus") que se realizarán utilizando el objeto /org/freedesktop/DBus que reside en el nombre del bus org.freedesktop.DBus . [17] Cada bus reserva este nombre de bus especial para sí mismo y gestiona 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 gestionar 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 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 formato". [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 serialización . [5]
:1.14
El bus admite dos modos de intercambiar 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 requerida 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 interpreta el proceso receptor, por ejemplo, los argumentos de entrada o salida. Todos los datos están codificados en un formato binario bien conocido llamado formato de cable 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 serialización .
La especificación D-Bus define el protocolo de conexión : cómo construir 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 exige 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 método de transporte subyacente, pero también admite sockets TCP . [5] [18]
Las bibliotecas de comunicaciones de ambos procesos deben acordar el método de transporte seleccionado y también 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 mediante 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 del bus , la dirección mediante la cual un proceso puede establecer una conexión D-Bus con la central. proceso del bus de mensajes. [5] [18] En este escenario, el demonio del bus de mensajes selecciona la dirección del bus y el resto de los procesos deben pasar ese valor a su libdbus correspondiente o bibliotecas equivalentes. 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 normalmente se pretende utilizar D-Bus. La forma habitual es utilizar siempre 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 del bus de mensajes lo recibe en primera instancia y lo entrega al destinatario apropiado. El demonio del bus de mensajes puede verse como un concentrador o enrutador encargado de llevar cada mensaje a su destino repitiéndolo a través de la conexión D-Bus con el proceso del destinatario. [18] El proceso del destinatario está determinado por el nombre del bus de destino en el campo de encabezado del mensaje, [17] o por la información de suscripción a las señales mantenidas por el demonio del bus de mensajes en el caso de mensajes de propagación de señales. [6] El demonio del 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 funciones que ya proporciona D-Bus con funcionalidad adicional. Por ejemplo, la activación del servicio permite el inicio automático de los servicios cuando sea necesario: cuando la primera solicitud a cualquier nombre de bus de dicho servicio llega al demonio del bus de mensajes. [5] De esta manera, los procesos de servicio no necesitan iniciarse durante la inicialización del sistema o la etapa de inicialización del usuario ni necesitan consumir memoria u otros recursos cuando no se utilizan. Esta característica se implementó originalmente usando ayudantes setuid , [23] pero hoy en día también puede ser proporcionada por el marco de activación de servicios de systemd . [ cita necesaria ] La activación del servicio es una característica importante que facilita la gestión del ciclo de vida del proceso de los servicios (por ejemplo, cuando un componente de escritorio debe iniciarse o detenerse). [18]
D-Bus fue fundada 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 utilizado 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 es compatible con la mayoría de los sistemas operativos POSIX y existe un puerto para Windows . Es utilizado por Qt 4 y posteriores por GNOME . En GNOME ha reemplazado gradualmente la mayoría de las partes del anterior mecanismo Bonobo . También es utilizado por Xfce .
Uno de los primeros en adoptarlo fue la capa de abstracción de hardware (hoy en desuso) . HAL usó D-Bus para exportar información sobre el hardware que se agregó o eliminó de la computadora. [8]
El uso de D-Bus se está expandiendo constantemente 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 Bluetooth BlueZ y el servidor de sonido PulseAudio utilizan D-Bus para proporcionar parte o la totalidad de sus servicios. systemd utiliza el protocolo de cable D-Bus para la comunicación entre systemctl y systemd, y también está promoviendo demonios de sistemas tradicionales para 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 estuvo destinada a ser utilizada directamente por los desarrolladores de aplicaciones, sino como guía de referencia para otras reimplementaciones de D-Bus (como las incluidas en bibliotecas estándar de entornos de escritorio o en enlaces de lenguajes de programación ). ). El propio proyecto freedesktop.org recomienda a los autores de aplicaciones "utilizar 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 usaran a menudo indistintamente, lo que generó confusión. [ cita necesaria ]
GDBus [9] es una implementación de D-Bus basada en flujos GIO incluidos en GLib , cuyo objetivo es ser utilizado 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 están basados en GTK+ 3, también usan GDBus. [ cita necesaria ]
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 pruebas comparativas preliminares, BMW descubrió que la biblioteca D-Bus del sistema aumentó el rendimiento en un 360%. [33] En la versión 221 de systemd , la API sd-bus se declaró estable. [34]
/dev/kdbus
(cf. devfs ).kdbus era 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 kernel . Además de las mejoras de rendimiento, kdbus tendría ventajas derivadas de otras características del kernel de Linux , como espacios de nombres y auditoría, [33] [37] seguridad mediada por el kernel, cierre de condiciones de carrera y permitir que D-Bus se utilice durante el arranque y el apagado (como necesario por systemd). [38] La inclusión de kdbus en el kernel de Linux resultó controvertida, [39] y se abandonó en favor de BUS1, como una comunicación entre procesos más genérica . [40]
Se han desarrollado varios enlaces de lenguajes de programación para D-Bus, [41] como los de Java , C# , Ruby , Rust y Perl . [ cita necesaria ]
Uno de los desarrollos más importantes surgidos del escritorio Linux es el Desktop Bus (D-Bus), un sistema de paso de mensajes. D-Bus es importante porque sirve como 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 de middleware unificada debajo de los principales entornos de escritorio gratuitos.
Para el caso de uso dentro de la sesión del escritorio, los escritorios GNOME y KDE tienen una experiencia previa significativa con diferentes soluciones IPC como CORBA y DCOP. D-Bus se basa en esa experiencia y se adapta cuidadosamente para satisfacer las necesidades de estos proyectos de escritorio en particular.
D-Bus se creó por primera vez para reemplazar el modelo de componentes tipo CORBA subyacente al entorno de escritorio GNOME. Al igual que DCOP (que utiliza KDE), D-Bus está destinado a convertirse en un componente estándar de los principales entornos de escritorio gratuitos 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 hay algunas reimplementaciones del protocolo D-Bus para lenguajes como C#, Java y Ruby. Estos no utilizan la implementación de referencia 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. Más bien, 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 usa la implementación de referencia 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.