1 /* 2 * Copyright (c) 2003, 2019, 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.management; 27 28 import java.lang.management.*; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import javax.management.InstanceAlreadyExistsException; 32 import javax.management.InstanceNotFoundException; 33 import javax.management.MBeanServer; 34 import javax.management.MBeanRegistrationException; 35 import javax.management.NotCompliantMBeanException; 36 import javax.management.ObjectName; 37 import javax.management.RuntimeOperationsException; 38 import java.security.AccessController; 39 import java.security.PrivilegedActionException; 40 import java.security.PrivilegedExceptionAction; 41 42 import jdk.internal.access.SharedSecrets; 43 import jdk.internal.misc.VM; 44 import jdk.internal.misc.VM.BufferPool; 45 46 import java.util.ArrayList; 47 import java.util.List; 48 49 import java.lang.reflect.UndeclaredThrowableException; 50 import java.security.PrivilegedAction; 51 import java.util.Arrays; 52 import java.util.Collections; 53 import java.util.HashMap; 54 import java.util.Map; 55 import java.util.Optional; 56 57 /** 58 * ManagementFactoryHelper provides static factory methods to create 59 * instances of the management interface. 60 */ 61 public class ManagementFactoryHelper { 62 static { 63 // make sure that the management lib is loaded within 64 // java.lang.management.ManagementFactory 65 jdk.internal.misc.Unsafe.getUnsafe().ensureClassInitialized(ManagementFactory.class); 66 } 67 68 private static final VMManagement jvm = new VMManagementImpl(); 69 70 private ManagementFactoryHelper() {}; 71 72 public static VMManagement getVMManagement() { 73 return jvm; 74 } 75 76 static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; 77 private static ClassLoadingImpl classMBean = null; 78 private static MemoryImpl memoryMBean = null; 79 private static ThreadImpl threadMBean = null; 80 private static RuntimeImpl runtimeMBean = null; 81 private static CompilationImpl compileMBean = null; 82 private static BaseOperatingSystemImpl osMBean = null; 83 84 public static synchronized ClassLoadingMXBean getClassLoadingMXBean() { 85 if (classMBean == null) { 86 classMBean = new ClassLoadingImpl(jvm); 87 } 88 return classMBean; 89 } 90 91 public static synchronized MemoryMXBean getMemoryMXBean() { 92 if (memoryMBean == null) { 93 memoryMBean = new MemoryImpl(jvm); 94 } 95 return memoryMBean; 96 } 97 98 public static synchronized ThreadMXBean getThreadMXBean() { 99 if (threadMBean == null) { 100 threadMBean = new ThreadImpl(jvm); 101 } 102 return threadMBean; 103 } 104 105 public static synchronized RuntimeMXBean getRuntimeMXBean() { 106 if (runtimeMBean == null) { 107 runtimeMBean = new RuntimeImpl(jvm); 108 } 109 return runtimeMBean; 110 } 111 112 public static synchronized CompilationMXBean getCompilationMXBean() { 113 if (compileMBean == null && jvm.getCompilerName() != null) { 114 compileMBean = new CompilationImpl(jvm); 115 } 116 return compileMBean; 117 } 118 119 public static synchronized OperatingSystemMXBean getOperatingSystemMXBean() { 120 if (osMBean == null) { 121 osMBean = new BaseOperatingSystemImpl(jvm); 122 } 123 return osMBean; 124 } 125 126 public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() { 127 MemoryPoolMXBean[] pools = MemoryImpl.getMemoryPools(); 128 List<MemoryPoolMXBean> list = new ArrayList<>(pools.length); 129 for (MemoryPoolMXBean p : pools) { 130 list.add(p); 131 } 132 return list; 133 } 134 135 public static List<MemoryManagerMXBean> getMemoryManagerMXBeans() { 136 MemoryManagerMXBean[] mgrs = MemoryImpl.getMemoryManagers(); 137 List<MemoryManagerMXBean> result = new ArrayList<>(mgrs.length); 138 for (MemoryManagerMXBean m : mgrs) { 139 result.add(m); 140 } 141 return result; 142 } 143 144 public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans() { 145 MemoryManagerMXBean[] mgrs = MemoryImpl.getMemoryManagers(); 146 List<GarbageCollectorMXBean> result = new ArrayList<>(mgrs.length); 147 for (MemoryManagerMXBean m : mgrs) { 148 if (GarbageCollectorMXBean.class.isInstance(m)) { 149 result.add(GarbageCollectorMXBean.class.cast(m)); 150 } 151 } 152 return result; 153 } 154 155 public static PlatformLoggingMXBean getPlatformLoggingMXBean() { 156 if (LoggingMXBeanAccess.isAvailable()) { 157 return PlatformLoggingImpl.MBEAN; 158 } else { 159 return null; 160 } 161 } 162 163 public static boolean isPlatformLoggingMXBeanAvailable() { 164 return LoggingMXBeanAccess.isAvailable(); 165 } 166 167 /** 168 * Returns an array of the name of all memory pools. The order of the memory pools is 169 * significant and maintained in the VM. 170 */ 171 public static String[] getAllMemoryPoolNames() { 172 return Arrays.stream(MemoryImpl.getMemoryPools()) 173 .map(MemoryPoolMXBean::getName) 174 .toArray(String[]::new); 175 } 176 177 // The LoggingMXBeanAccess class uses reflection to determine 178 // whether java.util.logging is present, and load the actual LoggingMXBean 179 // implementation. 180 // 181 static final class LoggingMXBeanAccess { 182 183 final static String LOG_MANAGER_CLASS_NAME = "java.util.logging.LogManager"; 184 final static String LOGGING_MXBEAN_CLASS_NAME = "java.util.logging.LoggingMXBean"; 185 final static Class<?> LOG_MANAGER_CLASS = loadLoggingClass(LOG_MANAGER_CLASS_NAME); 186 187 static boolean isAvailable() { 188 return LOG_MANAGER_CLASS != null; 189 } 190 191 private static Class<?> loadLoggingClass(String className) { 192 return AccessController.doPrivileged(new PrivilegedAction<>() { 193 @Override 194 public Class<?> run() { 195 Optional<Module> logging = ModuleLayer.boot().findModule("java.logging"); 196 if (logging.isPresent()) { 197 return Class.forName(logging.get(), className); 198 } 199 return null; 200 } 201 }); 202 } 203 204 private Map<String, Method> initMethodMap(Object impl) { 205 if (impl == null) { 206 return Collections.emptyMap(); 207 } 208 Class<?> intfClass = loadLoggingClass(LOGGING_MXBEAN_CLASS_NAME); 209 final Map<String, Method> methodsMap = new HashMap<>(); 210 for (Method m : intfClass.getMethods()) { 211 try { 212 // Sanity checking: all public methods present in 213 // java.util.logging.LoggingMXBean should 214 // also be in PlatformLoggingMXBean 215 Method specMethod = PlatformLoggingMXBean.class 216 .getMethod(m.getName(), m.getParameterTypes()); 217 if (specMethod.getReturnType().isAssignableFrom(m.getReturnType())) { 218 if (methodsMap.putIfAbsent(m.getName(), m) != null) { 219 throw new RuntimeException("unexpected polymorphic method: " 220 + m.getName()); 221 } 222 } 223 } catch (NoSuchMethodException x) { 224 // All methods in java.util.logging.LoggingMXBean should 225 // also be in PlatformLoggingMXBean 226 throw new InternalError(x); 227 } 228 } 229 return Collections.unmodifiableMap(methodsMap); 230 } 231 232 private static Object getMXBeanImplementation() { 233 if (!isAvailable()) { 234 // should not happen 235 throw new NoClassDefFoundError(LOG_MANAGER_CLASS_NAME); 236 } 237 try { 238 final Method m = LOG_MANAGER_CLASS.getMethod("getLoggingMXBean"); 239 return m.invoke(null); 240 } catch (NoSuchMethodException 241 | IllegalAccessException 242 | InvocationTargetException x) { 243 throw new ExceptionInInitializerError(x); 244 } 245 } 246 247 // The implementation object, which will be invoked through 248 // reflection. The implementation does not need to implement 249 // PlatformLoggingMXBean, but must declare the same methods 250 // with same signatures, and they must be public, with one 251 // exception: 252 // getObjectName will not be called on the implementation object, 253 // so the implementation object does not need to declare such 254 // a method. 255 final Object impl = getMXBeanImplementation(); 256 final Map<String, Method> methods = initMethodMap(impl); 257 258 LoggingMXBeanAccess() { 259 } 260 261 <T> T invoke(String methodName, Object... args) { 262 Method m = methods.get(methodName); 263 if (m == null) { 264 throw new UnsupportedOperationException(methodName); 265 } 266 try { 267 @SuppressWarnings("unchecked") 268 T result = (T) m.invoke(impl, args); 269 return result; 270 } catch (IllegalAccessException ex) { 271 throw new UnsupportedOperationException(ex); 272 } catch (InvocationTargetException ex) { 273 throw unwrap(ex); 274 } 275 } 276 277 private static RuntimeException unwrap(InvocationTargetException x) { 278 Throwable t = x.getCause(); 279 if (t instanceof RuntimeException) { 280 return (RuntimeException)t; 281 } 282 if (t instanceof Error) { 283 throw (Error)t; 284 } 285 return new UndeclaredThrowableException(t == null ? x : t); 286 } 287 288 289 } 290 291 static final class PlatformLoggingImpl implements PlatformLoggingMXBean { 292 293 private final LoggingMXBeanAccess loggingAccess; 294 private PlatformLoggingImpl(LoggingMXBeanAccess loggingAccess) { 295 this.loggingAccess = loggingAccess; 296 } 297 298 private volatile ObjectName objname; // created lazily 299 @Override 300 public ObjectName getObjectName() { 301 ObjectName result = objname; 302 if (result == null) { 303 synchronized (this) { 304 result = objname; 305 if (result == null) { 306 result = Util.newObjectName(LOGGING_MXBEAN_NAME); 307 objname = result; 308 } 309 } 310 } 311 return result; 312 } 313 314 @Override 315 public java.util.List<String> getLoggerNames() { 316 return loggingAccess.invoke("getLoggerNames"); 317 } 318 319 @Override 320 public String getLoggerLevel(String loggerName) { 321 return loggingAccess.invoke("getLoggerLevel", loggerName); 322 } 323 324 @Override 325 public void setLoggerLevel(String loggerName, String levelName) { 326 loggingAccess.invoke("setLoggerLevel", loggerName, levelName); 327 } 328 329 @Override 330 public String getParentLoggerName(String loggerName) { 331 return loggingAccess.invoke("getParentLoggerName", loggerName); 332 } 333 334 private static PlatformLoggingImpl getInstance() { 335 return new PlatformLoggingImpl(new LoggingMXBeanAccess()); 336 } 337 338 static final PlatformLoggingMXBean MBEAN = getInstance(); 339 } 340 341 private static List<BufferPoolMXBean> bufferPools = null; 342 public static synchronized List<BufferPoolMXBean> getBufferPoolMXBeans() { 343 if (bufferPools == null) { 344 bufferPools = new ArrayList<>(3); 345 VM.getBufferPools().forEach(pool -> bufferPools.add(createBufferPoolMXBean(pool))); 346 } 347 return bufferPools; 348 } 349 350 private final static String BUFFER_POOL_MXBEAN_NAME = "java.nio:type=BufferPool"; 351 352 /** 353 * Creates management interface for the given buffer pool. 354 */ 355 private static BufferPoolMXBean 356 createBufferPoolMXBean(final BufferPool pool) 357 { 358 return new BufferPoolMXBean() { 359 private volatile ObjectName objname; // created lazily 360 @Override 361 public ObjectName getObjectName() { 362 ObjectName result = objname; 363 if (result == null) { 364 synchronized (this) { 365 result = objname; 366 if (result == null) { 367 result = Util.newObjectName(BUFFER_POOL_MXBEAN_NAME + 368 ",name=" + pool.getName()); 369 objname = result; 370 } 371 } 372 } 373 return result; 374 } 375 @Override 376 public String getName() { 377 return pool.getName(); 378 } 379 @Override 380 public long getCount() { 381 return pool.getCount(); 382 } 383 @Override 384 public long getTotalCapacity() { 385 return pool.getTotalCapacity(); 386 } 387 @Override 388 public long getMemoryUsed() { 389 return pool.getMemoryUsed(); 390 } 391 }; 392 } 393 394 private static HotspotRuntime hsRuntimeMBean = null; 395 private static HotspotClassLoading hsClassMBean = null; 396 private static HotspotThread hsThreadMBean = null; 397 private static HotspotCompilation hsCompileMBean = null; 398 private static HotspotMemory hsMemoryMBean = null; 399 400 /** 401 * This method is for testing only. 402 */ 403 public static synchronized HotspotRuntimeMBean getHotspotRuntimeMBean() { 404 if (hsRuntimeMBean == null) { 405 hsRuntimeMBean = new HotspotRuntime(jvm); 406 } 407 return hsRuntimeMBean; 408 } 409 410 /** 411 * This method is for testing only. 412 */ 413 public static synchronized HotspotClassLoadingMBean getHotspotClassLoadingMBean() { 414 if (hsClassMBean == null) { 415 hsClassMBean = new HotspotClassLoading(jvm); 416 } 417 return hsClassMBean; 418 } 419 420 /** 421 * This method is for testing only. 422 */ 423 public static synchronized HotspotThreadMBean getHotspotThreadMBean() { 424 if (hsThreadMBean == null) { 425 hsThreadMBean = new HotspotThread(jvm); 426 } 427 return hsThreadMBean; 428 } 429 430 /** 431 * This method is for testing only. 432 */ 433 public static synchronized HotspotMemoryMBean getHotspotMemoryMBean() { 434 if (hsMemoryMBean == null) { 435 hsMemoryMBean = new HotspotMemory(jvm); 436 } 437 return hsMemoryMBean; 438 } 439 440 /** 441 * This method is for testing only. 442 */ 443 public static synchronized HotspotCompilationMBean getHotspotCompilationMBean() { 444 if (hsCompileMBean == null) { 445 hsCompileMBean = new HotspotCompilation(jvm); 446 } 447 return hsCompileMBean; 448 } 449 450 /** 451 * Registers a given MBean if not registered in the MBeanServer; 452 * otherwise, just return. 453 */ 454 private static void addMBean(MBeanServer mbs, Object mbean, String mbeanName) { 455 try { 456 final ObjectName objName = Util.newObjectName(mbeanName); 457 458 // inner class requires these fields to be final 459 final MBeanServer mbs0 = mbs; 460 final Object mbean0 = mbean; 461 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 462 public Void run() throws MBeanRegistrationException, 463 NotCompliantMBeanException { 464 try { 465 mbs0.registerMBean(mbean0, objName); 466 return null; 467 } catch (InstanceAlreadyExistsException e) { 468 // if an instance with the object name exists in 469 // the MBeanServer ignore the exception 470 } 471 return null; 472 } 473 }); 474 } catch (PrivilegedActionException e) { 475 throw Util.newException(e.getException()); 476 } 477 } 478 479 private final static String HOTSPOT_CLASS_LOADING_MBEAN_NAME = 480 "sun.management:type=HotspotClassLoading"; 481 482 private final static String HOTSPOT_COMPILATION_MBEAN_NAME = 483 "sun.management:type=HotspotCompilation"; 484 485 private final static String HOTSPOT_MEMORY_MBEAN_NAME = 486 "sun.management:type=HotspotMemory"; 487 488 private static final String HOTSPOT_RUNTIME_MBEAN_NAME = 489 "sun.management:type=HotspotRuntime"; 490 491 private final static String HOTSPOT_THREAD_MBEAN_NAME = 492 "sun.management:type=HotspotThreading"; 493 494 static void registerInternalMBeans(MBeanServer mbs) { 495 // register all internal MBeans if not registered 496 // No exception is thrown if a MBean with that object name 497 // already registered 498 addMBean(mbs, getHotspotClassLoadingMBean(), 499 HOTSPOT_CLASS_LOADING_MBEAN_NAME); 500 addMBean(mbs, getHotspotMemoryMBean(), 501 HOTSPOT_MEMORY_MBEAN_NAME); 502 addMBean(mbs, getHotspotRuntimeMBean(), 503 HOTSPOT_RUNTIME_MBEAN_NAME); 504 addMBean(mbs, getHotspotThreadMBean(), 505 HOTSPOT_THREAD_MBEAN_NAME); 506 507 // CompilationMBean may not exist 508 if (getCompilationMXBean() != null) { 509 addMBean(mbs, getHotspotCompilationMBean(), 510 HOTSPOT_COMPILATION_MBEAN_NAME); 511 } 512 } 513 514 private static void unregisterMBean(MBeanServer mbs, String mbeanName) { 515 try { 516 final ObjectName objName = Util.newObjectName(mbeanName); 517 518 // inner class requires these fields to be final 519 final MBeanServer mbs0 = mbs; 520 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 521 public Void run() throws MBeanRegistrationException, 522 RuntimeOperationsException { 523 try { 524 mbs0.unregisterMBean(objName); 525 } catch (InstanceNotFoundException e) { 526 // ignore exception if not found 527 } 528 return null; 529 } 530 }); 531 } catch (PrivilegedActionException e) { 532 throw Util.newException(e.getException()); 533 } 534 } 535 536 static void unregisterInternalMBeans(MBeanServer mbs) { 537 // unregister all internal MBeans 538 unregisterMBean(mbs, HOTSPOT_CLASS_LOADING_MBEAN_NAME); 539 unregisterMBean(mbs, HOTSPOT_MEMORY_MBEAN_NAME); 540 unregisterMBean(mbs, HOTSPOT_RUNTIME_MBEAN_NAME); 541 unregisterMBean(mbs, HOTSPOT_THREAD_MBEAN_NAME); 542 543 // CompilationMBean may not exist 544 if (getCompilationMXBean() != null) { 545 unregisterMBean(mbs, HOTSPOT_COMPILATION_MBEAN_NAME); 546 } 547 } 548 549 public static boolean isThreadSuspended(int state) { 550 return ((state & JMM_THREAD_STATE_FLAG_SUSPENDED) != 0); 551 } 552 553 public static boolean isThreadRunningNative(int state) { 554 return ((state & JMM_THREAD_STATE_FLAG_NATIVE) != 0); 555 } 556 557 public static Thread.State toThreadState(int state) { 558 // suspended and native bits may be set in state 559 int threadStatus = state & ~JMM_THREAD_STATE_FLAG_MASK; 560 return jdk.internal.misc.VM.toThreadState(threadStatus); 561 } 562 563 // These values are defined in jmm.h 564 private static final int JMM_THREAD_STATE_FLAG_MASK = 0xFFF00000; 565 private static final int JMM_THREAD_STATE_FLAG_SUSPENDED = 0x00100000; 566 private static final int JMM_THREAD_STATE_FLAG_NATIVE = 0x00400000; 567 568 // Invoked by the VM 569 private static MemoryPoolMXBean createMemoryPool 570 (String name, boolean isHeap, long uThreshold, long gcThreshold) { 571 return new MemoryPoolImpl(name, isHeap, uThreshold, gcThreshold); 572 } 573 574 private static MemoryManagerMXBean createMemoryManager(String name) { 575 return new MemoryManagerImpl(name); 576 } 577 578 private static GarbageCollectorMXBean 579 createGarbageCollector(String name, String type) { 580 581 // ignore type parameter which is for future extension 582 return new GarbageCollectorImpl(name); 583 } 584 }