I am making a plugin system and i need to see when a plugin calls Thread.start() Is there a way similar to Runtime.getRuntime().addShutdownHook but for hooking when a thread starts?
I am making a plugin system and i need to see when a plugin calls Thread.start() Is there a way similar to Runtime.getRuntime().addShutdownHook but for hooking when a thread starts?
You can use Byteman to inject your own code into the thread.start() method.
In fact, the first example to using Byteman with JVM classes on their website is one showing how to print to the console when a thread has started.
Byteman script example from their tutorial:
RULE trace thread start
CLASS java.lang.Thread
METHOD start()
IF true
DO traceln("*** start for thread: "+ $0.getName())
ENDRULE
See https://developer.jboss.org/docs/DOC-17213#how_do_i_inject_code_into_jvm_classes for further implementation details.
If Byteman isn't your thing, there's another library called ByteBuddy which can be used to create a Java Agent that intercepts a method in the Thread class.
public class ThreadMonitor {
@RuntimeType
public static Object intercept(@Origin Method method,
@SuperCall Callable<?> callable) {
System.out.println("A thread start method called");
return callable.call(); //Calling the original start method.
}
}
public class ThreadMonitorAgent {
public static void premain(String arguments,
Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameEndsWith("start"))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any())
.intercept(MethodDelegation.to(ThreadMonitor.class))
).installOn(instrumentation);
}
}
Example code adapted from ByteBuddy github readme.
Hmm. Maybe there is a way.
If there is a SecurityManager for the current context, then there is a check to see if the current thread is permitted to access the ThreadGroup of the new Thread when it is being constructed.
So ...
You could (in theory) set up a custom SecurityManager and use the thread group access check as a way to "hook" the creation of a new Thread. But this will only tell you that a thread is being created, not what that thread actually it. So this approach may or may not be sufficient for your needs.
And there is no way to hook the Thread.start() call.
An alternative approach would be to extend Thread and implement the hooks on thread creation or starting in your subclass.
You could attach a debugger to your JVM and set a breakpoint to Thread.start(). Or even do it programmatically using JVMTI, etc. However, it is (AFAIK) not possible for an application to use JVMTI against its own JVM1 ... so this is not conventional "hooking".
Finally, there is always the option of downloading OpenJDK, modifying the Thread class, building a custom JVM, and installing it. That might be OK for doing some experiments, but it would be a crazy thing to do for a production application. (You don't want to burden yourself ... or your customers ... with maintaining a perpetual fork of OpenJDK.)
1 - Even if it was possible in some cases, the Thread class would present extra difficulties. For example, consider that things like bytecode rewriting have to be done before the classloader loads a class. But the Thread class has to be loaded during JVM bootstrapping ... and before any application code has been loaded.
Not in normal fashion, but remember that Thread.start is public and non-final, so you could create a subclass of Thread that would do your custom logic before start. But that's obviously not good enough for this question.
The black-magic solution that might work would be to remove the existing Thread class from runtime (what means modifying your JRE/JDK) and replacing it with your "enriched" version. As long as the new version does the same thing as "normal" one (registering natives, invoking native code) then it should be fine.
Another black-magic alternative would be to actually take a look into what's the native code that's invoked by Thread.start0 and modify that. But this means playing with your runtime environment again.
Final idea would be to have the application always run in something similar to a debug mode and do something whenever breakpoint is reached. This is doable, as it's what IDEs do. Though we have just moved to two-process design with what it entails.
I'm also wondering if Java instrumentation package might not provide some kind of alternative here.