0

I have a service (properly declared in the Manifest file) that upon onDestroy() schedules itself to start again one minute later via AlarmManager. However the service is not starting even though onDestroy() runs correctly. What could be wrong?

The scheduling code:

@Override
public void onDestroy() {

    BroadcastReceiver br = new BroadcastReceiver() {
        @Override
        public void onReceive(Context c, Intent i) {
            c.startService(new Intent(c, MyService.class));
        }
    };

    registerReceiver(br, new IntentFilter("xxxx"));

    PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent("xxxx"), 0);

    AlarmManager am = (AlarmManager)(this.getSystemService(Context.ALARM_SERVICE));

    am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + ONE_MINUTE, pi);

    Log.i("onDestroy", "Service scheduled.");

    unregisterReceiver(br);

    super.onDestroy();
}

The service declaration in the Manifest file:

<service
    android:name="com.xxxx.MyService"
    android:exported="true">
</service>
Piovezan
  • 3,215
  • 1
  • 28
  • 45
  • Since you create the receiver in onDestroy, it might be destroying the receiver. – neo Jun 12 '13 at 20:00

1 Answers1

3

First, your BroadcastReceiver is going away nanoseconds after the end of onDestroy(), making it useless. Please register your BroadcastReceiver in the manifest with a <receiver> element.

Second, a _WAKEUP alarm only keeps the device awake long enough to process an onReceive() in a BroadcastReceiver. You need to use a WakeLock to keep the device awake longer than that. Depending upon what you are doing, my WakefulIntentService may be of some use.

Third, you do not need to export your service, and by doing so, you are opening up potential security holes. I recommend removing android:exported="true".

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks! Is registering my BroadcastReceiver that important? I have to instantiate it anyway in the code, and depending on the instantiation point it may be still nanosseconds or more from the instance destruction, so wouldn't putting it away from onDestroy() be more important? Second, by "depending upon what you are doing" I assume you mean "depending upon how many seconds your service is going to run", due to the 10-second wake lock gap, right? If the task itself matters, it is: to stay wake for around 30 seconds acquiring GPS locations and sending them to a server. Thanks again! – Piovezan Jun 12 '13 at 20:31
  • @Piovezan: "Is registering my BroadcastReceiver that important?" -- if you want it to receive broadcasts, yes. "I have to instantiate it anyway in the code" -- why? "due to the 10-second wake lock gap, right?" -- I do not know what you mean by "the 10-second wake lock gap". Devices can fall asleep in less than 10 seconds after a `WakeLock` is released. "to stay wake for around 30 seconds acquiring GPS locations and sending them to a server" -- you may want to examine `LocationPoller`, then: https://github.com/commonsguy/cwac-locpoll – CommonsWare Jun 12 '13 at 20:41
  • By "the 10-second wake lock gap" I mean the what is stated in the onReceive() Android documentation http://developer.android.com/reference/android/content/BroadcastReceiver.html#onReceive(android.content.Context, android.content.Intent) unless they are different things. If I don't have to instantiate my BroadcastReceiver in the code, I'm sorry but I haven't yet found how to access a instance of it. – Piovezan Jun 12 '13 at 20:51
  • @Piovezan: "unless they are different things" -- that is referring to the maximum amount of time to spend in `onReceive()` and has nothing to do with a `WakeLock`. In reality, if you spend more than a few milliseconds in `onReceive()`, you will freeze your UI, if it is in the foreground. "I'm sorry but I haven't yet found how to access a instance of it" -- why do you need to access an instance of it? Android will create an instance and call `onReceive()` on it, when a broadcast `Intent` matches your ``. – CommonsWare Jun 12 '13 at 20:55
  • Thanks. I get it now. However I still don't get why my BroadcastReceiver needs a longer wake lock for performing a few milliseconds long call to startService() for a service that will last for an indeterminate amount of time, but apparently it does. – Piovezan Jun 12 '13 at 21:03
  • @Piovezan: The framework has its own `WakeLock` for the duration of `onReceive()`. Once `onReceive()` ends, the device can fall back asleep. Your call to `startService()` *will not even begin to do any work until after `onReceive()` ends*. Moreover, the service itself needs a `WakeLock` to do its work. Hence, you need to acquire your own `WakeLock` in `onReceive()`, for your own use, shared between the `BroadcastReceiver` and the `Service`. This is what `WakefulIntentService` and `LocationPoller` wrap up for you, so you don't have to fuss with it yourself. – CommonsWare Jun 12 '13 at 21:17
  • Also when I don't instantiate my BroadcastReceiver the application complains that I have leaked an IntentReceiver and may be missing a call to unregisterReceiver(). – Piovezan Jun 12 '13 at 21:18
  • @Piovezan: That error will only occur if you *have* instantiated a `BroadcastReceiver`, called `registerReceiver()`, and have not called `unregisterReceiver()`. You do not need `registerReceiver()` or `unregisterReceiver()`, for a `BroadcastReceiver` registered in the manifest. – CommonsWare Jun 12 '13 at 21:19
  • Strangely enough, I'm no longer calling `registerReceiver()` in my code. – Piovezan Jun 12 '13 at 21:24
  • @Piovezan: Then open a new StackOverflow question, supplying the stack trace, plus any relevant snippets of code referred to from the stack trace. – CommonsWare Jun 12 '13 at 21:28
  • Thanks again. And BTW, I'll stick to `WakefulIntentService`, as my code is already finished. ¯\_(ツ)_/¯ It's a pity that I couldn't find your useful code earlier... – Piovezan Jun 12 '13 at 21:59
  • I double checked the code and noticed `registerReceiver()` was actually being called. The issue no longer occurs. – Piovezan Jun 13 '13 at 11:27