Relevance of code
minification in a
performance world
Jitin Sharma
GDE Android, Gojek
Android Worldwide jitinsharma.com
@_jitinsharma
Slide 2
Slide 2 text
What we’ll
discuss
• Code obfuscation and minification
• Introduction to obfuscation tools
• Proguard rules
• Performance impacts of code
minification
• Common mistakes and how to avoid
them
Slide 3
Slide 3 text
Obfuscation
Slide 4
Slide 4 text
Life of code
Kotlin Class dex
Source code Bytecode Bytecode
Slide 5
Slide 5 text
Life of code
Kotlin Class dex
Source code Bytecode
resources
+
apk
Slide 6
Slide 6 text
Life of code
Kotlin Class dex
Source code Bytecode Bytecode
• dedexer
• smali
Slide 7
Slide 7 text
Life of code
Kotlin Class dex
Source code Bytecode Bytecode
jadx
Slide 8
Slide 8 text
Obfuscation
class Repository
viewModel.fetchData()
fun matchUser()
val loggedIn = false
package com.awesome.app
class a
c.zz()
fun rt()
val y = false
package com.g.f
Slide 9
Slide 9 text
minification
Slide 10
Slide 10 text
Minification
fun main() {
fetchUser()
}
fun fetchUser() {
fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 11
Slide 11 text
Minification
fun main() {
fetchUser()
}
fun fetchUser() {
// fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 12
Slide 12 text
Minification
fun main() {
fetchUser()
}
fun fetchUser() {
// fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 13
Slide 13 text
Minification
Activities Service Application Receivers
Code
Slide 14
Slide 14 text
Minification
Activities Service Application Receivers
Code resources
11.8 mb
596.6 ms
6.4 mb (45%)
361.3 ms (39%)
Non Minified
Minified
Slide 27
Slide 27 text
Optimisations
Slide 28
Slide 28 text
Code Inlining
fun myBranchedFunction() {
if (BuildConfig.DEBUG) {
debugMethod()
} else {
releaseMethod()
}
}
fun myBranchedFunction() {
releaseMethod()
}
Slide 29
Slide 29 text
Code Inlining
fun myBranchedFunction() {
releaseMethod()
}
fun main() {
myBranchedFunction()
myFunction2()
}
Slide 30
Slide 30 text
Code Inlining
fun myBranchedFunction() {
releaseMethod()
}
fun main() {
releaseMethod()
myFunction2()
}
Slide 31
Slide 31 text
Code Inlining
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ..
}
if (Build.VERSION.SDK_INT >= 28) {
val displayCutOut = decorView.rootWindowInsets.displayCutout
...
}
minSdk 19
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ..
}
if (Build.VERSION.SDK_INT >= 28) {
val displayCutOut = decorView.rootWindowInsets.displayCutout
...
}
Slide 32
Slide 32 text
Code Inlining
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ..
}
if (Build.VERSION.SDK_INT >= 28) {
val displayCutOut = decorView.rootWindowInsets.displayCutout
...
}
minSdk 21
window.statusBarColor = ..
if (Build.VERSION.SDK_INT >= 28) {
val displayCutOut = decorView.rootWindowInsets.displayCutout
...
}
Slide 33
Slide 33 text
Code Inlining
if (Build.VERSION.SDK_INT >= 21) {
window.statusBarColor = ..
}
if (Build.VERSION.SDK_INT >= 28) {
val displayCutOut = decorView.rootWindowInsets.displayCutout
...
}
minSdk 28
window.statusBarColor = .. val displayCutOut = decorView.rootWindowInsets.displayCutout
...
Slide 34
Slide 34 text
Code Inlining
fun trim(String name) {
Intrinsics.checkParameterIsNotNull(name)
name(…)
}
fun trim(String name) {
if (name != null) {
name(…)
} else { // exception }
}
Slide 35
Slide 35 text
App Startup
596.6 ms 361.3 ms (39%)
Non Minified
Minified
Slide 36
Slide 36 text
App Startup
Non Minified
Minified
Slide 37
Slide 37 text
App Startup
Non Minified
Minified
Dex load: 2.96 ms
Dex load: 0.07 ms
Slide 38
Slide 38 text
Systrace Event Non minified Minified Mode
bindApplication 54.46 ms 19.24 ms Release
ResourcesManager#getRes
ources
4.62 ms 3.97 ms Release
ResourcesImpl#updateCon
figuration
3.98 ms 2.62 ms Release
LoadApkAssets 1.3 ms 0.68 ms Release
VectorDrawable#inflate 0.41 ms 0.39 ms Release
Slide 39
Slide 39 text
Rules
Slide 40
Slide 40 text
Rules can hurt you
- keep class com.mypackage.**
- keep com.somepackage.R$*
- keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
Slide 41
Slide 41 text
Case Study
keepclassmembers class **.R$* {
public static ;
}
Rules
• Be aggressive instead of defensive when defining proguard rules.
• Avoid wildcard package rules.
• Use @Keep to attach rules to codebase instead of rules files.
• Scan for rules which third party rules are importing in your codebase.