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
Related
Currently trying to obtain profile trace logs files for a huge Android app, that we have instrumented on MyApplication class, following the documentation about instrumenting my app to get trace logs.
We are trying to dig into what happens when our app is initialized and Dagger2 creates the object graph when the app is started.
A cold startup can take a few seconds normally, the issue I have is that when I add the Debug traces, it dramatically slows down the initialization of the app, making it crash with an ANR message.
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$$$_Thread: main (state = RUNNABLE)
I would like to know if there is a way to prevent the Android OS from crashing my app when it blocks for a long period of time, or to at least increase the ANR threshold.
Any help or tips are welcome. Thanks!
For further context, this is roughly what I am doing in my MyApplication.class:
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("MyApp_onCreate()");
injectSelf();
AppInit.initApp(this);
Debug.stopMethodTracing();
}
Actually, it turns out we have our own ANRWatchDogManager which I wasn't aware of, where I can extend the limit.
public class ANRWatchDogManager implements ANRWatchDog.ANRListener {
Somewhere in that class:
public void startANRWatchDog() {
final int timeoutInterval = isDebugBuild() && isEmulator()
? ANR_INCREASED_TIMEOUT
: ANR_DEFAULT_TIMEOUT;
new ANRWatchDog(timeoutInterval).setANRListener(this).start();
}
As we all know android doesn't unload *.so after close application. I had found the solve by adding "exit(0)" at the end, that is solved problem, but I wanna know exactly that all are OK.
The code is work fine as expected after solving the problem:
static int value = 0;
// In android_main
LOGI("value = %d", value); // always print 0, but not 1 after second run of
// application as it was without "exit(0)" at the end
value = 1;
I wanna to test that on class like:
class A {
A() {
LOGI("Constructor");
}
~A() {
LOGI("Destructor");
}
statis A a;
In such way prints only "Constructor".
Maybe because of destructor is calling after when LOGI isn't working more for application that will be closed ?
Question: why LOGI in destructor isn't working? According to first example on top destructor is calling really.
This is not only pointless, but quite possibly counterproductive. If android wants the memory utilized by your process, it will terminate the process to reclaim it; if it doesn't, it won't.
To specifically address your question, killing or exiting a process does not invoke destructors, it merely terminates execution and the kernel bulk-releases all memory and (conventional) resources.
Do not try to second guess the system, as that can frequently result in killing a process only to have android immediately restart it. Further, it can allegedly cause problems with a few Android IPC resources (like the camera) which may not be freed up when the process of a utilizing application unexpectedly dies.
Thanks to Proguard's optimization features I am now able to do as much debug-logging as I which in my code - for production I simply let it strip all this unnecessary code.
That is fine and works (with the latest Proguard version).
But: before I went this way, I had my final static boolean DEBUG constant that "guarded" all my Log.d/Log.v calls. To ensure I did not forget to disable that for signed production apk's, I just had an easily visible add on in my UI main activity that in some corner put an ugly text "DEBUG IS ON".
So, when producing my final apk, all I had to do is install it once - in case I forgot to switch debug mode off, I was reminded by that.
Now, with Proguard doing the work of removing debug-log-calls: how could I DETECT that in my app and control a UI element that states "DEBUG IS ON"?
Any idea?
My first attempt was to try this:
boolean loggingEnabled = false;
Log.d(TAG, (loggingEnabled = true) ? "Logging test" : "");
And I hoped that Proguard would also remove the assignment loggingEnabled=true- but I underestimated Proguard. It removes the call to Log.d, but still does the assignment... :)
You can do a few things:
Check the mapping.txt in proguard's output folder: grep -E '(android/util/|de/ub0r/android/logg0r/)Log.[dv]' */build/proguard/release/dump.txt
Run the app and check if any d/v log is printed.
Decompilte the app and look at the source code for calls to Log.d() and Log.v().
I build a simple wrapper library to make it a little bit more handy:
https://github.com/felixb/ub0rlogg0r
--- EDIT ---
To Check if your logs got stripped, do the following:
Fork ub0rlogg0r.
Add a public static boolean sHasDebugCalls = false; to Log.
Add sHasDebugCalls = true to all the Log.d() and Log.v() methods.
Place a Log.d(TAG, "has debug logs") somewhere in the very beginning of your app.
When creating your UI, test for Log.sHasDebugCalls to decide visibility of the DEBUG reminder.
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 would to know whether logging can decrease application performance?
Also, please give me some tips to increase android application performance.
Yes. Excessive logging affects the performance of any application not just Android.
The developer guide suggests you to deactivate and disabled logging before release:
Turn off logging and debugging Make sure you deactivate logging and
disable the debugging option before you build your application for
release. You can deactivate logging by removing calls to Log methods
in your source files. You can disable debugging by removing the
android:debuggable attribute from the tag in your
manifest file, or by setting the android:debuggable attribute to false
in your manifest file. Also, remove any log files or static test files
that were created in your project.
Also, you should remove all Debug tracing calls that you added to your
code, such as startMethodTracing() and stopMethodTracing() method
calls.
So, you should suppress the logs in "release" or "production" build of your App.
Turn off it in Android Manifest by setting debuggable:
<application android:icon="#drawable/icon"
android:label="#string/app_name"
android:debuggable="false">
Another way
Create your own logger class and check for debugging mode before executing log. It allows single point modification between debugging mode and deployed application and allows extra things to do such as writing to log file.
import android.util.Log;
public class MyLog {
private static final boolean isDebug = false;;
public static void i(String tag, String msg) {
if (isDebug) {
Log.i(tag, msg);
}
}
public static void e(String tag, String msg) {
if (isDebug) {
Log.e(tag, msg);
}
}
}
For further info read http://rxwen.blogspot.com/2009/11/logging-in-android.html
and The SO QAs :
Log.d and impact on performance
Android Logging - How to clear for better performance
use 'if' statement before log writing.
you can disable log when application release.
example :
public class LogTest extends Activity {
private static final String TAG = "YOUR_LOG_TAG_NAME";
private static final boolean mDebug = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//--[Start Log example]-----------------------------------------
if(mDebug) Log.d(TAG, "Log Write Test");
//--[End Log example]-----------------------------------------
}
}
Any text output in excess will slow down your application, even with a desktop application. Excessive logging does slow things down, but you would basically need an insane amount of data being sent through, which by the way, isn't that hard to do with a for or while loop. Things that happen in the background while logging sometime include string manipulation, text rendering, cache management, data filtering, log length limiting, and the list goes on.
There's several ways to remove logcat from your final app, especially those involving ProGuard. ProGuard didn't work for me, but there's plenty of brilliant ideas out there on how to remove them including scripting programs like sed.