Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2014, 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 package java.security;
     28 
     29 import java.io.*;
     30 import java.util.*;
     31 import java.util.concurrent.atomic.AtomicBoolean;
     32 
     33 import static java.util.Locale.ENGLISH;
     34 
     35 import java.lang.ref.*;
     36 import java.lang.reflect.*;
     37 import java.security.Security;
     38 import java.util.function.BiConsumer;
     39 import java.util.function.BiFunction;
     40 import java.util.function.Function;
     41 
     42 /**
     43  * This class represents a "provider" for the
     44  * Java Security API, where a provider implements some or all parts of
     45  * Java Security. Services that a provider may implement include:
     46  *
     47  * <ul>
     48  *
     49  * <li>Algorithms (such as DSA, RSA, MD5 or SHA-1).
     50  *
     51  * <li>Key generation, conversion, and management facilities (such as for
     52  * algorithm-specific keys).
     53  *
     54  *</ul>
     55  *
     56  * <p>Each provider has a name and a version number, and is configured
     57  * in each runtime it is installed in.
     58  *
     59  * <p>See <a href =
     60  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html#Provider">The Provider Class</a>
     61  * in the "Java Cryptography Architecture API Specification &amp; Reference"
     62  * for information about how a particular type of provider, the
     63  * cryptographic service provider, works and is installed. However,
     64  * please note that a provider can be used to implement any security
     65  * service in Java that uses a pluggable architecture with a choice
     66  * of implementations that fit underneath.
     67  *
     68  * <p>Some provider implementations may encounter unrecoverable internal
     69  * errors during their operation, for example a failure to communicate with a
     70  * security token. A {@link ProviderException} should be used to indicate
     71  * such errors.
     72  *
     73  * <p>The service type {@code Provider} is reserved for use by the
     74  * security framework. Services of this type cannot be added, removed,
     75  * or modified by applications.
     76  * The following attributes are automatically placed in each Provider object:
     77  * <table cellspacing=4>
     78  * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption>
     79  * <tr><th>Name</th><th>Value</th>
     80  * <tr><td>{@code Provider.id name}</td>
     81   *    <td>{@code String.valueOf(provider.getName())}</td>
     82  * <tr><td>{@code Provider.id version}</td>
     83  *     <td>{@code String.valueOf(provider.getVersion())}</td>
     84  * <tr><td>{@code Provider.id info}</td>
     85        <td>{@code String.valueOf(provider.getInfo())}</td>
     86  * <tr><td>{@code Provider.id className}</td>
     87  *     <td>{@code provider.getClass().getName()}</td>
     88  * </table>
     89  *
     90  * @author Benjamin Renaud
     91  * @author Andreas Sterbenz
     92  */
     93 public abstract class Provider extends Properties {
     94 
     95     // Declare serialVersionUID to be compatible with JDK1.1
     96     static final long serialVersionUID = -4298000515446427739L;
     97 
     98     private volatile boolean registered = false;
     99 
    100     private static final sun.security.util.Debug debug =
    101         sun.security.util.Debug.getInstance
    102         ("provider", "Provider");
    103 
    104     /**
    105      * The provider name.
    106      *
    107      * @serial
    108      */
    109     private String name;
    110 
    111     /**
    112      * A description of the provider and its services.
    113      *
    114      * @serial
    115      */
    116     private String info;
    117 
    118     /**
    119      * The provider version number.
    120      *
    121      * @serial
    122      */
    123     private double version;
    124 
    125 
    126     private transient Set<Map.Entry<Object,Object>> entrySet = null;
    127     private transient int entrySetCallCount = 0;
    128 
    129     private transient boolean initialized;
    130 
    131     /**
    132      * Constructs a provider with the specified name, version number,
    133      * and information.
    134      *
    135      * @param name the provider name.
    136      *
    137      * @param version the provider version number.
    138      *
    139      * @param info a description of the provider and its services.
    140      */
    141     protected Provider(String name, double version, String info) {
    142         this.name = name;
    143         this.version = version;
    144         this.info = info;
    145         putId();
    146         initialized = true;
    147     }
    148 
    149     /**
    150      * Returns the name of this provider.
    151      *
    152      * @return the name of this provider.
    153      */
    154     public String getName() {
    155         return name;
    156     }
    157 
    158     /**
    159      * Returns the version number for this provider.
    160      *
    161      * @return the version number for this provider.
    162      */
    163     public double getVersion() {
    164         return version;
    165     }
    166 
    167     /**
    168      * Returns a human-readable description of the provider and its
    169      * services.  This may return an HTML page, with relevant links.
    170      *
    171      * @return a description of the provider and its services.
    172      */
    173     public String getInfo() {
    174         return info;
    175     }
    176 
    177     /**
    178      * Returns a string with the name and the version number
    179      * of this provider.
    180      *
    181      * @return the string with the name and the version number
    182      * for this provider.
    183      */
    184     public String toString() {
    185         return name + " version " + version;
    186     }
    187 
    188     /*
    189      * override the following methods to ensure that provider
    190      * information can only be changed if the caller has the appropriate
    191      * permissions.
    192      */
    193 
    194     /**
    195      * Clears this provider so that it no longer contains the properties
    196      * used to look up facilities implemented by the provider.
    197      *
    198      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    199      * method is called with the string {@code "clearProviderProperties."+name}
    200      * (where {@code name} is the provider name) to see if it's ok to clear
    201      * this provider.
    202      *
    203      * @throws  SecurityException
    204      *          if a security manager exists and its {@link
    205      *          java.lang.SecurityManager#checkSecurityAccess} method
    206      *          denies access to clear this provider
    207      *
    208      * @since 1.2
    209      */
    210     @Override
    211     public synchronized void clear() {
    212         check("clearProviderProperties."+name);
    213         if (debug != null) {
    214             debug.println("Remove " + name + " provider properties");
    215         }
    216         implClear();
    217     }
    218 
    219     /**
    220      * Reads a property list (key and element pairs) from the input stream.
    221      *
    222      * @param inStream   the input stream.
    223      * @exception  IOException  if an error occurred when reading from the
    224      *               input stream.
    225      * @see java.util.Properties#load
    226      */
    227     @Override
    228     public synchronized void load(InputStream inStream) throws IOException {
    229         check("putProviderProperty."+name);
    230         if (debug != null) {
    231             debug.println("Load " + name + " provider properties");
    232         }
    233         Properties tempProperties = new Properties();
    234         tempProperties.load(inStream);
    235         implPutAll(tempProperties);
    236     }
    237 
    238     /**
    239      * Copies all of the mappings from the specified Map to this provider.
    240      * These mappings will replace any properties that this provider had
    241      * for any of the keys currently in the specified Map.
    242      *
    243      * @since 1.2
    244      */
    245     @Override
    246     public synchronized void putAll(Map<?,?> t) {
    247         check("putProviderProperty."+name);
    248         if (debug != null) {
    249             debug.println("Put all " + name + " provider properties");
    250         }
    251         implPutAll(t);
    252     }
    253 
    254     /**
    255      * Returns an unmodifiable Set view of the property entries contained
    256      * in this Provider.
    257      *
    258      * @see   java.util.Map.Entry
    259      * @since 1.2
    260      */
    261     @Override
    262     public synchronized Set<Map.Entry<Object,Object>> entrySet() {
    263         checkInitialized();
    264         if (entrySet == null) {
    265             if (entrySetCallCount++ == 0)  // Initial call
    266                 entrySet = Collections.unmodifiableMap(this).entrySet();
    267             else
    268                 return super.entrySet();   // Recursive call
    269         }
    270 
    271         // This exception will be thrown if the implementation of
    272         // Collections.unmodifiableMap.entrySet() is changed such that it
    273         // no longer calls entrySet() on the backing Map.  (Provider's
    274         // entrySet implementation depends on this "implementation detail",
    275         // which is unlikely to change.
    276         if (entrySetCallCount != 2)
    277             throw new RuntimeException("Internal error.");
    278 
    279         return entrySet;
    280     }
    281 
    282     /**
    283      * Returns an unmodifiable Set view of the property keys contained in
    284      * this provider.
    285      *
    286      * @since 1.2
    287      */
    288     @Override
    289     public Set<Object> keySet() {
    290         checkInitialized();
    291         return Collections.unmodifiableSet(super.keySet());
    292     }
    293 
    294     /**
    295      * Returns an unmodifiable Collection view of the property values
    296      * contained in this provider.
    297      *
    298      * @since 1.2
    299      */
    300     @Override
    301     public Collection<Object> values() {
    302         checkInitialized();
    303         return Collections.unmodifiableCollection(super.values());
    304     }
    305 
    306     /**
    307      * Sets the {@code key} property to have the specified
    308      * {@code value}.
    309      *
    310      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    311      * method is called with the string {@code "putProviderProperty."+name},
    312      * where {@code name} is the provider name, to see if it's ok to set this
    313      * provider's property values.
    314      *
    315      * @throws  SecurityException
    316      *          if a security manager exists and its {@link
    317      *          java.lang.SecurityManager#checkSecurityAccess} method
    318      *          denies access to set property values.
    319      *
    320      * @since 1.2
    321      */
    322     @Override
    323     public synchronized Object put(Object key, Object value) {
    324         check("putProviderProperty."+name);
    325         if (debug != null) {
    326             debug.println("Set " + name + " provider property [" +
    327                           key + "/" + value +"]");
    328         }
    329         return implPut(key, value);
    330     }
    331 
    332     /**
    333      * If the specified key is not already associated with a value (or is mapped
    334      * to {@code null}) associates it with the given value and returns
    335      * {@code null}, else returns the current value.
    336      *
    337      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    338      * method is called with the string {@code "putProviderProperty."+name},
    339      * where {@code name} is the provider name, to see if it's ok to set this
    340      * provider's property values.
    341      *
    342      * @throws  SecurityException
    343      *          if a security manager exists and its {@link
    344      *          java.lang.SecurityManager#checkSecurityAccess} method
    345      *          denies access to set property values.
    346      *
    347      * @since 1.8
    348      */
    349     @Override
    350     public synchronized Object putIfAbsent(Object key, Object value) {
    351         check("putProviderProperty."+name);
    352         if (debug != null) {
    353             debug.println("Set " + name + " provider property [" +
    354                           key + "/" + value +"]");
    355         }
    356         return implPutIfAbsent(key, value);
    357     }
    358 
    359     /**
    360      * Removes the {@code key} property (and its corresponding
    361      * {@code value}).
    362      *
    363      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    364      * method is called with the string {@code "removeProviderProperty."+name},
    365      * where {@code name} is the provider name, to see if it's ok to remove this
    366      * provider's properties.
    367      *
    368      * @throws  SecurityException
    369      *          if a security manager exists and its {@link
    370      *          java.lang.SecurityManager#checkSecurityAccess} method
    371      *          denies access to remove this provider's properties.
    372      *
    373      * @since 1.2
    374      */
    375     @Override
    376     public synchronized Object remove(Object key) {
    377         check("removeProviderProperty."+name);
    378         if (debug != null) {
    379             debug.println("Remove " + name + " provider property " + key);
    380         }
    381         return implRemove(key);
    382     }
    383 
    384     /**
    385      * Removes the entry for the specified key only if it is currently
    386      * mapped to the specified value.
    387      *
    388      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    389      * method is called with the string {@code "removeProviderProperty."+name},
    390      * where {@code name} is the provider name, to see if it's ok to remove this
    391      * provider's properties.
    392      *
    393      * @throws  SecurityException
    394      *          if a security manager exists and its {@link
    395      *          java.lang.SecurityManager#checkSecurityAccess} method
    396      *          denies access to remove this provider's properties.
    397      *
    398      * @since 1.8
    399      */
    400     @Override
    401     public synchronized boolean remove(Object key, Object value) {
    402         check("removeProviderProperty."+name);
    403         if (debug != null) {
    404             debug.println("Remove " + name + " provider property " + key);
    405         }
    406         return implRemove(key, value);
    407     }
    408 
    409     /**
    410      * Replaces the entry for the specified key only if currently
    411      * mapped to the specified value.
    412      *
    413      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    414      * method is called with the string {@code "putProviderProperty."+name},
    415      * where {@code name} is the provider name, to see if it's ok to set this
    416      * provider's property values.
    417      *
    418      * @throws  SecurityException
    419      *          if a security manager exists and its {@link
    420      *          java.lang.SecurityManager#checkSecurityAccess} method
    421      *          denies access to set property values.
    422      *
    423      * @since 1.8
    424      */
    425     @Override
    426     public synchronized boolean replace(Object key, Object oldValue,
    427             Object newValue) {
    428         check("putProviderProperty." + name);
    429 
    430         if (debug != null) {
    431             debug.println("Replace " + name + " provider property " + key);
    432         }
    433         return implReplace(key, oldValue, newValue);
    434     }
    435 
    436     /**
    437      * Replaces the entry for the specified key only if it is
    438      * currently mapped to some value.
    439      *
    440      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    441      * method is called with the string {@code "putProviderProperty."+name},
    442      * where {@code name} is the provider name, to see if it's ok to set this
    443      * provider's property values.
    444      *
    445      * @throws  SecurityException
    446      *          if a security manager exists and its {@link
    447      *          java.lang.SecurityManager#checkSecurityAccess} method
    448      *          denies access to set property values.
    449      *
    450      * @since 1.8
    451      */
    452     @Override
    453     public synchronized Object replace(Object key, Object value) {
    454         check("putProviderProperty." + name);
    455 
    456         if (debug != null) {
    457             debug.println("Replace " + name + " provider property " + key);
    458         }
    459         return implReplace(key, value);
    460     }
    461 
    462     /**
    463      * Replaces each entry's value with the result of invoking the given
    464      * function on that entry, in the order entries are returned by an entry
    465      * set iterator, until all entries have been processed or the function
    466      * throws an exception.
    467      *
    468      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    469      * method is called with the string {@code "putProviderProperty."+name},
    470      * where {@code name} is the provider name, to see if it's ok to set this
    471      * provider's property values.
    472      *
    473      * @throws  SecurityException
    474      *          if a security manager exists and its {@link
    475      *          java.lang.SecurityManager#checkSecurityAccess} method
    476      *          denies access to set property values.
    477      *
    478      * @since 1.8
    479      */
    480     @Override
    481     public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
    482         check("putProviderProperty." + name);
    483 
    484         if (debug != null) {
    485             debug.println("ReplaceAll " + name + " provider property ");
    486         }
    487         implReplaceAll(function);
    488     }
    489 
    490     /**
    491      * Attempts to compute a mapping for the specified key and its
    492      * current mapped value (or {@code null} if there is no current
    493      * mapping).
    494      *
    495      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    496      * method is called with the strings {@code "putProviderProperty."+name}
    497      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    498      * provider name, to see if it's ok to set this provider's property values
    499      * and remove this provider's properties.
    500      *
    501      * @throws  SecurityException
    502      *          if a security manager exists and its {@link
    503      *          java.lang.SecurityManager#checkSecurityAccess} method
    504      *          denies access to set property values or remove properties.
    505      *
    506      * @since 1.8
    507      */
    508     @Override
    509     public synchronized Object compute(Object key,
    510         BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    511         check("putProviderProperty." + name);
    512         check("removeProviderProperty" + name);
    513 
    514         if (debug != null) {
    515             debug.println("Compute " + name + " provider property " + key);
    516         }
    517         return implCompute(key, remappingFunction);
    518     }
    519 
    520     /**
    521      * If the specified key is not already associated with a value (or
    522      * is mapped to {@code null}), attempts to compute its value using
    523      * the given mapping function and enters it into this map unless
    524      * {@code null}.
    525      *
    526      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    527      * method is called with the strings {@code "putProviderProperty."+name}
    528      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    529      * provider name, to see if it's ok to set this provider's property values
    530      * and remove this provider's properties.
    531      *
    532      * @throws  SecurityException
    533      *          if a security manager exists and its {@link
    534      *          java.lang.SecurityManager#checkSecurityAccess} method
    535      *          denies access to set property values and remove properties.
    536      *
    537      * @since 1.8
    538      */
    539     @Override
    540     public synchronized Object computeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
    541         check("putProviderProperty." + name);
    542         check("removeProviderProperty" + name);
    543 
    544         if (debug != null) {
    545             debug.println("ComputeIfAbsent " + name + " provider property " +
    546                     key);
    547         }
    548         return implComputeIfAbsent(key, mappingFunction);
    549     }
    550 
    551     /**
    552      * If the value for the specified key is present and non-null, attempts to
    553      * compute a new mapping given the key and its current mapped value.
    554      *
    555      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    556      * method is called with the strings {@code "putProviderProperty."+name}
    557      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    558      * provider name, to see if it's ok to set this provider's property values
    559      * and remove this provider's properties.
    560      *
    561      * @throws  SecurityException
    562      *          if a security manager exists and its {@link
    563      *          java.lang.SecurityManager#checkSecurityAccess} method
    564      *          denies access to set property values or remove properties.
    565      *
    566      * @since 1.8
    567      */
    568     @Override
    569     public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    570         check("putProviderProperty." + name);
    571         check("removeProviderProperty" + name);
    572 
    573         if (debug != null) {
    574             debug.println("ComputeIfPresent " + name + " provider property " +
    575                     key);
    576         }
    577         return implComputeIfPresent(key, remappingFunction);
    578     }
    579 
    580     /**
    581      * If the specified key is not already associated with a value or is
    582      * associated with null, associates it with the given value. Otherwise,
    583      * replaces the value with the results of the given remapping function,
    584      * or removes if the result is null. This method may be of use when
    585      * combining multiple mapped values for a key.
    586      *
    587      * <p>If a security manager is enabled, its {@code checkSecurityAccess}
    588      * method is called with the strings {@code "putProviderProperty."+name}
    589      * and {@code "removeProviderProperty."+name}, where {@code name} is the
    590      * provider name, to see if it's ok to set this provider's property values
    591      * and remove this provider's properties.
    592      *
    593      * @throws  SecurityException
    594      *          if a security manager exists and its {@link
    595      *          java.lang.SecurityManager#checkSecurityAccess} method
    596      *          denies access to set property values or remove properties.
    597      *
    598      * @since 1.8
    599      */
    600     @Override
    601     public synchronized Object merge(Object key, Object value,  BiFunction<? super Object, ? super Object, ? extends Object>  remappingFunction) {
    602         check("putProviderProperty." + name);
    603         check("removeProviderProperty" + name);
    604 
    605         if (debug != null) {
    606             debug.println("Merge " + name + " provider property " + key);
    607         }
    608         return implMerge(key, value, remappingFunction);
    609     }
    610 
    611     // let javadoc show doc from superclass
    612     @Override
    613     public Object get(Object key) {
    614         checkInitialized();
    615         return super.get(key);
    616     }
    617     /**
    618      * @since 1.8
    619      */
    620     @Override
    621     public synchronized Object getOrDefault(Object key, Object defaultValue) {
    622         checkInitialized();
    623         return super.getOrDefault(key, defaultValue);
    624     }
    625 
    626     /**
    627      * @since 1.8
    628      */
    629     @Override
    630     public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
    631         checkInitialized();
    632         super.forEach(action);
    633     }
    634 
    635     // let javadoc show doc from superclass
    636     @Override
    637     public Enumeration<Object> keys() {
    638         checkInitialized();
    639         return super.keys();
    640     }
    641 
    642     // let javadoc show doc from superclass
    643     @Override
    644     public Enumeration<Object> elements() {
    645         checkInitialized();
    646         return super.elements();
    647     }
    648 
    649     // let javadoc show doc from superclass
    650     public String getProperty(String key) {
    651         checkInitialized();
    652         return super.getProperty(key);
    653     }
    654 
    655     private void checkInitialized() {
    656         if (!initialized) {
    657             throw new IllegalStateException();
    658         }
    659     }
    660 
    661     private void check(String directive) {
    662         checkInitialized();
    663         SecurityManager security = System.getSecurityManager();
    664         if (security != null) {
    665             security.checkSecurityAccess(directive);
    666         }
    667     }
    668 
    669     // legacy properties changed since last call to any services method?
    670     private transient boolean legacyChanged;
    671     // serviceMap changed since last call to getServices()
    672     private transient boolean servicesChanged;
    673 
    674     // Map<String,String>
    675     private transient Map<String,String> legacyStrings;
    676 
    677     // Map<ServiceKey,Service>
    678     // used for services added via putService(), initialized on demand
    679     private transient Map<ServiceKey,Service> serviceMap;
    680 
    681     // Map<ServiceKey,Service>
    682     // used for services added via legacy methods, init on demand
    683     private transient Map<ServiceKey,Service> legacyMap;
    684 
    685     // Set<Service>
    686     // Unmodifiable set of all services. Initialized on demand.
    687     private transient Set<Service> serviceSet;
    688 
    689     // register the id attributes for this provider
    690     // this is to ensure that equals() and hashCode() do not incorrectly
    691     // report to different provider objects as the same
    692     private void putId() {
    693         // note: name and info may be null
    694         super.put("Provider.id name", String.valueOf(name));
    695         super.put("Provider.id version", String.valueOf(version));
    696         super.put("Provider.id info", String.valueOf(info));
    697         super.put("Provider.id className", this.getClass().getName());
    698     }
    699 
    700     private void readObject(ObjectInputStream in)
    701                 throws IOException, ClassNotFoundException {
    702         registered = false;
    703         Map<Object,Object> copy = new HashMap<>();
    704         for (Map.Entry<Object,Object> entry : super.entrySet()) {
    705             copy.put(entry.getKey(), entry.getValue());
    706         }
    707         defaults = null;
    708         in.defaultReadObject();
    709         implClear();
    710         initialized = true;
    711         putAll(copy);
    712     }
    713 
    714     private boolean checkLegacy(Object key) {
    715         if (registered) {
    716             Security.increaseVersion();
    717         }
    718         String keyString = (String)key;
    719         if (keyString.startsWith("Provider.")) {
    720             return false;
    721         }
    722 
    723         legacyChanged = true;
    724         if (legacyStrings == null) {
    725             legacyStrings = new LinkedHashMap<String,String>();
    726         }
    727         return true;
    728     }
    729 
    730     /**
    731      * Copies all of the mappings from the specified Map to this provider.
    732      * Internal method to be called AFTER the security check has been
    733      * performed.
    734      */
    735     private void implPutAll(Map<?,?> t) {
    736         for (Map.Entry<?,?> e : t.entrySet()) {
    737             implPut(e.getKey(), e.getValue());
    738         }
    739         if (registered) {
    740             Security.increaseVersion();
    741         }
    742     }
    743 
    744     private Object implRemove(Object key) {
    745         if (key instanceof String) {
    746             if (!checkLegacy(key)) {
    747                 return null;
    748             }
    749             legacyStrings.remove((String)key);
    750         }
    751         return super.remove(key);
    752     }
    753 
    754     private boolean implRemove(Object key, Object value) {
    755         if (key instanceof String && value instanceof String) {
    756             if (!checkLegacy(key)) {
    757                 return false;
    758             }
    759             legacyStrings.remove((String)key, value);
    760         }
    761         return super.remove(key, value);
    762     }
    763 
    764     private boolean implReplace(Object key, Object oldValue, Object newValue) {
    765         if ((key instanceof String) && (oldValue instanceof String) &&
    766                 (newValue instanceof String)) {
    767             if (!checkLegacy(key)) {
    768                 return false;
    769             }
    770             legacyStrings.replace((String)key, (String)oldValue,
    771                     (String)newValue);
    772         }
    773         return super.replace(key, oldValue, newValue);
    774     }
    775 
    776     private Object implReplace(Object key, Object value) {
    777         if ((key instanceof String) && (value instanceof String)) {
    778             if (!checkLegacy(key)) {
    779                 return null;
    780             }
    781             legacyStrings.replace((String)key, (String)value);
    782         }
    783         return super.replace(key, value);
    784     }
    785 
    786     private void implReplaceAll(BiFunction<? super Object, ? super Object, ? extends Object> function) {
    787         legacyChanged = true;
    788         if (legacyStrings == null) {
    789             legacyStrings = new LinkedHashMap<String,String>();
    790         } else {
    791             legacyStrings.replaceAll((BiFunction<? super String, ? super String, ? extends String>) function);
    792         }
    793         super.replaceAll(function);
    794     }
    795 
    796 
    797     private Object implMerge(Object key, Object value, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    798         if ((key instanceof String) && (value instanceof String)) {
    799             if (!checkLegacy(key)) {
    800                 return null;
    801             }
    802             legacyStrings.merge((String)key, (String)value,
    803                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
    804         }
    805         return super.merge(key, value, remappingFunction);
    806     }
    807 
    808     private Object implCompute(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    809         if (key instanceof String) {
    810             if (!checkLegacy(key)) {
    811                 return null;
    812             }
    813             // BEGIN Android-changed: was
    814             // legacyStrings.computeIfAbsent((String) key,
    815             //         (Function<? super String, ? extends String>) remappingFunction);
    816             // which cannot ever succeed as the cast from BiFunction to Function always fails
    817             legacyStrings.compute((String) key,
    818                     (BiFunction<? super String, ? super String, ? extends String>)
    819                             remappingFunction);
    820             // END Android-changed
    821         }
    822         return super.compute(key, remappingFunction);
    823     }
    824 
    825     private Object implComputeIfAbsent(Object key, Function<? super Object, ? extends Object> mappingFunction) {
    826         if (key instanceof String) {
    827             if (!checkLegacy(key)) {
    828                 return null;
    829             }
    830             legacyStrings.computeIfAbsent((String) key,
    831                     (Function<? super String, ? extends String>) mappingFunction);
    832         }
    833         return super.computeIfAbsent(key, mappingFunction);
    834     }
    835 
    836     private Object implComputeIfPresent(Object key, BiFunction<? super Object, ? super Object, ? extends Object> remappingFunction) {
    837         if (key instanceof String) {
    838             if (!checkLegacy(key)) {
    839                 return null;
    840             }
    841             legacyStrings.computeIfPresent((String) key,
    842                     (BiFunction<? super String, ? super String, ? extends String>) remappingFunction);
    843         }
    844         return super.computeIfPresent(key, remappingFunction);
    845     }
    846 
    847     private Object implPut(Object key, Object value) {
    848         if ((key instanceof String) && (value instanceof String)) {
    849             if (!checkLegacy(key)) {
    850                 return null;
    851             }
    852             legacyStrings.put((String)key, (String)value);
    853         }
    854         return super.put(key, value);
    855     }
    856 
    857     private Object implPutIfAbsent(Object key, Object value) {
    858         if ((key instanceof String) && (value instanceof String)) {
    859             if (!checkLegacy(key)) {
    860                 return null;
    861             }
    862             legacyStrings.putIfAbsent((String)key, (String)value);
    863         }
    864         return super.putIfAbsent(key, value);
    865     }
    866 
    867     private void implClear() {
    868         if (legacyStrings != null) {
    869             legacyStrings.clear();
    870         }
    871         if (legacyMap != null) {
    872             legacyMap.clear();
    873         }
    874         if (serviceMap != null) {
    875             serviceMap.clear();
    876         }
    877         legacyChanged = false;
    878         servicesChanged = false;
    879         serviceSet = null;
    880         super.clear();
    881         putId();
    882         if (registered) {
    883           Security.increaseVersion();
    884         }
    885     }
    886 
    887     // used as key in the serviceMap and legacyMap HashMaps
    888     private static class ServiceKey {
    889         private final String type;
    890         private final String algorithm;
    891         private final String originalAlgorithm;
    892         private ServiceKey(String type, String algorithm, boolean intern) {
    893             this.type = type;
    894             this.originalAlgorithm = algorithm;
    895             algorithm = algorithm.toUpperCase(ENGLISH);
    896             this.algorithm = intern ? algorithm.intern() : algorithm;
    897         }
    898         public int hashCode() {
    899             return type.hashCode() + algorithm.hashCode();
    900         }
    901         public boolean equals(Object obj) {
    902             if (this == obj) {
    903                 return true;
    904             }
    905             if (obj instanceof ServiceKey == false) {
    906                 return false;
    907             }
    908             ServiceKey other = (ServiceKey)obj;
    909             return this.type.equals(other.type)
    910                 && this.algorithm.equals(other.algorithm);
    911         }
    912         boolean matches(String type, String algorithm) {
    913             return (this.type == type) && (this.originalAlgorithm == algorithm);
    914         }
    915     }
    916 
    917     /**
    918      * Ensure all the legacy String properties are fully parsed into
    919      * service objects.
    920      */
    921     private void ensureLegacyParsed() {
    922         if ((legacyChanged == false) || (legacyStrings == null)) {
    923             return;
    924         }
    925         serviceSet = null;
    926         if (legacyMap == null) {
    927             legacyMap = new LinkedHashMap<ServiceKey,Service>();
    928         } else {
    929             legacyMap.clear();
    930         }
    931         for (Map.Entry<String,String> entry : legacyStrings.entrySet()) {
    932             parseLegacyPut(entry.getKey(), entry.getValue());
    933         }
    934         removeInvalidServices(legacyMap);
    935         legacyChanged = false;
    936     }
    937 
    938     /**
    939      * Remove all invalid services from the Map. Invalid services can only
    940      * occur if the legacy properties are inconsistent or incomplete.
    941      */
    942     private void removeInvalidServices(Map<ServiceKey,Service> map) {
    943         for (Iterator<Map.Entry<ServiceKey, Service>> t =
    944                 map.entrySet().iterator(); t.hasNext(); ) {
    945             Service s = t.next().getValue();
    946             if (s.isValid() == false) {
    947                 t.remove();
    948             }
    949         }
    950     }
    951 
    952     private String[] getTypeAndAlgorithm(String key) {
    953         int i = key.indexOf(".");
    954         if (i < 1) {
    955             if (debug != null) {
    956                 debug.println("Ignoring invalid entry in provider "
    957                         + name + ":" + key);
    958             }
    959             return null;
    960         }
    961         String type = key.substring(0, i);
    962         String alg = key.substring(i + 1);
    963         return new String[] {type, alg};
    964     }
    965 
    966     private final static String ALIAS_PREFIX = "Alg.Alias.";
    967     private final static String ALIAS_PREFIX_LOWER = "alg.alias.";
    968     private final static int ALIAS_LENGTH = ALIAS_PREFIX.length();
    969 
    970     private void parseLegacyPut(String name, String value) {
    971         if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) {
    972             // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1");
    973             // aliasKey ~ MessageDigest.SHA
    974             String stdAlg = value;
    975             String aliasKey = name.substring(ALIAS_LENGTH);
    976             String[] typeAndAlg = getTypeAndAlgorithm(aliasKey);
    977             if (typeAndAlg == null) {
    978                 return;
    979             }
    980             String type = getEngineName(typeAndAlg[0]);
    981             String aliasAlg = typeAndAlg[1].intern();
    982             ServiceKey key = new ServiceKey(type, stdAlg, true);
    983             Service s = legacyMap.get(key);
    984             if (s == null) {
    985                 s = new Service(this);
    986                 s.type = type;
    987                 s.algorithm = stdAlg;
    988                 legacyMap.put(key, s);
    989             }
    990             legacyMap.put(new ServiceKey(type, aliasAlg, true), s);
    991             s.addAlias(aliasAlg);
    992         } else {
    993             String[] typeAndAlg = getTypeAndAlgorithm(name);
    994             if (typeAndAlg == null) {
    995                 return;
    996             }
    997             int i = typeAndAlg[1].indexOf(' ');
    998             if (i == -1) {
    999                 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
   1000                 String type = getEngineName(typeAndAlg[0]);
   1001                 String stdAlg = typeAndAlg[1].intern();
   1002                 String className = value;
   1003                 ServiceKey key = new ServiceKey(type, stdAlg, true);
   1004                 Service s = legacyMap.get(key);
   1005                 if (s == null) {
   1006                     s = new Service(this);
   1007                     s.type = type;
   1008                     s.algorithm = stdAlg;
   1009                     legacyMap.put(key, s);
   1010                 }
   1011                 s.className = className;
   1012             } else { // attribute
   1013                 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
   1014                 String attributeValue = value;
   1015                 String type = getEngineName(typeAndAlg[0]);
   1016                 String attributeString = typeAndAlg[1];
   1017                 String stdAlg = attributeString.substring(0, i).intern();
   1018                 String attributeName = attributeString.substring(i + 1);
   1019                 // kill additional spaces
   1020                 while (attributeName.startsWith(" ")) {
   1021                     attributeName = attributeName.substring(1);
   1022                 }
   1023                 attributeName = attributeName.intern();
   1024                 ServiceKey key = new ServiceKey(type, stdAlg, true);
   1025                 Service s = legacyMap.get(key);
   1026                 if (s == null) {
   1027                     s = new Service(this);
   1028                     s.type = type;
   1029                     s.algorithm = stdAlg;
   1030                     legacyMap.put(key, s);
   1031                 }
   1032                 s.addAttribute(attributeName, attributeValue);
   1033             }
   1034         }
   1035     }
   1036 
   1037     /**
   1038      * Get the service describing this Provider's implementation of the
   1039      * specified type of this algorithm or alias. If no such
   1040      * implementation exists, this method returns null. If there are two
   1041      * matching services, one added to this provider using
   1042      * {@link #putService putService()} and one added via {@link #put put()},
   1043      * the service added via {@link #putService putService()} is returned.
   1044      *
   1045      * @param type the type of {@link Service service} requested
   1046      * (for example, {@code MessageDigest})
   1047      * @param algorithm the case insensitive algorithm name (or alternate
   1048      * alias) of the service requested (for example, {@code SHA-1})
   1049      *
   1050      * @return the service describing this Provider's matching service
   1051      * or null if no such service exists
   1052      *
   1053      * @throws NullPointerException if type or algorithm is null
   1054      *
   1055      * @since 1.5
   1056      */
   1057     public synchronized Service getService(String type, String algorithm) {
   1058         checkInitialized();
   1059         // avoid allocating a new key object if possible
   1060         ServiceKey key = previousKey;
   1061         if (key.matches(type, algorithm) == false) {
   1062             key = new ServiceKey(type, algorithm, false);
   1063             previousKey = key;
   1064         }
   1065         if (serviceMap != null) {
   1066             Service service = serviceMap.get(key);
   1067             if (service != null) {
   1068                 return service;
   1069             }
   1070         }
   1071         ensureLegacyParsed();
   1072         return (legacyMap != null) ? legacyMap.get(key) : null;
   1073     }
   1074 
   1075     // ServiceKey from previous getService() call
   1076     // by re-using it if possible we avoid allocating a new object
   1077     // and the toUpperCase() call.
   1078     // re-use will occur e.g. as the framework traverses the provider
   1079     // list and queries each provider with the same values until it finds
   1080     // a matching service
   1081     private static volatile ServiceKey previousKey =
   1082                                             new ServiceKey("", "", false);
   1083 
   1084     /**
   1085      * Get an unmodifiable Set of all services supported by
   1086      * this Provider.
   1087      *
   1088      * @return an unmodifiable Set of all services supported by
   1089      * this Provider
   1090      *
   1091      * @since 1.5
   1092      */
   1093     public synchronized Set<Service> getServices() {
   1094         checkInitialized();
   1095         if (legacyChanged || servicesChanged) {
   1096             serviceSet = null;
   1097         }
   1098         if (serviceSet == null) {
   1099             ensureLegacyParsed();
   1100             Set<Service> set = new LinkedHashSet<>();
   1101             if (serviceMap != null) {
   1102                 set.addAll(serviceMap.values());
   1103             }
   1104             if (legacyMap != null) {
   1105                 set.addAll(legacyMap.values());
   1106             }
   1107             serviceSet = Collections.unmodifiableSet(set);
   1108             servicesChanged = false;
   1109         }
   1110         return serviceSet;
   1111     }
   1112 
   1113     /**
   1114      * Add a service. If a service of the same type with the same algorithm
   1115      * name exists and it was added using {@link #putService putService()},
   1116      * it is replaced by the new service.
   1117      * This method also places information about this service
   1118      * in the provider's Hashtable values in the format described in the
   1119      * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1120      * Java Cryptography Architecture API Specification &amp; Reference </a>.
   1121      *
   1122      * <p>Also, if there is a security manager, its
   1123      * {@code checkSecurityAccess} method is called with the string
   1124      * {@code "putProviderProperty."+name}, where {@code name} is
   1125      * the provider name, to see if it's ok to set this provider's property
   1126      * values. If the default implementation of {@code checkSecurityAccess}
   1127      * is used (that is, that method is not overriden), then this results in
   1128      * a call to the security manager's {@code checkPermission} method with
   1129      * a {@code SecurityPermission("putProviderProperty."+name)}
   1130      * permission.
   1131      *
   1132      * @param s the Service to add
   1133      *
   1134      * @throws SecurityException
   1135      *      if a security manager exists and its {@link
   1136      *      java.lang.SecurityManager#checkSecurityAccess} method denies
   1137      *      access to set property values.
   1138      * @throws NullPointerException if s is null
   1139      *
   1140      * @since 1.5
   1141      */
   1142     protected synchronized void putService(Service s) {
   1143         check("putProviderProperty." + name);
   1144         if (debug != null) {
   1145             debug.println(name + ".putService(): " + s);
   1146         }
   1147         if (s == null) {
   1148             throw new NullPointerException();
   1149         }
   1150         if (s.getProvider() != this) {
   1151             throw new IllegalArgumentException
   1152                     ("service.getProvider() must match this Provider object");
   1153         }
   1154         if (serviceMap == null) {
   1155             serviceMap = new LinkedHashMap<ServiceKey,Service>();
   1156         }
   1157         servicesChanged = true;
   1158         String type = s.getType();
   1159         String algorithm = s.getAlgorithm();
   1160         ServiceKey key = new ServiceKey(type, algorithm, true);
   1161         // remove existing service
   1162         implRemoveService(serviceMap.get(key));
   1163         serviceMap.put(key, s);
   1164         for (String alias : s.getAliases()) {
   1165             serviceMap.put(new ServiceKey(type, alias, true), s);
   1166         }
   1167         putPropertyStrings(s);
   1168     }
   1169 
   1170     /**
   1171      * Put the string properties for this Service in this Provider's
   1172      * Hashtable.
   1173      */
   1174     private void putPropertyStrings(Service s) {
   1175         String type = s.getType();
   1176         String algorithm = s.getAlgorithm();
   1177         // use super() to avoid permission check and other processing
   1178         super.put(type + "." + algorithm, s.getClassName());
   1179         for (String alias : s.getAliases()) {
   1180             super.put(ALIAS_PREFIX + type + "." + alias, algorithm);
   1181         }
   1182         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
   1183             String key = type + "." + algorithm + " " + entry.getKey();
   1184             super.put(key, entry.getValue());
   1185         }
   1186         if (registered) {
   1187             Security.increaseVersion();
   1188         }
   1189     }
   1190 
   1191     /**
   1192      * Remove the string properties for this Service from this Provider's
   1193      * Hashtable.
   1194      */
   1195     private void removePropertyStrings(Service s) {
   1196         String type = s.getType();
   1197         String algorithm = s.getAlgorithm();
   1198         // use super() to avoid permission check and other processing
   1199         super.remove(type + "." + algorithm);
   1200         for (String alias : s.getAliases()) {
   1201             super.remove(ALIAS_PREFIX + type + "." + alias);
   1202         }
   1203         for (Map.Entry<UString,String> entry : s.attributes.entrySet()) {
   1204             String key = type + "." + algorithm + " " + entry.getKey();
   1205             super.remove(key);
   1206         }
   1207         if (registered) {
   1208           Security.increaseVersion();
   1209         }
   1210     }
   1211 
   1212     /**
   1213      * Remove a service previously added using
   1214      * {@link #putService putService()}. The specified service is removed from
   1215      * this provider. It will no longer be returned by
   1216      * {@link #getService getService()} and its information will be removed
   1217      * from this provider's Hashtable.
   1218      *
   1219      * <p>Also, if there is a security manager, its
   1220      * {@code checkSecurityAccess} method is called with the string
   1221      * {@code "removeProviderProperty."+name}, where {@code name} is
   1222      * the provider name, to see if it's ok to remove this provider's
   1223      * properties. If the default implementation of
   1224      * {@code checkSecurityAccess} is used (that is, that method is not
   1225      * overriden), then this results in a call to the security manager's
   1226      * {@code checkPermission} method with a
   1227      * {@code SecurityPermission("removeProviderProperty."+name)}
   1228      * permission.
   1229      *
   1230      * @param s the Service to be removed
   1231      *
   1232      * @throws  SecurityException
   1233      *          if a security manager exists and its {@link
   1234      *          java.lang.SecurityManager#checkSecurityAccess} method denies
   1235      *          access to remove this provider's properties.
   1236      * @throws NullPointerException if s is null
   1237      *
   1238      * @since 1.5
   1239      */
   1240     protected synchronized void removeService(Service s) {
   1241         check("removeProviderProperty." + name);
   1242         if (debug != null) {
   1243             debug.println(name + ".removeService(): " + s);
   1244         }
   1245         if (s == null) {
   1246             throw new NullPointerException();
   1247         }
   1248         implRemoveService(s);
   1249     }
   1250 
   1251     private void implRemoveService(Service s) {
   1252         if ((s == null) || (serviceMap == null)) {
   1253             return;
   1254         }
   1255         String type = s.getType();
   1256         String algorithm = s.getAlgorithm();
   1257         ServiceKey key = new ServiceKey(type, algorithm, false);
   1258         Service oldService = serviceMap.get(key);
   1259         if (s != oldService) {
   1260             return;
   1261         }
   1262         servicesChanged = true;
   1263         serviceMap.remove(key);
   1264         for (String alias : s.getAliases()) {
   1265             serviceMap.remove(new ServiceKey(type, alias, false));
   1266         }
   1267         removePropertyStrings(s);
   1268     }
   1269 
   1270     // Wrapped String that behaves in a case insensitive way for equals/hashCode
   1271     private static class UString {
   1272         final String string;
   1273         final String lowerString;
   1274 
   1275         UString(String s) {
   1276             this.string = s;
   1277             this.lowerString = s.toLowerCase(ENGLISH);
   1278         }
   1279 
   1280         public int hashCode() {
   1281             return lowerString.hashCode();
   1282         }
   1283 
   1284         public boolean equals(Object obj) {
   1285             if (this == obj) {
   1286                 return true;
   1287             }
   1288             if (obj instanceof UString == false) {
   1289                 return false;
   1290             }
   1291             UString other = (UString)obj;
   1292             return lowerString.equals(other.lowerString);
   1293         }
   1294 
   1295         public String toString() {
   1296             return string;
   1297         }
   1298     }
   1299 
   1300     // describe relevant properties of a type of engine
   1301     private static class EngineDescription {
   1302         final String name;
   1303         final boolean supportsParameter;
   1304         final String constructorParameterClassName;
   1305         private volatile Class<?> constructorParameterClass;
   1306 
   1307         EngineDescription(String name, boolean sp, String paramName) {
   1308             this.name = name;
   1309             this.supportsParameter = sp;
   1310             this.constructorParameterClassName = paramName;
   1311         }
   1312         Class<?> getConstructorParameterClass() throws ClassNotFoundException {
   1313             Class<?> clazz = constructorParameterClass;
   1314             if (clazz == null) {
   1315                 clazz = Class.forName(constructorParameterClassName);
   1316                 constructorParameterClass = clazz;
   1317             }
   1318             return clazz;
   1319         }
   1320     }
   1321 
   1322     // built in knowledge of the engine types shipped as part of the JDK
   1323     private static final Map<String,EngineDescription> knownEngines;
   1324 
   1325     private static void addEngine(String name, boolean sp, String paramName) {
   1326         EngineDescription ed = new EngineDescription(name, sp, paramName);
   1327         // also index by canonical name to avoid toLowerCase() for some lookups
   1328         knownEngines.put(name.toLowerCase(ENGLISH), ed);
   1329         knownEngines.put(name, ed);
   1330     }
   1331 
   1332     static {
   1333         knownEngines = new HashMap<String,EngineDescription>();
   1334         // JCA
   1335         addEngine("AlgorithmParameterGenerator",        false, null);
   1336         addEngine("AlgorithmParameters",                false, null);
   1337         addEngine("KeyFactory",                         false, null);
   1338         addEngine("KeyPairGenerator",                   false, null);
   1339         addEngine("KeyStore",                           false, null);
   1340         addEngine("MessageDigest",                      false, null);
   1341         addEngine("SecureRandom",                       false, null);
   1342         addEngine("Signature",                          true,  null);
   1343         addEngine("CertificateFactory",                 false, null);
   1344         addEngine("CertPathBuilder",                    false, null);
   1345         addEngine("CertPathValidator",                  false, null);
   1346         addEngine("CertStore",                          false,
   1347                             "java.security.cert.CertStoreParameters");
   1348         // JCE
   1349         addEngine("Cipher",                             true,  null);
   1350         addEngine("ExemptionMechanism",                 false, null);
   1351         addEngine("Mac",                                true,  null);
   1352         addEngine("KeyAgreement",                       true,  null);
   1353         addEngine("KeyGenerator",                       false, null);
   1354         addEngine("SecretKeyFactory",                   false, null);
   1355         // JSSE
   1356         addEngine("KeyManagerFactory",                  false, null);
   1357         addEngine("SSLContext",                         false, null);
   1358         addEngine("TrustManagerFactory",                false, null);
   1359         // JGSS
   1360         addEngine("GssApiMechanism",                    false, null);
   1361         // SASL
   1362         addEngine("SaslClientFactory",                  false, null);
   1363         addEngine("SaslServerFactory",                  false, null);
   1364         // POLICY
   1365         addEngine("Policy",                             false,
   1366                             "java.security.Policy$Parameters");
   1367         // CONFIGURATION
   1368         addEngine("Configuration",                      false,
   1369                             "javax.security.auth.login.Configuration$Parameters");
   1370         // XML DSig
   1371         addEngine("XMLSignatureFactory",                false, null);
   1372         addEngine("KeyInfoFactory",                     false, null);
   1373         addEngine("TransformService",                   false, null);
   1374         // Smart Card I/O
   1375         addEngine("TerminalFactory",                    false,
   1376                             "java.lang.Object");
   1377     }
   1378 
   1379     // get the "standard" (mixed-case) engine name for arbitary case engine name
   1380     // if there is no known engine by that name, return s
   1381     private static String getEngineName(String s) {
   1382         // try original case first, usually correct
   1383         EngineDescription e = knownEngines.get(s);
   1384         if (e == null) {
   1385             e = knownEngines.get(s.toLowerCase(ENGLISH));
   1386         }
   1387         return (e == null) ? s : e.name;
   1388     }
   1389 
   1390     /**
   1391      * The description of a security service. It encapsulates the properties
   1392      * of a service and contains a factory method to obtain new implementation
   1393      * instances of this service.
   1394      *
   1395      * <p>Each service has a provider that offers the service, a type,
   1396      * an algorithm name, and the name of the class that implements the
   1397      * service. Optionally, it also includes a list of alternate algorithm
   1398      * names for this service (aliases) and attributes, which are a map of
   1399      * (name, value) String pairs.
   1400      *
   1401      * <p>This class defines the methods {@link #supportsParameter
   1402      * supportsParameter()} and {@link #newInstance newInstance()}
   1403      * which are used by the Java security framework when it searches for
   1404      * suitable services and instantiates them. The valid arguments to those
   1405      * methods depend on the type of service. For the service types defined
   1406      * within Java SE, see the
   1407      * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1408      * Java Cryptography Architecture API Specification &amp; Reference </a>
   1409      * for the valid values.
   1410      * Note that components outside of Java SE can define additional types of
   1411      * services and their behavior.
   1412      *
   1413      * <p>Instances of this class are immutable.
   1414      *
   1415      * @since 1.5
   1416      */
   1417     public static class Service {
   1418 
   1419         private String type, algorithm, className;
   1420         private final Provider provider;
   1421         private List<String> aliases;
   1422         private Map<UString,String> attributes;
   1423 
   1424         // Reference to the cached implementation Class object
   1425         private volatile Reference<Class<?>> classRef;
   1426 
   1427         // flag indicating whether this service has its attributes for
   1428         // supportedKeyFormats or supportedKeyClasses set
   1429         // if null, the values have not been initialized
   1430         // if TRUE, at least one of supportedFormats/Classes is non null
   1431         private volatile Boolean hasKeyAttributes;
   1432 
   1433         // supported encoding formats
   1434         private String[] supportedFormats;
   1435 
   1436         // names of the supported key (super) classes
   1437         private Class[] supportedClasses;
   1438 
   1439         // whether this service has been registered with the Provider
   1440         private boolean registered;
   1441 
   1442         private static final Class<?>[] CLASS0 = new Class<?>[0];
   1443 
   1444         // this constructor and these methods are used for parsing
   1445         // the legacy string properties.
   1446 
   1447         private Service(Provider provider) {
   1448             this.provider = provider;
   1449             aliases = Collections.<String>emptyList();
   1450             attributes = Collections.<UString,String>emptyMap();
   1451         }
   1452 
   1453         private boolean isValid() {
   1454             return (type != null) && (algorithm != null) && (className != null);
   1455         }
   1456 
   1457         private void addAlias(String alias) {
   1458             if (aliases.isEmpty()) {
   1459                 aliases = new ArrayList<String>(2);
   1460             }
   1461             aliases.add(alias);
   1462         }
   1463 
   1464         void addAttribute(String type, String value) {
   1465             if (attributes.isEmpty()) {
   1466                 attributes = new HashMap<UString,String>(8);
   1467             }
   1468             attributes.put(new UString(type), value);
   1469         }
   1470 
   1471         /**
   1472          * Construct a new service.
   1473          *
   1474          * @param provider the provider that offers this service
   1475          * @param type the type of this service
   1476          * @param algorithm the algorithm name
   1477          * @param className the name of the class implementing this service
   1478          * @param aliases List of aliases or null if algorithm has no aliases
   1479          * @param attributes Map of attributes or null if this implementation
   1480          *                   has no attributes
   1481          *
   1482          * @throws NullPointerException if provider, type, algorithm, or
   1483          * className is null
   1484          */
   1485         public Service(Provider provider, String type, String algorithm,
   1486                 String className, List<String> aliases,
   1487                 Map<String,String> attributes) {
   1488             if ((provider == null) || (type == null) ||
   1489                     (algorithm == null) || (className == null)) {
   1490                 throw new NullPointerException();
   1491             }
   1492             this.provider = provider;
   1493             this.type = getEngineName(type);
   1494             this.algorithm = algorithm;
   1495             this.className = className;
   1496             if (aliases == null) {
   1497                 this.aliases = Collections.<String>emptyList();
   1498             } else {
   1499                 this.aliases = new ArrayList<String>(aliases);
   1500             }
   1501             if (attributes == null) {
   1502                 this.attributes = Collections.<UString,String>emptyMap();
   1503             } else {
   1504                 this.attributes = new HashMap<UString,String>();
   1505                 for (Map.Entry<String,String> entry : attributes.entrySet()) {
   1506                     this.attributes.put(new UString(entry.getKey()), entry.getValue());
   1507                 }
   1508             }
   1509         }
   1510 
   1511         /**
   1512          * Get the type of this service. For example, {@code MessageDigest}.
   1513          *
   1514          * @return the type of this service
   1515          */
   1516         public final String getType() {
   1517             return type;
   1518         }
   1519 
   1520         /**
   1521          * Return the name of the algorithm of this service. For example,
   1522          * {@code SHA-1}.
   1523          *
   1524          * @return the algorithm of this service
   1525          */
   1526         public final String getAlgorithm() {
   1527             return algorithm;
   1528         }
   1529 
   1530         /**
   1531          * Return the Provider of this service.
   1532          *
   1533          * @return the Provider of this service
   1534          */
   1535         public final Provider getProvider() {
   1536             return provider;
   1537         }
   1538 
   1539         /**
   1540          * Return the name of the class implementing this service.
   1541          *
   1542          * @return the name of the class implementing this service
   1543          */
   1544         public final String getClassName() {
   1545             return className;
   1546         }
   1547 
   1548         // internal only
   1549         private final List<String> getAliases() {
   1550             return aliases;
   1551         }
   1552 
   1553         /**
   1554          * Return the value of the specified attribute or null if this
   1555          * attribute is not set for this Service.
   1556          *
   1557          * @param name the name of the requested attribute
   1558          *
   1559          * @return the value of the specified attribute or null if the
   1560          *         attribute is not present
   1561          *
   1562          * @throws NullPointerException if name is null
   1563          */
   1564         public final String getAttribute(String name) {
   1565             if (name == null) {
   1566                 throw new NullPointerException();
   1567             }
   1568             return attributes.get(new UString(name));
   1569         }
   1570 
   1571         /**
   1572          * Return a new instance of the implementation described by this
   1573          * service. The security provider framework uses this method to
   1574          * construct implementations. Applications will typically not need
   1575          * to call it.
   1576          *
   1577          * <p>The default implementation uses reflection to invoke the
   1578          * standard constructor for this type of service.
   1579          * Security providers can override this method to implement
   1580          * instantiation in a different way.
   1581          * For details and the values of constructorParameter that are
   1582          * valid for the various types of services see the
   1583          * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1584          * Java Cryptography Architecture API Specification &amp;
   1585          * Reference</a>.
   1586          *
   1587          * @param constructorParameter the value to pass to the constructor,
   1588          * or null if this type of service does not use a constructorParameter.
   1589          *
   1590          * @return a new implementation of this service
   1591          *
   1592          * @throws InvalidParameterException if the value of
   1593          * constructorParameter is invalid for this type of service.
   1594          * @throws NoSuchAlgorithmException if instantiation failed for
   1595          * any other reason.
   1596          */
   1597         public Object newInstance(Object constructorParameter)
   1598                 throws NoSuchAlgorithmException {
   1599             if (registered == false) {
   1600                 if (provider.getService(type, algorithm) != this) {
   1601                     throw new NoSuchAlgorithmException
   1602                         ("Service not registered with Provider "
   1603                         + provider.getName() + ": " + this);
   1604                 }
   1605                 registered = true;
   1606             }
   1607             try {
   1608                 EngineDescription cap = knownEngines.get(type);
   1609                 if (cap == null) {
   1610                     // unknown engine type, use generic code
   1611                     // this is the code path future for non-core
   1612                     // optional packages
   1613                     return newInstanceGeneric(constructorParameter);
   1614                 }
   1615                 if (cap.constructorParameterClassName == null) {
   1616                     if (constructorParameter != null) {
   1617                         throw new InvalidParameterException
   1618                             ("constructorParameter not used with " + type
   1619                             + " engines");
   1620                     }
   1621                     Class<?> clazz = getImplClass();
   1622                     Class<?>[] empty = {};
   1623                     Constructor<?> con = clazz.getConstructor(empty);
   1624                     return con.newInstance();
   1625                 } else {
   1626                     Class<?> paramClass = cap.getConstructorParameterClass();
   1627                     if (constructorParameter != null) {
   1628                         Class<?> argClass = constructorParameter.getClass();
   1629                         if (paramClass.isAssignableFrom(argClass) == false) {
   1630                             throw new InvalidParameterException
   1631                             ("constructorParameter must be instanceof "
   1632                             + cap.constructorParameterClassName.replace('$', '.')
   1633                             + " for engine type " + type);
   1634                         }
   1635                     }
   1636                     Class<?> clazz = getImplClass();
   1637                     Constructor<?> cons = clazz.getConstructor(paramClass);
   1638                     return cons.newInstance(constructorParameter);
   1639                 }
   1640             } catch (NoSuchAlgorithmException e) {
   1641                 throw e;
   1642             } catch (InvocationTargetException e) {
   1643                 throw new NoSuchAlgorithmException
   1644                     ("Error constructing implementation (algorithm: "
   1645                     + algorithm + ", provider: " + provider.getName()
   1646                     + ", class: " + className + ")", e.getCause());
   1647             } catch (Exception e) {
   1648                 throw new NoSuchAlgorithmException
   1649                     ("Error constructing implementation (algorithm: "
   1650                     + algorithm + ", provider: " + provider.getName()
   1651                     + ", class: " + className + ")", e);
   1652             }
   1653         }
   1654 
   1655         // return the implementation Class object for this service
   1656         private Class<?> getImplClass() throws NoSuchAlgorithmException {
   1657             try {
   1658                 Reference<Class<?>> ref = classRef;
   1659                 Class<?> clazz = (ref == null) ? null : ref.get();
   1660                 if (clazz == null) {
   1661                     ClassLoader cl = provider.getClass().getClassLoader();
   1662                     if (cl == null) {
   1663                         clazz = Class.forName(className);
   1664                     } else {
   1665                         clazz = cl.loadClass(className);
   1666                     }
   1667                     if (!Modifier.isPublic(clazz.getModifiers())) {
   1668                         throw new NoSuchAlgorithmException
   1669                             ("class configured for " + type + " (provider: " +
   1670                             provider.getName() + ") is not public.");
   1671                     }
   1672                     classRef = new WeakReference<Class<?>>(clazz);
   1673                 }
   1674                 return clazz;
   1675             } catch (ClassNotFoundException e) {
   1676                 throw new NoSuchAlgorithmException
   1677                     ("class configured for " + type + " (provider: " +
   1678                     provider.getName() + ") cannot be found.", e);
   1679             }
   1680         }
   1681 
   1682         /**
   1683          * Generic code path for unknown engine types. Call the
   1684          * no-args constructor if constructorParameter is null, otherwise
   1685          * use the first matching constructor.
   1686          */
   1687         private Object newInstanceGeneric(Object constructorParameter)
   1688                 throws Exception {
   1689             Class<?> clazz = getImplClass();
   1690             if (constructorParameter == null) {
   1691                 // create instance with public no-arg constructor if it exists
   1692                 try {
   1693                     Class<?>[] empty = {};
   1694                     Constructor<?> con = clazz.getConstructor(empty);
   1695                     return con.newInstance();
   1696                 } catch (NoSuchMethodException e) {
   1697                     throw new NoSuchAlgorithmException("No public no-arg "
   1698                         + "constructor found in class " + className);
   1699                 }
   1700             }
   1701             Class<?> argClass = constructorParameter.getClass();
   1702             Constructor[] cons = clazz.getConstructors();
   1703             // find first public constructor that can take the
   1704             // argument as parameter
   1705             for (Constructor<?> con : cons) {
   1706                 Class<?>[] paramTypes = con.getParameterTypes();
   1707                 if (paramTypes.length != 1) {
   1708                     continue;
   1709                 }
   1710                 if (paramTypes[0].isAssignableFrom(argClass) == false) {
   1711                     continue;
   1712                 }
   1713                 return con.newInstance(constructorParameter);
   1714             }
   1715             throw new NoSuchAlgorithmException("No public constructor matching "
   1716                 + argClass.getName() + " found in class " + className);
   1717         }
   1718 
   1719         /**
   1720          * Test whether this Service can use the specified parameter.
   1721          * Returns false if this service cannot use the parameter. Returns
   1722          * true if this service can use the parameter, if a fast test is
   1723          * infeasible, or if the status is unknown.
   1724          *
   1725          * <p>The security provider framework uses this method with
   1726          * some types of services to quickly exclude non-matching
   1727          * implementations for consideration.
   1728          * Applications will typically not need to call it.
   1729          *
   1730          * <p>For details and the values of parameter that are valid for the
   1731          * various types of services see the top of this class and the
   1732          * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
   1733          * Java Cryptography Architecture API Specification &amp;
   1734          * Reference</a>.
   1735          * Security providers can override it to implement their own test.
   1736          *
   1737          * @param parameter the parameter to test
   1738          *
   1739          * @return false if this this service cannot use the specified
   1740          * parameter; true if it can possibly use the parameter
   1741          *
   1742          * @throws InvalidParameterException if the value of parameter is
   1743          * invalid for this type of service or if this method cannot be
   1744          * used with this type of service
   1745          */
   1746         public boolean supportsParameter(Object parameter) {
   1747             EngineDescription cap = knownEngines.get(type);
   1748             if (cap == null) {
   1749                 // unknown engine type, return true by default
   1750                 return true;
   1751             }
   1752             if (cap.supportsParameter == false) {
   1753                 throw new InvalidParameterException("supportsParameter() not "
   1754                     + "used with " + type + " engines");
   1755             }
   1756             // allow null for keys without attributes for compatibility
   1757             if ((parameter != null) && (parameter instanceof Key == false)) {
   1758                 throw new InvalidParameterException
   1759                     ("Parameter must be instanceof Key for engine " + type);
   1760             }
   1761             if (hasKeyAttributes() == false) {
   1762                 return true;
   1763             }
   1764             if (parameter == null) {
   1765                 return false;
   1766             }
   1767             Key key = (Key)parameter;
   1768             if (supportsKeyFormat(key)) {
   1769                 return true;
   1770             }
   1771             if (supportsKeyClass(key)) {
   1772                 return true;
   1773             }
   1774             return false;
   1775         }
   1776 
   1777         /**
   1778          * Return whether this service has its Supported* properties for
   1779          * keys defined. Parses the attributes if not yet initialized.
   1780          */
   1781         private boolean hasKeyAttributes() {
   1782             Boolean b = hasKeyAttributes;
   1783             if (b == null) {
   1784                 synchronized (this) {
   1785                     String s;
   1786                     s = getAttribute("SupportedKeyFormats");
   1787                     if (s != null) {
   1788                         supportedFormats = s.split("\\|");
   1789                     }
   1790                     s = getAttribute("SupportedKeyClasses");
   1791                     if (s != null) {
   1792                         String[] classNames = s.split("\\|");
   1793                         List<Class<?>> classList =
   1794                             new ArrayList<>(classNames.length);
   1795                         for (String className : classNames) {
   1796                             Class<?> clazz = getKeyClass(className);
   1797                             if (clazz != null) {
   1798                                 classList.add(clazz);
   1799                             }
   1800                         }
   1801                         supportedClasses = classList.toArray(CLASS0);
   1802                     }
   1803                     boolean bool = (supportedFormats != null)
   1804                         || (supportedClasses != null);
   1805                     b = Boolean.valueOf(bool);
   1806                     hasKeyAttributes = b;
   1807                 }
   1808             }
   1809             return b.booleanValue();
   1810         }
   1811 
   1812         // get the key class object of the specified name
   1813         private Class<?> getKeyClass(String name) {
   1814             try {
   1815                 return Class.forName(name);
   1816             } catch (ClassNotFoundException e) {
   1817                 // ignore
   1818             }
   1819             try {
   1820                 ClassLoader cl = provider.getClass().getClassLoader();
   1821                 if (cl != null) {
   1822                     return cl.loadClass(name);
   1823                 }
   1824             } catch (ClassNotFoundException e) {
   1825                 // ignore
   1826             }
   1827             return null;
   1828         }
   1829 
   1830         private boolean supportsKeyFormat(Key key) {
   1831             if (supportedFormats == null) {
   1832                 return false;
   1833             }
   1834             String format = key.getFormat();
   1835             if (format == null) {
   1836                 return false;
   1837             }
   1838             for (String supportedFormat : supportedFormats) {
   1839                 if (supportedFormat.equals(format)) {
   1840                     return true;
   1841                 }
   1842             }
   1843             return false;
   1844         }
   1845 
   1846         private boolean supportsKeyClass(Key key) {
   1847             if (supportedClasses == null) {
   1848                 return false;
   1849             }
   1850             Class<?> keyClass = key.getClass();
   1851             for (Class<?> clazz : supportedClasses) {
   1852                 if (clazz.isAssignableFrom(keyClass)) {
   1853                     return true;
   1854                 }
   1855             }
   1856             return false;
   1857         }
   1858 
   1859         /**
   1860          * Return a String representation of this service.
   1861          *
   1862          * @return a String representation of this service.
   1863          */
   1864         public String toString() {
   1865             String aString = aliases.isEmpty()
   1866                 ? "" : "\r\n  aliases: " + aliases.toString();
   1867             String attrs = attributes.isEmpty()
   1868                 ? "" : "\r\n  attributes: " + attributes.toString();
   1869             return provider.getName() + ": " + type + "." + algorithm
   1870                 + " -> " + className + aString + attrs + "\r\n";
   1871         }
   1872 
   1873     }
   1874 
   1875     /**
   1876      * @hide
   1877      */
   1878     public void setRegistered() {
   1879         registered = true;
   1880     }
   1881 
   1882     /**
   1883      * @hide
   1884      */
   1885     public void setUnregistered() {
   1886         registered = false;
   1887     }
   1888 
   1889     /**
   1890      * @hide
   1891      */
   1892     public boolean isRegistered() {
   1893         return registered;
   1894     }
   1895 
   1896     /**
   1897      * Ensure the values cached by {@link #getServices} and {@link #getService} are already computed
   1898      *
   1899      * Used by the zygote so that initialization is performed during preload for the providers
   1900      * available at that point.
   1901      *
   1902      * @hide
   1903      */
   1904     public synchronized void warmUpServiceProvision() {
   1905         checkInitialized();
   1906         // Further calls do nothing if the services didn't change. If not called here, it would
   1907         // parse legacy strings the first time that a service is requested.
   1908         ensureLegacyParsed();
   1909         // This call to getServices will update fields so that further calls will just return a
   1910         // stored field, if the services didn't change in the meantime.
   1911         getServices();
   1912     }
   1913 }
   1914