入り口に戻る

原文はこちら

原文は CC-BY-SA-4.0 で公開されており、本サイトのこのページも同じ。

D-Bus 入門

D-Bus の主要概念をアプリケーション開発者の視点から紹介する。

目次

概要

D-Bus は、フリー且つオープン・ソースのプロセス間通信機構(inter-process communication (IPC) mechanism)であり、freedesktop.org プロジェクトの一部である。D-Bus は様々な領域のアプリケーションで利用されており、Desktop Notifications(デスクトップ通知)や、media player control(TotemやVLCなどのメディア・プレイヤーを制御するアプリケーション)、XDG portals (XDG デスクトップ・ポータル)を始めとした freedesktop.org 標準アプリケーションの多くも土台部分に D-Bus を用いて構築されている。

「IPC」という用語は、あるプロセスから別のプロセスへ情報を移す方法を述べる時に使用されるものである。IPC には、データ交換、メソッド呼び出し、イベントの待ち受けなどがある。

デスクトップにおける IPC の使用例としては、次のようなものが挙げられる。即ち、スクリプティング(ありふれた環境でユーザがスクリプトを実行して、様々なアプリケーション(実行中のもの)とやり取りしたり、それらを操作したりすることを可能にすること)、中央集権型サービスへのアクセスの提供、共同作業を行うアプリケーションの複数のインスタンスの間における調整などであり、多岐に渡る。

D-Bus の使用例としては、freedesktop.org の Desktop Notifications Specification (デスクトップ通知仕様)がある。アプリケーションは自身の通知を中央サーバ(例えば Plasma)へ送信する。それを受けた中央サーバは、通知を表示し、「通知の表示が閉じられた」あるいは「動作(action)が呼び出された」といったイベントを送り返す。

IPC の別の使用例を挙げると、同時に1つしか稼働しないアプリケーションへの対応がある。そうしたアプリケーションは、起動するとまず同一アプリケーションの他の実行中インスタンスが存在するかどうかを調べる。そして実行中インスタンスが存在した場合、新たに起動した方のアプリケーションは、IPC を通して実行中インスタンスへメッセージを送信し、自身の存在を伝え、終了する。

D-Busは言語やツールキットに依存しない。そのためアプリケーションやサービスは、D-Bus によって、それらの開発者が誰であるかにかかわらず互いにやり取りできるようになる。Qt には、D-Bus とやり取りするためのクラスとツールの一式が備わっている。本文書から始まる一連のチュートリアルでは、D-Bus の上層部分の概念(訳註:要確認:high-level concepts)と、Qt 及び KDE における同概念の実装とを説明する。

バス(Bus)

D-Bus は、複数のメッセージ・バスをアプリケーションに提供するものである。アプリケーションはこのメッセージ・バスを使用して互いに通信することができる。1つ1つのバスは自分用の接続機構を持っており、これによって異なる種類のメッセージを分離することが可能になる。あるバスで送信されるメッセージには別のバスからはアクセスできないけれども、同一のバスに接続しているアプリケーションは皆、互いに通信することができる。任意のバスに対して、任意の時に、複数のアプリケーションを接続することができる。また、1つのアプリケーションは同時に複数のバスに接続することもできる。これによって、異なるバスに異なるセキュリティ・ポリシーを適用することが可能となり、また、グローバルなメッセージとローカルのメッセージの両方を効率的に共有できるようにもなる。

D-Bus には既定のバスが2種類あり、この2つで D-Bus の典型的な使用方法の大半に対応することができる。

1つはシステム・バスである。これは、ハードウェア管理などのシステム単位の大域的なサービス(system-global services)のために使用される。システム・バスは、ユーザ間で共有され、通常は厳格なセキュリティ・ポリシーを持つ。

もう1つはセッションバスである。各デスクトップ・セッションは(例えばログインしているユーザのそれぞれは)、システム・バスに加えてセッション・バスをも使用する。このバスは、デスクトップ・アプリケーションが最も頻繁に使用するバスである。

これらに加えて、アプリケーションは、必要に応じて自分のバスを任意の数だけ作成することができる。

メッセージ

メッセージは、バスにおける通信の基本単位となる。TCP/IP を用いて転送される情報がパケットを使ってやり取りされるのと同様に、バスを通る情報は全て「メッセージ」の形式でやり取りされる。しかしながら、ネットワーク・パケットとは異なり、D-BUS メッセージの1つ1つには送受信されるデータの一式全体が含まれることが保証されている。メッセージには、送るデータに加えて、送信者が誰なのか及び届け先となる受信者が誰なのかも記録されている。これによって適切な配送が可能になる。

メッセージには、メソッドの呼び出し、シグナルの発出、メソッドの戻り値がある。また、メッセージにはエラー情報を入れることもできる。

名前空間とアドレス

同一バス上には複数のアプリケーションが存在可能であり、且つ1つのアプリケーションは複数のオブジェクト(メッセージは「オブジェクト」に対して送信することができる)を提供することができるので、任意のバス上の任意のオブジェクトのアドレス(番地)を効率的かつ明確に指定する手段が必要である。これは、任意の住居やオフィスを住所によって一意に指定するのと同じような手法による。「インタフェイス」「サービス」「オブジェクト名」という3つの情報要素が存在し、これらを組み合わせることで、あるバスにおける任意のオブジェクトの被りのないアドレス(unique address)を作り出す。

インタフェイス

1つのインタフェイスは、バス上に公開されている(be advertised)呼び出し可能なメソッド群とシグナル群の組1つから成る。インタフェイスは、メッセージをやり取りするアプリケーションの間の「契約」(contract)を提供する。この契約によって、インタフェイスの名前、引数(もしあれば)、戻り値(もしあれば)が定義される。これらのメソッドは、インタフェイスを公開しているアプリケーションのメソッドや API とは一対一に対応していなくても良い(但し、大抵は一対一に対応している)。これによって、複数のアプリケーションが、その内部の実装にかかわらず、同様のインタフェイスあるいは同一のインタフェイスを提供することが可能となる。と同時に、インタフェイスを利用するアプリケーションは、インタフェイスを公開しているアプリケーションの内部の設計を気にすることなく、それらのインタフェイスを使用することができるようになる。

インタフェイスは、XML を使用して記述することができるようになっている。これは、ドキュメントの作成とコードの再利用を目的としている。ユーザとプログラマは XML で書かれたインタフェイスの定義を参照できるし、開発者は XML から自動生成されたクラスを利用することができる。これによって、D-Bus の利用が簡単になり、D-Bus の利用によるエラーも発生し難くなっている(例えば、コンパイル時にメッセージの構文をコンパイラで検査することができる。) 。

サービス

サービスは、バスに対するアプリケーションの接続を表す。

ここでいうサービスとは、D-Bus 仕様の用語で「バス名」(Bus names)として知られているもののことである。「バス名」という用語は、少し紛らわしい。その字面にも関わらず、バス名とは、バス上の接続!の名前であり、バスの名前ではない。そこで、Qt の文書における呼び方に倣って、ここではサービスという用語を用いることにする。

サービス(バス名)は、「逆ドメイン名」(reverse domain name)形式を用いて被りのないように保たれる。この方法は、名前空間を用いて複数の要素を管理する必要がある他の多くのシステムで見られるものと同じである。KDE プロジェクトのアプリケーションが提供するサービスでは、大抵、そのサービス名の頭に org.kde という接頭辞が付いている。例えば、セッション・バスにおいて org.kde.screensaver というサービスが公開されていることに気づくであろう。

サービス名には、組織のドメイン名やアプリケーション(のドメイン名)を用いるものとする。例えば、ドメインが awesomeapps.org であり、アプリケーションの名前が wickedwidget である場合、バス上にあるサービスの名前として org.awesomeapps.wickedwidget を使用することになるであろう。

1つのアプリケーションが1つのバスに対して複数の接続を持っている場合、あるいは同一のアプリケーションの複数のインスタンスが同時に稼働する可能性がある場合、接続ごとに一意のサービス名を割り当てる必要がある。これは多くの場合、サービス名にプロセス ID をくっつけることによって行われる。

オブジェクト

(訳註:1つのサービスの中に複数のオブジェクトがあり、1つのオブジェクトには複数のインタフェイスがある。)

アプリケーションは、バス上で複数のオブジェクトへのアクセスを提供する(advertise)ことがある。オブジェクトとサービスの間のこの多対一の関係は、パス(path:経路)という要素をアドレスに追加することで解決する。1つのサービスに結び付けられている(複数の)パスの1つ1つは、他とは異なる唯一無二のオブジェクトを指す。パスは、/MainInterface/Documents/Doc1 のような形を取ることができる。けれども、実際のパスの(表記の)構造は完全に任意であり、パス(の表記)をどのようなものにするかは、サービスを提供するアプリケーションに委ねられている。こうしたパスは、サービスを提供するアプリケーションに対してメッセージを送信するアプリケーションに、オブジェクトを識別したりオブジェクトを論理的に分類したりする手段を提供するだけである。

ライブラリの中には、自身のオブジェクトを名前空間の中に適切に位置付けるために、オブジェクト・パス(object path)の頭に自身の「逆ドメイン」を付加してから同パスを公開(export)するものが存在する。この手法は次のようなライブラリやプラグインでよく採用されている手法である。即ち、任意のサービスに参加し、それゆえにアプリケーションと他のコンポーネント(機能部品)とが公開しているオブジェクトと名前が衝突しないようにしなければならないライブラリやプラグインである。しかしながら、このやり方は KDE のアプリケーションとライブラリでは採用されていない。

オブジェクトは、インタフェイスへのアクセスを提供する。もう一歩踏み込んで言うと、1つのオブジェクトは同時に複数のインタフェイスへのアクセスを提供することができる。

全てを纏めると…

D-Bus メッセージには、上記の要素全てを組み合わせて作ったアドレスが入っている。これによって、D-Bus メッセージを正しいアプリケーション、正しいオブジェクト、正しいメソッド呼び出しへと導くことが可能になる。そうしたアドレスの見た目は次のようなものになる。

org.kde.krunner /App org.kde.krunner.App.display

この例では、org.kde.krunner はサービスであり、/App はオブジェクトへのパス(経路)であり、org.kde.krunner.App は同オブジェクトが公開しているインタフェイスであり、display は同インタフェイスにあるメソッドである。オブジェクト /App の提供するインタフェイスが org.kde.krunner.App のみである場合(あるいは実装されているサービス群の間で display という名前のメソッドがただ1つしか存在しない場合)、次のアドレスは上記のアドレスと同じように機能する。

org.kde.krunner /App display

このようにして、存在し得る宛先の1つ1つを一意に、且つ確実にアドレス指定することができる。

手続き呼び出しの送信と受信

ここまでの説明でバス上の任意の端点(end point)のアドレスを指定する方法がわかったので、実際にメッセージを送信したり受信したりする場合にどのようなことが可能なのかを見てみよう。

メソッド

メソッドとは、アプリケーションへ送信されるメッセージである。このメッセージは、受信したアプリケーションの中でコードの実行を引き起こす。アドレスが間違っている、あるいは宛先となったアプリケーションが実行中でないといった理由により、メソッドが使用不能であった場合、メソッドを呼び出したアプリケーションへエラーが返る。メソッドの呼び出しが成功した場合、同メソッドを呼び出したアプリケーションへ戻り値が返ることがある。たとえ戻り値が存在しない場合であっても、成功を知らせるメッセージが返る。このメッセージの往復には当然オーバーヘッド(負荷)が存在するため、実行効率が大切なコードの場合、この点に留意しておくことが重要である。

このようなメソッド呼び出しは必ず呼び出し側アプリケーションによって開始され、結果として生ずるメッセージはきっかり1つの送信元アドレスと同じくきっかり1つの宛先アドレスを持つ。

シグナル

シグナルはメソッド呼び出しに似ている。けれども、発生の方向が逆である点、及び単一の宛先に結び付けられていない点が異なっている。シグナルは、インタフェイスを公開しているアプリケーションによって発行されるものであり、同一バス上の任意のアプリケーションが取得できるものである。これによって、アプリケーションは意識せずに状態変更やそれ以外のイベントを広報することができるようになり、また、この広報は状態変更等を追跡することに関心を持っている可能性があるアプリケーションのいづれにも届くようになる。

これが Qt のシグナルとスロットの仕組みによく似ているように見えるとすれば、それはまさにその通りだからである。あらゆる意図、あらゆる目的において、これは同じ機能の非ローカル版なのである。

便利なツール

D-Bus のバスを探査したり、D-Bus を利用するアプリケーションの開発をしたりするための便利なツールが存在する。ここではエンド・ユーザ(end user)用のツールについて手短に説明する。この後の記事(訳註:「D-Bus 入門」の後の記事)では、開発用のツールについてより詳しく、使用場面に即した形で説明を行う。

qdbus

qdbus はコマンド・ライン・ツールである。qdbus を使用することで、指定したバスに存在するサービス、オブジェクト及びインタフェイスの一覧を表示したり、バス上の指定したアドレスへメッセージを送信したりすることができる。qdbus では、システム・バスとデフォルトのセッション・バスの両方を探索することができる。--system という引数(スイッチ)が指定された場合、qdbus はシステム・バスに接続する。同引数が指定されなかった場合、qdbus はセッション・バスを使用する。

qdbus は、命令文の中の他の引数をアドレス、及び指定されたオブジェクトへ渡す引数(もし引数があれば)として使用する。完全なアドレスが指定されなかった場合、qdbus は、バス上の(不完全なアドレスによって)指定された点から利用できるオブジェクト全てを表示する。たとえば、アドレスが全く指定されなかった場合、利用可能なサービスの一覧が表示される。サービス名(1つ)だけが指定された場合、オブジェクト・パスの群が表示される。パス(1つ)も指定されていた場合、全てのインタフェイスにある全てのメソッドが表示される。このようにして、とても簡単にバス上のオブジェクトを探知したり同オブジェクトとやり取りしたりすることができる。そのため、qdbus はプログラムの試験、スクリプト開発(IPC関連)に大いに役立つものであり、遊びの探索にも使えてしまう。

qdbusviewer

qdbusviewer は、Qt アプリケーションの1つである。qdbusviewer は、qdbus がコマンド・ライン上で提供する機能群と本質的に同一の機能群に、グラフィカル・インタフェイスを与えたものである。そのため、バスとやり取りする仕組みとして、ユーザがより親しみやすいものになっている。qdbusviewer は、Qt 自体に同梱されており、D-Bus の基本的な概念(オブジェクトのアドレス等)に通じている人であれば誰でも簡単に使用することができる。

入り口に戻る