Real-Time Service

The real-time service (RealtimeService) is designed for implementing a background task that requires no user input. RealtimeService extends and preserves the lifecycle callback functions of Android's Service. Any developer who is familiar with Android's constructs should be able to quickly learn how to use RTDroid's real-time service.

Similar to Android's service, the real-time service is designed to perform one-shot real-time tasks, thereby modeling either aperiodic or sporadic computations. In real-time application, it is very common to perform a computation at a constant rate, as periodic task. It is foreign to Android and as such we introduce a new construct, periodic task, which is defined as Repeatable interface. A real-time service can be used to expressing periodic logic by implementing Repeatable interface, the periodic computations are provided in its onRelease() function. This tutorial shows the implementation of the periodic service in a cochlear implant application. Additionally, A real-time service can also contains a number of sporadic and periodic tasks by including a set of real-time receivers and periodic tasks as sub-components, which is discussed in mission service tutorial.

In conclusion, the real-time service can be used in three forms:

  1. Basic Service: executes a one-time computation, when the real-time service is started.
  2. Periodic Service: performs a single periodic computation
  3. Mission Service: groups a set of coupled periodic and sporadic tasks, including periodic task and real-time receivers.

Basic Callback Functions[edit]

Stage Transition for RealtimeService

Fig.1 Stage Transition for RealtimeService

The real-time service is defined as an abstract class, and a programmer needs to implement its callbacks. These callbacks are directly inherited from Android’s service and they are invoked at different times in the lifetime of a real-time service. For example, onCreate() is invoked when a real-time service is first created, onStartCommand() is invoked when a real-time service is starting, etc. More concretely, the onCreate() initializes the class variables for RealtimeService. The onStartCommand() implements meaningful application logic, such the registration of its sub-components, the actual computation of the service and so on. Fig.2 shows a real-time service from our cochlear implant application example, ProcessingService. It implements onStartCommand() to start a periodic task. Note that real-time service still only performs one computation and thus can be considered one-shot, though in this case that computation is periodic. Fig.1 shows the state transition of RealtimeService and associated framework APIs that trigger the corresponding lifetime callback functions. This behavior is exactly the same as that of Android’s service.

 1 public class ProcessingService extends RealtimeService implements Repeatable{
 2   public static final int MESSAGE_AUDIO_SAMPLE = 1;
 3   public static final int MESSAGE_CONFIG_CHANGE = 2;
 4   public static final int NUM_CHANNELS = 22;
 5   private static final int windowSize = 128;
 6   private static final int bufSize =  1792;
 7 
 8   private int volume;
 9   private double window[];
10   private int[] buffer;
11   private FFT fftClass = new FFT(128);
12   private MessageBufferHandler handler;
13   private Object lock = new Object();
14 
15   @Override
16   public void onCreate() {
17     executeInPersistent( new Runnable() {
18       @Override
19       public void run(){
20         volume = 40;
21         window[] = new double[windowSize];
22         for(int n=0;n<windowSize; n++) {
23             window[n] = 0.49656*Math.cos((2*Math.PI*n) / (windowSize - 1))
24               + 0.076849 * Math.cos((4 * Math.PI * n) / (windowSize - 1));
25         }
26         fftClass = new FFT(128);         
27         handler = new MessageBufferHandler("msg.buf.handler");;
28         lock = new Object();
29       } 
30     }); 
31   }
32     
33   @Override
34   public int onStartCommand(Intent i, int f, int id) {
35       registerRealtimeHandler("msg.buf.handler", handler);
36       registerPeriodicTask("processTask", processTask);
37   }
38   ...
39   @Override
40   public void onDestroy() {
41     stopPeriodicTask("processTask");
42     unregisterRealtimeHandler("msg.buf.handler");
43   }
44     
45   @Override
46   public void onRelease(Context context) {
47     if ( buf is ready ) { 
48     //check configuration
49     //apply volume
50     //audio signal processing
51     //send intent to OutputReceiver
52     }
53   }
54 }
Fig.2 Simplified Real-Time Audio Processing Service

There are two main semantic differences between the real-time service and Android’s service. First, a programmer can statically assign a priority to a real-time service, a starting time relative to the time when the system started, a deadline by when the computation should complete, as well as the amount of memory it is allowed to consume at run time. We enable this with our manifest extension described further in Section 3.4. Thus, at runtime, real-time services will be given preference over Android services and the priority dictates which service will execute. A real-time service of a high priority will never be interrupted by a real-time service of lower priority or by an Android service. If a real-time service exceeds its specified memory bound, an out of memory exception is generated. Second, a real-time service executes in its own thread; Android does not provide such semantics to its services (i.e., all services run in the main thread). This change is necessary in order to enable individual priority assignment for each real-time service.