Many Android developers have experienced this: everything works fine during testing, but once the app goes live, all kinds of system crashes start rolling in – often intermittent ones like:
WindowManager$BadTokenException
Resources.NotFoundException
NullPointerException
SecurityException
IllegalArgumentException
RuntimeException
……
In many cases, these crashes aren’t caused by the app at all, and there’s not a single trace of app code in the stack. Take WindowManager$BadTokenException – some are caused by an Android 7.1 bug, others by Dialog or Fragment operations. If it’s an app logic issue, the stack trace reveals it easily. But what about crashes caused by the system itself? Are we simply out of luck?
Fixing System Bugs
Let’s stick with WindowManager$BadTokenException as an example. If it’s caused by Toast, the first instinct for most developers is to create a custom Toast. That works, but Booster takes a completely different approach – during the build, it replaces all Toast.show(...) call instructions in the code with ShadowToast.show(Toast):
A fair question: if we just blanket catch-all exceptions like we did with Toast, won’t that hide real bugs in the app? Yes, exactly.
That’s precisely why Booster doesn’t blindly swallow everything. Sure, catching all exceptions would make crash rates look better, but it would also mask real issues. We have higher standards than that. So how does Booster distinguish system-caused exceptions from app-caused ones? Stack trace analysis.
for (Throwablecause= t; null != cause; cause = cause.getCause()) { for (final StackTraceElement element : cause.getStackTrace()) { if (!isSystemStackTrace(element)) { returnfalse; } } }
The exception handling above addresses many edge cases – for instance, on Android N and above, the AssetManager may become unavailable after the first launch following an app upgrade. The strategy is simple: if the exception wasn’t caused by the system, rethrow it. This way, real app bugs surface immediately.
Side Effects
After hooking ActivityThread, rethrowing non-system exceptions does wonders for crash rates, but it creates a headache for APM systems doing exception aggregation. Many APM systems aggregate exceptions based on stack traces, and since these rethrown exceptions all end up going through ActivityThreadCallback, they get incorrectly grouped together.
Summary
All of these solutions are available as ready-to-use modules in the Booster framework: