3. 23 June 2016
ProGuard in Android builds
Application
Java bytec.
ProGuard
Processed
Java bytec.
Zip
align
Application
Java source
Libraries
Java bytec.
XML res.
Assets
Aapt
Javac
Libraries
Java bytec.
Dalvik
bytecode
Assets
Compiled
XML res.
Signatures
Assets
Compiled
XML res.
Dalvik
bytecode
Signatures
Assets
Compiled
XML res.
Dalvik
bytecode
Dex
Jar
signer
Application
Native src
Native
libraries
Native
libraries
Native
libraries
Gcc
4. 23 June 2016
android {
buildTypes {
debug {
minifyEnabled false
}
release {
minifyEnabled true
proguardFile getDefaultProguardFile('proguard-android.txt')
// To enable optimization, use the following instead:
// proguardFile getDefaultProguardFile('proguard-android-optimize.txt')
proguardFile 'proguard-project.txt'
}
}
}
Build configuration
Gradle: build.gradle
5. 23 June 2016
Build configuration
Used configurations:
● Specified proguardFiles in build.gradle
● consumerProguardFiles from libraries
(automatically added by Android plugin)
● Proguard rules generated by aapt, located in
build/intermediates/proguard-rules/<build-
type>/aapt_rules.txt
Tip
6. 23 June 2016
Configuration Debugging
Help for figuring out whats going on:
● Use '-printconfiguration config.pro'
● Use '-whyareyoukeeping class xxx.yyy ...'
Tip
com.example.HelloWorldActivity
is kept by a directive in the configuration.
com.example.HelloWorldActivity: java.lang.String TAG
is not being kept.
com.example.HelloWorldActivity: HelloWorldActivity() (18:18)
is kept by a directive in the configuration.
com.example.HelloWorldActivity: void onCreate(android.os.Bundle)
(25:39)
implements android.app.Activity: void
onCreate(android.os.Bundle)
is a library method.
7. 23 June 2016
Keep rules
Keep From being removed or renamed From being renamed
Classes and class members -keep -keepnames
Class members only -keepclassmembers -keepclassmembernames
Classes and class members, if
class members present
-keepclasseswithmembers -keepclasseswithmembernames
Hints:
● '-keep class xxx.yyy' will only keep the class itself
(+ default ctor), not its members
● Avoid '-keep class xxx.yyy { *; }' rules,
prefer '-keep class xxx.yyy { public protected *; }'
8. 23 June 2016
Pattern matching
Pattern types:
● Inclusion patterns: com.example.**
● Exclusion patterns: !com.example.foo.*
Pattern analysis:
● Patterns are analyzed in sequential order
● Exclusion patterns must come first
Tip
9. 23 June 2016
Pattern example
Keep everything in the package com.example and its
subpackages, except for package com.example.internal:
This won't work:
Tip
keep class !com.example.internal.**,
com.example.** {
*;
}
keep class !com.example.internal.**,
com.example.** {
*;
}
keep class !com.example.internal.** { *; }
keep class com.example.** { *; }
keep class !com.example.internal.** { *; }
keep class com.example.** { *; }
10. 23 June 2016
Notes and warnings
“Closed-world assumption”
● Might lead to problems during optimization
● Better to resolve than to hide
● Warnings and Notes are handled separately (-dontnote)
Tip
Warning: twitter4j.internal.logging.Log4JLoggerFactory:
can't find referenced class org.apache.log4j.Logger
Warning: twitter4j.internal.logging.SLF4JLoggerFactory:
can't find referenced class org.slf4j.LoggerFactory
...
Warning: twitter4j.internal.logging.Log4JLoggerFactory:
can't find referenced class org.apache.log4j.Logger
Warning: twitter4j.internal.logging.SLF4JLoggerFactory:
can't find referenced class org.slf4j.LoggerFactory
...
dontwarn twitter4j.internal.logging.**
# last resort
ignorewarnings
dontwarn twitter4j.internal.logging.**
# last resort
ignorewarnings
11. 23 June 2016
Shrinking
Attributes:
Default config only keeps *Annotation*
Other useful / necessary attributes to keep:
● Signature
● InnerClasses
● LineNumberTable
● SourceFile (together with -renamesourcefileattribute '')
Tip
12. 23 June 2016
Optimization
Various techniques:
● Method inlining
● Constant propagation
● Class merging
● Dead code elimination
● Code removal
● Peephole optimizations
● Variable allocations
● Field/Parameter/Exception removal
● ...
13. 23 June 2016
Optimization limitations
Extracted from user guide:
Warning: 3rd party libraries might be obfuscated in a way that breaks these
assumptions.
Mitigations:
● -dontoptimize
●
System property: -Doptimize.conservatively
For best results, ProGuard's optimization algorithms assume that the processed code never intentionally
throws NullPointerExceptions or ArrayIndexOutOfBoundsExceptions, or even OutOfMemoryErrors
or StackOverflowErrors, in order to achieve something useful. For instance, it may remove a method call
myObject.myMethod() if that call wouldn't have any effect. It ignores the possibility that myObject might be
null, causing a NullPointerException. In some way this is a good thing: optimized code may throw fewer
exceptions. Should this entire assumption be false, you'll have to switch off optimization using the
-dontoptimize option.
Tip
14. 23 June 2016
Optimization Methods
Optimization Technique Flags Safe? Impact
Method inlining method/inlining/* Yes
Peephole optimizations code/simplification/* Yes
Unreachable Code removal code/removal/simple Yes
Code removal code/removal/advanced Yes (ex. Obfuscated
libs)
Needed for logging removal, generally
safe, but depends on configuration.
Enum unboxing class/unboxing/enum Mostly yes Might lead to problems, especially when
using EnumMap / EnumSet
Variable allocation code/allocation/variable For Applications. Dx might crash when
-keepparameternames is used (or
LocalVariableTable is kept).
Method de-synchronization method/marking/synchronized Yes Effect might not be noticable, Slow
optimization
Constant propagation field/propagation/value
method/propagation/*
Yes
Class merging class/merging/* Mostly yes Might cause issues in rare cases.
Field removal field/removal/writeonly Yes
Tip
16. 23 June 2016
Logging Removal
ProGuard configuration:
assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int d(...);
public static int i(...);
public static int w(...);
public static int e(...);
public static java.lang.String getStackTraceString(java.lang.Throwable);
}
19. 23 June 2016
Logging Removal
ProGuard configuration:
assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int d(...);
public static int i(...);
public static int w(...);
public static int e(...);
public static java.lang.String getStackTraceString(java.lang.Throwable);
}
assumenosideeffects class java.lang.String {
public static java.lang.String format(...);
}
Tip
21. 23 June 2016
Side Effect Checking
Explicit (for library classes/methods):
Implicit (for program classes/method):
● During optimization by analysing the actual code
● Can be prevented with -keep rules
Note: removes invocations not methods themselves!
-assumenosideeffects class xxx.yyy { … }
22. 23 June 2016
Side Effect Example
public static int sum(int a, int b) {
return a + b;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
…
setContentView(xxx);
sum(10, 30);
…
}
.line 57
invokevirtual { p0, p1 }, Lcom/example/HelloWorldActivity;>setContentView(Landroid/view/View;)V
.line 66
.line 57
invokevirtual { p0, v2 }, Lcom/example/HelloWorldActivity;>setContentView(Landroid/view/View;)V
.line 63
const/16 v0, 10
const/16 v1, 30
invokestatic { v0, v1 }, Lcom/example/HelloWorldActivity;>sum(II)I
.line 66
Optimized:
25. 23 June 2016
DexGuard in Android builds
Compiled
XML res. DexGuard
Application
Java source
Libraries
Java bytec.
XML res.
Assets
Aapt
Javac
Libraries
Java bytec.
Processed
assets
Processed
XML res.
Dalvik
bytecode
Application
Java bytec.
Signatures
Application
Native src
Native
libraries
Processed
native
libraries
Gcc
26. 23 June 2016
DexGuard in Android builds (2)
Jack
Dex
Guard
Application
Java source
Libraries
Java bytec.
XML res.
Assets
Aapt
Jill
Libraries
.jayce
Dalvik
bytecode
Assets
Compiled
XML res.
Signatures
Assets
Compiled
XML res.
Dalvik
bytecode
Signatures
Assets
Compiled
XML res.
Dalvik
bytecode
Jar
signer
Application
Native src
Native
libraries
Native
libraries
Native
libraries
Gcc
27. 23 June 2016
Optimization
Features in addition to ProGuard:
● Parallel Optimization → faster on multi-core machines
● New modifier 'includecode' for -keep rules
● Support for more fine-grained side-effect configuration →
more effective code removal
29. 23 June 2016
Logging Removal
Result:
Much better!
Possible due to more fine-grained configuration:
.line 31
invokevirtual { p0, p1 }, Lcom/example/HelloWorldActivity;>setContentView(Landroid/view/View;)V
.line 35
assumenoexternalsideeffects public final class java.lang.StringBuilder {
public java.lang.StringBuilder();
public java.lang.StringBuilder(int);
public java.lang.StringBuilder(java.lang.String);
public java.lang.StringBuilder append(java.lang.String);
…
}
30. 23 June 2016
More DexGuard Goodies
● Default configurations for applications/libraries supporting
many 3rd party libs
● Great support :-)
● Many samples
● Configuration debugging
● Java 8 language support → backported to Java 6/7 similar to
retrolambda
● Planned: Stream API support for older Android devices
● Planned: Native code obfuscation