Add additional information to compatibility faq regarding full-mode

Bug: 188690067
Bug: 188703877
Change-Id: I754395adf818d3cd678512e969af0feeb9af3e60
diff --git a/compatibility-faq.md b/compatibility-faq.md
index f3dde4e..3ba23c8 100644
--- a/compatibility-faq.md
+++ b/compatibility-faq.md
@@ -1,10 +1,38 @@
-# R8 compatibility FAQ
+# R8 FAQ
 
 R8 uses the same configuration specification language as ProGuard, and tries to
 be compatible with ProGuard. However as R8 has different optimizations it can be
-necessary to change the configuration when switching to R8.
+necessary to change the configuration when switching to R8. R8 provides two
+modes, R8 compatibility mode and R8 full mode. R8 compatibility mode is default
+in Android Studio and is meant to make the transition to R8 from ProGuard easier
+by limiting the optimizations performed by R8.
 
-This FAQ collects some of the common issues.
+## R8 full mode
+In non-compat mode, also called “full mode”, R8 performs more aggressive
+optimizations, meaning additional ProGuard configuration rules may be required.
+Full mode can be enabled by adding `android.enableR8.fullMode=true` in the
+`gradle.properties` file. The main differences compared to R8 compatibility mode
+are:
+
+- The default constructor (`<init>()`) is not implicitly kept when a class is
+kept.
+- The default constructor (`<init>()`) is not implicitly kept for types which
+are only used with `ldc`, `instanceof` or `checkcast`.
+- The enclosing classes of fields or methods that are matched by a
+`-keepclassmembers` rule are not implicitly considered to be instantiated.
+Classes that are only instantiated using reflection should be kept explicitly
+with a `-keep` rule.
+- Default methods are not implicitly kept as abstract methods.
+- Attributes (such as `Signature`) and annotations are only kept for classes,
+methods and fields which are matched by keep rules even when `-keepattributes`
+is specified.
+Additionally, for attributes describing a relationship such as `InnerClass` and
+`EnclosingMethod`, non-compat mode requires both endpoints being kept.
+
+# Troubleshooting
+
+The rest of this document describes known issues with libraries that use
+reflection.
 
 ## GSON
 
@@ -21,7 +49,7 @@
 
 ```
 -keepclassmembers,allowobfuscation class * {
-  @com.google.gson.annotations.SerializedName <fields>;
+ @com.google.gson.annotations.SerializedName <fields>;
 }
 ```
 
@@ -35,7 +63,7 @@
 
 ```
 -keepclassmembers class MyDataClass {
-  !transient <fields>;
+ !transient <fields>;
 }
 ```
 
@@ -46,15 +74,15 @@
 ### Error `java.lang.IllegalArgumentException: class <class name> declares multiple JSON fields named <name>`
 
 This can be caused by obfuscation selecting the same name for private fields in
-several classes in a class hierachy. Consider the following example:
+several classes in a class hierarchy. Consider the following example:
 
 ```
 class A {
-  private String fieldInA;
+ private String fieldInA;
 }
 
 class B extends A {
-  private String fieldInB;
+ private String fieldInB;
 }
 ```
 
@@ -66,33 +94,33 @@
 
 ```
 class A {
-  private transient String fieldInA;
+ private transient String fieldInA;
 }
 
 class B extends A {
-  private transient String fieldInB;
+ private transient String fieldInB;
 }
 ```
 
 If the fields _are_ to be serialized, the annotation `SerializedName` can be
-used to fix the `IllegalArgumentException` together the rule to keep fields
+used to fix the `IllegalArgumentException` together with the rule to keep fields
 annotated with `SerializedName`
 
 ```
 class A {
-  @SerializedName("fieldInA")
-  private String fieldInA;
+ @SerializedName("fieldInA")
+ private String fieldInA;
 }
 
 class B extends A {
-  @SerializedName("fieldInB")
-  private String fieldInB;
+ @SerializedName("fieldInB")
+ private String fieldInB;
 }
 ```
 
 ```
 -keepclassmembers,allowobfuscation class * {
-  @com.google.gson.annotations.SerializedName <fields>;
+ @com.google.gson.annotations.SerializedName <fields>;
 }
 ```
 
@@ -101,15 +129,26 @@
 the fields to be renamed by R8 to the same name, but GSON serialization will
 work as expected.
 
-# R8 full mode
+### GSON with full mode
 
-In full mode, R8 performs more aggressive optimizations, meaning that additional
-ProGuard configuration rules may be required. This section highlights some
-common issues that have been seen when using full mode.
+GSON uses type tokens to serialize and deserialize generic types.
+
+```TypeToken<List<String>> listOfStrings = new TypeToken<List<String>>() {};```
+
+The anonymous class will have a generic signature argument of `List<String>` to
+the super type `TypeToken` that is reflective read for serialization. It
+is therefore necessary to keep both the `Signature` attribute, the
+`com.google.gson.reflect.TypeToken` class and all sub-types:
+
+```
+-keepattributes Signature
+-keep class com.google.gson.reflect.TypeToken { *; }
+-keep class * extends com.google.gson.reflect.TypeToken
+```
 
 ## Retrofit
 
-### Object instantiated with Retrofit's `create()` method is always replaced with `null`
+### Objects instantiated with Retrofit's `create()` method are always replaced with `null`
 
 This happens because Retrofit uses reflection to return an object that
 implements a given interface. The issue can be resolved by using the most recent
@@ -117,3 +156,18 @@
 
 See also https://github.com/square/retrofit/issues/3005 ("Insufficient keep
 rules for R8 in full mode").
+
+### Kotlin suspend functions and generic signatures
+
+For Kotlin suspend functions the generic signature is reflectively read.
+Therefore keeping the `Signature` attribute is necessary. Full mode only keeps
+the signature for kept classes thus a keep on `kotlin.coroutines.Continuation` in
+addition to a keep on the api classes is needed:
+```
+-keepattributes Signature
+-keep class kotlin.coroutines.Continuation
+```
+
+This should be included automatically from versions built after the pull-request
+https://github.com/square/retrofit/pull/3563
+