Our app daily receives around 1k crashes based on bug mentioned on OneSignal's github issues.
Bug explanation:
Unfortunately, I can't reproduce this issue. All crashes come from
Crashlytics reports. SDK version 3.12.4
Devices:
1) Samsung: Galaxy A5(2017), Galaxy S8, Galaxy A50, Galaxy S10+, Galaxy S10
2) Xiaomi: Mi A2, Mi A2 lite, Mi A1, Mi A3, Redmi Note 5 Pro
3) Oneplus: ONEPLUS A6010, OnePlus5T, GM191011, GM19008, OnePlus58
Stacktrace:
Caused by java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:724)
at com.onesignal.OneSignalPrefs$WritePrefHandlerThread.startDelayedWrite(OneSignalPrefs.java:117)
at com.onesignal.OneSignalPrefs.startDelayedWrite(OneSignalPrefs.java:183)
at com.onesignal.OneSignal.setAppContext(OneSignal.java:601)
at com.onesignal.OneSignalSyncServiceUtils.doBackgroundSync(OneSignalSyncServiceUtils.java:175)
at com.onesignal.SyncJobService.onStartJob(SyncJobService.java:40)
at android.app.job.JobService$1.onStartJob(JobService.java:62)
at android.app.job.JobServiceEngine$JobHandler.handleMessage(JobServiceEngine.java:108)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:280)
at android.app.ActivityThread.main(ActivityThread.java:6748)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Question:
The main problem is that they tagged it as medium priority and bug exists around 3 months. Our vitals are going for a toss, just because of this issue. It's costing us a lot.
Does there exist any workaround that can temporary solve the problem?
P.S:
I'm ready to provide more related info, if required. Thanks in advance!
It is possible(if not likely) that you have an old version of OneSignal where synchronized void startDelayedWrite() is not synchronized. In this case I would update, and see if that fixes things. If not see the following:
The exception in question occurs here:
synchronized void startDelayedWrite() {
if (mHandler == null) {
start();
mHandler = new Handler(getLooper());
}
//rest of function irrelevant.
The Javadoc for Thread.start,states the following:
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
From this and the implementation of Thread.start, we can infer that the thread in question is being started twice.
For this to be started twice in startDelayedWrite, new Handler(getLooper()) needs to throw an exception, otherwise we won't enter this if statement again. I don't see any way for getLooper() to throw an exception, but new Handler, certainly can if getLooper() is null.
The implementation of getLooper() is as follows:
public Looper getLooper() {
if (!isAlive()) {
return null;
}
//rest omitted b/c irrelevant
The only way the thread in question could have exited is if Thread.run exited early.
The thread's run implementation looks like this:
#Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
Looper.loop, is intended to be a semi-infinite loop which reads from a message queue.
Note the following in Looper.loop:
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
So if msg == null, then our thread exits quickly, possibly causing an exception in mHandler = new Handler(getLooper());, resulting in Thread.start being called twice.
There are other plausible explanations. For example it is possible that Looper.loop crashes at some earlier point.
To mitigate this I would add a try{} finally{} block around mHandler = new Handler(getLooper());, to handle the case where the Looper has already exited. Alternatively I may be wrong and this race condition may be caused by something completely different.
Bug is fixed
The IllegalThreadStateException will no longer be thrown in the
3.13.0 Release. You will now see the root exception being thrown
instead so these crashes can be diagnosed further.
Related
I am getting the above error : System.AggregateException: One or more errors occurred.
With this line of code here:
List<tblDeviceIds> installIDs = KumulosHelper.Functions.Device.GetDeviceIDsOfUser(toUser);
The Method "GetDeviceIdsOfUser" looks like this:
public static List<tblDeviceIds> GetDeviceIDsOfUser(string username)
{
IDictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("username", username);
return KumulosGeneral.getTblDeviceIds("getDeviceIDsOfUser", myDict);
}
So, there is really nothing fancy going on.
Sometimes, but only on CERTAIN users above error. So even when the user would be "null", which by the way he never is, the list would just return nothing. BUT instead it crashes. This itself is something I didnt quite understand, so what I did was:
List<tblDeviceIds> installIDs = null;
try
{
installIDs = KumulosHelper.Functions.Device.GetDeviceIDsOfUser(toUser);
}
catch
{
installIDs = null;
}
This would be a bullet prove workaround, but yet: It goes into try, it crashes, it never goes into catch, it is dead.
Would someone care to explain?
Thanks!
O, maybe this has something todo with doing this on another thread? This is the function that calls all that:
await Task.Run(() =>
{
Intermediate.SendMessageToUser(toUsername, temp);
});
As you can see, it is inside an async task... but that should not be a problem, right?
The reason you receive an AggregateException is because the exception is originating from within a Task (that is likely running on a separate thread). To determine the cause, walk the line of InnerException(s).
Regarding the catch not catching, my suggestions would be: Ensure the latest code is being used. Add Tracing instead of relying on breakpoints. And see if the inner exception is thrown from yet another thread (is GetDeviceIDsOfUser also using async?)
See also: Why is .NET exception not caught by try/catch block?
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...
I'm using Handler and HandlerThread to perform asynchronous loading in my application, but something is going wrong, for example:
handler.postDelayed(new Runnable() {
#Override
public void run() {
.....................
}
}, 100);
this handler wrip (sic) in a new HandlerThread and is created in onCreate().
It seems like that is no problem, however there are times when an error appears, one example of this is a NullPointerException caused on this handler - it is stable before - but when I test on 2.1 version emulator this happen some times and I can't solve it, is thee any one that can help me?
have you considered race conditions in your code? it sounds like the handler code is not performing proper synchonization - and might sometimes see changes from a different thread - which again causes your nullPointer exception.
try wrapping your problem code in a synchonized block - or if you are using primitve types only - move to volatile or atomic types.
Unfortunately I cannot reliably reproduce this error but infrequently I get it and occasionally it gets reported in the live crash logs also. Here's a stacktrace reported by user with Droid 2.2.2 FRG83G
junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertNull(Assert.java:233)
at junit.framework.Assert.assertNull(Assert.java:226)
at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:594)
at java.lang.Thread.run(Thread.java:1096)
This seems to be due to this line in WebViewCore.java
Assert.assertNull(sWebCoreHandler);
Somehow sWebCoreHandler which is private static instance of android.os.Handler is not (Thanks #Idolon for the correction) already initialized but I have no clue how to work around or prevent this issue.
This occurs often enough for me to worry. What is also interesting is seemingly happens when the app is loading Activity that doesn't even have WebView though one of the activities does have it.
P.S. This was filed as bug #16258
Looking at the incriminating source code...
public WebViewCore(Context context, WebView w, CallbackProxy proxy,
Map<String, Object> javascriptInterfaces) {
//....
// We need to wait for the initial thread creation before sending
// a message to the WebCore thread.
// XXX: This is the only time the UI thread will wait for the WebCore
// thread!
synchronized (WebViewCore.class) {
if (sWebCoreHandler == null) {
// Create a global thread and start it.
Thread t = new Thread(new WebCoreThread());
//...
}
}
//...
private static Handler sWebCoreHandler;
// Class for providing Handler creation inside the WebCore thread.
private static class WebCoreThread implements Runnable {
public void run() {
Looper.prepare();
Assert.assertNull(sWebCoreHandler); // this assertion fails
synchronized (WebViewCore.class) {
sWebCoreHandler = new Handler() {
//...
This is executed in the constructor of any WebView and the assertion error comes from the WebCoreThread constructor, which is only called when the sWebCoreHandler is null, so this assertion should never fail... in theory. Except it's ran outside of the synchronized clause and inside a new Thread that is created and started inside a synchronized clause, supposedly only once.
It seems your error is tied to concurrent creation of webviews. If your application has only one activity with one webview, make sure that this activity is not called more often than necessary (=one at a time), that the WebView is created in the onCreate method rather than the activity constructor, that the startActivity is called in the main thread, and you should be good.
I am getting a
NullPointerException at android.app.ActivityThread$PackageInfo$ServiceDispatcher.doConnected(ActivityThread.java:1012)
My application is not even in the stack trace, so I have no idea what is going on.
I am trying to connect to a service when it happens.
How can I fix this problem?
This probably way too old for my response to be of any use, but in case anybody else has this problem, here's what it was for me. I am using a newer version of the SDK, so I'm getting this issue at line 1061.
It was happening to me because I was passing a null ServiceConnection object to the function bindService.
It was helpful to browse the SDK code in my case - although the line numbers don't add up due to version differences, the general code is likely the same (and I knew which method to check):
1097 // If there was an old service, it is not disconnected.
1098 if (old != null) {
1099 mConnection.onServiceDisconnected(name);
1100 }
1101 // If there is a new service, it is now connected.
1102 if (service != null) {
1103 mConnection.onServiceConnected(name, service);
1104 }
mConnection was pretty much the only thing that made sense to be null.