WakefulIntentService implementation clarifications
android, android-service, commonsware-cwac, intentservice
Solution
AFAIK a process killed takes its locks with it.
Correct.
Or is this an impossible scenario ?
It's fairly unlikely, but certainly not impossible.
In view of the previous should (flags & START_FLAG_RETRY) be added ?
That should be covered by `START_FLAG_REDELIVERY`. AFAIK, with `START_REDELIVER_INTENT`, there is no `RETRY` without `REDELIVERY`. If you have evidence to the contrary, I'd love to see it.
Why the if (!lock.isHeld()) check ?
Calling `release()` on a `WakeLock` that is not held results in an exception. This is just a safety blanket to ensure we don't wind up throwing an unnecessary exception. In theory, it should never be needed; in theory, I should have hair.
Why is this.getApplicationContext() needed ? is not this enough ?
We create a `WakeLock`, which we hold in a static data member. Probably the `getSystemService()` call does not wind up putting the `Context` that called it inside the `PowerManager`. And, even if it did, probably the `Context` would not be passed to the resulting `WakeLock` instance. However, to be safe, by using `getApplicationContext()`, we obtain the `WakeLock` in a fashion that ensures that the only `Context` we could possibly "leak" is the singleton application context, which, as a singleton, is effectively pre-leaked. :-)
Problem
Commonsware's WakefulIntentService works beautifully but there are some things I do not quite get. Below is the core of the service - a stripped down version of the source : ``` class WIS extends IntentService { private static final String NAME = WIS.class.getName() + ".Lock"; private static volatile WakeLock lockStatic = null; 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); } public static void startWIS(Context ctxt, Intent i) { getLock(ctxt.getApplicationContext()).acquire(); ctxt.startService(i); } public WIS(String name) { super(name); setIntentRedelivery(true); } @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); } @Override protected void onHandleIntent(Intent intent) { try { // do your thing } finally { PowerManager.WakeLock lock = getLock(this.getApplicationContext()); if (lock.isHeld()) lock.release(); } } } ``` Questions - What happens if the process is killed just after the `onReceive()` of our alarm receiver returns ? That is if service `onCreate()` (if the service is not already instantiated) or `onStartCommand()` never run. AFAIK a process killed takes its locks with it. Or is this an impossible scenario ? - In view of the previous should `(flags & START_FLAG_RETRY)` be added ? - Why the `if (!lock.isHeld())` check ? - Why is `this.getApplicationContext()` needed ? is not `this` enough ?