|
1 /* |
|
2 * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package sun.tools.jconsole; |
|
27 |
|
28 import java.util.*; |
|
29 import java.io.IOException; |
|
30 import java.io.File; |
|
31 |
|
32 import com.sun.tools.attach.VirtualMachine; |
|
33 import com.sun.tools.attach.VirtualMachineDescriptor; |
|
34 import com.sun.tools.attach.AttachNotSupportedException; |
|
35 |
|
36 import jdk.internal.agent.ConnectorAddressLink; |
|
37 import sun.jvmstat.monitor.HostIdentifier; |
|
38 import sun.jvmstat.monitor.MonitoredHost; |
|
39 import sun.jvmstat.monitor.MonitoredVm; |
|
40 import sun.jvmstat.monitor.MonitoredVmUtil; |
|
41 import sun.jvmstat.monitor.MonitorException; |
|
42 import sun.jvmstat.monitor.VmIdentifier; |
|
43 |
|
44 public class LocalVirtualMachine { |
|
45 private String address; |
|
46 private String commandLine; |
|
47 private String displayName; |
|
48 private int vmid; |
|
49 private boolean isAttachSupported; |
|
50 |
|
51 public LocalVirtualMachine(int vmid, String commandLine, boolean canAttach, String connectorAddress) { |
|
52 this.vmid = vmid; |
|
53 this.commandLine = commandLine; |
|
54 this.address = connectorAddress; |
|
55 this.isAttachSupported = canAttach; |
|
56 this.displayName = getDisplayName(commandLine); |
|
57 } |
|
58 |
|
59 private static String getDisplayName(String commandLine) { |
|
60 // trim the pathname of jar file if it's a jar |
|
61 String[] res = commandLine.split(" ", 2); |
|
62 if (res[0].endsWith(".jar")) { |
|
63 File jarfile = new File(res[0]); |
|
64 String displayName = jarfile.getName(); |
|
65 if (res.length == 2) { |
|
66 displayName += " " + res[1]; |
|
67 } |
|
68 return displayName; |
|
69 } |
|
70 return commandLine; |
|
71 } |
|
72 |
|
73 public int vmid() { |
|
74 return vmid; |
|
75 } |
|
76 |
|
77 public boolean isManageable() { |
|
78 return (address != null); |
|
79 } |
|
80 |
|
81 public boolean isAttachable() { |
|
82 return isAttachSupported; |
|
83 } |
|
84 |
|
85 public void startManagementAgent() throws IOException { |
|
86 if (address != null) { |
|
87 // already started |
|
88 return; |
|
89 } |
|
90 |
|
91 if (!isAttachable()) { |
|
92 throw new IOException("This virtual machine \"" + vmid + |
|
93 "\" does not support dynamic attach."); |
|
94 } |
|
95 |
|
96 loadManagementAgent(); |
|
97 // fails to load or start the management agent |
|
98 if (address == null) { |
|
99 // should never reach here |
|
100 throw new IOException("Fails to find connector address"); |
|
101 } |
|
102 } |
|
103 |
|
104 public String connectorAddress() { |
|
105 // return null if not available or no JMX agent |
|
106 return address; |
|
107 } |
|
108 |
|
109 public String displayName() { |
|
110 return displayName; |
|
111 } |
|
112 |
|
113 public String toString() { |
|
114 return commandLine; |
|
115 } |
|
116 |
|
117 // This method returns the list of all virtual machines currently |
|
118 // running on the machine |
|
119 public static Map<Integer, LocalVirtualMachine> getAllVirtualMachines() { |
|
120 Map<Integer, LocalVirtualMachine> map = |
|
121 new HashMap<Integer, LocalVirtualMachine>(); |
|
122 getMonitoredVMs(map); |
|
123 getAttachableVMs(map); |
|
124 return map; |
|
125 } |
|
126 |
|
127 private static void getMonitoredVMs(Map<Integer, LocalVirtualMachine> map) { |
|
128 MonitoredHost host; |
|
129 Set<Integer> vms; |
|
130 try { |
|
131 host = MonitoredHost.getMonitoredHost(new HostIdentifier((String)null)); |
|
132 vms = host.activeVms(); |
|
133 } catch (java.net.URISyntaxException | MonitorException x) { |
|
134 throw new InternalError(x.getMessage(), x); |
|
135 } |
|
136 for (Object vmid: vms) { |
|
137 if (vmid instanceof Integer) { |
|
138 int pid = ((Integer) vmid).intValue(); |
|
139 String name = vmid.toString(); // default to pid if name not available |
|
140 boolean attachable = false; |
|
141 String address = null; |
|
142 try { |
|
143 MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name)); |
|
144 // use the command line as the display name |
|
145 name = MonitoredVmUtil.commandLine(mvm); |
|
146 attachable = MonitoredVmUtil.isAttachable(mvm); |
|
147 address = ConnectorAddressLink.importFrom(pid); |
|
148 mvm.detach(); |
|
149 } catch (Exception x) { |
|
150 // ignore |
|
151 } |
|
152 map.put((Integer) vmid, |
|
153 new LocalVirtualMachine(pid, name, attachable, address)); |
|
154 } |
|
155 } |
|
156 } |
|
157 |
|
158 private static final String LOCAL_CONNECTOR_ADDRESS_PROP = |
|
159 "com.sun.management.jmxremote.localConnectorAddress"; |
|
160 |
|
161 private static void getAttachableVMs(Map<Integer, LocalVirtualMachine> map) { |
|
162 List<VirtualMachineDescriptor> vms = VirtualMachine.list(); |
|
163 for (VirtualMachineDescriptor vmd : vms) { |
|
164 try { |
|
165 Integer vmid = Integer.valueOf(vmd.id()); |
|
166 if (!map.containsKey(vmid)) { |
|
167 boolean attachable = false; |
|
168 String address = null; |
|
169 try { |
|
170 VirtualMachine vm = VirtualMachine.attach(vmd); |
|
171 attachable = true; |
|
172 Properties agentProps = vm.getAgentProperties(); |
|
173 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
|
174 vm.detach(); |
|
175 } catch (AttachNotSupportedException x) { |
|
176 // not attachable |
|
177 } catch (IOException x) { |
|
178 // ignore |
|
179 } |
|
180 map.put(vmid, new LocalVirtualMachine(vmid.intValue(), |
|
181 vmd.displayName(), |
|
182 attachable, |
|
183 address)); |
|
184 } |
|
185 } catch (NumberFormatException e) { |
|
186 // do not support vmid different than pid |
|
187 } |
|
188 } |
|
189 } |
|
190 |
|
191 public static LocalVirtualMachine getLocalVirtualMachine(int vmid) { |
|
192 Map<Integer, LocalVirtualMachine> map = getAllVirtualMachines(); |
|
193 LocalVirtualMachine lvm = map.get(vmid); |
|
194 if (lvm == null) { |
|
195 // Check if the VM is attachable but not included in the list |
|
196 // if it's running with a different security context. |
|
197 // For example, Windows services running |
|
198 // local SYSTEM account are attachable if you have Adminstrator |
|
199 // privileges. |
|
200 boolean attachable = false; |
|
201 String address = null; |
|
202 String name = String.valueOf(vmid); // default display name to pid |
|
203 try { |
|
204 VirtualMachine vm = VirtualMachine.attach(name); |
|
205 attachable = true; |
|
206 Properties agentProps = vm.getAgentProperties(); |
|
207 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
|
208 vm.detach(); |
|
209 lvm = new LocalVirtualMachine(vmid, name, attachable, address); |
|
210 } catch (AttachNotSupportedException x) { |
|
211 // not attachable |
|
212 if (JConsole.isDebug()) { |
|
213 x.printStackTrace(); |
|
214 } |
|
215 } catch (IOException x) { |
|
216 // ignore |
|
217 if (JConsole.isDebug()) { |
|
218 x.printStackTrace(); |
|
219 } |
|
220 } |
|
221 } |
|
222 return lvm; |
|
223 } |
|
224 |
|
225 // load the management agent into the target VM |
|
226 private void loadManagementAgent() throws IOException { |
|
227 VirtualMachine vm = null; |
|
228 String name = String.valueOf(vmid); |
|
229 try { |
|
230 vm = VirtualMachine.attach(name); |
|
231 } catch (AttachNotSupportedException x) { |
|
232 IOException ioe = new IOException(x.getMessage()); |
|
233 ioe.initCause(x); |
|
234 throw ioe; |
|
235 } |
|
236 |
|
237 vm.startLocalManagementAgent(); |
|
238 |
|
239 // get the connector address |
|
240 Properties agentProps = vm.getAgentProperties(); |
|
241 address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP); |
|
242 |
|
243 vm.detach(); |
|
244 } |
|
245 } |