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());
Related
I am using OkHttp (first the original verison, then I upgraded to OkHttp3), some users of my App have been reporting significant battery life loss when the App isn't running.
I ran a profiler and this is the result:
As you can see, Okio Watchdog is running the whole time. At roughly the halfway point, my App is fully in the background. There are no HTTP tasks taking place at this point in time. I started profiling after the last HTTP task ended.
Is it normal that the Watchdog runs throughout like that? If so, am I right in assuming this thread is causing a lot of battery waste? If it isn't normal, could something like a leaked Context keep the Watchdog running?
The Watchdog code runs here, it seems like to runs without a termination condition:
private static final class Watchdog extends Thread {
public Watchdog() {
super("Okio Watchdog");
setDaemon(true);
}
public void run() {
while (true) {
try {
AsyncTimeout timedOut = awaitTimeout();
// Didn't find a node to interrupt. Try again.
if (timedOut == null) continue;
// Close the timed out node.
timedOut.timedOut();
} catch (InterruptedException ignored) {
}
}
}
}
Looks like a severe & unexpected bug in Okio. I'll try to reproduce & fix. If you're able to produce this consistently, please comment on this bug!
https://github.com/square/okio/issues/185
For me it was caused by proguard's optimization. After some investigation - see the okio issue linked above - a workaround (if not final fix?) is to disable optimization or add this to your proguard-rules.pro:
-optimizations !method/marking/static,!method/removal/parameter,!code/removal/advanced
I find a NOTE in this manual
Note: the configuration specifies that none of the methods of class '...' have any side effects
Your configuration contains an option -assumenosideeffects to indicate that the specified methods don't have any side effects. However, the configuration tries to match all methods, by using a wildcard like "*;". This includes methods from java.lang.Object, such as wait() and notify(). Removing invocations of those methods will most likely break your application. You should list the methods without side effects more conservatively. You can switch off these notes by specifying the -dontnote option.
You should specify the method name in the -assumenosideeffects block.
I add this comment at https://github.com/square/okio/issues/185#issuecomment-220520926
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();
}
I am using a simple conditional check on Build.Version.SDK_INT in the onCreate method of my application (code below) to prevent strict mode being enabled on any Android OS earlier than 2.3. Up until recently this had been working fine, but after a re-jig of my project, I receive the following error:
Could not find class 'android.os.StrictMode$ThreadPolicy$Builder', referenced from method com.myPackage.MyApp.onCreate
I have heard that the way class dependencies were evaluated and loaded changed from a static analysis of the class to a 'lazy loading' system in Android 2.0, but since I am using 2.2, I don't think this is at play. I suspect there is something elsewhere in my project structure that is causing this error, but I am at a loss as to what that might be.
Has anyone here had a similar experience and could maybe shed some light on this? Any help would be gratefully received.
Thanks in advance for your help!
Please see my code below for reference:
public class MyApp extends Application {
#Override
public void onCreate() {
// Set up strict mode
int buildInt = Build.VERSION.SDK_INT;
Log.d(LogTags.TRIGGER_CODE, String.format("Build is %d (%s)", buildInt, Build.VERSION.CODENAME));
if (buildInt >= 9) {
StrictMode.setThreadPolicy(new ThreadPolicy.Builder()
.detectCustomSlowCalls()
.detectNetwork()
.build());
StrictMode.setVmPolicy((new VmPolicy.Builder()
.detectAll()
.build()));
}
super.onCreate();
}
}
This turned out to be just a symptom of another problem elsewhere in code, far too specific to the project to be worth going into here...
Thanks for the thoughts on the root cause here, and sorry for the 'doh' moment :)
When Android's StrictMode detects a leaked object (e.g. activity) violation, it would be helpful if I could capture a heap dump at that moment in time. There's no obvious way, however, to configure it to do this. Does anyone know of some trick that can be used to achieve it, e.g. a way to convince the system to run a particular piece of code just prior to the death penalty being invoked? I don't think StrictMode throws an exception, so I can't use the trick described here: Is there a way to have an Android process produce a heap dump on an OutOfMemoryError?
No exception, but StrictMode does print a message to System.err just before it terminates. So, this is a hack, but it works, and as it's only going to be enabled on debug builds I figure it's fine... :)
in onCreate():
//monitor System.err for messages that indicate the process is about to be killed by
//StrictMode and cause a heap dump when one is caught
System.setErr (new HProfDumpingStderrPrintStream (System.err));
and the class referred to:
private static class HProfDumpingStderrPrintStream extends PrintStream
{
public HProfDumpingStderrPrintStream (OutputStream destination)
{
super (destination);
}
#Override
public synchronized void println (String str)
{
super.println (str);
if (str.equals ("StrictMode VmPolicy violation with POLICY_DEATH; shutting down."))
{
// StrictMode is about to terminate us... don't let it!
super.println ("Trapped StrictMode shutdown notice: logging heap data");
try {
android.os.Debug.dumpHprofData(app.getDir ("hprof", MODE_WORLD_READABLE) + "/strictmode-death-penalty.hprof");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
(where app is a static field in the outer class containing a reference to the application context, for ease of reference)
The string it matches has survived unchanged from gingerbread release all the way up to jelly bean, but it could theoretically change in future versions, so it's worth checking new releases to ensure they still use the same message.
I do have an old app that refuses to work on Android 4.1 devices. It's the NetworkOnMainThreadException that jumps in here.
So I tried to permit this with the following steps - but these don't work. I tested that with the 4.1 emulator. What is really needed to come around that error - app rewrite is no option. Currently I exclude 4.1 devices from my apps.
A class file ...
public class StrictModeWrapper {
static {
try {
Class.forName("android.os.StrictMode");
} catch (Exception exception) {
throw new RuntimeException(exception);
}
}
public static void checkAvailable() {
}
#SuppressLint("NewApi")
public static void setThreadPolicy() {
StrictMode.ThreadPolicy strictModeThreadPolicy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(strictModeThreadPolicy);
}
}
... called in an extended Application class:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
try {
StrictModeWrapper.checkAvailable();
StrictModeWrapper.setThreadPolicy();
} catch (Throwable throwable) {
}
}
}
The extended Application class is registered in the Manifest and working.
Nothing seems to have changed in StrictMode since api 11. It must be the changes in some other android classes you used, that caused a StrictMode policy violation.
The Android documentation itself says
"But don't feel compelled to fix everything that StrictMode finds. "
But since its a NetworkOnMainThreadException you must do a thorough check. See all network communications in your app, and ensure that they are not blocking your main thread.
And make sure you remove/disable the StrictMode code in your release build, as it is only a developer tool to identify accidental mistakes.
Update:
Your app crashed because :
You had not blocked the execution of StrictMode policy setting code in your release build. It should be executed only while testing.
Something changed in the StrictMode class that caused the strict mode policy to reset after onCreate.
I have 2 questions :
Doesnt the crash indicate that the StrictMode policy was working? There was a policy violation and hence it crashed.
Doesnt it indicate that there is some network code in your app that blocks the main thread?
StrictMode behaves different on Android version >= 16 than prior releases. The docs suggest to issue StrictMode calls in onCreate() of an extended Application, Activity, etc.. At least onCreate() in an extended Application works different now and proofes the docs wrong (as of today).
Here's the StrictMode doc that describes how to add StrictMode calls to an extended application for example (that's wrong as of today):
StrictMode
Here's a Google Code issue that describes the problem and gives a workaround:
Google Code Issue 35298