<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hal on Roberto Selbach</title><link>https://rselbach.com/tags/hal/</link><description>Recent content in Hal on Roberto Selbach</description><generator>Hugo</generator><language>en-US</language><lastBuildDate>Tue, 29 Aug 2006 20:41:00 +0000</lastBuildDate><atom:link href="https://rselbach.com/tags/hal/index.xml" rel="self" type="application/rss+xml"/><item><title>Solid Lines Around Hardware</title><link>https://rselbach.com/solid-lines-around-hardware/</link><pubDate>Tue, 29 Aug 2006 20:41:00 +0000</pubDate><guid>https://rselbach.com/solid-lines-around-hardware/</guid><description>&lt;p&gt;My network widget broke today because a property changed underneath it. More precisely, the widget knew enough about the hardware backend to parse a backend-specific property, and not enough to notice when that property was absent. This is the sort of knowledge that makes software feel powerful right up to the first different machine.&lt;/p&gt;
&lt;p&gt;Solid is the KDE 4 attempt to draw a stable line between applications and hardware discovery mechanisms. An application should ask for devices and capabilities in KDE terms. A backend can obtain those facts from HAL, NetworkManager, or another platform facility. The abstraction is not meant to make all hardware identical; it is meant to stop every application from inventing a private translation layer.&lt;/p&gt;
&lt;p&gt;The useful mental model is a device plus interfaces. A device has an identity and general properties. Interfaces describe capabilities such as storage access, battery status, or networking. Code can first ask whether a capability exists, then use the corresponding interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Solid&lt;span style="color:#f92672"&gt;::&lt;/span&gt;Device device(udi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (device.isDeviceInterface(Solid&lt;span style="color:#f92672"&gt;::&lt;/span&gt;DeviceInterface&lt;span style="color:#f92672"&gt;::&lt;/span&gt;StorageVolume)) {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Solid&lt;span style="color:#f92672"&gt;::&lt;/span&gt;StorageVolume &lt;span style="color:#f92672"&gt;*&lt;/span&gt;volume &lt;span style="color:#f92672"&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; device.as&lt;span style="color:#f92672"&gt;&amp;lt;&lt;/span&gt;Solid&lt;span style="color:#f92672"&gt;::&lt;/span&gt;StorageVolume&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; qDebug() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; volume&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;label() &lt;span style="color:#f92672"&gt;&amp;lt;&amp;lt;&lt;/span&gt; volume&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;size();
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The pointer still needs checking because devices disappear and backends can fail. A USB disk is not contractually obliged to remain attached while my slot admires it.&lt;/p&gt;
&lt;p&gt;Identity is harder than it first appears. A display name is for humans and can change. A device path may reflect discovery order. A HAL UDI is useful within that backend but should not leak into an application&amp;rsquo;s persistent file format if the application claims backend independence. For a short-lived object map, the current unique identifier is fine. For durable preferences, I need a stable property appropriate to the device class, and sometimes no truly stable identifier exists.&lt;/p&gt;
&lt;p&gt;Hotplug events introduce ordering questions. My first implementation reacted to a &amp;ldquo;device added&amp;rdquo; signal by immediately requesting every interface. Some properties were not ready yet, and parent devices could appear after children. The safer path is to tolerate incomplete devices, query only required capabilities, and update when relevant properties change. Applications must not infer a complete topology from the first signal they see.&lt;/p&gt;
&lt;p&gt;Networking demonstrates why policy should remain separate. NetworkManager can report devices, available networks, activation state, and changes. Solid can present that information consistently to KDE code. It should not mean that a text editor decides which wireless network to activate. A desktop networking component may own that policy; most applications only need to know whether connectivity is currently available, perhaps with enough uncertainty to avoid promising too much.&lt;/p&gt;
&lt;p&gt;Storage has a similar distinction. Discovering a volume is not the same as mounting it, and mounting it is not the same as opening a file manager. Those are three mechanisms with three possible policy owners. When a camera appears, a photo application may offer an import action. Automatically performing one because a hardware signal arrived would be efficient in the same way as a trapdoor.&lt;/p&gt;
&lt;p&gt;For the widget, I replaced direct HAL property access with a tiny internal state derived from Solid interfaces:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;NetworkState&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; QString name;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; available;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;bool&lt;/span&gt; active;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The widget receives this state and paints it. It no longer knows whether the information came from NetworkManager or a test backend. The adapter listens for device and property changes, rebuilds the affected state, and emits one application-level update. This also keeps backend callbacks away from paint code.&lt;/p&gt;
&lt;p&gt;I prefer capability queries over a deep inheritance tree of device types. Real hardware combines roles inconveniently, and capability composition lets one object expose several useful interfaces. The caveat is discoverability: callers must know which combinations make sense, and an abstraction can become a bag of optional pointers if its contracts are weak.&lt;/p&gt;
&lt;p&gt;I also prefer asynchronous operations for actions such as mounting or network activation. Hardware can wait for media, authentication, or a helper process. Blocking the GUI thread while reality decides what to do is poor manners. Completion needs an error path that preserves enough backend detail for diagnosis without requiring the application to parse backend internals.&lt;/p&gt;
&lt;p&gt;None of this makes Solid finished. We still need to learn which properties are genuinely portable, how device lifetimes should be represented, and how much backend-specific information may escape without defeating the purpose. HAL itself is evolving, and NetworkManager behaviour differs across the machines I can test. A clean interface can expose uncertainty; it cannot abolish it.&lt;/p&gt;
&lt;p&gt;My practical rule after today&amp;rsquo;s failure is simple: application code depends on capabilities, UI code depends on application state, and raw backend properties stop at the adapter boundary. Exceptions may be necessary for specialised tools, but they should look like exceptions rather than quietly becoming architecture.&lt;/p&gt;
&lt;p&gt;The widget now survives the missing property. It also reports my wired interface as &amp;ldquo;network cable,&amp;rdquo; which is accurate, stable, and not likely to win a naming award.&lt;/p&gt;</description></item><item><title>HAL Is a Source, Not a Policy</title><link>https://rselbach.com/hal-is-a-source-not-a-policy/</link><pubDate>Tue, 28 Mar 2006 19:48:00 +0000</pubDate><guid>https://rselbach.com/hal-is-a-source-not-a-policy/</guid><description>&lt;p&gt;I plugged in a USB disk this afternoon and my test application offered to open it twice. Unplugging it removed only one entry. This is an efficient way to make hardware discovery look supernatural.&lt;/p&gt;
&lt;p&gt;The bug was mundane: startup enumeration and hotplug notification both created an object, while neither path checked whether the same device identifier was already present. HAL supplies facts about devices and changes, but it does not decide how my application should represent them.&lt;/p&gt;
&lt;p&gt;I now funnel both paths through one function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;void&lt;/span&gt; DeviceList&lt;span style="color:#f92672"&gt;::&lt;/span&gt;addDevice(&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; QString &lt;span style="color:#f92672"&gt;&amp;amp;&lt;/span&gt;udi)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (devices.contains(udi))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Device device &lt;span style="color:#f92672"&gt;=&lt;/span&gt; backend&lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt;device(udi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; (&lt;span style="color:#f92672"&gt;!&lt;/span&gt;device.isValid())
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; devices.insert(udi, device);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; emit &lt;span style="color:#a6e22e"&gt;deviceAdded&lt;/span&gt;(udi);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Removal uses the same identifier and emits only after the internal state is consistent. That ordering lets slots query the list without observing a ghost.&lt;/p&gt;
&lt;p&gt;The larger KDE 4 question is where HAL ends and a hardware abstraction such as Solid begins. I do not want every application parsing HAL properties or knowing which backend discovered a battery. Applications should ask stable questions: is this a storage volume, can it be mounted, is this network interface active? Solid can translate those questions to the platform mechanism.&lt;/p&gt;
&lt;p&gt;I prefer keeping the backend thin and putting application policy above Solid. A media player may automatically inspect an audio disc; a file manager may offer actions; a backup tool may ignore both and look only for a labelled volume. The same hardware event should not imply the same decision.&lt;/p&gt;
&lt;p&gt;For testing, the backend now accepts a recorded sequence of add and remove events. Replaying &amp;ldquo;add, add, remove&amp;rdquo; verifies the duplicate guard without requiring me to develop exceptional timing with a USB plug. It also makes event ordering assumptions visible in a small test rather than in a user&amp;rsquo;s device list.&lt;/p&gt;
&lt;p&gt;The caveat is that abstraction can hide information we have not yet learned to model. During early porting I am logging the raw UDI and selected properties beside the abstract device type. When a device is classified incorrectly, that evidence is valuable. I would remove such noise from a normal release, assuming we eventually have one that does not greet a single disk as twins.&lt;/p&gt;</description></item></channel></rss>