Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can anyone explain the Proguard configuration setting: -keep @interface *

This is the config setting in question: -keep @interface *

This setting is referenced in this post: https://stackoverflow.com/a/17437740/367544

And here in the Proguard manual: https://www.guardsquare.com/en/proguard/manual/troubleshooting#notkept

But the manual (or the post) doesn't explain how or why this config setting works. I would think that this config value would keep any annotations that were defined in your application. I emphasize the word defined here because I want to compare it to where an annotation is used. So if I defined an annotation in my code like public @interface MyAnnotation {} then I would expect this config setting to preserve it. However, if I were to use my annotation in another class like public class MyClass { @MyAnnotation public void run(){} } then I would not expect this config setting to preserve it there. I would think that to preserve the annotation where it's used, you would need a setting like -keep class * { @interface <methods>; }. However, my understanding is clearly wrong, because the -keep @interface * config setting does preserve the annotations where they're used.

Can anyone explain why the -keep @interface * config setting affects annotations where they're used inside other classes? Additionally, the Proguard manual never explains how to use @interface keyword at all. Is that like a wildcard for any annotation? Or does it refer to the definition of the annotation like in my example public @interface MyAnnotation {}? Or is it something else entirely?

like image 786
Dasmowenator Avatar asked Apr 22 '18 03:04

Dasmowenator


1 Answers

When every interface is compiled, even with proguard, it should create a valid class file that can be used in the java virtual machine. Java has specific naming rules for connecting interfaces and classes in packages with the files.

So for example even if interface VeryImportantInterface of package com.mycompany.mypackage is obfuscated and as a result you get: interface a in package b.c.d java expects to find interface a in package b.c.d in a file named a.class

Similar rules apply for inner classes and interfaces.

So if you do obfuscate the definition of a class or interface, it will have to be mentioned everywhere with its obfuscated name.Otherwise if for example class MyClass.class is obfuscated to a.class and another class, e.g. MyClassReference still references this class as MyClass then a ClassNotFoundException will be thrown when MyClassReference attempts to use MyClass for the first time.

Regarding -keep @interface * As specified in ProGuard RefCard

'keep' prevents classes and class members from being removed or renamed.

ProGuard RefCard also mentions that wildcard * can be used

  1. * can be used for any number of characters (but not the package separator)
  2. the class name * refers to any class, irrespective of its package.
  3. * matches any field or method

So -keep @interface * according to the definitions above applies to public @interface MyAnnotation {} since its name match the wildcard *. Since according to the definition MyAnnotation is not to be removed, it is not removed from anywhere.

On the contrary -keep class * { @interface <methods>; } is more specific and would keep only the usages of the annotation.

Another thing to consider is that keep is followed by a Class specification. And based on the Class specification

The @ specifications can be used to restrict classes and class members to the ones that are annotated with the specified annotation types. An annotationtype is specified just like a classname.

During the shrinking process pro guard will delete all the methods and members that are directly or indirectly used plus the ones specified by -keep. However it does not explicitly mention what it does with annotations. Pro-Guard mentions regarding shrinking the following:

By default, shrinking is applied; all classes and class members are removed, except for the ones listed by the various -keep options, and the ones on which they depend, directly or indirectly. Shrinking Options So one case could be that pro-guard somehow detects that the annotation is used and prevents it from beeing removed during shrinking. Another case would be that the annotations are considered metadatum of the methods and not beeing considered members. It is really not obvious or well documented in proguard documentation.

You can use -whyareyoukeeping @interface * and -verbose to get a feedback from Prog-Guard on why it is keeping the related interfaces.

Update: Since the result of the above configuration directives was: ... is kept by a directive in the configuration., it can only be concluded that the -keep @interface * actually . Hence it is does not provide any additional clarification. Without any specific explanation on the Pro-Guard documentation I think the following 2 possible explanations are possible: 1. The proguard shrinking step considers that the annotation is used in some part of the code, thus needed and is not reduced. 2. The class_specification @interface * matches both annotated methods and annotation declarations.

like image 76
Spyros K Avatar answered Oct 17 '22 08:10

Spyros K