java.lang.RuntimeException: WakeLock under-locked C2DM_LIB - android

I have uploaded my application on google play but users have reported the following exception
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.

You didn't post your code, so I don't know if you've already done what I will suggest here,
but I also had that exception and all I added to fix it was a simple "if" to make sure the WakeLock is actually being held, before trying to release it.
All I added in my onPause was this "if" statement (before the "release()"):
if (mWakeLock.isHeld())
mWakeLock.release();
and the exception was gone.

I have traced same exception in new GCM Library too. Actually old C2DM Android library have same error, same crash, and Google hasn't fixed it yet. As I can see by our statistics, about 0.1% of users experiencing this crash.
My investigations shows that problem is in incorrect releasing of network WakeLock in GCM library, when library tries to release WakeLock that holds nothing (internal lock counter becomes negative).
I was satisfied with simple solution - just catch this exception and do nothing, because we don't need to do any extra job then our wakelock hold nothing.
In order to do this you need to import GCM library sources in your project, rather than already compiled .jar file. You can find GCM library sources under "$Android_SDK_Home$/extras/google/gcm/gcm-client/src" folder (you need to download it first using Android SDK Manager).
Next open GCMBaseIntentService class, find line
sWakeLock.release();
and surround it with try-catch.
It should look 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 #fasti in his answer, you can use mWakeLock.isHeld() method to check if wakelock actually holding this lock.

Although the isHeld() solution seems nicer, it can actually fail - because it is not atomic (i.e. not thread safe). If you have more than one thread that might release the lock then between the check (isHeld) and the call to relase another thread may release the lock... and then you fail.
By using try/catch you disguise the bug, but in a thread-safe way.

I don't have this problem as long as I don't reinitialize the wake lock and call acquire on the new Object. You should only keep one instance of wakeLock (so make it a field variable). Then you know you're always releasing 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();

Related

Android: wait for vibrator to finish

Let's say I have async tasks that when finished, lock the vibrator and send it a pattern. In a nutshell, that's the kind of code I'm dealing with:
lock(vib);
vib.vibrate(pattern);
release(vib);
return;
The problem is, the vibration starts and just immediately stops due to the task's returning and I could use some help in changing that.
I have tried
lock(vib);
long duration = getDuration(pattern);
vib.vibrate(pattern);
synchronized(this){
try {
wait(duration);
} catch (InterruptedException e) {
...
}
}
release(vib);
return;
but that doesn't seem to actually do anything.
Since I have not found a way to determine whether or not the phone is currently vibrating, any suggestions on how I should best resolve the issue?

In App Billing v3 IllegalArgumentException using IabHelper

I've had in app billing v3 implemented in my app for about a week now. I used a lot of android's sample code to simplify the integration. I've been logging a crash fairly often that I can't seem to reproduce:
Exception Type: java.lang.RuntimeException
Reason: Unable to destroy activity {[package].billing.BillingActivity}: java.lang.IllegalArgumentException: Service not registered: [package].billing.util.IabHelper$1#40646a70
It seems to be breaking on this line:
if (mContext != null) mContext.unbindService(mServiceConn);
I'm binding this service in my onCreate method and disposing it in my onDestroy method (which is where this error is logged). Any pointers?
You could replace the line you mentioned:
if (mContext != null) mContext.unbindService(mServiceConn);
by this line
if (mContext != null && mService != null) mContext.unbindService(mServiceConn);
This should do the trick
I checked out the latest version of the sample project and up to today my recommendation is to currently to NOT use IabHelper. It is massively flawed.
To give you an idea:
1.) the async methods of IabHelper start a new thread. If IabHelper.dispose() is called while a thread is running you will always get various exceptions you cannot even handle.
2.) If the connection to the billing service goes down, they set it to null. But apart from that they never check if mService is null before accessing the methods. So it will always crash with NullPointerException in this case.
public void onServiceDisconnected(ComponentName name) {
logDebug("Billing service disconnected.");
mService = null;
and this is just the tip of the ice berg. Seriously I do not understand how somebody can publish this as reference code.
I just encountered the same issue but on android emulator. Billing v3 requires that Google Play app should be launched at least once and since the emulator lack of Google Play app it cannot set up helper and cannot dispose it in onDestroy().
My personal workaround is just skipping that error in try/catch:
#Override
protected void onDestroy() {
super.onDestroy();
if (bHelper != null){
try {
bHelper.dispose();
}catch (IllegalArgumentException ex){
ex.printStackTrace();
}finally{}
}
bHelper = null;
}
Add this in every onDestroy() where you dispose helper. Works fine for me.
The IabHelper class is working in a normal way.
What you need to do is:
when you call startSetup for the helper, you need to pass a callback IabHelper.OnIabSetupFinishedListener which will tell you the result of starting setup. If you get failure in the callback, the service connection with the google play services was not established.
You should handle future calls to IabHelper depending upon the result received in IabHelper.OnIabSetupFinishedListener. You can surely keep a boolean field to know what was the status.
The answer sam provided is actually a trick (in his own words). The helper classes aren't supposed to throw exceptions so that the user of those classes can implement some task in such scenarios.
And of-course, try/catch is best way if you don't want to go in details (whenever anything breaks due to exception, surely first thing which comes in mind is to put that in a try/catch block).

TextToSpeech.setEngineByPackageName() triggers NullPointerException

My activity's onInit() contains a call to TextToSpeech.setEngineByPackageName():
tts = new TextToSpeech(this, this);
tts.setEngineByPackageName("com.ivona.tts.voicebeta.eng.usa.kendra");
It works on an Android 2.2.2 device, but on an Android 2.3.4 device it produced a NullPointerException, with the following stack trace:
E/TextToSpeech.java - setEngineByPackageName(3423): NullPointerException
W/System.err(3423): java.lang.NullPointerException
W/System.err(3423): at android.os.Parcel.readException(Parcel.java:1328)
W/System.err(3423): at android.os.Parcel.readException(Parcel.java:1276)
W/System.err(3423): at android.speech.tts.ITts$Stub$Proxy.setEngineByPackageName(ITts.java:654)
W/System.err(3423): at android.speech.tts.TextToSpeech.setEngineByPackageName(TextToSpeech.java:1356)
Since I am providing a hard-coded string parameter, I know that the parameter isn't what's causing the NullPointerException.
I also know that setEngineByPackageName() is deprecated but that's only since API 14, so this couldn't be the reason.
Any idea what could be causing this NullPointerException?
EDIT: I wouldn't have been concerned with the "why" if this didn't result in an endless bombardment of:
I/TextToSpeech.java(3652): initTts() successfully bound to service
Followed by calls to onInit() (by the system, not by my code).
My hope is that if I underderstand why this is happening, I can stop the bombardment of onInit()s and recover gracefully from the error.
Is the TTS engine you are referencing installed on the 2.3.4 device? If it is, it might be a platform bug.
EDIT:
Don't remember what results I got when I did this, but calling setEngineByPackageName() when the package doesn't exists is not a good idea. Check if it is installed and don't try to use it if it's not. Something like:
boolean isPackageInstalled(String packageName) {
PackageManager pm = context.getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(packageName, 0);
return pi != null;
} catch (NameNotFoundException e) {
return false;
}
}
Attempting to investigate this myself, in case an expert on the subject isn't around:
The NullPointerException stack trace is printed by setEngineByPackageName() itself in the catch handler for this try clause:
try {
result = mITts.setEngineByPackageName(enginePackageName);
if (result == TextToSpeech.SUCCESS){
mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
}
}
Which suggests that either of the following is null:
mITts
mCachedParams
mCachedParams is unlikely to be the null one because it is initialized in the constructor. So this leaves us with mITts:
If I examine TextToSpeech.initTts() I can easily spot 2 points in which mITts can remain null:
onServiceConnected()
onServiceDisconnected()
But why this is happening only on the 2.3.4 device? This is still a mystery.
Possible clue: The method TextToSpeech.initTts() ends with the following comment:
mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
// TODO handle case where the binding works (should always work) but
// the plugin fails
Which may explain why I receive a barrage of onInit()s ("initTts() successfully bound to service"): Binding always works, but since the package is not installed, "the plugin fails".
The question now is how to stop this endless loop...

How to abort LocalServerSocket.accept

How to abort/interrupt a LocalServerSocket waiting, in a background thread, for a connection in method LocalServerSocker.accept() ?
I've tried to call close() method from another thread, but it does not seem to work.
There is a ticket opened for it in Android project: http://code.google.com/p/android/issues/detail?id=29939.
Seems the problem is confirmed by Google, as the first comment is:
i think we should rewrite this to use the same underlying libcore
stuff, and get the interruption behavior for free.
The workaround can be to send a custom shutdown command to the LocalServerSocket from another thread to unblock accept.
Instead of localSocket.close, use this: (requires API 21+)
try {
Os.shutdown(localSocket.fileDescriptor, OsConstants.SHUT_RDWR)
} catch (e: ErrnoException) {
if (e.errno != OsConstants.EBADF) throw e // suppress fd already closed
}

Null pointer exception reports in C2DMBaseReceiver class (from marketplace)

I have C2DM implemented in my app, I see a decent number of crash reports in the marketplace caused by a null pointer exception in the C2DMBaseReceiver class. This class is from the chrometophone project, which is referenced in the C2DM guide (http://code.google.com/android/c2dm/):
http://code.google.com/p/chrometophone/source/browse/trunk/android/c2dm/com/google/android/c2dm/C2DMBaseReceiver.java
The npe happens in onHandleIntent(), mWakeLock is sometimes null:
// From C2DMBaseReceiver.java:
#Override
public final void onHandleIntent(Intent intent) {
try {
Context context = getApplicationContext();
if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {
handleRegistration(context, intent);
} else if (intent.getAction().equals(C2DM_INTENT)) {
onMessage(context, intent);
} else if (intent.getAction().equals(C2DM_RETRY)) {
C2DMessaging.register(context, senderId);
}
} finally {
// Release the power lock, so phone can get back to sleep.
// The lock is reference counted by default, so multiple
// messages are ok.
// If the onMessage() needs to spawn a thread or do something else,
// it should use it's own lock.
//
//
//
// NULL POINTER EXCEPTION REPORTS HERE
mWakeLock.release();
//
//
//
}
}
The fix is easy enough, just check for mWakeLock != null before accessing it. But I wonder if anyone else has seen this, if the docs should be updated with this check? Or maybe this is a bigger problem, if the author expected mWakeLock to always be initialized?
Thanks
I put a null check in that line, just moved the error a bit:
java.lang.RuntimeException: WakeLock under-locked C2DM_LIB
at android.os.PowerManager$WakeLock.release(PowerManager.java:304)
at android.os.PowerManager$WakeLock.release(PowerManager.java:279)
at com.google.android.c2dm.C2DMBaseReceiver.onHandleIntent(C2DMBaseReceiver.java:122)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:59)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.os.HandlerThread.run(HandlerThread.java:60)
Still no idea how to fix this.
According to Mark Murphy, who helped develop this code, there are scenarios where this error will occur, even if your code is entirely correct. See this Google Groups thread for his explanation - either the lock wasn't acquired to start with or was acquired in a different process.
If you get this exception persistently then you likely have a defect. Check (using diagnostics) to see if the same process is acquiring the wake lock as the one that is releasing it.
There is a new class in the support library, WakefulBroadcastReceiver , that helps with the hand off of a wake lock between broadcaster and receiver.
The new GCM implementation instructions specify its use: http://developer.android.com/google/gcm/client.html

Categories

Resources