1

My app works But when it goes to Stop service it just crashes because wakelock "DoNotSleep" state so I will be glad to hear some advices. thats my logcat:

05-15 00:41:06.925: E/AndroidRuntime(4471): FATAL EXCEPTION: main

05-15 00:41:06.925: E/AndroidRuntime(4471): java.lang.RuntimeException: Unable to stop service com.example.iw84u.GpsTracker@40812c40: java.lang.RuntimeException: WakeLock under-locked DoNotSleep

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.app.ActivityThread.handleStopService(ActivityThread.java:2086)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.app.ActivityThread.access$2900(ActivityThread.java:117)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1001)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.os.Handler.dispatchMessage(Handler.java:99)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.os.Looper.loop(Looper.java:130)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.app.ActivityThread.main(ActivityThread.java:3691)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at java.lang.reflect.Method.invokeNative(Native Method)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at java.lang.reflect.Method.invoke(Method.java:507)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at dalvik.system.NativeStart.main(Native Method)

05-15 00:41:06.925: E/AndroidRuntime(4471): Caused by: java.lang.RuntimeException: WakeLock under-locked DoNotSleep

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.os.PowerManager$WakeLock.release(PowerManager.java:311)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.os.PowerManager$WakeLock.release(PowerManager.java:286)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at com.example.iw84u.GpsTracker.onDestroy(GpsTracker.java:126)

05-15 00:41:06.925: E/AndroidRuntime(4471):     at android.app.ActivityThread.handleStopService(ActivityThread.java:2069)
05-15 00:41:06.925: E/AndroidRuntime(4471):     ... 10 more

And in my code here in the service wakelock exists:

public void onCreate() {
        super.onCreate();
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DoNotSleep");
}
public void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();

     wakeLock.release();

    }
public int onStartCommand(Intent intent, int flags, int startId) {
    // Here there's some calculations with the intent

        return START_REDELIVER_INTENT;

    }
private void UpdateWithNewLocation(final Location loc) {
//Some commands and then .....
 stopSelf(); 
}

What can I do with that crash of wakelock? thanks.

mynavy
  • 81
  • 2
  • 9
  • You need to call `wakeLock.release();` _before_ `super.onDestroy();` – Onur May 14 '14 at 21:59
  • 1
    @Onur that's certainly wrong advice and wouldn't change a thing – Emanuel Moecklin May 14 '14 at 22:21
  • 1
    @Emanuel Well it is at least good practice. `super.onDestroy();` obviously destroys the service so it must be called last. Just like when you override onCreate you call super first. For the real answer I didn't realized he didn't call `wakeLock.acquire();`. if( wakeLock.isHeld()) { wakeLock.release(); } should do it. – Onur May 14 '14 at 22:32
  • 1
    @EmanuelMoecklin: While "need to" is probably over-stating it, I definitely recommend doing your own cleanup before `super.onDestroy()`. That way, if your own cleanup depends upon something that is affected by `super.onDestroy()`, you're still safe. In practice, this is unlikely to be a problem (I used to call `super.onDestroy()` first, before others pointed out the error of my ways), but it's still a good idea. – CommonsWare May 14 '14 at 22:45
  • @Onur: While `isHeld()` is a good defensive mechanism, in this case, not calling `acquire()` means that the `WakeLock` simply isn't working. If you're not going to `acquire()` the `WakeLock`, don't create it in the first place. – CommonsWare May 14 '14 at 22:46
  • @CommonsWare: "Generally the order doesn't matter, and won't cause a crash. – hackbod" (http://stackoverflow.com/a/4423688/534471). You could argue all day long about the order in onDestroy ;-). I can't recollect ever having an issue related to the order in onDestroy (unlike onCreate where the order is sometimes very important). – Emanuel Moecklin May 15 '14 at 01:44
  • 1
    @Onur good practice maybe but "must be called last" is not correct. and super.onCreate doesn't have to be called first either. The documentation is clear: "Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown". Must call through doesn't mean it has to be the first call (it's not a constructor!) even if it usually is. – Emanuel Moecklin May 15 '14 at 02:00
  • @EmanuelMoecklin just because order doesn't matter right now doesn't mean it always won't. Can you guarantee me that they won't do anything in onDestroy method on the next version of android that won't effect your code? They probably won't but what if they decide to manage wakelocks by themselfs and release all the acquired wakelocks at onDestroy? If they do and you put a wakelock.release() after super.onDestroy() you will get an error even if you acquired it in the first place. – Onur May 15 '14 at 02:48
  • @Onur Maybe "they" decide that you need to call onDestroy at the very end? Exactly because they want to make sure that ALL wake locks are released (because someone clever/devious might decide to acquire a new one after calling through to super.onDestroy()? But unless "they" decide that order matters, it doesn't and everything else is pure speculation. – Emanuel Moecklin May 15 '14 at 03:07
  • @Onur one last thing. If someone decides to define the call order then my guess would be that it's either (1) super.onCreate, this.onCreate(), this.onDestroy(), super.onDestroy() or (2) this.onCreate, super.onCreate(), super.onDestroy(), this.onDestroy() so either the code in this or the one in super should be first & last because that would allow for proper cleanup. – Emanuel Moecklin May 15 '14 at 03:42

2 Answers2

5

You need to acquire the wake lock before you can release it:

http://developer.android.com/reference/android/os/PowerManager.WakeLock.html#acquire()

That's because wake locks are reference counted by default. If a wake lock is reference counted, then each call to acquire() must be balanced by an equal number of calls to release() (and vice versa). If a wake lock is reference counted and you release it more often than you acquire it (in your case you don't acquire it at all), then the WakeLock under-locked exception will be thrown.

http://developer.android.com/reference/android/os/PowerManager.WakeLock.html#setReferenceCounted(boolean)

Your code only creates a wake lock but it never acquires it. In order to balance the count, acquire it in onCreate():

public void onCreate() {
    super.onCreate();

    // this only creates the wake lock without acquiring it
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DoNotSleep");

    // this acquires the wake lock
    wakeLock.acquire();
}
Emanuel Moecklin
  • 28,488
  • 11
  • 69
  • 85
  • I dont see the error now But my service doesnt stop... + – mynavy May 15 '14 at 08:19
  • please look here: http://stackoverflow.com/questions/23674852/wakelock-donotsleep-continue-to-crash – mynavy May 15 '14 at 10:10
  • You already got your answer there. I'd suggest to put the acquire/release at the beginning and the end of onStartCommand. That's where you do all the processing and where the device needs to be awake. – Emanuel Moecklin May 15 '14 at 12:11
3

Before you can release the Wakelock, you must first acquire it

public void onCreate() {
    super.onCreate();
    PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DoNotSleep");

    // ADD THIS LINE
    wakeLock.acquire();
}
user184994
  • 17,791
  • 1
  • 46
  • 52
  • As i said in other comments it did stop the error of app stoped.. But actually the service doesnt stop... Only when i remove wakeLock.acquire(); its stop. – mynavy May 15 '14 at 08:41