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

R8/ProGuard 徹底比較

Sato Shun
February 07, 2019

R8/ProGuard 徹底比較

DroidKaigi2019:

R8はJavaコードを最適化されたdexコードに変換するためのシュリンカーです。Proguardを置き換える目的で作成されました。R8ではコンパイルタイムの軽減、dexコードのさらなる最適化を目指しています。
dexコードのさらなる最適化とは具体的にどのようなものでしょうか?

本セッションでは、R8でどのような最適化が行われているかをバイトコードレベルから説明します。また、Kotlinに関する最適化など、R8の特徴について説明し、Proguardと比べどこが進化したのかを紹介します。

具体的に以下のことを学ぶことが出来ます。

- R8の内部実装
- R8とProguardの違い
- R8ではどのような最適化が行われているか?

Sato Shun

February 07, 2019
Tweet

More Decks by Sato Shun

Other Decks in Technology

Transcript

  1. ProGuardΛ࢖ͬͨϏϧυ Optimized Dalvik όΠτίʔυ (.dex) javac
 kotlinc D8 Java όΠτίʔυ

    (.class) ιʔε ίʔυ (.java/.kt) Optimized Java όΠτίʔυ (.class) ProGuard
  2. E Process: com.github.satoshun.example, PID: 11495 E java.lang.RuntimeException: Unable to start

    activity ComponentInfo{com.github.satoshun.example/com.github.satoshun.example.MainActivity}: java.lang.Il legalArgumentException: Invalid attempt to bind an instance of com.github.satoshun.example.TestDeserializer as a @JsonAdapter for com.github.satoshun. example.Hoge. @JsonAdapter value must be a TypeAdapter, TypeAdapterFactory, JsonSerializer or JsonDeserializer. E at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913) E at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
  3. E Process: com.github.satoshun.example, PID: 11495 E java.lang.RuntimeException: Unable to start

    activity ComponentInfo{com.github.satoshun.example/com.github.satoshun.example.MainActivity}: java.lang.Il legalArgumentException: Invalid attempt to bind an instance of com.github.satoshun.example.TestDeserializer as a @JsonAdapter for com.github.satoshun. example.Hoge. @JsonAdapter value must be a TypeAdapter, TypeAdapterFactory, JsonSerializer or JsonDeserializer. E at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913) E at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) -addconfigurationdebuggingΛ ઃఆʹ௥Ճ
  4. ProGuard W The class 'com.google.gson.internal.ConstructorConstructor' is calling Class.getDeclaredConstructor W on

    class 'com.github.satoshun.example.TestDeserializer' to retrieve W the constructor with signature (), but the latter could not be found. W It may have been obfuscated or shrunk. W You should consider preserving the constructor, with a setting like: W -keepclassmembers class com.github.satoshun.example.TestDeserializer { W public <init>(); W }
  5. ProGuard W The class 'com.google.gson.internal.ConstructorConstructor' is calling Class.getDeclaredConstructor W on

    class 'com.github.satoshun.example.TestDeserializer' to retrieve W the constructor with signature (), but the latter could not be found. W It may have been obfuscated or shrunk. W You should consider preserving the constructor, with a setting like: W -keepclassmembers class com.github.satoshun.example.TestDeserializer { W public <init>(); W }
  6. checkdiscard • ର৅ͷΫϥεɺϝϯόʔ͕ ফ͍͑ͯΔ͔Λ֬ೝ͢Δ • ΠϯϥΠϯԽͰ͋ͬͨΓɺ unusedͰফ͞Ε͍ͯΕ͹͓̺ fun noInline(i: Int)

    { … } —- -checkdiscard class ** { *** noInline(***); } —- Item void CheckDiscardKt.noInline(int) was not discarded. Error: Discard checks failed.
  7. assumevaluesͷྫ if (Build.VERSION.SDK_INT >= 16) { println("true") } else {

    println("false") } -assumevalues class android.os.Build$VERSION { int SDK_INT return 16..2147483647; }
  8. assumevaluesͷྫ if (Build.VERSION.SDK_INT >= 16) { println("true") } else {

    println("false") } -assumevalues class android.os.Build$VERSION { int SDK_INT return 16..2147483647; } if (true) { println("true") } else { println("false") }
  9. assumevaluesͷྫ if (Build.VERSION.SDK_INT >= 16) { println("true") } else {

    println("false") } -assumevalues class android.os.Build$VERSION { int SDK_INT return 16..2147483647; } if (true) { println("true") } else { println("false") }
  10. assumevaluesͷྫ if (Build.VERSION.SDK_INT >= 16) { println("true") } else {

    println("false") } -assumevalues class android.os.Build$VERSION { int SDK_INT return 16..2147483647; } println("true") CompatܥͷϥΠϒϥϦͰ͸ԼҐޓ׵ʹ഑ྀ͍ͯ͠Δ ίʔυ͕ଟ͍ͨΊɺ͔ͳΓͷίʔυ࡟ݮ͕ظ଴Ͱ͖ Δɻ ·ͨɺAGP 3.4.0-beta02͔Β͸্هͷઃఆ͕σ ϑΥϧτͰೖΔΑ͏ʹͳͬͨʂʂ
  11. public class HelloWorld { private int a = 111; public

    void main() { System.out.println("Hello World!!" + a); } }
  12. $ javac *.java $ ls HelloWorld.class … $ java -jar

    $R8_HOME/build/libs/d8.jar \ --release \ *.class $ ls classes.dex …
  13. $ javac *.java $ ls HelloWorld.class … $ java -jar

    $R8_HOME/build/libs/d8.jar \ --release \ *.class $ ls classes.dex … $ $ANDROID_HOME/build-tools/28.0.3/dexdump -d classes.dex Opened 'classes.dex', DEX version '035' Class #0 - Class descriptor : ‘LHelloWorld;' …
  14. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) …
  15. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) class HelloWorld
  16. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) public class HelloWorld
  17. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) public class HelloWorld
  18. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) public class HelloWorld
  19. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) public class HelloWorld
  20. Class #0 - Class descriptor : 'LHelloWorld;' Access flags :

    0x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - #0 : (in LHelloWorld;) name : 'a' type : 'I' access : 0x0002 (PRIVATE) public class HelloWorld { private int a; }
  21. Direct methods - #0 : (in LHelloWorld;) name : '<init>'

    type : '()V' access : 0x10001 (PUBLIC CONSTRUCTOR) … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003: const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void …
  22. Direct methods - #0 : (in LHelloWorld;) name : '<init>'

    type : '()V' access : 0x10001 (PUBLIC CONSTRUCTOR) … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003: const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void … public class HelloWorld { private int a; public HelloWorld() { } }
  23. … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003:

    const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void …
  24. … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/ Object;.<init>:()V // method@0003

    0003: const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void … public class HelloWorld { private int a; public HelloWorld() { super(); } }
  25. … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003:

    const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void … public class HelloWorld { private int a; public HelloWorld() { super(); int v0 = 111; } }
  26. … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003:

    const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void … public class HelloWorld { private int a; public HelloWorld() { super(); (int v0 = 111;) this.a = v0; } }
  27. … [000194] HelloWorld.<init>:()V 0000: invoke-direct {v1}, Ljava/lang/Object;.<init>:()V // method@0003 0003:

    const/16 v0, #int 111 // #6f 0005: iput v0, v1, LHelloWorld;.a:I // field@0000 0007: return-void … public class HelloWorld { private int a; public HelloWorld() { super(); (int v0 = 111;) this.a = v0; } }
  28. Virtual methods - #0 : (in LHelloWorld;) name : 'main'

    type : '()V' access : 0x0001 (PUBLIC) … [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void …
  29. Virtual methods - #0 : (in LHelloWorld;) name : 'main'

    type : '()V' access : 0x0001 (PUBLIC) … [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { } }
  30. [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance

    v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void …
  31. [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/ io/PrintStream; // field@0001 0002:

    new-instance v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; } }
  32. [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance

    v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/ StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); } }
  33. [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance

    v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); String v2 = "Hello World!!”; } }
  34. … 0009: invoke-virtual {v1, v2}, Ljava/lang/ StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006

    000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); String v2 = "Hello World!!”; v1.append(v2); } }
  35. … lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I //

    field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); String v2 = "Hello World!!”; v1.append(v2); int v2 = this.a; } }
  36. … 000e: invoke-virtual {v1, v2}, Ljava/lang/ StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005

    0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); String v2 = "Hello World!!”; v1.append(v2); int v2 = this.a; v1.append(v2); }
  37. … 0011: invoke-virtual {v1}, Ljava/lang/ StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object

    v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { … v1.append(v2); v1.toString(); } }
  38. [0001b4] HelloWorld.main:()V … 0014: move-result-object v1 0015: invoke-virtual {v0, v1},

    Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { … v1.append(v2); v1.toString(); } }
  39. [0001b4] HelloWorld.main:()V … 0015: invoke-virtual {v0, v1}, Ljava/io/ PrintStream;.println:(Ljava/lang/String;)V //

    method@0002 0018: return-void … public class HelloWorld { private int a; … public void main() { … v1.append(v2); v0.println(v1.toString()); } }
  40. [0001b4] HelloWorld.main:()V 0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0001 0002: new-instance

    v1, Ljava/lang/StringBuilder; // type@0005 0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0004 0007: const-string v2, "Hello World!!" // string@0001 0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/ lang/StringBuilder; // method@0006 000c: iget v2, v3, LHelloWorld;.a:I // field@0000 000e: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/ StringBuilder; // method@0005 0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0007 0014: move-result-object v1 0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0002 0018: return-void …
  41. public class HelloWorld { private int a; public HelloWorld() {

    super(); (int v0 = 111;) this.a = v0; } public void main() { java.io.PrintStream v0 = System.out; java.lang.StringBuilder v1 = new StringBuilder(); String v2 = "Hello World!!”; v1.append(v2); int v2 = this.a; v1.append(v2); v0.println(v1.toString()); } }
  42. class CompanionTest { companion object { fun show(i: Int) {

    println("started show method") println("processing show method action $i") println("finished show method") } } }
  43. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(DefaultConstructorMarker defaultConstructorMarker) { this(); } public final void show(int i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } } }
  44. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(DefaultConstructorMarker defaultConstructorMarker) { this(); } public final void show(int i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } } } CompanionΠϯελϯε͕ੜ੒͞ΕΔ & NestedΫϥε͕ఆٛ͞ΕΔ
  45. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(DefaultConstructorMarker defaultConstructorMarker) { this(); } public final void show(int i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } } } CompanionΠϯελϯε͕ੜ੒͞ΕΔ & NestedΫϥε͕ఆٛ͞ΕΔ ͜ΕΛR8ͰίϯύΠϧ͢Δ
  46. public abstract class CompanionTest { public static final void show(int

    i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } }
  47. public abstract class CompanionTest { public static final void show(int

    i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } } Πϯελϯεੜ੒͕ແ͘ͳͬͨ & NestedΫϥε͕ແ͘ͳͬͨ
  48. public abstract class CompanionTest { public static final void show(int

    i) { System.out.println("started show method"); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("processing show method action "); stringBuilder.append(i); System.out.println(stringBuilder.toString()); System.out.println("finished show method"); } } R8Ͱ͸staticϝιουʹม׵͞ΕΔͨΊɺ ΠϯελϯεΛੜ੒͠ͳͯ͘΋ྑ͘ͳ͍ͬͯΔ
  49. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(byte b) { this(); } public static void show(int i) { System.out.println("started show method"); System.out.println("processing show method action ".concat(String.valueOf(i))); System.out.println("finished show method"); } } }
  50. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(byte b) { this(); } public static void show(int i) { System.out.println("started show method"); System.out.println("processing show method action ".concat(String.valueOf(i))); System.out.println("finished show method"); } } }
  51. public final class CompanionTest { public static final Companion Companion

    = new Companion(); public static final class Companion { private Companion() { } public /* synthetic */ Companion(byte b) { this(); } public static void show(int i) { System.out.println("started show method"); System.out.println("processing show method action ".concat(String.valueOf(i))); System.out.println("finished show method"); } } } ProGuradͰ͸CompanionΠϯελϯε͕ফ͑ͳ͍ & NestedΫϥε΋ఆٛ͞Εͨ··
  52. fun main() { lambdaTest { println("Kotlin lambda1") } lambdaTest {

    println("Kotlin lambda2") } lambdaTest { println("Kotlin lambda3") } } private fun lambdaTest(body: () -> Unit) { println("before lambdaTest") body() println("after lambdaTest") }
  53. sget-object v0, LLambdaTestKt$main$1;.INSTANCE:LLambdaTestKt$main$1; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$2;.INSTANCE:LLambdaTestKt$main$2;

    invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$3;.INSTANCE:LLambdaTestKt$main$3; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V
  54. sget-object v0, LLambdaTestKt$main$1;.INSTANCE:LLambdaTestKt$main$1; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$2;.INSTANCE:LLambdaTestKt$main$2;

    invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$3;.INSTANCE:LLambdaTestKt$main$3; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V
  55. sget-object v0, LLambdaTestKt$main$1;.INSTANCE:LLambdaTestKt$main$1; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$2;.INSTANCE:LLambdaTestKt$main$2;

    invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, LLambdaTestKt$main$3;.INSTANCE:LLambdaTestKt$main$3; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V 3ͭͷΫϥε͕ੜ੒͞Εͨ - ϥϜμຖʹΫϥε͕ੜ੒͞ΕΔ
  56. sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$0:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object

    v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$1:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$2:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V
  57. sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$0:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object

    v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$1:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$2:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V
  58. sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$0:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object

    v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$1:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V sget-object v0, L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI;.INSTANCE$2:L-$ $LambdaGroup$ks$BpS7w8o_KOkdSUy0gHGt84S7irI; invoke-static {v0}, LLambdaTestKt;.lambdaTest:(Lkotlin/jvm/functions/ Function0;)V LambdaGroupͱݺ͹ΕΔ࠷దԽ 1ͭͷΫϥεʹϥϜμΛ·ͱΊΔ͜ͱͰɺ ΫϥεɺϝιουΛݮΒ͢͜ͱ͕Ͱ͖Δ
  59. // R8.java … IRConverter converter = new IRConverter(appView, options, timing,

    printer, mainDexClasses, rootSet); converter.optimize(application, executorService);
  60. // R8.java … IRConverter converter = new IRConverter(appView, options, timing,

    printer, mainDexClasses, rootSet); converter.optimize(application, executorService); IR: Intermediate Representations ιʔείʔυͱ࠷ऴ੒Ռͷؒʹ͋Δதؒදݱܗࣜ
  61. // R8.java … IRConverter converter = new IRConverter(appView, options, timing,

    printer, mainDexClasses, rootSet); converter.optimize(application, executorService);
  62. // IRConverter.java public DexApplication optimize( DexApplication application, ExecutorService executorService )

    throws ExecutionException { computeReachabilitySensitivity(application); removeLambdaDeserializationMethods(); collectLambdaMergingCandidates(application); collectStaticizerCandidates(application); …
  63. // IRConverter.java public DexApplication optimize( DexApplication application, ExecutorService executorService )

    throws ExecutionException { computeReachabilitySensitivity(application); removeLambdaDeserializationMethods(); collectLambdaMergingCandidates(application); collectStaticizerCandidates(application); …
  64. private void collectLambdaMergingCandidates( DexApplication application ) { if (lambdaMerger !=

    null) { lambdaMerger.collectGroupCandidates( application, appInfo.withLiveness(), options ); } }
  65. private void collectLambdaMergingCandidates( DexApplication application ) { if (lambdaMerger !=

    null) { lambdaMerger.collectGroupCandidates( application, appInfo.withLiveness(), options ); } }
  66. private void collectLambdaMergingCandidates( DexApplication application ) { if (lambdaMerger !=

    null) { lambdaMerger.collectGroupCandidates( application, appInfo.withLiveness(), options ); } } LambdaMerger: ෳ਺ͷϥϜμΛ1ͭͷάϧʔϓʹϚʔδ͢Δ
  67. // LambdaMerger.collectGroupCandidates app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo()

    && cls.getKotlinInfo().isSyntheticClass() && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } });
  68. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } });
  69. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } }); pin͞Ε͍ͯͳ͍ == มܗ͕ՄೳͳΫϥεΛநग़
  70. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } }); Kotlin && ߹੒Ϋϥε && ϥϜμࣜ
  71. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } }); classͷॱ൪Λιʔτ
  72. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } }); LambdaGroupIdͱLambdaGroup Λ࡞Δ
  73. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } }); LambdaGroupIdΠϯελϯεͷग़ྗ capture: interface: Lkotlin/jvm/functions/Function0; package: signature: null main method name: invoke main method: Proto V void main annotations: com.android.tools.r8.graph.DexAnnotationSet@1 main param annotations: com.android.tools.r8.graph.ParameterAnnotationsList@1 inner: none
  74. app.classes() .stream() .filter(cls -> !infoWithLiveness.isPinned(cls.type)) .filter(cls -> cls.hasKotlinInfo() && cls.getKotlinInfo().isSyntheticClass()

    && cls.getKotlinInfo().asSyntheticClass().isLambda()) .sorted((a, b) -> a.type.slowCompareTo(b.type)) .forEachOrdered(lambda -> { try { LambdaGroupId id = KotlinLambdaGroupIdFactory.create(kotlin, lambda, options); LambdaGroup group = groups.computeIfAbsent(id, LambdaGroupId::createGroup); group.add(lambda); lambdas.put(lambda.type, group); } catch (LambdaStructureError error) { … } });
  75. // IRConverter.java public DexApplication optimize( DexApplication application, ExecutorService executorService )

    throws ExecutionException { computeReachabilitySensitivity(application); removeLambdaDeserializationMethods(); collectLambdaMergingCandidates(application); collectStaticizerCandidates(application); …
  76. // IRConverter.java public DexApplication optimize( DexApplication application, ExecutorService executorService )

    throws ExecutionException { … printPhase("Lambda merging finalization"); finalizeLambdaMerging( application, feedback, builder, executorService, synthesizedClasses ); …
  77. private void finalizeLambdaMerging( DexApplication application, OptimizationFeedback directFeedback, Builder<?> builder, ExecutorService

    executorService, Map<DexType, DexProgramClass> synthesizedClasses) throws ExecutionException { if (lambdaMerger != null) { lambdaMerger.applyLambdaClassMapping( application, this, directFeedback, builder, executorService, synthesizedClasses); } }
  78. private void finalizeLambdaMerging( DexApplication application, OptimizationFeedback directFeedback, Builder<?> builder, ExecutorService

    executorService, Map<DexType, DexProgramClass> synthesizedClasses) throws ExecutionException { if (lambdaMerger != null) { lambdaMerger.applyLambdaClassMapping( application, this, directFeedback, builder, executorService, synthesizedClasses); } }
  79. // LambdaMerger.java private void rewriteLambdaReferences(…) { … for (DexEncodedMethod method

    : methods) { DexEncodedMethod mappedMethod = converter.graphLense().mapDexEncodedMethod( method, converter.appInfo, synthesizedClasses); … }
  80. // LambdaMerger.java private void rewriteLambdaReferences(…) { … for (DexEncodedMethod method

    : methods) { DexEncodedMethod mappedMethod = converter.graphLense().mapDexEncodedMethod( method, converter.appInfo, synthesizedClasses); … }
  81. // LambdaMerger.java private void rewriteLambdaReferences(…) { … for (DexEncodedMethod method

    : methods) { DexEncodedMethod mappedMethod = converter.graphLense().mapDexEncodedMethod( method, converter.appInfo, synthesizedClasses); … } GraphLense: ίʔυ৘ใΛ֨ೲ͓ͯ͠Γɺ ϝιουɺϑΟʔϧυͷҠಈɺ ΫϥεͷmappingͳͲΛߦ͏ɻ
  82. private void rewriteLambdaReferences(…) { … for (DexEncodedMethod method : methods)

    { DexEncodedMethod mappedMethod = converter.graphLense().mapDexEncodedMethod( method, converter.appInfo, synthesizedClasses); … } mapDexEncodedMethod: ੜ੒ͨ͠߹੒ΫϥεʢLambdaGroupʣΛGraphLenseʹ ొ࿥͢Δ
  83. private void rewriteLambdaReferences(…) { … for (DexEncodedMethod method : methods)

    { DexEncodedMethod mappedMethod = converter.graphLense().mapDexEncodedMethod( method, converter.appInfo, synthesizedClasses); … }
  84. … val retrofit = Retrofit .Builder() .build() val api =

    retrofit.create(Api::class.java) api.hoge().execute() } 
 interface Api { @GET fun hoge(): Call<Void> }
  85. .method public onCreate(Landroid/os/Bundle;)V .line 1 sget-object p1, Lretrofit2/Platform;->a:Lretrofit2/Platform; .line 2

    new-instance p1, Ljava/util/ArrayList; invoke-direct {p1}, Ljava/util/ArrayList;-><init>()V new-instance p1, Ljava/util/ArrayList; invoke-direct {p1}, Ljava/util/ArrayList;-><init>()V .line 3 new-instance p1, Ljava/lang/IllegalStateException; const-string v0, "Base URL required." invoke-direct {p1, v0}, Ljava/lang/IllegalStateException;- ><init>(Ljava/lang/String;)V throw p1 .end method
  86. ... Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); throw new IllegalStateException("Base URL required."); }
  87. ... Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); throw new IllegalStateException("Base URL required."); } IllegalStateExceptionͰϝιου͕ ऴΘͬͯΔ
  88. public static final class Builder { private @Nullable HttpUrl baseUrl;

    public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); return baseUrl(HttpUrl.get(baseUrl)); } public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } … } }
  89. public static final class Builder { private @Nullable HttpUrl baseUrl;

    public Builder baseUrl(String baseUrl) { checkNotNull(baseUrl, "baseUrl == null"); return baseUrl(HttpUrl.get(baseUrl)); } public Retrofit build() { if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } … } } baseUrl͕nullͳΒthrow͍ͯ͠Δ
  90. … val retrofit = Retrofit .Builder() .build() val api =

    retrofit.create(Api::class.java) api.hoge().execute() }
  91. … Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); if (baseUrl == null) { throw new IllegalStateException("Base URL required."); } val api = retrofit.create(Api::class.java) api.hoge().execute() }
  92. … Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); if (null == null) { throw new IllegalStateException("Base URL required."); } val api = retrofit.create(Api::class.java) api.hoge().execute() }
  93. … Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); if (true) { throw new IllegalStateException("Base URL required."); } val api = retrofit.create(Api::class.java) api.hoge().execute() }
  94. … Platform platform = Platform.a; ArrayList arrayList = new ArrayList();

    arrayList = new ArrayList(); throw new IllegalStateException("Base URL required."); }
  95. class MainActivity : AppCompatActivity() { @Inject lateinit var appService: AppService

    @Inject lateinit var appService2: AppService2 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val appComponent = DaggerAppComponent.builder().build() appComponent.inject(this) appService.test().execute() appService2.test().execute() } } interface AppService { @GET("todos/1") fun test(): Call<TestData> } interface AppService2 { @GET("todos/1") fun test(): Call<TestData> }
  96. method public onCreate(Landroid/os/Bundle;)V .registers 3 invoke-super {p0, p1}, La/b/e/a/m;->onCreate(Landroid/os/Bundle;)V const

    p1, 0x7f09001c invoke-virtual {p0, p1}, La/b/e/a/m;->setContentView(I)V .line 1 new-instance p1, Lcom/github/satoshun/example/AppModule1; invoke-direct {p1}, Lcom/github/satoshun/example/AppModule1;-><init>()V .line 2 invoke-virtual {p1}, Lcom/github/satoshun/example/AppModule1;->a()Lcom/github/satoshun/example/AppService; move-result-object p1 const-string v0, "Cannot return null from a non-@Nullable @Provides method" invoke-static {p1, v0}, La/b/b/a/a/a;->a(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object; .line 3 iput-object p1, p0, Lcom/github/satoshun/example/MainActivity;->o:Lcom/github/satoshun/example/AppService; .line 4 invoke-static {}, Lcom/github/satoshun/example/AppModule2_ProvideService2Factory;->a()Lcom/github/satoshun/example/AppService2; move-result-object p1 .line 5 iput-object p1, p0, Lcom/github/satoshun/example/MainActivity;->p:Lcom/github/satoshun/example/AppService2; .line 6 iget-object p1, p0, Lcom/github/satoshun/example/MainActivity;->o:Lcom/github/satoshun/example/AppService; const/4 v0, 0x0 if-eqz p1, :cond_3d invoke-interface {p1}, Lcom/github/satoshun/example/AppService;->a()Lretrofit2/Call; move-result-object p1 invoke-interface {p1}, Lretrofit2/Call;->execute()Lretrofit2/Response; iget-object p1, p0, Lcom/github/satoshun/example/MainActivity;->p:Lcom/github/satoshun/example/AppService2; if-eqz p1, :cond_37 invoke-interface {p1}, Lcom/github/satoshun/example/AppService2;->a()Lretrofit2/Call;
  97. public final class MainActivity extends m { public AppService o;

    public AppService2 p; public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView((int) R.layout.activity_main); Object a = new AppModule1().a(); a.a(a, "Cannot return null from a non-@Nullable @Provides method"); this.o = a; this.p = AppModule2_ProvideService2Factory.a(); AppService appService = this.o; if (appService != null) { appService.a().execute(); AppService2 appService2 = this.p; if (appService2 != null) { appService2.a().execute(); return; } else { e.a.a.a.a("appService2"); throw …; } } e.a.a.a.a("appService"); throw …; } }
  98. public final class MainActivity extends m { public AppService o;

    public AppService2 p; public void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView((int) R.layout.activity_main); Object a = new AppModule1().a(); a.a(a, "Cannot return null from a non-@Nullable @Provides method"); this.o = a; this.p = AppModule2_ProvideService2Factory.a(); AppService appService = this.o; if (appService != null) { appService.a().execute(); AppService2 appService2 = this.p; if (appService2 != null) { appService2.a().execute(); return; } else { e.a.a.a.a("appService2"); throw …; } } e.a.a.a.a("appService"); throw …; } } AppComponent͕ফ͑ͨ!! AppComponentͷ֤ϝιου͕ inlineԽ͞ΕɺऔΓআ͔Εͨɻ