• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
36 import java.beans.PropertyChangeListener;
37 import java.beans.PropertyChangeSupport;
38 
39 /**
40  * There is a single global LogManager object that is used to
41  * maintain a set of shared state about Loggers and log services.
42  * <p>
43  * This LogManager object:
44  * <ul>
45  * <li> Manages a hierarchical namespace of Logger objects.  All
46  *      named Loggers are stored in this namespace.
47  * <li> Manages a set of logging control properties.  These are
48  *      simple key-value pairs that can be used by Handlers and
49  *      other logging objects to configure themselves.
50  * </ul>
51  * <p>
52  * The global LogManager object can be retrieved using LogManager.getLogManager().
53  * The LogManager object is created during class initialization and
54  * cannot subsequently be changed.
55  * <p>
56  * At startup the LogManager class is located using the
57  * java.util.logging.manager system property.
58  * <p>
59  * By default, the LogManager reads its initial configuration from
60  * a properties file "lib/logging.properties" in the JRE directory.
61  * If you edit that property file you can change the default logging
62  * configuration for all uses of that JRE.
63  * <p>
64  * In addition, the LogManager uses two optional system properties that
65  * allow more control over reading the initial configuration:
66  * <ul>
67  * <li>"java.util.logging.config.class"
68  * <li>"java.util.logging.config.file"
69  * </ul>
70  * These two properties may be set via the Preferences API, or as
71  * command line property definitions to the "java" command, or as
72  * system property definitions passed to JNI_CreateJavaVM.
73  * <p>
74  * If the "java.util.logging.config.class" property is set, then the
75  * property value is treated as a class name.  The given class will be
76  * loaded, an object will be instantiated, and that object's constructor
77  * is responsible for reading in the initial configuration.  (That object
78  * may use other system properties to control its configuration.)  The
79  * alternate configuration class can use <tt>readConfiguration(InputStream)</tt>
80  * to define properties in the LogManager.
81  * <p>
82  * If "java.util.logging.config.class" property is <b>not</b> set,
83  * then the "java.util.logging.config.file" system property can be used
84  * to specify a properties file (in java.util.Properties format). The
85  * initial logging configuration will be read from this file.
86  * <p>
87  * If neither of these properties is defined then, as described
88  * above, the LogManager will read its initial configuration from
89  * a properties file "lib/logging.properties" in the JRE directory.
90  * <p>
91  * The properties for loggers and Handlers will have names starting
92  * with the dot-separated name for the handler or logger.
93  * <p>
94  * The global logging properties may include:
95  * <ul>
96  * <li>A property "handlers".  This defines a whitespace or comma separated
97  * list of class names for handler classes to load and register as
98  * handlers on the root Logger (the Logger named "").  Each class
99  * name must be for a Handler class which has a default constructor.
100  * Note that these Handlers may be created lazily, when they are
101  * first used.
102  *
103  * <li>A property "&lt;logger&gt;.handlers". This defines a whitespace or
104  * comma separated list of class names for handlers classes to
105  * load and register as handlers to the specified logger. Each class
106  * name must be for a Handler class which has a default constructor.
107  * Note that these Handlers may be created lazily, when they are
108  * first used.
109  *
110  * <li>A property "&lt;logger&gt;.useParentHandlers". This defines a boolean
111  * value. By default every logger calls its parent in addition to
112  * handling the logging message itself, this often result in messages
113  * being handled by the root logger as well. When setting this property
114  * to false a Handler needs to be configured for this logger otherwise
115  * no logging messages are delivered.
116  *
117  * <li>A property "config".  This property is intended to allow
118  * arbitrary configuration code to be run.  The property defines a
119  * whitespace or comma separated list of class names.  A new instance will be
120  * created for each named class.  The default constructor of each class
121  * may execute arbitrary code to update the logging configuration, such as
122  * setting logger levels, adding handlers, adding filters, etc.
123  * </ul>
124  * <p>
125  * Note that all classes loaded during LogManager configuration are
126  * first searched on the system class path before any user class path.
127  * That includes the LogManager class, any config classes, and any
128  * handler classes.
129  * <p>
130  * Loggers are organized into a naming hierarchy based on their
131  * dot separated names.  Thus "a.b.c" is a child of "a.b", but
132  * "a.b1" and a.b2" are peers.
133  * <p>
134  * All properties whose names end with ".level" are assumed to define
135  * log levels for Loggers.  Thus "foo.level" defines a log level for
136  * the logger called "foo" and (recursively) for any of its children
137  * in the naming hierarchy.  Log Levels are applied in the order they
138  * are defined in the properties file.  Thus level settings for child
139  * nodes in the tree should come after settings for their parents.
140  * The property name ".level" can be used to set the level for the
141  * root of the tree.
142  * <p>
143  * All methods on the LogManager object are multi-thread safe.
144  *
145  * @since 1.4
146 */
147 
148 public class LogManager {
149     // The global LogManager object
150     private static LogManager manager;
151 
152     private Properties props = new Properties();
153     private PropertyChangeSupport changes
154                          = new PropertyChangeSupport(LogManager.class);
155     private final static Level defaultLevel = Level.INFO;
156 
157     // LoggerContext for system loggers and user loggers
158     private final LoggerContext systemContext = new SystemLoggerContext();
159     private final LoggerContext userContext = new LoggerContext();
160     private Logger rootLogger;
161 
162     // Have we done the primordial reading of the configuration file?
163     // (Must be done after a suitable amount of java.lang.System
164     // initialization has been done)
165     private volatile boolean readPrimordialConfiguration;
166     // Have we initialized global (root) handlers yet?
167     // This gets set to false in readConfiguration
168     private boolean initializedGlobalHandlers = true;
169     // True if JVM death is imminent and the exit hook has been called.
170     private boolean deathImminent;
171 
172     static {
AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { String cname = null; try { cname = System.getProperty("java.util.logging.manager"); if (cname != null) { manager = (LogManager) getClassInstance(cname).newInstance(); } } catch (Exception ex) { System.err.println("Could not load Logmanager \\"" + cname + "\\""); ex.printStackTrace(); } if (manager == null) { manager = new LogManager(); } manager.rootLogger = manager.new RootLogger(); manager.addLogger(manager.rootLogger); manager.systemContext.addLocalLogger(manager.rootLogger, false); manager.userContext.addLocalLogger(manager.rootLogger, false); Logger.global.setLogManager(manager); manager.addLogger(Logger.global); manager.systemContext.addLocalLogger(Logger.global, false); manager.userContext.addLocalLogger(Logger.global, false); return null; } })173         AccessController.doPrivileged(new PrivilegedAction<Object>() {
174                 public Object run() {
175                     String cname = null;
176                     try {
177                         cname = System.getProperty("java.util.logging.manager");
178                         if (cname != null) {
179                                 manager = (LogManager) getClassInstance(cname).newInstance();
180                         }
181                     } catch (Exception ex) {
182                         System.err.println("Could not load Logmanager \"" + cname + "\"");
183                         ex.printStackTrace();
184                     }
185                     if (manager == null) {
186                         manager = new LogManager();
187                     }
188 
189                     // Create and retain Logger for the root of the namespace.
190                     manager.rootLogger = manager.new RootLogger();
191                     // since by design the global manager's userContext and
192                     // systemContext don't have their requiresDefaultLoggers
193                     // flag set - we make sure to add the root logger to
194                     // the global manager's default contexts here.
195                     manager.addLogger(manager.rootLogger);
196                     manager.systemContext.addLocalLogger(manager.rootLogger, false);
197                     manager.userContext.addLocalLogger(manager.rootLogger, false);
198 
199                     // Adding the global Logger. Doing so in the Logger.<clinit>
200                     // would deadlock with the LogManager.<clinit>.
201                     Logger.global.setLogManager(manager);
202                     // Make sure the global logger will be registered in the
203                     // global manager's default contexts.
204                     manager.addLogger(Logger.global);
205                     manager.systemContext.addLocalLogger(Logger.global, false);
206                     manager.userContext.addLocalLogger(Logger.global, false);
207 
208                     // We don't call readConfiguration() here, as we may be running
209                     // very early in the JVM startup sequence.  Instead readConfiguration
210                     // will be called lazily in getLogManager().
211                     return null;
212                 }
213             });
214     }
215 
216 
217     // This private class is used as a shutdown hook.
218     // It does a "reset" to close all open handlers.
219     private class Cleaner extends Thread {
220 
Cleaner()221         private Cleaner() {
222             /* Set context class loader to null in order to avoid
223              * keeping a strong reference to an application classloader.
224              */
225             this.setContextClassLoader(null);
226         }
227 
run()228         public void run() {
229             // This is to ensure the LogManager.<clinit> is completed
230             // before synchronized block. Otherwise deadlocks are possible.
231             LogManager mgr = manager;
232 
233             // If the global handlers haven't been initialized yet, we
234             // don't want to initialize them just so we can close them!
235             synchronized (LogManager.this) {
236                 // Note that death is imminent.
237                 deathImminent = true;
238                 initializedGlobalHandlers = true;
239             }
240 
241             // Do a reset to close all active handlers.
242             reset();
243         }
244     }
245 
246 
247     /**
248      * Protected constructor.  This is protected so that container applications
249      * (such as J2EE containers) can subclass the object.  It is non-public as
250      * it is intended that there only be one LogManager object, whose value is
251      * retrieved by calling Logmanager.getLogManager.
252      */
LogManager()253     protected LogManager() {
254         // Add a shutdown hook to close the global handlers.
255         try {
256             Runtime.getRuntime().addShutdownHook(new Cleaner());
257         } catch (IllegalStateException e) {
258             // If the VM is already shutting down,
259             // We do not need to register shutdownHook.
260         }
261     }
262 
263     /**
264      * Return the global LogManager object.
265      */
getLogManager()266     public static LogManager getLogManager() {
267         if (manager != null) {
268             manager.readPrimordialConfiguration();
269         }
270         return manager;
271     }
272 
readPrimordialConfiguration()273     private void readPrimordialConfiguration() {
274         if (!readPrimordialConfiguration) {
275             synchronized (this) {
276                 if (!readPrimordialConfiguration) {
277                     // If System.in/out/err are null, it's a good
278                     // indication that we're still in the
279                     // bootstrapping phase
280                     if (System.out == null) {
281                         return;
282                     }
283                     readPrimordialConfiguration = true;
284 
285                     try {
286                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
287                                 public Void run() throws Exception {
288                                     readConfiguration();
289 
290                                     // Platform loggers begin to delegate to java.util.logging.Logger
291                                     sun.util.logging.PlatformLogger.redirectPlatformLoggers();
292                                     return null;
293                                 }
294                             });
295                     } catch (Exception ex) {
296                         // System.err.println("Can't read logging configuration:");
297                         // ex.printStackTrace();
298                     }
299                 }
300             }
301         }
302     }
303 
304     /**
305      * Adds an event listener to be invoked when the logging
306      * properties are re-read. Adding multiple instances of
307      * the same event Listener results in multiple entries
308      * in the property event listener table.
309      *
310      * @param l  event listener
311      * @exception  SecurityException  if a security manager exists and if
312      *             the caller does not have LoggingPermission("control").
313      * @exception NullPointerException if the PropertyChangeListener is null.
314      */
addPropertyChangeListener(PropertyChangeListener l)315     public void addPropertyChangeListener(PropertyChangeListener l) throws SecurityException {
316         if (l == null) {
317             throw new NullPointerException();
318         }
319         checkPermission();
320         changes.addPropertyChangeListener(l);
321     }
322 
323     /**
324      * Removes an event listener for property change events.
325      * If the same listener instance has been added to the listener table
326      * through multiple invocations of <CODE>addPropertyChangeListener</CODE>,
327      * then an equivalent number of
328      * <CODE>removePropertyChangeListener</CODE> invocations are required to remove
329      * all instances of that listener from the listener table.
330      * <P>
331      * Returns silently if the given listener is not found.
332      *
333      * @param l  event listener (can be null)
334      * @exception  SecurityException  if a security manager exists and if
335      *             the caller does not have LoggingPermission("control").
336      */
removePropertyChangeListener(PropertyChangeListener l)337     public void removePropertyChangeListener(PropertyChangeListener l) throws SecurityException {
338         checkPermission();
339         changes.removePropertyChangeListener(l);
340     }
341 
342     // Returns the LoggerContext for the user code (i.e. application or AppContext).
343     // Loggers are isolated from each AppContext.
getUserContext()344     private LoggerContext getUserContext() {
345         // Android-changed: No AWT specific hooks.
346         return userContext;
347     }
348 
contexts()349     private List<LoggerContext> contexts() {
350         List<LoggerContext> cxs = new ArrayList<>();
351         cxs.add(systemContext);
352         cxs.add(getUserContext());
353         return cxs;
354     }
355 
356     // Find or create a specified logger instance. If a logger has
357     // already been created with the given name it is returned.
358     // Otherwise a new logger instance is created and registered
359     // in the LogManager global namespace.
360     // This method will always return a non-null Logger object.
361     // Synchronization is not required here. All synchronization for
362     // adding a new Logger object is handled by addLogger().
363     //
364     // This method must delegate to the LogManager implementation to
365     // add a new Logger or return the one that has been added previously
366     // as a LogManager subclass may override the addLogger, getLogger,
367     // readConfiguration, and other methods.
demandLogger(String name, String resourceBundleName, Class<?> caller)368     Logger demandLogger(String name, String resourceBundleName, Class<?> caller) {
369         Logger result = getLogger(name);
370         if (result == null) {
371             // only allocate the new logger once
372             Logger newLogger = new Logger(name, resourceBundleName, caller);
373             do {
374                 if (addLogger(newLogger)) {
375                     // We successfully added the new Logger that we
376                     // created above so return it without refetching.
377                     return newLogger;
378                 }
379 
380                 // We didn't add the new Logger that we created above
381                 // because another thread added a Logger with the same
382                 // name after our null check above and before our call
383                 // to addLogger(). We have to refetch the Logger because
384                 // addLogger() returns a boolean instead of the Logger
385                 // reference itself. However, if the thread that created
386                 // the other Logger is not holding a strong reference to
387                 // the other Logger, then it is possible for the other
388                 // Logger to be GC'ed after we saw it in addLogger() and
389                 // before we can refetch it. If it has been GC'ed then
390                 // we'll just loop around and try again.
391                 result = getLogger(name);
392             } while (result == null);
393         }
394         return result;
395     }
396 
demandSystemLogger(String name, String resourceBundleName)397     Logger demandSystemLogger(String name, String resourceBundleName) {
398         // Add a system logger in the system context's namespace
399         final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName);
400 
401         // Add the system logger to the LogManager's namespace if not exist
402         // so that there is only one single logger of the given name.
403         // System loggers are visible to applications unless a logger of
404         // the same name has been added.
405         Logger logger;
406         do {
407             // First attempt to call addLogger instead of getLogger
408             // This would avoid potential bug in custom LogManager.getLogger
409             // implementation that adds a logger if does not exist
410             if (addLogger(sysLogger)) {
411                 // successfully added the new system logger
412                 logger = sysLogger;
413             } else {
414                 logger = getLogger(name);
415             }
416         } while (logger == null);
417 
418         // LogManager will set the sysLogger's handlers via LogManager.addLogger method.
419         if (logger != sysLogger && sysLogger.getHandlers().length == 0) {
420             // if logger already exists but handlers not set
421             final Logger l = logger;
422             AccessController.doPrivileged(new PrivilegedAction<Void>() {
423                 public Void run() {
424                     for (Handler hdl : l.getHandlers()) {
425                         sysLogger.addHandler(hdl);
426                     }
427                     return null;
428                 }
429             });
430         }
431         return sysLogger;
432     }
433 
getClassInstance(String cname)434     private static Class getClassInstance(String cname) {
435         Class clz = null;
436         if (cname != null) {
437             try {
438                 clz = ClassLoader.getSystemClassLoader().loadClass(cname);
439             } catch (ClassNotFoundException ex) {
440                 try {
441                     clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
442                 } catch (ClassNotFoundException innerEx) {
443                     clz = null;
444                 }
445             }
446         }
447         return clz;
448     }
449 
450     // LoggerContext maintains the logger namespace per context.
451     // The default LogManager implementation has one system context and user
452     // context.  The system context is used to maintain the namespace for
453     // all system loggers and is queried by the system code.  If a system logger
454     // doesn't exist in the user context, it'll also be added to the user context.
455     // The user context is queried by the user code and all other loggers are
456     // added in the user context.
457     static class LoggerContext {
458         // Table of named Loggers that maps names to Loggers.
459         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
460         // Tree of named Loggers
461         private final LogNode root;
462         private final boolean requiresDefaultLoggers;
LoggerContext()463         private LoggerContext() {
464             this(false);
465         }
LoggerContext(boolean requiresDefaultLoggers)466         private LoggerContext(boolean requiresDefaultLoggers) {
467             this.root = new LogNode(null, this);
468             this.requiresDefaultLoggers = requiresDefaultLoggers;
469         }
470 
demandLogger(String name, String resourceBundleName)471         Logger demandLogger(String name, String resourceBundleName) {
472             // a LogManager subclass may have its own implementation to add and
473             // get a Logger.  So delegate to the LogManager to do the work.
474             return manager.demandLogger(name, resourceBundleName, null);
475         }
476 
477 
478         // Due to subtle deadlock issues getUserContext() no longer
479         // calls addLocalLogger(rootLogger);
480         // Therefore - we need to add the default loggers later on.
481         // Checks that the context is properly initialized
482         // This is necessary before calling e.g. find(name)
483         // or getLoggerNames()
484         //
ensureInitialized()485         private void ensureInitialized() {
486             if (requiresDefaultLoggers) {
487                 // Ensure that the root and global loggers are set.
488                 ensureDefaultLogger(manager.rootLogger);
489                 ensureDefaultLogger(Logger.global);
490             }
491         }
492 
493 
findLogger(String name)494         synchronized Logger findLogger(String name) {
495             // ensure that this context is properly initialized before
496             // looking for loggers.
497             ensureInitialized();
498             LoggerWeakRef ref = namedLoggers.get(name);
499             if (ref == null) {
500                 return null;
501             }
502             Logger logger = ref.get();
503             if (logger == null) {
504                 // Hashtable holds stale weak reference
505                 // to a logger which has been GC-ed.
506                 removeLogger(name);
507             }
508             return logger;
509         }
510 
511         // This method is called before adding a logger to the
512         // context.
513         // 'logger' is the context that will be added.
514         // This method will ensure that the defaults loggers are added
515         // before adding 'logger'.
516         //
ensureAllDefaultLoggers(Logger logger)517         private void ensureAllDefaultLoggers(Logger logger) {
518             if (requiresDefaultLoggers) {
519                 final String name = logger.getName();
520                 if (!name.isEmpty()) {
521                     ensureDefaultLogger(manager.rootLogger);
522                 }
523                 if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
524                     ensureDefaultLogger(Logger.global);
525                 }
526             }
527         }
528 
ensureDefaultLogger(Logger logger)529         private void ensureDefaultLogger(Logger logger) {
530             // Used for lazy addition of root logger and global logger
531             // to a LoggerContext.
532 
533             // This check is simple sanity: we do not want that this
534             // method be called for anything else than Logger.global
535             // or owner.rootLogger.
536             if (!requiresDefaultLoggers || logger == null
537                     || logger != Logger.global && logger != manager.rootLogger) {
538 
539                 // the case where we have a non null logger which is neither
540                 // Logger.global nor manager.rootLogger indicates a serious
541                 // issue - as ensureDefaultLogger should never be called
542                 // with any other loggers than one of these two (or null - if
543                 // e.g manager.rootLogger is not yet initialized)...
544                 assert logger == null;
545 
546                 return;
547             }
548 
549             // Adds the logger if it's not already there.
550             if (!namedLoggers.containsKey(logger.getName())) {
551                 // It is important to prevent addLocalLogger to
552                 // call ensureAllDefaultLoggers when we're in the process
553                 // off adding one of those default loggers - as this would
554                 // immediately cause a stack overflow.
555                 // Therefore we must pass addDefaultLoggersIfNeeded=false,
556                 // even if requiresDefaultLoggers is true.
557                 addLocalLogger(logger, false);
558             }
559         }
560 
addLocalLogger(Logger logger)561         boolean addLocalLogger(Logger logger) {
562             // no need to add default loggers if it's not required
563             return addLocalLogger(logger, requiresDefaultLoggers);
564         }
565 
addLocalLogger(Logger logger, LogManager manager)566         boolean addLocalLogger(Logger logger, LogManager manager) {
567             // no need to add default loggers if it's not required
568             return addLocalLogger(logger, requiresDefaultLoggers, manager);
569         }
570 
addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded)571         boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded) {
572             return addLocalLogger(logger, addDefaultLoggersIfNeeded, manager);
573         }
574 
575         // Add a logger to this context.  This method will only set its level
576         // and process parent loggers.  It doesn't set its handlers.
addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded, LogManager manager)577         synchronized boolean addLocalLogger(Logger logger, boolean addDefaultLoggersIfNeeded,
578                                             LogManager manager) {
579             // addDefaultLoggersIfNeeded serves to break recursion when adding
580             // default loggers. If we're adding one of the default loggers
581             // (we're being called from ensureDefaultLogger()) then
582             // addDefaultLoggersIfNeeded will be false: we don't want to
583             // call ensureAllDefaultLoggers again.
584             //
585             // Note: addDefaultLoggersIfNeeded can also be false when
586             //       requiresDefaultLoggers is false - since calling
587             //       ensureAllDefaultLoggers would have no effect in this case.
588             if (addDefaultLoggersIfNeeded) {
589                 ensureAllDefaultLoggers(logger);
590             }
591 
592             final String name = logger.getName();
593             if (name == null) {
594                 throw new NullPointerException();
595             }
596 
597             LoggerWeakRef ref = namedLoggers.get(name);
598             if (ref != null) {
599                 if (ref.get() == null) {
600                     // It's possible that the Logger was GC'ed after a
601                     // drainLoggerRefQueueBounded() call so allow
602                     // a new one to be registered.
603                     removeLogger(name);
604                 } else {
605                     // We already have a registered logger with the given name.
606                     return false;
607                 }
608             }
609 
610             // We're adding a new logger.
611             // Note that we are creating a weak reference here.
612             ref = manager.new LoggerWeakRef(logger);
613             namedLoggers.put(name, ref);
614 
615             // Apply any initial level defined for the new logger.
616             Level level = manager.getLevelProperty(name + ".level", null);
617             if (level != null) {
618                 doSetLevel(logger, level);
619             }
620 
621             processParentHandlers(logger, name);
622 
623             // Find the new node and its parent.
624             LogNode node = getNode(name);
625             node.loggerRef = ref;
626             Logger parent = null;
627             LogNode nodep = node.parent;
628             while (nodep != null) {
629                 LoggerWeakRef nodeRef = nodep.loggerRef;
630                 if (nodeRef != null) {
631                     parent = nodeRef.get();
632                     if (parent != null) {
633                         break;
634                     }
635                 }
636                 nodep = nodep.parent;
637             }
638 
639             if (parent != null) {
640                 doSetParent(logger, parent);
641             }
642             // Walk over the children and tell them we are their new parent.
643             node.walkAndSetParent(logger);
644             // new LogNode is ready so tell the LoggerWeakRef about it
645             ref.setNode(node);
646             return true;
647         }
648 
649         // note: all calls to removeLogger are synchronized on LogManager's
650         // intrinsic lock
removeLogger(String name)651         void removeLogger(String name) {
652             namedLoggers.remove(name);
653         }
654 
getLoggerNames()655         synchronized Enumeration<String> getLoggerNames() {
656             // ensure that this context is properly initialized before
657             // returning logger names.
658             ensureInitialized();
659             return namedLoggers.keys();
660         }
661 
662         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
663         // parents have levels or handlers defined, make sure they are instantiated.
processParentHandlers(final Logger logger, final String name)664         private void processParentHandlers(final Logger logger, final String name) {
665             AccessController.doPrivileged(new PrivilegedAction<Void>() {
666                 public Void run() {
667                     if (logger != manager.rootLogger) {
668                         boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
669                         if (!useParent) {
670                             logger.setUseParentHandlers(false);
671                         }
672                     }
673                     return null;
674                 }
675             });
676 
677             int ix = 1;
678             for (;;) {
679                 int ix2 = name.indexOf(".", ix);
680                 if (ix2 < 0) {
681                     break;
682                 }
683                 String pname = name.substring(0, ix2);
684                 if (manager.getProperty(pname + ".level") != null ||
685                     manager.getProperty(pname + ".handlers") != null) {
686                     // This pname has a level/handlers definition.
687                     // Make sure it exists.
688                     demandLogger(pname, null);
689                 }
690                 ix = ix2+1;
691             }
692         }
693 
694         // Gets a node in our tree of logger nodes.
695         // If necessary, create it.
getNode(String name)696         LogNode getNode(String name) {
697             if (name == null || name.equals("")) {
698                 return root;
699             }
700             LogNode node = root;
701             while (name.length() > 0) {
702                 int ix = name.indexOf(".");
703                 String head;
704                 if (ix > 0) {
705                     head = name.substring(0, ix);
706                     name = name.substring(ix + 1);
707                 } else {
708                     head = name;
709                     name = "";
710                 }
711                 if (node.children == null) {
712                     node.children = new HashMap<>();
713                 }
714                 LogNode child = node.children.get(head);
715                 if (child == null) {
716                     child = new LogNode(node, this);
717                     node.children.put(head, child);
718                 }
719                 node = child;
720             }
721             return node;
722         }
723     }
724 
725     static class SystemLoggerContext extends LoggerContext {
726         // Add a system logger in the system context's namespace as well as
727         // in the LogManager's namespace if not exist so that there is only
728         // one single logger of the given name.  System loggers are visible
729         // to applications unless a logger of the same name has been added.
demandLogger(String name, String resourceBundleName)730         Logger demandLogger(String name, String resourceBundleName) {
731             Logger result = findLogger(name);
732             if (result == null) {
733                 // only allocate the new system logger once
734                 Logger newLogger = new Logger(name, resourceBundleName);
735                 do {
736                     if (addLocalLogger(newLogger)) {
737                         // We successfully added the new Logger that we
738                         // created above so return it without refetching.
739                         result = newLogger;
740                     } else {
741                         // We didn't add the new Logger that we created above
742                         // because another thread added a Logger with the same
743                         // name after our null check above and before our call
744                         // to addLogger(). We have to refetch the Logger because
745                         // addLogger() returns a boolean instead of the Logger
746                         // reference itself. However, if the thread that created
747                         // the other Logger is not holding a strong reference to
748                         // the other Logger, then it is possible for the other
749                         // Logger to be GC'ed after we saw it in addLogger() and
750                         // before we can refetch it. If it has been GC'ed then
751                         // we'll just loop around and try again.
752                         result = findLogger(name);
753                     }
754                 } while (result == null);
755             }
756             return result;
757         }
758     }
759 
760     // Add new per logger handlers.
761     // We need to raise privilege here. All our decisions will
762     // be made based on the logging configuration, which can
763     // only be modified by trusted code.
loadLoggerHandlers(final Logger logger, final String name, final String handlersPropertyName)764     private void loadLoggerHandlers(final Logger logger, final String name,
765                                     final String handlersPropertyName)
766     {
767         AccessController.doPrivileged(new PrivilegedAction<Object>() {
768             public Object run() {
769                 String names[] = parseClassNames(handlersPropertyName);
770                 for (int i = 0; i < names.length; i++) {
771                     String word = names[i];
772                     try {
773                         Class clz = getClassInstance(word);
774                         Handler hdl = (Handler) clz.newInstance();
775                         // Check if there is a property defining the
776                         // this handler's level.
777                         String levs = getProperty(word + ".level");
778                         if (levs != null) {
779                             Level l = Level.findLevel(levs);
780                             if (l != null) {
781                                 hdl.setLevel(l);
782                             } else {
783                                 // Probably a bad level. Drop through.
784                                 System.err.println("Can't set level for " + word);
785                             }
786                         }
787                         // Add this Handler to the logger
788                         logger.addHandler(hdl);
789                     } catch (Exception ex) {
790                         System.err.println("Can't load log handler \"" + word + "\"");
791                         System.err.println("" + ex);
792                         ex.printStackTrace();
793                     }
794                 }
795                 return null;
796             }
797         });
798     }
799 
800 
801     // loggerRefQueue holds LoggerWeakRef objects for Logger objects
802     // that have been GC'ed.
803     private final ReferenceQueue<Logger> loggerRefQueue
804         = new ReferenceQueue<>();
805 
806     // Package-level inner class.
807     // Helper class for managing WeakReferences to Logger objects.
808     //
809     // LogManager.namedLoggers
810     //     - has weak references to all named Loggers
811     //     - namedLoggers keeps the LoggerWeakRef objects for the named
812     //       Loggers around until we can deal with the book keeping for
813     //       the named Logger that is being GC'ed.
814     // LogManager.LogNode.loggerRef
815     //     - has a weak reference to a named Logger
816     //     - the LogNode will also keep the LoggerWeakRef objects for
817     //       the named Loggers around; currently LogNodes never go away.
818     // Logger.kids
819     //     - has a weak reference to each direct child Logger; this
820     //       includes anonymous and named Loggers
821     //     - anonymous Loggers are always children of the rootLogger
822     //       which is a strong reference; rootLogger.kids keeps the
823     //       LoggerWeakRef objects for the anonymous Loggers around
824     //       until we can deal with the book keeping.
825     //
826     final class LoggerWeakRef extends WeakReference<Logger> {
827         private String                name;       // for namedLoggers cleanup
828         private LogNode               node;       // for loggerRef cleanup
829         private WeakReference<Logger> parentRef;  // for kids cleanup
830 
LoggerWeakRef(Logger logger)831         LoggerWeakRef(Logger logger) {
832             super(logger, loggerRefQueue);
833 
834             name = logger.getName();  // save for namedLoggers cleanup
835         }
836 
837         // dispose of this LoggerWeakRef object
dispose()838         void dispose() {
839             if (node != null) {
840                 // if we have a LogNode, then we were a named Logger
841                 // so clear namedLoggers weak ref to us
842                 node.context.removeLogger(name);
843                 name = null;  // clear our ref to the Logger's name
844 
845                 node.loggerRef = null;  // clear LogNode's weak ref to us
846                 node = null;            // clear our ref to LogNode
847             }
848 
849             if (parentRef != null) {
850                 // this LoggerWeakRef has or had a parent Logger
851                 Logger parent = parentRef.get();
852                 if (parent != null) {
853                     // the parent Logger is still there so clear the
854                     // parent Logger's weak ref to us
855                     parent.removeChildLogger(this);
856                 }
857                 parentRef = null;  // clear our weak ref to the parent Logger
858             }
859         }
860 
861         // set the node field to the specified value
setNode(LogNode node)862         void setNode(LogNode node) {
863             this.node = node;
864         }
865 
866         // set the parentRef field to the specified value
setParentRef(WeakReference<Logger> parentRef)867         void setParentRef(WeakReference<Logger> parentRef) {
868             this.parentRef = parentRef;
869         }
870     }
871 
872     // Package-level method.
873     // Drain some Logger objects that have been GC'ed.
874     //
875     // drainLoggerRefQueueBounded() is called by addLogger() below
876     // and by Logger.getAnonymousLogger(String) so we'll drain up to
877     // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
878     //
879     // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
880     // us about a 50/50 mix in increased weak ref counts versus
881     // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
882     // Here are stats for cleaning up sets of 400 anonymous Loggers:
883     //   - test duration 1 minute
884     //   - sample size of 125 sets of 400
885     //   - average: 1.99 ms
886     //   - minimum: 0.57 ms
887     //   - maximum: 25.3 ms
888     //
889     // The same config gives us a better decreased weak ref count
890     // than increased weak ref count in the LoggerWeakRefLeak test.
891     // Here are stats for cleaning up sets of 400 named Loggers:
892     //   - test duration 2 minutes
893     //   - sample size of 506 sets of 400
894     //   - average: 0.57 ms
895     //   - minimum: 0.02 ms
896     //   - maximum: 10.9 ms
897     //
898     private final static int MAX_ITERATIONS = 400;
drainLoggerRefQueueBounded()899     final synchronized void drainLoggerRefQueueBounded() {
900         for (int i = 0; i < MAX_ITERATIONS; i++) {
901             if (loggerRefQueue == null) {
902                 // haven't finished loading LogManager yet
903                 break;
904             }
905 
906             LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
907             if (ref == null) {
908                 break;
909             }
910             // a Logger object has been GC'ed so clean it up
911             ref.dispose();
912         }
913     }
914 
915     /**
916      * Add a named logger.  This does nothing and returns false if a logger
917      * with the same name is already registered.
918      * <p>
919      * The Logger factory methods call this method to register each
920      * newly created Logger.
921      * <p>
922      * The application should retain its own reference to the Logger
923      * object to avoid it being garbage collected.  The LogManager
924      * may only retain a weak reference.
925      *
926      * @param   logger the new logger.
927      * @return  true if the argument logger was registered successfully,
928      *          false if a logger of that name already exists.
929      * @exception NullPointerException if the logger name is null.
930      */
addLogger(Logger logger)931     public boolean addLogger(Logger logger) {
932         final String name = logger.getName();
933         if (name == null) {
934             throw new NullPointerException();
935         }
936         drainLoggerRefQueueBounded();
937         LoggerContext cx = getUserContext();
938         if (cx.addLocalLogger(logger, this)) {
939             // Do we have a per logger handler too?
940             // Note: this will add a 200ms penalty
941             loadLoggerHandlers(logger, name, name + ".handlers");
942             return true;
943         } else {
944             return false;
945         }
946     }
947 
948     // Private method to set a level on a logger.
949     // If necessary, we raise privilege before doing the call.
doSetLevel(final Logger logger, final Level level)950     private static void doSetLevel(final Logger logger, final Level level) {
951         SecurityManager sm = System.getSecurityManager();
952         if (sm == null) {
953             // There is no security manager, so things are easy.
954             logger.setLevel(level);
955             return;
956         }
957         // There is a security manager.  Raise privilege before
958         // calling setLevel.
959         AccessController.doPrivileged(new PrivilegedAction<Object>() {
960             public Object run() {
961                 logger.setLevel(level);
962                 return null;
963             }});
964     }
965 
966     // Private method to set a parent on a logger.
967     // If necessary, we raise privilege before doing the setParent call.
doSetParent(final Logger logger, final Logger parent)968     private static void doSetParent(final Logger logger, final Logger parent) {
969         SecurityManager sm = System.getSecurityManager();
970         if (sm == null) {
971             // There is no security manager, so things are easy.
972             logger.setParent(parent);
973             return;
974         }
975         // There is a security manager.  Raise privilege before
976         // calling setParent.
977         AccessController.doPrivileged(new PrivilegedAction<Object>() {
978             public Object run() {
979                 logger.setParent(parent);
980                 return null;
981             }});
982     }
983 
984     /**
985      * Method to find a named logger.
986      * <p>
987      * Note that since untrusted code may create loggers with
988      * arbitrary names this method should not be relied on to
989      * find Loggers for security sensitive logging.
990      * It is also important to note that the Logger associated with the
991      * String {@code name} may be garbage collected at any time if there
992      * is no strong reference to the Logger. The caller of this method
993      * must check the return value for null in order to properly handle
994      * the case where the Logger has been garbage collected.
995      * <p>
996      * @param name name of the logger
997      * @return  matching logger or null if none is found
998      */
getLogger(String name)999     public Logger getLogger(String name) {
1000         return getUserContext().findLogger(name);
1001     }
1002 
1003     /**
1004      * Get an enumeration of known logger names.
1005      * <p>
1006      * Note:  Loggers may be added dynamically as new classes are loaded.
1007      * This method only reports on the loggers that are currently registered.
1008      * It is also important to note that this method only returns the name
1009      * of a Logger, not a strong reference to the Logger itself.
1010      * The returned String does nothing to prevent the Logger from being
1011      * garbage collected. In particular, if the returned name is passed
1012      * to {@code LogManager.getLogger()}, then the caller must check the
1013      * return value from {@code LogManager.getLogger()} for null to properly
1014      * handle the case where the Logger has been garbage collected in the
1015      * time since its name was returned by this method.
1016      * <p>
1017      * @return  enumeration of logger name strings
1018      */
getLoggerNames()1019     public Enumeration<String> getLoggerNames() {
1020         return getUserContext().getLoggerNames();
1021     }
1022 
1023     /**
1024      * Reinitialize the logging properties and reread the logging configuration.
1025      * <p>
1026      * The same rules are used for locating the configuration properties
1027      * as are used at startup.  So normally the logging properties will
1028      * be re-read from the same file that was used at startup.
1029      * <P>
1030      * Any log level definitions in the new configuration file will be
1031      * applied using Logger.setLevel(), if the target Logger exists.
1032      * <p>
1033      * A PropertyChangeEvent will be fired after the properties are read.
1034      *
1035      * @exception  SecurityException  if a security manager exists and if
1036      *             the caller does not have LoggingPermission("control").
1037      * @exception  IOException if there are IO problems reading the configuration.
1038      */
readConfiguration()1039     public void readConfiguration() throws IOException, SecurityException {
1040         checkPermission();
1041 
1042         // if a configuration class is specified, load it and use it.
1043         String cname = System.getProperty("java.util.logging.config.class");
1044         if (cname != null) {
1045             try {
1046                 // Instantiate the named class.  It is its constructor's
1047                 // responsibility to initialize the logging configuration, by
1048                 // calling readConfiguration(InputStream) with a suitable stream.
1049                 getClassInstance(cname).newInstance();
1050                 return;
1051             } catch (Exception ex) {
1052                 System.err.println("Logging configuration class \"" + cname + "\" failed");
1053                 System.err.println("" + ex);
1054                 // keep going and useful config file.
1055             }
1056         }
1057 
1058         String fname = System.getProperty("java.util.logging.config.file");
1059         if (fname == null) {
1060             fname = System.getProperty("java.home");
1061             if (fname == null) {
1062                 throw new Error("Can't find java.home ??");
1063             }
1064             File f = new File(fname, "lib");
1065             f = new File(f, "logging.properties");
1066             fname = f.getCanonicalPath();
1067         }
1068 
1069         // Android-changed: Look in the boot class-path jar files for the logging.properties.
1070         // It will not be present in the file system.
1071         InputStream in;
1072         try {
1073             in = new FileInputStream(fname);
1074         } catch (Exception e) {
1075             in = LogManager.class.getResourceAsStream("logging.properties");
1076             if (in == null) {
1077                 throw e;
1078             }
1079         }
1080 
1081         BufferedInputStream bin = new BufferedInputStream(in);
1082         try {
1083             readConfiguration(bin);
1084         } finally {
1085             if (in != null) {
1086                 in.close();
1087             }
1088         }
1089     }
1090 
1091     /**
1092      * Reset the logging configuration.
1093      * <p>
1094      * For all named loggers, the reset operation removes and closes
1095      * all Handlers and (except for the root logger) sets the level
1096      * to null.  The root logger's level is set to Level.INFO.
1097      *
1098      * @exception  SecurityException  if a security manager exists and if
1099      *             the caller does not have LoggingPermission("control").
1100      */
1101 
reset()1102     public void reset() throws SecurityException {
1103         checkPermission();
1104         synchronized (this) {
1105             props = new Properties();
1106             // Since we are doing a reset we no longer want to initialize
1107             // the global handlers, if they haven't been initialized yet.
1108             initializedGlobalHandlers = true;
1109         }
1110         for (LoggerContext cx : contexts()) {
1111             Enumeration<String> enum_ = cx.getLoggerNames();
1112             while (enum_.hasMoreElements()) {
1113                 String name = enum_.nextElement();
1114                 Logger logger = cx.findLogger(name);
1115                 if (logger != null) {
1116                     resetLogger(logger);
1117                 }
1118             }
1119         }
1120     }
1121 
1122     // Private method to reset an individual target logger.
resetLogger(Logger logger)1123     private void resetLogger(Logger logger) {
1124         // Close all the Logger's handlers.
1125         Handler[] targets = logger.getHandlers();
1126         for (int i = 0; i < targets.length; i++) {
1127             Handler h = targets[i];
1128             logger.removeHandler(h);
1129             try {
1130                 h.close();
1131             } catch (Exception ex) {
1132                 // Problems closing a handler?  Keep going...
1133             }
1134         }
1135         String name = logger.getName();
1136         if (name != null && name.equals("")) {
1137             // This is the root logger.
1138             logger.setLevel(defaultLevel);
1139         } else {
1140             logger.setLevel(null);
1141         }
1142     }
1143 
1144     // get a list of whitespace separated classnames from a property.
parseClassNames(String propertyName)1145     private String[] parseClassNames(String propertyName) {
1146         String hands = getProperty(propertyName);
1147         if (hands == null) {
1148             return new String[0];
1149         }
1150         hands = hands.trim();
1151         int ix = 0;
1152         Vector<String> result = new Vector<>();
1153         while (ix < hands.length()) {
1154             int end = ix;
1155             while (end < hands.length()) {
1156                 if (Character.isWhitespace(hands.charAt(end))) {
1157                     break;
1158                 }
1159                 if (hands.charAt(end) == ',') {
1160                     break;
1161                 }
1162                 end++;
1163             }
1164             String word = hands.substring(ix, end);
1165             ix = end+1;
1166             word = word.trim();
1167             if (word.length() == 0) {
1168                 continue;
1169             }
1170             result.add(word);
1171         }
1172         return result.toArray(new String[result.size()]);
1173     }
1174 
1175     /**
1176      * Reinitialize the logging properties and reread the logging configuration
1177      * from the given stream, which should be in java.util.Properties format.
1178      * A PropertyChangeEvent will be fired after the properties are read.
1179      * <p>
1180      * Any log level definitions in the new configuration file will be
1181      * applied using Logger.setLevel(), if the target Logger exists.
1182      *
1183      * @param ins       stream to read properties from
1184      * @exception  SecurityException  if a security manager exists and if
1185      *             the caller does not have LoggingPermission("control").
1186      * @exception  IOException if there are problems reading from the stream.
1187      */
readConfiguration(InputStream ins)1188     public void readConfiguration(InputStream ins) throws IOException, SecurityException {
1189         checkPermission();
1190         reset();
1191 
1192         // Load the properties
1193         props.load(ins);
1194         // Instantiate new configuration objects.
1195         String names[] = parseClassNames("config");
1196 
1197         for (int i = 0; i < names.length; i++) {
1198             String word = names[i];
1199             try {
1200                 getClassInstance(word).newInstance();
1201             } catch (Exception ex) {
1202                 System.err.println("Can't load config class \"" + word + "\"");
1203                 System.err.println("" + ex);
1204                 // ex.printStackTrace();
1205             }
1206         }
1207 
1208         // Set levels on any pre-existing loggers, based on the new properties.
1209         setLevelsOnExistingLoggers();
1210 
1211         // Notify any interested parties that our properties have changed.
1212         changes.firePropertyChange(null, null, null);
1213 
1214         // Note that we need to reinitialize global handles when
1215         // they are first referenced.
1216         synchronized (this) {
1217             initializedGlobalHandlers = false;
1218         }
1219     }
1220 
1221     /**
1222      * Get the value of a logging property.
1223      * The method returns null if the property is not found.
1224      * @param name      property name
1225      * @return          property value
1226      */
getProperty(String name)1227     public String getProperty(String name) {
1228         return props.getProperty(name);
1229     }
1230 
1231     // Package private method to get a String property.
1232     // If the property is not defined we return the given
1233     // default value.
getStringProperty(String name, String defaultValue)1234     String getStringProperty(String name, String defaultValue) {
1235         String val = getProperty(name);
1236         if (val == null) {
1237             return defaultValue;
1238         }
1239         return val.trim();
1240     }
1241 
1242     // Package private method to get an integer property.
1243     // If the property is not defined or cannot be parsed
1244     // we return the given default value.
getIntProperty(String name, int defaultValue)1245     int getIntProperty(String name, int defaultValue) {
1246         String val = getProperty(name);
1247         if (val == null) {
1248             return defaultValue;
1249         }
1250         try {
1251             return Integer.parseInt(val.trim());
1252         } catch (Exception ex) {
1253             return defaultValue;
1254         }
1255     }
1256 
1257     // Package private method to get a boolean property.
1258     // If the property is not defined or cannot be parsed
1259     // we return the given default value.
getBooleanProperty(String name, boolean defaultValue)1260     boolean getBooleanProperty(String name, boolean defaultValue) {
1261         String val = getProperty(name);
1262         if (val == null) {
1263             return defaultValue;
1264         }
1265         val = val.toLowerCase();
1266         if (val.equals("true") || val.equals("1")) {
1267             return true;
1268         } else if (val.equals("false") || val.equals("0")) {
1269             return false;
1270         }
1271         return defaultValue;
1272     }
1273 
1274     // Package private method to get a Level property.
1275     // If the property is not defined or cannot be parsed
1276     // we return the given default value.
getLevelProperty(String name, Level defaultValue)1277     Level getLevelProperty(String name, Level defaultValue) {
1278         String val = getProperty(name);
1279         if (val == null) {
1280             return defaultValue;
1281         }
1282         Level l = Level.findLevel(val.trim());
1283         return l != null ? l : defaultValue;
1284     }
1285 
1286     // Package private method to get a filter property.
1287     // We return an instance of the class named by the "name"
1288     // property. If the property is not defined or has problems
1289     // we return the defaultValue.
getFilterProperty(String name, Filter defaultValue)1290     Filter getFilterProperty(String name, Filter defaultValue) {
1291         String val = getProperty(name);
1292         try {
1293             if (val != null) {
1294                 return (Filter) getClassInstance(val).newInstance();
1295             }
1296         } catch (Exception ex) {
1297             // We got one of a variety of exceptions in creating the
1298             // class or creating an instance.
1299             // Drop through.
1300         }
1301         // We got an exception.  Return the defaultValue.
1302         return defaultValue;
1303     }
1304 
1305 
1306     // Package private method to get a formatter property.
1307     // We return an instance of the class named by the "name"
1308     // property. If the property is not defined or has problems
1309     // we return the defaultValue.
getFormatterProperty(String name, Formatter defaultValue)1310     Formatter getFormatterProperty(String name, Formatter defaultValue) {
1311         String val = getProperty(name);
1312         try {
1313             if (val != null) {
1314                 return (Formatter) getClassInstance(val).newInstance();
1315             }
1316         } catch (Exception ex) {
1317             // We got one of a variety of exceptions in creating the
1318             // class or creating an instance.
1319             // Drop through.
1320         }
1321         // We got an exception.  Return the defaultValue.
1322         return defaultValue;
1323     }
1324 
1325     // Private method to load the global handlers.
1326     // We do the real work lazily, when the global handlers
1327     // are first used.
initializeGlobalHandlers()1328     private synchronized void initializeGlobalHandlers() {
1329         if (initializedGlobalHandlers) {
1330             return;
1331         }
1332 
1333         initializedGlobalHandlers = true;
1334 
1335         if (deathImminent) {
1336             // Aaargh...
1337             // The VM is shutting down and our exit hook has been called.
1338             // Avoid allocating global handlers.
1339             return;
1340         }
1341         loadLoggerHandlers(rootLogger, null, "handlers");
1342     }
1343 
1344     private final Permission controlPermission = new LoggingPermission("control", null);
1345 
checkPermission()1346     void checkPermission() {
1347         SecurityManager sm = System.getSecurityManager();
1348         if (sm != null)
1349             sm.checkPermission(controlPermission);
1350     }
1351 
1352     /**
1353      * Check that the current context is trusted to modify the logging
1354      * configuration.  This requires LoggingPermission("control").
1355      * <p>
1356      * If the check fails we throw a SecurityException, otherwise
1357      * we return normally.
1358      *
1359      * @exception  SecurityException  if a security manager exists and if
1360      *             the caller does not have LoggingPermission("control").
1361      */
checkAccess()1362     public void checkAccess() throws SecurityException {
1363         checkPermission();
1364     }
1365 
1366     // Nested class to represent a node in our tree of named loggers.
1367     private static class LogNode {
1368         HashMap<String,LogNode> children;
1369         LoggerWeakRef loggerRef;
1370         LogNode parent;
1371         final LoggerContext context;
1372 
LogNode(LogNode parent, LoggerContext context)1373         LogNode(LogNode parent, LoggerContext context) {
1374             this.parent = parent;
1375             this.context = context;
1376         }
1377 
1378         // Recursive method to walk the tree below a node and set
1379         // a new parent logger.
walkAndSetParent(Logger parent)1380         void walkAndSetParent(Logger parent) {
1381             if (children == null) {
1382                 return;
1383             }
1384             Iterator<LogNode> values = children.values().iterator();
1385             while (values.hasNext()) {
1386                 LogNode node = values.next();
1387                 LoggerWeakRef ref = node.loggerRef;
1388                 Logger logger = (ref == null) ? null : ref.get();
1389                 if (logger == null) {
1390                     node.walkAndSetParent(parent);
1391                 } else {
1392                     doSetParent(logger, parent);
1393                 }
1394             }
1395         }
1396     }
1397 
1398     // We use a subclass of Logger for the root logger, so
1399     // that we only instantiate the global handlers when they
1400     // are first needed.
1401     private class RootLogger extends Logger {
RootLogger()1402         private RootLogger() {
1403             super("", null);
1404             setLevel(defaultLevel);
1405         }
1406 
log(LogRecord record)1407         public void log(LogRecord record) {
1408             // Make sure that the global handlers have been instantiated.
1409             initializeGlobalHandlers();
1410             super.log(record);
1411         }
1412 
addHandler(Handler h)1413         public void addHandler(Handler h) {
1414             initializeGlobalHandlers();
1415             super.addHandler(h);
1416         }
1417 
removeHandler(Handler h)1418         public void removeHandler(Handler h) {
1419             initializeGlobalHandlers();
1420             super.removeHandler(h);
1421         }
1422 
getHandlers()1423         public Handler[] getHandlers() {
1424             initializeGlobalHandlers();
1425             return super.getHandlers();
1426         }
1427     }
1428 
1429 
1430     // Private method to be called when the configuration has
1431     // changed to apply any level settings to any pre-existing loggers.
setLevelsOnExistingLoggers()1432     synchronized private void setLevelsOnExistingLoggers() {
1433         Enumeration<?> enum_ = props.propertyNames();
1434         while (enum_.hasMoreElements()) {
1435             String key = (String)enum_.nextElement();
1436             if (!key.endsWith(".level")) {
1437                 // Not a level definition.
1438                 continue;
1439             }
1440             int ix = key.length() - 6;
1441             String name = key.substring(0, ix);
1442             Level level = getLevelProperty(key, null);
1443             if (level == null) {
1444                 System.err.println("Bad level value for property: " + key);
1445                 continue;
1446             }
1447             for (LoggerContext cx : contexts()) {
1448                 Logger l = cx.findLogger(name);
1449                 if (l == null) {
1450                     continue;
1451                 }
1452                 l.setLevel(level);
1453             }
1454         }
1455     }
1456 
1457     // Management Support
1458     private static LoggingMXBean loggingMXBean = null;
1459     /**
1460      * String representation of the {@code ObjectName} for the management interface
1461      * for the logging facility.
1462      *
1463      * @see java.util.logging.LoggingMXBean
1464      *
1465      * @since 1.5
1466      */
1467     // Android-changed : Remove reference to java.lang.management.ObjectName.
1468     //
1469     //@see java.lang.management.PlatformLoggingMXBean
1470     public final static String LOGGING_MXBEAN_NAME
1471         = "java.util.logging:type=Logging";
1472 
1473     /**
1474      * Returns <tt>LoggingMXBean</tt> for managing loggers.
1475      *
1476      * @return a {@link LoggingMXBean} object.
1477      *
1478      * @since 1.5
1479      */
1480     // Android-removed docs areferring to java.lang.management.
1481     //
1482     // An alternative way to manage loggers is through the
1483     // {@link java.lang.management.PlatformLoggingMXBean} interface
1484     // that can be obtained by calling:
1485     // <pre>
1486     //     PlatformLoggingMXBean logging = {@link java.lang.management.ManagementFactory#getPlatformMXBean(Class)
1487     //        ManagementFactory.getPlatformMXBean}(PlatformLoggingMXBean.class);
1488     // </pre>
1489     //
1490     // @see java.lang.management.PlatformLoggingMXBean
getLoggingMXBean()1491     public static synchronized LoggingMXBean getLoggingMXBean() {
1492         if (loggingMXBean == null) {
1493             loggingMXBean =  new Logging();
1494         }
1495         return loggingMXBean;
1496     }
1497 
1498 }
1499