D-Bus

Esse é o 21º artigo da série Comunicação entre processos. Nesse artigo será apresentado o IPC Dbus.

Introdução

O D-Bus foi criado em 2002 e faz parte do projeto freedesktop.org, é mantido pela RedHat e pela comunidade. D-Bus é um IPC projetado com o objetivo de servir como camada intermediária(middleware) para ambientes desktop. Um projeto conhecido como GNOME faz uso desse mecanismo. D-Bus diferente de outros mecanismos como shared memory, queues e sockets carece de recursos, o que o torna rápido e simples. D-Bus não é um substituto para os outros IPC, cada IPC tem um propósito.

D-Bus

O conceito principal no D-Bus é o barramento. Através do canal é possível chamadas de métodos, enviar sinais e escutar sinais. Existe dois tipos de barramento: o barramento de sessão e o barramento de sistema.

  • Session Bus – é usado para a comunicação de aplicações que são conectadas em uma mesma sessão desktop.
  • System Bus – é usado quando aplicações rodando em sessões separadas que precisam se comunicar entre si.

Um barramento D-Bus no sistema está na forma de bus daemon, que é um processo especializado em repassar as mensagens de um processo para o outro.

O D-Bus trabalha com diversos elementos sendo: Serviços, Objetos, Interfaces e Clientes, a seguir é apresentado as definições de cada elemento:

  • Serviços – Um serviço é uma coleção de Objetos que fornece algum recurso, sendo apresentado no formato well-know name que facilita a leitura
  • Objetos – Objetos são parte de um serviço, podem ser criados e removidos dinamicamente. Para acessar um objeto é usado o formato object path que é idêntico ao caminho de diretorio /org/servico/alguma_coisa. Objetos podem implementar uma ou mais interfaces.
  • Interfaces – São as implementações, os métodos, sinais e propriedades

Para demonstrar o relacionamento entre esse elementos segue uma imagem:

d-bus

Permissões

Para poder ter acesso ao barramento é necessário registrar e conceder permissão para quem vai utilizar os serviços. Esses arquivos são representados no formato XML e ficam nos diretórios /etc/dbus-1/system.d e /etc/dbus-1/session.d


Para exemplificar a implementação desses arquivos é apresentado o arquivo de configuração utilizado para o processo de botão

Nesse arquivo os usuários root e pi recebem a permissão de utilização desse serviço. Permite envio de dados para a interface org.pi.led_process que que tem como destino o serviço org.pi.led_process.

Ferramentas

Para auxiliar o desenvolvimento usando o D-Bus existem algumas ferramentas que permite enviar dados para o barramento e monitorá-lo, sendo elas dbus-send e dbus-monitor.

API

A API referente ao dbus é extensa segue link para consulta das funções utilizadas no exemplo

Implementação

Para demonstrar o uso desse IPC, iremos utilizar o modelo Produtor/Consumidor, onde o processo Produtor(button_process) vai escrever seu estado no barramento, e o Consumidor(led_process) vai ler o estado do barramento e aplicar o estado para si. Aplicação é composta por três executáveis sendo eles:

  • launch_processes – é responsável por lançar os processos button_process e led_process através da combinação fork e exec
  • button_interface – é responsável por ler o GPIO em modo de leitura da Raspberry Pi e escrever o estado no barramento
  • led_interface – é responsável por ler do barramento o estado do botão e aplicar em um GPIO configurado como saída

O diagrama para a aplicação de LED fica da seguinte forma:

d-bus

launch_processes.c

No main criamos duas variáveis para armazenar o PID do button_process e do led_process, e mais duas variáveis para armazenar o resultado caso o exec venha a falhar.

Em seguida criamos um processo clone, se processo clone for igual a 0, criamos um array de strings com o nome do programa que será usado pelo exec, em caso o exec retorne, o estado do retorno é capturado e será impresso no stdout e aborta a aplicação. Se o exec for executado com sucesso o programa button_process será carregado.

O mesmo procedimento é repetido novamente, porém com a intenção de carregar o led_process.

dbus_endpoint.h

Aqui é definido os nomes dos componentes

button_interface.h

Para usar a interface do botão precisa implementar essas duas callbacks para permitir o seu uso.

A assinatura do uso da interface corresponde ao contexto do botão, que depende do modo selecionado e a interface do botão devidamente preenchida.

button_interface.c

Aqui é criado algumas variáveis, conn que representa o contexto no qual irá conter as informações sobre a conexão com o barramento, dbus_error que irá apresentar os resultados de algumas funções para poder ser apresentada, state que é o estado interno do botão e uma lista de comando que representa a mensagem a ser enviada. Logo em seguida é feita a inicialização do botão e do D-Bus, após a inicialização fica em um loop aguardando o pressionamento do botão para alterar o estado interno, requisita o barramento, requisita o serviço no qual quer enviar a mensagem, realiza o envio e libera os recursos, retornando ao início dessa forma aguardando um novo pressionamento.

Apresenta qual o erro que ocorreu.

Inicia o D-Bus em modo bus system.

Requisita o serviço no qual quer se comunicar.

Requisita o método no qual quer enviar a mensagem para um determinado objeto referente ao serviço.

Concatena a mensagem e envia para o serviço.

led_interface.h

Para realizar o uso da interface de LED é necessário preencher os callbacks que serão utilizados pela implementação da interface, sendo a inicialização e a função que altera o estado do LED.

A assinatura do uso da interface corresponde ao contexto do LED, que depende do modo selecionado e a interface do LED devidamente preenchida.

led_interface.c

Aqui é criado algumas variáveis, conn que representa o contexto no qual irá conter as informações sobre a conexão com o barramento, dbus_error que irá apresentar os resultados de algumas funções para poder ser apresentada. Logo em seguida é feita a inicialização do LED e do D-Bus, após a inicialização requisita qual o serviço que vai se comunicar. No loop fica aguardando alguma mensagem chegar, caso sim verifica se é referente a interface e o método, recupera a mensagem aplica caso for reconhecida pela aplicação e libera os recursos.

Apresenta qual o erro que ocorreu.

Inicializa o D-Bus requisitando o modo bus system

Requisita o serviço no qual quer se comunicar

Compilando, Executando e Matando os processos

Para compilar e testar o projeto é necessário instalar a biblioteca de hardware necessária para resolver as dependências de configuração de GPIO da Raspberry Pi.

Compilando

Para facilitar a execução do exemplo, o exemplo proposto foi criado baseado em uma interface, onde é possível selecionar se usará o hardware da Raspberry Pi 3, ou se a interação com o exemplo vai ser através de input feito por FIFO e o output visualizado através de LOG.

Clonando o projeto

Pra obter uma cópia do projeto execute os comandos a seguir:

Selecionando o modo

Para selecionar o modo devemos passar para o cmake uma variável de ambiente chamada de ARCH, e pode-se passar os seguintes valores, PC ou RASPBERRY, para o caso de PC o exemplo terá sua interface preenchida com os sources presentes na pasta src/platform/pc, que permite a interação com o exemplo através de FIFO e LOG, caso seja RASPBERRY usará os GPIO’s descritos no artigo.

Modo PC

Modo RASPBERRY

Instalando os arquivos de configurações do D-Bus

Após a compilação do projeto para que os arquivos sejam instalados no diretório pertinente as permissões de uso do D-Bus basta executar:

Após a instalação é importante verificar se os arquivos de fato constam no diretório

Output

Executando

Para executar a aplicação execute o processo launch_processes para lançar os processos button_process e led_process que foram determinados de acordo com o modo selecionado.

Uma vez executado podemos verificar se os processos estão rodando através do comando:

O output

Interagindo com o exemplo

Dependendo do modo de compilação selecionado a interação com o exemplo acontece de forma diferente

MODO PC

Para o modo PC, precisamos abrir um terminal e monitorar os LOG’s

Dessa forma o terminal irá apresentar somente os LOG’s referente ao exemplo.

Para simular o botão, o processo em modo PC cria uma FIFO para permitir enviar comandos para a aplicação, dessa forma todas às vezes que for enviado o número 0 irá logar no terminal onde foi configurado para o monitoramento, segue o exemplo

Output do LOG quando enviado o comando algumas vezez

MODO RASPBERRY

Para o modo RASPBERRY a cada vez que o botão for pressionado irá alternar o estado do LED.

Monitorando

Para monitorar a interface que foi implementada é usada a ferramenta dbus-monitor. Com essa ferramente é possível ver os dados que trafegam nesse barramento. Para monitorar uma interface específica é possível filtrar passando o argumento interface com a interface desejada. No exemplo fica assim:

Para saber mais sobre a ferramenta use o man pages

Enviando comandos usando o dbus-send

Para poder enviar dados para o barramento é possível fazer uso da ferramenta dbus-send

Para enviar comandos para o barramento é necessário ter a permissão de acesso,para este exemplo será usado o usuário root

Então o comando fica da seguinte forma

Nesse ponto vai gerar um erro devido a aplicação não responder. Com o monitoramento ligado é possível ver a seguinte saída:

Output

Existe uma ferramenta gráfica conhecida como d-feet verifique as referências para saber mais.

Para saber mais sobre a ferramenta use o man pages

Matando os processos

Para matar os processos criados execute o script kill_process.sh

Conclusão

D-Bus é uma forma de comunicação entre processos muito versátil, pois garante a implementação de forma desacoplada entre os processos. Projetos como KDE, Gnome, Systemd, Bluez, Network-manager fazem uso desse IPC. Garante segurança no uso desses serviços através de permissões, ou seja, não basta somente saber da existência serviço, mas também deve-se ter a permissão de poder usá-lo. A desvantagem que dbus possui é não poder realizar comunicação entre nodes, dessa forma caracteriza que cada forma de IPC possui sua área de atuação.

Agradecimentos

Bom chegamos ao fim de uma série tão extensa e cheia de conteúdo e exemplos práticos. Espero que tenham gostado e quero deixar os meus agradecimentos pelo apoio e feedback recebido durante essa jornada.
Gostaria de agradecer ao Embarcados por permitir nós conceder essa gama de experiência compartilhada pelos nossos colegas. Gostaria de agradecer ao Fábio Souza pelo primeiro contato quando ainda estava receoso sobre como meus artigos seriam recepcionados. Obrigado Fábio pela força. Ao Thiago Lima pela forma que apresentou e recomendou meus artigos, meu muito obrigado. Ao Augusto que meu ajudou testando todos os exemplos e atuando como revisor final. E em especial a comunidade de receber os meus estudos de forma tão positiva, isso só me incentiva a continuar escrevendo. Obrigado a todos.

Referência

Outros artigos da série

<< POSIX Shared Memory

Engenheiro Elétrico de Formação mas é Engenheiro de Software de profissão, Pós Graduado em Sistemas Embarcados. Apaixonado por Idiomas, mas o idioma que mais lhe fascina é a Linguagem C.
Jogador de CTF, mas prefire Battlefield 1, exige menos da capacidade cognitiva :P. Atualmente atua como desenvolvedor de sistemas distribuídos no ramo aeronáutico. Quando está de bobeira fica desenhando personagens de Anime, criando conteúdo para o canal[Solidcris - Zerando Games] ou pedalando pela cidade de São Paulo.

Notificações
Notificar
guest
1 Comentário
recentes
antigos mais votados
Inline Feedbacks
View all comments
Matheus Souza
Matheus
30/08/2021 22:09

Muito bom!
Obrigado.

WEBINAR

Imagens de Ultrassom: Princípios e Aplicações

DATA: 26/10 ÀS 19:30 H