Provider.java revision 14481df9ffa74f4a37060be77e8befe5a6c9bf12
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
27package java.security;
28
29import java.io.*;
30import java.util.*;
31import java.util.concurrent.atomic.AtomicBoolean;
32
33import static java.util.Locale.ENGLISH;
34
35import java.lang.ref.*;
36import java.lang.reflect.*;
37import java.security.Security;
38import java.util.function.BiConsumer;
39import java.util.function.BiFunction;
40import 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 */
93public 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 = 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 = 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 = 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        // NOTE: The original OpenJDK code supported case-insensitive lookups on the list
1328        // of known engines.
1329        //
1330        // knownEngines.put(name.toLowerCase(ENGLISH), ed);
1331        knownEngines.put(name, ed);
1332    }
1333
1334    static {
1335        knownEngines = new HashMap<String,EngineDescription>();
1336        // JCA
1337        addEngine("AlgorithmParameterGenerator",        false, null);
1338        addEngine("AlgorithmParameters",                false, null);
1339        addEngine("KeyFactory",                         false, null);
1340        addEngine("KeyPairGenerator",                   false, null);
1341        addEngine("KeyStore",                           false, null);
1342        addEngine("MessageDigest",                      false, null);
1343        addEngine("SecureRandom",                       false, null);
1344        addEngine("Signature",                          true,  null);
1345        addEngine("CertificateFactory",                 false, null);
1346        addEngine("CertPathBuilder",                    false, null);
1347        addEngine("CertPathValidator",                  false, null);
1348        addEngine("CertStore",                          false,
1349                            "java.security.cert.CertStoreParameters");
1350        // JCE
1351        addEngine("Cipher",                             true,  null);
1352        addEngine("ExemptionMechanism",                 false, null);
1353        addEngine("Mac",                                true,  null);
1354        addEngine("KeyAgreement",                       true,  null);
1355        addEngine("KeyGenerator",                       false, null);
1356        addEngine("SecretKeyFactory",                   false, null);
1357        // JSSE
1358        addEngine("KeyManagerFactory",                  false, null);
1359        addEngine("SSLContext",                         false, null);
1360        addEngine("TrustManagerFactory",                false, null);
1361        // JGSS
1362        addEngine("GssApiMechanism",                    false, null);
1363        // SASL
1364        addEngine("SaslClientFactory",                  false, null);
1365        addEngine("SaslServerFactory",                  false, null);
1366        // POLICY
1367        addEngine("Policy",                             false,
1368                            "java.security.Policy$Parameters");
1369        // CONFIGURATION
1370        addEngine("Configuration",                      false,
1371                            "javax.security.auth.login.Configuration$Parameters");
1372        // XML DSig
1373        addEngine("XMLSignatureFactory",                false, null);
1374        addEngine("KeyInfoFactory",                     false, null);
1375        addEngine("TransformService",                   false, null);
1376        // Smart Card I/O
1377        addEngine("TerminalFactory",                    false,
1378                            "java.lang.Object");
1379    }
1380
1381    /**
1382     * The description of a security service. It encapsulates the properties
1383     * of a service and contains a factory method to obtain new implementation
1384     * instances of this service.
1385     *
1386     * <p>Each service has a provider that offers the service, a type,
1387     * an algorithm name, and the name of the class that implements the
1388     * service. Optionally, it also includes a list of alternate algorithm
1389     * names for this service (aliases) and attributes, which are a map of
1390     * (name, value) String pairs.
1391     *
1392     * <p>This class defines the methods {@link #supportsParameter
1393     * supportsParameter()} and {@link #newInstance newInstance()}
1394     * which are used by the Java security framework when it searches for
1395     * suitable services and instantiates them. The valid arguments to those
1396     * methods depend on the type of service. For the service types defined
1397     * within Java SE, see the
1398     * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
1399     * Java Cryptography Architecture API Specification &amp; Reference </a>
1400     * for the valid values.
1401     * Note that components outside of Java SE can define additional types of
1402     * services and their behavior.
1403     *
1404     * <p>Instances of this class are immutable.
1405     *
1406     * @since 1.5
1407     */
1408    public static class Service {
1409
1410        private String type, algorithm, className;
1411        private final Provider provider;
1412        private List<String> aliases;
1413        private Map<UString,String> attributes;
1414
1415        // Reference to the cached implementation Class object
1416        private volatile Reference<Class<?>> classRef;
1417
1418        // flag indicating whether this service has its attributes for
1419        // supportedKeyFormats or supportedKeyClasses set
1420        // if null, the values have not been initialized
1421        // if TRUE, at least one of supportedFormats/Classes is non null
1422        private volatile Boolean hasKeyAttributes;
1423
1424        // supported encoding formats
1425        private String[] supportedFormats;
1426
1427        // names of the supported key (super) classes
1428        private Class[] supportedClasses;
1429
1430        // whether this service has been registered with the Provider
1431        private boolean registered;
1432
1433        private static final Class<?>[] CLASS0 = new Class<?>[0];
1434
1435        // this constructor and these methods are used for parsing
1436        // the legacy string properties.
1437
1438        private Service(Provider provider) {
1439            this.provider = provider;
1440            aliases = Collections.<String>emptyList();
1441            attributes = Collections.<UString,String>emptyMap();
1442        }
1443
1444        private boolean isValid() {
1445            return (type != null) && (algorithm != null) && (className != null);
1446        }
1447
1448        private void addAlias(String alias) {
1449            if (aliases.isEmpty()) {
1450                aliases = new ArrayList<String>(2);
1451            }
1452            aliases.add(alias);
1453        }
1454
1455        void addAttribute(String type, String value) {
1456            if (attributes.isEmpty()) {
1457                attributes = new HashMap<UString,String>(8);
1458            }
1459            attributes.put(new UString(type), value);
1460        }
1461
1462        /**
1463         * Construct a new service.
1464         *
1465         * @param provider the provider that offers this service
1466         * @param type the type of this service
1467         * @param algorithm the algorithm name
1468         * @param className the name of the class implementing this service
1469         * @param aliases List of aliases or null if algorithm has no aliases
1470         * @param attributes Map of attributes or null if this implementation
1471         *                   has no attributes
1472         *
1473         * @throws NullPointerException if provider, type, algorithm, or
1474         * className is null
1475         */
1476        public Service(Provider provider, String type, String algorithm,
1477                String className, List<String> aliases,
1478                Map<String,String> attributes) {
1479            if ((provider == null) || (type == null) ||
1480                    (algorithm == null) || (className == null)) {
1481                throw new NullPointerException();
1482            }
1483            this.provider = provider;
1484            // Android-changed.
1485            this.type = type;
1486            this.algorithm = algorithm;
1487            this.className = className;
1488            if (aliases == null) {
1489                this.aliases = Collections.<String>emptyList();
1490            } else {
1491                this.aliases = new ArrayList<String>(aliases);
1492            }
1493            if (attributes == null) {
1494                this.attributes = Collections.<UString,String>emptyMap();
1495            } else {
1496                this.attributes = new HashMap<UString,String>();
1497                for (Map.Entry<String,String> entry : attributes.entrySet()) {
1498                    this.attributes.put(new UString(entry.getKey()), entry.getValue());
1499                }
1500            }
1501        }
1502
1503        /**
1504         * Get the type of this service. For example, {@code MessageDigest}.
1505         *
1506         * @return the type of this service
1507         */
1508        public final String getType() {
1509            return type;
1510        }
1511
1512        /**
1513         * Return the name of the algorithm of this service. For example,
1514         * {@code SHA-1}.
1515         *
1516         * @return the algorithm of this service
1517         */
1518        public final String getAlgorithm() {
1519            return algorithm;
1520        }
1521
1522        /**
1523         * Return the Provider of this service.
1524         *
1525         * @return the Provider of this service
1526         */
1527        public final Provider getProvider() {
1528            return provider;
1529        }
1530
1531        /**
1532         * Return the name of the class implementing this service.
1533         *
1534         * @return the name of the class implementing this service
1535         */
1536        public final String getClassName() {
1537            return className;
1538        }
1539
1540        // internal only
1541        private final List<String> getAliases() {
1542            return aliases;
1543        }
1544
1545        /**
1546         * Return the value of the specified attribute or null if this
1547         * attribute is not set for this Service.
1548         *
1549         * @param name the name of the requested attribute
1550         *
1551         * @return the value of the specified attribute or null if the
1552         *         attribute is not present
1553         *
1554         * @throws NullPointerException if name is null
1555         */
1556        public final String getAttribute(String name) {
1557            if (name == null) {
1558                throw new NullPointerException();
1559            }
1560            return attributes.get(new UString(name));
1561        }
1562
1563        /**
1564         * Return a new instance of the implementation described by this
1565         * service. The security provider framework uses this method to
1566         * construct implementations. Applications will typically not need
1567         * to call it.
1568         *
1569         * <p>The default implementation uses reflection to invoke the
1570         * standard constructor for this type of service.
1571         * Security providers can override this method to implement
1572         * instantiation in a different way.
1573         * For details and the values of constructorParameter that are
1574         * valid for the various types of services see the
1575         * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
1576         * Java Cryptography Architecture API Specification &amp;
1577         * Reference</a>.
1578         *
1579         * @param constructorParameter the value to pass to the constructor,
1580         * or null if this type of service does not use a constructorParameter.
1581         *
1582         * @return a new implementation of this service
1583         *
1584         * @throws InvalidParameterException if the value of
1585         * constructorParameter is invalid for this type of service.
1586         * @throws NoSuchAlgorithmException if instantiation failed for
1587         * any other reason.
1588         */
1589        public Object newInstance(Object constructorParameter)
1590                throws NoSuchAlgorithmException {
1591            if (registered == false) {
1592                if (provider.getService(type, algorithm) != this) {
1593                    throw new NoSuchAlgorithmException
1594                        ("Service not registered with Provider "
1595                        + provider.getName() + ": " + this);
1596                }
1597                registered = true;
1598            }
1599            try {
1600                EngineDescription cap = knownEngines.get(type);
1601                if (cap == null) {
1602                    // unknown engine type, use generic code
1603                    // this is the code path future for non-core
1604                    // optional packages
1605                    return newInstanceGeneric(constructorParameter);
1606                }
1607                if (cap.constructorParameterClassName == null) {
1608                    if (constructorParameter != null) {
1609                        throw new InvalidParameterException
1610                            ("constructorParameter not used with " + type
1611                            + " engines");
1612                    }
1613                    Class<?> clazz = getImplClass();
1614                    Class<?>[] empty = {};
1615                    Constructor<?> con = clazz.getConstructor(empty);
1616                    return con.newInstance();
1617                } else {
1618                    Class<?> paramClass = cap.getConstructorParameterClass();
1619                    if (constructorParameter != null) {
1620                        Class<?> argClass = constructorParameter.getClass();
1621                        if (paramClass.isAssignableFrom(argClass) == false) {
1622                            throw new InvalidParameterException
1623                            ("constructorParameter must be instanceof "
1624                            + cap.constructorParameterClassName.replace('$', '.')
1625                            + " for engine type " + type);
1626                        }
1627                    }
1628                    Class<?> clazz = getImplClass();
1629                    Constructor<?> cons = clazz.getConstructor(paramClass);
1630                    return cons.newInstance(constructorParameter);
1631                }
1632            } catch (NoSuchAlgorithmException e) {
1633                throw e;
1634            } catch (InvocationTargetException e) {
1635                throw new NoSuchAlgorithmException
1636                    ("Error constructing implementation (algorithm: "
1637                    + algorithm + ", provider: " + provider.getName()
1638                    + ", class: " + className + ")", e.getCause());
1639            } catch (Exception e) {
1640                throw new NoSuchAlgorithmException
1641                    ("Error constructing implementation (algorithm: "
1642                    + algorithm + ", provider: " + provider.getName()
1643                    + ", class: " + className + ")", e);
1644            }
1645        }
1646
1647        // return the implementation Class object for this service
1648        private Class<?> getImplClass() throws NoSuchAlgorithmException {
1649            try {
1650                Reference<Class<?>> ref = classRef;
1651                Class<?> clazz = (ref == null) ? null : ref.get();
1652                if (clazz == null) {
1653                    ClassLoader cl = provider.getClass().getClassLoader();
1654                    if (cl == null) {
1655                        clazz = Class.forName(className);
1656                    } else {
1657                        clazz = cl.loadClass(className);
1658                    }
1659                    if (!Modifier.isPublic(clazz.getModifiers())) {
1660                        throw new NoSuchAlgorithmException
1661                            ("class configured for " + type + " (provider: " +
1662                            provider.getName() + ") is not public.");
1663                    }
1664                    classRef = new WeakReference<Class<?>>(clazz);
1665                }
1666                return clazz;
1667            } catch (ClassNotFoundException e) {
1668                throw new NoSuchAlgorithmException
1669                    ("class configured for " + type + " (provider: " +
1670                    provider.getName() + ") cannot be found.", e);
1671            }
1672        }
1673
1674        /**
1675         * Generic code path for unknown engine types. Call the
1676         * no-args constructor if constructorParameter is null, otherwise
1677         * use the first matching constructor.
1678         */
1679        private Object newInstanceGeneric(Object constructorParameter)
1680                throws Exception {
1681            Class<?> clazz = getImplClass();
1682            if (constructorParameter == null) {
1683                // create instance with public no-arg constructor if it exists
1684                try {
1685                    Class<?>[] empty = {};
1686                    Constructor<?> con = clazz.getConstructor(empty);
1687                    return con.newInstance();
1688                } catch (NoSuchMethodException e) {
1689                    throw new NoSuchAlgorithmException("No public no-arg "
1690                        + "constructor found in class " + className);
1691                }
1692            }
1693            Class<?> argClass = constructorParameter.getClass();
1694            Constructor[] cons = clazz.getConstructors();
1695            // find first public constructor that can take the
1696            // argument as parameter
1697            for (Constructor<?> con : cons) {
1698                Class<?>[] paramTypes = con.getParameterTypes();
1699                if (paramTypes.length != 1) {
1700                    continue;
1701                }
1702                if (paramTypes[0].isAssignableFrom(argClass) == false) {
1703                    continue;
1704                }
1705                return con.newInstance(constructorParameter);
1706            }
1707            throw new NoSuchAlgorithmException("No public constructor matching "
1708                + argClass.getName() + " found in class " + className);
1709        }
1710
1711        /**
1712         * Test whether this Service can use the specified parameter.
1713         * Returns false if this service cannot use the parameter. Returns
1714         * true if this service can use the parameter, if a fast test is
1715         * infeasible, or if the status is unknown.
1716         *
1717         * <p>The security provider framework uses this method with
1718         * some types of services to quickly exclude non-matching
1719         * implementations for consideration.
1720         * Applications will typically not need to call it.
1721         *
1722         * <p>For details and the values of parameter that are valid for the
1723         * various types of services see the top of this class and the
1724         * <a href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/crypto/CryptoSpec.html">
1725         * Java Cryptography Architecture API Specification &amp;
1726         * Reference</a>.
1727         * Security providers can override it to implement their own test.
1728         *
1729         * @param parameter the parameter to test
1730         *
1731         * @return false if this this service cannot use the specified
1732         * parameter; true if it can possibly use the parameter
1733         *
1734         * @throws InvalidParameterException if the value of parameter is
1735         * invalid for this type of service or if this method cannot be
1736         * used with this type of service
1737         */
1738        public boolean supportsParameter(Object parameter) {
1739            EngineDescription cap = knownEngines.get(type);
1740            if (cap == null) {
1741                // unknown engine type, return true by default
1742                return true;
1743            }
1744            if (cap.supportsParameter == false) {
1745                throw new InvalidParameterException("supportsParameter() not "
1746                    + "used with " + type + " engines");
1747            }
1748            // allow null for keys without attributes for compatibility
1749            if ((parameter != null) && (parameter instanceof Key == false)) {
1750                throw new InvalidParameterException
1751                    ("Parameter must be instanceof Key for engine " + type);
1752            }
1753            if (hasKeyAttributes() == false) {
1754                return true;
1755            }
1756            if (parameter == null) {
1757                return false;
1758            }
1759            Key key = (Key)parameter;
1760            if (supportsKeyFormat(key)) {
1761                return true;
1762            }
1763            if (supportsKeyClass(key)) {
1764                return true;
1765            }
1766            return false;
1767        }
1768
1769        /**
1770         * Return whether this service has its Supported* properties for
1771         * keys defined. Parses the attributes if not yet initialized.
1772         */
1773        private boolean hasKeyAttributes() {
1774            Boolean b = hasKeyAttributes;
1775            if (b == null) {
1776                synchronized (this) {
1777                    String s;
1778                    s = getAttribute("SupportedKeyFormats");
1779                    if (s != null) {
1780                        supportedFormats = s.split("\\|");
1781                    }
1782                    s = getAttribute("SupportedKeyClasses");
1783                    if (s != null) {
1784                        String[] classNames = s.split("\\|");
1785                        List<Class<?>> classList =
1786                            new ArrayList<>(classNames.length);
1787                        for (String className : classNames) {
1788                            Class<?> clazz = getKeyClass(className);
1789                            if (clazz != null) {
1790                                classList.add(clazz);
1791                            }
1792                        }
1793                        supportedClasses = classList.toArray(CLASS0);
1794                    }
1795                    boolean bool = (supportedFormats != null)
1796                        || (supportedClasses != null);
1797                    b = Boolean.valueOf(bool);
1798                    hasKeyAttributes = b;
1799                }
1800            }
1801            return b.booleanValue();
1802        }
1803
1804        // get the key class object of the specified name
1805        private Class<?> getKeyClass(String name) {
1806            try {
1807                return Class.forName(name);
1808            } catch (ClassNotFoundException e) {
1809                // ignore
1810            }
1811            try {
1812                ClassLoader cl = provider.getClass().getClassLoader();
1813                if (cl != null) {
1814                    return cl.loadClass(name);
1815                }
1816            } catch (ClassNotFoundException e) {
1817                // ignore
1818            }
1819            return null;
1820        }
1821
1822        private boolean supportsKeyFormat(Key key) {
1823            if (supportedFormats == null) {
1824                return false;
1825            }
1826            String format = key.getFormat();
1827            if (format == null) {
1828                return false;
1829            }
1830            for (String supportedFormat : supportedFormats) {
1831                if (supportedFormat.equals(format)) {
1832                    return true;
1833                }
1834            }
1835            return false;
1836        }
1837
1838        private boolean supportsKeyClass(Key key) {
1839            if (supportedClasses == null) {
1840                return false;
1841            }
1842            Class<?> keyClass = key.getClass();
1843            for (Class<?> clazz : supportedClasses) {
1844                if (clazz.isAssignableFrom(keyClass)) {
1845                    return true;
1846                }
1847            }
1848            return false;
1849        }
1850
1851        /**
1852         * Return a String representation of this service.
1853         *
1854         * @return a String representation of this service.
1855         */
1856        public String toString() {
1857            String aString = aliases.isEmpty()
1858                ? "" : "\r\n  aliases: " + aliases.toString();
1859            String attrs = attributes.isEmpty()
1860                ? "" : "\r\n  attributes: " + attributes.toString();
1861            return provider.getName() + ": " + type + "." + algorithm
1862                + " -> " + className + aString + attrs + "\r\n";
1863        }
1864
1865    }
1866
1867    /**
1868     * @hide
1869     */
1870    public void setRegistered() {
1871        registered = true;
1872    }
1873
1874    /**
1875     * @hide
1876     */
1877    public void setUnregistered() {
1878        registered = false;
1879    }
1880
1881    /**
1882     * @hide
1883     */
1884    public boolean isRegistered() {
1885        return registered;
1886    }
1887
1888    /**
1889     * Ensure the values cached by {@link #getServices} and {@link #getService} are already computed
1890     *
1891     * Used by the zygote so that initialization is performed during preload for the providers
1892     * available at that point.
1893     *
1894     * @hide
1895     */
1896    public synchronized void warmUpServiceProvision() {
1897        checkInitialized();
1898        // Further calls do nothing if the services didn't change. If not called here, it would
1899        // parse legacy strings the first time that a service is requested.
1900        ensureLegacyParsed();
1901        // This call to getServices will update fields so that further calls will just return a
1902        // stored field, if the services didn't change in the meantime.
1903        getServices();
1904    }
1905}
1906