How can I enable language-level assertions on the

2019-06-25 14:05发布

问题:

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?

回答1:

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.