Why does the BuildConfig class use Boolean.parseBoolean() instead of literal values?
Asked Answered
W

3

16

When looking at the BuildConfig class generated by Android Studio and the Gradle plugin one can see that the BuildConfig.DEBUG field is initialized using the Boolean.parseBoolean(String) call instead of using one of the boolean literals true or false.

When I add custom build properties using Gradle I would simply do it like this:

android {
    buildTypes.debug.buildConfigField 'boolean', 'SOME_SETTING', 'true'
}

But looking at the generated BuildConfig tells me that Google has taken a different approach with the DEBUG flag:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");

  // more fields here

  // Fields from build type: debug
  public static final boolean SOME_SETTING = true;
}

What is the benefit of using Boolean.parseBoolean(String) instead of literals?

Willmert answered 27/4, 2015 at 6:56 Comment(4)
You asked the question and answered it the same second? Achievement unlocked. Claim your superhuman badge.Sawdust
blog.stackoverflow.com/2011/07/…Willmert
There is a checkbox for that, when asking a question. I just wanted to share my learnings with the community ;-)Willmert
Thanks for the info, haven't seen that blog post before. But I guess your question is not a problem per se, and this would have more suited as a blog post.Sawdust
W
29

Boolean literals inside the BuildConfig class are going to produce IDE warnings when using them in your code (at least within Android Studio). For example when using it in a boolean expression Android Studio will (mistakenly) recommend to simplify the boolean expression because the constant value is always the same (for current build variant that is).

Android Studio producing code warning because of missing build configuration knowledge

This warning is only because Android Studio does not know that the final value inside BuildConfig.SOME_SETTING may be different for other build variants.

To keep the code clean and free of warnings you can tell Android Studio to ignore this specific warning by adding an IDE comment like this:

Add code comments to ignore IDE warnings

But again this will add some noise to the code and reduce readability. By using the Boolean.parseBoolean(String) method to initialize your constant field, you actually trick Android Studio which will no longer be able to completely analyze your boolean expressions, thus not generating warnings any longer.

Use parseBoolean(String) to prevent IDE warnings

This approach is very useful, as it keeps your code clean and readable, without turning off important code analysis and generation of warnings.

Security & performance considerations

As mentioned by Jiří Křivánek, the usage of parsed booleans does not only "trick" the static analysis performed by IDEs, but also by compilers, code minifiers, and obfuscators - making it harder for them to remove dead code from your application. This might leave code parts inside your application binaries, that would be stripped otherwise.

Willmert answered 27/4, 2015 at 6:56 Comment(10)
Maybe I'm missing something but what, exactly, does one add to build.gradle to declare a BuildConfig value using parseBoolean?Desiccated
@Desiccated try following buildConfigField 'boolean', 'SOME_FLAG', 'Boolean.parseBoolean("false")' inside your defaultConfig or any flavor or build type config.Willmert
Ah, I was probably missing the outer quotes, thanks. I ended up solving my issue using manifest substitutions instead.Desiccated
Doesn't it turn off compile-time optimizations though?Death
Yes, they do not consider that this "very useful trick" is actually very dangerous, as I can see daily that programmers are misusing it, because they have NO clue about the !!!SIDE EFFECTS!!! of this trickery... Of course for most of the world who do not care about security, it may look like usefull...Ricardaricardama
Thanks @JiříKřivánek for your input. I'm curious what security considerations in particular you're talking about, and I'm certain that others, too, would be interested in you sharing your thoughts here.Willmert
Please excuse the comment, I didn't see your answer before replying here.Willmert
The problem is that programmers around me tend to use the BuildConfig.DEBUG for a conditional compilation - just to remove various debug utilities (and logging, ...) at all from the code. But thanks to this nasty trickery which Google did and which most of the people around me have no idea about, it actually does not work as conditional compiling. And when we have the penetration testing, the pen-test team reports back to us, like "your code contains sensitive information useful for reverse attacks". And programmers say: Impossible, we carefully reviewed it is conditionally compiled :)Ricardaricardama
This answer doesn't contain any sources that this is the reason (IDE warnings) the developers have chosen this parseBoolean wayNasalize
@J.Doe you are right, but the question didn't specifically ask for this either. I don't know for sure why the Android team originally adopted this pattern, but I would assume it was for inlining reasons (i.e. Android being a modular system where those booleans might be different depending on the actually at runtime loaded variant, a system which would break when Proguard or other minimizers would inline).Willmert
R
3

To me, it appears that the "trick" is actually very dangerous, as you cannot do the conditional compiling based on BuildConfig.DEBUG!

if(!BuildConfig.DEBUG) { Log.d("Here we are verifying the signature!"); }

According to my reverse engineering, the logging WILL REMAIN IN THE OUTPUT .class FILE!

Which would be a very good clue for the attacker...

Rodge answered 28/4, 2020 at 6:28 Comment(3)
That's a very valid downside of the mentioned workaround 👍 dead branch shaking is not working well with most minifiers/obfuscators. Then on the other hand, I do not think that most developers will write if(constant) { Log.d("sensitive content"); } over and over again. Logging of sensitive data is generally a bad idea. Also, while I agree that attackers shouldn't be given an easy time deconstructing an app, the app's securit shouldn't be compromised even if they manage to read your code.Willmert
I updated my answer with a section on security and performance considerations. Thank you so much for your input!Willmert
You are right, my job is a kind of special, I agree that most of the world is not so picky with the code security.Ricardaricardama
S
0

To expand on this, what is you want to pass a boolean as a variable with gradlew to BuildConfig?

  1. add your variable to gradle.properties with a default value

     MY_VAR=false
    
  2. in your build.gradle

    android {
        defaultConfig {
            buildConfigField "boolean", "MY_VAR", "Boolean.parseBoolean(\"" + MY_VAR + "\")" 
        }
    }
    
  3. add the parameter to your gradlew command

     gradlew <task> -P MY_VAR=true
    

All this will generate the following in your BuildConfig

public static final boolean MY_VAR = Boolean.parseBoolean("true");

And obviously it will default to false if you don't pass the paramter with gradlew

Subternatural answered 22/12, 2022 at 9:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.