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