This specification describes how to enable a management agent to control the relative starting and stopping order of bundles in an OSGi framework.
The management agent can set the start levels for bundles and set the active start level of the Framework, which will start and stop the appropriate bundles. Only bundles that have a start level less or equal to this active start level must be active. The purpose of the Start Level API is to allow the management agent to control, in detail, what bundles will be started and stopped and when this occurs.
-
Ordering - A management agent should be able to order the startup and shutdown sequences of bundles.
-
Levels - The management agent should support a virtually unlimited number of levels.
-
Bundle Start Level - The adapter on a bundle that is used by a management agent to order the startup and shutdown sequences of bundles.
-
Framework Start Level - The adapter that is used to set the framework start levels.
-
Management Agent - A bundle that is provided by the Operator to implement an Operator specific policy.
-
Framework Event - See Events.
-
Framework Listener - See Listeners.
The Start Level API provides the following functions:
-
Controls the beginning start level of the OSGi Framework.
-
Is used to modify the active start level of the Framework.
-
Can be used to assign a specific start level to a bundle.
-
Can set the initial start level for newly installed bundles.
Defining the order in which bundles are started and stopped is useful for the following:
-
Safe mode - The management agent can implement a safe mode. In this mode, only fully trusted bundles are started. Safe mode might be necessary when a bundle causes a failure at startup that disrupts normal operation and prevents correction of the problem.
-
Splash screen - If the total startup time is long, it might be desirable to show a splash screen during initialization. This improves the user's perception of the boot time of the device. The startup ordering can ensure that the right bundle is started first.
-
Handling erratic bundles - Problems can occur because bundles require services to be available when they are activated (this is a programming error). By controlling the start order, the management agent can prevent these problems.
-
High priority bundles - Certain tasks such as metering need to run as quickly as possible and cannot have a long startup delay. These bundles can be started first.
Start levels are not intended to be used for ensuring that dependencies are met when a bundle is started. Any of the life cycle actions (install/update/uninstall) can cause a dependency to become unavailable regardless of start levels.
This specification provides two adaptations of a
Bundle
object to a:
-
BundleStartLevel - Used to get and set the start level on a specific bundle.
-
FrameworkStartLevel - Used to get and control the framework start level. This adaptation must return null for any other bundle than the system bundle (bundle 0).
The adaptation provides the following methods:
-
setStartLevel(int) - Sets the current start level for the adapted bundle.
-
getStartLevel() - Gets the current start level for the adapted bundle.
-
isActivationPolicyUsed() - Answer if the activation policy is used.
-
isPersistentlyStarted() - Answer if this bundle as persistently started.
The Framework Start Level adaptation is only possible for the
system bundle. Other bundles must return null
for this
adaptation. The adaptation provides the following methods:
-
getInitialBundleStartLevel() - Return the start level to assign for newly installed bundles.
-
setInitialBundleStartLevel(int) - Set the initial start level.
-
getStartLevel() - Get the current framework start level.
-
setStartLevel(int,FrameworkListener...) - Set the current framework start level and provide an optional callback Framework Listener. This listener is called back when the set start level has been reached.
A start level is defined as a non-negative
integer. A start level of 0 (zero) is the state in which the Framework has
either not been launched or has completed shutdown (these two states are
considered equivalent). In this state, no bundles are running.
Progressively higher integral values represent progressively higher start
levels. For example, 2 is a higher start level than 1. The Framework must
support all positive int
values
(Integer.MAX_VALUE
) for start levels.
The Framework has an active start level that is
used to decide which bundles can be started. All bundles must be assigned
a bundle start level. This is the minimum start level
to start a bundle. The bundle start level can be set with the setStartLevel(int) method on the BundleStartLevel
object. When a bundle is installed, it is initially assigned the bundle
start level returned by getInitialBundleStartLevel() on a FrameworkStartLevel
object. The
initial bundle start level to be used when bundles are installed can be
set with setInitialBundleStartLevel(int).
In addition, a bundle can be persistently marked as
started or stopped with the
Bundle
start
and stop
methods. A
bundle cannot run unless it is marked started, regardless of the bundle's
start level.
A management agent can influence the active start level with the setStartLevel(int) method. The Framework must then increase or decrease the active start level by 1 until the requested start level is reached. The process of starting or stopping bundles, which is initiated by the setStartLevel(int) method, must take place asynchronously.
This means that the active start level (the one that is active at a certain moment in time) must be changed to a new start level, called the requested start level. The active and requested levels differ during a certain period when the Framework starts and stops the appropriate bundles. Moving from the active start level to the requested start level must take place in increments of one (1).
If the requested start level is higher than the active start level, the Framework must increase the start level by one and then start all bundles that meet the following criteria:
-
Bundles that are persistently marked started, and
-
Bundles that have a bundle start level equal to the new active start level.
The Framework continues increasing the active start level and starting the appropriate bundles until it has started all bundles with a bundle start level that equals the requested start level.
The Framework must not increase to the next active start level
until all started bundles have returned from their
BundleActivator.start
method normally or with an exception.
A FrameworkEvent.ERROR
must be broadcast when the
BundleActivator.start
method throws an exception.
If the requested start level is lower than the active start level,
the Framework must stop all bundles that have a bundle start level that
is equal to the active start level. The Framework must then decrease the
active start level by 1. If the active start level is still higher than
the requested start level, it should continue stopping the appropriate
bundles and decreasing the active start level until the requested start
level is reached. A FrameworkEvent.ERROR
must be broadcast
when the BundleActivator.stop
method throws an
exception.
If the requested start level is the active start level, the Framework will not start or stop any bundles.
When the requested start level is reached and all bundles satisfy
the condition that their bundle start level <= active start level in
order to be started, then the
FrameworkEvent.STARTLEVEL_CHANGED
event must be sent to all
registered FrameworkListener
objects. If the requested
start level and active start level are equal, then this event may arrive
before the setStartLevel
method has returned.
It must therefore always be true that:
-
A bundle is started, or will be started soon, if the start level is less or equal to the active start level.
-
A bundle is stopped, or will be stopped soon, when it has a start level more than the active start level.
These steps are depicted in the flow chart in Figure 9.2.
If the Framework is currently involved in changing the active start level, it must first reach the previously requested start level before it is allowed to continue with a newly requested start level. For example, assume the active start level is 5 and the Framework is requested to transition to start level 3. Before start level 3 is reached, another request is made to transition to start level 7. In this case, the OSGi Framework must first complete the transition to start level 3 before it transitions to start level 7.
At startup, the Framework must have an active start level of zero. It must then move the active start level to the beginning start level. The beginning start level is specified with an argument when starting the Framework or through some other means, which is left undefined here. If no beginning start level is given, the Framework must assume a beginning start level of one (1).
The Framework must launch and then set the requested start level
to the beginning start level. It must then follow the procedure
described in Changing the Active Start Level to make the active start level
equal the beginning start level, with the exception of the
FrameworkEvent.START_LEVEL_CHANGED
event broadcast. During
launching, the Framework must broadcast a
FrameworkEvent.STARTED
event when the beginning start level
is reached.
When the Framework shuts down, the requested start level must be set to zero. The Framework must then follow the process described in Changing the Active Start Level to make the active start level equal to zero.
Bundles are assigned an initial start level when they are installed. The default value for the initial start level is set to one, but can be changed with the setInitialBundleStartLevel(int) method on the FrameworkStartLevel object. A bundle's start level will not change when the setInitialBundleStartLevel(int) method later modifies the default initial start level.
Once installed, the start level of a bundle can be changed with setStartLevel(int). When a bundle's start level is changed and the bundle is marked persistently to be started, then the OSGi Framework must compare the new bundle start level to the active start level. For example, assume that the active start level is 5 and a bundle with start level 5 is started. If the bundle's start level subsequently is changed to 6 then this bundle must be stopped by the OSGi Framework but it must still be marked persistently to be started.
If a bundle is started by calling the
Bundle.start
method, then the OSGi Framework must mark the
bundle as persistently started. The OSGi Framework must not actually
start a bundle when the active start level is less than the bundle's
start level. In that case, the state must not change.
If the BundleActivator.start
or stop
method throws an Exception
, then the handling of this
Exception
is different depending who invoked the
start
or stop
method.
If the bundle is started/stopped due to a change in the active
start level or the bundle's start level, then the Exception
must be wrapped in a BundleException
and broadcast as a
FrameworkEvent.ERROR
event. Otherwise, a new
BundleException
must be created containing the exception
and this BundleException
is then thrown to the
caller.
The Start Level API allows a management agent to implement many different startup schemes. The following sections show some examples.
A management agent can implement a safe mode
in which it runs trusted bundles at level 1 and runs itself on level 2.
When the management agent gets control, it constructs a list of all
applications to be started. This list can be constructed from
BundleContext.getBundles()
. The management agent checks
each bundle to determine if it is not started but is marked to be
started persistently by calling the isPersistentlyStarted() method of the Start Level API.
Before it starts each bundle, the management agent persistently records the bundle to be started and then starts the bundle. This continues until all bundles are started. When all bundles are successfully started, the management agent persistently records that all bundles started without problems.
If the OSGi framework is restarted, the management agent should inspect the persistently recorded information. If the persistently recorded information indicates a bundle failure, the management agent should try to restart the system without that application bundle since that bundle failed. Alternatively, it could contact its Remote Manager and ask for assistance.
A splash screen is a popup containing startup information about an application. The popup provides feedback to the end user indicating that the system is still initializing. The Start Level API can be used by a bundle to pop-up a splash screen before any other bundle is started, and remove it once all bundles have been started. The splash-screen bundle would start at start level 1 and all other bundles would start at start level 2 or higher.
class SplashScreen implements
BundleActivator, FrameworkListener {
Screen screen;
public void start(BundleContext context) {
context.addFrameworkListener( this );
screen = createSplash();
screen.open();
}
public void stop(BundleContext context) {
screen.close();
}
public void frameworkEvent( FrameworkEvent event ) {
if ( event.getType() == FrameworkEvent.STARTED )
screen.close();
}
Screen createSplash() { ... }
}
The Start Level API requires Adapt Permission with action
ADAPT
for the following type:
-
org.osgi.framework.startlevel.BundleStartLevel
-
org.osgi.framework.startlevel.FrameworkStartLevel
The Start Level methods that mutate state require an additional Admin Permission with the action:
-
EXECUTE
- For bundles that must be able to modify a bundle's start level -
STARTLEVEL
- For modifying the Framework's active start level.