Status Update
Comments
ch...@google.com <ch...@google.com>
mk...@google.com <mk...@google.com> #2
Thank you for the dump and APK. I was not able to reproduce a crash on the APK but I also don't know what buttons to press to have the issue trigger.
With that said, there is no keep rule keeping the class of the fields:
# Do not strip any field that is annotated with @SerializedName
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
This says that we need to keep members if we can see the class instantiated (since these are instance fields) - if not the class can be merged/pruned.
And if we prune the class all generic signatures pointing to TopFriendSuggestionJson
are removed.
You can use the following rule instead:
# Do not strip any fields or remove classes that is annotated with @SerializedName
-keepclasseswithmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
However, it seems like there is reflective behavior going on that is not captured in the program or keep rules. You also have this rule:
# Ensure init methods are preserved if class has @SerializedName annotations
# Ref: https://partnerissuetracker.corp.google.com/issues/150189783#comment2
-if class *
-keepclasseswithmembers,allowshrinking,allowobfuscation class <1> {
<init>(...);
@com.google.gson.annotations.SerializedName <fields>;
}
If TopFriendSuggestionJson
was referenced in the residual we would have kept the class. From the mapping I could see that mapTopFriendSuggestionJsonToSnapchatterDisplayInfo
. Why I do not know but that part of the program is consired dead by R8. I guess the only reference may be the field val result = Gson.fromJson(data, object : TypeToken<List<TopFriendSuggestionJson>>() {}.type)
where the generic type is now TypeToken<List<Object>>
.
So if you know you need to be able to parse the message from json always you could create a base interface or annotation, annotate TopFriendSuggestionJson
and put a specific keep rule for that to ensure not adding to many data unneeded objects.
br...@snapchat.com <br...@snapchat.com> #3
With the way we setup the rules, we expect that the class only kept if referenced by residuals with the expectation is that these types of crashes are possible if the residual is dead code removed. We don't want a stronger keep rule as it would lead to a large amount of extra code to be kept.
In this case, the problem seems to lie with mapTopFriendSuggestionJsonToSnapchatterDisplayInfo
getting stripped out, which does not look correct and leads to TopFriendSuggestionJson
getting removed.
We've been using an explicit keep rule to mitigate the issue, but there seems something wrong at a deeper level
mk...@google.com <mk...@google.com> #4
It seems like this rule is incorrect:
# Ensure init methods are preserved if class has @SerializedName annotations
# Ref: https://partnerissuetracker.corp.google.com/issues/150189783#comment2
-if class *
-keepclasseswithmembers,allowshrinking,allowobfuscation class <1> {
<init>(...);
@com.google.gson.annotations.SerializedName <fields>;
}
We are actually allowed to remove the <init>(...)
if we cannot see any references to it - and I believe that is the most cases for things deserialized by json. The rule suggested in
-if class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep class <1> {
<init>();
}
I also uploaded a test to show that we can remove the <init>()
call of a data classes:
What basically can happen is that if we do not see any calls to the constructor, we can remove it and thereby not consider the data class to be instantiated. That will allow us to rewrite instance getters to throwing NPE and that can remove the reference.
Using the following keep rules should keep the TopFriendSuggestionJson
class:
# Ensure init methods are preserved if class has @SerializedName annotations
# Ref: https://partnerissuetracker.corp.google.com/issues/150189783#comment2
-if class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keepclasseswithmembers,allowobfuscation class <1> {
<init>(...);
}
-if class *
-keepclasseswithmembers,allowshrinking,allowobfuscation class <1> {
@com.google.gson.annotations.SerializedName <fields>;
}
From what I can see that should be sufficient to keep the class.
br...@snapchat.com <br...@snapchat.com> #5
Thanks. This seems to work and doesn't have any negative effect to our app size.
Description
Background
We've got the following keep rule:
and the following code:
We are seeing that the
TopFriendSuggestionJson
type is being removed and the outputted code looks like the following,class ... extends TypeToken<List<Object>>
, which leads to an exception to be thrown.I recall seeing similar issue in the past where this would occur when the fields / methods of the type are never referenced. However, in this case we do have a method that should be invoking the fields later on and thus preserving the class:
This method also seems to be excluded from the final artifact. The offending original class is
TopSuggestedFriendV2NotifHandlerImpl
. I'll share a compiler dump over email