Proguard not keeping class although it says so - java

I'm trying to keep proguard from renaming/optimizing classes which have a certain annotaion. There are quite a few examples out there and it should be straight forward but proguard isn't behaving as I would expect it to be.
Issue
Proguard v6.2.2 obfuscates classes annotated with #KeepClass although -whyareyoukeeping shows test.KeepMe is kept by a directive in the configuration.
I can reproduce the issue with a simple 3 file project.
Proguard config:
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 3
-allowaccessmodification
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-keep public class test.Entry {
public static void main(java.lang.String[]);
}
-keep #proguard.annotation.KeepClass public class * {
*;
}
-whyareyoukeeping class test.KeepMe
Class which should be kept:
import proguard.annotation.KeepClass;
#KeepClass
public class KeepMe
{
}
Proguard log:
Explaining why classes and class members are being kept...
Printing usage to [D:\Development\Projects\ProguardTest\build\usage.txt]...
test.KeepMe
is kept by a directive in the configuration.
Removing unused program classes and class elements...
Original number of program classes: 3
Final number of program classes: 2
And finally the files in the processed jar file:
- test
|- Entry.class
|- a.class (Obfuscated KeepMe class)
If however I explicitly list the class in the proguard configuration using
-keep class test.KeepMe{*;}
proguard reports the same log output but the class is untouched (as expected)
Am I missing something or is this a bug in proguard?

As it turns out the issue was actually related to a bug in proguard. After trying the latest beta it's working as expected.

Related

How to avoid proguard to modify the package structure when obfuscating

I have a android library project with the following structure:
- com.domain
------------.internal //internal classes of the library
------------.thirdPartyLib //3rd party library package renamed
------------.library.publicclasses //All the public classes of the library
The idea is to configure progrard to:
- Don't remove any unused classes (since it is a library)
- Obfuscate and optimize everything (including class and methods names) except the classes under **publicclasses** that should keep their names and public elements unchanged
Currently my proguard config is:
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-keep,allowobfuscation class com.domain.** {*;}
-keep class com.domain.library.publicclasses.** {public *;}
-keep class com.domain.library.publicclasses.Foo {public protected *;}
The result of this config is:
- com.domain.library.publicclasses //All the public classes of the library
- a.a.a /// all the internal and thirdPartyLib classes
My problem is the a.a.a classes are colliding with other library obfuscated classes, so i'd like the final class structure too be
- com.domain.library
--------------------.publicclasses //All the public classes of the library
--------------------.a /// all the internal and thirdPartyLib classes
Keeping the obfuscated classes under my domain so it can't collide.
How can I achieve this?

Is it possible to let ProGuard keep elements with RetentionPolicy.SOURCE?

I'm using the #VisibleForTesting annotation located in the Android Support Annotations library, and it looks like this:
#Retention(SOURCE)
public #interface VisibleForTesting {
}
As I understand it, ProGuard operates on the .class files and since this annotation isn't available at compile time due to its retention policy, all the annotated methods are stripped away. I'd like to run automated tests on my app and use the methods exposed for testing to verify that the ProGuard configuration doesn't break any use cases.
Is it possible to configure ProGuard to keep these elements somehow? So far I've tried:
-keep #android.support.annotation.VisibleForTesting class *
-keep class android.support.annotation.** {
#**.VisibleForTesting *;
}
-keep interface android.support.annotation.** {
#**.VisibleForTesting *;
}
And:
-keep interface android.support.annotation.VisibleForTesting
-keepclasseswithmembers class * {
#android.support.annotation.VisibleForTesting *;
}
-keepclassmembers class ** {
#android.support.annotation.VisibleForTesting *;
}
These two configurations do not work. If I annotate the methods with #Keep as well, and configure ProGuard to keep those methods, the methods are kept and the tests pass. However, by doing that I have to annotate all methods with two annotations.
Is it possible to hook into the annotation processor and override the retention policy for #VisibleForTesting? Or is that already too late in the build process?
Guava's #VisibleForTesting uses RetentionPolicy.CLASS, while Android Support Annotations Library uses RetentionPolicy.SOURCE. I'm considering posting a request to change the policy, but I suppose it's set to SOURCE for a reason, possibly due to performance and a very slightly increased file size?
Are there any options other than using two annotations (#VisibleForTesting and #Keep)?
Annotations with a RetentionPolicy == SOURCE are not present in .class files on which ProGuard is operating. Thus there is no way to use them in rules as they will never match.
Annotations with RetentionPolicy == CLASS should work fine. If needed, they can even be removed in release builds using ProGuard.

Android Proguard - keep class and methods

I need to make sure the method
java.lang.String -> isEmpty()
Is present in the compiled code.
Will Proguard keep this method if it is referenced somewhere in my code? Or is it better to include
-keep class java.lang.String { *; }
Into Proguard configuration file?
I'm asking because to fix java.lang.ClassNotFoundException this code is used:
try {
Class.forName("android.os.AsyncTask");
}
catch(Throwable ignore) {}
Instead of adding this to Proguard:
-keep class android.os.AsyncTask { *; }
If you're referencing that method in your code, it should be kept by Proguard. From the documentation:
The ProGuard tool shrinks, optimizes, and obfuscates your code by
removing unused code and renaming classes, fields, and methods with
semantically obscure names
So if the code is being used, there's no reason why Proguard would remove it.

Getting "Note: duplicate definition of library class" Proguard

Below is the application.pro which is the configuration to obfuscate the spring related standalone application:
# This ProGuard configuration file illustrates how to process applications.
# Usage:
# java -jar proguard.jar #applications.pro
#
# Specify the input jars, output jars, and library jars.
-injars xyz.jar
-outjars xyz_out.jar
-libraryjars C:\Program Files\Java\jdk1.8.0_20\jre\lib\rt.jar
-libraryjars <LocationOfJar>/xyz.jar
#-libraryjars servlet.jar
#-libraryjars jai_core.jar
#...
# Save the obfuscation mapping to a file, so you can de-obfuscate any stack
# traces later on. Keep a fixed source file attribute and all line number
# tables to get line numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.
-printmapping out.map
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# Preserve all annotations.
-keepattributes *Annotation*
# You can print out the seeds that are matching the keep options below.
#-printseeds out.seeds
# Preserve all public applications.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your application doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Your application may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:
# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface
#Warnings to be removed. Otherwise maven plugin stops, but not dangerous
-keep public class com.sun.xml.internal.**
-keep public class com.sun.istack.internal.**
-keep public class org.codehaus.jackson.**
-keep public class org.springframework.**
-keep public class java.awt.**
-keep public class javax.security.**
-keep public class java.beans.**
-keep public class javax.xml.**
-keep public class java.util.**
-keep public class org.w3c.dom.**
-keep public class com.google.common.**
-keep public class org.apache.**
-keep public class org.xnio.**
-keep public class javax.xml.**
-keep public class java.time.**
-keep public class com.sun.corba.**
-keep public class org.hibernate.**
-keep public class antlr.**
-dontwarn com.sun.xml.internal.**
-dontwarn com.sun.istack.internal.**
-dontwarn org.codehaus.jackson.**
-dontwarn org.springframework.**
-dontwarn java.awt.**
-dontwarn javax.security.**
-dontwarn java.beans.**
-dontwarn javax.xml.**
-dontwarn java.util.**
-dontwarn org.w3c.dom.**
-dontwarn com.google.common.**
-dontwarn org.apache.**
-dontwarn org.xnio.**
-dontwarn javax.xml.**
-dontwarn java.time.**
-dontwarn com.sun.corba.**
-dontwarn org.hibernate.**
-dontwarn antlr.**
-dontskipnonpubliclibraryclasses
When I run:
java -jar proguard.jar #applications.pro
I get this below error:
Note: duplicate definition of library class
And output is not generated as given in the application.pro:
Note: there were 166 classes trying to access generic signatures using reflection.
You should consider keeping the signature attributes
(using '-keepattributes Signature').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 21 classes trying to access enclosing classes using reflection.
You should consider keeping the inner classes attributes
(using '-keepattributes InnerClasses').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 5 classes trying to access enclosing methods using reflection.
You should consider keeping the enclosing method attributes
(using '-keepattributes InnerClasses,EnclosingMethod').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 563 library classes explicitly being kept.
You don't need to keep library classes; they are already left unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#libraryclass)
Note: there were 55 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 4 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Note: there were 292 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Warning: there were 5329 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 117 instances of library classes depending on program classes.
You must avoid such dependencies, since the program classes will
be processed, while the library classes will remain unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)
Warning: there were 42 unresolved references to program class members.
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
Error: Please correct the above warnings first.
How to resolve this issue?

MalformedParameterizedTypeException when using proguard

I'm using proguard to shrink a shaded jar for use as a command line tool. The shaded jar works fine but I'm getting an exception when running the jar created by proguard. The app uses Guice injection and I added configuration that I found on SO, mostly in this answer.
This is the Exception:
Exception in thread "main" java.lang.reflect.MalformedParameterizedTypeException
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:60)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:53)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:95)
at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:105)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:140)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.ClassRepository.getSuperclass(ClassRepository.java:84)
at java.lang.Class.getGenericSuperclass(Class.java:696)
at com.google.inject.internal.MoreTypes.getGenericSupertype(MoreTypes.java:273)
at com.google.inject.TypeLiteral.getSupertype(TypeLiteral.java:257)
at com.google.inject.spi.InjectionPoint.hierarchyFor(InjectionPoint.java:755)
at com.google.inject.spi.InjectionPoint.getInjectionPoints(InjectionPoint.java:635)
at com.google.inject.spi.InjectionPoint.forInstanceMethodsAndFields(InjectionPoint.java:356)
at com.google.inject.internal.ConstructorBindingImpl.getInternalDependencies(ConstructorBindingImpl.java:151)
at com.google.inject.internal.InjectorImpl.getInternalDependencies(InjectorImpl.java:585)
at com.google.inject.internal.InjectorImpl.cleanup(InjectorImpl.java:543)
at com.google.inject.internal.InjectorImpl.initializeJitBinding(InjectorImpl.java:529)
at com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:847)
at com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:772)
at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:256)
at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:205)
at com.google.inject.internal.InjectorImpl.getInternalFactory(InjectorImpl.java:853)
at com.google.inject.internal.FactoryProxy.notify(FactoryProxy.java:46)
at com.google.inject.internal.ProcessedBindingData.runCreationListeners(ProcessedBindingData.java:50)
at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:133)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
at com.google.inject.Guice.createInjector(Guice.java:95)
at com.google.inject.Guice.createInjector(Guice.java:72)
at com.google.inject.Guice.createInjector(Guice.java:62)
at com.acme.ui.cli.Main.main(Main.java:44)
And this the configuration that's producing it:
-injars acme-cli-0.2.1-SNAPSHOT.jar
-outjars target/acme-cli-0.2.1-SNAPSHOT.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/jce.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/jsse.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/rt.jar
-dontobfuscate
-dontpreverify
-dontoptimize
-printmapping mapping.map
-ignorewarnings
-keepattributes *Annotation*,Signature
# Keep - Applications. Keep all application classes, along with their 'main' methods.
-keep public class com.acme.ui.cli.Main {
public static void main(java.lang.String[]);
}
# Keep Guice-related classes
-keep public class javax.inject.**
-keep class com.google.inject**
-keep class * extends com.google.inject.AbstractModule
# keeps all fields and Constructors annotated with #Inject and #AssistedInject
-keepclasseswithmembers class * {
#com.google.inject.Inject <fields>;
#com.google.inject.Inject <init>(...);
}
-keepclasseswithmembers class * {
#com.google.inject.assistedinject.AssistedInject <fields>;
#com.google.inject.assistedinject.AssistedInject <init>(...);
}
When I add this the problem goes away:
-keep class * {
<init>(...);
}
But it keeps many more classes and doubles the size of the jar. I'm using proguard 4.10 and tried 4.9 too. These are some of the option I've experimented with that seemed most relevant:
-keepattributes *
-keepparameternames
-keep class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl {
<init>(...);
}
Since it's seems related to Guice and keeping all constructors solves the problem, I've also experimented with the various ways you can configure the keep options without results. But I must say that I don't understand them fully.
I'm not sure if it's related to the problem, but what looks odd is that the only constructor in the class ParameterizedTypeImpl has a signature like this: private ParameterizedTypeImpl(java.lang.Class<?> aClass, java.lang.reflect.Type[] types, java.lang.reflect.Type type), but the signature in the stacktrace looks like it's accepting ParameterizedTypeImpl itself: ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:53).
Now I'm stuck; Any suggestions that could help me further are very appreciated.
This is a known bug that was fixed in Proguard 5.0. See https://sourceforge.net/p/proguard/bugs/518/

Categories

Resources