Does Proguard remove methods used in only one place? [method inlining] - java

I'm considering using Proguard as my app comes closer to production to make it lighter.
On Android, there's the 65K method limit in addition to low storage devices. I know that Proguard removes unused methods, but does it remove methods which are used only in one place? I mean, I'm writing some methods just to make the code cleaner, but it would save a method call (one of the most expensive operation with return for the CPU and RAM, I studied microcode) and a method in the 65K max count as well as some bytes in the final package.
Does Proguard detect such cases and remove methods? Do I have to configure it myself? What about stacktrace deobfuscation if so?

It does not remove them since the code is used.
If you have the method/inlining/unique optimization enabled, it will inline such methods: the method call is removed and the method code is inserted in the place where the method call was.
What about stacktrace deobfuscation if so?
If there's an exception in the inlined method, it will show up in the stacktrace at the method call site (where the call was removed).

If used proguard will not remove the method.
And, If you already know one such method, why don't you just build an apk with proguard enabled and test out the functionality in the app which makes the method call and check for yourself?

Related

Bytebuddy Java Agent: AgentBuilder affects control flow of a second, unrelated AgentBuilder

So I am implementing a Java Agent that installs multiple AgentBuilder, one of them only if an environment variable was defined correctly. The problem I face is that the behavior of a second AgentBuilder changes depending on whether the optional one was installed. To me it seems like installing the optional AgentBuilder affects which methods, that are instrumented by the second unrelated AgentBuilder, get called and how often.
if (EnvVar.isTrue()) {
// These methods are customs so I don't have to rewrite the whole AgentBuilder-chain...
getAgentBuilder1(inst, tempFolder).installOn(inst);
}
getAgentBuilder2(inst, tempFolder).installOn(inst);
The AgentBuilder1 uses the following type matching:
ElementMatchers.isSubTypeOf(InputStream.class)
.and(
ElementMatchers.not(
ElementMatchers.namedOneOf(InflaterInputStream.class.getName())
.or(ElementMatchers.isPrivate())
)
)
and the AgentBuilder2 this one:
ElementMatchers.namedOneOf(Class.class.getName(), ClassLoader.class.getName());
Now the transformer for AgentBuilder1 uses an Advice to print a log message when the read(...)-method of an InputStream was called, and AgentBuilder2 prints a log message when the ClassLoader.getResource(...)-method or the Class.getResource(...)-method was called.
Everything works as expected, apart from the fact that the AgentBuilder2 logs a lot more resources if AgentBuilder1 was installed than if it wasn't installed - while instrumenting the exact same program... It looks like the Class.getResource(...) method is being called much more often if AgentBuilder1 was installed. Any Ideas?
Byte Buddy invokes these methods. If you want to instrument classes that might already be loaded, you would need to use a retransformation strategy. Also, I would recommend to combine these agents in a single builder and only install it once.

how to create a custom stacktrace in java with additional info (like parameters)?

I was assigned a task to create a custom stacktrace like output to a log file for some specified functions, but instead of just using the class and method names I would also have to output the parameters and their values.
This is supposed to be a separate jar that could run on any java project, after.
I don't even know if such thing is possible, let alone where to start.
Any help would be appreciated.
EDIT: there is other library that does that by using native VM api: https://github.com/cretz/stackparam it also modifies Throwable class to always print that modified stacktrace.
The only possible way I can think of is using agents and instrumentalization, but agent needs to be added to startup command line.
Then I would register transformer to transform every class (remember that some basic java classes might be already loaded) using ASM library and add code to beginning of every method invocation to manually track each method class and pass it to my library that would track them:
// note that parameters names might not exist in runtime if code was compiled without a flag to include them.
public void doSomething(String name, int something) {
MyLib.enterMethod(ThisClass.class, new MethodSignature(void.class, String.class, int.class), new Argument("name", name), new Argument("something", something));
try {
// original code
} finally { // so we don't need to care about return in the middle of original code or exceptions
MyLib.exitMethod();
}
}
enterMethod would add invocation frame to some queue and exitMethod would remove last added frame. Note that you should have separate queue for each thread, use some Map<Thread, MyFrame> or ThreadLocal it might be good idea to use some weak references for threads.
And then you could use frames from that queue to create own stacktrace.
But doing something like that might decrease performance a lot - not even just because cost of this code, but adding that to every setter/getter might cause that methods to never be inlined and affect performance even more.
So it is possible but I really don't recommend doing something like that.
Also some other transformers added by other libraries might affect results, it might be good idea to also compare your stacktrace with original stacktrace to find any missing methods that you didn't transform - like native ones, and add them to your stacktrace but without that additional data.
If you really need to support native methods too - then you can create more advanced transformer that would add enterMethod/exitMethod before and after call to native method.
Also if this is only for debugging you could use debugging API so it would only work as a debugger.

Intellij IDEA doesn't grey out some unused methods

In intellij IDEA, if a method is unused, the method is shown in a gray color. But in some cases, IDEA doesn't grey out the method, but when I check the references of those methods using alt + F7, IDEA says that the method is unused.
Is this a IDEA bug or is there any reason why IDEA wouldn't grey out these specific methods? If it is a bug, is there some workaround to make IDEA identify that method is unused?
Most likely it's not a bug, it's a limitation for performance reasons. Methods likely to take a long time when searching for usages are skipped.
A workaround is to run Unused Declaration inspection explicitly in all your project via Analyze | Inspect Code or Analyze | Run Inspection by Name. That'll take some time. You can also set up TeamCity server to do it for you automatically every night.
I used to have it working like charm, but one time, I by mistake clicked on alt+Enter on an unused method, and chose to suppress the inspection on unused code. Ever since then, I stopped getting the grayed out methods and code, so since there is a way to get it undone, there sure must be a way to get it back working.
After 5 minutes of searching, I found a solution:
Settings --> Editor --> Inspections --> Java --> Declaration Redundancy --> Unused Declaration
Make sure you check "Unused Declaration"
And I just checked by creating a new useless method, working like a charm.
My answer is quite late, but perhaps it will help others to identify their problem:
IntelliJ didn't mark methods as unused for me, because they were overloaded methods, for example:
1: methodName(String argument)
2: methodName(ArrayList<String> argument)
The first method was no longer used, but the second method was. IntelliJ (I assume) simply checks the method names, and sees that the method name is used, even though one of them is no longer used.
I have checked the other answers on this page for finding unused methods, but have not found a solution to filter out unused, overloaded methods.
It might be a bug if you're using a method with a very common name.
If you tried #Peter Gromov method above, and your method is still yellow, it might be the case that this is a bug.
I had a very common named method, named "stop".
Looking for usages (using ALT + F7) didn't show anything.
Analyzing the whole project, clearly showed that this method did not have any use.
Despite that, the method was still yellow.
I was surprised to find out, that if I try to refactor the method name, I get a pop-up warning that this will change in other places as well.
Turns out, that the refactoring warned about changing the method name in TODO comments. Somehow Lint recognized the TODO comments as using this method.
My advice is to just not name your methods as something that may be written in a TODO comment.
See this image, where I am using a method named "stop" :

JNI: How to get method signature for debugging purposes

Can I enumerate all native methods in java, those that have to be
implemented in c/c++ using JNI?
Can I enumerate native methods by
name (there could be multiple overloads with the same name)?
How can I retrieve method signature to be able to generate the method
signature used by JNI?
Is there a way to check if all native jni methods have been bound properly, instead of trying to call them and get java.lang.UnsatisfiedLinkError exceptions. Sometimes method signature changes on either side without properly updating java or c++ side and I'd like to add some debugging code to detect these issues and handle them (perhaps by generating proper method signature and printing it to the log so I can easily fix the code).
I prefer JNI solution, but if something can be done with help on java side then it's ok also.
If I use registerNatives and register methods that weren't declared in java then it fails and prints it to logcat:
E/dalvikvm( 1445): ERROR: couldn't find native method
E/dalvikvm( 1445): Requested: Lcom/bla/bla/bla/Test;.nativeTestXX:()Z
but I'd like to catch this error and handle it myself. Is it possible to do it?
EDIT:
In my JNI code I have a static nativeInit (as suggested in Android JNI tips) that registers all native methods. In that same function I'd like to verify that all native methods are properly bound. That is, I don't need to wait till some uninitialized method is called and the app exists. The problem that I have: there is a lot of jni code written at different times by different ppl and some methods simply became incorrect, but they are used only in some obscure conditions. The best way for me, I think, is to check that all native methods are bound to some c++ function. The other problem, is that part of JNI code uses binding by exporting all these Long_java_names where method signature changes on either side cannot be detected.
There is no call to check for "unbound" native methods. Using RegisterNatives to perform explicit registration ensures that all methods you register have a matching declaration in the Java sources, but there is no way to check for native-declared methods for which there is no implementation (other than calling it and catching the exception).
At the point where a method with a native implementation is called, if nothing has yet been registered then Dalvik will search through the various shared libraries to find a match. What it sounds like you want is a way to force this search and check the result without actually calling the method. There is no such thing.
There are various ways to generate lists of native-declared methods, either statically or at runtime, but you also need a way to determine if an implementation is available. You're better off in the long run having unit tests that exercise the code.

Remove uses of certain Java classes at compile time

I am looking for a way to remove all uses of a particular class, including the class itself, at compile time. Basically a form of pre-processing, but I'd like to do it without having to surround all the instances with #ifdebug ... #endif.
Is there any ant-based tool out there that can do this? If not, can anyone point me in the right direction for how to write such a tool? (not a minor undertaking I know, but if its the only option...)
The situation is I have a helper class for debugging function calls. This is instantiated at the beginning of a function and a call is made at the end. This is a JavaME application so I'm nervous about the overhead this is adding to performance. I already have a release and debug build that have pre-processor directives using ProGuard, so I would like to exclude the use of this helper class from the release build. It doesn't appear this can be done with ProGuard.
"This is instantiated at the beginning of a function and a call is made at the end. "
If this is all over your code maybe you need to look at AOP.
or a state design pattern for the helper class, in test mode it does one thing but in prod it does another(like nothing)
Do you know that this debug code will make the JavaME app slow? You could also try creating a way to conditionally call these debug methods.
A few more ideas ... I've never written a JavaME app, but I assume there is way to run/test with running on the actual device. Given this way of running/testing, perhaps you can use Eclipse/Netbeans to debug your code and use proper breakpoints instead of programmatically tracing method calls. No harm to compiled code in this case. Also consider using AspectJ to trace method calls, this can be conditionally done after code is compiled since AspectJ alters bytecode directly (not sure how this plays with JavaME). Lastly, I've heard of people using the standard GNU C/C++ preprocessor on Java. I have no idea if it works, google will help you.
Not exactly what you want but...
You could separate your code to modules (core and debug, in your case), then make sure modules call each other via reflection: use an interface available in core, create a wrapper class in core that will hide object instantiation via reflection detail/
Then, on production, just omit the debug code and have the wrapper "do nothing" if the instantiation fail / when you set a specific flag.
This way your debug classes won't make it into production and you won't have to "statically link" to them so your core production code won't care.
Of course, this is only possible if your debug code has no side effects visible to core code, but it seems that's your case (from your problem description).
Is it possible to just create the class once, on application startup, instead of creating an instance for each method? Your debug class could then look like this:
public class Debug // maybe make this a *gasp* singleton?
{
public static void start(); // called at start of method
public static void end(); // called at end, probably should be in a finally block
public static void setDebugMode(boolean debugOn); // turn off for production mode
}
Set debug mode to "true" in testing but "false" in production. When debug mode is off, none of the methods do anything (except check the state of debug mode, of course).
You don't avoid the overhead of the function call, and you do need to check the state of that boolean, but you do get to avoid jumping through hoops trying to avoid load the class at all.
This will need more work if you have a multithreaded application, too.

Categories

Resources