A Framework is a meeting point for services and devices from many different vendors: a meeting point where users add and cancel service subscriptions, newly installed services find their corresponding input and output devices, and device drivers connect to their hardware.
In an OSGi Framework, these activities will dynamically take place while the Framework is running. Technologies such as USB and IEEE 1394 explicitly support plugging and unplugging devices at any time, and wireless technologies are even more dynamic.
This flexibility makes it hard to configure all aspects of an OSGi Framework, particularly those relating to devices. When all of the possible services and device requirements are factored in, each OSGi Framework will be unique. Therefore, automated mechanisms are needed that can be extended and customized, in order to minimize the configuration needs of the OSGi environment.
The Device Access specification supports the coordination of automatic detection and attachment of existing devices on an OSGi Framework, facilitates hot-plugging and -unplugging of new devices, and downloads and installs device drivers on demand.
This specification, however, deliberately does not prescribe any particular device or network technology, and mentioned technologies are used as examples only. Nor does it specify a particular device discovery method. Rather, this specification focuses on the attachment of devices supplied by different vendors. It emphasizes the development of standardized device interfaces to be defined in device categories, although no such device categories are defined in this specification.
-
Embedded Devices - OSGi bundles will likely run in embedded devices. This environment implies limited possibility for user interaction, and low-end devices will probably have resource limitations.
-
Remote Administration - OSGi environments must support administration by a remote service provider.
-
Vendor Neutrality - OSGi-compliant driver bundles will be supplied by different vendors; each driver bundle must be well-defined, documented, and replaceable.
-
Continuous Operation - OSGi environments will be running for extended periods without being restarted, possibly continuously, requiring stable operation and stable resource consumption.
-
Dynamic Updates - As much as possible, driver bundles must be individually replaceable without affecting unrelated bundles. In particular, the process of updating a bundle should not require a restart of the whole OSGi Framework or disrupt operation of connected devices.
A number of requirements must be satisfied by Device Access implementations in order for them to be OSGi-compliant. Implementations must support the following capabilities:
-
Hot-Plugging - Plugging and unplugging of devices at any time if the underlying hardware and drivers allow it.
-
Legacy Systems - Device technologies which do not implement the automatic detection of plugged and unplugged devices.
-
Dynamic Device Driver Loading - Loading new driver bundles on demand with no prior device-specific knowledge of the Device service.
-
Multiple Device Representations - Devices to be accessed from multiple levels of abstraction.
-
Deep Trees - Connections of devices in a tree of mixed network technologies of arbitrary depth.
-
Topology Independence - Separation of the interfaces of a device from where and how it is attached.
-
Complex Devices - Multifunction devices and devices that have multiple configurations.
This specification defines the behavior of a device manager (which is not a service as might be expected). This device manager detects registration of Device services and is responsible for associating these devices with an appropriate Driver service. These tasks are done with the help of Driver Locator services and the Driver Selector service that allow a device manager to find a Driver bundle and install it.
The main entities of the Device Access specification are:
-
Device Manager - The bundle that controls the initiation of the attachment process behind the scenes.
-
Device Category - Defines how a Driver service and a Device service can cooperate.
-
Driver - Competes for attaching Device services of its recognized device category. See Driver Services.
-
Device - A representation of a physical device or other entity that can be attached by a Driver service. See Device Services.
-
DriverLocator - Assists in locating bundles that provide a Driver service. See Driver Locator Service.
-
DriverSelector - Assists in selecting which Driver service is best suited to a Device service. See The Driver Selector Service.
Figure 103.1 show the classes and their relationships.
A Device service represents some form of a device. It can represent a hardware device, but that is not a requirement. Device services differ widely: some represent individual physical devices and others represent complete networks. Several Device services can even simultaneously represent the same physical device at different levels of abstraction. For example:
-
A USB network.
-
A device attached on the USB network.
-
The same device recognized as a USB to Ethernet bridge.
-
A device discovered on the Ethernet using Salutation.
-
The same device recognized as a simple printer.
-
The same printer refined to a PostScript printer.
A device can also be represented in different ways. For example, a USB mouse can be considered as:
-
A USB device which delivers information over the USB bus.
-
A mouse device which delivers
x
andy
coordinates and information about the state of its buttons.
Each representation has specific implications:
-
That a particular device is a mouse is irrelevant to an application which provides management of USB devices.
-
That a mouse is attached to a USB bus or a serial port would be inconsequential to applications that respond to mouse-like input.
Device services must belong to a defined device category, or else they can implement a generic service which models a particular device, independent of its underlying technology. Examples of this type of implementation could be Sensor or Actuator services.
A device category specifies the methods for communicating with a Device service, and enables interoperability between bundles that are based on the same underlying technology. Generic Device services will allow interoperability between bundles that are not coupled to specific device technologies.
For example, a device category is required for the USB, so that Driver bundles can be written that communicate to the devices that are attached to the USB. If a printer is attached, it should also be available as a generic Printer service defined in a Printer service specification, indistinguishable from a Printer service attached to a parallel port. Generic categories, such as a Printer service, should also be described in a Device Category.
It is expected that most Device service objects will actually represent a physical device in some form, but that is not a requirement of this specification. A Device service is represented as a normal service in the OSGi Framework and all coordination and activities are performed upon Framework services. This specification does not limit a bundle developer from using Framework mechanisms for services that are not related to physical devices.
A Device service is defined as a normal service registered with the Framework that either:
-
Registers a service object under the interface
org.osgi.service.Device
with the Framework, or -
Sets the DEVICE_CATEGORY property in the registration. The value of
DEVICE_CATEGORY
is an array ofString
objects of all the device categories that the device belongs to. These strings are defined in the associated device category.
If this document mentions a Device service, it is meant to refer
to services registered with the name
org.osgi.service.device.Device
or
services registered with the DEVICE_CATEGORY
property
set.
When a Device service is registered, additional properties may be set that describe the device to the device manager and potentially to the end users. The following properties have their semantics defined in this specification:
-
DEVICE_CATEGORY - A marker property indicating that this service must be regarded as a Device service by the device manager. Its value is of type
String[]
, and its meaning is defined in the associated device category specification. -
DEVICE_DESCRIPTION - Describes the device to an end user. Its value is of type
String
. -
DEVICE_SERIAL - A unique serial number for this device. If the device hardware contains a serial number, the driver bundle is encouraged to specify it as this property. Different Device services representing the same physical hardware at different abstraction levels should set the same
DEVICE_SERIAL
, thus simplifying identification. Its value is of typeString
. -
service.pid
- Service Persistent ID (PID), defined inorg.osgi.framework.Constants
. Device services should set this property. It must be unique among all registered services. Even different abstraction levels of the same device must use different PIDs. The service PIDs must be reproducible, so that every time the same hardware is plugged in, the same PIDs are used.
When a Device service is registered with the Framework, the device manager is responsible for finding a suitable Driver service and instructing it to attach to the newly registered Device service. The Device service itself is passive: it only registers a Device service with the Framework and then waits until it is called.
The actual communication with the underlying physical device is
not defined in the Device
interface because it differs
significantly between different types of devices. The Driver service is
responsible for attaching the device in a device type-specific manner.
The rules and interfaces for this process must be defined in the
appropriate device category.
If the device manager is unable to find a suitable Driver service,
the Device service remains unattached. In that case, if the service
object implements the Device
interface, it must receive a
call to the noDriverFound() method. The Device service can wait until a new
driver is installed, or it can unregister and attempt to register again
with different properties that describe a more generic device or try a
different configuration.
The main purpose of the device manager is to try to attach drivers to idle devices. For this purpose, a Device service is considered idle if no bundle that itself has registered a Driver service is using the Device service.
When a Device service is unregistered, no immediate action is required by the device manager. The normal service of unregistering events, provided by the Framework, takes care of propagating the unregistration information to affected drivers. Drivers must take the appropriate action to release this Device service and perform any necessary cleanup, as described in their device category specification.
The device manager may, however, take a device unregistration as an indication that driver bundles may have become idle and are thus eligible for removal. It is therefore important for Device services to unregister their service object when the underlying entity becomes unavailable.
A device category specifies the rules and interfaces needed for the communication between a Device service and a Driver service. Only Device services and Driver services of the same device category can communicate and cooperate.
The Device Access service specification is limited to the attachment of Device services by Driver services, and does not enumerate different device categories.
Other specifications must specify a number of device categories before this specification can be made operational. Without a set of defined device categories, no interoperability can be achieved.
Device categories are related to a specific device technology, such as USB, IEEE 1394, JINI, UPnP, Salutation, CEBus, Lonworks, and others. The purpose of a device category specification is to make all Device services of that category conform to an agreed interface, so that, for example, a USB Driver service of vendor A can control Device services from vendor B attached to a USB bus.
This specification is limited to defining the guidelines for device category definitions only. Device categories may be defined by the OSGi organization or by external specification bodies - for example, when these bodies are associated with a specific device technology.
A device category definition comprises the following elements:
-
An interface that all devices belonging to this category must implement. This interface should lay out the rules of how to communicate with the underlying device. The specification body may define its own device interfaces (or classes) or leverage existing ones. For example, a serial port device category could use the
javax.comm.SerialPort
interface which is defined in [1] Java Communications API.When registering a device belonging to this category with the Framework, the interface or class name for this category must be included in the registration.
-
A set of service registration properties, their data types, and semantics, each of which must be declared as either
MANDATORY
orOPTIONAL
for this device category. -
A range of match values specific to this device category. Matching is explained later in The Device Attachment Algorithm.
The following is a partial example of a fictitious device category:
public interface /* com.acme.widget.*/ WidgetDevice{
int MATCH_SERIAL = 10;
int MATCH_VERSION = 8;
int MATCH_MODEL = 6;
int MATCH_MAKE = 4;
int MATCH_CLASS = 2;
void sendPacket( byte [] data );
byte [] receivePacket( long timeout );
}
Devices in this category must implement the interface
com.acme.widget.WidgetDevice
to receive attachments from
Driver services in this category.
Device properties for this fictitious category are defined in the following table.
Table 103.1 Example Device Category Properties, M=Mandatory, O=Optional
Property name | M/O | Type | Value |
---|---|---|---|
DEVICE_CATEGORY |
M |
String[] |
{"Widget"} |
com.acme.class |
M |
String |
A class description of this device. For example
" |
com.acme.model |
M |
String |
A definition of the model. This is usually vendor
specific. For example " |
com.acme.manufacturer |
M |
String |
Manufacturer of this device, for example "ACME Widget Division". |
com.acme.revision |
O |
String |
Revision number. For example, "42". |
com.acme.serial |
O |
String |
A serial number. For example
" |
Driver services and Device services are connected via a matching
process that is explained in The Device Attachment Algorithm. The Driver
service plays a pivotal role in this matching process. It must inspect
the Device service (from its ServiceReference
object) that
has just been registered and decide if it potentially could cooperate
with this Device service.
It must be able to answer a value indicating the quality of the match. The scale of this match value must be defined in the device category so as to allow Driver services to match on a fair basis. The scale must start at least at 1 and go upwards.
Driver services for this sample device category must return one of
the match codes defined in the com.acme.widget.WidgetDevice
interface or Device.MATCH_NONE
if the Device service is not
recognized. The device category must define the exact rules for the
match codes in the device category specification. In this example, a
small range from 2 to 10 (MATCH_NONE
is 0) is defined for
WidgetDevice
devices. They are named in the
WidgetDevice
interface for convenience and have the
following semantics.
Table 103.2 Sample Device Category Match Scale
Match name | Value | Description |
---|---|---|
MATCH_SERIAL |
10 |
An exact match, including the serial number. |
MATCH_VERSION |
8 |
Matches the right class, make model, and version. |
MATCH_MODEL |
6 |
Matches the right class and make model. |
MATCH_MAKE |
4 |
Matches the make. |
MATCH_CLASS |
2 |
Only matches the class. |
A Driver service should use the constants to return when it
decides how closely the Device service matches its suitability. For
example, if it matches the exact serial number, it should return
MATCH_SERIAL
.
A Driver service is responsible for attaching to suitable Device services under control of the device manager. Before it can attach a Device service, however, it must compete with other Driver services for control.
If a Driver service wins the competition, it must attach the device in a device category-specific way. After that, it can perform its intended functionality. This functionality is not defined here nor in the device category; this specification only describes the behavior of the Device service, not how the Driver service uses it to implement its intended functionality. A Driver service may register one or more new Device services of another device category or a generic service which models a more refined form of the device.
Both refined Device services as well as generic services should be defined in a Device Category. See Device Category Specifications.
A Driver service is, like all services,
implemented in a bundle, and is recognized by the device manager by
registering one or more Driver
service objects with the
Framework.
Such bundles containing one or more Driver services are called driver bundles. The device manager must be aware of the fact that the cardinality of the relationship between bundles and Driver services is 1:1...*.
A driver bundle must register at least one
Driver service in its BundleActivator.start
implementation.
Device Drivers may belong to one of the following categories:
-
Base Drivers (Discovery, Pure Discovery and Normal)
-
Refining Drivers
-
Network Drivers
-
Composite Drivers
-
Referring Drivers
-
Bridging Drivers
-
Multiplexing Drivers
-
Pure Consuming Drivers
This list is not definitive, and a Driver service is not required to fit into one of these categories. The purpose of this taxonomy is to show the different topologies that have been considered for the Device Access service specification.
The first category of device drivers are called base drivers because they provide the lowest-level representation of a physical device. The distinguishing factor is that they are not registered as Driver services because they do not have to compete for access to their underlying technology.
Base drivers discover physical devices using code not specified here (for example, through notifications from a device driver in native code) and then register corresponding Device services.
When the hardware supports a discovery mechanism and reports a physical device, a Device service is then registered. Drivers supporting a discovery mechanism are called discovery base drivers.
An example of a discovery base driver is a USB driver. Discovered USB devices are registered with the Framework as a generic USB Device service. The USB specification (see [2] USB Specification ) defines a tightly integrated discovery method. Further, devices are individually addressed; no provision exists for broadcasting a message to all devices attached to the USB bus. Therefore, there is no reason to expose the USB network itself; instead, a discovery base driver can register the individual devices as they are discovered.
Not all technologies support a discovery mechanism. For example, most serial ports do not support detection, and it is often not even possible to detect whether a device is attached to a serial port.
Although each driver bundle should perform discovery on its own, a driver for a non-discoverable serial port requires external help - either through a user interface or by allowing the Configuration Admin service to configure it.
It is possible for the driver bundle to combine automatic discovery of Plug and Play-compliant devices with manual configuration when non-compliant devices are plugged in.
The second category of device drivers are called refining drivers. Refining drivers provide a refined view of a physical device that is already represented by another Device service registered with the Framework. Refining drivers register a Driver service with the Framework. This Driver service is used by the device manager to attach the refining driver to a less refined Device service that is registered as a result of events within the Framework itself.
An example of a refining driver is a mouse driver, which is attached to the generic USB Device service representing a physical mouse. It then registers a new Device service which represents it as a Mouse service, defined elsewhere.
The majority of drivers fall into the refining driver type.
An Internet Protocol (IP) capable network such as Ethernet supports individually addressable devices and allows broadcasts, but does not define an intrinsic discovery protocol. In this case, the entire network should be exposed as a single Device service.
Complex devices can often be broken down into several parts. Drivers that attach to a single service and then register multiple Device services are called composite drivers. For example, a USB speaker containing software-accessible buttons can be registered by its driver as two separate Device services: an Audio Device service and a Button Device service.
This approach can greatly reduce the number of interfaces needed, as well as enhance reusability.
A referring driver is actually not a driver in the sense that it controls Device services. Instead, it acts as an intermediary to help locate the correct driver bundle. This process is explained in detail in The Device Attachment Algorithm.
A referring driver implements the call to the
attach
method to inspect the Device service, and decides
which Driver bundle would be able to attach to the device. This
process can actually involve connecting to the physical device and
communicating with it. The attach
method then returns a
String
object that indicates the DRIVER_ID
of another driver bundle. This process is called a referral.
For example, a vendor ACME can implement one driver bundle that specializes in recognizing all of the devices the vendor produces. The referring driver bundle does not contain code to control the device - it contains only sufficient logic to recognize the assortment of devices. This referring driver can be small, yet can still identify a large product line. This approach can drastically reduce the amount of downloading and matching needed to find the correct driver bundle.
A bridging driver registers a Device service from one device category but attaches it to a Device service from another device category.
For example, USB to Ethernet bridges exist that allow connection to an Ethernet network through a USB device. In this case, the top level of the USB part of the Device service stack would be an Ethernet Device service. But the same Ethernet Device service can also be the bottom layer of an Ethernet layer of the Device service stack. A few layers up, a bridge could connect into yet another network.
The stacking depth of Device services has no limit, and the same drivers could in fact appear at different levels in the same Device service stack. The graph of drivers-to-Device services roughly mirrors the hardware connections.
A multiplexing driver attaches a number of Device services and aggregates them in a new Device service.
For example, assume that a system has a mouse on USB, a graphic tablet on a serial port, and a remote control facility. Each of these would be registered as a service with the Framework. A multiplexing driver can attach all three, and can merge the different positions in a central Cursor Position service.
A pure consuming driver bundle will attach to devices without registering a refined version.
For example, one driver bundle could decide to handle all serial
ports through javax.comm
instead of registering them as
services. When a USB serial port is plugged in, one or more Driver
services are attached, resulting in a Device service stack with a
Serial Port Device service. A pure consuming driver may then attach to
the Serial Port Device service and register a new serial port with the
javax.comm.*
registry instead of the Framework service
registry. This registration effectively transfers the device from the
OSGi environment into another environment.
It should be noted that any bundle installed in the OSGi environment may get and use a Device service without having to register a Driver service.
The following functionality is offered to those bundles that do register a Driver service and conform to the this specification:
-
The bundles can be installed and uninstalled on demand.
-
Attachment to the Device service is only initiated after the winning the competition with other drivers.
Drivers are recognized by registering a Driver service with the
Framework. This event makes the device manager aware of the existence of
the Driver service. A Driver service registration must have a DRIVER_ID property whose value is a String
object, uniquely identifying the driver to the device manager. The
device manager must use the DRIVER_ID
to prevent the
installation of duplicate copies of the same driver bundle.
Therefore, this DRIVER_ID
must:
-
Depend only on the specific behavior of the driver, and thus be independent of unrelated aspects like its location or mechanism of downloading.
-
Start with the reversed form of the domain name of the company that implements it: for example,
com.acme.widget.1.1
. -
Differ from the
DRIVER_ID
of drivers with different behavior. Thus, it must also be different for each revision of the same driver bundle so they may be distinguished.
When a new Driver service is registered, the Device Attachment Algorithm must be applied to each idle Device service. This requirement gives the new Driver service a chance to compete with other Driver services for attaching to idle devices. The techniques outlined in Optimizations can provide significant shortcuts for this situation.
As a result, the Driver service object can receive
match
and attach
requests before the method
which registered the service has returned.
This specification does not define any method for new Driver services to steal already attached devices. Once a Device service has been attached by a Driver service, it can only be released by the Driver service itself.
When a Driver service is unregistered, it must release all Device services to which it is attached. Thus, all its attached Device services become idle. The device manager must gather all of these idle Device services and try to re-attach them. This condition gives other Driver services a chance to take over the refinement of devices after the unregistering driver. The techniques outlined in Optimizations can provide significant shortcuts for this situation.
A Driver service that is installed by the device manager must remain registered as long as the driver bundle is active. Therefore, a Driver service should only be unregistered if the driver bundle is stopping, an occurrence which may precede its being uninstalled or updated. Driver services should thus not unregister in an attempt to minimize resource consumption. Such optimizations can easily introduce race conditions with the device manager.
The Driver
interface consists of the following
methods:
-
match(ServiceReference) - This method is called by the device manager to find out how well this Driver service matches the Device service as indicated by the
ServiceReference
argument. The value returned here is specific for a device category. If this Device service is of another device category, the valueDevice.MATCH_NONE
must be returned. Higher values indicate a better match. For the exact matching algorithm, see The Device Attachment Algorithm.Driver match values and referrals must be deterministic, in that repeated calls for the same Device service must return the same results so that results can be cached by the device manager.
-
attach(ServiceReference) - If the device manager decides that a Driver service should be attached to a Device service, it must call this method on the Driver service object. Once this method is called, the Device service is regarded as attached to that Driver service, and no other Driver service must be called to attach to the Device service. The Device service must remain owned by the Driver service until the Driver bundle is stopped. No
unattach
method exists.The
attach
method should returnnull
when the Device service is correctly attached. A referring driver (see Referring Drivers ) can return aString
object that specifies theDRIVER_ID
of a driver that can handle this Device service. In this case, the Device service is not attached and the device manager must attempt to install a Driver service with the sameDRIVER_ID
via a Driver Locator service. The attach method must be deterministic as described in the previous method.
The device manager must automatically install Driver bundles, which are obtained from Driver Locator services, when new Device services are registered.
A Driver Locator service encapsulates the knowledge of how to fetch
the Driver bundles needed for a specific Device service. This selection is
made on the properties that are registered with a device: for example,
DEVICE_CATEGORY
and any other properties registered with the
Device service registration.
The purpose of the Driver Locator service is to separate the mechanism from the policy. The decision to install a new bundle is made by the device manager (the mechanism), but a Driver Locator service decides which bundle to install and from where the bundle is downloaded (the policy).
Installing bundles has many consequences for the security of the system, and this process is also sensitive to network setup and other configuration details. Using Driver Locator services allows the Operator to choose a strategy that best fits its needs.
Driver services are identified by the DRIVER_ID
property. Driver Locator services use this particular ID to identify the
bundles that can be installed. Driver ID properties have uniqueness
requirements as specified in Device Service Registration. This uniqueness
allows the device manager to maintain a list of Driver services and
prevent unnecessary installs.
An OSGi Framework can have several different Driver Locator services
installed. The device manager must consult all of them and use the
combined result set, after pruning duplicates based on the
DRIVER_ID
values.
The DriverLocator interface allows suitable driver bundles to be located, downloaded, and installed on demand, even when completely unknown devices are detected.
It has the following methods:
-
findDrivers(Dictionary) - This method returns an array of driver IDs that potentially match a service described by the properties in the
Dictionary
object. A driver ID is theString
object that is registered by a Driver service under theDRIVER_ID
property. -
loadDriver(String) - This method returns an
InputStream
object that can be used to download the bundle containing the Driver service as specified by the driver ID argument. If the Driver Locator service cannot download such a bundle, it should returnnull
. Once this bundle is downloaded and installed in the Framework, it must register a Driver service with theDRIVER_ID
property set to the value of theString
argument.
The following example shows a very minimal Driver service
implementation. It consists of two classes. The first class is
SerialWidget
. This class tracks a single
WidgetDevice
from Sample Device Category Specification. It registers
a javax.comm.SerialPort
service, which is a general serial
port specification that could also be implemented from other device
categories like USB, a COM port, etc. It is created when the
SerialWidgetDriver
object is requested to attach a
WidgetDevice
by the device manager. It registers a new
javax.comm.SerialPort
service in its constructor.
The org.osgi.util.tracker.ServiceTracker
is extended
to handle the Framework events that are needed to simplify tracking this
service. The removedService
method of this class is
overridden to unregister the SerialPort
when the underlying
WidgetDevice
is unregistered.
package com.acme.widget;
import org.osgi.service.device.*;
import org.osgi.framework.*;
import org.osgi.util.tracker.*;
class SerialWidget extends ServiceTracker
implements javax.comm.SerialPort,
org.osgi.service.device.Constants {
ServiceRegistration registration;
SerialWidget( BundleContext c, ServiceReference r ) {
super( c, r, null );
open();
}
public Object addingService( ServiceReference ref ) {
WidgetDevice dev = (WidgetDevice)
context.getService( ref );
registration = context.registerService(
javax.comm.SerialPort.class.getName(),
this,
null );
return dev;
}
public void removedService( ServiceReference ref,
Object service ) {
registration.unregister();
context.ungetService(ref);
}
... methods for javax.comm.SerialPort that are
... converted to underlying WidgetDevice
}
A SerialWidgetDriver
object is registered with the
Framework in the Bundle Activator start method under the
Driver
interface. The device manager must call the match
method for each idle Device service that is registered. If it is chosen
by the device manager to control this Device service, a new
SerialWidget
is created that offers serial port
functionality to other bundles.
public class SerialWidgetDriver implementsDriver {
BundleContext context;
String spec =
"(&"
+" (objectclass=com.acme.widget.WidgetDevice)"
+" (DEVICE_CATEGORY=WidgetDevice)"
+" (com.acme.class=Serial)"
+")";
Filter filter;
SerialWidgetDriver( BundleContext context )
throws Exception {
this.context = context;
filter = context.createFilter(spec);
}
public int match( ServiceReference d ) {
if ( filter.match( d ) )
return WidgetDevice.MATCH_CLASS;
else
return Device.MATCH_NONE;
}
public synchronized String attach(ServiceReference r){
new SerialWidget( context, r );
}
}
The purpose of the Driver Selector service is to customize the selection of the best Driver service from a set of suitable Driver bundles. The device manager has a default algorithm as described in The Device Attachment Algorithm. When this algorithm is not sufficient and requires customizing by the operator, a bundle providing a Driver Selector service can be installed in the Framework. This service must be used by the device manager as the final arbiter when selecting the best match for a Device service.
The Driver Selector service is a singleton; only one such service is
recognized by the device manager. The Framework method
BundleContext.getServiceReference
must be used to obtain a
Driver Selector service. In the erroneous case that multiple Driver
Selector services are registered, the service.ranking
property will thus define which service is actually used.
A device manager implementation must invoke the method select(ServiceReference,Match[]). This method receives a Service Reference to the
Device service and an array of Match objects.
Each Match
object contains a link to the
ServiceReference
object of a Driver service and the result of
the match value returned from a previous call to
Driver.match
. The Driver Selector service should inspect the
array of Match
objects and use some means to decide which
Driver service is best suited. The index of the best match should be
returned. If none of the Match
objects describe a possible
Driver service, the implementation must return
DriverSelector.SELECT_NONE (-1)
.
Device Access is controlled by the device manager in the background. The device manager is responsible for initiating all actions in response to the registration, modification, and unregistration of Device services and Driver services, using Driver Locator services and a Driver Selector service as helpers.
The device manager detects the registration of Device services and
coordinates their attachment with a suitable Driver service. Potential
Driver services do not have to be active in the Framework to be eligible.
The device manager must use Driver Locator services to find bundles that
might be suitable for the detected Device service and that are not
currently installed. This selection is done via a DRIVER_ID
property that is unique for each Driver service.
The device manager must install and start these bundles with the
help of a Driver Locator service. This activity must result in the
registration of one or more Driver services. All available Driver
services, installed by the device manager and also others, then
participate in a bidding process. The Driver service can inspect the
Device service through its ServiceReference
object to find
out how well this Driver service matches the Device service.
If a Driver Selector service is available in the Framework service registry, it is used to decide which of the eligible Driver services is the best match.
If no Driver Selector service is available, the highest bidder must
win, with tie breaks defined on the service.ranking
and
service.id
properties. The selected Driver service is then
asked to attach
the Device service.
If no Driver service is suitable, the Device service remains idle. When new Driver bundles are installed, these idle Device services must be reattached.
The device manager must reattach a Device service if, at a later time, a Driver service is unregistered due to an uninstallation or update. At the same time, however, it should prevent superfluous and non-optimal reattachments. The device manager should also garbage-collect driver bundles it installed which are no longer used.
The device manager is a singleton. Only one device manager may exist, and it must have no public interface.
To prevent race conditions during Framework startup, the device manager must monitor the state of Device services and Driver services immediately when it is started. The device manager must not, however, begin attaching Device services until the Framework has been fully started, to prevent superfluous or non-optimal attachments.
The Framework has completed starting when the
FrameworkEvent.STARTED
event has been published.
Publication of that event indicates that Framework has finished all its
initialization and all bundles are started. If the device manager is
started after the Framework has been initialized, it should detect the
state of the Framework by examining the state of the system
bundle.
A key responsibility of the device manager is to attach refining drivers to idle devices. The following diagram illustrates the device attachment algorithm.
Table 103.3 Driver attachment algorithm
Step | Description |
---|---|
A |
If the
|
B |
For each found If this method succeeds, the device manager installs and starts the driver bundle. Driver bundles must register their Driver services synchronously during bundle activation. |
C |
For each Driver service, except those on the
exclusion list, call its Collect all successful matches - that is,
those whose return values are greater than
|
D |
If there is a Driver Selector service, the device
manager calls the If the Driver Selector service returns the
index of one of the If the Driver Selector service throws an exception or returns an invalid result, the default selection algorithm is used. Only one Driver Selector service is used, even if there is more than one registered in the Framework. See The Driver Selector Service. |
E |
The winner is the one with the highest match value. Tie breakers are respectively:
|
F |
The selected Driver service's If an exception is thrown, the Driver service has failed, and the algorithm proceeds to try another Driver service after excluding this one from further consideration at Step H. |
G |
The device manager attempts to load the referred
driver bundle in a manner similar to Step B, except that it is
unknown which Driver Locator service to use. Therefore, the
|
H |
The referring driver bundle is added to the exclusion list. Because each new referral adds an entry to the exclusion list, which in turn disqualifies another driver from further matching, the algorithm cannot loop indefinitely. This list is maintained for the duration of this algorithm. The next time a new Device service is processed, the exclusion list starts out empty. |
I |
If no Driver service attached the Device service,
the Device service is checked to see whether it implements the
|
K |
Whether an attachment was successful or not, the algorithm may have installed a number of driver bundles. The device manager should remove any idle driver bundles that it installed. |
Optimizations are explicitly allowed and even recommended for an implementation of a device manager. Implementations may use the following assumptions:
-
Driver match values and referrals must be deterministic, in that repeated calls for the same Device service must return the same results.
-
The device manager may cache match values and referrals. Therefore, optimizations in the device attachment algorithm based on this assumption are allowed.
-
The device manager may delay loading a driver bundle until it is needed. For example, a delay could occur when that
DRIVER_ID
's match values are cached. -
The results of calls to
DriverLocator
andDriverSelector
methods are not required to be deterministic, and must not be cached by the device manager. -
Thrown exceptions must not be cached. Exceptions are considered transient failures, and the device manager must always retry a method call even if it has thrown an exception on a previous invocation with the same arguments.
The device manager may remove driver bundles it has installed at any time, provided that all the Driver services in that bundle are idle. This recommended practice prevents unused driver bundles from accumulating over time. Removing driver bundles too soon, however, may cause unnecessary installs and associated delays when driver bundles are needed again.
If a device manager implements driver bundle reclamation, the specified matching algorithm is not guaranteed to terminate unless the device manager takes reclamation into account.
For example, assume that a new Device service triggers the attachment algorithm. A driver bundle recommended by a Driver Locator service is loaded. It does not match, so the Device service remains idle. The device manager is eager to reclaim space, and unloads the driver bundle. The disappearance of the Driver service causes the device manager to reattach idle devices. Because it has not kept a record of its previous activities, it tries to reattach the same device, which closes the loop.
On systems where the device manager implements driver bundle reclamation, all refining drivers should be loaded through Driver Locator services. This recommendation is intended to prevent the device manager from erroneously uninstalling pre-installed driver bundles that cannot later be reinstalled when needed.
The device manager can be updated or restarted. It cannot, however, rely on previously stored information to determine which driver bundles were pre-installed and which were dynamically installed and thus are eligible for removal. The device manager may persistently store cachable information for optimization, but must be able to cold start without any persistent information and still be able to manage an existing connection state, satisfying all of the requirements in this specification.
It is not straightforward to determine whether a driver bundle is
being updated when the UNREGISTER
event for a Driver
service is received. In order to facilitate this distinction, the device
manager should wait for a period of time after the unregistration for
one of the following events to occur:
-
A
BundleEvent.UNINSTALLED
event for the driver bundle. -
A
ServiceEvent.REGISTERED
event for another Driver service registered by the driver bundle.
If the driver bundle is uninstalled, or if neither of the above events are received within the allotted time period, the driver is assumed to be inactive. The appropriate waiting period is implementation-dependent and will vary for different installations. As a general rule, this period should be long enough to allow a driver to be stopped, updated, and restarted under normal conditions, and short enough not to cause unnecessary delays in reattaching devices. The actual time should be configurable.
The device attachment algorithm may discover new driver bundles that were installed outside its direct control, which requires executing the device attachment algorithm recursively. However, in this case, the appearance of the new driver bundles should be queued until completion of the current device attachment algorithm.
Only one device attachment algorithm may be in progress at any moment in time.
The following example sequence illustrates this process when a Driver service is registered:
-
Collect the set of all idle devices.
-
Apply the device attachment algorithm to each device in the set.
-
If no Driver services were registered during the execution of the device attachment algorithm, processing terminates.
-
Otherwise, restart this process.
The device manager is the only privileged bundle in the Device
Access specification and requires the
org.osgi.framework.AdminPermission
with the
LIFECYCLE
action to install and uninstall driver
bundles.
The device manager itself should be free from any knowledge of policies and should not actively set bundle permissions. Rather, if permissions must be set, it is up to the Management Agent to listen to synchronous bundle events and set the appropriate permissions.
Driver Locator services can trigger the download of any bundle,
because they deliver the content of a bundle to the privileged device
manager and could potentially insert a Trojan horse into the environment.
Therefore, Driver Locator bundles need the
ServicePermission[DriverLocator, REGISTER]
to register Driver
Locator services, and the operator should exercise prudence in assigning
this ServicePermission
.
Bundles with Driver Selector services only require
ServicePermission[DriverSelector, REGISTER]
to register the
DriverSelector
service. The Driver Selector service can play
a crucial role in the selection of a suitable Driver service, but it has
no means to define a specific bundle itself.
Device Access Package Version 1.1.
Bundles wishing to use this package must list the package in the Import-Package header of the bundle's manifest. This package has two types of users: the consumers that use the API in this package and the providers that implement the API in this package.
Example import for consumers using the API in this package:
Import-Package: org.osgi.service.device; version="[1.1,2.0)"
Example import for providers implementing the API in this package:
Import-Package: org.osgi.service.device; version="[1.1,1.2)"
-
Constants
- This interface defines standard names for property keys associated with Device and Driver services. -
Device
- Interface for identifying device services. -
Driver
- ADriver
service object must be registered by each Driver bundle wishing to attach to Device services provided by other drivers. -
DriverLocator
- A Driver Locator service can find and load device driver bundles given a property set. -
DriverSelector
- When the device manager detects a new Device service, it calls all registered Driver services to determine if anyone matches the Device service. -
Match
- Instances ofMatch
are used in the DriverSelector.select(ServiceReference, Match[]) method to identify Driver services matching a Device service.
This interface defines standard names for property keys associated with Device and Driver services.
The values associated with these keys are of type java.lang.String
,
unless otherwise stated.
1.1
Consumers of this API must not implement this interface
Property (named "DEVICE_CATEGORY") containing a human readable
description of the device categories implemented by a device. This
property is of type String[]
Services registered with this property will be treated as devices and discovered by the device manager
Property (named "DEVICE_DESCRIPTION") containing a human readable string describing the actual hardware device.
Property (named "DEVICE_SERIAL") specifying a device's serial number.
Property (named "DRIVER_ID") identifying a driver.
A DRIVER_ID
should start with the reversed domain name of the
company that implemented the driver (e.g., com.acme
), and must
meet the following requirements:
-
It must be independent of the location from where it is obtained.
-
It must be independent of the DriverLocator service that downloaded it.
-
It must be unique.
-
It must be different for different revisions of the same driver.
This property is mandatory, i.e., every Driver
service must be
registered with it.
Interface for identifying device services.
A service must implement this interface or use the
Constants.DEVICE_CATEGORY registration property to indicate that it
is a device. Any services implementing this interface or registered with the
DEVICE_CATEGORY
property will be discovered by the device manager.
Device services implementing this interface give the device manager the
opportunity to indicate to the device that no drivers were found that could
(further) refine it. In this case, the device manager calls the
noDriverFound() method on the Device
object.
Specialized device implementations will extend this interface by adding methods appropriate to their device category to it.
Thread-safe
Return value from Driver.match(ServiceReference) indicating that the driver cannot refine the device presented to it by the device manager. The value is zero.
A Driver
service object must be registered by each Driver bundle
wishing to attach to Device services provided by other drivers. For each
newly discovered Device object, the device manager enters a bidding
phase. The Driver
object whose match(ServiceReference)
method bids the highest for a particular Device
object will be
instructed by the device manager to attach to the Device
object.
Thread-safe
the ServiceReference
object of the device to
attach to
Attaches this Driver service to the Device service represented by the
given ServiceReference
object.
A return value of null
indicates that this Driver service has
successfully attached to the given Device service. If this Driver service
is unable to attach to the given Device service, but knows of a more
suitable Driver service, it must return the DRIVER_ID
of that
Driver service. This allows for the implementation of referring drivers
whose only purpose is to refer to other drivers capable of handling a
given Device service.
After having attached to the Device service, this driver may register the underlying device as a new service exposing driver-specific functionality.
This method is called by the device manager.
null
if this Driver service has successfully attached to
the given Device service, or the DRIVER_ID
of a more
suitable driver
Exception
– if the driver cannot attach to the given
device and does not know of a more suitable driver
the ServiceReference
object of the device to
match
Checks whether this Driver service can be attached to the Device service. The Device service is represented by the given ServiceReference and returns a value indicating how well this driver can support the given Device service, or Device.MATCH_NONE if it cannot support the given Device service at all.
The return value must be one of the possible match values defined in the
device category definition for the given Device service, or
Device.MATCH_NONE
if the category of the Device service is not
recognized.
In order to make its decision, this Driver service may examine the properties associated with the given Device service, or may get the referenced service object (representing the actual physical device) to talk to it, as long as it ungets the service and returns the physical device to a normal state before this method returns.
A Driver service must always return the same match code whenever it is presented with the same Device service.
The match function is called by the device manager during the matching process.
value indicating how well this driver can support the given
Device service, or Device.MATCH_NONE
if it cannot support
the Device service at all
Exception
– if this Driver service cannot examine the
Device service
A Driver Locator service can find and load device driver bundles given a
property set. Each driver is represented by a unique DRIVER_ID
.
Driver Locator services provide the mechanism for dynamically downloading new device driver bundles into an OSGi environment. They are supplied by providers and encapsulate all provider-specific details related to the location and acquisition of driver bundles.
Thread-safe
the properties of the device for which a driver is sought
Returns an array of DRIVER_ID
strings of drivers capable of
attaching to a device with the given properties.
The property keys in the specified Dictionary
objects are
case-insensitive.
array of driver DRIVER_ID
strings of drivers capable of
attaching to a Device service with the given properties, or
null
if this Driver Locator service does not know of any
such drivers
the DRIVER_ID
of the driver that needs to be installed.
Get an InputStream
from which the driver bundle providing a
driver with the giving DRIVER_ID
can be installed.
An InputStream
object from which the driver bundle can be
installed or null
if the driver with the given ID cannot
be located
IOException
– the input stream for the bundle cannot be
created
When the device manager detects a new Device service, it calls all registered
Driver services to determine if anyone matches the Device service. If at
least one Driver service matches, the device manager must choose one. If
there is a Driver Selector service registered with the Framework, the device
manager will ask it to make the selection. If there is no Driver Selector
service, or if it returns an invalid result, or throws an Exception
,
the device manager uses the default selection strategy.
1.1
Thread-safe
Return value from DriverSelector.select
, if no Driver service
should be attached to the Device service. The value is -1.
the ServiceReference
object of the Device
service.
the array of all non-zero matches.
Select one of the matching Driver services. The device manager calls this
method if there is at least one driver bidding for a device. Only Driver
services that have responded with nonzero (not Device.MATCH_NONE)
match values will be included in the list.
index into the array of Match
objects, or
SELECT_NONE
if no Driver service should be attached
Instances of Match
are used in the
DriverSelector.select(ServiceReference, Match[]) method to identify
Driver services matching a Device service.
1.1
Thread-safe
Consumers of this API must not implement this interface
Return the reference to a Driver service.
ServiceReference
object to a Driver service.
[1]Java Communications APIhttps://www.oracle.com/java/technologies/java-communications-api.html
[2]USB Specificationhttps://www.usb.org
[3]Universal Plug and Playhttps://openconnectivity.org/developer/specifications/upnp-resources/upnp/
[4]Jini, Service Discovery and Usagehttps://en.wikipedia.org/wiki/Jini