fornwall
fornwall

Reputation: 2917

Why do WakefulIntentService check START_FLAG_REDELIVERY?

In WakefileIntentService.java from the CWAC Wakeful library the code contains:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    PowerManager.WakeLock lock = getLock(this.getApplicationContext());
    if (!lock.isHeld() || (flags & START_FLAG_REDELIVERY) != 0) {
        lock.acquire();
    }
    super.onStartCommand(intent, flags, startId);
    return(START_REDELIVER_INTENT);
}

Why do the code check for START_FLAG_REDELIVERY - what prevents the following scenario?

  1. onStartCommand() is called and the lock is acquired.
  2. The system kills the service before completion.
  3. The system re-delivers the intent with START_FLAG_REDELIVERY, causing another acquire() call on the already held lock.
  4. The service completes and calls release() once.
  5. The reference counted lock is still held forever due to being acquired twice but released only once.

Upvotes: 0

Views: 980

Answers (3)

CommonsWare
CommonsWare

Reputation: 1006564

what prevents the following scenario?

Your scenario implies that Android would terminate the service and leave a WakeLock outstanding. I am aware of no scenario under which this will occur. Android terminates processes, not services, and it is the OS's responsibility to release any acquired WakeLock at that point.

It seems strange since START_FLAG_RETRY is not handled, I've opened the issue https://github.com/commonsguy/cwac-wakeful/issues/10 for that.

As I noted in that issue, while START_FLAG_REDELIVERY has decent documentation, START_FLAG_RETRY does not. I have no idea when it will get used. I have no idea what the state of the WakeLock will be based upon those undocumented causes. And so forth. It is far better to risk the occasional accidental sleep than it is to accidentally keep the CPU powered on indefinitely.

Upvotes: 0

fornwall
fornwall

Reputation: 2917

It seems to be with the purpose of reacquiring the lock after the process has been killed, but when another intentservice is already running with a lock, in which case it needs to increase the refcount for the redelivered intent since the original locking from sendWakefulWork() in the old process no longer exists.

It seems strange since START_FLAG_RETRY is not handled, I've opened the issue https://github.com/commonsguy/cwac-wakeful/issues/10 for that.

Upvotes: 0

smith324
smith324

Reputation: 13060

If the service is killed then its executing process is terminated, later when it is restarted the lock is no longer held. You can see in this snippit that the lock is just held in a static variable.

synchronized private static PowerManager.WakeLock getLock(Context context) {
    if (lockStatic == null) {
      PowerManager mgr=
          (PowerManager)context.getSystemService(Context.POWER_SERVICE);

      lockStatic=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
      lockStatic.setReferenceCounted(true);
    }

    return(lockStatic);
  }

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/w8BdsI1BVdA

Upvotes: 1

Related Questions