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