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