Home | History | Annotate | Download | only in logging
      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 "&lt;logger&gt;.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 "&lt;logger&gt;.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 
    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
    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      */
    241     protected LogManager() {
    242         this(checkSubclassPermissions());
    243     }
    244 
    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 
    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;
    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      */
    367     public static LogManager getLogManager() {
    368         if (manager != null) {
    369             manager.ensureLogManagerInitialized();
    370         }
    371         return manager;
    372     }
    373 
    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
    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
    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.
    489     private LoggerContext getUserContext() {
    490         // Android-changed: No AWT specific hooks.
    491         return userContext;
    492     }
    493 
    494     // The system context.
    495     final LoggerContext getSystemContext() {
    496         return systemContext;
    497     }
    498 
    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.
    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 
    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 
    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;
    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.
    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.
    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.
    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.
    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 
    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         //
    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 
    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         //
    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 
    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 
    741         boolean addLocalLogger(Logger logger) {
    742             // no need to add default loggers if it's not required
    743             return addLocalLogger(logger, requiresDefaultLoggers());
    744         }
    745 
    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 
    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.
    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 
    834         synchronized void removeLoggerRef(String name, LoggerWeakRef ref) {
    835             namedLoggers.remove(name, ref);
    836         }
    837 
    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.
    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.
    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
    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.
    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 
   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
   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
   1082         void setNode(LogNode node) {
   1083             this.node = node;
   1084         }
   1085 
   1086         // set the parentRef field to the specified value
   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;
   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      */
   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.
   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.
   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      */
   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      */
   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      */
   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 
   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.
   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.
   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      */
   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      */
   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.
   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.
   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.
   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.
   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.
   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.
   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.
   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 
   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      */
   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 
   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.
   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 {
   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
   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
   1657         public void addHandler(Handler h) {
   1658             initializeGlobalHandlers();
   1659             super.addHandler(h);
   1660         }
   1661 
   1662         @Override
   1663         public void removeHandler(Handler h) {
   1664             initializeGlobalHandlers();
   1665             super.removeHandler(h);
   1666         }
   1667 
   1668         @Override
   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.
   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
   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 
   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         }
   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 
   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          */
   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          */
   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          */
   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