Relevance of code
mini
fi
cation in a
performance world
Jitin Sharma
BLR Devfest jitinsharma.com
@_jitinsharma
Architect, Groww
GDE Android
Slide 2
Slide 2 text
What we’ll
discuss
• Code obfuscation and mini
fi
cation
• Introduction to obfuscation tools
• Proguard rules
• Performance impacts of code
mini
fi
cation
• 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
mini
fi
cation
Slide 10
Slide 10 text
Mini
fi
cation
fun main() {
fetchUser()
}
fun fetchUser() {
fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 11
Slide 11 text
Mini
fi
cation
fun main() {
fetchUser()
}
fun fetchUser() {
// fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 12
Slide 12 text
Mini
fi
cation
fun main() {
fetchUser()
}
fun fetchUser() {
// fetchProfile()
}
fun fetchProfile() {
displayProfile()
}
fun displayProfile() { .. }
main()
fetchUser()
fetchProfile()
displayProfile()
Slide 13
Slide 13 text
Mini
fi
cation
Activities Service Application Receivers
Code
Slide 14
Slide 14 text
Mini
fi
cation
Activities Service Application Receivers
Code resources
Test bed project
~20 modules, 100 classes, 6000 methods
androidx Rxjava Glide Kotlin
AGP 7.0 D8/R8
Slide 25
Slide 25 text
Comparison
App Type Size App Launch Mode
Non Mini
fi
ed 11.8MB 596.6ms Release
Mini
fi
ed 6.5MB 367.9ms Release
Mini
fi
ed + Shrinked 6.4MB 361.3ms Release
Slide 26
Slide 26 text
11.8 mb
596.6 ms
6.4 mb (45%)
361.3 ms (39%)
Non Mini
fi
ed
Mini
fi
ed
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 Mini
fi
ed
Mini
fi
ed
Slide 36
Slide 36 text
App Startup
Non Mini
fi
ed
Mini
fi
ed
Slide 37
Slide 37 text
App Startup
Non Mini
fi
ed
Mini
fi
ed
Dex load: 2.96 ms
Dex load: 0.07 ms
Slide 38
Slide 38 text
Systrace Event Non mini
fi
ed Mini
fi
ed Mode
bindApplication 54.46 ms 19.24 ms Release
ResourcesManager#getRes
ources
4.62 ms 3.97 ms Release
ResourcesImpl#updateCon
fi
guration
3.98 ms 2.62 ms Release
LoadApkAssets 1.3 ms 0.68 ms Release
VectorDrawable#in
fl
ate 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 ;
}
11.8 mb
596.6 ms
6.4 mb (45%)
361.3 ms (39%)
Non Mini
fi
ed
Mini
fi
ed
Slide 45
Slide 45 text
6.4 mb
361.3 ms
Mini
fi
ed
6.6 mb (+3%)
487.1 ms (+34%)
Mini
fi
ed with faulty rules
Slide 46
Slide 46 text
6.4 mb
361.3 ms
Mini
fi
ed
6.6 mb (+3%)
487.1 ms (+34%)
Mini
fi
ed with faulty rules
Dex Count: 1
Dex Size: 634KB
Dex load: 0.07ms
Dex Count: 2
Dex Size: 894KB
Dex load: 0.09ms
Slide 47
Slide 47 text
Rules
• Be aggressive instead of defensive when de
fi
ning proguard rules.
• Avoid wildcard package rules.
• Use @Keep to attach rules to codebase instead of rules
fi
les.
• Scan for rules which third party rules are importing in your codebase.