1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 28 package java.util.logging; 29 30 import java.io.*; 31 import java.util.*; 32 import java.security.*; 33 import java.lang.ref.ReferenceQueue; 34 import java.lang.ref.WeakReference; 35 import java.lang.reflect.Constructor; 36 import java.lang.reflect.InvocationTargetException; 37 import java.lang.reflect.Method; 38 import java.beans.PropertyChangeListener; 39 40 /** 41 * There is a single global LogManager object that is used to 42 * maintain a set of shared state about Loggers and log services. 43 * <p> 44 * This LogManager object: 45 * <ul> 46 * <li> Manages a hierarchical namespace of Logger objects. All 47 * named Loggers are stored in this namespace. 48 * <li> Manages a set of logging control properties. These are 49 * simple key-value pairs that can be used by Handlers and 50 * other logging objects to configure themselves. 51 * </ul> 52 * <p> 53 * The global LogManager object can be retrieved using LogManager.getLogManager(). 54 * The LogManager object is created during class initialization and 55 * cannot subsequently be changed. 56 * <p> 57 * At startup the LogManager class is located using the 58 * java.util.logging.manager system property. 59 * <p> 60 * The LogManager defines two optional system properties that allow control over 61 * the initial configuration: 62 * <ul> 63 * <li>"java.util.logging.config.class" 64 * <li>"java.util.logging.config.file" 65 * </ul> 66 * These two properties may be specified on the command line to the "java" 67 * command, or as system property definitions passed to JNI_CreateJavaVM. 68 * <p> 69 * If the "java.util.logging.config.class" property is set, then the 70 * property value is treated as a class name. The given class will be 71 * loaded, an object will be instantiated, and that object's constructor 72 * is responsible for reading in the initial configuration. (That object 73 * may use other system properties to control its configuration.) The 74 * alternate configuration class can use <tt>readConfiguration(InputStream)</tt> 75 * to define properties in the LogManager. 76 * <p> 77 * If "java.util.logging.config.class" property is <b>not</b> set, 78 * then the "java.util.logging.config.file" system property can be used 79 * to specify a properties file (in java.util.Properties format). The 80 * initial logging configuration will be read from this file. 81 * <p> 82 * If neither of these properties is defined then the LogManager uses its 83 * default configuration. The default configuration is typically loaded from the 84 * properties file "{@code lib/logging.properties}" in the Java installation 85 * directory. 86 * <p> 87 * The properties for loggers and Handlers will have names starting 88 * with the dot-separated name for the handler or logger. 89 * <p> 90 * The global logging properties may include: 91 * <ul> 92 * <li>A property "handlers". This defines a whitespace or comma separated 93 * list of class names for handler classes to load and register as 94 * handlers on the root Logger (the Logger named ""). Each class 95 * name must be for a Handler class which has a default constructor. 96 * Note that these Handlers may be created lazily, when they are 97 * first used. 98 * 99 * <li>A property "<logger>.handlers". This defines a whitespace or 100 * comma separated list of class names for handlers classes to 101 * load and register as handlers to the specified logger. Each class 102 * name must be for a Handler class which has a default constructor. 103 * Note that these Handlers may be created lazily, when they are 104 * first used. 105 * 106 * <li>A property "<logger>.useParentHandlers". This defines a boolean 107 * value. By default every logger calls its parent in addition to 108 * handling the logging message itself, this often result in messages 109 * being handled by the root logger as well. When setting this property 110 * to false a Handler needs to be configured for this logger otherwise 111 * no logging messages are delivered. 112 * 113 * <li>A property "config". This property is intended to allow 114 * arbitrary configuration code to be run. The property defines a 115 * whitespace or comma separated list of class names. A new instance will be 116 * created for each named class. The default constructor of each class 117 * may execute arbitrary code to update the logging configuration, such as 118 * setting logger levels, adding handlers, adding filters, etc. 119 * </ul> 120 * <p> 121 * Note that all classes loaded during LogManager configuration are 122 * first searched on the system class path before any user class path. 123 * That includes the LogManager class, any config classes, and any 124 * handler classes. 125 * <p> 126 * Loggers are organized into a naming hierarchy based on their 127 * dot separated names. Thus "a.b.c" is a child of "a.b", but 128 * "a.b1" and a.b2" are peers. 129 * <p> 130 * All properties whose names end with ".level" are assumed to define 131 * log levels for Loggers. Thus "foo.level" defines a log level for 132 * the logger called "foo" and (recursively) for any of its children 133 * in the naming hierarchy. Log Levels are applied in the order they 134 * are defined in the properties file. Thus level settings for child 135 * nodes in the tree should come after settings for their parents. 136 * The property name ".level" can be used to set the level for the 137 * root of the tree. 138 * <p> 139 * All methods on the LogManager object are multi-thread safe. 140 * 141 * @since 1.4 142 */ 143 144 public class LogManager { 145 // The global LogManager object 146 private static final LogManager manager; 147 148 // 'props' is assigned within a lock but accessed without it. 149 // Declaring it volatile makes sure that another thread will not 150 // be able to see a partially constructed 'props' object. 151 // (seeing a partially constructed 'props' object can result in 152 // NPE being thrown in Hashtable.get(), because it leaves the door 153 // open for props.getProperties() to be called before the construcor 154 // of Hashtable is actually completed). 155 private volatile Properties props = new Properties(); 156 private final static Level defaultLevel = Level.INFO; 157 158 // The map of the registered listeners. The map value is the registration 159 // count to allow for cases where the same listener is registered many times. 160 private final Map<Object,Integer> listenerMap = new HashMap<>(); 161 162 // LoggerContext for system loggers and user loggers 163 private final LoggerContext systemContext = new SystemLoggerContext(); 164 private final LoggerContext userContext = new LoggerContext(); 165 // non final field - make it volatile to make sure that other threads 166 // will see the new value once ensureLogManagerInitialized() has finished 167 // executing. 168 private volatile Logger rootLogger; 169 // Have we done the primordial reading of the configuration file? 170 // (Must be done after a suitable amount of java.lang.System 171 // initialization has been done) 172 private volatile boolean readPrimordialConfiguration; 173 // Have we initialized global (root) handlers yet? 174 // This gets set to false in readConfiguration 175 private boolean initializedGlobalHandlers = true; 176 // True if JVM death is imminent and the exit hook has been called. 177 private boolean deathImminent; 178 179 static { 180 manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() { 181 @Override 182 public LogManager run() { 183 LogManager mgr = null; 184 String cname = null; 185 try { 186 cname = System.getProperty("java.util.logging.manager"); 187 if (cname != null) { 188 mgr = (LogManager) getClassInstance(cname).newInstance(); 189 } 190 } catch (Exception ex) { 191 System.err.println("Could not load Logmanager \"" + cname + "\""); 192 ex.printStackTrace(); 193 } 194 if (mgr == null) { 195 mgr = new LogManager(); 196 } 197 return mgr; 198 199 } 200 }); 201 } 202 203 204 // This private class is used as a shutdown hook. 205 // It does a "reset" to close all open handlers. 206 private class Cleaner extends Thread { 207 Cleaner()208 private Cleaner() { 209 /* Set context class loader to null in order to avoid 210 * keeping a strong reference to an application classloader. 211 */ 212 this.setContextClassLoader(null); 213 } 214 215 @Override run()216 public void run() { 217 // This is to ensure the LogManager.<clinit> is completed 218 // before synchronized block. Otherwise deadlocks are possible. 219 LogManager mgr = manager; 220 221 // If the global handlers haven't been initialized yet, we 222 // don't want to initialize them just so we can close them! 223 synchronized (LogManager.this) { 224 // Note that death is imminent. 225 deathImminent = true; 226 initializedGlobalHandlers = true; 227 } 228 229 // Do a reset to close all active handlers. 230 reset(); 231 } 232 } 233 234 235 /** 236 * Protected constructor. This is protected so that container applications 237 * (such as J2EE containers) can subclass the object. It is non-public as 238 * it is intended that there only be one LogManager object, whose value is 239 * retrieved by calling LogManager.getLogManager. 240 */ LogManager()241 protected LogManager() { 242 this(checkSubclassPermissions()); 243 } 244 LogManager(Void checked)245 private LogManager(Void checked) { 246 247 // Add a shutdown hook to close the global handlers. 248 try { 249 Runtime.getRuntime().addShutdownHook(new Cleaner()); 250 } catch (IllegalStateException e) { 251 // If the VM is already shutting down, 252 // We do not need to register shutdownHook. 253 } 254 } 255 checkSubclassPermissions()256 private static Void checkSubclassPermissions() { 257 final SecurityManager sm = System.getSecurityManager(); 258 if (sm != null) { 259 // These permission will be checked in the LogManager constructor, 260 // in order to register the Cleaner() thread as a shutdown hook. 261 // Check them here to avoid the penalty of constructing the object 262 // etc... 263 sm.checkPermission(new RuntimePermission("shutdownHooks")); 264 sm.checkPermission(new RuntimePermission("setContextClassLoader")); 265 } 266 return null; 267 } 268 269 /** 270 * Lazy initialization: if this instance of manager is the global 271 * manager then this method will read the initial configuration and 272 * add the root logger and global logger by calling addLogger(). 273 * 274 * Note that it is subtly different from what we do in LoggerContext. 275 * In LoggerContext we're patching up the logger context tree in order to add 276 * the root and global logger *to the context tree*. 277 * 278 * For this to work, addLogger() must have already have been called 279 * once on the LogManager instance for the default logger being 280 * added. 281 * 282 * This is why ensureLogManagerInitialized() needs to be called before 283 * any logger is added to any logger context. 284 * 285 */ 286 private boolean initializedCalled = false; 287 private volatile boolean initializationDone = false; ensureLogManagerInitialized()288 final void ensureLogManagerInitialized() { 289 final LogManager owner = this; 290 if (initializationDone || owner != manager) { 291 // we don't want to do this twice, and we don't want to do 292 // this on private manager instances. 293 return; 294 } 295 296 // Maybe another thread has called ensureLogManagerInitialized() 297 // before us and is still executing it. If so we will block until 298 // the log manager has finished initialized, then acquire the monitor, 299 // notice that initializationDone is now true and return. 300 // Otherwise - we have come here first! We will acquire the monitor, 301 // see that initializationDone is still false, and perform the 302 // initialization. 303 // 304 synchronized(this) { 305 // If initializedCalled is true it means that we're already in 306 // the process of initializing the LogManager in this thread. 307 // There has been a recursive call to ensureLogManagerInitialized(). 308 final boolean isRecursiveInitialization = (initializedCalled == true); 309 310 assert initializedCalled || !initializationDone 311 : "Initialization can't be done if initialized has not been called!"; 312 313 if (isRecursiveInitialization || initializationDone) { 314 // If isRecursiveInitialization is true it means that we're 315 // already in the process of initializing the LogManager in 316 // this thread. There has been a recursive call to 317 // ensureLogManagerInitialized(). We should not proceed as 318 // it would lead to infinite recursion. 319 // 320 // If initializationDone is true then it means the manager 321 // has finished initializing; just return: we're done. 322 return; 323 } 324 // Calling addLogger below will in turn call requiresDefaultLogger() 325 // which will call ensureLogManagerInitialized(). 326 // We use initializedCalled to break the recursion. 327 initializedCalled = true; 328 try { 329 AccessController.doPrivileged(new PrivilegedAction<Object>() { 330 @Override 331 public Object run() { 332 assert rootLogger == null; 333 assert initializedCalled && !initializationDone; 334 335 // Read configuration. 336 owner.readPrimordialConfiguration(); 337 338 // Create and retain Logger for the root of the namespace. 339 owner.rootLogger = owner.new RootLogger(); 340 owner.addLogger(owner.rootLogger); 341 if (!owner.rootLogger.isLevelInitialized()) { 342 owner.rootLogger.setLevel(defaultLevel); 343 } 344 345 // Adding the global Logger. 346 // Do not call Logger.getGlobal() here as this might trigger 347 // subtle inter-dependency issues. 348 @SuppressWarnings("deprecation") 349 final Logger global = Logger.global; 350 351 // Make sure the global logger will be registered in the 352 // global manager 353 owner.addLogger(global); 354 return null; 355 } 356 }); 357 } finally { 358 initializationDone = true; 359 } 360 } 361 } 362 363 /** 364 * Returns the global LogManager object. 365 * @return the global LogManager object 366 */ getLogManager()367 public static LogManager getLogManager() { 368 if (manager != null) { 369 manager.ensureLogManagerInitialized(); 370 } 371 return manager; 372 } 373 readPrimordialConfiguration()374 private void readPrimordialConfiguration() { 375 if (!readPrimordialConfiguration) { 376 synchronized (this) { 377 if (!readPrimordialConfiguration) { 378 // If System.in/out/err are null, it's a good 379 // indication that we're still in the 380 // bootstrapping phase 381 if (System.out == null) { 382 return; 383 } 384 readPrimordialConfiguration = true; 385 386 try { 387 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 388 @Override 389 public Void run() throws Exception { 390 readConfiguration(); 391 392 // Platform loggers begin to delegate to java.util.logging.Logger 393 sun.util.logging.PlatformLogger.redirectPlatformLoggers(); 394 return null; 395 } 396 }); 397 } catch (Exception ex) { 398 assert false : "Exception raised while reading logging configuration: " + ex; 399 } 400 } 401 } 402 } 403 } 404 405 /** 406 * Adds an event listener to be invoked when the logging 407 * properties are re-read. Adding multiple instances of 408 * the same event Listener results in multiple entries 409 * in the property event listener table. 410 * 411 * <p><b>WARNING:</b> This method is omitted from this class in all subset 412 * Profiles of Java SE that do not include the {@code java.beans} package. 413 * </p> 414 * 415 * @param l event listener 416 * @exception SecurityException if a security manager exists and if 417 * the caller does not have LoggingPermission("control"). 418 * @exception NullPointerException if the PropertyChangeListener is null. 419 * @deprecated The dependency on {@code PropertyChangeListener} creates a 420 * significant impediment to future modularization of the Java 421 * platform. This method will be removed in a future release. 422 * The global {@code LogManager} can detect changes to the 423 * logging configuration by overridding the {@link 424 * #readConfiguration readConfiguration} method. 425 */ 426 @Deprecated addPropertyChangeListener(PropertyChangeListener l)427 public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException { 428 PropertyChangeListener listener = Objects.requireNonNull(l); 429 checkPermission(); 430 synchronized (listenerMap) { 431 // increment the registration count if already registered 432 Integer value = listenerMap.get(listener); 433 value = (value == null) ? 1 : (value + 1); 434 listenerMap.put(listener, value); 435 } 436 } 437 438 /** 439 * Removes an event listener for property change events. 440 * If the same listener instance has been added to the listener table 441 * through multiple invocations of <CODE>addPropertyChangeListener</CODE>, 442 * then an equivalent number of 443 * <CODE>removePropertyChangeListener</CODE> invocations are required to remove 444 * all instances of that listener from the listener table. 445 * <P> 446 * Returns silently if the given listener is not found. 447 * 448 * <p><b>WARNING:</b> This method is omitted from this class in all subset 449 * Profiles of Java SE that do not include the {@code java.beans} package. 450 * </p> 451 * 452 * @param l event listener (can be null) 453 * @exception SecurityException if a security manager exists and if 454 * the caller does not have LoggingPermission("control"). 455 * @deprecated The dependency on {@code PropertyChangeListener} creates a 456 * significant impediment to future modularization of the Java 457 * platform. This method will be removed in a future release. 458 * The global {@code LogManager} can detect changes to the 459 * logging configuration by overridding the {@link 460 * #readConfiguration readConfiguration} method. 461 */ 462 @Deprecated removePropertyChangeListener(PropertyChangeListener l)463 public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException { 464 checkPermission(); 465 if (l != null) { 466 PropertyChangeListener listener = l; 467 synchronized (listenerMap) { 468 Integer value = listenerMap.get(listener); 469 if (value != null) { 470 // remove from map if registration count is 1, otherwise 471 // just decrement its count 472 int i = value.intValue(); 473 if (i == 1) { 474 listenerMap.remove(listener); 475 } else { 476 assert i > 1; 477 listenerMap.put(listener, i - 1); 478 } 479 } 480 } 481 } 482 } 483 484 // LoggerContext maps from AppContext 485 private WeakHashMap<Object, LoggerContext> contextsMap = null; 486 487 // Returns the LoggerContext for the user code (i.e. application or AppContext). 488 // Loggers are isolated from each AppContext. getUserContext()489 private LoggerContext getUserContext() { 490 // Android-changed: No AWT specific hooks. 491 return userContext; 492 } 493 494 // The system context. getSystemContext()495 final LoggerContext getSystemContext() { 496 return systemContext; 497 } 498 contexts()499 private List<LoggerContext> contexts() { 500 List<LoggerContext> cxs = new ArrayList<>(); 501 cxs.add(getSystemContext()); 502 cxs.add(getUserContext()); 503 return cxs; 504 } 505 506 // Find or create a specified logger instance. If a logger has 507 // already been created with the given name it is returned. 508 // Otherwise a new logger instance is created and registered 509 // in the LogManager global namespace. 510 // This method will always return a non-null Logger object. 511 // Synchronization is not required here. All synchronization for 512 // adding a new Logger object is handled by addLogger(). 513 // 514 // This method must delegate to the LogManager implementation to 515 // add a new Logger or return the one that has been added previously 516 // as a LogManager subclass may override the addLogger, getLogger, 517 // readConfiguration, and other methods. demandLogger(String name, String resourceBundleName, Class<?> caller)518 Logger demandLogger(String name, String resourceBundleName, Class<?> caller) { 519 Logger result = getLogger(name); 520 if (result == null) { 521 // only allocate the new logger once 522 Logger newLogger = new Logger(name, resourceBundleName, caller, this, false); 523 do { 524 if (addLogger(newLogger)) { 525 // We successfully added the new Logger that we 526 // created above so return it without refetching. 527 return newLogger; 528 } 529 530 // We didn't add the new Logger that we created above 531 // because another thread added a Logger with the same 532 // name after our null check above and before our call 533 // to addLogger(). We have to refetch the Logger because 534 // addLogger() returns a boolean instead of the Logger 535 // reference itself. However, if the thread that created 536 // the other Logger is not holding a strong reference to 537 // the other Logger, then it is possible for the other 538 // Logger to be GC'ed after we saw it in addLogger() and 539 // before we can refetch it. If it has been GC'ed then 540 // we'll just loop around and try again. 541 result = getLogger(name); 542 } while (result == null); 543 } 544 return result; 545 } 546 demandSystemLogger(String name, String resourceBundleName)547 Logger demandSystemLogger(String name, String resourceBundleName) { 548 // Add a system logger in the system context's namespace 549 final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName); 550 551 // Add the system logger to the LogManager's namespace if not exist 552 // so that there is only one single logger of the given name. 553 // System loggers are visible to applications unless a logger of 554 // the same name has been added. 555 Logger logger; 556 do { 557 // First attempt to call addLogger instead of getLogger 558 // This would avoid potential bug in custom LogManager.getLogger 559 // implementation that adds a logger if does not exist 560 if (addLogger(sysLogger)) { 561 // successfully added the new system logger 562 logger = sysLogger; 563 } else { 564 logger = getLogger(name); 565 } 566 } while (logger == null); 567 568 // LogManager will set the sysLogger's handlers via LogManager.addLogger method. 569 if (logger != sysLogger && sysLogger.accessCheckedHandlers().length == 0) { 570 // if logger already exists but handlers not set 571 final Logger l = logger; 572 AccessController.doPrivileged(new PrivilegedAction<Void>() { 573 @Override 574 public Void run() { 575 for (Handler hdl : l.accessCheckedHandlers()) { 576 sysLogger.addHandler(hdl); 577 } 578 return null; 579 } 580 }); 581 } 582 return sysLogger; 583 } 584 getClassInstance(String cname)585 private static Class getClassInstance(String cname) { 586 Class clz = null; 587 if (cname != null) { 588 try { 589 clz = ClassLoader.getSystemClassLoader().loadClass(cname); 590 } catch (ClassNotFoundException ex) { 591 try { 592 clz = Thread.currentThread().getContextClassLoader().loadClass(cname); 593 } catch (ClassNotFoundException innerEx) { 594 clz = null; 595 } 596 } 597 } 598 return clz; 599 } 600 601 // LoggerContext maintains the logger namespace per context. 602 // The default LogManager implementation has one system context and user 603 // context. The system context is used to maintain the namespace for 604 // all system loggers and is queried by the system code. If a system logger 605 // doesn't exist in the user context, it'll also be added to the user context. 606 // The user context is queried by the user code and all other loggers are 607 // added in the user context. 608 class LoggerContext { 609 // Table of named Loggers that maps names to Loggers. 610 private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>(); 611 // Tree of named Loggers 612 private final LogNode root; LoggerContext()613 private LoggerContext() { 614 this.root = new LogNode(null, this); 615 } 616 617 618 // Tells whether default loggers are required in this context. 619 // If true, the default loggers will be lazily added. requiresDefaultLoggers()620 final boolean requiresDefaultLoggers() { 621 final boolean requiresDefaultLoggers = (getOwner() == manager); 622 if (requiresDefaultLoggers) { 623 getOwner().ensureLogManagerInitialized(); 624 } 625 return requiresDefaultLoggers; 626 } 627 628 // This context's LogManager. getOwner()629 final LogManager getOwner() { 630 return LogManager.this; 631 } 632 633 // This context owner's root logger, which if not null, and if 634 // the context requires default loggers, will be added to the context 635 // logger's tree. getRootLogger()636 final Logger getRootLogger() { 637 return getOwner().rootLogger; 638 } 639 640 // The global logger, which if not null, and if 641 // the context requires default loggers, will be added to the context 642 // logger's tree. getGlobalLogger()643 final Logger getGlobalLogger() { 644 // Android-changed: s/deprecated/deprecation 645 @SuppressWarnings("deprecation") // avoids initialization cycles. 646 final Logger global = Logger.global; 647 return global; 648 } 649 demandLogger(String name, String resourceBundleName)650 Logger demandLogger(String name, String resourceBundleName) { 651 // a LogManager subclass may have its own implementation to add and 652 // get a Logger. So delegate to the LogManager to do the work. 653 final LogManager owner = getOwner(); 654 return owner.demandLogger(name, resourceBundleName, null); 655 } 656 657 658 // Due to subtle deadlock issues getUserContext() no longer 659 // calls addLocalLogger(rootLogger); 660 // Therefore - we need to add the default loggers later on. 661 // Checks that the context is properly initialized 662 // This is necessary before calling e.g. find(name) 663 // or getLoggerNames() 664 // ensureInitialized()665 private void ensureInitialized() { 666 if (requiresDefaultLoggers()) { 667 // Ensure that the root and global loggers are set. 668 ensureDefaultLogger(getRootLogger()); 669 ensureDefaultLogger(getGlobalLogger()); 670 } 671 } 672 673 findLogger(String name)674 synchronized Logger findLogger(String name) { 675 // ensure that this context is properly initialized before 676 // looking for loggers. 677 ensureInitialized(); 678 LoggerWeakRef ref = namedLoggers.get(name); 679 if (ref == null) { 680 return null; 681 } 682 Logger logger = ref.get(); 683 if (logger == null) { 684 // Hashtable holds stale weak reference 685 // to a logger which has been GC-ed. 686 ref.dispose(); 687 } 688 return logger; 689 } 690 691 // This method is called before adding a logger to the 692 // context. 693 // 'logger' is the context that will be added. 694 // This method will ensure that the defaults loggers are added 695 // before adding 'logger'. 696 // ensureAllDefaultLoggers(Logger logger)697 private void ensureAllDefaultLoggers(Logger logger) { 698 if (requiresDefaultLoggers()) { 699 final String name = logger.getName(); 700 if (!name.isEmpty()) { 701 ensureDefaultLogger(getRootLogger()); 702 if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) { 703 ensureDefaultLogger(getGlobalLogger()); 704 } 705 } 706 } 707 } 708 ensureDefaultLogger(Logger logger)709 private void ensureDefaultLogger(Logger logger) { 710 // Used for lazy addition of root logger and global logger 711 // to a LoggerContext. 712 713 // This check is simple sanity: we do not want that this 714 // method be called for anything else than Logger.global 715 // or owner.rootLogger. 716 if (!requiresDefaultLoggers() || logger == null 717 || logger != Logger.global && logger != LogManager.this.rootLogger) { 718 719 // the case where we have a non null logger which is neither 720 // Logger.global nor manager.rootLogger indicates a serious 721 // issue - as ensureDefaultLogger should never be called 722 // with any other loggers than one of these two (or null - if 723 // e.g manager.rootLogger is not yet initialized)... 724 assert logger == null; 725 726 return; 727 } 728 729 // Adds the logger if it's not already there. 730 if (!namedLoggers.containsKey(logger.getName())) { 731 // It is important to prevent addLocalLogger to 732 // call ensureAllDefaultLoggers when we're in the process 733 // off adding one of those default loggers - as this would 734 // immediately cause a stack overflow. 735 // Therefore we must pass addDefaultLoggersIfNeeded=false, 736 // even if requiresDefaultLoggers is true. 737 addLocalLogger(logger, false); 738 } 739 } 740 addLocalLogger(Logger logger)741 boolean addLocalLogger(Logger logger) { 742 // no need to add default loggers if it's not required 743 return addLocalLogger(logger, requiresDefaultLoggers()); 744 } 745 addLocalLogger(Logger logger, LogManager manager)746 boolean addLocalLogger(Logger logger, LogManager manager) { 747 // no need to add default loggers if it's not required 748 return addLocalLogger(logger, requiresDefaultLoggers(), manager); 749 } 750 addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded)751 boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) { 752 return addLocalLogger(logger, addDefaultLoggersIfNeeded, manager); 753 } 754 755 // Add a logger to this context. This method will only set its level 756 // and process parent loggers. It doesn't set its handlers. addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded, LogManager manager)757 synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded, 758 LogManager manager) { 759 // addDefaultLoggersIfNeeded serves to break recursion when adding 760 // default loggers. If we're adding one of the default loggers 761 // (we're being called from ensureDefaultLogger()) then 762 // addDefaultLoggersIfNeeded will be false: we don't want to 763 // call ensureAllDefaultLoggers again. 764 // 765 // Note: addDefaultLoggersIfNeeded can also be false when 766 // requiresDefaultLoggers is false - since calling 767 // ensureAllDefaultLoggers would have no effect in this case. 768 if (addDefaultLoggersIfNeeded) { 769 ensureAllDefaultLoggers(logger); 770 } 771 772 final String name = logger.getName(); 773 if (name == null) { 774 throw new NullPointerException(); 775 } 776 LoggerWeakRef ref = namedLoggers.get(name); 777 if (ref != null) { 778 if (ref.get() == null) { 779 // It's possible that the Logger was GC'ed after a 780 // drainLoggerRefQueueBounded() call above so allow 781 // a new one to be registered. 782 ref.dispose(); 783 } else { 784 // We already have a registered logger with the given name. 785 return false; 786 } 787 } 788 789 // We're adding a new logger. 790 // Note that we are creating a weak reference here. 791 final LogManager owner = getOwner(); 792 logger.setLogManager(owner); 793 ref = owner.new LoggerWeakRef(logger); 794 namedLoggers.put(name, ref); 795 796 // Apply any initial level defined for the new logger, unless 797 // the logger's level is already initialized 798 Level level = owner.getLevelProperty(name + ".level", null); 799 if (level != null && !logger.isLevelInitialized()) { 800 doSetLevel(logger, level); 801 } 802 803 // instantiation of the handler is done in the LogManager.addLogger 804 // implementation as a handler class may be only visible to LogManager 805 // subclass for the custom log manager case 806 processParentHandlers(logger, name); 807 808 // Find the new node and its parent. 809 LogNode node = getNode(name); 810 node.loggerRef = ref; 811 Logger parent = null; 812 LogNode nodep = node.parent; 813 while (nodep != null) { 814 LoggerWeakRef nodeRef = nodep.loggerRef; 815 if (nodeRef != null) { 816 parent = nodeRef.get(); 817 if (parent != null) { 818 break; 819 } 820 } 821 nodep = nodep.parent; 822 } 823 824 if (parent != null) { 825 doSetParent(logger, parent); 826 } 827 // Walk over the children and tell them we are their new parent. 828 node.walkAndSetParent(logger); 829 // new LogNode is ready so tell the LoggerWeakRef about it 830 ref.setNode(node); 831 return true; 832 } 833 removeLoggerRef(String name, LoggerWeakRef ref)834 synchronized void removeLoggerRef(String name, LoggerWeakRef ref) { 835 namedLoggers.remove(name, ref); 836 } 837 getLoggerNames()838 synchronized Enumeration<String> getLoggerNames() { 839 // ensure that this context is properly initialized before 840 // returning logger names. 841 ensureInitialized(); 842 return namedLoggers.keys(); 843 } 844 845 // If logger.getUseParentHandlers() returns 'true' and any of the logger's 846 // parents have levels or handlers defined, make sure they are instantiated. processParentHandlers(final Logger logger, final String name)847 private void processParentHandlers(final Logger logger, final String name) { 848 final LogManager owner = getOwner(); 849 AccessController.doPrivileged(new PrivilegedAction<Void>() { 850 @Override 851 public Void run() { 852 if (logger != owner.rootLogger) { 853 boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true); 854 if (!useParent) { 855 logger.setUseParentHandlers(false); 856 } 857 } 858 return null; 859 } 860 }); 861 862 int ix = 1; 863 for (;;) { 864 int ix2 = name.indexOf(".", ix); 865 if (ix2 < 0) { 866 break; 867 } 868 String pname = name.substring(0, ix2); 869 if (owner.getProperty(pname + ".level") != null || 870 owner.getProperty(pname + ".handlers") != null) { 871 // This pname has a level/handlers definition. 872 // Make sure it exists. 873 demandLogger(pname, null); 874 } 875 ix = ix2+1; 876 } 877 } 878 879 // Gets a node in our tree of logger nodes. 880 // If necessary, create it. getNode(String name)881 LogNode getNode(String name) { 882 if (name == null || name.equals("")) { 883 return root; 884 } 885 LogNode node = root; 886 while (name.length() > 0) { 887 int ix = name.indexOf("."); 888 String head; 889 if (ix > 0) { 890 head = name.substring(0, ix); 891 name = name.substring(ix + 1); 892 } else { 893 head = name; 894 name = ""; 895 } 896 if (node.children == null) { 897 node.children = new HashMap<>(); 898 } 899 LogNode child = node.children.get(head); 900 if (child == null) { 901 child = new LogNode(node, this); 902 node.children.put(head, child); 903 } 904 node = child; 905 } 906 return node; 907 } 908 } 909 910 final class SystemLoggerContext extends LoggerContext { 911 // Add a system logger in the system context's namespace as well as 912 // in the LogManager's namespace if not exist so that there is only 913 // one single logger of the given name. System loggers are visible 914 // to applications unless a logger of the same name has been added. 915 @Override demandLogger(String name, String resourceBundleName)916 Logger demandLogger(String name, String resourceBundleName) { 917 Logger result = findLogger(name); 918 if (result == null) { 919 // only allocate the new system logger once 920 Logger newLogger = new Logger(name, resourceBundleName, null, getOwner(), true); 921 do { 922 if (addLocalLogger(newLogger)) { 923 // We successfully added the new Logger that we 924 // created above so return it without refetching. 925 result = newLogger; 926 } else { 927 // We didn't add the new Logger that we created above 928 // because another thread added a Logger with the same 929 // name after our null check above and before our call 930 // to addLogger(). We have to refetch the Logger because 931 // addLogger() returns a boolean instead of the Logger 932 // reference itself. However, if the thread that created 933 // the other Logger is not holding a strong reference to 934 // the other Logger, then it is possible for the other 935 // Logger to be GC'ed after we saw it in addLogger() and 936 // before we can refetch it. If it has been GC'ed then 937 // we'll just loop around and try again. 938 result = findLogger(name); 939 } 940 } while (result == null); 941 } 942 return result; 943 } 944 } 945 946 // Add new per logger handlers. 947 // We need to raise privilege here. All our decisions will 948 // be made based on the logging configuration, which can 949 // only be modified by trusted code. loadLoggerHandlers(final Logger logger, final String name, final String handlersPropertyName)950 private void loadLoggerHandlers(final Logger logger, final String name, 951 final String handlersPropertyName) 952 { 953 AccessController.doPrivileged(new PrivilegedAction<Object>() { 954 @Override 955 public Object run() { 956 String names[] = parseClassNames(handlersPropertyName); 957 for (int i = 0; i < names.length; i++) { 958 String word = names[i]; 959 try { 960 // Android-changed: 961 Class<?> clz = getClassInstance(word); 962 Handler hdl = (Handler) clz.newInstance(); 963 // Check if there is a property defining the 964 // this handler's level. 965 String levs = getProperty(word + ".level"); 966 if (levs != null) { 967 Level l = Level.findLevel(levs); 968 if (l != null) { 969 hdl.setLevel(l); 970 } else { 971 // Probably a bad level. Drop through. 972 System.err.println("Can't set level for " + word); 973 } 974 } 975 // Add this Handler to the logger 976 logger.addHandler(hdl); 977 } catch (Exception ex) { 978 System.err.println("Can't load log handler \"" + word + "\""); 979 System.err.println("" + ex); 980 ex.printStackTrace(); 981 } 982 } 983 return null; 984 } 985 }); 986 } 987 988 989 // loggerRefQueue holds LoggerWeakRef objects for Logger objects 990 // that have been GC'ed. 991 private final ReferenceQueue<Logger> loggerRefQueue 992 = new ReferenceQueue<>(); 993 994 // Package-level inner class. 995 // Helper class for managing WeakReferences to Logger objects. 996 // 997 // LogManager.namedLoggers 998 // - has weak references to all named Loggers 999 // - namedLoggers keeps the LoggerWeakRef objects for the named 1000 // Loggers around until we can deal with the book keeping for 1001 // the named Logger that is being GC'ed. 1002 // LogManager.LogNode.loggerRef 1003 // - has a weak reference to a named Logger 1004 // - the LogNode will also keep the LoggerWeakRef objects for 1005 // the named Loggers around; currently LogNodes never go away. 1006 // Logger.kids 1007 // - has a weak reference to each direct child Logger; this 1008 // includes anonymous and named Loggers 1009 // - anonymous Loggers are always children of the rootLogger 1010 // which is a strong reference; rootLogger.kids keeps the 1011 // LoggerWeakRef objects for the anonymous Loggers around 1012 // until we can deal with the book keeping. 1013 // 1014 final class LoggerWeakRef extends WeakReference<Logger> { 1015 private String name; // for namedLoggers cleanup 1016 private LogNode node; // for loggerRef cleanup 1017 private WeakReference<Logger> parentRef; // for kids cleanup 1018 private boolean disposed = false; // avoid calling dispose twice 1019 LoggerWeakRef(Logger logger)1020 LoggerWeakRef(Logger logger) { 1021 super(logger, loggerRefQueue); 1022 1023 name = logger.getName(); // save for namedLoggers cleanup 1024 } 1025 1026 // dispose of this LoggerWeakRef object dispose()1027 void dispose() { 1028 // Avoid calling dispose twice. When a Logger is gc'ed, its 1029 // LoggerWeakRef will be enqueued. 1030 // However, a new logger of the same name may be added (or looked 1031 // up) before the queue is drained. When that happens, dispose() 1032 // will be called by addLocalLogger() or findLogger(). 1033 // Later when the queue is drained, dispose() will be called again 1034 // for the same LoggerWeakRef. Marking LoggerWeakRef as disposed 1035 // avoids processing the data twice (even though the code should 1036 // now be reentrant). 1037 synchronized(this) { 1038 // Note to maintainers: 1039 // Be careful not to call any method that tries to acquire 1040 // another lock from within this block - as this would surely 1041 // lead to deadlocks, given that dispose() can be called by 1042 // multiple threads, and from within different synchronized 1043 // methods/blocks. 1044 if (disposed) return; 1045 disposed = true; 1046 } 1047 1048 final LogNode n = node; 1049 if (n != null) { 1050 // n.loggerRef can only be safely modified from within 1051 // a lock on LoggerContext. removeLoggerRef is already 1052 // synchronized on LoggerContext so calling 1053 // n.context.removeLoggerRef from within this lock is safe. 1054 synchronized (n.context) { 1055 // if we have a LogNode, then we were a named Logger 1056 // so clear namedLoggers weak ref to us 1057 n.context.removeLoggerRef(name, this); 1058 name = null; // clear our ref to the Logger's name 1059 1060 // LogNode may have been reused - so only clear 1061 // LogNode.loggerRef if LogNode.loggerRef == this 1062 if (n.loggerRef == this) { 1063 n.loggerRef = null; // clear LogNode's weak ref to us 1064 } 1065 node = null; // clear our ref to LogNode 1066 } 1067 } 1068 1069 if (parentRef != null) { 1070 // this LoggerWeakRef has or had a parent Logger 1071 Logger parent = parentRef.get(); 1072 if (parent != null) { 1073 // the parent Logger is still there so clear the 1074 // parent Logger's weak ref to us 1075 parent.removeChildLogger(this); 1076 } 1077 parentRef = null; // clear our weak ref to the parent Logger 1078 } 1079 } 1080 1081 // set the node field to the specified value setNode(LogNode node)1082 void setNode(LogNode node) { 1083 this.node = node; 1084 } 1085 1086 // set the parentRef field to the specified value setParentRef(WeakReference<Logger> parentRef)1087 void setParentRef(WeakReference<Logger> parentRef) { 1088 this.parentRef = parentRef; 1089 } 1090 } 1091 1092 // Package-level method. 1093 // Drain some Logger objects that have been GC'ed. 1094 // 1095 // drainLoggerRefQueueBounded() is called by addLogger() below 1096 // and by Logger.getAnonymousLogger(String) so we'll drain up to 1097 // MAX_ITERATIONS GC'ed Loggers for every Logger we add. 1098 // 1099 // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives 1100 // us about a 50/50 mix in increased weak ref counts versus 1101 // decreased weak ref counts in the AnonLoggerWeakRefLeak test. 1102 // Here are stats for cleaning up sets of 400 anonymous Loggers: 1103 // - test duration 1 minute 1104 // - sample size of 125 sets of 400 1105 // - average: 1.99 ms 1106 // - minimum: 0.57 ms 1107 // - maximum: 25.3 ms 1108 // 1109 // The same config gives us a better decreased weak ref count 1110 // than increased weak ref count in the LoggerWeakRefLeak test. 1111 // Here are stats for cleaning up sets of 400 named Loggers: 1112 // - test duration 2 minutes 1113 // - sample size of 506 sets of 400 1114 // - average: 0.57 ms 1115 // - minimum: 0.02 ms 1116 // - maximum: 10.9 ms 1117 // 1118 private final static int MAX_ITERATIONS = 400; drainLoggerRefQueueBounded()1119 final void drainLoggerRefQueueBounded() { 1120 for (int i = 0; i < MAX_ITERATIONS; i++) { 1121 if (loggerRefQueue == null) { 1122 // haven't finished loading LogManager yet 1123 break; 1124 } 1125 1126 LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll(); 1127 if (ref == null) { 1128 break; 1129 } 1130 // a Logger object has been GC'ed so clean it up 1131 ref.dispose(); 1132 } 1133 } 1134 1135 /** 1136 * Add a named logger. This does nothing and returns false if a logger 1137 * with the same name is already registered. 1138 * <p> 1139 * The Logger factory methods call this method to register each 1140 * newly created Logger. 1141 * <p> 1142 * The application should retain its own reference to the Logger 1143 * object to avoid it being garbage collected. The LogManager 1144 * may only retain a weak reference. 1145 * 1146 * @param logger the new logger. 1147 * @return true if the argument logger was registered successfully, 1148 * false if a logger of that name already exists. 1149 * @exception NullPointerException if the logger name is null. 1150 */ addLogger(Logger logger)1151 public boolean addLogger(Logger logger) { 1152 final String name = logger.getName(); 1153 if (name == null) { 1154 throw new NullPointerException(); 1155 } 1156 drainLoggerRefQueueBounded(); 1157 LoggerContext cx = getUserContext(); 1158 if (cx.addLocalLogger(logger, this)) { 1159 // Do we have a per logger handler too? 1160 // Note: this will add a 200ms penalty 1161 loadLoggerHandlers(logger, name, name + ".handlers"); 1162 return true; 1163 } else { 1164 return false; 1165 } 1166 } 1167 1168 // Private method to set a level on a logger. 1169 // If necessary, we raise privilege before doing the call. doSetLevel(final Logger logger, final Level level)1170 private static void doSetLevel(final Logger logger, final Level level) { 1171 SecurityManager sm = System.getSecurityManager(); 1172 if (sm == null) { 1173 // There is no security manager, so things are easy. 1174 logger.setLevel(level); 1175 return; 1176 } 1177 // There is a security manager. Raise privilege before 1178 // calling setLevel. 1179 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1180 @Override 1181 public Object run() { 1182 logger.setLevel(level); 1183 return null; 1184 }}); 1185 } 1186 1187 // Private method to set a parent on a logger. 1188 // If necessary, we raise privilege before doing the setParent call. doSetParent(final Logger logger, final Logger parent)1189 private static void doSetParent(final Logger logger, final Logger parent) { 1190 SecurityManager sm = System.getSecurityManager(); 1191 if (sm == null) { 1192 // There is no security manager, so things are easy. 1193 logger.setParent(parent); 1194 return; 1195 } 1196 // There is a security manager. Raise privilege before 1197 // calling setParent. 1198 AccessController.doPrivileged(new PrivilegedAction<Object>() { 1199 @Override 1200 public Object run() { 1201 logger.setParent(parent); 1202 return null; 1203 }}); 1204 } 1205 1206 /** 1207 * Method to find a named logger. 1208 * <p> 1209 * Note that since untrusted code may create loggers with 1210 * arbitrary names this method should not be relied on to 1211 * find Loggers for security sensitive logging. 1212 * It is also important to note that the Logger associated with the 1213 * String {@code name} may be garbage collected at any time if there 1214 * is no strong reference to the Logger. The caller of this method 1215 * must check the return value for null in order to properly handle 1216 * the case where the Logger has been garbage collected. 1217 * <p> 1218 * @param name name of the logger 1219 * @return matching logger or null if none is found 1220 */ getLogger(String name)1221 public Logger getLogger(String name) { 1222 return getUserContext().findLogger(name); 1223 } 1224 1225 /** 1226 * Get an enumeration of known logger names. 1227 * <p> 1228 * Note: Loggers may be added dynamically as new classes are loaded. 1229 * This method only reports on the loggers that are currently registered. 1230 * It is also important to note that this method only returns the name 1231 * of a Logger, not a strong reference to the Logger itself. 1232 * The returned String does nothing to prevent the Logger from being 1233 * garbage collected. In particular, if the returned name is passed 1234 * to {@code LogManager.getLogger()}, then the caller must check the 1235 * return value from {@code LogManager.getLogger()} for null to properly 1236 * handle the case where the Logger has been garbage collected in the 1237 * time since its name was returned by this method. 1238 * <p> 1239 * @return enumeration of logger name strings 1240 */ getLoggerNames()1241 public Enumeration<String> getLoggerNames() { 1242 return getUserContext().getLoggerNames(); 1243 } 1244 1245 /** 1246 * Reinitialize the logging properties and reread the logging configuration. 1247 * <p> 1248 * The same rules are used for locating the configuration properties 1249 * as are used at startup. So normally the logging properties will 1250 * be re-read from the same file that was used at startup. 1251 * <P> 1252 * Any log level definitions in the new configuration file will be 1253 * applied using Logger.setLevel(), if the target Logger exists. 1254 * <p> 1255 * A PropertyChangeEvent will be fired after the properties are read. 1256 * 1257 * @exception SecurityException if a security manager exists and if 1258 * the caller does not have LoggingPermission("control"). 1259 * @exception IOException if there are IO problems reading the configuration. 1260 */ readConfiguration()1261 public void readConfiguration() throws IOException, SecurityException { 1262 checkPermission(); 1263 1264 // if a configuration class is specified, load it and use it. 1265 String cname = System.getProperty("java.util.logging.config.class"); 1266 if (cname != null) { 1267 try { 1268 // Instantiate the named class. It is its constructor's 1269 // responsibility to initialize the logging configuration, by 1270 // calling readConfiguration(InputStream) with a suitable stream. 1271 getClassInstance(cname).newInstance(); 1272 return; 1273 } catch (Exception ex) { 1274 System.err.println("Logging configuration class \"" + cname + "\" failed"); 1275 System.err.println("" + ex); 1276 // keep going and useful config file. 1277 } 1278 } 1279 1280 String fname = System.getProperty("java.util.logging.config.file"); 1281 if (fname == null) { 1282 fname = System.getProperty("java.home"); 1283 if (fname == null) { 1284 throw new Error("Can't find java.home ??"); 1285 } 1286 File f = new File(fname, "lib"); 1287 f = new File(f, "logging.properties"); 1288 fname = f.getCanonicalPath(); 1289 } 1290 1291 // Android-changed: Look in the boot class-path jar files for the logging.properties. 1292 // It will not be present in the file system. 1293 InputStream in; 1294 try { 1295 in = new FileInputStream(fname); 1296 } catch (Exception e) { 1297 in = LogManager.class.getResourceAsStream("logging.properties"); 1298 if (in == null) { 1299 throw e; 1300 } 1301 } 1302 1303 BufferedInputStream bin = new BufferedInputStream(in); 1304 try { 1305 readConfiguration(bin); 1306 } finally { 1307 if (in != null) { 1308 in.close(); 1309 } 1310 } 1311 } 1312 1313 /** 1314 * Reset the logging configuration. 1315 * <p> 1316 * For all named loggers, the reset operation removes and closes 1317 * all Handlers and (except for the root logger) sets the level 1318 * to null. The root logger's level is set to Level.INFO. 1319 * 1320 * @exception SecurityException if a security manager exists and if 1321 * the caller does not have LoggingPermission("control"). 1322 */ 1323 reset()1324 public void reset() throws SecurityException { 1325 checkPermission(); 1326 synchronized (this) { 1327 props = new Properties(); 1328 // Since we are doing a reset we no longer want to initialize 1329 // the global handlers, if they haven't been initialized yet. 1330 initializedGlobalHandlers = true; 1331 } 1332 for (LoggerContext cx : contexts()) { 1333 Enumeration<String> enum_ = cx.getLoggerNames(); 1334 while (enum_.hasMoreElements()) { 1335 String name = enum_.nextElement(); 1336 Logger logger = cx.findLogger(name); 1337 if (logger != null) { 1338 resetLogger(logger); 1339 } 1340 } 1341 } 1342 } 1343 1344 // Private method to reset an individual target logger. resetLogger(Logger logger)1345 private void resetLogger(Logger logger) { 1346 // Close all the Logger's handlers. 1347 Handler[] targets = logger.getHandlers(); 1348 for (int i = 0; i < targets.length; i++) { 1349 Handler h = targets[i]; 1350 logger.removeHandler(h); 1351 try { 1352 h.close(); 1353 } catch (Exception ex) { 1354 // Problems closing a handler? Keep going... 1355 } 1356 } 1357 String name = logger.getName(); 1358 if (name != null && name.equals("")) { 1359 // This is the root logger. 1360 logger.setLevel(defaultLevel); 1361 } else { 1362 logger.setLevel(null); 1363 } 1364 } 1365 1366 // get a list of whitespace separated classnames from a property. parseClassNames(String propertyName)1367 private String[] parseClassNames(String propertyName) { 1368 String hands = getProperty(propertyName); 1369 if (hands == null) { 1370 return new String[0]; 1371 } 1372 hands = hands.trim(); 1373 int ix = 0; 1374 final List<String> result = new ArrayList<>(); 1375 while (ix < hands.length()) { 1376 int end = ix; 1377 while (end < hands.length()) { 1378 if (Character.isWhitespace(hands.charAt(end))) { 1379 break; 1380 } 1381 if (hands.charAt(end) == ',') { 1382 break; 1383 } 1384 end++; 1385 } 1386 String word = hands.substring(ix, end); 1387 ix = end+1; 1388 word = word.trim(); 1389 if (word.length() == 0) { 1390 continue; 1391 } 1392 result.add(word); 1393 } 1394 return result.toArray(new String[result.size()]); 1395 } 1396 1397 /** 1398 * Reinitialize the logging properties and reread the logging configuration 1399 * from the given stream, which should be in java.util.Properties format. 1400 * A PropertyChangeEvent will be fired after the properties are read. 1401 * <p> 1402 * Any log level definitions in the new configuration file will be 1403 * applied using Logger.setLevel(), if the target Logger exists. 1404 * 1405 * @param ins stream to read properties from 1406 * @exception SecurityException if a security manager exists and if 1407 * the caller does not have LoggingPermission("control"). 1408 * @exception IOException if there are problems reading from the stream. 1409 */ readConfiguration(InputStream ins)1410 public void readConfiguration(InputStream ins) throws IOException, SecurityException { 1411 checkPermission(); 1412 reset(); 1413 1414 // Load the properties 1415 props.load(ins); 1416 // Instantiate new configuration objects. 1417 String names[] = parseClassNames("config"); 1418 1419 for (int i = 0; i < names.length; i++) { 1420 String word = names[i]; 1421 try { 1422 getClassInstance(word).newInstance(); 1423 } catch (Exception ex) { 1424 System.err.println("Can't load config class \"" + word + "\""); 1425 System.err.println("" + ex); 1426 // ex.printStackTrace(); 1427 } 1428 } 1429 1430 // Set levels on any pre-existing loggers, based on the new properties. 1431 setLevelsOnExistingLoggers(); 1432 1433 // Notify any interested parties that our properties have changed. 1434 // We first take a copy of the listener map so that we aren't holding any 1435 // locks when calling the listeners. 1436 Map<Object,Integer> listeners = null; 1437 synchronized (listenerMap) { 1438 if (!listenerMap.isEmpty()) 1439 listeners = new HashMap<>(listenerMap); 1440 } 1441 if (listeners != null) { 1442 assert Beans.isBeansPresent(); 1443 Object ev = Beans.newPropertyChangeEvent(LogManager.class, null, null, null); 1444 for (Map.Entry<Object,Integer> entry : listeners.entrySet()) { 1445 Object listener = entry.getKey(); 1446 int count = entry.getValue().intValue(); 1447 for (int i = 0; i < count; i++) { 1448 Beans.invokePropertyChange(listener, ev); 1449 } 1450 } 1451 } 1452 1453 1454 // Note that we need to reinitialize global handles when 1455 // they are first referenced. 1456 synchronized (this) { 1457 initializedGlobalHandlers = false; 1458 } 1459 } 1460 1461 /** 1462 * Get the value of a logging property. 1463 * The method returns null if the property is not found. 1464 * @param name property name 1465 * @return property value 1466 */ getProperty(String name)1467 public String getProperty(String name) { 1468 return props.getProperty(name); 1469 } 1470 1471 // Package private method to get a String property. 1472 // If the property is not defined we return the given 1473 // default value. getStringProperty(String name, String defaultValue)1474 String getStringProperty(String name, String defaultValue) { 1475 String val = getProperty(name); 1476 if (val == null) { 1477 return defaultValue; 1478 } 1479 return val.trim(); 1480 } 1481 1482 // Package private method to get an integer property. 1483 // If the property is not defined or cannot be parsed 1484 // we return the given default value. getIntProperty(String name, int defaultValue)1485 int getIntProperty(String name, int defaultValue) { 1486 String val = getProperty(name); 1487 if (val == null) { 1488 return defaultValue; 1489 } 1490 try { 1491 return Integer.parseInt(val.trim()); 1492 } catch (Exception ex) { 1493 return defaultValue; 1494 } 1495 } 1496 1497 // Package private method to get a boolean property. 1498 // If the property is not defined or cannot be parsed 1499 // we return the given default value. getBooleanProperty(String name, boolean defaultValue)1500 boolean getBooleanProperty(String name, boolean defaultValue) { 1501 String val = getProperty(name); 1502 if (val == null) { 1503 return defaultValue; 1504 } 1505 val = val.toLowerCase(); 1506 if (val.equals("true") || val.equals("1")) { 1507 return true; 1508 } else if (val.equals("false") || val.equals("0")) { 1509 return false; 1510 } 1511 return defaultValue; 1512 } 1513 1514 // Package private method to get a Level property. 1515 // If the property is not defined or cannot be parsed 1516 // we return the given default value. getLevelProperty(String name, Level defaultValue)1517 Level getLevelProperty(String name, Level defaultValue) { 1518 String val = getProperty(name); 1519 if (val == null) { 1520 return defaultValue; 1521 } 1522 Level l = Level.findLevel(val.trim()); 1523 return l != null ? l : defaultValue; 1524 } 1525 1526 // Package private method to get a filter property. 1527 // We return an instance of the class named by the "name" 1528 // property. If the property is not defined or has problems 1529 // we return the defaultValue. getFilterProperty(String name, Filter defaultValue)1530 Filter getFilterProperty(String name, Filter defaultValue) { 1531 String val = getProperty(name); 1532 try { 1533 if (val != null) { 1534 return (Filter) getClassInstance(val).newInstance(); 1535 } 1536 } catch (Exception ex) { 1537 // We got one of a variety of exceptions in creating the 1538 // class or creating an instance. 1539 // Drop through. 1540 } 1541 // We got an exception. Return the defaultValue. 1542 return defaultValue; 1543 } 1544 1545 1546 // Package private method to get a formatter property. 1547 // We return an instance of the class named by the "name" 1548 // property. If the property is not defined or has problems 1549 // we return the defaultValue. getFormatterProperty(String name, Formatter defaultValue)1550 Formatter getFormatterProperty(String name, Formatter defaultValue) { 1551 String val = getProperty(name); 1552 try { 1553 if (val != null) { 1554 return (Formatter) getClassInstance(val).newInstance(); 1555 } 1556 } catch (Exception ex) { 1557 // We got one of a variety of exceptions in creating the 1558 // class or creating an instance. 1559 // Drop through. 1560 } 1561 // We got an exception. Return the defaultValue. 1562 return defaultValue; 1563 } 1564 1565 // Private method to load the global handlers. 1566 // We do the real work lazily, when the global handlers 1567 // are first used. initializeGlobalHandlers()1568 private synchronized void initializeGlobalHandlers() { 1569 if (initializedGlobalHandlers) { 1570 return; 1571 } 1572 1573 initializedGlobalHandlers = true; 1574 1575 if (deathImminent) { 1576 // Aaargh... 1577 // The VM is shutting down and our exit hook has been called. 1578 // Avoid allocating global handlers. 1579 return; 1580 } 1581 loadLoggerHandlers(rootLogger, null, "handlers"); 1582 } 1583 1584 private final Permission controlPermission = new LoggingPermission("control", null); 1585 checkPermission()1586 void checkPermission() { 1587 SecurityManager sm = System.getSecurityManager(); 1588 if (sm != null) 1589 sm.checkPermission(controlPermission); 1590 } 1591 1592 /** 1593 * Check that the current context is trusted to modify the logging 1594 * configuration. This requires LoggingPermission("control"). 1595 * <p> 1596 * If the check fails we throw a SecurityException, otherwise 1597 * we return normally. 1598 * 1599 * @exception SecurityException if a security manager exists and if 1600 * the caller does not have LoggingPermission("control"). 1601 */ checkAccess()1602 public void checkAccess() throws SecurityException { 1603 checkPermission(); 1604 } 1605 1606 // Nested class to represent a node in our tree of named loggers. 1607 private static class LogNode { 1608 HashMap<String,LogNode> children; 1609 LoggerWeakRef loggerRef; 1610 LogNode parent; 1611 final LoggerContext context; 1612 LogNode(LogNode parent, LoggerContext context)1613 LogNode(LogNode parent, LoggerContext context) { 1614 this.parent = parent; 1615 this.context = context; 1616 } 1617 1618 // Recursive method to walk the tree below a node and set 1619 // a new parent logger. walkAndSetParent(Logger parent)1620 void walkAndSetParent(Logger parent) { 1621 if (children == null) { 1622 return; 1623 } 1624 Iterator<LogNode> values = children.values().iterator(); 1625 while (values.hasNext()) { 1626 LogNode node = values.next(); 1627 LoggerWeakRef ref = node.loggerRef; 1628 Logger logger = (ref == null) ? null : ref.get(); 1629 if (logger == null) { 1630 node.walkAndSetParent(parent); 1631 } else { 1632 doSetParent(logger, parent); 1633 } 1634 } 1635 } 1636 } 1637 1638 // We use a subclass of Logger for the root logger, so 1639 // that we only instantiate the global handlers when they 1640 // are first needed. 1641 private final class RootLogger extends Logger { RootLogger()1642 private RootLogger() { 1643 // We do not call the protected Logger two args constructor here, 1644 // to avoid calling LogManager.getLogManager() from within the 1645 // RootLogger constructor. 1646 super("", null, null, LogManager.this, true); 1647 } 1648 1649 @Override log(LogRecord record)1650 public void log(LogRecord record) { 1651 // Make sure that the global handlers have been instantiated. 1652 initializeGlobalHandlers(); 1653 super.log(record); 1654 } 1655 1656 @Override addHandler(Handler h)1657 public void addHandler(Handler h) { 1658 initializeGlobalHandlers(); 1659 super.addHandler(h); 1660 } 1661 1662 @Override removeHandler(Handler h)1663 public void removeHandler(Handler h) { 1664 initializeGlobalHandlers(); 1665 super.removeHandler(h); 1666 } 1667 1668 @Override accessCheckedHandlers()1669 Handler[] accessCheckedHandlers() { 1670 initializeGlobalHandlers(); 1671 return super.accessCheckedHandlers(); 1672 } 1673 } 1674 1675 1676 // Private method to be called when the configuration has 1677 // changed to apply any level settings to any pre-existing loggers. setLevelsOnExistingLoggers()1678 synchronized private void setLevelsOnExistingLoggers() { 1679 Enumeration<?> enum_ = props.propertyNames(); 1680 while (enum_.hasMoreElements()) { 1681 String key = (String)enum_.nextElement(); 1682 if (!key.endsWith(".level")) { 1683 // Not a level definition. 1684 continue; 1685 } 1686 int ix = key.length() - 6; 1687 String name = key.substring(0, ix); 1688 Level level = getLevelProperty(key, null); 1689 if (level == null) { 1690 System.err.println("Bad level value for property: " + key); 1691 continue; 1692 } 1693 for (LoggerContext cx : contexts()) { 1694 Logger l = cx.findLogger(name); 1695 if (l == null) { 1696 continue; 1697 } 1698 l.setLevel(level); 1699 } 1700 } 1701 } 1702 1703 // Management Support 1704 private static LoggingMXBean loggingMXBean = null; 1705 /** 1706 * String representation of the {@code ObjectName} for the management interface 1707 * for the logging facility. 1708 * 1709 * @see java.util.logging.LoggingMXBean 1710 * 1711 * @since 1.5 1712 */ 1713 // Android-changed: Remove reference to java.lang.management.ObjectName. 1714 // 1715 //@see java.lang.management.PlatformLoggingMXBean 1716 public final static String LOGGING_MXBEAN_NAME 1717 = "java.util.logging:type=Logging"; 1718 1719 /** 1720 * Returns <tt>LoggingMXBean</tt> for managing loggers. 1721 * 1722 * @return a {@link LoggingMXBean} object. 1723 * 1724 * @since 1.5 1725 */ 1726 // Android-removed docs areferring to java.lang.management. 1727 // 1728 // An alternative way to manage loggers is through the 1729 // {@link java.lang.management.PlatformLoggingMXBean} interface 1730 // that can be obtained by calling: 1731 // <pre> 1732 // PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class) 1733 // ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class); 1734 // </pre> 1735 // 1736 // @see java.lang.management.PlatformLoggingMXBean getLoggingMXBean()1737 public static synchronized LoggingMXBean getLoggingMXBean() { 1738 if (loggingMXBean == null) { 1739 loggingMXBean = new Logging(); 1740 } 1741 return loggingMXBean; 1742 } 1743 1744 /** 1745 * A class that provides access to the java.beans.PropertyChangeListener 1746 * and java.beans.PropertyChangeEvent without creating a static dependency 1747 * on java.beans. This class can be removed once the addPropertyChangeListener 1748 * and removePropertyChangeListener methods are removed. 1749 */ 1750 private static class Beans { 1751 private static final Class<?> propertyChangeListenerClass = 1752 getClass("java.beans.PropertyChangeListener"); 1753 1754 private static final Class<?> propertyChangeEventClass = 1755 getClass("java.beans.PropertyChangeEvent"); 1756 1757 private static final Method propertyChangeMethod = 1758 getMethod(propertyChangeListenerClass, 1759 "propertyChange", 1760 propertyChangeEventClass); 1761 1762 private static final Constructor<?> propertyEventCtor = 1763 getConstructor(propertyChangeEventClass, 1764 Object.class, 1765 String.class, 1766 Object.class, 1767 Object.class); 1768 getClass(String name)1769 private static Class<?> getClass(String name) { 1770 try { 1771 return Class.forName(name, true, Beans.class.getClassLoader()); 1772 } catch (ClassNotFoundException e) { 1773 return null; 1774 } 1775 } getConstructor(Class<?> c, Class<?>... types)1776 private static Constructor<?> getConstructor(Class<?> c, Class<?>... types) { 1777 try { 1778 return (c == null) ? null : c.getDeclaredConstructor(types); 1779 } catch (NoSuchMethodException x) { 1780 throw new AssertionError(x); 1781 } 1782 } 1783 getMethod(Class<?> c, String name, Class<?>... types)1784 private static Method getMethod(Class<?> c, String name, Class<?>... types) { 1785 try { 1786 return (c == null) ? null : c.getMethod(name, types); 1787 } catch (NoSuchMethodException e) { 1788 throw new AssertionError(e); 1789 } 1790 } 1791 1792 /** 1793 * Returns {@code true} if java.beans is present. 1794 */ isBeansPresent()1795 static boolean isBeansPresent() { 1796 return propertyChangeListenerClass != null && 1797 propertyChangeEventClass != null; 1798 } 1799 1800 /** 1801 * Returns a new PropertyChangeEvent with the given source, property 1802 * name, old and new values. 1803 */ newPropertyChangeEvent(Object source, String prop, Object oldValue, Object newValue)1804 static Object newPropertyChangeEvent(Object source, String prop, 1805 Object oldValue, Object newValue) 1806 { 1807 try { 1808 return propertyEventCtor.newInstance(source, prop, oldValue, newValue); 1809 } catch (InstantiationException | IllegalAccessException x) { 1810 throw new AssertionError(x); 1811 } catch (InvocationTargetException x) { 1812 Throwable cause = x.getCause(); 1813 if (cause instanceof Error) 1814 throw (Error)cause; 1815 if (cause instanceof RuntimeException) 1816 throw (RuntimeException)cause; 1817 throw new AssertionError(x); 1818 } 1819 } 1820 1821 /** 1822 * Invokes the given PropertyChangeListener's propertyChange method 1823 * with the given event. 1824 */ invokePropertyChange(Object listener, Object ev)1825 static void invokePropertyChange(Object listener, Object ev) { 1826 try { 1827 propertyChangeMethod.invoke(listener, ev); 1828 } catch (IllegalAccessException x) { 1829 throw new AssertionError(x); 1830 } catch (InvocationTargetException x) { 1831 Throwable cause = x.getCause(); 1832 if (cause instanceof Error) 1833 throw (Error)cause; 1834 if (cause instanceof RuntimeException) 1835 throw (RuntimeException)cause; 1836 throw new AssertionError(x); 1837 } 1838 } 1839 } 1840 } 1841