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