[ACCEPTED]-java.lang.RuntimeException: WakeLock under-locked C2DM_LIB-google-cloud-messaging

Accepted answer
Score: 191

You didn't post your code, so I don't know 6 if you've already done what I will suggest 5 here, but I also had that exception and 4 all I added to fix it was a simple "if" to 3 make sure the WakeLock is actually being held, before trying to release it.

All I added in my onPause was this "if" statement 2 (before the "release()"):

if (mWakeLock.isHeld())
    mWakeLock.release();

and the exception 1 was gone.

Score: 64

I have traced same exception in new GCM 22 Library too. Actually old C2DM Android library 21 have same error, same crash, and Google 20 hasn't fixed it yet. As I can see by our 19 statistics, about 0.1% of users experiencing 18 this crash.

My investigations shows that 17 problem is in incorrect releasing of network 16 WakeLock in GCM library, when library tries to release 15 WakeLock that holds nothing (internal lock counter 14 becomes negative).

I was satisfied with simple 13 solution - just catch this exception and 12 do nothing, because we don't need to do 11 any extra job then our wakelock hold nothing.

In 10 order to do this you need to import GCM 9 library sources in your project, rather 8 than already compiled .jar file. You can find 7 GCM library sources under "$Android_SDK_Home$/extras/google/gcm/gcm-client/src" folder 6 (you need to download it first using Android 5 SDK Manager).

Next open GCMBaseIntentService class, find line

sWakeLock.release();

and 4 surround it with try-catch.

It should look 3 like this:

    synchronized (LOCK) {
        // sanity check for null as this is a public method
        if (sWakeLock != null) {
            Log.v(TAG, "Releasing wakelock");
            try {
                sWakeLock.release();
            } catch (Throwable th) {
                // ignoring this exception, probably wakeLock was already released
            }
        } else {
            // should never happen during normal workflow
            Log.e(TAG, "Wakelock reference is null");
        }
    }

UPDATE: Alternativally, as suggested 2 @fasti in his answer, you can use mWakeLock.isHeld() method to check 1 if wakelock actually holding this lock.

Score: 5

Although the isHeld() solution seems nicer, it 8 can actually fail - because it is not atomic 7 (i.e. not thread safe). If you have more 6 than one thread that might release the lock 5 then between the check (isHeld) and the 4 call to relase another thread may release 3 the lock... and then you fail.

By using try/catch 2 you disguise the bug, but in a thread-safe 1 way.

Score: 1

I don't have this problem as long as I don't 5 reinitialize the wake lock and call acquire 4 on the new Object. You should only keep 3 one instance of wakeLock (so make it a field 2 variable). Then you know you're always releasing 1 that one wakeLock.

So....

 if (mWakeLock == null) {
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
                | PowerManager.ON_AFTER_RELEASE, "MyWakeLock");
    }

try{
        mWakeLock.release();//always release before acquiring for safety just in case
    }
    catch(Exception e){
        //probably already released
        Log.e(TAG, e.getMessage());
    }
    mWakeLock.acquire();

More Related questions