Issue an overview
In the development of our project, crashes related to TimeoutException may be frequently encountered on Crash collection platform, which are usually repeated on OPPO Android 5.0-6.0 phones. The output stack logs are as follows:
java.util.regex.Pattern.finalize() timed out after 120 seconds
com.android.internal.os.BinderInternal$GcWatcher.finalize() timed
out after 120 seconds
android.database.CursorWindow.finalize() timed out after 10
seconds
java.util.regex.Matcher.finalize() timed out after 10 seconds
android.graphics.Bitmap$BitmapFinalizer.finalize() timed out after
10 seconds
org.apache.http.impl.conn.SingleClientConnManager.finalize()
timed out after 10 seconds
java.util.concurrent.ThreadPoolExecutor.finalize() timed out after
10 seconds
android.os.BinderProxy.finalize() timed out after 10 seconds
android.graphics.Path.finalize() timed out after 10 secondsCopy the code
The number of crashes is quite large, so how to solve the problem? The following is to analyze the cause of the problem and the way to solve it.
Cause analysis,
The root of the problem is that devices “go to Sleep” for a while, which means the operating system Goes to Sleep by turning off the screen, lowering the CPU frequency, etc., to reduce power consumption. This is done by pausing the process at the Linux kernel layer. It can happen at any time during the normal running of the application, but will stop during a kernel call because the context switch is done at the kernel layer. So, this is how the Dalvik GC participates in the TimeoutExceptions problem mentioned above.
The basic way the Dalvik GC works is that in a GC loop, the collector has a list of objects to destroy. The basic loop process can be summarized as follows:
- Starting_timestamp;
- Remove an object from the list of objects to release
- Free objects – call Finalize () and the native destroy() methods if necessary;
- End_timestamp;
- Computes (end_timestamp – starting_timestamp) and compares it with a hardcoded timeout of 10 seconds;
- If the timeout, throw the Java. Util. Concurrent. TimeoutException abnormalities, and kill the process.
Now consider the following scenario:
There is a process running in the background during which objects are created, consumed, and need to be collected to free memory. In general, Wakelock is not used by apps because it consumes power and seems unnecessary. This means that the application will perform GC actions from time to time. Normally, the GC action will complete normally without being suspended. However, sometimes (very rarely) the operating system will go to sleep during a GC run. If your app runs long enough, it can happen.
Now, take a look at the timestamp logic in the basic GC loop above. It is possible that the device starts GC, records the start timestamp, and then goes to sleep during a call to destroy() on the system object. When the GC resumes running after being awakened, the destroy() method is about to end, and the end timestamp is recorded. That is, the time taken for the GC action = the destroy() execution time + the sleep time. If sleep lasts longer than 10 seconds, a TimeoutException is thrown.
In addition, on Android 5.0+, this crash is much less likely to occur because of the ART GC. OPPO may be an exception…
The solution
We can solve the problem by stopping FinalizerWatchdogDaemon with reflection, which can only be handled specially for OPPO Android versions below 7.0. Methods such as attachBaseContext() can be called during the Application lifecycle:
private void fixTimeoutException() {
if (Build.BRAND.equalsIgnoreCase("oppo") &&
Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
try {
Class clazz =
Class.forName("java.lang.Daemons$FinalizerWatchdogDaemon");
Method method =
clazz.getSuperclass().getDeclaredMethod("stop");
method.setAccessible(true);
Field field = clazz.getDeclaredField("INSTANCE");
field.setAccessible(true); method.invoke(field.get(null)); } catch (Exception e) { e.printStackTrace(); }}}Copy the code
Refer to the link
- Stackoverflow.com/questions/2…
- www.jianshu.com/p/0119c682d…