Skip to content

DeviceManagerListener

opencode-agent[bot] edited this page May 11, 2026 · 1 revision

DeviceManagerListener

Observer interface for device discovery and binding events in JNode's driver framework.

Overview

DeviceManagerListener (core/src/driver/org/jnode/driver/DeviceManagerListener.java) is JNode's observer interface for high-level device manager events — device registration and unregistration. It allows any component to be notified whenever a device enters or leaves the system's device registry, without coupling to the device's lifecycle details.

This differs from DeviceListener (core/src/driver/org/jnode/driver/DeviceListener.java), which fires on device start and stop (the driver lifecycle within an already-registered device). DeviceManagerListener fires at a higher level: when the device is first registered with the manager and when it is about to be removed from the registry entirely.

Key Components

File Role
core/src/driver/org/jnode/driver/DeviceManagerListener.java The listener interface: deviceRegistered(Device), deviceUnregister(Device)
core/src/driver/org/jnode/driver/AbstractDeviceManager.java Listener registration (addListener/removeListener) and event dispatch (fireRegisteredEvent, fireUnregisterEvent)
core/src/driver/org/jnode/driver/DeviceManager.java Public interface declaring addListener(DeviceManagerListener) / removeListener(DeviceManagerListener)
gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java Canonical usage: deferred initialization of the framebuffer console

How It Works

Listener Interface

The interface is minimal — two methods:

// core/src/driver/org/jnode/driver/DeviceManagerListener.java
public interface DeviceManagerListener {
    public void deviceRegistered(Device device);
    public void deviceUnregister(Device device);
}

Registration and Dispatch

Listeners register via AbstractDeviceManager.addListener(DeviceManagerListener). The manager maintains an internal List<DeviceManagerListener>:

// AbstractDeviceManager.java
private final List<DeviceManagerListener> listeners = new LinkedList<DeviceManagerListener>();

public final void addListener(DeviceManagerListener listener) {
    synchronized (listeners) {
        listeners.add(listener);
    }
}

public final void removeListener(DeviceManagerListener listener) {
    synchronized (listeners) {
        listeners.remove(listener);
    }
}

When a device is registered, AbstractDeviceManager.register() calls fireRegisteredEvent():

// Called inside register(), before start()
protected final void fireRegisteredEvent(Device device) {
    final List<DeviceManagerListener> list;
    synchronized (this.listeners) {
        list = new ArrayList<DeviceManagerListener>(this.listeners);
    }
    final StopWatch sw = new StopWatch();
    for (DeviceManagerListener l : list) {
        sw.start();
        l.deviceRegistered(device);
        if (sw.isElapsedLongerThen(100)) {
            BootLogInstance.get().error("DeviceManagerListener took " + sw
                + " in deviceRegistered: " + l.getClass().getName());
        }
    }
}

The same pattern applies to fireUnregisterEvent() — called from unregister() after stopping the device but before removing it from the map.

The listener list is copied under the lock before iteration, ensuring safe concurrent modification. A StopWatch measures each callback; any listener exceeding 100ms triggers an error log.

Canonical Use Case: Deferred Initialization

The primary use case is deferred initialization — a component that depends on a device that may not exist yet. FBConsole in the GUI driver demonstrates this pattern:

// gui/src/driver/org/jnode/driver/textscreen/fb/FBConsole.java
public static void start() throws Exception {
    final Collection<Device> devs = DeviceUtils.getDevicesByAPI(FrameBufferAPI.class);
    int dev_count = devs.size();
    if (dev_count > 0) {
        startFBConsole(devs.iterator().next());
    } else {
        DeviceUtils.getDeviceManager().addListener(new DeviceManagerListener() {
            public void deviceRegistered(Device device) {
                if (device.implementsAPI(FrameBufferAPI.class)) {
                    startFBConsole(device);
                }
            }
            public void deviceUnregister(Device device) {
                // TODO stop the FBConsole
            }
        });
    }
}

This is the wait-for-device pattern: poll first, and if nothing is found, register a listener to wait asynchronously for a future device.

Relationship to DeviceListener

DeviceManagerListener DeviceListener
Package org.jnode.driver org.jnode.driver
Methods deviceRegistered, deviceUnregister deviceStarted, deviceStop
Fires when Device is registered/unregistered in the manager Device driver starts/stops
Registered on DeviceManager DeviceManager or Device
Scope Manager-wide (all devices) Per-device or manager-wide

Both listener types share the same 100ms warning threshold in AbstractDeviceManager. The distinction is between the device registry lifecycle (DeviceManagerListener) and the device driver lifecycle (DeviceListener).

Gotchas

  • Listener is on the manager, not the device — unlike DeviceListener which can be added directly to a Device instance, DeviceManagerListener is always registered with the DeviceManager and receives events for all devices.
  • Fire order relative to lifecycledeviceRegistered is fired before the device is started (start(device) is called after the fire). deviceUnregister is fired after the device is stopped but before it is removed from the map.
  • 100ms warning threshold — slow listeners affect the timing of all subsequent listener callbacks and device startup. Avoid blocking I/O in listener callbacks.
  • No filtering by device class — the listener receives every registration. Use device.implementsAPI(SomeAPI.class) to filter.
  • Anonymous inner class memory leak risk — the manager holds a strong reference to the listener. If the listener captures a large context, it won't be GC'd until explicitly removed. Always removeListener() when done, or use weak references for long-lived listeners with short-lived implementations.

Related Pages

  • DeviceManager — The manager this listener attaches to, including event dispatch details.
  • Driver-Framework — The broader driver subsystem where this observer pattern lives.
  • DeviceListener — Lower-level listener for device start/stop events (different scope).
  • Plugin-System — How device finders trigger the registration events observed by this listener.
  • Resource-Management — Hardware resources that devices claim at startup time.

Clone this wiki locally