Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Decoding Android Runtime (DroidJam 2018)

Ce1ca64f3265f01a8718a622427f0a1d?s=47 Jitin
July 13, 2018

Decoding Android Runtime (DroidJam 2018)

While writing code, we mostly care about that it should be efficient and should not break. How that code executes at runtime is a completely different story in case of Android. The .dex format has been here for years and everyone is accustomed to it. But there are a lot of complexities going on once the .dex reaches your device. This talk will focussed on analyzing on what happens after your code in Kotlin/Java is compiled, packaged and run on an actual device. We will take a deep dive into .dex format as well as see how runtime has evolved since Android 1.0 and taken a great leap with Android 5.0 and above. In the process, we will also learn how to write runtime efficient code.

Ce1ca64f3265f01a8718a622427f0a1d?s=128

Jitin

July 13, 2018
Tweet

More Decks by Jitin

Other Decks in Technology

Transcript

  1. JITIN S HARMA D E C O D I N

    G A N D R O I D R U N T I M E @js_2892
  2. What is Android - Some Hardware - Some Linux -

    Some C++ - Some Java
  3. None
  4. Boot-Up

  5. Boot-Up Hardware Start-Up 02 Software Start-Up ZYGOTE 03 01

  6. Boot-Up init.rc AndroidRuntime.cpp Zygote main() Transition to Java base execution

    Linux Kernel Start
  7. Zygote - Zygote Process acts a base process from which

    all processes are forked for subsequent applications. - This allows Android to run in a Multi-Process environment where all processes run independent of each other. - All resources preloaded by Zygote are accessed by subsequent applications through shared memory.
  8. Zygote System Server Load core libraries and resources Starts Activity

    Manager Notification Manager, Bluetooth Service, Package Manager, Sensor Service…
  9. Zygote System Server Load core libraries and resources Starts Activity

    Manager Notification Manager, Bluetooth Service, Package Manager, Sensor Service…
  10. Zygote

  11. Phone is ON

  12. Building APK java/kt files .class files .dex javac kotlinc dx

    APK
  13. Installing Application

  14. Manifest Parsing - All data from AndroidManifest.xml is read and

    is written to data/system/packages.xml - This file acts as a global source for all packages and is used by PackageManager API - This happens only once either when device is booted or an application is being installed.
  15. Manifest Parsing - Identifies various elements within your application -

    At the same time manifest performs checks which can cause installation errors if elements are not defined properly.
  16. Code Compilation and Other Stuff

  17. Code Compilation and Other Stuff Dalvik ART

  18. dex and Dalvik Era Android 1.0 - 4.4 (2008-2014)

  19. .dex Dalvik VM A register based VM optimised for memory

    constrained device .dex -> Dalvik Executable
  20. Stack Machines value1 value2 value3 value4 value1 value2 operation pop

    pop value5 value3 value4 push
  21. Stack Machines Register Machines value1 value2 value3 value4 value1 value2

    operation pop pop value5 value3 value4 push addr1 value1 operation addr2 value2 addr3 value3
  22. Stack Machines Register Machines value1 value2 value3 value4 value1 value2

    operation pop pop value5 value3 value4 push addr1 value1 operation addr2 value2 addr3 value3 ARM Optimized
  23. dex - Uses 16 bit instruction format. - Bytecode tends

    to be larger due to register based architecture for storing addresses
  24. dex - Uses 16 bit instruction format. - Bytecode tends

    to be larger due to register based architecture for storing addresses ‣header ‣string_ids ‣type_ids ‣proto_ids ‣field_ids ‣method_ids ‣class_defs ‣call_site_ids ‣method_handles ‣data ‣link_data
  25. dex - Uses 16 bit instruction format. - Bytecode tends

    to be larger due to register based architecture for storing addresses ‣header ‣string_ids ‣type_ids ‣proto_ids ‣field_ids ‣method_ids ‣class_defs ‣call_site_ids ‣method_handles ‣data ‣link_data Contains verification signatures
  26. dex

  27. dex

  28. public class Data { int id; String name = "";

    public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
  29. public int getId() { return id; } .METHOD getId :

    int .MODIFIERS public .REGISTERS 2 .CODE iget v0, v1 field@8046 return v0 .METHOD setName : void .PARAM java.lang.String .MODIFIERS public .REGISTERS 2 .CODE iput-object v1, v0 field@8047 return-void public void setName(String name) { this.name = name; }
  30. private fun forEachTest(): Int { var sum = 0 (0..50).forEach

    { sum += it } return sum } private fun forTest(): Int { var sum = 0 for (i in 0 until 50) { sum += i } return sum } VS
  31. private fun forTest(): Int { var sum = 0 for

    (i in 0 until 50) { sum += i } return sum } .METHOD forTest : int .MODIFIERS private final .REGISTERS 4 .CODE const/4 v0, #0 const/4 v1, #0 const/16 v2, #50 if-ge v1, v2, 6 add-int/2addr v1, v0 add-int/lit8 v1, v1, #1 goto -7 return v0
  32. private fun forEachTest(): Int { var sum = 0 (0..50).forEach

    { sum += it } return sum } .METHOD forEachTest : int .MODIFIERS private final .REGISTERS 8 .CODE const/4 v0, #0 new-instance v1, type@2439 const/4 v2, #0 const/16 v3, #50 invoke-direct {v1, v2, v3}, meth@20280 check-cast v1, type@1851 move v3, v2 invoke-interface {v1}, meth@15176 move-result-object v4 invoke-interface {v4}, meth@15640 move-result v5 if-eqz v5, 13 move-object v5, v4 check-cast v5, type@2142 invoke-virtual {v5}, meth@18564 move-result v5 move v6, v5 add-int/2addr v6, v0 goto -16 return v0
  33. A.class B.class Z.class classes.dex

  34. A.class B.class Z.class classes.dex - Reduction in bytecode size during

    conversion. - Duplicate constants from class files are converted to a single one. - Each method needs have a reference which is limited by dex instruction format of 16 bits, hence total method references which a single dex file can hold is 65,536 (2^16)
  35. dex++

  36. Multidexing classes.dex java/kt classes2.dex classesN.dex …

  37. Installation data/dalvik-cache data/data/com.example.myapplication

  38. dexopt - Verification and Optimization of contents of .dex file

    - Result differ from device to device. - Starts a small version of VM to optimize dex files. - Contents of system/framework/ can be used to optimize dex files outside Android OS. - Code is optimized for runtime not memory.
  39. classes.dex My Application Zygote Process

  40. Multidex.install(this) classes.dex classes2.dex classes3.dex …. System Application classesN.dex Inject values

    into ClassLoader
  41. Multidex.install(this) classes.dex classes2.dex classes3.dex …. System Application Must have Application

    class classesN.dex Inject values into ClassLoader
  42. Multidex.install(this) classes.dex classes2.dex classes3.dex …. System Application Must have Application

    class Library dependencies classesN.dex Inject values into ClassLoader
  43. Multidex.install(this) classes.dex classes2.dex classes3.dex …. System Application Must have Application

    class Library dependencies (multiDexKeepFile) classesN.dex Inject values into ClassLoader
  44. DexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(), getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader());

  45. DexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(), getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader()); Network

  46. DexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(), getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader()); Class<?>

    dynamicClass = dexClassLoader.loadClass("com.example.myapplication.runtime"); Method dynamicMethod = dynamicClass.getDeclaredMethod("executeDataLoad", Integer.class, Integer.class); Integer value = (Integer) dynamicMethod.invoke(dynamicClass.newInstance(), 1, 2); Network
  47. DexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(), getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader()); Class<?>

    dynamicClass = dexClassLoader.loadClass("com.example.myapplication.runtime"); Method dynamicMethod = dynamicClass.getDeclaredMethod("executeDataLoad", Integer.class, Integer.class); Integer value = (Integer) dynamicMethod.invoke(dynamicClass.newInstance(), 1, 2); Network public Integer executeDataLoad(Integer value1, Integer value2) { // return result; }
  48. DexClassLoader DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(), getCodeCacheDir().getAbsolutePath(), null, context.getClassLoader()); Class<?>

    dynamicClass = dexClassLoader.loadClass("com.example.myapplication.runtime"); Method dynamicMethod = dynamicClass.getDeclaredMethod("executeDataLoad", Integer.class, Integer.class); Integer value = (Integer) dynamicMethod.invoke(dynamicClass.newInstance(), 1, 2); Network public Integer executeDataLoad(Integer value1, Integer value2) { // return result; }
  49. JIT

  50. JIT private void handleIntent() { ... public RequestQueue getRequestQueue() {

    if (requestQueue == null) { requestQueue = Volley.newRequestQueue(this); } return requestQueue; } for (String s : networkRequestMap.keySet()) { if (BuildConfig.DEBUG) { //
  51. Tracing and Profiling Low Memory Optimized (100K/200K) Faster results Google

    I/O 2010
  52. Shortcomings of Dalvik Time

  53. ART (Android Runtime) Android 5.0 - present (2014-present)

  54. Embracing the GBs…

  55. None
  56. None
  57. Embracing the GBs…

  58. Revamped GC - ART keeps track of application going in

    non-UI state. - Seperate types of GC for low memory and non-low memory devices. - GC pauses reduced from 2 to 1. - Larger objects like bitmap have seperate heap for faster allocation. - Young Objects are moved to stack for faster reclamation of memory.
  59. Dalvik GC GC GC 1MB 3MB 5MB

  60. ART GC GC GC 1MB 3MB 5MB

  61. ART GC GC GC 1MB 3MB 5MB 9MB Heap Compaction

  62. AOT Compilation classes.dex classes2.dex classesN.dex .oat dex2oat - AOT works

    on principle of compile once and then run. - Compilation takes significant time and memory since whole bytecode is converted to machine code at installation. - AOT compilers do not benefit from profile guided compilation which JIT compilers have instead use a restrictive approach to do compilation. Android Runtime VM
  63. .oat header instruction set dex file count dex2oat cmd line

    code data/app/
  64. DEX CODE: 0x0000: 5210 e10f | iget v0, v1, I

    com.example.myapplication.Data.id // field@4065 0x0002: 0f00 | return v0 public int getId() { return id; } Java
  65. CODE: (code_offset=0x00d6a3fc size_offset=0x00d6a3f8 size=68)... 0x00d6a3fc: 4885842400E0FFFF testq rax, [rsp +

    -8192] suspend point dex PC: 0x0000 GC map objects: v1 ([sp + #40]) 0x00d6a404: 4883EC18 subq rsp, 24 0x00d6a408: 48893C24 movq [rsp], rdi 0x00d6a40c: 89742428 mov [rsp + 40], esi 0x00d6a410: 6566833C250000000000 cmpw gs:[0], 0 ; state_and_flags 0x00d6a41a: 0F8516000000 jnz/ne +22 (0x00d6a436) 0x00d6a420: 8B442428 mov eax, [rsp + 40] 0x00d6a424: 8500 test eax, [rax] suspend point dex PC: 0x0000 GC map objects: v1 ([sp + #40]) 0x00d6a426: 8B480C mov ecx, [rax + 12] suspend point dex PC: 0x0000 GC map objects: v1 ([sp + #40]) 0x00d6a429: 894C2410 mov [rsp + 16], ecx 0x00d6a42d: 8B442410 mov eax, [rsp + 16] 0x00d6a431: 4883C418 addq rsp, 24 0x00d6a435: C3 ret 0x00d6a436: 65FF142538040000 call gs:[1080] ; pTestSuspend ……..
  66. Problems with AOT compilation

  67. None
  68. JIT/AOT Hybrid ‣System boot after OS update will no longer

    optimise the app, a job solely performed by JIT. ‣dex2oat is still used for .oat creation but it uses profile data generated by JIT to do so. ‣Code may be executed by directed .dex interpretation or JIT cache or AOT compiled. ‣At any time JIT compiled data will be more efficient because of availability of better environment data than AOT compiled code, and the same is preferred if both are present.
  69. DEX CODE: 0x0000: 5210 e10f | iget v0, v1, I

    com.example.myapplication.Data.id // field@4065 0x0002: 0f00 | return v0 public int getId() { return id; } Java CODE: (code_offset=0x00000000 size_offset=0x00aea110 size=0) NO CODE!
  70. Third party frameworks

  71. Future

  72. Future A.I

  73. Thanks @js_2892