Application Lifecycle Control APIs

There are two APIs in an MHP receiver that deal with actions that can affect the execution state of another MHP application, either by causing an application to start running, or by killing an already running application. As we will see later, the service selection API is one of these, but this is not its main purpose and application lifecycle control is really a small part of what it does.

If you really want detailed control over which applications run and don't run in the current service, then the application discovery and launching API (contained in the org.dvb.application package) is for you. This API is organized around the AppsDatabase class, which maintains a database of all applications currently being signalled on the current service. An application can use this database to get information about other applications, start them and possibly stop them, and monitor the status of other applications and the contents of the database.

The philosophy behind the design of the application listing and launching that there are two types of operation that are likely to be carried out. Some applications will only want (or only be allowed) to get information about other applications that are being signalled. This is all encapsulated in the AppAttributes class, which provides access to the information contained in the AIT.

Other applications will want to actually manipulate other applications. This functionality is provided by the AppProxy class and its subclasses, which has methods that enable the controlling application to change the state of another application. Both of these classes are described in more detail below.

By separating these functions into two different objects, the application manager can check the security of requests for more easily - anything can access information about other applications, so no security checking is necessary in the AppAttributes class. On the other hand, any request for an AppProxy object will cause the permissions of the requesting application to be checked, in order to make sure that it has permission to control applications.

The AppsDatabase is a singleton object, and applications can get a reference to it by calling the static AppsDatabase.getAppsDatabase() method.

Applications can request information from the applications database using the AppsDatabase.getAppAttributes() method. There are two versions of this, one taking an application ID (actually an instance of the AppID class that represents an application ID), and one taking a AppsDatabaseFilter. This allows the application to select only the applications that match a set of conditions. AppsDatabaseFilter and its subclasses have an accept() method that takes an application identifier as an argument. The AppsDatabaseFilter implementation checks the application with this identifier against the criteria that are hard-wired into that particular filter. If the specified application matches these criteria, then the method returns true - otherwise, it returns false. This allows a pluggable mechanism for adding new types of filter in future versions of MHP.

The only filters currently defined in MHP is the CurrentServiceFilter that selects only those applications signalled as part of the current service and the RunningApplicationsFilter that selects only those applications that are currently executing, but others may be defined later and specifications that use MHP have defined some extra filters. Applications may not define their own filters - any filters other than the CurrentServiceFilter and the RunningApplicationsFilter will return an empty list of application in an MHP implementation.

Controlling applications

If an application actually wants to manipulate another application, it can call the AppsDatabase.getAppProxy() method. This takes an application ID as a parameter, and returns an AppProxy object representing that application (if the requesting application actually has permission to manipulate it).

Now that we've seen what the AppsDatabase can actually do, here is its complete interface:

public interface AppsDatabase {
  public static AppsDatabase getAppsDatabase();
	  
  public int size();

  public Enumeration gettAppIDs(
    AppsDatabaseFilter filter);

  public Enumeration getAppAttributes(
    AppsDatabaseFilter filter);
	
  public AppAttributes getAppAttributes(AppID key);
  public AppProxy getAppProxy(AppID key);
  
  public void addListener(
    AppsDatabaseEventListener listener);
	
  public void removeListener(
    AppsDatabaseEventListener listener)
}

The contents of the database can change with time, depending on actions by the broadcaster or the user. For instance, the broadcaster may choose to stop signalling one application, while signalling another in its place (e.g. when one TV show finishes and another starts). Alternatively, the user may switch to a different channel, which is signalling a completely new set of applications. An application can get notification of these changes by listening to AppsDatabaseEvents. These allow an application to be notified about changes to the contents of the applications database. Applications can also register to receive events when the contents of the AIT change using the addListener() method, and unregister using the removeListener() method. An AppsDatabaseEvent gets generated whenever an application is added or removed from the AIT, when an application is changed, or when the whole AIT gets changed (e.g. when the user changes channel).

The AppAttributes class

The AppAttributes class, as we saw earlier, maintains all the information that the applications database holds about a given application. As such, it's not that complex and I won't describe it in too much detail. AppAttributes is an interface that provides get methods for all the attributes listed in the AIT for any application, ranging from the name and the type of the application (DVB-J or DVB-HTML) to the priority that it's been given by the broadcaster.

public interface AppAttributes{

  public final int DVB_J_application; 
  public final int DVB_HTML_application;

  public int getType();
  public String getName();
  public String getName(String iso639Code) 
    throws LanguageNotAvailableException;
  public String[][] getNames();

  public String[] getProfiles();
  public int[] getVersions(String profile) 
    throws IllegalProfileParameterException;

  public boolean getIsServiceBound();
  public boolean isStartable();
  public AppID getIdentifier ();
  public AppIcon getAppIcon ();
  public int getPriority();
  public org.davic.net.Locator getServiceLocator();

  public Object getProperty (String index);
}

This class is relatively simple, and so we won't cover it in too much detail here.

The AppProxy class

The AppProxy class is also relatively simple. As we can see from the interface definition below, it provides a set of methods to control the state of the application:

public interface AppProxy {
  public int getState();
  public void start();
  public void stop(boolean forced);
  public void pause();
  public void addAppStateChangeEventListener
    (AppStateChangeEventListener listener);
}

The only non-obvious method here is the addAppStateChangeEventListener() method. This allows an application to listen to events (specifically, AppStateChangeEvent and its subclasses) that notify it of changes in the state of another application. For instance, if one application needs to know when another application terminates, this mechanism lets the first application receive notification of this.

You might have noticed that both the AppAttributes class and AppProxy class are actually defined as interfaces. There was much argument during the design of this API as to whether separate classes were needed, or whether they should be merged into one. In the end, the decision was that for security reasons, separate interfaces were better. By defining these as interfaces, however, an MHP or OCAP receiver may choose to implement both interfaces in a single class. This is a compromise, but doesn't significantly affect security. Application should not assume that these two interfaces will be implemented by the same class.

Given that we've now seen all the important elements of the application listing and launching API, let's take a look at an example:

// This example starts all applications that are  
// signalled on the current service.

// The first thing that we have to do is get a  
// reference to the applications database.  Since 
// this is a singleton object, we use the 
// getDatabase() static method.
AppsDatabase theDatabase;
theDatabase = AppsDatabase.getDatabase();

// Now that we've got a reference to the database, 
// we can find what applications are being 
// signalled on the current service by using a 
// CurrentServiceFilter to tell us what is being 
// signalled on this service.
AppsDatabaseFilter filter;
filter = new CurrentServiceFilter();

Enumeration attributes;
attributes = theDatabase.getAppAttributes(filter);


// Since the version of the method that uses a 
// filter returns an Enumeration to us, we need 
// to loop through the returned elements to find 
// one that's interesting to us. 
while(attributes.hasMoreElements()) {


  // First, get the attributes of the application 
  // from the enumeration
  AppAttributes info;
  info  = (AppAttributes)attributes.nextElement();
  
  // The attributes contain the application ID 
  // which we can get by using the getIdentifier() 
  // method on the AppAttributes object.  
  AppID id = info.getIdentifier()
  
  // We then use this to get an AppProxy object 
  // that represents the application by using 
  // the getAppProxy() method on the AppsDatabase.
  AppProxy proxy;


  proxy  = (AppProxy)theDatabase.getAppProxy(id);

  // Now that we've got a reference to a proxy for 
  // the application, we can start it.
  proxy.start();
}

One thing that you'll notice if you read the specification is that the application 'requests' that operations get carried out on other applications. The main reason behind this is to allow the application manager running in the receiver to refuse to carry out a request. This could be either for security or for resource reasons, but it's aimed at improving the reliability of the receiver.

OCAP extends the application listing and launching API to give some more control over the applications that are running. The OCAP tutorial includes more information about this.