Tuesday, September 1, 2009

Starting an Android service after boot

After some consideration we decided that we should have a post about adding a regular Android service at boot and not just consider the cases where you have to modify the platform itself.

Simple boot service example

The key to this is the broadcast action android.intent.action.BOOT_COMPLETED that is sent out once the platform boot is complete. To perform an action on boot you need to include a broadcast receiver in your application that registers for this intent. The rest of the implementation follows the standard design for Android services and applications.
I have a small example that adds an Android service to perform a similar task as the native service that we had in the blog post about the init process. The service will start up at boot and then write something to the log at regular intervals. The first part we need is the broadcast receiver to take care of the boot intent:
package com.enea.training.bootdemo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

/**
 * Simple receiver that will handle the boot completed intent and send the intent to 
 * launch the BootDemoService.
 * @author BMB
 *
 */
public class BootDemoReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(final Context context, final Intent bootintent) {
  Intent mServiceIntent = new Intent();
mServiceIntent.setAction("com.enea.training.bootdemo.BootDemoService");
  context.startService(mServiceIntent);
 }
}
This component is basic and it will just create an intent to start our background service when it receives the boot completed intent.

The service will create a Timer task to write to the log at a preset interval. Once it is started the timer task will be registered and the service will keep running in the background.
package com.enea.training.bootdemo;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

/**
 * Simple demo service that schedules a timer task to write something to 
 * the log at regular intervals.
 * @author BMB
 *
 */
public class BootDemoService extends Service {
 /**
  * Delay until first exeution of the Log task.
  */
 private final long mDelay = 0;
 /**
  * Period of the Log task.
  */
 private final long mPeriod = 500;
 /**
  * Log tag for this service.
  */ 
 private final String LOGTAG = "BootDemoService";
 /**
  * Timer to schedule the service.
  */
 private Timer mTimer;
 
 /**
  * Implementation of the timer task.
  */
 private class LogTask extends TimerTask {
  public void run() {
   Log.i(LOGTAG, "scheduled");
  }
 }
 private LogTask mLogTask; 
 
 @Override
 public IBinder onBind(final Intent intent) {
  return null;
 }
 
 @Override
 public void onCreate() {
  super.onCreate();
  Log.i(LOGTAG, "created");
  mTimer = new Timer();
  mLogTask = new LogTask();
 }
 
 @Override
 public void onStart(final Intent intent, final int startId) {
  super.onStart(intent, startId);
  Log.i(LOGTAG, "started");
  mTimer.schedule(mLogTask, mDelay, mPeriod);
 }
}
There is one more important thing to consider for this simple demo application and that is to add the correct intent-filters to the Android.xml file. We need to register for the BOOT_COMPLETED intent but also for the intent that will start the actual service.
< ?xml version="1.0" encoding="utf-8"?>
< manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.enea.oresund.training.bootdemo"
      android:versionCode="1"
      android:versionName="1.0">
      < uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    < application android:icon="@drawable/icon" android:label="@string/app_name">
       < service android:name=".BootDemoService">
       < intent-filter>
       < action
       android:name = "com.enea.training.bootdemo.BootDemoService">
       < /action>
       < /intent-filter>
       < /service>
       < receiver android:name=".BootDemoReceiver">
       < intent-filter>
       < action
       android:name ="android.intent.action.BOOT_COMPLETED">
       < /action>
       < /intent-filter>
       < /receiver>
    < /application>
    < uses-sdk android:minSdkVersion="3" />
< /manifest> 

Summary - adding functionality at startup

With this post I think that we have covered the alternatives for adding functionality at some point during the boot process. To sum things up there is three possible places to do something like this:
  1. Modifying the init.rc script for native services
  2. Modifying the system server to include a separate thread
  3. Writing a standard Android service and register to launch it through the BOOT_COMPLETED intent
There may be other tricks you could use but they are more far-fetched. Unless you are building your own hardware or playing with the open source project for fun the third alternative is the only possible option. This is useful to register alarms or maybe an IM-client running in the background.
I would however like to add a word of caution since running services in the background will take some resources from the system. Think carefully about if you really need to automatically launch your service every time the system has booted up. It may be better to let the user choose when to start your application in order to save some system resources.

/Mattias

13 comments:

  1. In your example, is the android service running in system server process ?

    ReplyDelete
  2. In this example the service is added as a standard Android application that runs in its own context. It will get started by the system at boot since it has registered for the BOOT_COMPLETED intent but apart from that there is nothing special about this service. It will still get launched in a process with an id similar to "app2" and run in its own context. To add something to the system server requires that you build your own firmware and that is a more complicated process.

    While I am at it I also recommend anyone following this example about starting your app at boot to also read this article on AndroidGuys:
    http://www.androidguys.com/2009/12/07/code-pollution-boot-time-services/

    ReplyDelete
  3. 1) The service has an intent-filter on itself ? Or, more precisely, on itself 2) with a different package name (com.enea.training.bootdemo instead of com.enea.oresund.training.bootdemo) ?? O_o

    2) might be a typo, but don't understand why 1)

    ReplyDelete
  4. Hi,

    "2. Modifying the system server to include a separate thread"

    can you tell me how to do this pls?

    ReplyDelete
  5. Hi,

    I have 1 java service, which starts at boot time by reciving android.intent.action.BOOT_COMPLETED intent.

    but i want to change the owner and grop of my running service, so that i can get access to /cache folder. /cache permission are drwxrwx---.
    Can i start java service from init.rc ?
    How we can change user or group of runing service?

    Thanks in Advance............

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Can someone help me.. ive got application made in Eclipse. It doesnt run @ boot.. cant find the way to fix it.. please mail me to nikola.pervan@gmail.com

    ReplyDelete
  8. i made one application which is based on receiver class i gave the permissionandroid.intent.action.BOOT_COMPLETED. It will work fine below ICS(Icecream sandwith) sdk. But Above ICS and also in ICS this permission will not work why? This will demotivate. please reply

    ReplyDelete
  9. In 3.1 and onwards the applications need to be started once for it intents to be registered, could this be the problem?
    http://commonsware.com/blog/2011/07/13/boot-completed-regression-confirmed.html

    ReplyDelete
  10. Hi,
    I want to check a conditional state in a service and send its result to another activity.
    How can I do this?

    ReplyDelete
  11. very good post, it was really informative thanks a lot for posting…
    Mobile App Development

    ReplyDelete
  12. Great post. I learned lot of information. Thanks for sharing.

    web design in chennai

    ReplyDelete