SO_PEERCRED gets useful
System tray is an integral part of many applications. It provides easy integration to the OS taskbar, allowing users to interact with apps even if they are not focused.
Nowadays most utilises the StatusNotifier specification. They expose various methods on their bus name, under path /StatusNotifierItem and register themselves with a central service StatusNotifierWatcher, which is usually part of a desktop environment itself (e.g. Appindicator extension on GNOME).
Many applications may have broken single instance behaviour inside a sandbox. Whether that’s using a D-Bus name which is not allowed, or the whole app is just broken and does not offer proper single instance detection (looking at you, Tencent). Launching a new instance does not wake up the previous one and exit, but ignores them and start regardlessly. We need to fix this broken landscape.
D-Bus messages go through a central proxy in Portable. This process is entirely transparent thanks to xdg-dbus-proxy. On the host side, the proxy relays any allowed messages and signals on it’s behalf and between the sandbox and the host. You may remember that socket listeners can obtain peer’s credentials via multiple means, like SO_PEERCRED. It just so happens that the messaging bus itself provides a mean to obtain PID of a bus name owner, via the GetConnectionUnixProcessID method. Annnnd, if you can recall, the status notifier watcher acts like a central register of tray icons. Naturally it holds the list of registered bus names on property RegisteredStatusNotifierItems. The stars have aligned, and we can associate tray icons with sandboxes in a breeze.
Portable uses control groups version 2, not only for the sandboxed app, but also the proxy itself for tracking processes. In control groups we can see inner processes via the cgroup.procs file, containing PIDs separated by newlines. Since the proxy talks on behalf of anything inside the sandbox and can be tracked via a process ID, we can filter out which tray icon is registered by the sandboxed app. The StatusNotifierItem specification also conveniently provides a method Active for applications to attempt raising it’s own window. Connecting the previous dots into a path… There you have it, you can now wake up sandboxed applications without accidently triggering anything else.
