diff --git a/build.gradle b/build.gradle index 136ca79..42440d8 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,10 @@ jar { 'Implementation-Timestamp': new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), 'Git-Commit': gitInfo.gitHashFull, 'Git-IsClean': gitInfo.isCleanTag, - 'Premain-Class': 'org.to2mbn.authlibinjector.javaagent.AuthlibInjectorPremain' + 'Premain-Class': 'org.to2mbn.authlibinjector.javaagent.AuthlibInjectorPremain', + 'Agent-Class': 'org.to2mbn.authlibinjector.javaagent.AuthlibInjectorPremain', + 'Can-Retransform-Classes': true, + 'Can-Redefine-Classes': true ) } } diff --git a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java index 9fb32ec..02b9ba7 100644 --- a/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java +++ b/src/main/java/org/to2mbn/authlibinjector/AuthlibInjector.java @@ -15,7 +15,7 @@ import org.to2mbn.authlibinjector.transform.YggdrasilKeyTransformUnit; public final class AuthlibInjector { - private static final String[] nonTransformablePackages = new String[] { "java.", "javax.", "com.sun.", + public static final String[] nonTransformablePackages = new String[] { "java.", "javax.", "com.sun.", "com.oracle.", "jdk.", "sun.", "org.apache.", "com.google.", "oracle.", "com.oracle.", "com.paulscode.", "io.netty.", "org.lwjgl.", "net.java.", "org.w3c.", "javassist.", "org.xml.", "org.jcp.", "paulscode.", "com.ibm.", "joptsimple.", "org.to2mbn.authlibinjector." }; diff --git a/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java b/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java index 3154223..7d64df5 100644 --- a/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java +++ b/src/main/java/org/to2mbn/authlibinjector/javaagent/AuthlibInjectorPremain.java @@ -1,21 +1,92 @@ package org.to2mbn.authlibinjector.javaagent; import static org.to2mbn.authlibinjector.AuthlibInjector.bootstrap; +import static org.to2mbn.authlibinjector.AuthlibInjector.debug; import static org.to2mbn.authlibinjector.AuthlibInjector.info; +import static org.to2mbn.authlibinjector.AuthlibInjector.nonTransformablePackages; import java.lang.instrument.Instrumentation; +import java.util.Arrays; public class AuthlibInjectorPremain { public static void premain(String arg, Instrumentation instrumentation) { try { - info("launched from javaagent"); - if (arg != null && !arg.isEmpty()) { - System.setProperty("org.to2mbn.authlibinjector.config", arg); - } - bootstrap(instrumentation::addTransformer); + info("launched from premain"); + initInjector(arg, instrumentation, false); } catch (Throwable e) { // prevent the exception being thrown to VM e.printStackTrace(); } } + + public static void agentmain(String arg, Instrumentation instrumentation) { + try { + info("launched from agentmain"); + initInjector(arg, instrumentation, true); + } catch (Throwable e) { + // prevent the exception being thrown to VM + e.printStackTrace(); + } + } + + public static void initInjector(String arg, Instrumentation instrumentation, boolean needsRetransform) { + setupConfig(arg); + + boolean retransformSupported = instrumentation.isRetransformClassesSupported(); + boolean retransformEnabled = retransformSupported && needsRetransform; + bootstrap(x -> instrumentation.addTransformer(x, retransformEnabled)); + + if (needsRetransform) { + if (retransformSupported) { + info("start retransforming"); + doRetransform(instrumentation); + } else { + info("retransforming is not supported"); + } + } + } + + private static void setupConfig(String arg) { + if (arg != null && !arg.isEmpty()) { + System.setProperty("org.to2mbn.authlibinjector.config", arg); + } + } + + private static void doRetransform(Instrumentation instrumentation) { + try { + long t0 = System.currentTimeMillis(); + Class[] classToRetransform = getClassesToRetransform(instrumentation); + if (classToRetransform.length > 0) { + instrumentation.retransformClasses(classToRetransform); + } + long t1 = System.currentTimeMillis(); + info("retransforming finished in {0}ms", t1 - t0); + } catch (Throwable e) { + info("unable to retransform"); + e.printStackTrace(); + } + } + + private static Class[] getClassesToRetransform(Instrumentation instrumentation) { + Class[] loadedClasses = instrumentation.getAllLoadedClasses(); + Class[] dest = new Class[loadedClasses.length]; + int idx = 0; + for (Class clazz : loadedClasses) { + if (instrumentation.isModifiableClass(clazz)) { + boolean toRetransform = true; + for (String nonTransformablePackage : nonTransformablePackages) { + if (clazz.getName().startsWith(nonTransformablePackage)) { + toRetransform = false; + break; + } + } + if (toRetransform) { + dest[idx++] = clazz; + } + } + } + debug("loaded {0} classes, {1} to retransform", loadedClasses.length, idx); + return Arrays.copyOf(dest, idx); + } + }