Does Kotlin code gets "minified" when compiled? - android

In Typescript (or JavaScript) I always try to write in a way that if I (or another developer) has to touch my code in one year, it is really easy to understand what is happening. So I do not try to find the shortest code possible but the clearer one.
I do not worry about the size of the file because I know in production this function:
function myFunction(value: number) {
if(otherFunction(number){
return true;
}
if(yetAtherFunction(number){
return true;
}
return false;
}
will be converted to this:
function myFunction(n){return!!otherFunction(n)||!!yetAtherFunction(n)}
Would something similar happens with kotlin?
I ask because I offen find this kind of code:
val myDrawable = item?.image?.let { Uri.parse(it.toString()) } ?: R.drawable.my_default_image
and to me it is not easy to do a fast parse to know what is happening why doing a PR or similar.
If I write that in a more verbose way, would it have an impact on the size of the final apk ?
Important:
To clarify, I am not asking is it better to write in this or that way? I am asking if the compiler tries to optimize the input like a typescript/javascript minifier does.

In Kotlin / Java world, all code must get compiled into bytecode before it can run anywhere, and in general this is basically an incredibly optimized binary blob where whitespace doesn't exist.
In interpreted languages like JS, the client / browser downloads a copy of the source and runs the source directly. Minifying is super important in these cases because it reduces the size of the file clients need to download by removing logically redundant characters. In TS, most clients cannot run it directly, so it instead gets transpiled into JS, and that is what is typically served to browsers / clients. (Some exceptions like Deno exist for example, which has a native ts interpreter).
The reason you see inlined code stuffed into one line, is purely for cosmetic / code style purposes.
Additional whitespace and variable names generally have no impact on the size / performance of your compiled Android app, so you can simply write code in the way that seems most presentable to you.

Related

Obfuscating or removing string literal from all calls to Log-function in Android

We are building an Android application where we use Timber for Log-output. We have defined our own .e, .d, .v etc functions and use if (BuildConfig.DEBUG) to see if we should output the log. This takes care of the issue that we don't want to output Debug-logs in our releases but all the string literals used in our functions calls are still present in the compiled source code. We furthermore use ProGuard for obfuscation. To exemplify, in a class we can have:
somObj.normalFunction(variable)
Log.d("This secret class achieved its secret mission!");
In our release, this will not be seen in the app logs but if you reverse-engineer the APK you will see something like:
q.b(m)
z.a("This secret class achieved its secret mission!");
which can give a hint to the hackers about what class they are looking at.
So what we're looking for is to either be able to completely REMOVE all the Log function calls at compile time (using some pre-processing, annotation or something, but hopefully without having to add something before EVERY function call) OR to obfuscate all the String literal parameters to those function calls. So, two ideal solutions would be if the source, just before compilation, instead looks like:
q.b(m);
or
q.b(m);
z.a("jgasoisamgp23mmwaföfm,ak,ä")
Just by thinking I can see two bad ways to achieve this. Either we surround ALL calls to Log.d with if(BuildConfig.DEBUG) which will make the compiler remove them before compilation. But this is very tideous. OR, we make sure that every time you want to add a log-printout you need to do
Log.d(LogClass.getLog(1234))
and you then define ALL those logs inside LogClass and then remove them with if(BuildConfig.DEBUG) and return null in getLog if that's the case. But that makes it more tideous every time you want to add a log.
So finally, is there any GOOD solution to this?
DISCLAIMER: I work for PreEmptive, the company that makes PreEmptive Protection - DashO.
DashO is capable of removing calls to specific methods (e.g., Log methods). While this doesn't remove the instructions to load the string literal, just the call itself, DashO also offers String Encryption, which would offer some protection to those string literals.
As an example, I ran this class through DashO:
public class App {
public static void main(String[] args) {
Log.d("Secret message here");
}
}
After removing calls to Log.d with String Encryption on, the decompiled output looks like this:
public class App
{
public static void main(String[] paramArrayOfString)
{
a.replace("Bwpfpb7u|ih}z{?($0&", -12 - -61);
}
}
DashO offers other protections (e.g., Control Flow Obfuscation) that tend to break decompilers; I've turned those off for this demonstration.
What I would do is one or some of the following:
Use Timber (so you don't need to bother removing things or adding if statements). You simply do this once in your Application#onCreate(); if you are in DEBUG, then you plant a DebugTree that prints to the console. Else, you plant an "empty tree" that does nothing.
Simulate Timber but create your own "YourLogger" class and do the same (if you don't want to include a "third-party" library even though it's just one class). So you'd have YourLogger.v("tag", "string") and inside you'd do: if (debug) { Log.v(tag, string); } and so on and so forth for all other log types.
Use Proguard to strip the logging, and what not.
1 and 2 imply you go through your app and replace all Log. lines with either Timber. or YourLogger.
Option 3 wouldn't need that, since the code would be removed during obfuscation and the calls would do nothing, but this is mode complicated (and I haven't done it in years, don't even remember how it's done, probably easy to look it up).
I'd go for 1.
Update
Since apparently I don't know how to read, I think that in order to achieve this, your only bet is to have some sort of lookup mechanism for the actual text you want to emit/hide.
Strings.xml is the easiest, since it's included with Android and you can even localize the error messages (if that were needed, of course). Yes, there's a lookup time penalty, but I'd say unless you're iterating over thousands of items and logging different strings every time or something, the penalty wont' be noticeable (I don't have data for this, you'd have to benchmark).
Alternatively, instead of relying on resources, you could just use a file, read it, and load the strings in memory... a trade off; do you use more memory at the cost of simplicity and time to code the solution, or do you use the built-in mechanism and pay the CPU time?

How can I build an sbt plugin that stores the name of all implementations of an interface?

I'm trying to do the impossible and it doesn't seem to be working. The overall goal is this: I have a Component interface and I would like to show the user a list of classes on the classpath that implement that interface. The trick is, it has to run in Android.
Near as I can tell this is impossible to do at run time. The java mechanism (ServiceLoader) has been intentionally crippled by the Android toolchain, so it doesn't work. Guava doesn't work on Android, nor does ClassUtils, nor does Reflections.
At this point I've been yak shaving for 8 hours strait and there's no end in sight, so I'm looking for alternative approaches. My current thinking is to build a plugin (very much like sbt-spi, but not, because Android hates SPI) that can generate a text file at compile time that lists every class which implements the interface, so that at runtime I can open that file as a resource and then use reflection to start building them. Is that a reasonable idea? How should I go about it? (my current approach is "read the sbt-spi plugin source and try to copy it", but this seems like a scenario where "ask for wisdom" is a better approach)
Got it! I ended up using sbt-spi after all (huzzah not reinventing any wheels!) and just moving the output into the intermediate assets directory as part of the resourceGenerators task:
lazy val androidEntryPoint = (project in file("android-entry-point"))
.dependsOn(core, components, androidComponents)
.enablePlugins(SpiPlugin)
.settings(commonSettings: _*)
.settings(resourceGenerators in Compile += Def.task{
// This task copies the list of Components to the appropriate place to ensure
// it gets included in an accessible place in the APK
val res = collectResources.value._1 // item _1 here is for assets, item _2 is for resources. See the output of sbt "show androidEntryPoint/android:collectResources"
mapExport.value.toSeq.map { name =>
IO.move(target.value / name, res / name)
res / name
}
}.taskValue
)
That said, I'd love to hear a better approach if you can think of one. If none turn up in the next week or so I'll mark this one the answer.

Using arc4random_uniform with cocos2d-x

I was happy using arc4random_uniform since iOS, and also for iOS targets of cocos2d-x.
Turns out it doesn't work for Android. The error:
error: 'arc4random_uniform' was not declared in this scope
How can I get around this?
Worst case, at compile time I'd check if arc4random_uniform() exists, and if not, use some other method (like the old arc4random()...).
I really would like to avoid using different code bases for different targets here.
Any other suggestions?
Note: As cocos2d-x is a "one code"→"many platforms", delegating this issue to Java code for Android would work against that.
Some of the C++ libs you can use in ios are not available in Android.
Unfortunately arc4ramndom is just one of them.
So the only way is to use an alternative of the stdlib like std::rand() or the default random engine if you want something more.
This is an example about how to use std::default_random_engine to get a random value in a given interval.
int randomValue(int from, int to) {
std::random_device rd;
std::default_random_engine e1(rd());
std::uniform_int_distribution<int> uniform_dist(from, to);
int mean = uniform_dist(e1);
return mean;
}
You can use Cocos2d native methods for generating random numbers. CCRANDOM_0_1() for example generates a random CGFloat between 0 and 1.

efficient way to put debug/log statements in code - so they do not influence runtime

In C-derivative languages there is the possibility to have conditional code for debug and runtime. That way there is no overhead left in the runtime.
How would I do this with Java/Android and the Log.i statements? If I just use a constant global boolean debugOn that obviously leaves the redundant checks in the runtime.
What is the best approach for conditional Log-statements?
Many thanks
EDIT:
Since there are quite some comments following the accepted answer I post my conclusion here....
private static final boolean DEBUG = true;
if (DEBUG) Log.i("xxx",this.getClass().getName()+ "->" + Thread.currentThread().getStackTrace()[2].getMethodName() );
...just like in xCode :)
Android build system started providing a constant BuildConfig.DEBUG some time ago, so I suggest using it and writing the code like this:
if (BuildConfig.DEBUG) Log.i(TAG, "Message");
No redundant checks will be made since it's a constant. This code will be optimized even by compiler, but you also have ProGuard at your disposal. Even if the checks are in place, any possible impact on performance should be negligible.
This approach used to have one drawback that you had to edit this constant yourself, either manually or through a custom rule in the build file. Now, however, this is handled automatically by the build system, so you don't have to do anything yourself.
Create your own Log class by by extending Log class , create static variable debugLevel inside it , create your own methods and labels like INFO, DEBUG ect .
now change in value of static varable debugLevel , will reflect to whole application.
so no need for if(debug) everywhere .
Java doesn't have C-like conditional compilation, unless you implement it yourself. (It's not all that difficult, but IMO it's not worth the trouble.)
Your options are pretty limited. The best you can do is wrap expensive logging statements in an isLoggable.
if (Log.isLoggable(tag, Log.DEBUG)) {
Log.d(tag, expensiveStringGeneration());
}
For short log statements, it's more noise than it's worth.
Edit Malcolm might be right (although I still wouldn't bother, in all likelihood.)
Edit The comparison to a static DEBUG is still in the byte code; ProGuard should remove it the unnecessary branch. Without ProGuard, it would be up to the JIT, or the compiler implementation.

better way to do Debug only assert code

I am writing my first Android application and I am liberally using asserts() from junit.framework.Assert
I would like to find a way to ensure that the asserts are only compiled into the debug build, not in the release build.
I know how to query the android:debuggable attribute from the manifest so I could create a variable and accomplish this in the following fashon:
static final boolean mDebug = ...
if (mDebug)
Assert.assertNotNull(view);
Is there a better way to do this? i.e. I would prefer not to use an if() with each assert.
thanks
I think the Java language's assert keyword is likely what you want. Under the covers, the assert keyword essentially compiles into Dalvik byte code that does two things:
Checks whether the static variable assertionsDisabled (set in the class' static constructor via a call to java.lang.Class.desiredAssertionStatus()) is != 0 and if so, does nothing
If it is 0, then it checks the assertion expression and throws a java.lang.AssertionError if the expression resolves to false, effectively terminating your application.
The Dalvik runtime by default has assertions turned off, and therefore desiredAssertionStatus always returns 1 (or more precisely, some non-zero value). This is akin to running in "retail" mode. In order to turn on "debug" mode, you can run the following command against the emulator or the device:
adb shell setprop debug.assert 1
and this should do the trick (should work on the emulator or any rooted debugging-ready device).
Note however that the aforementioned Dalvik code that checks the value of assertionsDisabled and throws an AssertionError if the expression is false is always included in your byte code and liberal sprinkling of asserts in your code may lead to byte code bloat.
Please see this for a bit more detail: Can I use assert on Android devices?
If you're concerned about shipping code with the JUnit asserts in (or any other class path), you can use the ProGuard config option 'assumenosideeffects', which will strip out a class path on the assumption that removing it does nothing to the code.
Eg.
-assumenosideeffects class junit.framework.Assert {
*;
}
I have a common debug library I put all my testing methods in, and then use this option to strip it from my released apps.
This also removes the hard to spot problem of strings being manipulated that are never used in release code. For example if you write a debug log method, and in that method you check for debug mode before logging the string, you are still constructing the string, allocating memory, calling the method, but then opting to do nothing. Stripping the class out then removes the calls entirely, meaning as long as your string is constructed inside the method call, it goes away as well.
Make sure it is genuinely safe to just strip the lines out however, as it is done with no checking on ProGuard's part. Removing any void returning method will be fine, however if you are taking any return values from whatever you are removing, make sure you aren't using them for actual operational logic.
I mean if you were using a language feature, like assert(), the compiler should be able to strip that out. But this is an actual class and if a class is referenced by executable code it will be included or assumed included in the final product by the compiler.
However there is nothing stopping you from creating a script that removes all the references to the Assert class in all of your code base before compilation.
Another approach would be to make a test project that targets your application and within JUnit tests actually calls the Assert on the areas which you want to make sure work. I personally like this approach because it is a nice and clean separation of test and application.
If you are just worried about the having an if-statement everywhere, then just wrap Assert with your own class, DebuggableAssert which does that check before each call to Assert.X. It will be sort of less performant because of the method entry/exit and the conditionals but if you can maintain your code better then it might be worth it.

Categories

Resources