Managing Scarce Resources

A digital TV receiver is usually a fairly low-end device, with limited resources available to applications and a requirement that those resources be shared effectively between concurrent applications, and between applications and the receiver middleware. This makes resource management a major issue for receiver manufacturers and application developers, and it's something that developers will encounter fairly frequently in the MHP APIs.

Many of the APIs in MHP are based on the DAVIC resource notification API contained in the org.davic.resources package. Note the choice of words there - this is not a resource management API. Resource management is carried out purely by the receiver middleware as it sees fit, and an application has very little say in whether it gets to keep a scarce resource that is requested by another application.

The resource notification API consists of three main classes, and is not intended to be a complete API in its own right. Instead, it's designed to be used by other APIs in a way that best suits them, although it does define some common concepts. To make this clearer in the following description, any references to a 'using' API mean an MHP API that implements the resource notification API as part of its own specification.

As you can see from looking at the API specification, it's based around a client-server model, with one minor change for security and resilience. First, let's deal with the standard aspects. The ResourceServer interface is implemented by a class in the using API. This is responsible for handling requests for scarce resources, and for managing how those scarce resources are allocated. These could be either software (e.g. a software section filter) or hardware resources (e.g. a modem or MPEG decoder) - the API makes no distinction.

public interface ResourceServer
{
  public abstract void addResourceStatusEventListener(
    ResourceStatusListener listener);
  public void removeResourceStatusEventListener(
    ResourceStatusListener listener);
}

You'll notice that the ResourceServer interface defines no methods for actually requesting or releasing exclusive access to a scarce resource. This is a deliberate design decision, and it allows the using API to provide these functions in a way that's most natural to it. The way that a resource is reserved in a telephony API will very likely be different from the way a resource is reserved in a section filter API, for instance.

The only methods that this interface defines allows an application to register as a listener for events indicating the change in status of a resource. APIs which use this interface can provide events to show how specific resources change their status.

The ResourceClient interface is, not surprisingly, the client side of the API. This interface is implemented by a class in the MHP application and is responsible for communicating with the middleware about the application's use of the resource. The receiver middleware uses this interface to notify an application that a resource is needed by something else in the receiver, and that it should give it up. This may help to clarify why this is called a resource notification API.

public interface ResourceClient
{
  public abstract boolean requestRelease(
    ResourceProxy proxy,
    Object requestData);

  public abstract void release(
    ResourceProxy proxy);

  public abstract void notifyRelease(
    ResourceProxy proxy);
}

As you can see from the interface definition above, the ResourceClient interface contains three methods. These methods are all used to inform the application, with varying degrees of politeness, that a resource is needed by another application. The RequestRelease() method is the most polite of these, in effect requesting that an application gives up a scarce resource so that it can be used by something else in the receiver. The application is perfectly within its rights to refuse to release the resource (by returning the value false), either because it is currently using it for something critical or simply because it has decided not to release it.

The release() method tells the client that it must give up the scarce resource. In this case, the client has no choice - all it can do is give up the resource so that whatever else needs to use it can do so. When this method returns, the receiver will assume that the resource is available for other parts of the system to use.

This assumes that an application is going to be cooperative, of course. In the case above, the application could simply not return from the release() and it would try to keep access to the resource  Life is not that simple for malicious application, however. If the release() method doesn't return within an appropriate timeout period, the receiver can assume that the application is crashed or malicious, and reclaim the resource anyway. If this happens, the receiver will call the notifyReleased() method, which tells the client that the resource has been taken away from it and that it should clean up as best it can. This is a potentially brutal operation, and so it is only saved for those cases where the application really is not cooperating.

A class implementing the ResourceProxy interface sits between the client and the actual resource. This serves an important security function (which we will see below), but there are several other reasons for its existence.

The first purpose of the resource proxy is to provide an application with a simple way to set up the resource. If you have a fairly complex resource that needs a lot of setting up, such as a modem or MPEG section filter, you don't want to have to explicitly set all of its parameters every time that you request it. The design of the resource notification API lets you set parameters on the resource proxy, which can then be applied to the underlying resource with a single method call. Since the resource proxy exists across multiple request/release cycles, this can make life significantly easier.

A second reason for having the resource proxy is that in most using APIs, instances are created by the client, and have no link to a real resource until they are attached to it.  The application can create multiple resource proxies, each with different parameter settings, and then choose to use only one of these when it really needs to access the resource.

The final and possibly most important reason is security. By using the resource proxy as an indirection mechanism, the application never has a direct reference to the Java object that actually controls the scarce resource. This makes it much, much easier for the receiver to take a resource away from a misbehaving application. If the application has a direct link to the object controlling the resource, there is no way that it can be forced to break that link. However, consider the situation when we have the resource proxy acting as an indirection mechanism. In this case, the following steps happen when the application requests access to a resource:

The application creates a ResourceProxy instance of the appropriate type.

The application creates a ResourceProxy instance of the appropriate type.

The application requests that the resource server gives this resource proxy access to the resource.

The application requests that the resource server gives this resource proxy access to the underlying resource.

The resource server enables the resource proxy via a private method.

The resource server enables the resource proxy via a private method.

The application can now use the resource.

The application can now use the resource.

All communication between the application and the underlying resource goes via the resource proxy.

All communication between the application and the underlying resource goes via the resource proxy.

  1. First, the application creates an instance of the appropriate ResourceProxy object for that API and sets any parameters that need setting. In this case, we show that being done by the resource client, but any class in the application could do this in practise.
  2. Next, the resource client calls the appropriate method on the ResourceServer implementation for the API and requests access to the resource, passing the ResourceProxy object to it as a parameter.
  3. If access is granted, the resource server calls a private method on the resource proxy to tell the proxy that it is valid.
  4. This establishes a link between the resource proxy and the resource itself. Until this point, the resource proxy has no connection to the underlying resource. There are two reasons for this. First, this is an added security feature. Second, the resource proxy may be connected to a different underlying resource, depending on how other applications are using the resource and on which resource management algorithm is used by the middleware.
  5. After this, the resource is available to the application. The application can call methods on the resource proxy to manipulate the resource, and the resource proxy forwards these requests to the real resource. This means that the application never has a direct connection to the underlying resource.

The process of releasing a resource is more or less the reverse of this:

The application tells the resource server that it has finished with the resource.

The application tells the resource server that it has finished with the resource.

The resource server disables the resource proxy.

The resource server disables the resource proxy.

The resource proxy can no longer be used to access the underlying resource, even if the application doesn't co-operate.

The resource proxy can no longer be used to access the underlying resource, even if the application doesn't co-operate.

  1. When the resource client wishes to give up the resource, it calls the appropriate method on the resource server (which is defined by the using API) to release the resource, passing the resource proxy as a parameter.
  2. As when we validate the resource, the resource server then calls a private method on the resource proxy, which may or may not be the same as the method used to validate the resource.
  3. This time, the resource server tells the resource proxy that it is no longer valid and should not forward any more requests to the underlying resource. As a result of this, the resource proxy should destroy any references to the underlying resource.
  4. Finally, the resource server updates its internal table of the state of the resources and marks the resource that was being used as free again. After this, the resource is free to be used by another application (or even by the same application)

So far, none of this is very new or complex. Now let's look at what happens when access to a resource is revoked. For this example, we'll assume that the application is malicious and refuses to give up control of the resource:

  1. The resource server calls the release() method on the resource client to tell the application to release its resource.
  2. The resource client fails to return from this call, in an attempt to keep access to the resource.
  3. After a suitable timeout period, a watchdog timer in the middleware notices that the call has not returned and notifies the resource server.
  4. The resource server calls a private method on the resource proxy that has access to the scarce resource, telling it that it is no longer valid.
  5. The resource proxy breaks the link between it and the scarce resource, and resets its internal state to take account of this.
  6. The receiver calls the notifyReleased() method on the class in the application that implements the ResourceClient interface. This informs the application that it no longer has access to the resource and that it should do any housekeeping necessary.
  7. Any further attempts by the application to access the resource have no effect on the scarce resource.

In this case, there is absolutely nothing that the application can do to interfere with the communication between the middleware and the resource proxy. Since the resource proxy is implemented by the receiver manufacturer, and can thus be trusted by the rest of the middleware, the resource proxy can be guaranteed to always give up the resource when it is asked. Similarly, since the methods used to validate or invalidate the resource proxy are not defined by the resource notification API (and are probably declared as private), a malicious application can do nothing to spoof a message from the resource server granting access to the resource.

This may seem a little extreme, but it's the only way that reliability and paranoia concerns can be satisfied.

Using the resource notification API

In those APIs that use the resource notification API, resources typically accessed as follows:

  1. The application creates an instance of a ResourceProxy object
  2. The application sets some parameters on the ResourceProxy that will be passed to the real resource when it is acquired
  3. The application calls an API-dependent method on the ResourceServer for the API (usually passing the ResourceProxy it has created as a parameter) in order to reserve the real resource.
  4. The application uses the resource as it wants to.
  5. When it has finished, the application calls an API-dependent method on the ResourceServer object to release the resource for use by another application.

As you can see, there's nothing too complex about this. Although it sounds complex, in practise it's not that difficult to actually use. Knowing the philosophy behind this approach helps a lot - as one of the designers of this API, I've had to explain the reasoning behind it many times in the past, and every time I've done so it's answered the many questions that people usually have about this API.

There are some things that an application author should consider when they are writing an application. As an application writer, you must be aware when you are using a scarce resource - your application may be stopping others from using the resource, and if another application with a higher priority wants the resource that you are using, your access to it may be revoked at any time. For these reasons, an application should only reserve scarce resources when it actually needs to use them, and it should also be prepared to lose access to its resources at any time so that it can recover gracefully when this happens. Graceful handling of conditions like these are the type of consideration that makes for a really reliable MHP application.

While your application doesn't have to implement any sensible precautions in the methods provided by the ResourceClient interface, it's obviously much better. Failing to take account of the way that resources are used by your application (and especially those resources that are reclaimed by the receiver middleware) will lead to your application being more unreliable and error-prone.