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