Zelix KlassMaster - Documentation

Trim Tutorial

This tutorial is divided into the following sections:

Overview

The Zelix KlassMaster™ Trim function deletes unused classes, fields and methods. It can also optionally delete specified attributes within bytecode. By doing this the Trim function reduces the overall size of your application.

Trim exclusions specify the classes, fields and methods that should not be deleted by the "Trim" function. By default, the Trim function will delete all classes, fields and methods that have not been explicitly or implicitly excluded from being trimmed. If there are no trim exclusions at all then the Trim function will delete ALL opened classes along with their fields and methods. So, the way to understand the Trim function is to understand how trim exclusions are processed.

How Trim Exclusions Works

The key aspects of trim exclusions are
  1. Any class, field or method that is not explicitly or implicitly excluded will be deleted. So if you have no trim exclusions then every class, field and method will be deleted.
  2. If a class is implicitly or explicitly excluded then it will not be deleted. However, its fields and methods will be deleted unless they are otherwise excluded.
  3. If a field is implicitly or explicitly excluded and its containing class has also been implicitly or explicitly excluded then the field will not be deleted.
  4. If a method is implicitly or explicitly excluded and its containing class has also been implicitly or explicitly excluded then
    1. the method will not be deleted and
    2. all the classes, fields and methods directly or indirectly accessed by the method will be implicitly excluded from being trimmed.
Methods are also implicitly excluded if
  1. They override a method in a class that has not been opened for trimming.
    1. For example, if an opened class contains the method hashCode() then that method will be implicitly excluded because it overrides the corresponding method in java.lang.Object (which presumably has not been opened for obfuscation).
  2. They override a method that has been explicitly or implicitly excluded.
    1. For example, if you explicitly exclude the method method1() in a particular interface then the method method1() will be implicitly excluded in all classes that implement that interface.
It is very important to note that the exclusion of classes and the fields and methods they contain are handled separately. As indicated by point 2 above, the exclusion of a class does not in itself exclude the fields and methods of that class. Also, as indicated by points 3 and 4 above, the exclusion of a field or method does not in itself exclude the class containing the field or method. This separation gives you the flexibility to specify that if a class contains a field named serialVersionUID and the class is not going to be deleted then do not delete the field named serialVersionUID.

The final thing to note is that, as indicated by point 4b above, Zelix KlassMaster™ will trace all possible lines of execution from all methods that will not be deleted and implicitly exclude all classes, fields and methods that can be accessed directly or indirectly by the methods. This means that you do not have to explicitly exclude all classes, fields and methods that should not be deleted. Typically, you only need to explicitly exclude the "entry point" methods and the classes that contain them.

Trimming "classic" applications

If you are obfuscating a classic application with one public static main(java.lang.String[]) method which is the only "entry point" into the application then you only need to explicitly exclude
  • the public static main(java.lang.String[]) method and
  • the class that contains the public static main(java.lang.String[]) method.
Because the method public static main(java.lang.String[]) will not be deleted, Zelix KlassMaster™ will trace all classes, fields and methods that are accessed directly or directly from that method and implicitly exclude them.

A typical ZKM Script trimExclude statement for a classic application would be
trimExclude com.mycompany.MyMainClass^ public static main(java.lang.String[]);
Note the '^' containing object exclusion tag that specifies that the containing class should also be excluded.

Trimming applets

If your application is a straightforward Applet then you only need to explicitly exclude the Applet class itself. The init(), start(), stop() and destroy() methods will be implicitly excluded because they override methods in the java.applet.Applet API (see point 5a above). Zelix KlassMaster™ will then implicitly exclude all classes, fields and methods accessed directly or indirectly by these methods.

A typical ZKM Script trimExclude statement for an applet would be
trimExclude com.mycompany.Applet;

Trimming class libraries and extensible frameworks

If you are trimming a class library then you need to exclude the classes, fields and methods that can be accessed by an application using the class library. Typically that means that you should exclude
  • public classes and
  • public fields and methods and the classes containing them

A typical ZKM Script trimExclude statement for a non-extensible class library would be
trimExclude public *.* and   //public classes in all packages
            *.* public * and //public fields in all classes in all packages
            *.* public *(*); //public methods in all classes in all packages
If the class library is really an extensible framework then you typically should also exclude
  • protected fields and methods and the classes containing them
A typical ZKM Script trimExclude statement for an extensible framework would be
trimExclude public *.* and      //public classes in all packages
            *.* public * and    //public fields in all classes in all packages
            *.* protected * and //protected fields in all classes in all packages
            *.* public *(*) and //public methods in all classes in all packages
            *.* protected *(*); //protected methods in all classes in all packages

Default Trim Exclusions

Zelix KlassMaster™ has some default trim exclusions that are applied everytime you trim. These default exclusions cover a number of APIs such as Serialization and RMI. For example, static final long serialVersionUID fields are excluded by default. The default exclusions are intended to free you from the need to specify general purposes exclusions that apply to a wide range of applications. However, you will almost always have to explicitly exclude you "entry point" methods and the classes that contain them.

You may override these defaults with your own. Zelix KlassMaster™ looks for a file in the default directory (which is the current working directory unless you have specified otherwise) named "defaultTrimExclude.txt". This file should either be empty or contain a single ZKM Script "trimeExclude" statement. If Zelix KlassMaster™ finds the file then it will use its contents as the default trim exclusions.

If the defaultTrimExclude.txt file doesn't exist then Zelix KlassMaster™ applies its predefined internal default trim exclusions that are identical to those in the original defaultTrimExclude.txt file. If the defaultTrimExclude.txt file exists but is is empty then there are no default trim exclusions.

Note that, in the Zelix KlassMaster™ GUI, the default trim exclusion parameters appear as disabled list entries in the "Exclusion parameter list" of the "Trim Exclusions" window. These disabled entries can only be altered by editing the "defaultTrimExclude.txt" file.
 

Trim Exclusions Using the GUI

Zelix KlassMaster - Trim Exclusions Typically you will only need to set the Application Type and Application Entry Point Class lists.

If you are obfuscating a classic application with one public static main(java.lang.String[]) method which is the only "entry point" into the application then you should
  • set the Application Type to "Self contained application or applet"
  • select the class containing the main(java.lang.String[]) method in the Application Entry Point Class list.

If you are obfuscating an applet then you should
  • set the Application Type to "Self contained application or applet"
  • select the applet class in the Application Entry Point Class list.

If you are obfuscating a class library that is NOT going to be extended by your users then you should
  • set the Application Type to "Non-extensible class library"
  • set the Application Entry Point Class to "none".

If you are obfuscating a class library that IS going to be extended by your users then you should
  • set the Application Type to "Extensible framework"
  • set the Application Entry Point Class to "none".
 

Trim Exclusion Troubleshooting

The settings discussed above will be adequate for relatively straightforward applications. However, more complex application may require extra trim exclusions. You may even have to do a little experimentation with your trim exclusions. Some scenarios that can cause problems are
  1. Java Reflection API accesses to classes, fields and methods that Zelix KlassMaster™ was unable to fully resolve. (If Zelix KlassMaster™ was unable to fully resolve a Reflection API call then it will report the fact in the Class Open Warnings dialog or the Zelix KlassMaster™ log.}
  2. Specialized APIs (not catered for by the existing default exclusions) that directly access your classes, fields or methods.
In such cases the best solution is to add explicit trim exclusions to tell Zelix KlassMaster™ that additional classes, fields or methods are indeed accessed.

If you find yourself needing to debug your trim exclusions when running a ZKM Script then you may find it helpful to run Zelix KlassMaster™ using the "-v" (ie. verbose) parameter. This will result in a great deal of extra information being written to the log. This extra information will include
  • the effective trim exclude parameters (including the default exclusions)
  • which classes, fields and methods were directly matched by an exclusion parameter
  • which classes, fields and methods were deleted as part of the trim process.
Note that the list of trimmed classes, fields and methods is also written to the ZKM_TrimLog.txt file regardless of how you start Zelix KlassMaster.

When debugging your trim exclusions, it can also be very useful to temporarily halt any name obfuscation by excluding all class, field and method names or by simply commenting out your "obfuscate" statement. With name obfuscation suspended any runtime stack traces you are getting will specify real class, field and methods names which usually makes the root cause of any trim problem obvious.
 
Documentation Table of Contents