Showing posts with label services. Show all posts
Showing posts with label services. Show all posts

Thursday, June 17, 2010

Plugins

I blogged 2 years ago that Android is a surprisingly modern application platform, I even said that it was the most modern application platform. This is partly due to Android's advanced component features. These features are not always evident to the naked eye so I present here a standard exercise to demonstrate them.

Click here to download the example program.

In this exercise we will implement a plugin framework for an example program. Plugins are components that connect to the main application over a uniform interface and are dynamically deployable. The download package contains two Android applications. The first, pluginapp is the example application that will use the plugins. The second, plugin1 is a plugin package that contains two plugins for pluginapp. Plugin1 package is not visible among the executable applications, it does not expose any activity that may be launched by the end user. If deployed, however, its plugins appear in pluginapp. Plugin deployment/undeployment is dynamic, if you uninstall plugin1 package while pluginapp is running, pluginapp notices the changes and the plugins disappear from the plugin list.




In order to implement these functionalities, the following features of the Android framework were used.


  • Each plugin is a service. Plugin1 exposes two of them. In order to identify our plugins, I defined a specific Intent (aexp.intent.action.PICK_PLUGIN) and I attached an intent filter listening to this intent in plugin1's AndroidManifest.xml. In order to select a particular plugin, I abused the category field again. One plugin can be accessed therefore by binding a service with an intent whose action is aexp.intent.action.PICK_PLUGIN and whose category equals to the category listed in AndroidManifest.xml of the package that exposes the plugin service.
  • Plugins are discovered using the Android PackageManager. Pluginapp asks the PackageManager to return the list of plugins that are bound to aexp.intent.action.PICK_PLUGIN action. Pluginapp then retrieves the category from this list and can produce an intent that is able to bindthe selected plugin.
  • Pluginapp updates the plugin list dynamically by listening to ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and ACTION_PACKAGE_REPLACED intents. Whenever any of these intents are detected, it refreshes the plugin list.
Even though Android is not as sophisticated as OSGi when it comes to component framework, it has every necessary element. It has a searchable service registry, packages can be queried for the services they expose and there are deployment events.

Saturday, January 16, 2010

Oneway interfaces

In early betas, the Android IPC was strictly synchronous. This means that service invocations had to wait for the return value of the remote method to arrive back to the caller. This is generally an advantage because the caller can be sure that the called service received the invocation by the time the remote method returns. In some cases, however, this causes the caller to wait unnecessarily. If synchronicity is not required and the method has no return value, oneway AIDL interfaces may be used.

Oneway methods are specified by addind the oneway keyword to the AIDL interface definition.

oneway interface IncreaseCounter { void increaseCounter( int diff ); }

Only the entire interface can be oneway and these methods must all have void return value. The stub compiled from oneway AIDL interface does not have return path for remote methods on the service side and does not wait for the method to execute on the client side. The delivery is reliable (no invocations are lost) but the timing is not guaranteed, e.g. two sequential oneway invocations may arrive at the invoked service in different order. Oneway interfaces are therefore more complicated to use (they are also faster and don't block the caller) and are used extensively by the Android framework internally to deliver event notifications.

Click here to download the example program.

Update: In order to address a comment in the comment section, the project was adapted to the Android Studio tool chain. Click here to download the updated sources and read this blog post, how to import the project into Android Studio.


Our primitive example has an Activity and a Service. The service exposes two interfaces: one "normal" (Counter.aidl) and one oneway (increaseCounter.aidl). The interesting bit here is how one service can expose two interfaces. The onBind method checks the Intent used to bind the service and returns different binders based on the Intent. The important point here not to use the Intent extra Bundle to differentiate among interfaces. I did this and I can confirm that even though extras arrive at onBind (the API documentation states the contrary) but the framework gets completely confused and thinks that the service has already been bound with the same Intent (the framework seemingly cannot figure out that the Intent extras were different). In the example program I abused the category field therefore and this works nicely.

Friday, February 29, 2008

Autostarting services

Some privileged services start automatically in Android while the lowly applications I have written so far had to be started manually. I was not satisfied with the situation so I went after the Android bootup sequence.

The Linux layer under the JVM boots up normally, using the init script but I was not interested in that. I found that the Java services are all started by the System server (android.server.SystemServer) which does launch each system server in a hardwired way.

...
Log.i("SystemServer", "Starting Alarm Manager.");
sm.addService("alarm", new AlarmManagerService(context));
Log.i("SystemServer", "Starting Window Manager.");
wm = WindowManagerService.main(context, power);
sm.addService("window", wm);
...


There is no way getting our service autostarted this way but fortunately there is the android.intent.action.BOOT_COMPLETED intent which is broadcasted when the boot completes. One needs android.permission.RECEIVE_BOOT_COMPLETED permission to receive this intent.

Download the example program from here.

The example program has two parts: an intent receiver catching the BOOT_COMPLETED intent and a primitive service that counts down from 10 in every 3 seconds and logs the counter value. When it counts down, the service dies completely, this is necessary as there is no simple way to uninstall packages in the SDK so this service is not allowed to cause trouble later. Please, note the use of Handler for the timed countdown: you can't stay for too long in onStart() otherwise the application manager will shoot down the service.

Check the boot log below and you will find how the service is started. Each ... represents deleted log entries because meanwhile the boot process is happening and other services write the log.

D/BootCompletedIntentReceiver( 576): android.intent.action.BOOT_COMPLETED
...
D/BootCompletedIntentReceiver( 576): BackgroundService started
...
D/ActivityThread( 576): Creating service aexp.persistentapp.BackgroundService
D/BackgroundService( 576): onStart
I/ActivityManager( 510): Stopping service: {aexp.persistentapp/aexp.persistentapp.BackgroundService}
D/ActivityThread( 576): Stopping service aexp.persistentapp.BackgroundService@400bcb18
D/BackgroundService( 576): onDestroy
...
D/BackgroundService( 576): Counter: 10
...
D/BackgroundService( 576): Counter: 9
D/BackgroundService( 576): Counter: 8
D/BackgroundService( 576): Counter: 7
....
D/BackgroundService( 576): Counter: 6
D/BackgroundService( 576): Counter: 5
...

Sunday, February 3, 2008

Double life of a service

Earlier (with much less experience in Android services) I wrote about the two kinds of services behind the android.app.Service abstraction: a long-running service whose lifecycle is independent of the activity that started it (Context.startService) and a service bound by other services and activities by its AIDL interface (Context.bindService). The lifecycle of this second type of service depends on the lifecycles of the entities that bind it, if the service has no more bound client, the application manager is free to destroy it. Meanwhile, the first type of service exists until the clients that started the service stop it or until the service stops itself. In extremely low resource conditions the application manager may shut down the first type of service too but this is rare.

I don't know how about you but the difference between the two types always seemed to be unnatural for me. For starter, I can pretty much imagine a number of useful and practical services that are long-running and clients want to communicate with them at the same time. For example a P2P module would be such a service; it would run in the background doing discovery-related or other long-running tasks and occassionally client applications would connect to it to accomplish P2P operations.

It turns out that this difference is artificial. Android services can exhibit both properties: they can be long-running and can be bound and unbound with AIDL interface operations. This is possible because there is only one service instance, independently of the method the service was started with. I discovered it recently and as there was a topic about it in the Android groups, I decided to quickly put together an example program about it.

You can download the example program from here.

You can download the example program updated for SDK 1.5 from here.

Our example is simple. There is a service that holds a counter and can return that counter by means of an AIDL interface. The service need to be bound by Context.bindService() to obtain client-side interface stub. This is not very useful, however, because the counter does not change, it needs to count forward. In order to do that, we start the same service with Context.startService(). It turns out that the onStart() that follows is invoked on the same service instance. Hence we have a service that conforms to both types: it is long-running and serves interface invocations at the same time.

Simple? I thought so. I implemented a version of the example program and it worked flawlessy except that the service could not be stopped. It turns out that a dual service like that can be stopped with Context.stopService() call only if both lifecycles models allow it. This means that stopService() has no effect on a bound service!

Let's take an example. The client activity allows binding/unbinding, starting/stopping the service manually.



Now let's see what happens if the service is bound, unbound then started and stopped.

D/DUALSERVICECLIENT( 568): bindService()
D/ActivityThread( 568): Creating service aexp.dualservice.DualService
D/DUALSERVICE( 568): onCreate
D/DUALSERVICECLIENT( 568): onServiceConnected
I/ActivityManager( 465): Stopping service: {aexp.dualservice/aexp.dualservice.DualService}
D/DUALSERVICECLIENT( 568): unbindService()
D/ActivityThread( 568): Stopping service aexp.dualservice.DualService@40044928
D/DUALSERVICE( 568): onDestroy
D/DUALSERVICECLIENT( 568): startService()
D/ActivityThread( 568): Creating service aexp.dualservice.DualService
D/DUALSERVICE( 568): onCreate
D/DUALSERVICE( 568): onStart
I/ActivityManager( 465): Stopping service: {aexp.dualservice/aexp.dualservice.DualService}
D/DUALSERVICECLIENT( 568): stopService()
D/ActivityThread( 568): Stopping service aexp.dualservice.DualService@40048cd0
D/DUALSERVICE( 568): onDestroy

The service lifecycles work nicely: when the service is bound, its onCreate is called, then it is destroyed (onDestroy()) when it is unbound. The same goes for startService-stopService except that onStart() is called after onCreate(), as it should happen.

Now let's see what happens if the sequence is bind-start-stop-unbind!

D/DUALSERVICECLIENT( 568): bindService()
D/ActivityThread( 568): Creating service aexp.dualservice.DualService
D/DUALSERVICE( 568): onCreate
D/DUALSERVICECLIENT( 568): onServiceConnected
D/DUALSERVICECLIENT( 568): startService()
D/DUALSERVICE( 568): onStart
D/DUALSERVICECLIENT( 568): stopService()
I/ActivityManager( 465): Stopping service: {aexp.dualservice/aexp.dualservice.DualService}
D/DUALSERVICECLIENT( 568): unbindService()
D/ActivityThread( 568): Stopping service aexp.dualservice.DualService@4004a430
D/DUALSERVICE( 568): onDestroy


ActivityManager reports twice that the service was stopped. Of these two, only the second one is real (leads to the invocation of onDestroy()). As the service abstraction has no onStop() method (that would be counterpart of onStart()), the service is not notified that it was stopped. You can examine that with getting the counter: it continues counting after the service was stopped.

This is annoying enough but a method like stopCounting() on the AIDL interface would solve the problem. My opinion, however, is that the lack of service stop notification will cause problems with less tricky long-running services too. For example a voice recorder service will not be able to correctly free the resources (e.g. close the output file correctly) if it is just stopped by one of its clients or if the ActivityManager shuts it down due to low resource condition. I don't know how hard it would be ti implement stop notification callback (finalizers are the toughest kind of callbacks) but this enhancement was hacked into every application model that missed it originally (like Java applications, for example).

Saturday, January 26, 2008

About binders

I wanted to go back to my Bluetooth exercise once again but then I stumbled into this beautiful sample program from John Guilfoyle. I decided immediately that before playing again with that wicked Bluetooth service, I have to test-drive again the service framework and the low-level mechanisms behind it.

My Android experiences with services were so far restricted to repeating the sample program in the documentation. This time I wanted to try something more ambitious: connecting two applications through services. In order to do that, it is worth getting behind the facade of the Android service framework. This thread contains a lot of information that I try to recap here.

The workhorse of the Android IPC is the "IBinder class". As its name implies, android.os.IBinder is really an interface, implemented by the real worker objects, namely android.os.BinderNative and android.os.BinderProxy. The binder provides a simple functionality of synchronous method invocation. Calling the transact() method on the binder is able to transmit a function code, a java.os.Parcel instance and some flags. The result is returned in another Parcel instance. Look for this method signature:

public final boolean transact(int code, Parcel data, Parcel reply, int flags ) throws DeadObjectException;

The client calls the transact method and the other side of the binder, in the other side of the process separation will receive a callback.

protected boolean onTransact(int code, Parcel data, Parcel reply, int flags);
The IPC has a thread pool for each process and the onTransact method is invoked in the context of a thread in the IPC thread pool. Parcel is the abstraction of the data the IPC framework is able to serialize and deserialize, you can look at the documentation of the android.os.Parcel object to see, what data types are supported. The most interesting data type is the IBinder itself (readStrongBinder, writeStrongBinder) so it is possible to pass binder endpoints to another processes. The interface mechanism that the aidl tool provides is really simple after that. Aidl takes the interface description and turns it into Java code that serializes and deserializes invocation parameters and return values to and from Parcels. Take for example our trusty IAdderService which has a method with this signature:

int add( in int i1, in int i2 );

Aidl has to generate a code that serializes two integers into the request Parcel and deserializes the return integer from the response Parcel in transact() because this is the client side of the stub. In onTransact method, as it is the receiver side of the call, it has to deserialize the input parameters, invoke the service-side implementation of the method then serialize the result. And it does exactly that (excerpts from the IAdderService.java generated by the aidl tool):

public int add(int i1, int i2) throws android.os.DeadObjectException { android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();

int _result;

try {

_data.writeInt(i1);

_data.writeInt(i2);

mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);

_result = _reply.readInt();

}

...

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) {
try {
switch (code)

{

case TRANSACTION_add:

{
int _arg0;
_arg0 = data.readInt();

int _arg1;

_arg1 = data.readInt();

int _result = this.add(_arg0, _arg1);

reply.writeInt(_result);
return true;
}

}

The service framework does not provide any means to find out, what is the serialization and deserialization stub on the client and the service side which I consider a drawback. This is a reason why it is impossible to discover the service interfaces (one can retrieve the client-side binder but not the interface stub, therefore it is impossible to know, how to talk to the service without knowing the interface stub from some other, independent source). The framework simply assumes that the client- and the server-side stubs match, if not, then it is the programmer's fault.

I was now ready to realize my dream to connect two applications by means of service invocations. The best way is, of course, Intent-based invocation but I wanted to work that around just for the sake of hacking. As Dianne Hackbod pointed out, however, Android application lifecycle makes the direct connection impossible. Depending on resource situation, Android apps just come and go and therefore the binders connecting them may stop functioning without any warning. One has to go through services because service dependencies are respected by the application manager. So I created the following simple application (actually, two applications and one service).

You can download the example program from here.

The task is to receive a callback from Application 2 (called SClientApp) by Application 1 (called HostappClient). The connection between the two applications goes through a service (HostappServiceImpl, co-located with HostappClient). Both applications bind this service in a usual way. In addition to that, HostappClient provides the HostappServiceImpl with a callback binder. Why binder, why not interface? It could be interface and it would be more elegant to do so. The Windows version of the aidl tool in the current version (m3-rc37a) has an annoying bug that makes the import statement almost unusable so there is no way to import our own interface classes. This is not a problem, however, if we know the relationship of binders and interfaces. We just pass the binder reference and apply the interface stubs onto it when the binder arrives. The call flow is the following:
  • HostappClient binds HostappServiceImpl. When the service binding callback arrives, we pass the binder of HostAppClient's ISetTextService to HostappServiceImpl.
  • Now HostappClient launches SClientApp as subActivity. The first thing SClientApp does is to bind HostAppServiceImpl. When the service is bound succesfully, SClientApp passes the hugely valuable text result to HostAppServiceImpl which in turn calls HostappClient's ISetTextService whose binder we have received previously.
  • One interesting bit remained: the use of android.os.Handler in HostappClient. When HostappClient receives the service callback, it cannot directly manipulate the UI, only the UI thread is allowed to do that. The service callback runs in an IPC thread, not the UI thread, therefore it uses a Handler instance to pass a Runnable to the UI thread which is then executed there (the Handler executes the Runnable in the context of the thread it was created in and our Handler instance was created in the context of the UI thread).

Huh, pretty complicated instead of returning that hugely important string in the intent invocation bundle? And that is not the end, because our example program is not perfect. It is not prepared for low-memory situations when each of our three players may be destroyed and resurrected by the application manager. The worst-case scenario is this:
  • HostappClient is launched and when it binds HostappServiceImpl, these two entities are in the memory.
  • When HostappClient makes an intent invocation to SClientApp, both HostappClient and HostappService may be destroyed by the application manager.
  • SClientApp now binds HostappServiceImpl and these two are in the memory now. The IBinder instance passed by HostappClient is now lost.
  • When SClientApp finishes, SClientApp and HostappServiceImpl may both be destroyed again. Our hugely valuable text data passed by SClientApp to HostappServiceImpl is lost then.
  • HostappClient is resurrected but it has nothing to receive from HostappServiceImpl.
A robust implementation of HostappServiceImpl would store setMyText() invocations in a persistent storage, e.g. SQLite database if the callback to HostappClient fails (DeadObjectException or appService==null in HostappServiceImpl.setMyText). When the binder is set by HostappClient's invocation to setCallback(), HostappServiceImpl would check its storage and would immediately send back setMyText() callbacks to HostappClient from the persistent storage. This exercise is left, however, to the interested reader. :-)

Sunday, January 20, 2008

Using the service directory

Originally I wanted to play with Bluetooth which seemed easy but then - as usual with Android - unexpected complications occured. By the way, does anyone know, how to get the default Adapter activated? :-)

Playing with Bluetooth brought me back to services and I was surprised once again how well Android documentation keeps the secret that Android is a service-based platform. Actually, I found, that the Android system's architecture is pretty similar to that of the Symbian. The system is built in client-server fashion. System services (all located in the android.server package) run in their own virtual VMs. Whenever a client wants to talk to those services, they go through the service framework that I played with in this blog entry. The client side sees the services through client-side stubs whose name normally start with I (like IServiceManager). All the other classes on the client side are purely convenience methods, building on the functions offered by the interface class.

Android is superior to Symbian in that it has a proper service directory. This functionality was added to Symbian later, this is the ECom framework. General Symbian servers are not registered, however, in a service directory which is a major drawback of the platform. Android servers are nicely listed in Android's local service directory but of course this feature is not documented at all. :-)

I went after the service directory by decompiling the Android emulator's framework library with Pavel Kouznetsov's wonderful Jad tool. The android.jar is located under the root directory of the Android SDK. I found that the service directory is accessible via the android.os.ServiceManagerNative class.

IServiceManager sm = ServiceManagerNative.getDefault();

The android.os.IServiceManager is the service interface class through which the default service manager can be accessed. I put together a simple program to list these, you can download the program from here.

The display of this program is like this:

This is nice and good but how can one access one of those services? The example program demonstrates it by accessing a less known system service, the Statistics service.

The key lines are the following:

IServiceManager sm = ServiceManagerNative.getDefault();
IBinder statBinder = sm.getService( "statistics" );
IStatisticsService statService = IStatisticsService.Stub.asInterface( statBinder );


The service name "statistics" is the same name that was displayed by the previous program. Unfortunately, there seems to be no programmatic way to get from the IBinder (which is a client-side stub) to the IStatisticsService (or any other service interface class) without knowing, what is the real interface the binder supports. It is the programmer's responsibility to know the interface the service supports and obtain it correctly using the I class belonging to the service (like IStatisticsService this time).

Convenience classes using the service interface classes are more suitable for the application programmer to talk to services. Services may have other means to interact with applications, like Intent broadcasts. In the present state of Android with a lot of areas under development, consequently very poor or not-existing documentation, service interface classes may in many cases be the only way to activate features of the platform.

Monday, January 7, 2008

Invoking services

Update: please check out the updated example program for Android SDK 1.5.

I was not blogging very actively in the past few days and the reason for that was ... erm ... partying. The parties seem to be over for some days so I can return to my favourite pastime of finding service-oriented architecture (SOA) traits in Android.

Activity invocation is just one way of Android's service-oriented design. Android has a complete IDL-based invocation framework built into it. I was particularly curious about it because this sort of service invocation does not have to go through the service lifecycle management that slows down activity invocation considerably.

First, about services. Similarly to intents, I was a bit surprised to find out that the same Service class is used to cover two different service abstractions.
  • If the service is started with Context.startService then it is a long-running background task whose lifecycle is not related to the lifecycle of the application that started it. Beside passing a start-up parameter bundle to this kind of service, Android platform does not provide any means of communicating with the service.
  • If the service is started with Context.bindService then the lifecycles of the service and that of the application using it are tied. The application using the service is notified about the state of the service by means of service lifecycle events. It is also possible to communicate with this type of service using the Android IDL (AIDL) framework.
As I wanted to play with AIDL, this second type of service was of interest for me. That model reminds me of OSGi and its ServiceTracker except that OSGi was much more cumbersome to program and did not not provide any client-service separation whatsoever.

  • The client requests connection to the service (by specifying an intent, as with activities). This launches the service (in separate address space)
  • Once the service is ready to accept requests, the client is notified by means of a registered listener object (conforming to the ServiceConnection interface).
  • The notification also carries the address of a stub object that can be used to invoke the service. If the service crashes or closes unexpectedly, the client is notified by the same service connection object.
  • Meanwhile, the service can be invoked through the stub objects that the aidl tool generates from the service description.
The example code can be downloaded from here.

The service description (with the extension of .aidl) is actually quite similar to a Java file. This is the AIDL of the example program.

package aexp.aidl;

// Adder service interface.

interface IAdderService {

int add( in int i1, in int i2 );
}


Currently one service can have only one interface although Dianne Hackborn from Google hopes for improvement here.

The convention of the aidl tool is that AIDL files are mixed with the Java files. This is how the tool finds them and converts them to Java stub files. In spite of the documentation's statement that only the Eclipse plugin converts AIDL to Java stub file, the Ant script generated by activityCreator invokes the aidl tool before compiling the Java file so if the AIDL is located correctly (in the Java source directory corresponding to the package declaration). In the picture below you can see IAdderService.aidl and the IAdderService.java Java stub file generated by the aidl tool.



Although AdderService is located in the same package as the activity, it has a life (and lifecycle) of its own. The service is declared in the AndroidManifest.xml file (again, XML fragment is garbled so that the blog engine does not corrupt it).

[service class=".AdderServiceImpl"/]

The service declaration could have intent filters as activities may have. In our example we target it directly, using its class name. In order to demonstrate the service lifecycle, the lifecycle events are logged.

The client is located in a separate application. The client also depends on the Java stub file generated by the service project so this file has to be copied by hand into the client project.


The interesting bit here is the AdderServiceConnection embedded class that acts as the service state listener. Just because the bindService call was issued, the service is not available! (actually, we can't obtain the stub object until the ServiceConnection object is notified by its onServiceConnected method). Note that the interfaceName argument of bindService is always null and this argument is supposed to disappear altogether.

Here is the snippet invoking the service.

private void invokeService( int i1, int i2 ) {
TextView t = (TextView)findViewById(R.id.invokeserv_result);
if( service == null )
t.setText( "Service not available" );
else {
try {
int result = service.add( i1,i2 );
t.setText( Integer.toString( result ) );
} catch( DeadObjectException ex ) {
t.setText( "Service invocation error" );
}
}
}


The code invoking the service needs to be prepared for the following exceptional cases:
  • Service is not yet available (onServiceConnected was not yet called) or has gone (onServiceDisconnected was called).
  • For some reason, the invocation was not succesful (DeadObjectException).
I expect that service invocation performance is superior to activity invocation performance but let's see that later. :-)