みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

yocto pulseaudio.socketをレシピからenableする

pulseaudioのUnitはUser Unitであるが、yoctoのUser Unitの取り扱いに問題がありboot時に正しく実行されない。 boot時にpulseaudio.socketが実行されるようにするための方法を調査したのでメモ。

systemdのenableの仕掛け

まず、「systemctl enable」をした時に何が起こるかを見てみる。

System Unitの場合

$ systemctl enable dropbear.socket
Created symlink from /etc/systemd/system/sockets.target.wants/dropbear.socket to /lib/systemd/system/dropbear.socket.

/etc/systemd/system/sockets.target.wants/dropbear.socketに/lib/systemd/system/dropbear.socketのシンボリックリンクが作成される。

つまり下記と同じになる。

$ ln -s /lib/systemd/system/dropbear.socket /etc/systemd/system/sockets.target.wants/dropbear.socket

さらに、Unitの状態をenabledに変更している。この情報がどこに存在するかは今回は見つけられなかった。 シンボリックリンクをはっただけの状態は、linkedとなる。

User Unitの場合

$ systemctl --user enable pulseaudio.socket
Created symlink from /home/root/.config/systemd/user/sockets.target.wants/pulseaudio.socket to /usr/lib/systemd/user/pulseaudio.socket.

こちらも/home/root/.config/systemd/user/sockets.target.wants/pulseaudio.socketに/usr/lib/systemd/user/pulseaudio.socketのシンボリックリンクが作成される。

$ ln -s /usr/lib/systemd/user/pulseaudio.socket /home/root/.config/systemd/user/sockets.target.wants/pulseaudio.socket

こちらも、Unitの状態をenabledに変更する。

つまり、Unit状態がenabledであり、XXXX.target.wants以下にUnit Fileのシンボリックファイルがあれば、自動実行されるようになっている。 どちらか片方だけでは自動実行は正しく動作しない。

Unit fileの格納場所

System UnitとUser Unitはそれぞれ下記の場所に格納されている。

種別 格納場所
System Unit /etc/systemd/system
User Unit /usr/lib/systemd/user

enable用のシンボリックリンクの格納場所

下記のディレクトリの下に「XXXX.target.wants」というディレクトリがあり、その中に格納されている。

種別 格納場所
System Unit /etc/systemd/system
User Unit ${HOME}/.config/systemd/user

Unit種別がsocketの場合は「socket.target.wants」になるようだが、 serviceの場合は「bluetooth.target.wants」や「multi-user.target.wants」など命名規則が見つけられなかった。

しかし、基本的にはsystemctlコマンドを使用するため、自身が気にする必要があるケースは非常に少ないだろう。

レシピでenableを行う

ここにこんな書き込みがあった。

Sure, you can manually create the link as you're told in this answer. Though, the better way would be to use the systemd.bbclass. You'd do this by inherit systemd in your recipe, and then specify the name of the service file in SYSTEMD_SERVICE = "name_of_the_file". This will automatically enable the service for you.

つまり下記の様にすると、自動的にenableされた状態になる。

inherit systemd

SYSTEMD_SERVICE = "name_of_the_file"

ただこれは、User Unitではうまく動作しない。 pulseaudio.incで下記のようになっている。

SYSTEMD_SERVICE_${PN}-server = "pulseaudio.service"

しかし、実機ではpulseaudio.serviceは実行されない。

$ systemctl --user status pulseaudio.service
● pulseaudio.service - Sound Service
   Loaded: loaded (/usr/lib/systemd/user/pulseaudio.service; enabled; vendor preset: enabled)
   Active: inactive (dead)

enableはされているが、実際にはpulseaudio.serviceは起動されていない。 systemd.bbclassの実装が、User Unitに関してはうまくケアできていない状態のようだ。

対処方法

根本の原因はsystemd.bbclass及びsystemd-systemctl-nativeのsystemctlがUser Unitをきちんと取り扱っていない事のようなので、 汎用性のある対処はビルドシステムを修正しないと難しい。

今回はpulseaudio.serviceに絞って対処する。

meta-local-systemd/recipes-multimedia/pulseaudio/pulseaudio_%.bbappend

FILES_${PN} += "${ROOT_HOME}/.config/systemd/user/*"
SYSTEMD_SERVICE_${PN}-server = "pulseaudio.socket"

do_install_append() {
    install -d ${D}${ROOT_HOME}/.config/systemd/user/sockets.target.wants
    ln -sf ${D}/${systemd_user_unitdir}/pulseaudio.socket \
       ${D}${ROOT_HOME}/.config/systemd/user/sockets.target.wants/pulseaudio.socket
}

現在は、pulseaudio.serviceが中途半端な状態でenableされているが、 このbbappendにより、pulseaudio.serviceのenableは行わず、 pulseaudio.socketをenableし、必要なシンボリックリンクの作成を行う。