60

我已在 google play 上上传了我的应用程序,但用户报告了以下异常

java.lang.RuntimeException: WakeLock under-locked C2DM_LIB. This exception occurs when I try to release the WakeLock. Can anyone tell what could be the problem.

4

4 回答 4

188

你没有发布你的代码,所以我不知道你是否已经完成了我在这里建议的操作,但我也有这个异常,我添加的所有修复它都是一个简单的“如果”以确保 WakeLock在试图释放它之前实际上是被持有的

我在 onPause 中添加的只是这个“if”语句(在“release()”之前):

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

异常消失了。

于 2013-02-19T03:32:01.280 回答
64

我也在新的 GCM 库中发现了同样的异常。实际上旧的 C2DM Android 库有同样的错误,同样的崩溃,谷歌还没有修复它。从我们的统计数据中可以看出,大约 0.1% 的用户经历了这次崩溃。

我的调查表明问题在于WakeLockGCM 库中网络的错误释放,当库尝试释放WakeLock不包含任何内容时(内部锁计数器变为负数)。

我对简单的解决方案很满意——只要捕获这个异常,什么都不做,因为我们不需要做任何额外的工作,然后我们的唤醒锁就什么也不做。

为此,您需要在项目中导入 GCM 库源,而不是已经编译的.jar文件。您可以在“ $Android_SDK_Home$/extras/google/gcm/gcm-client/src ”文件夹下找到 GCM 库源(您需要先使用 Android SDK Manager 下载它)。

下一节公开GCMBaseIntentService课,找线

sWakeLock.release();

并用try-catch包围它。

它应该如下所示:

    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");
        }
    }

更新: 或者,正如@fasti 在他的回答中所建议的那样,您可以使用mWakeLock.isHeld()方法来检查唤醒锁是否实际持有此锁。

于 2012-08-27T12:30:57.190 回答
4

尽管 isHeld() 解决方案看起来更好,但它实际上可能会失败——因为它不是原子的(即不是线程安全的)。如果您有多个线程可能会释放锁,那么在检查 (isHeld) 和调用释放另一个线程之间可能会释放锁......然后您就会失败。

通过使用 try/catch,您可以伪装错误,但以线程安全的方式。

于 2014-06-05T10:39:06.470 回答
1

只要我不重新初始化唤醒锁并在新对象上调用获取,我就没有这个问题。您应该只保留一个 wakeLock 实例(因此将其设为字段变量)。然后你知道你总是释放那个唤醒锁。

所以....

 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();
于 2014-07-12T17:33:30.927 回答