ModernAsyncTask IllegalStateException - android

We are using AsyncTaskLoaders in our app, to load the content. We are getting this crash
java.lang.IllegalStateException: Cannot execute task: the task is already running.
at android.support.v4.content.ModernAsyncTask.doInBackground(ModernAsyncTask.java:414)
at android.support.v4.content.AsyncTaskLoader.executePendingTask(AsyncTaskLoader.java:219)
at android.support.v4.content.AsyncTaskLoader.dispatchOnCancelled(AsyncTaskLoader.java:232)
at android.support.v4.content.AsyncTaskLoader$LoadTask.onCancelled(AsyncTaskLoader.java:88)
at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:464)
at android.support.v4.content.ModernAsyncTask.access$400(ModernAsyncTask.java:48)
at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:483)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:211)
at android.app.ActivityThread.main(ActivityThread.java:5335)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1016)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:811)
We have tried to reproduce this, but haven't been successful!
Is there a way to find out which Loader that is causing this?
We are using
com.android.support:support-v4:23.0.1
We are looking into the possibility that this might have a link to Activity Leaks, other than that, this is all the info we are getting.
Any ideas?

I'm still hunting this error as I can't reproduce it myself, but I believe I found the cause (at least for my case, but I have to release and see if it helps).
Turns out that when creating the observer on my loader I passed the handler as null, expecting similar beheavior as I would get if I use the default constructor for Handler (for it to run on the main thread, the thread I was creating it from).
However what happens is that it calls onChange inmediately, from whatever thread.. onChange at least in my case calls the loader's onContentChanged, that is documented to need to be called from the main thread... as that's not the case, the task and cancellationTask get screwed up (for lack of a better technical term) which causes the cancellation to be triggered in an unexpected state of the task, hence the error message.
This also manifested in my case as the loader not correctly updating entries, the cancellationTask was already loaded with a value, so the loader discarded new tasks, so the new load was skipped (takeContentChanged was false).
So make sure you are initializing your observer using new Handler() from the main thread (onStartLoading should be a fine place to do it).

Propably you have in your activity, or wrapper class reference to async task. If you have execution of this task in onClick. You can tap two times on View and you get this error.
Update
If you want to check if activity has leaked , you can use Leak Canary. This is very useful tool.
Leak canary
You can use StrictMode for finding information about leaks.
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}

Related

IllegalThreadStateException OneSignal crash workaround

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.

use ExecutorService occur out of memory on android

I use ExecutorService. but sometimes occur OutOfMemoryError
error log.
java.lang.OutOfMemoryError: pthread_create (1040KB stack) failed: Try again
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:921)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1339)
at kr.co.iosystem.blackeyeonandroid.m4m.domain.CapturePipeline.executeProcessor(CapturePipeline.java:195)
at kr.co.iosystem.blackeyeonandroid.m4m.domain.CapturePipeline.start(CapturePipeline.java:156)
at kr.co.iosystem.blackeyeonandroid.record.VideoCapture.start(VideoCapture.java:92)
at kr.co.iosystem.blackeyeonandroid.record.Capturing.startCapturing(Capturing.java:97)
at kr.co.iosystem.blackeyeonandroid.record.RecTimerHandler.startRecording(RecTimerHandler.java:221)
at kr.co.iosystem.blackeyeonandroid.record.RecTimerHandler.handleMessage(RecTimerHandler.java:83)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5415)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:745)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:635)
and my source
protected ExecutorService pools;
public void start() {
pools = Executors.newCachedThreadPool();
executeProcessor();
}
protected void executeProcessor() {
pools.execute(new Runnable() {
#Override
public void run() {
...
}
}
}
first, pools = Executors.newCachedTheadPool(); previously pools = Executors.newSingleThreadExecutor();
usually, this situation. how to fix OutOfMemory when I use ExecutorService on android?
if you know this problem. please advice for me
thanks
The cachedThreadPoolExecutor() will create a potentially unbounded (infinite) number of threads given new tasks. I am not sure what you have included in you run() method, however if it has a for loop/while loop or any other mechanism that spawns new work, it will automatically create a new thread costing you memory. This is what could potentially lead you to the OutOfMemoryException you are receiving.
To diagnose, try using a fixedThreadPool(int numOfThreads) with a low (bounded) number of threads e.g. 4 and see if you still get the error.
If yes, then consider what the run method is doing to consume memory
If no, then you now know that the number of threads the cachedThreadPoolExecutor() was creating was problematic, try decompose your tasks to use fewer threads. Try finding that sweet spot of thread count/ memory usage/ performance , this kind of stuff is usually about management and there rarely is a one-size fits all approach.

CursorWindowAllocationException thrown in SyncAdapter

I occasionally get the following exception thrown in my SyncAdapter class. I think that I am closing all cursors correctly. Can there be any other explanation for why this exception is being thrown? Or am I definitely missing a cursor.close() somewhere?
Fatal Exception: android.database.CursorWindowAllocationException: Cursor window could not be created from binder.
at android.database.CursorWindow.<init>(CursorWindow.java:150)
at android.database.CursorWindow.<init>(CursorWindow.java:42)
at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:698)
at android.database.CursorWindow$1.createFromParcel(CursorWindow.java:696)
at android.database.BulkCursorDescriptor.readFromParcel(BulkCursorDescriptor.java:75)
at android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:34)
at android.database.BulkCursorDescriptor$1.createFromParcel(BulkCursorDescriptor.java:30)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:424)
at android.content.ContentProviderClient.query(ContentProviderClient.java:161)
at android.content.ContentProviderClient.query(ContentProviderClient.java:123)
at com.forever.forever.Utils.sync.SyncAdapter.getNextItemInUploadQueue(SyncAdapter.java:799)
at com.forever.forever.Utils.sync.SyncAdapter.proccessUploads(SyncAdapter.java:697)
at com.forever.forever.Utils.sync.SyncAdapter.onPerformSync(SyncAdapter.java:199)
at android.content.AbstractThreadedSyncAdapter$SyncThread.run(AbstractThreadedSyncAdapter.java:272)
I was able to find an additional closable leaks by adding the following snippet to my application onCreate():
if(BuildConfig.DEBUG){
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.build());
}
It logged a couple leaks that I was able to fix. This is an EXTREMELY helpful development tool.

Finding what violated StrictMode policy

I've enabled StrictMode in my app and it's causing a few crashes as expected.
How can I find out where in my code I'm violating these policies?
This is the stack trace:
E/AndroidRuntime(19523): FATAL EXCEPTION: main
E/AndroidRuntime(19523): android.os.StrictMode$StrictModeViolation: policy=95 violation=2
E/AndroidRuntime(19523): at android.os.StrictMode.executeDeathPenalty(StrictMode.java:1326)
E/AndroidRuntime(19523): at android.os.StrictMode.access$1300(StrictMode.java:111)
E/AndroidRuntime(19523): at android.os.StrictMode$AndroidBlockGuardPolicy.handleViolation(StrictMode.java:1319)
E/AndroidRuntime(19523): at android.os.StrictMode$AndroidBlockGuardPolicy$1.run(StrictMode.java:1206)
E/AndroidRuntime(19523): at android.os.Handler.handleCallback(Handler.java:605)
E/AndroidRuntime(19523): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(19523): at android.os.Looper.loop(Looper.java:137)
E/AndroidRuntime(19523): at android.app.ActivityThread.main(ActivityThread.java:4424)
E/AndroidRuntime(19523): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(19523): at java.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime(19523): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:787)
E/AndroidRuntime(19523): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:554)
E/AndroidRuntime(19523): at dalvik.system.NativeStart.main(Native Method)
but as you can see ... it's not very useful ... I know who killed my app, I need to know why!
Thanks.
You need to call penaltyLog() on your StrictMode.ThreadPolicy.Builder, so that it will show you the underlying reason as well as stopping your app.
Here's what you probably have currently:
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyDeath()
.build());
If you call the network on the main thread, you'll get this exception which is hard to understand:
E/AndroidRuntime(8752): android.os.StrictMode$StrictModeViolation: policy=71 violation=4
E/AndroidRuntime(8752): at android.os.StrictMode.executeDeathPenalty(StrictMode.java:1311)
If you then add penaltyLog() to your policy...
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyDeath()
.build());
then you will see a much more helpful message like the one below. This will be in the LogCat output.
D/StrictMode(8810): StrictMode policy violation; ~duration=2956 ms: android.os.StrictMode$StrictModeNetworkViolation: policy=87 violation=4
D/StrictMode(8810): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1090)
If you look closely, you'll see that this stack trace will lead you to the code which is causing the StrictMode violation.
StrictMode (android.os.StrictMode) class can be used to enable and enforce various policies that can be checked for and reported upon.
This can be a StrictMode violation in executing a disk write violation that occurs when you are performing disk writes on the main UI thread. To solve it, you need to move the disk writes off the main thread.
If you can't move the code at this point, you could disable the check for a part of the code.
Explicitly add code to stop checking for a particular rule violation just before the offending code is executed and then re-enable detection for that rule after the offending code has completed.
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
.permitDiskWrites()
.build());
doCorrectStuffThatWritesToDisk();
StrictMode.setThreadPolicy(old);
Source code taken from here.
Whenever I see stack traces like this I always look into my Activity lifecycle events. Checkout what's going on in your onCreate, onResume, onPause methods (there are more lifecycle events but these are the common ones). Put break points in those methods and see which one terminates with this fatal message. Then take it from there.
Try catching this error using
protected void onResume() {
super.onResume();
try {
codeThatCrashesBecauseOfStrictMode();
} catch(Throwable tr) { Log.e(tr); }
}
This should be a pretty good starting point for debugging this problem.
even though this does nothing to understand root cause, would it help you to simply add "strict=False" to your Library definition? (note that my context is Robot Framework *** Settings *** where I include "Browser" library): eg:
Library Browser strict=False

Android StrictMode InstanceCountViolation

I am running my app with StrictMode activated in development as documented here StrictMode for lower platform versions
and noticed an error message that I do not know what to think about nor can I find any reference.
I get a android.os.StrictMode$InstanceCountViolation with values for instances and limit e.g.
instances=3; limit=2
Now I am wondering:
A) how is the limit calculated
B) how can such a violation actually happen and then I would look into evasive actions.
Any ideas?
It's all in the code
The key is StrictMode.sExpectedActivityInstanceCount and incrementExpectedActivityCount and decrementExpectedActivityCount:
Increment is called in ActivityThread.performLaunchActivity
just after creating the Activity instance.
Decrement is called in ActivityThread.performDestroyActivity
after the activity has been removed from the application.
So the limit is less each time an activity is destroyed, however if an instance is leaked the real instance count will be bigger than the limit, to detect if it's leaked they do some GC magic (in decrementExpectedActivityCount):
System.gc();
System.runFinalization(); // added in https://github.com/android/platform_frameworks_base/commit/6f3a38f3afd79ed6dddcef5c83cb442d6749e2ff
System.gc();
if after this the GC didn't remove the activity from the app's memory it is considered a leak.
Conclusion
Based on the above the only way to prevent is to make sure there are no references to the offending activity after onDestroy. The problem is that some there may be some WeakReferences which are still accessible through some native objects, which seem to have a different lifecycle. Here's how I came to this conclusion:
after backing out from MyActivity and seeing the log message
make a heap dump (.hprof)
open it in Eclipse Memory Analyzer
run OQL: select * from instanceof full.package.name.of.MyActivity
select all with Ctrl+Click or Shift+Click
right click and Merge Shortest Path to GC Roots > with all references
Workaround
If we increase the count initially we'll have more legroom before it reports the leak for specific classes:
// Application.onCreate or nearby where you set up StrictMode detectActivityLeaks
Method incrementExpectedActivityCount = StrictMode.class.getMethod("incrementExpectedActivityCount", Class.class)
incrementExpectedActivityCount.invoke(null, MyActivity.class);
incrementExpectedActivityCount.invoke(null, MyActivity2.class);
Further reading
WeakReferences
Eclipse Memory Analyzer (MAT)
History of StrictMode
It seems there might be a bug in the StrictMode checking on some devices.
If an Activity is started, and exited and restarted very quickly, you can get a StrictMode.InstanceCountViolation.
However this is simply because the garbage collector has not yet finalized the first instance of the Activity, meaning there are temporarily 2 (or more) instances in memory.
Calling System.gc() before startActivity() or startActivityForResult() will stop the StrictMode.InstanceCountViolation.
This seems to indicate a bug (or perhaps a feature?) in the StrictMode checking.
Here is a discussion on google groups about handling the StrictMode InstanceCountViolation. It looks like every different Android version has a different policy so they seem to just disable it. Also the Android docs say about Strict Mode
But don't feel compelled to fix everything that StrictMode finds. In particular, many cases of disk access are often necessary during the normal activity lifecycle. Use StrictMode to find things you did by accident. Network requests on the UI thread are almost always a problem, though.
I think that is what #sri is trying to show with his code.
public class MyApplication extends Application {
#Override
public void onCreate (){
super.onCreate();
// when you create a new application you can set the Thread and VM Policy
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() // API level 11, to use with StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyFlashScreen() // API level 11
.build());
//If you use StrictMode you might as well define a VM policy too
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() // API level 11
.setClassInstanceLimit(Class.forName(“com.apress.proandroid.SomeClass”), 100)
.penaltyLog()
.build());
}
}
My understanding is that this violation is used to detect memory leaks. So at that point you should only have 2 instances of the class loaded, but the VM found 3.
I have seen this violation in my code also, but my extra instances were all referenced by weak pointers. So I choose to disable this rule.
see the below example it varies based on android version
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectCustomSlowCalls() // API level 11, to use with StrictMode.noteSlowCode
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.penaltyFlashScreen() // API level 11
.build());
// not really performance-related, but if you use StrictMode you might as well define a VM policy too
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects() // API level 11
.setClassInstanceLimit(Class.forName(“com.apress.proandroid.SomeClass”), 100) // API level 11
.penaltyLog()
.build());
}
}
Remove the line below from on create.
//StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().penaltyDeath().detectLeakedSqlLiteObjects().build());

Categories

Resources