├── .travis.yml ├── .gitignore ├── agent-loader ├── src │ ├── main │ │ ├── resources │ │ │ └── com │ │ │ │ └── ea │ │ │ │ └── agentloader │ │ │ │ └── shaded │ │ │ │ ├── AttachProvider.class │ │ │ │ ├── VirtualMachine.class │ │ │ │ ├── AttachPermission.class │ │ │ │ ├── BsdAttachProvider.class │ │ │ │ ├── BsdVirtualMachine.class │ │ │ │ ├── AgentLoadException.class │ │ │ │ ├── LinuxAttachProvider.class │ │ │ │ ├── LinuxVirtualMachine.class │ │ │ │ ├── HotSpotAttachProvider.class │ │ │ │ ├── HotSpotVirtualMachine.class │ │ │ │ ├── SolarisAttachProvider.class │ │ │ │ ├── SolarisVirtualMachine.class │ │ │ │ ├── WindowsAttachProvider.class │ │ │ │ ├── WindowsVirtualMachine.class │ │ │ │ ├── VirtualMachineDescriptor.class │ │ │ │ ├── AttachNotSupportedException.class │ │ │ │ ├── AgentInitializationException.class │ │ │ │ ├── AttachOperationFailedException.class │ │ │ │ ├── BsdVirtualMachine$SocketInputStream.class │ │ │ │ ├── LinuxVirtualMachine$SocketInputStream.class │ │ │ │ ├── SolarisVirtualMachine$SocketInputStream.class │ │ │ │ ├── WindowsVirtualMachine$PipedInputStream.class │ │ │ │ └── HotSpotAttachProvider$HotSpotVirtualMachineDescriptor.class │ │ └── java │ │ │ └── com │ │ │ └── ea │ │ │ └── agentloader │ │ │ ├── AttachProviderPlaceHolder.java │ │ │ ├── AgentLoaderHotSpot.java │ │ │ ├── ClassPathUtils.java │ │ │ └── AgentLoader.java │ └── test │ │ └── java │ │ └── com │ │ └── ea │ │ └── agentloader │ │ └── test │ │ ├── HelloAgentWorld.java │ │ ├── AgentFailure.java │ │ └── AgentLoaderTest.java └── pom.xml ├── CONTRIBUTING.md ├── .idea ├── copyright │ ├── profiles_settings.xml │ └── Orbit_Copyright.xml └── codeStyleSettings.xml ├── README.md ├── LICENSE └── pom.xml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: oraclejdk8 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea 3 | target 4 | *.versionsBackup 5 | dependency-reduced-pom.xml 6 | tests.yml -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/VirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/VirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachPermission.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachPermission.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdAttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdAttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdVirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdVirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AgentLoadException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AgentLoadException.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxAttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxAttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxVirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxVirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotAttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotAttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotVirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotVirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisAttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisAttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisVirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisVirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsAttachProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsAttachProvider.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsVirtualMachine.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsVirtualMachine.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/VirtualMachineDescriptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/VirtualMachineDescriptor.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachNotSupportedException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachNotSupportedException.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AgentInitializationException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AgentInitializationException.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachOperationFailedException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/AttachOperationFailedException.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdVirtualMachine$SocketInputStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/BsdVirtualMachine$SocketInputStream.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxVirtualMachine$SocketInputStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/LinuxVirtualMachine$SocketInputStream.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisVirtualMachine$SocketInputStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/SolarisVirtualMachine$SocketInputStream.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsVirtualMachine$PipedInputStream.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/WindowsVirtualMachine$PipedInputStream.class -------------------------------------------------------------------------------- /agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotAttachProvider$HotSpotVirtualMachineDescriptor.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/electronicarts/ea-agent-loader/HEAD/agent-loader/src/main/resources/com/ea/agentloader/shaded/HotSpotAttachProvider$HotSpotVirtualMachineDescriptor.class -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Thanks for your interest! 2 | 3 | In order to clarify the intellectual property license granted for contributions to EA open source projects you must sign the [Contributor License Agreement (CLA)](https://ea.tap.thinksmart.com/prod/Portal/ShowWorkFlow/AnonymousEmbed/26adfdf8-b74e-4212-bb4a-3e756b722c32). -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | EA Agent Loader 2 | ============ 3 | 4 | #### Project Deprecated 5 | With the introduction of JDK9, dynamically self attaching Java Agents is considered bad practice. As such we are deprecating this project and will no longer continue to maintain it. 6 | The project remains here for reference and for JDK8 users. 7 | 8 | Brief 9 | ============ 10 | EA Agent Loader is a collection of utilities for [java agent](https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html) developers. 11 | It allows programmers to write and test their java agents using dynamic agent loading (without using the -javaagent jvm parameter). 12 | 13 | Developer & License 14 | ====== 15 | This project was developed by [Electronic Arts](http://www.ea.com) and is licensed under the [BSD 3-Clause License](LICENSE). 16 | 17 | Example 18 | ======= 19 | ```java 20 | public class HelloAgentWorld 21 | { 22 | public static class HelloAgent 23 | { 24 | public static void agentmain(String agentArgs, Instrumentation inst) 25 | { 26 | System.out.println(agentArgs); 27 | System.out.println("Hi from the agent!"); 28 | System.out.println("I've got instrumentation!: " + inst); 29 | } 30 | } 31 | 32 | public static void main(String[] args) 33 | { 34 | AgentLoader.loadAgentClass(HelloAgent.class.getName(), "Hello!"); 35 | } 36 | } 37 | ``` 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2015 - 2016 Electronic Arts Inc. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 13 | its contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 17 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /.idea/copyright/Orbit_Copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /agent-loader/src/main/java/com/ea/agentloader/AttachProviderPlaceHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader; 30 | 31 | import com.sun.tools.attach.AttachNotSupportedException; 32 | import com.sun.tools.attach.VirtualMachine; 33 | import com.sun.tools.attach.VirtualMachineDescriptor; 34 | import com.sun.tools.attach.spi.AttachProvider; 35 | 36 | import java.io.IOException; 37 | import java.util.List; 38 | 39 | class AttachProviderPlaceHolder extends AttachProvider 40 | { 41 | @Override 42 | public String name() 43 | { 44 | return null; 45 | } 46 | 47 | @Override 48 | public String type() 49 | { 50 | return null; 51 | } 52 | 53 | @Override 54 | public VirtualMachine attachVirtualMachine(final String id) throws AttachNotSupportedException, IOException 55 | { 56 | return null; 57 | } 58 | 59 | @Override 60 | public List listVirtualMachines() 61 | { 62 | return null; 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /agent-loader/src/test/java/com/ea/agentloader/test/HelloAgentWorld.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader.test;/* 30 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 31 | 32 | Redistribution and use in source and binary forms, with or without 33 | modification, are permitted provided that the following conditions 34 | are met: 35 | 36 | 1. Redistributions of source code must retain the above copyright 37 | notice, this list of conditions and the following disclaimer. 38 | 2. Redistributions in binary form must reproduce the above copyright 39 | notice, this list of conditions and the following disclaimer in the 40 | documentation and/or other materials provided with the distribution. 41 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 42 | its contributors may be used to endorse or promote products derived 43 | from this software without specific prior written permission. 44 | 45 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 46 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 47 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 48 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 49 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 52 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | */ 56 | 57 | import com.ea.agentloader.AgentLoader; 58 | import com.ea.agentloader.ClassPathUtils; 59 | 60 | import java.lang.instrument.Instrumentation; 61 | 62 | import static org.junit.Assert.assertEquals; 63 | 64 | 65 | public class HelloAgentWorld 66 | { 67 | public static class HelloAgent 68 | { 69 | public static void agentmain(String agentArgs, Instrumentation inst) 70 | { 71 | System.out.println(agentArgs); 72 | System.out.println("Hi from the agent!"); 73 | System.out.println("I've got instrumentation!: " + inst); 74 | } 75 | } 76 | 77 | public static void main(String[] args) 78 | { 79 | // this example only works if the current classloader is the system classloader 80 | if (ClassLoader.getSystemClassLoader() != HelloAgent.class.getClassLoader()) 81 | { 82 | ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(HelloAgent.class)); 83 | } 84 | AgentLoader.loadAgentClass(HelloAgent.class.getName(), "Hello!"); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /agent-loader/src/test/java/com/ea/agentloader/test/AgentFailure.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader.test;/* 30 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 31 | 32 | Redistribution and use in source and binary forms, with or without 33 | modification, are permitted provided that the following conditions 34 | are met: 35 | 36 | 1. Redistributions of source code must retain the above copyright 37 | notice, this list of conditions and the following disclaimer. 38 | 2. Redistributions in binary form must reproduce the above copyright 39 | notice, this list of conditions and the following disclaimer in the 40 | documentation and/or other materials provided with the distribution. 41 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 42 | its contributors may be used to endorse or promote products derived 43 | from this software without specific prior written permission. 44 | 45 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 46 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 47 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 48 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 49 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 52 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | */ 56 | 57 | import com.ea.agentloader.AgentLoader; 58 | 59 | import org.junit.Test; 60 | 61 | import java.lang.instrument.Instrumentation; 62 | 63 | import static org.junit.Assert.fail; 64 | 65 | 66 | public class AgentFailure 67 | { 68 | public static class FailAgent 69 | { 70 | public static void agentmain(String agentArgs, Instrumentation inst) 71 | { 72 | } 73 | } 74 | 75 | @Test 76 | public void testNotPresentInSystemClassLoader() 77 | { 78 | //assertNotEquals(ClassLoader.getSystemClassLoader(), FailAgent.class.getClassLoader()); 79 | if (ClassLoader.getSystemClassLoader() != FailAgent.class.getClassLoader()) 80 | { 81 | try 82 | { 83 | AgentLoader.loadAgentClass(FailAgent.class.getName(), null, null, false, false, false); 84 | } 85 | catch (Exception ex) 86 | { 87 | return; 88 | } 89 | // this test must run from a special maven configuration that 90 | // will cause the agent to fail. 91 | fail("Should have failed"); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /agent-loader/src/test/java/com/ea/agentloader/test/AgentLoaderTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader.test;/* 30 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 31 | 32 | Redistribution and use in source and binary forms, with or without 33 | modification, are permitted provided that the following conditions 34 | are met: 35 | 36 | 1. Redistributions of source code must retain the above copyright 37 | notice, this list of conditions and the following disclaimer. 38 | 2. Redistributions in binary form must reproduce the above copyright 39 | notice, this list of conditions and the following disclaimer in the 40 | documentation and/or other materials provided with the distribution. 41 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 42 | its contributors may be used to endorse or promote products derived 43 | from this software without specific prior written permission. 44 | 45 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 46 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 47 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 48 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 49 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 50 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 52 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | */ 56 | 57 | import com.ea.agentloader.AgentLoader; 58 | import com.ea.agentloader.ClassPathUtils; 59 | 60 | import org.junit.Ignore; 61 | import org.junit.Test; 62 | 63 | import java.lang.instrument.Instrumentation; 64 | 65 | import static org.junit.Assert.assertEquals; 66 | import static org.junit.Assert.fail; 67 | 68 | 69 | public class AgentLoaderTest 70 | { 71 | public static class SomeAgent 72 | { 73 | public static void agentmain(String agentArgs, Instrumentation inst) 74 | { 75 | System.setProperty(SomeAgent.class.getName(), agentArgs); 76 | } 77 | } 78 | 79 | @Test 80 | public void testLoading() 81 | { 82 | if (ClassLoader.getSystemClassLoader() != SomeAgent.class.getClassLoader()) 83 | { 84 | ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(SomeAgent.class)); 85 | } 86 | String options = "test" + System.currentTimeMillis(); 87 | AgentLoader.loadAgentClass(SomeAgent.class.getName(), options, null, false, false, false); 88 | assertEquals(options, System.getProperty(SomeAgent.class.getName())); 89 | } 90 | 91 | @Test 92 | public void testLoadingWithParameters() 93 | { 94 | if (ClassLoader.getSystemClassLoader() != SomeAgent.class.getClassLoader()) 95 | { 96 | ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(SomeAgent.class)); 97 | } 98 | String options = "test" + System.currentTimeMillis(); 99 | AgentLoader.loadAgentClass(SomeAgent.class.getName(), options, null, false, false, false); 100 | assertEquals(options, System.getProperty(SomeAgent.class.getName())); 101 | } 102 | 103 | 104 | @Ignore 105 | public void testWrongClassNameFailure() 106 | { 107 | AgentLoader.loadAgentClass("bogusname", null); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /agent-loader/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 29 | 32 | 4.0.0 33 | 34 | com.ea.agentloader 35 | ea-agent-loader-parent 36 | 1.0.4-SNAPSHOT 37 | .. 38 | 39 | ea-agent-loader 40 | EA Agent Loader 41 | 42 | 43 | 44 | 45 | org.apache.maven.plugins 46 | maven-surefire-plugin 47 | 48 | 49 | 50 | 51 | test-fork-never 52 | 53 | test 54 | 55 | test 56 | 57 | never 58 | 59 | 60 | 61 | 62 | 63 | test-failure 64 | 65 | test 66 | 67 | test 68 | 69 | false 70 | 71 | **/AgentFailure.java 72 | 73 | never 74 | 75 | 76 | 77 | 78 | 79 | test-fork-always 80 | 81 | test 82 | 83 | test 84 | 85 | always 86 | false 87 | always 88 | 89 | 90 | 91 | 92 | test-no-sun-tools 93 | 94 | test 95 | 96 | test 97 | 98 | false 99 | 100 | com.sun:tools 101 | 102 | always 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | ${java.home}/../lib/tools.jar 112 | 113 | 114 | 115 | 116 | mac-profile 117 | 118 | 119 | ${java.home}/../Classes/classes.jar 120 | 121 | 122 | 123 | ${java.home}/../Classes/classes.jar 124 | 125 | 126 | 127 | 128 | 129 | 130 | com.sun 131 | tools 132 | 1.8.0 133 | system 134 | true 135 | ${toolsjar} 136 | 137 | 138 | junit 139 | junit 140 | test 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /agent-loader/src/main/java/com/ea/agentloader/AgentLoaderHotSpot.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader; 30 | 31 | import com.sun.tools.attach.VirtualMachine; 32 | import com.sun.tools.attach.spi.AttachProvider; 33 | 34 | import java.lang.management.ManagementFactory; 35 | import java.lang.reflect.Constructor; 36 | import java.util.Locale; 37 | 38 | /** 39 | * Agent load for the hotspot virtual machine and virtual machines that provide con.sun.tools.attach.* 40 | * Don't use this class directly, prefer {@link AgentLoader} instead. 41 | */ 42 | public class AgentLoaderHotSpot 43 | { 44 | /** 45 | * Dynamically loads a java agent. 46 | * Deals with the problem of finding the proper jvm classes. 47 | * Don't call this method directly use {@link AgentLoader#loadAgent} instead 48 | * 49 | * @param agentJar the agent jar 50 | * @param options options that will be passed back to the agent, can be null 51 | * @see java.lang.instrument.Instrumentation 52 | */ 53 | public void loadAgent(String agentJar, String options) 54 | { 55 | 56 | VirtualMachine vm = getVirtualMachine(); 57 | if (vm == null) 58 | { 59 | throw new RuntimeException("Can't attach to this jvm. Add -javaagent:" + agentJar + " to the commandline"); 60 | } 61 | try 62 | { 63 | try 64 | { 65 | vm.loadAgent(agentJar, options); 66 | } 67 | finally 68 | { 69 | vm.detach(); 70 | } 71 | } 72 | catch (Exception e) 73 | { 74 | throw new RuntimeException("Can't attach to this jvm. Add -javaagent:" + agentJar + " to the commandline", e); 75 | } 76 | } 77 | 78 | public static VirtualMachine getVirtualMachine() 79 | { 80 | if (VirtualMachine.list().size() > 0) 81 | { 82 | // tools jar present 83 | String pid = getPid(); 84 | try 85 | { 86 | return VirtualMachine.attach(pid); 87 | } 88 | catch (Exception e) 89 | { 90 | throw new RuntimeException(e); 91 | } 92 | } 93 | 94 | String jvm = System.getProperty("java.vm.name").toLowerCase(Locale.ENGLISH); 95 | if (jvm.contains("hotspot") || jvm.contains("openjdk") || jvm.contains("dynamic code evolution")) 96 | { 97 | // tools jar not present, but it's a sun vm 98 | Class virtualMachineClass = pickVmImplementation(); 99 | try 100 | { 101 | final AttachProviderPlaceHolder attachProvider = new AttachProviderPlaceHolder(); 102 | Constructor vmConstructor = virtualMachineClass.getDeclaredConstructor(AttachProvider.class, String.class); 103 | vmConstructor.setAccessible(true); 104 | VirtualMachine newVM = vmConstructor.newInstance(attachProvider, getPid()); 105 | return newVM; 106 | } 107 | catch (UnsatisfiedLinkError e) 108 | { 109 | throw new RuntimeException("This jre doesn't support the native library for attaching to the jvm", e); 110 | } 111 | catch (Exception e) 112 | { 113 | throw new RuntimeException(e); 114 | } 115 | } 116 | 117 | // not a hotspot based virtual machine 118 | return null; 119 | } 120 | 121 | 122 | /** 123 | * Gets the current jvm pid. 124 | * 125 | * @return the pid as String 126 | */ 127 | public static String getPid() 128 | { 129 | String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); 130 | int p = nameOfRunningVM.indexOf('@'); 131 | return nameOfRunningVM.substring(0, p); 132 | } 133 | 134 | /** 135 | * Picks one of the Oracle's implementations of VirtualMachine 136 | */ 137 | @SuppressWarnings("unchecked") 138 | private static Class pickVmImplementation() 139 | { 140 | String os = System.getProperty("os.name").toLowerCase(Locale.ENGLISH); 141 | try 142 | { 143 | if (os.contains("win")) 144 | { 145 | return (Class) AgentLoaderHotSpot.class.getClassLoader().loadClass("sun.tools.attach.WindowsVirtualMachine"); 146 | } 147 | if (os.contains("nix") || os.contains("nux") || os.indexOf("aix") > 0) 148 | { 149 | return (Class) AgentLoaderHotSpot.class.getClassLoader().loadClass("sun.tools.attach.LinuxVirtualMachine"); 150 | } 151 | if (os.contains("mac")) 152 | { 153 | return (Class) AgentLoaderHotSpot.class.getClassLoader().loadClass("sun.tools.attach.BsdVirtualMachine"); 154 | } 155 | if (os.contains("sunos") || os.contains("solaris")) 156 | { 157 | return (Class) AgentLoaderHotSpot.class.getClassLoader().loadClass("sun.tools.attach.SolarisVirtualMachine"); 158 | } 159 | } 160 | catch (Exception ex) 161 | { 162 | throw new RuntimeException(ex); 163 | } 164 | throw new RuntimeException("Can't find a vm implementation for the operational system: " + System.getProperty("os.name")); 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /agent-loader/src/main/java/com/ea/agentloader/ClassPathUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader; 30 | 31 | import java.io.File; 32 | import java.io.IOException; 33 | import java.io.InputStream; 34 | import java.lang.reflect.Method; 35 | import java.net.URL; 36 | import java.net.URLClassLoader; 37 | import java.util.Arrays; 38 | import java.util.Locale; 39 | 40 | /** 41 | * Class path and class loader utilities to help java agent developers. 42 | * 43 | * @author Daniel Sperry 44 | */ 45 | public class ClassPathUtils 46 | { 47 | 48 | /** 49 | * Returns the path for the jar or directory that contains a given java class. 50 | * 51 | * @param clazz the class whose classpath entry needs to be located. 52 | * @return an url with the jar or directory that contains that class 53 | */ 54 | public static URL getClassPathFor(final Class clazz) 55 | { 56 | if (clazz == null) 57 | { 58 | throw new IllegalArgumentException("Null class"); 59 | } 60 | try 61 | { 62 | final URL url = getClassFile(clazz); 63 | String urlString = url.toString(); 64 | final int endIndex = urlString.indexOf("!"); 65 | if (endIndex > 0) 66 | { 67 | // assuming it's something inside a jar 68 | int beginIndex = urlString.toLowerCase(Locale.ENGLISH).lastIndexOf("file:/"); 69 | if (beginIndex >= 0) 70 | { 71 | return new URL(urlString.substring(beginIndex, endIndex)); 72 | } 73 | beginIndex = urlString.lastIndexOf("[a-zA-Z]+://"); 74 | if (beginIndex > 0) 75 | { 76 | return new URL(urlString.substring(beginIndex, endIndex)); 77 | } 78 | } 79 | else 80 | { 81 | // assuming it's a file 82 | File dir = new File(url.toURI()).getParentFile(); 83 | if (clazz.getPackage() != null) 84 | { 85 | String pn = clazz.getPackage().getName(); 86 | for (int i = pn.indexOf('.'); i >= 0; i = pn.indexOf('.', i + 1)) 87 | { 88 | dir = dir.getParentFile(); 89 | } 90 | dir = dir.getParentFile(); 91 | } 92 | return dir.toURI().toURL(); 93 | } 94 | throw new RuntimeException("Error locating classpath entry for: " + clazz.getName() + " url: " + url); 95 | } 96 | catch (Exception e) 97 | { 98 | throw new RuntimeException("Error locating classpath entry for: " + clazz.getName(), e); 99 | } 100 | } 101 | 102 | /** 103 | * Get the actual classpath resource location for a class 104 | * 105 | * @param clazz the class whose .class file must be located. 106 | * @return a resource url or null if the class is runtime generated. 107 | */ 108 | public static URL getClassFile(final Class clazz) 109 | { 110 | int idx = clazz.getName().lastIndexOf('.'); 111 | final String fileName = (idx >= 0 ? clazz.getName().substring(idx + 1) : clazz.getName()) + ".class"; 112 | return clazz.getResource(fileName); 113 | } 114 | 115 | 116 | /** 117 | * Appends a directory or jar to the system class loader. 118 | * 119 | * Do this only if you understand the consequences: 120 | *
    121 | *
  • classes loaded by different class loaders are different classes
  • 122 | *
  • if the application uses the same classes the load order might create inconsistencies
  • 123 | *
124 | * 125 | * @param path the url to append to the system class loader 126 | */ 127 | public static void appendToSystemPath(URL path) 128 | { 129 | if (path == null) 130 | { 131 | throw new IllegalArgumentException("Null path"); 132 | } 133 | try 134 | { 135 | ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); 136 | final Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{ URL.class }); 137 | method.setAccessible(true); 138 | method.invoke(systemClassLoader, path); 139 | } 140 | catch (Exception ex) 141 | { 142 | throw new RuntimeException("Add URL failed: " + path, ex); 143 | } 144 | } 145 | 146 | static byte[] toByteArray(InputStream input) throws IOException 147 | { 148 | byte[] buffer = new byte[Math.max(1024, input.available())]; 149 | int offset = 0; 150 | for (int bytesRead; -1 != (bytesRead = input.read(buffer, offset, buffer.length - offset)); ) 151 | { 152 | offset += bytesRead; 153 | if (offset == buffer.length) 154 | { 155 | buffer = Arrays.copyOf(buffer, buffer.length + Math.max(input.available(), buffer.length >> 1)); 156 | } 157 | } 158 | return (offset == buffer.length) ? buffer : Arrays.copyOf(buffer, offset); 159 | } 160 | 161 | public static Class defineClass(ClassLoader loader, InputStream inputStream) 162 | { 163 | try 164 | { 165 | final byte[] bytes = toByteArray(inputStream); 166 | final Method defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); 167 | defineClassMethod.setAccessible(true); 168 | return (Class) defineClassMethod.invoke(loader, null, bytes, 0, bytes.length); 169 | } 170 | catch (Exception e) 171 | { 172 | throw new RuntimeException(e); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 290 | 292 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 29 | 4.0.0 30 | com.ea.agentloader 31 | ea-agent-loader-parent 32 | 1.0.4-SNAPSHOT 33 | pom 34 | EA Agent Loader Parent 35 | EA Agent Loader is a collection of utilities for java agent developers. 36 | https://github.com/electronicarts/ea-agent-loader/ 37 | 38 | 39 | 1.8 40 | 1.8 41 | UTF-8 42 | UTF-8 43 | 44 | 45 | 46 | agent-loader 47 | 48 | 49 | 50 | 51 | 52 | junit 53 | junit 54 | 4.12 55 | 56 | 57 | 58 | 59 | 60 | 61 | The BSD 3-Clause License 62 | http://opensource.org/licenses/BSD-3-Clause 63 | 64 | 65 | 66 | 67 | 68 | Electronic Arts Inc 69 | http://www.ea.com 70 | 71 | 72 | 73 | 74 | Electronic Arts Inc 75 | http://www.ea.com 76 | 77 | 78 | 79 | https://github.com/electronicarts/ea-agent-loader 80 | scm:git:git://github.com/electronicarts/ea-agent-loader.git 81 | scm:git:ssh://git@github.com/electronicarts/ea-agent-loader.git 82 | 83 | 84 | 85 | 86 | 87 | 88 | org.apache.maven.plugins 89 | maven-compiler-plugin 90 | 3.3 91 | 92 | 93 | 94 | org.apache.maven.plugins 95 | maven-jar-plugin 96 | 2.6 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-gpg-plugin 101 | 1.6 102 | 103 | 104 | org.apache.maven.plugins 105 | maven-surefire-plugin 106 | 2.18.1 107 | 108 | 109 | org.apache.maven.plugins 110 | maven-source-plugin 111 | 2.4 112 | 113 | 114 | org.apache.maven.plugins 115 | maven-javadoc-plugin 116 | 2.10.3 117 | 118 | 119 | 120 | 121 | 122 | 123 | org.apache.maven.plugins 124 | maven-compiler-plugin 125 | 126 | ${project.target.jdk} 127 | ${project.source.jdk} 128 | 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-source-plugin 133 | 134 | 135 | attach-sources 136 | 137 | jar 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | public-deploy 148 | 149 | 150 | !internalDeploy 151 | 152 | 153 | 154 | 155 | ossrh 156 | https://oss.sonatype.org/content/repositories/snapshots 157 | 158 | 159 | ossrh 160 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 161 | 162 | 163 | 164 | 165 | internal-deploy 166 | 167 | 168 | internalDeploy 169 | true 170 | 171 | 172 | 173 | 174 | ${internalSnapshotRepo.id} 175 | ${internalSnapshotRepo.url} 176 | 177 | 178 | ${internalReleaseRepo.id} 179 | ${internalReleaseRepo.url} 180 | 181 | 182 | 183 | 184 | stageRelease 185 | 186 | 187 | 188 | org.apache.maven.plugins 189 | maven-javadoc-plugin 190 | 191 | false 192 | -Xdoclint:none 193 | 194 | 195 | 196 | 197 | false 198 | -Xdoclint:none 199 | 200 | attach-javadocs 201 | 202 | jar 203 | 204 | 205 | 206 | attach-javadocs-2 207 | 208 | aggregate 209 | 210 | 211 | 212 | 213 | 214 | org.apache.maven.plugins 215 | maven-gpg-plugin 216 | 217 | 218 | sign-artifacts 219 | verify 220 | 221 | sign 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | -------------------------------------------------------------------------------- /agent-loader/src/main/java/com/ea/agentloader/AgentLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2015 Electronic Arts Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 2. Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY 18 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | package com.ea.agentloader; 30 | 31 | import java.io.File; 32 | import java.io.FileOutputStream; 33 | import java.io.IOException; 34 | import java.io.OutputStream; 35 | import java.lang.management.ManagementFactory; 36 | import java.lang.reflect.Method; 37 | import java.net.URL; 38 | import java.util.ArrayList; 39 | import java.util.Arrays; 40 | import java.util.List; 41 | import java.util.jar.Attributes; 42 | import java.util.jar.JarOutputStream; 43 | import java.util.jar.Manifest; 44 | 45 | /** 46 | * Utilities to load java agents dynamically. 47 | *

48 | * Deals with the problem of finding the proper jvm classes. 49 | * 50 | * @author Daniel Sperry 51 | * @see java.lang.instrument.Instrumentation 52 | */ 53 | public class AgentLoader 54 | { 55 | private volatile static AgentLoaderInterface agentLoader; 56 | 57 | /** 58 | * Internal class. 59 | */ 60 | // used internally, has to be public to be accessible from the shadeClassLoaders 61 | interface AgentLoaderInterface 62 | { 63 | void loadAgent(String agentJar, String options); 64 | } 65 | 66 | /** 67 | * Dynamically loads a java agent. 68 | * Deals with the problem of finding the proper jvm classes. 69 | * 70 | * @param agentJar the agent jar 71 | * @param options options that will be passed back to the agent, can be null 72 | * @see java.lang.instrument.Instrumentation 73 | */ 74 | public static void loadAgent(String agentJar, String options) 75 | { 76 | AgentLoaderInterface agentLoader = getAgentLoader(agentJar); 77 | agentLoader.loadAgent(agentJar, options); 78 | } 79 | 80 | 81 | /** 82 | * Creates loads the agent class directly. The agent class must be visible from the system class loader. 83 | *

84 | * This method creates a temporary jar with the proper manifest and loads the agent using the jvm attach facilities. 85 | *

86 | * This will not work if the agent class can't be loaded by the system class loader. 87 | *
88 | * This can be worked around like by adding the specific class and any other dependencies to the system class loader: 89 | *


 90 |      *     if(MyAgent.class.getClassLoader() != ClassLoader.getSystemClassLoader()) {
 91 |      *         ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(MyAgent.class));
 92 |      *         ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(OtherDepenencies.class));
 93 |      *     }
 94 |      *     loadAgent(MyAgent.class.getName(), null, null, true, true, false);
 95 |      * 
96 | * 97 | * @param agentClassName the agent class name 98 | * @param options options that will be passed back to the agent, can be null 99 | */ 100 | public static void loadAgentClass(String agentClassName, String options) 101 | { 102 | loadAgentClass(agentClassName, options, null, true, true, false); 103 | } 104 | 105 | 106 | /** 107 | * Creates loads the agent class directly. 108 | *

109 | * This method creates a temporary jar with the proper manifest and loads the agent using the jvm attach facilities. 110 | *

111 | * This will not work if the agent class can't be loaded by the system class loader. 112 | *
113 | * This can be worked around like by adding the specific class and any other dependencies to the system class loader: 114 | *


115 |      *     if(MyAgent.class.getClassLoader() != ClassLoader.getSystemClassLoader()) {
116 |      *         ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(MyAgent.class));
117 |      *         ClassPathUtils.appendToSystemPath(ClassPathUtils.getClassPathFor(OtherDepenencies.class));
118 |      *     }
119 |      *     loadAgent(MyAgent.class.getName(), null, null, true, true, false);
120 |      * 
121 | * 122 | * @param agentClass the agent class 123 | * @param options options that will be passed back to the agent, can be null 124 | * @param bootClassPath list of jars to be loaded with the agent, can be null 125 | * @param canRedefineClasses if the ability to redefine classes is need by the agent, suggested default: false 126 | * @param canRetransformClasses if the ability to retransform classes is need by the agent, suggested default: false 127 | * @param canSetNativeMethodPrefix if the ability to set native method prefix is need by the agent, suggested default: false 128 | * @see ClassPathUtils 129 | * @see java.lang.instrument.Instrumentation 130 | */ 131 | public static void loadAgentClass( 132 | final String agentClass, 133 | final String options, 134 | final String bootClassPath, 135 | final boolean canRedefineClasses, 136 | final boolean canRetransformClasses, 137 | final boolean canSetNativeMethodPrefix) 138 | { 139 | final File jarFile; 140 | try 141 | { 142 | jarFile = createTemporaryAgentJar(agentClass, bootClassPath, canRedefineClasses, canRetransformClasses, canSetNativeMethodPrefix); 143 | } 144 | catch (IOException ex) 145 | { 146 | throw new RuntimeException("Can't write jar file for agent:" + agentClass, ex); 147 | } 148 | loadAgent(jarFile.getPath(), options); 149 | } 150 | 151 | @SuppressWarnings("unchecked") 152 | private synchronized static AgentLoaderInterface getAgentLoader(final String agentJar) 153 | { 154 | if (agentLoader != null) 155 | { 156 | return agentLoader; 157 | } 158 | Class agentLoaderClass; 159 | try 160 | { 161 | Class.forName("com.sun.tools.attach.VirtualMachine"); 162 | agentLoaderClass = (Class) Class.forName("com.ea.agentloader.AgentLoaderHotSpot"); 163 | } 164 | catch (Exception ex) 165 | { 166 | // tools.jar not available in the class path 167 | // so we load our own copy of those files 168 | final List shaded = Arrays.asList( 169 | "shaded/AttachProvider.class", 170 | "shaded/VirtualMachine.class", 171 | "AttachProviderPlaceHolder.class", 172 | "shaded/AgentInitializationException.class", 173 | "shaded/AgentLoadException.class", 174 | "shaded/AttachNotSupportedException.class", 175 | "shaded/AttachOperationFailedException.class", 176 | "shaded/AttachPermission.class", 177 | "shaded/HotSpotAttachProvider.class", 178 | "shaded/HotSpotVirtualMachine.class", 179 | "shaded/VirtualMachineDescriptor.class", 180 | 181 | "shaded/WindowsAttachProvider.class", 182 | "shaded/WindowsVirtualMachine.class", 183 | 184 | "shaded/SolarisAttachProvider.class", 185 | "shaded/SolarisVirtualMachine.class", 186 | 187 | "shaded/LinuxAttachProvider.class", 188 | "shaded/LinuxVirtualMachine.class", 189 | 190 | "shaded/BsdAttachProvider.class", 191 | "shaded/BsdVirtualMachine.class", 192 | 193 | "shaded/HotSpotAttachProvider$HotSpotVirtualMachineDescriptor.class", 194 | 195 | "shaded/BsdVirtualMachine$SocketInputStream.class", 196 | "shaded/LinuxVirtualMachine$SocketInputStream.class", 197 | "shaded/SolarisVirtualMachine$SocketInputStream.class", 198 | "shaded/WindowsVirtualMachine$PipedInputStream.class" 199 | ); 200 | final ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); 201 | List> classes = new ArrayList<>(); 202 | for (String s : shaded) 203 | { 204 | // have to load those class in the system class loader 205 | // to prevent getting "Native Library .../libattach.so already loaded in another classloader" 206 | // when the vm is used more than once. 207 | try 208 | { 209 | classes.add(ClassPathUtils.defineClass(systemLoader, AgentLoader.class.getResourceAsStream(s))); 210 | } 211 | catch (Exception e) 212 | { 213 | throw new RuntimeException("Error defining: " + s, e); 214 | } 215 | } 216 | try 217 | { 218 | agentLoaderClass = (Class) ClassPathUtils.defineClass(systemLoader, AgentLoader.class.getResourceAsStream("/com/ea/agentloader/AgentLoaderHotSpot.class")); 219 | } 220 | catch (Exception e) 221 | { 222 | throw new RuntimeException("Error loading AgentLoader implementation", e); 223 | } 224 | } 225 | try 226 | { 227 | Object agentLoaderObject = agentLoaderClass.newInstance(); 228 | 229 | // the agent loader might be instantiated in another class loader 230 | // so no interface it implements is guaranteed to be visible here. 231 | // this reflection based implementation of this interface solves this problem. 232 | agentLoader = new AgentLoaderInterface() 233 | { 234 | @Override 235 | public void loadAgent(final String agentJar, final String options) 236 | { 237 | try 238 | { 239 | final Method loadAgentMethod = agentLoaderObject.getClass().getMethod("loadAgent", String.class, String.class); 240 | loadAgentMethod.invoke(agentLoaderObject, agentJar, options); 241 | } 242 | catch (Exception e) 243 | { 244 | throw new RuntimeException(e); 245 | } 246 | } 247 | }; 248 | } 249 | catch (Exception e) 250 | { 251 | throw new RuntimeException("Error getting agent loader implementation to load: " + agentJar, e); 252 | } 253 | return agentLoader; 254 | } 255 | 256 | /** 257 | * Gets the current jvm's pid. 258 | * 259 | * @return the pid as String 260 | */ 261 | public static String getPid() 262 | { 263 | String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); 264 | int p = nameOfRunningVM.indexOf('@'); 265 | return nameOfRunningVM.substring(0, p); 266 | } 267 | 268 | /** 269 | * Creates a jar in runtime with the proper manifest file to start the javaagent. 270 | *

271 | * This method is convenient to java agent developers since they can test their agents without creating a jar first. 272 | * 273 | * @param agentClass the agent class 274 | * @param bootClassPath list of jars to be loaded with the agent, can be null 275 | * @param canRedefineClasses if the ability to redefine classes is need by the agent, suggested default: false 276 | * @param canRetransformClasses if the ability to retransform classes is need by the agent, suggested default: false 277 | * @param canSetNativeMethodPrefix if the ability to set native method prefix is need by the agent, suggested default: false 278 | */ 279 | public static File createTemporaryAgentJar( 280 | final String agentClass, 281 | final String bootClassPath, 282 | final boolean canRedefineClasses, 283 | final boolean canRetransformClasses, 284 | final boolean canSetNativeMethodPrefix) throws IOException 285 | { 286 | final File jarFile = File.createTempFile("javaagent." + agentClass, ".jar"); 287 | jarFile.deleteOnExit(); 288 | createAgentJar(new FileOutputStream(jarFile), 289 | agentClass, 290 | bootClassPath, 291 | canRedefineClasses, 292 | canRetransformClasses, 293 | canSetNativeMethodPrefix); 294 | return jarFile; 295 | } 296 | 297 | /** 298 | * Creates an agent jar with the proper manifest file to start a javaagent. 299 | * 300 | * @param agentClass the agent class 301 | * @param bootClassPath list of jars to be loaded with the agent, can be null 302 | * @param canRedefineClasses if the ability to redefine classes is need by the agent, suggested default: false 303 | * @param canRetransformClasses if the ability to retransform classes is need by the agent, suggested default: false 304 | * @param canSetNativeMethodPrefix if the ability to set native method prefix is need by the agent, suggested default: false 305 | */ 306 | public static void createAgentJar( 307 | final OutputStream out, 308 | final String agentClass, 309 | final String bootClassPath, 310 | final boolean canRedefineClasses, 311 | final boolean canRetransformClasses, 312 | final boolean canSetNativeMethodPrefix) throws IOException 313 | { 314 | final Manifest man = new Manifest(); 315 | man.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); 316 | man.getMainAttributes().putValue("Agent-Class", agentClass); 317 | if (bootClassPath != null) 318 | { 319 | man.getMainAttributes().putValue("Boot-Class-Path", bootClassPath); 320 | } 321 | man.getMainAttributes().putValue("Can-Redefine-Classes", Boolean.toString(canRedefineClasses)); 322 | man.getMainAttributes().putValue("Can-Retransform-Classes", Boolean.toString(canRetransformClasses)); 323 | man.getMainAttributes().putValue("Can-Set-Native-Method-Prefix", Boolean.toString(canSetNativeMethodPrefix)); 324 | final JarOutputStream jarOut = new JarOutputStream(out, man); 325 | jarOut.flush(); 326 | jarOut.close(); 327 | } 328 | 329 | } 330 | --------------------------------------------------------------------------------