Just like every other digital TV receiver, OCAP receivers are usually fairly inexpensive platforms that have limited hardware resources. Another similarity with other types of digital TV receiver is that they have to be extremely reliable and work in a predictable way – taking someone’s TV away because your receiver crashes tends to annoy them. Taking these two issues together, it’s important that an OCAP receiver can manage the scarce resources that it has in an effective way. Applications must be able to share resources, and most importantly must be able to keep running when a resource they need isn’t available.
Like MHP, resource management in OCAP is based on the DAVIC resource notification API from the org.davic.resources
package. There are some differences, however, due to differences in business models between cable operators in the US and in Europe. For this reason, OCAP also adds the org.ocap.resources
package.
Early versions of the OCAP specification defined a full resource management API, but that was dropped in later versions of the standard in favour of an approach that was more compatible with MHP and GEM. Now, the biggest difference is that the OCAP monitor application can decide how to resolve conflicts between applications over resource allocation. Before we discuss that, however, let’s recap how resources work in MHP and OCAP. If you’ve already read the MHP tutorial on resource management, you may want to skip to the end of this tutorial where we discuss the OCAP-specific elements.
The DAVIC resource notification API is 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.
Resource Clients
When several applications are trying to share resources, sometimes the status of those resources will change. In this situation, the middleware needs to be able to tell the application using a resource about these changes. To do this, any application that wants to use a scarce resource must implement the ResourceClient
interface, which acts as the client part of our client-server model. This interface has the following methods:
public interface ResourceClient { public abstract boolean requestRelease( ResourceProxy proxy, Object requestData); public abstract void release(ResourceProxy proxy); public abstract void notifyRelease( ResourceProxy proxy); }
Sometimes, the middleware will need to take away a resource from one application and give it to another. In this case, the resource manager will ask an application to give up its resource. There are three methods that are related to this. requestRelease()
is called by the resource manager to check whether an application is willing to give up its resource. If the application is willing to do so, it should release the resource and return TRUE
. If an application needs that resource, or simply doesn’t want to give it up then it can return FALSE
.
The resource manager may choose to ask a little more forcefully, in which case it calls the release()
method. This method should make sure that the application releases the resource in question – when this method returns, the resource manager assumes that the resource is available.
In the event that an application doesn’t release a resource when release()
is called (either because it’s crashed or because it’s a hostile application), the resource manager may reclaim the resource anyway and call the notifyRelease()
method on the ResourceClient. This is simply a polite way of telling the application that its resource has been removed and to give it a chance to recover gracefully.
An application is not just limited to implementing this interface once – sometimes it’s easier for several different classes to implement the ResourceClient
interface if the application uses several different types of shares resource. This lets the developer handle issues related to a resource in the part of application that actually uses that resource, which makes the code easier to maintain and more modular.
Resources in an OCAP receiver
Scarce resources in OCAP are represented by the ResourceProxy
interface. APIs that need resource management capabilities implement this interface in order to provide access to scarce resources. It’s important to remember that an object implementing the ResourceProxy
interface is not the scarce resource itself. Resource proxies are classes that sit between an application and any scarce resources it wants to use.
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, like a modem, you don’t want to have to explicitly set parameters on it 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 downloaded to the real resource with a single method call. Since the resource proxy exists across multiple request/release cycles, this can make life significantly easier.
For instance, an application could create two resource proxies for a PSTN modem, each connecting to a different phone number and using a different username and password. The application could then keep these proxies, requesting and releasing the underlying resources without needing to reset the parameters every time it connects to a different phone number.
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:
- 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. - Next, the resource client calls the appropriate method on the
ResourceServer
implementation for the API and requests access to the resource, passing theResourceProxy
object to it as a parameter. - If access is granted, the resource server calls a private method on the resource proxy to tell the proxy that it is valid.
- 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.
- 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:
- 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.
- 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.
- 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.
- 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:
- The resource server calls the
release()
method on the resource client to tell the application to release its resource. - The resource client fails to return from this call, in an attempt to keep access to the resource.
- After a suitable timeout period, a watchdog timer in the middleware notices that the call has not returned and notifies the resource server.
- 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.
- The resource proxy breaks the link between it and the scarce resource, and resets its internal state to take account of this.
- The receiver calls the
notifyReleased()
method on the class in the application that implements theResourceClient
interface. This informs the application that it no longer has access to the resource and that it should do any housekeeping necessary. - 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:
- The application creates an instance of a
ResourceProxy
object - The application sets some parameters on the
ResourceProxy
that will be passed to the real resource when it is acquired - The application calls an API-dependent method on the
ResourceServer
for the API (usually passing theResourceProxy
it has created as a parameter) in order to reserve the real resource. - The application uses the resource as it wants to.
- 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.
Resource management and the monitor application
So now that we’ve seen how resources are represented, it’s time to take a look at how they are managed in an OCAP receiver. The MHP specification makes no assumptions about whether there is a central resource manager, or whether each API manages resources separately. OCAP changes this slightly, by giving the monitor application a great deal of control over how resources are allocated to applications. The OCAP resource management API includes an interface called the ResourceContentionHandler
. This allows the monitor application to provide its own strategy for resolving conflicts of this type by registering a class which implements this interface with the resource manager. The ResourceContentionHandler
class has one method:
public AppID resolveResourceContention( AppID[], AppID, OcapResource);
As you can see, this method takes three arguments. The first of these is the set of applications which already have the resource. The second is the application requesting the resource, and the final argument is a reference to the resource itself. This works in a pretty simple way: when a resource conflict occurs, if the monitor application has registered a ResourceContentionHandler then this method is called. In any resource conflict situation, there is always one more application wanting the resource than there are resources available (well OK, there may be many more, but for every request for a resource that can’t be met, there is only one more application than resources). What this means this that one application will be unlucky and have to do without the resource.
This method returns the application ID of the unlucky application – which may be the one that has just requested the resource. The resource manager uses this application ID to ask that application to release the resource (or deny the request, depending on which application lost out).
This two-tiered approach lets the monitor application handle resource management in a smarter way than is possible otherwise – the monitor application can enforce the network’s policy on resolving resource conflicts instead of relying on simple priority values. For instance, the monitor application may allow applications implemented by the network operator to get resources ahead of applications from other providers, or allow unbound applications preferential access over service-bound applications. The network operator can implement any strategy they like in order to meet the needs of their network, their business model, and their customers.
To register a ResourceContentionHandler
, the monitor application uses the ResourceContentionManager
class:
public class ResourceContentionManager { public static ResourceContentionManager getInstance(); public void setResourceContentionHandler( ResourceContentionHandler handler) throws SecurityException; public void setResourceFilter( org.dvb.application.AppsDatabaseFilter filter, java.lang.String resourceProxy) throws SecurityException; }
The monitor application can use this class to register a ResourceContentionHandler
, but it can also use it to deny one or more applications access to a specific resource. The setResourceFilter()
method allows the monitor application to tell the resource manager that certain applications should never be allowed access to a resource, even if they have the permission to do so. This method takes an AppsDatabaseFilter
object that describes the applications which should be granted access to a resource, and a string giving the name of the resource that is controlled by this AppsDatabaseFilter
. At most one resource filter can be set for each resource, so anyone developing a monitor application should take care to make sure that their AppsDatabaseFilter
covers all of the applications that it needs to. Any applications that are not covered will be denied access to the resource.
The resource management strategy
Resource managers
Even though we talk about the ‘resource manager’ in this tutorial, there may be no such thing in the middleware implementation.
Here, we are using ‘resource manager’ to mean the part of the middleware (or the API implementation that uses the resource management API) that allocates resources to applications and resolves resource contention.
We’ve already discussed how the resource client interface is used when resolving resource conflicts, but now we can look at the whole picture. When an application requests a resource, the resource manager will first check to see whether that resource has a resource filter set. if it has, it will call the accept()
method on the AppsDatabaseFilter
to check whether the application is allowed access to the resource. If it isn’t then the request is rejected immediately.
If the application is allowed access, then the resource manager will check to see whether any resources are available. If they are, then the resource manager will assign one of the free resources to that application. When an application requests a resource that’s already reserved, the resource manager asks the current holder of that resource to give it up by calling the requestRelease()
method on the resource client that has been registered for that resource. Some resources may be owned by more than one application at a time, and in these cases the resource manager will call requestRelease()
on every resource client (starting with the lowest priority application and working up) until an application releases the resource, or until every application has been checked.
When no application is willing to give up the resource, one of two things can happen. If the monitor application has registered a module to resolve resource conflicts, then that module is called to decide which application (if any) should be forced to give up its resource. This allows the monitor application (and thus the network operator) to decide what strategy should be adopted when several applications want access to the same resource. For instance, the monitor application may decide that unbound applications will always have access to scarce resources, and so decide to remove the resource from a service-bound application in the event of a conflict. We will see more about this in the next section.
If the monitor application is not resolving resource conflicts, then the application with the lowest priority loses access to the resource. In the case that the application requesting the resource is the one with lowest priority, then its request is denied and the current owners keep the resource.
Resource management – differences from MHP
-
The monitor application can have a great deal of influence over the way resource arbitration is handled, and may implement its own resource arbitration strategy. This is not possible in MHP, where the resource management strategy is coded into the middleware by the receiver manufacturer.
-
Some applications may be denied access to one or more resources, even if they have been given the permission to use those resources.