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