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).

45 comments:

rut said...

I'm testing your example Double Lige in the SDK m5, I start the service, bind the service but whe I try to invoke it, i have any problem, I get a null pointer, I think the my problem is in:

private CounterServiceConnection conn;

class CounterServiceConnection implements ServiceConnection {


public void onServiceConnected(ComponentName className,
IBinder boundService ) {
Log.d( LOG_TAG,"onServiceConnected 1" );
counterService = ICounterService.Stub.asInterface((IBinder)boundService);
Log.d( LOG_TAG,"onServiceConnected" );
}

public void onServiceDisconnected(ComponentName className) {
counterService = null;
Log.d( LOG_TAG,"onServiceDisconnected" );
updateServiceStatus();
}
};

Peggy said...

I also have the samne problem
bindService( i, conn, Context.BIND_AUTO_CREATE); seems successful, the return value is true.

Craig said...

In testing to be sure that service has been absolutely stopped, I commented out the sections where you set the connection and and service objects to null.

I unbinded the service and stopped it, then tried to invoke it. I found that even though the service should be stopped and not running, I was still able to receive numbers back.

Am I missing something, or is the null assignment just covering up a service that isn't really stopped?

Anonymous said...

SDK has updated, so I think you should update your example code. :)

Anonymous said...

is there an updated example, that runs with 1.5 SDK?

Gabor Paller said...

"is there an updated example, that runs with 1.5 SDK?"

Yes, there is. ;-)

Anonymous said...

where ? :D

Gabor Paller said...

In the blog text, there is a new example code link under the old one.

eithu said...

thanks a lot. It works well on both 1.5 and 1.6 :)
Thank you so much!

Max Pierson said...

I kept getting a null pointer exception whenever I tried to call any of my service methods, and finally I realized that calling bindService() means that Android will connect to your service at some point, whenever it has a moment.

So you need some time between binding and when you start calling methods, if anyone else is having issues.

Thanks for the great tutorial!

Gabor Paller said...

Max, check out the CounterServiceConnection.onServiceConnected method. You can use your service after the Android framework calls back this method.

Parag said...

Sorry but not able to download 1.5 specific example.

Gabor Paller said...

"Sorry but not able to download 1.5 specific example."

I have just tried (from the UK), it works for me.

Jeremy R. Fishman said...

Thanks, this was very helpful!

Blake said...

Wow ty so much, this really helped me understand what the heck is going on with a service and how to set one up. Sure the android dev manual tells you what a service is, but not how to use it.

naresh said...

Hi .. Thanks allot for sharing this demo. It helped me to understand service life cycle. Keepup your good work

réda said...

Thanks a lot for comment, hihi

Thanks max pierson ,

"So you need some time between binding and when you start calling methods, if anyone else is having issues."


boolean bo = bindService(intent2, mConnection, BIND_AUTO_CREATE);
serviceBinder.stopSelf();

serviceBinder here is null, you need to wait , or use it in onServiceConnected

Anonymous said...

Thank you.. and love you.. :p

SuVish said...

Thanks dude....the documentation on services don't clearly spill this out...thanks a bunch!

sasha said...

nice information

Anonymous said...

But, how can we make it wait some time between the binding and the calling? I am terribly lost on this!

developer code said...

it's not working.when i import this project in my eclipse then generate a error that is not a project.

John said...

What happens when i start the running service again..?

Gabor Paller said...

John, onStartCommand will be called again, see documentation here.

tournote said...

Your examples are very usefull and simple, thank you very much

snicolas said...

In the case the sequence is

start - bind - unbind - whatever

you got a onDestroy method invocation when unbinding the service. Then the service is recreated and the instance last for as long as stop is invoked.

This a real problem. The service is not expected to die after unbing it if it has been started. This seems to be a bug in Android. The only workaround I could find is to set the service to foreground.

Saranya N said...

Congratulations guys, quality information you have given!!!..Its really useful blog. Thanks for sharing this useful information
android development course fees in chennai | android app development training in chennai

Website Designing Company in Delhi said...

Alot of blogs I see these days don't really provide anything that I'm interested in, but I'm most definitely interested in this one. Just thought that I would post and let you know. Nice! thank you so much! Thank you for sharing.

Nadeem Malik said...

hello sir,
thanks for giving that type of information. Really enjoyed this blog post. Really looking forward to reading more. Much obliged.
digital marketing company in delhi

InstaaCoders Technologies said...

Nice Post, I really appreciate your work.Thanks for sharing it..


Web Design Company Los Angeles ca
Website Development Company Los Angeles
Ecommerce website design los angeles
Seo Services Los Angeles
App Development Companies in Los Angeles
new york website design company
web development company in new york
SEO Agency New York
android app development new york
Mobile App Development Company in Delhi
Mobile App Development Services in Delhi

IELTS Coaching in Dwarka said...

I feel happy about and learning more about this topic. keep sharing your information regularly for my future reference. This content creates a new hope and inspiration with in me. Thanks for sharing article like this. the information which you have provided is better then other blog.
Best IELTS training centre in Dwarka

sasireka said...

Really nice experience you have. Thank you for sharing. It will surely be an experience to someone.

angularjs online training

apache spark online training

informatica mdm online training

devops online training

aws online training

priya said...

It is amazing and wonderful to visit your site.Thanks for sharing this information,this is useful to me...
Microsoft Azure online training
Selenium online training
Java online training
Java Script online training
Share Point online training

deepak ogen said...

I will tell you one think about your blog, I am read your blog and I will collect a valuable information by your article, I really like to read your blog, I am suggest to my all friend to visit your blog and collect useful information, thank you so much for share this great information with us, if any one searching website designing company in India please contact with us.
Website Designing Company in India

Y and H Cargo India said...

I genuinely enjoy to read your articles, your blog page provided us useful information for me, I am ask with your only one thing keep sharing like this type useful blog I really like to read this type article, thank you so much for share this valuable information with us, I am suggest to my all dear friends to visit your article and collect helpful information, any one searching the shipping company in India please visit our website yhcargoindia.
Custom Broker in India

Mobile app development company in toronto said...

We are the best provide mobile app development service in Toronto And Canada please visit here my website more information.

Neha sharma said...

Rice Bags Manufacturers
Pouch Manufacturers
wall putty bag manufacturers

Neha sharma said...

we have provide the best ppc service.
ppc services in gurgaon
website designing company in Gurgaon
PPC company in Noida
PPC Company in Delhi

Neha sharma said...

we have provide the best fridge repair service.
fridge repair in faridabad
LG Fridge Repair in Faridabad
Videocon Fridge Repair in Faridabad
Whirlpool Fridge Repair in Faridabad
LG Refrigerator Repair In Faridabad
Washing Machine Repair Center in Noida

Neha sharma said...

Bali Honeymoon Packages From Delhi
Bali Honeymoon Packages From Chennai
Hong Kong Packages From Delhi
Europe Packages from Delhi
Bali Honeymoon Packages From Bangalore
Bali Honeymoon Packages From Mumbai
Maldives Honeymoon Packages From Bangalore

sasitamil said...

A universal message I suppose, not giving up is the formula for success I think. Some things take longer than others to accomplish, so people must understand that they should have their eyes on the goal, and that should keep them motivated to see it out til the end.
devops online training

aws online training

data science with python online training

data science online training

rpa online training

priya said...

Well researched article and I appreciate this. The blog is subscribed and will see new topics soon.
Microsoft Azure online training
Selenium online training
Java online training
Python online training
uipath online training

meenati said...


very informative blog and useful article thank you for sharing with us , keep posting learn more Technology

Tableau online Training

Android Training

Data Science Course

Dot net Course

iOS development course

Augurs Technologies Pvt Ltd. said...

Top Web Design & Development Company Hong Kong,
Mobile App Development Services Hong Kong,
iOS App Development Services Hong Kong,
iPhone App Development Services Hong Kong,
Custom Software Development Services in Hong Kong,

IELTS Coaching in Dwarka said...

I feel happy about and learning more about this topic. keep sharing your information regularly for my future reference. This content creates new hope and inspiration within me. Thanks for sharing an article like this. the information which you have provided is better than another blog.
Best IELTS Coaching in Dwarka sector 7