web-dev-qa-db-ja.com

java.lang.RuntimeException:WakeLock under-locked C2DM_LIB

Google Playでアプリケーションをアップロードしましたが、ユーザーから次の例外が報告されました

Java.lang.RuntimeException:WakeLock under-locked C2DM_LIB。この例外は、WakeLockを解放しようとすると発生します。誰でも問題の可能性を伝えることができます。

49
Rookie

新しいGCMライブラリでも同じ例外をトレースしました。実際、古いC2DM Androidライブラリには同じエラー、同じクラッシュがあり、Googleはまだ修正していません。統計によると、ユーザーの約0.1%がこのクラッシュを経験しています。

私の調査では、ライブラリが何も保持していないWakeLock(内部ロックカウンターが負になる)をリリースしようとすると、GCMライブラリのネットワークWakeLockの不正なリリースに問題があることがわかります。

私は単純な解決策に満足しました-この例外をキャッチして何もしません。余分な仕事をする必要がないため、ウェイクロックは何も保持しません。

これを行うには、既にコンパイル済みの_.jar_ファイルではなく、プロジェクトにGCMライブラリソースをインポートする必要があります。 GCMライブラリのソースは、「$ Android_SDK_Home $/extras/google/gcm/gcm-client/src」フォルダーにあります(最初にAndroidを使用してダウンロードする必要があります) SDKマネージャー)。

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

UPDATE:代わりに、 his answer で提案されている@fastiのように、mWakeLock.isHeld()メソッドを使用して確認できますwakelockが実際にこのロックを保持している場合。

54
HitOdessit

コードを投稿しなかったので、ここで提案することを既に行ったかどうかはわかりませんが、その例外もあり、修正するために追加したのはWakeLockを解放する前に、実際にWakeLockが保持されていることを確認してください

OnPauseに追加したのは、この「if」ステートメント(「release()」の前)だけです。

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

例外はなくなりました。

157
fasti

IsHeld()ソリューションはより良いように見えますが、実際には失敗する可能性があります-アトミックではない(つまり、スレッドセーフではない)ためです。ロックを解放する可能性のあるスレッドが複数ある場合、チェック(isHeld)と別のスレッドを解放する呼び出しの間にロックを解放する可能性があります...そして失敗します。

Try/catchを使用すると、バグを偽装できますが、スレッドセーフな方法です。

4
Shoham

ウェイクロックを再初期化し、新しいオブジェクトで取得を呼び出さない限り、この問題は発生しません。 wakeLockのインスタンスを1つだけ保持する必要があります(フィールド変数にします)。そうすれば、常に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();
1
MobileMon