Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proguard Optimization Settings: Enabling class merging, casts and field/* in modern API and Proguard versions

I've been obfuscating my apps for a long while, with the following settings I took like mantras, because they were Google's recommendations

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*

However, the other day I commented this line by mistake, the app got built correctly, and "apparently" works. I've made a lot of tests and couldn't made it crash.

So I wonder if those disabled optimization settings are needed ...

  • as of today's Android SDK and latest Proguard versions, I only target devices from Android 4.0.3 onwards (15), and use Proguard 5.1.
  • and for applications that don't do exotic stuff and have a properly written proguard.cfg instructing to keep the relevant problematic classes, etc.

Most answers here releated to this very issue have conflicting information, and are related to pretty old API versions.

One by one:

!code/simplification/arithmetic

I found a discussion on Google Groups where they say that simplification/arithmethic is not needed for SDK's after Android Donut. I assume then, I can safely enable this optimization.

!class/merging/*

It looks like proguard makes a good job in my projects with this optimization turned on:

[proguard]   Number of vertically merged classes:         296
[proguard]   Number of horizontally merged classes:       445

Are there other side effects besides the stack traces being incorrect? I mean, side effects related to the application crashing rather than to debug issues. I found this related question but it doesn't conclude wether it is safe or not.

!field/* and !code/simplification/cast

I read in this question answered by ProGuard's author that those were included to avoid bugs with older Proguard versions. So is it safe to activate them on Proguard 5.1?

like image 603
rupps Avatar asked Nov 15 '14 04:11

rupps


2 Answers

General advice: there's no guarantee that optimizations won't work, but there's always a risk. What the default Android proguard settings are attempting to do is provide a configuration that minimizes that risk, hence why they appear so conservative for your specific situation.

Enabling those optimizations just means that if something crashes, you can't be as certain as to the root cause. In general, the proguard step has less strong guarantees about what the outputs should be relative to the inputs, which is a source of non-determinism in your program. Small changes in code can result in significantly different changes in runtime behaviour, and it's not possible to know until you actually run the program, depending on your config.

In summary, if you can run your APK, and it all works - then great, the optimizations work for you. But, they're not guaranteed to.

like image 176
Fabian Tamp Avatar answered Nov 15 '22 15:11

Fabian Tamp


So is it safe to activate them on Proguard [5.1]?

It's a high risk move and I can give you an example where it causes a problem.

We're using ProGuard 5.2.1 and we're hitting a bug when reenabling the field/* optimization (more specifically, field/removal/writeonly seems to be causing the problem). Our code uses protobuf and enabling that optimization causes ProGuard to fail with this message on the third pass of optimizations:

Optimizing...
 Unexpected error while evaluating instruction:
  Class       = [com/google/protobuf/FieldSet$1]
  Method      = [()V]
  Instruction = [308] isub
  Exception   = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Unexpected error while performing partial evaluation:
  Class       = [com/google/protobuf/FieldSet$1]
  Method      = [()V]
  Exception   = [java.lang.IllegalArgumentException] (Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue])
Warning: Exception while processing task java.io.IOException: java.lang.IllegalArgumentException: Value "com/google/protobuf/WireFormat$JavaType!" is not an integer value [proguard.evaluation.value.TypedReferenceValue]

This is to say that the fact that these optimizations have been disabled for so many years means that they probably haven't been as well maintained as others. Luckily this was caught at compile time but re-enabling some of these optimizations (e.g. horizontally merging classes via class/merging/*) might easily break your app in certain versions/builds of Android without being properly reported back to you "the developer" (e.g. it might crash dexopts or fail to install altogether with VerifyError).

like image 2
Mike Laren Avatar answered Nov 15 '22 17:11

Mike Laren