Mais trabalho com Python e DBus no Maemo…

Depois de ter resolvido a bronca no desktop, que usa python-dbus 0.80 (o mais novo), foi a vez de testar dentro do maemo, que usa python-dbus 0.70. E como eu já esperava, funcionou parcialmente, apesar de examinando o código do binding do dbus aparentemente estar tudo certo.

No estado atual, as funções da biblioteca funcionam perfeitamente, exceto quando um objeto dbus.SystemBus é criado (exceto quando o argumento private é verdadeiro). Isso já era mais ou menos previsto uma vez que no 0.80, os objetos Bus herdam indiretamente de Connection, enquanto que no 0.70 são instâncias separadas (Connection é um atributo de Bus). Tentamos subir a versão no maemo mas pelo dbus ser uma versão mais antiga (0.61 ao invés de pelo menos 0.93) não foi possível.

Dessa forma, resolvemos lançar o binding (ainda essa semana) no estado atual, mantendo um aviso para não criar os objetos de forma que a biblioteca fique prejudicada…

Conexões compartilhadas do DBus e Python

Enquanto fazia um binding para Python (Usando PyGTK) de uma das bibliotecas usadas no N800, tudo corria bem até que me deparei com um problema ao usar funções que por “debaixo dos panos” usavam DBus. A função chamada registrava internamente um callback da própria biblioteca para um sinal DBus que, mesmo sem erro no momento do registro, não chamava o callback quando era lançado.

Alguns dos vários testes:

  • Usando bus.add_signal_receiver() o sinal era capturado no Python mas o callback ainda assim não era chamado.
  • Deixando de lado PyGTK e fazendo o binding “na mão” também dava o mesmo erro
  • Embutindo python numa aplicação C e apenas chamando as funções de registro funcionava. Nesse caso o MainLoop estava em C.
  • Embutindo python numa aplicação C e declarando e executando o MainLoop em Python funcionava (A inicialização do DBus ainda estava em C).

Nesse último teste e com a ajuda de um email de um dos desenvolvedores do dbus-python, descobri que o problema era justamente a conexão DBus não estar sendo “acoplada” ao MainLoop do programa.

Toda vez que alguém chama dbus_bus_get (em C…), é retornada uma conexão compartilhada, própria da aplicação (incluindo a biblioteca que estava escrevendo os bindings) e mantida “viva” pela libdbus (C). Para poder capturar os sinais, é necessário que essa conexão fosse configurada para o MainLoop atual, usando dbus_connection_setup_with_g_main.

O “problema” era que os bindings Python do DBus não usam essa conexão compartilhada e sim uma conexão privada, própria do binding. Ao configurar com o MainLoop em Python usando import glib ou DBusGMainLoop(set_as_default=True), a conexão privada era a configurada e não a conexão compartilhada, usada pela biblioteca. Para resolver, bastou usar dbus_connection_setup_with_g_main no código de inicialização e tudo acabou funcionando.

PS: Esse rolo todo me custou quase 2 semanas…

PS2: Funcionou no desktop, falta testar no dispositivo, que usa versões mais antigas do DBus…