How can I enable language-level assertions on the Android Runtime (ART)?
Asked Answered
G

2

7

I have a Pixel-C that I am developing for. My minimum API level is 21, which is also the level at which ART replaced Dalvik. I have tried both of:

adb shell setprop dalvik.vm.enableassertions all
adb shell setprop debug.assert 1

And they seem to execute successfully. I have placed

assert false : "assertions are active!";

in my onStart, and I am not seeing any stack traces in logcat. I would expect the app to exit immediately after I install and run it. Please tell me how to get this assertion to execute.

Please do not mention JUnit or other ways to do assertions, nor any solution that requires explicitly throwing an Error. Production code should never throw Errors, nor attempt to catch and handle them. That's why assertions were added to the language, to have a way to cause the app to crash when invariants are violated in test environments without incurring any overhead or risk whatsoever in production.

This 6-year old question is basically the same, but for Dalvik (IE out of date) and the solutions are either not working or not good: Can I use assert on Android devices?

Glyptograph answered 14/3, 2016 at 20:44 Comment(2)
I have to take some issue with your premises, namely that assertions add no risk in production. If an assertion would fail you're already doomed; it's just a question of how.Jahdai
@LouisWasserman yes, if an assertion would fail in production (if it ran) then you have a problem, but it is unclear how big a problem it would be. And having the assertion there adds no extra risk over the existing potential error, considering that they do not run.Glyptograph
Q
4

Android Gradle Plugin / Android Studio as of version 4.1 enables Java asserts in debug builds automatically.

Quicksand answered 16/10, 2020 at 11:9 Comment(1)
but warning Assertions are never enabled in Android. Use BuildConfig.DEBUG conditional checks insteadDue
G
3

I reluctantly submit that the answer seems to be: you can't enable assertions on ART. What works is to replace all assertions with an explicitly thrown AssertionError wrapped in an if statement like this:

if (BuildConfig.DEBUG) {
  if (writeBuffer.hasRemaining()) {
    // As with all assertions, this condition should never be met.
    throw new AssertionError("whole buffer not written");
  }
}

Apparently, in API levels 21, 22, and 23, ART will actually completely remove the bytecode for this if block from non-debug builds upon install, ie where BuildConfig.DEBUG == false. At these API levels, ART compiles bytecode to native on install, but that is changing for Android N. So I infer that on Android N, ART may still see the negligible performance penalty in production of checking BuildConfig.DEBUG until the optimizer potentially compiles it out after a certain amount of usage has occurred.

I don't like this because it removes the ability to choose to run assertions for a specific package in an apk. The choice now is at the granularity of the whole build, and only at build time.

The other major reason this sucks is that it's verbose and ugly. The brevity of assertions makes them good for documenting your code inline. Although these hacked-up assertions can serve as documentation, they're no longer unimposing and legible. Look at that example. That should be one line, not five.

If you have an idea why ART doesn't seem to support assertions, for example, inside knowledge about technical hurdles or Google's internal politics, please comment or leave a new answer. My assumption is that the widespread misunderstanding of the usefulness and role of assertions, and the prevalence of antipattern usage has led the Android team to just disable the feature rather than educate everybody. Maybe the Android team suffers from the same misunderstandings.

Glyptograph answered 26/4, 2016 at 22:47 Comment(2)
Not sure why they're so indifferent to assertions. Here are some links to past bug reports that document their indifference without giving a reason for it. — For my part, I've resorted to using a source preprocessor.Egest
Current Android Studio (4.2 Canary 11) suggests to use if ( BuildConfig.DEBUG && !(condition) ) { error("Assertion failed") } instead of assert(condition) because Assertions are never enabled in Android. Use BuildConfig.DEBUG conditional checks instead. The error() function Throws an IllegalStateException with the given message.. (This is all for Kotlin, but should be similar and also suggested for Java.)Pave

© 2022 - 2024 — McMap. All rights reserved.