am 22d9a81f: am 85fdc823: am df171680: am 009ec47d: am 7c761052: am 8114da7b: resolved conflicts for merge of 590e76dd to jb-mr1-dev-plus-aosp
* commit '22d9a81fd5f77f57051ad46d51b085bdc2944e5a':
DO NOT MERGE: Add a way to get all values of an attribute of DN.
diff --git a/NOTICE b/NOTICE
index 818f6c5..951e506 100644
--- a/NOTICE
+++ b/NOTICE
@@ -32,7 +32,7 @@
== NOTICE file for the ICU License. ==
=========================================================================
-Copyright (c) 1995-2009 International Business Machines Corporation and others
+Copyright (c) 1995-2014 International Business Machines Corporation and others
All rights reserved.
@@ -66,250 +66,6 @@
=========================================================================
- == NOTICE file for the JUnit License. ==
- =========================================================================
-
-Common Public License - v 1.0
-
-THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON
-PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF
-THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
-
-1. DEFINITIONS
-
-"Contribution" means:
-
- a) in the case of the initial Contributor, the initial code and
- documentation distributed under this Agreement, and
- b) in the case of each subsequent Contributor:
-
- i) changes to the Program, and
-
- ii) additions to the Program;
-
- where such changes and/or additions to the Program originate
- from and are distributed by that particular Contributor. A
- Contribution 'originates' from a Contributor if it was added to
- the Program by such Contributor itself or anyone acting on such
- Contributor's behalf. Contributions do not include additions to
- the Program which: (i) are separate modules of software
- distributed in conjunction with the Program under their own
- license agreement, and (ii) are not derivative works of the
- Program.
-
-"Contributor" means any person or entity that distributes the Program.
-
-"Licensed Patents " mean patent claims licensable by a Contributor
-which are necessarily infringed by the use or sale of its Contribution
-alone or when combined with the Program.
-
-"Program" means the Contributions distributed in accordance with this
-Agreement.
-
-"Recipient" means anyone who receives the Program under this
-Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
- a) Subject to the terms of this Agreement, each Contributor
- hereby grants Recipient a non-exclusive, worldwide, royalty-free
- copyright license to reproduce, prepare derivative works of,
- publicly display, publicly perform, distribute and sublicense
- the Contribution of such Contributor, if any, and such
- derivative works, in source code and object code form.
-
- b) Subject to the terms of this Agreement, each Contributor
- hereby grants Recipient a non-exclusive, worldwide, royalty-free
- patent license under Licensed Patents to make, use, sell, offer
- to sell, import and otherwise transfer the Contribution of such
- Contributor, if any, in source code and object code form. This
- patent license shall apply to the combination of the
- Contribution and the Program if, at the time the Contribution is
- added by the Contributor, such addition of the Contribution
- causes such combination to be covered by the Licensed Patents.
- The patent license shall not apply to any other combinations
- which include the Contribution. No hardware per se is licensed
- hereunder.
-
- c) Recipient understands that although each Contributor grants
- the licenses to its Contributions set forth herein, no
- assurances are provided by any Contributor that the Program does
- not infringe the patent or other intellectual property rights of
- any other entity. Each Contributor disclaims any liability to
- Recipient for claims brought by any other entity based on
- infringement of intellectual property rights or otherwise. As a
- condition to exercising the rights and licenses granted
- hereunder, each Recipient hereby assumes sole responsibility to
- secure any other intellectual property rights needed, if any.
- For example, if a third party patent license is required to
- allow Recipient to distribute the Program, it is Recipient's
- responsibility to acquire that license before distributing the
- Program.
-
- d) Each Contributor represents that to its knowledge it has
- sufficient copyright rights in its Contribution, if any, to
- grant the copyright license set forth in this Agreement.
-
-3. REQUIREMENTS
-
-A Contributor may choose to distribute the Program in object code form
-under its own license agreement, provided that:
-
- a) it complies with the terms and conditions of this Agreement; and
-
- b) its license agreement:
-
- i) effectively disclaims on behalf of all Contributors all
- warranties and conditions, express and implied, including
- warranties or conditions of title and non-infringement, and
- implied warranties or conditions of merchantability and fitness
- for a particular purpose;
-
- ii) effectively excludes on behalf of all Contributors all
- liability for damages, including direct, indirect, special,
- incidental and consequential damages, such as lost profits;
-
- iii) states that any provisions which differ from this Agreement
- are offered by that Contributor alone and not by any other
- party; and
-
- iv) states that source code for the Program is available from
- such Contributor, and informs licensees how to obtain it in a
- reasonable manner on or through a medium customarily used for
- software exchange.
-
-When the Program is made available in source code form:
-
- a) it must be made available under this Agreement; and
-
- b) a copy of this Agreement must be included with each copy of
- the Program.
-
-Contributors may not remove or alter any copyright notices contained
-within the Program.
-
-Each Contributor must identify itself as the originator of its
-Contribution, if any, in a manner that reasonably allows subsequent
-Recipients to identify the originator of the Contribution.
-
-4. COMMERCIAL DISTRIBUTION
-
-Commercial distributors of software may accept certain
-responsibilities with respect to end users, business partners and the
-like. While this license is intended to facilitate the commercial use
-of the Program, the Contributor who includes the Program in a
-commercial product offering should do so in a manner which does not
-create potential liability for other Contributors. Therefore, if a
-Contributor includes the Program in a commercial product offering,
-such Contributor ("Commercial Contributor") hereby agrees to defend
-and indemnify every other Contributor ("Indemnified Contributor")
-against any losses, damages and costs (collectively "Losses") arising
-from claims, lawsuits and other legal actions brought by a third party
-against the Indemnified Contributor to the extent caused by the acts
-or omissions of such Commercial Contributor in connection with its
-distribution of the Program in a commercial product offering. The
-obligations in this section do not apply to any claims or Losses
-relating to any actual or alleged intellectual property infringement.
-In order to qualify, an Indemnified Contributor must: a) promptly
-notify the Commercial Contributor in writing of such claim, and b)
-allow the Commercial Contributor to control, and cooperate with the
-Commercial Contributor in, the defense and any related settlement
-negotiations. The Indemnified Contributor may participate in any such
-claim at its own expense.
-
-For example, a Contributor might include the Program in a commercial
-product offering, Product X. That Contributor is then a Commercial
-Contributor. If that Commercial Contributor then makes performance
-claims, or offers warranties related to Product X, those performance
-claims and warranties are such Commercial Contributor's responsibility
-alone. Under this section, the Commercial Contributor would have to
-defend claims against the other Contributors related to those
-performance claims and warranties, and if a court requires any other
-Contributor to pay any damages as a result, the Commercial Contributor
-must pay those damages.
-
-5. NO WARRANTY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
-PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
-WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
-OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
-responsible for determining the appropriateness of using and
-distributing the Program and assumes all risks associated with its
-exercise of rights under this Agreement, including but not limited to
-the risks and costs of program errors, compliance with applicable
-laws, damage to or loss of data, programs or equipment, and
-unavailability or interruption of operations.
-
-6. DISCLAIMER OF LIABILITY
-
-EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
-ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
-INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
-WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
-DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-7. GENERAL
-
-If any provision of this Agreement is invalid or unenforceable under
-applicable law, it shall not affect the validity or enforceability of
-the remainder of the terms of this Agreement, and without further
-action by the parties hereto, such provision shall be reformed to the
-minimum extent necessary to make such provision valid and enforceable.
-
-If Recipient institutes patent litigation against a Contributor with
-respect to a patent applicable to software (including a cross-claim or
-counterclaim in a lawsuit), then any patent licenses granted by that
-Contributor to such Recipient under this Agreement shall terminate as
-of the date such litigation is filed. In addition, if Recipient
-institutes patent litigation against any entity (including a
-cross-claim or counterclaim in a lawsuit) alleging that the Program
-itself (excluding combinations of the Program with other software or
-hardware) infringes such Recipient's patent(s), then such Recipient's
-rights granted under Section 2(b) shall terminate as of the date such
-litigation is filed.
-
-All Recipient's rights under this Agreement shall terminate if it
-fails to comply with any of the material terms or conditions of this
-Agreement and does not cure such failure in a reasonable period of
-time after becoming aware of such noncompliance. If all Recipient's
-rights under this Agreement terminate, Recipient agrees to cease use
-and distribution of the Program as soon as reasonably practicable.
-However, Recipient's obligations under this Agreement and any licenses
-granted by Recipient relating to the Program shall continue and
-survive.
-
-Everyone is permitted to copy and distribute copies of this Agreement,
-but in order to avoid inconsistency the Agreement is copyrighted and
-may only be modified in the following manner. The Agreement Steward
-reserves the right to publish new versions (including revisions) of
-this Agreement from time to time. No one other than the Agreement
-Steward has the right to modify this Agreement. IBM is the initial
-Agreement Steward. IBM may assign the responsibility to serve as the
-Agreement Steward to a suitable separate entity. Each new version of
-the Agreement will be given a distinguishing version number. The
-Program (including Contributions) may always be distributed subject to
-the version of the Agreement under which it was received. In addition,
-after a new version of the Agreement is published, Contributor may
-elect to distribute the Program (including its Contributions) under
-the new version. Except as expressly stated in Sections 2(a) and 2(b)
-above, Recipient receives no rights or licenses to the intellectual
-property of any Contributor under this Agreement, whether expressly,
-by implication, estoppel or otherwise. All rights in the Program not
-expressly granted under this Agreement are reserved.
-
-This Agreement is governed by the laws of the State of New York and
-the intellectual property laws of the United States of America. No
-party to this Agreement will bring a legal action under this Agreement
-more than one year after the cause of action arose. Each party waives
-its rights to a jury trial in any resulting litigation.
-
-
- =========================================================================
== NOTICE file for the KXML License. ==
=========================================================================
@@ -336,38 +92,6 @@
=========================================================================
- == NOTICE file for the SQLite Java Wrapper License. ==
- =========================================================================
-
-This software is copyrighted by Christian Werner <chw@ch-werner.de>
-and others. The following terms apply to all files associated with the
-software unless explicitly disclaimed in individual files.
-
-The authors hereby grant permission to use, copy, modify, distribute,
-and license this software and its documentation for any purpose, provided
-that existing copyright notices are retained in all copies and that this
-notice is included verbatim in any distributions. No written agreement,
-license, or royalty fee is required for any of the authorized uses.
-Modifications to this software may be copyrighted by their authors
-and need not follow the licensing terms described here, provided that
-the new terms are clearly indicated on the first page of each file where
-they apply.
-
-IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
-FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
-ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
-DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
-
-THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
-IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
-NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
-MODIFICATIONS.
-
-
- =========================================================================
== NOTICE file for the W3C License. ==
=========================================================================
diff --git a/NativeCode.mk b/NativeCode.mk
index 12e8114..0ae615e 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -66,7 +66,7 @@
core_c_includes := libcore/include $(LOCAL_C_INCLUDES)
core_shared_libraries := $(LOCAL_SHARED_LIBRARIES)
core_static_libraries := $(LOCAL_STATIC_LIBRARIES)
-core_cflags := -Wall -Wextra -Werror
+core_cflags := $(LOCAL_CFLAGS) -Wall -Wextra -Werror
core_cppflags += -std=gnu++11
core_test_files := \
diff --git a/benchmarks/src/benchmarks/ReferenceGetBenchmark.java b/benchmarks/src/benchmarks/ReferenceGetBenchmark.java
new file mode 100644
index 0000000..80142a1
--- /dev/null
+++ b/benchmarks/src/benchmarks/ReferenceGetBenchmark.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package benchmarks;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.*;
+
+public class ReferenceGetBenchmark extends SimpleBenchmark {
+ @Param boolean intrinsicDisabled;
+
+ private Object obj = "str";
+
+ protected void setUp() throws Exception {
+ Field intrinsicDisabledField = Reference.class.getDeclaredField("disableIntrinsic");
+ intrinsicDisabledField.setAccessible(true);
+ intrinsicDisabledField.setBoolean(null, intrinsicDisabled);
+ }
+
+ public void timeSoftReferenceGet(int reps) throws Exception {
+ Reference soft = new SoftReference(obj);
+ for (int i = 0; i < reps; i++) {
+ Object o = soft.get();
+ }
+ }
+
+ public void timeWeakReferenceGet(int reps) throws Exception {
+ Reference weak = new WeakReference(obj);
+ for (int i = 0; i < reps; i++) {
+ Object o = weak.get();
+ }
+ }
+
+ public void timeNonPreservedWeakReferenceGet(int reps) throws Exception {
+ Reference weak = new WeakReference(obj);
+ obj = null;
+ Runtime.getRuntime().gc();
+ for (int i = 0; i < reps; i++) {
+ Object o = weak.get();
+ }
+ }
+}
diff --git a/benchmarks/src/benchmarks/regression/MathBenchmark.java b/benchmarks/src/benchmarks/regression/MathBenchmark.java
index 25a871d..19b2162 100644
--- a/benchmarks/src/benchmarks/regression/MathBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/MathBenchmark.java
@@ -30,339 +30,456 @@
private final int i = 1;
private final long l = 1L;
- public void timeAbsD(int reps) {
+ // NOTE: To avoid the benchmarked function from being optimized away, we store the result
+ // and use it as the benchmark's return value. This is good enough for now but may not be in
+ // the future, a smart compiler could determine that the result value will depend on whether
+ // we get into the loop or not and turn the whole loop into an if statement.
+
+ public double timeAbsD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.abs(d);
+ result = Math.abs(d);
}
+ return result;
}
- public void timeAbsF(int reps) {
+ public float timeAbsF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.abs(f);
+ result = Math.abs(f);
}
+ return result;
}
- public void timeAbsI(int reps) {
+ public int timeAbsI(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.abs(i);
+ result = Math.abs(i);
}
+ return result;
}
- public void timeAbsL(int reps) {
+ public long timeAbsL(int reps) {
+ long result = l;
for (int rep = 0; rep < reps; ++rep) {
- Math.abs(l);
+ result = Math.abs(l);
}
+ return result;
}
- public void timeAcos(int reps) {
+ public double timeAcos(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.acos(d);
+ result = Math.acos(d);
}
+ return result;
}
- public void timeAsin(int reps) {
+ public double timeAsin(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.asin(d);
+ result = Math.asin(d);
}
+ return result;
}
- public void timeAtan(int reps) {
+ public double timeAtan(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.atan(d);
+ result = Math.atan(d);
}
+ return result;
}
- public void timeAtan2(int reps) {
+ public double timeAtan2(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.atan2(3, 4);
+ result = Math.atan2(3, 4);
}
+ return result;
}
- public void timeCbrt(int reps) {
+ public double timeCbrt(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.cbrt(d);
+ result = Math.cbrt(d);
}
+ return result;
}
- public void timeCeil(int reps) {
+ public double timeCeil(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.ceil(d);
+ result = Math.ceil(d);
}
+ return result;
}
- public void timeCopySignD(int reps) {
+ public double timeCopySignD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.copySign(d, d);
+ result = Math.copySign(d, d);
}
+ return result;
}
- public void timeCopySignF(int reps) {
+ public float timeCopySignF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.copySign(f, f);
+ result = Math.copySign(f, f);
}
+ return result;
}
- public void timeCopySignD_strict(int reps) {
+ public double timeCopySignD_strict(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- StrictMath.copySign(d, d);
+ result = StrictMath.copySign(d, d);
}
+ return result;
}
- public void timeCopySignF_strict(int reps) {
+ public float timeCopySignF_strict(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- StrictMath.copySign(f, f);
+ result = StrictMath.copySign(f, f);
}
+ return result;
}
- public void timeCos(int reps) {
+ public double timeCos(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.cos(d);
+ result = Math.cos(d);
}
+ return result;
}
- public void timeCosh(int reps) {
+ public double timeCosh(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.cosh(d);
+ result = Math.cosh(d);
}
+ return result;
}
- public void timeExp(int reps) {
+ public double timeExp(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.exp(d);
+ result = Math.exp(d);
}
+ return result;
}
- public void timeExpm1(int reps) {
+ public double timeExpm1(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.expm1(d);
+ result = Math.expm1(d);
}
+ return result;
}
- public void timeFloor(int reps) {
+ public double timeFloor(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.floor(d);
+ result = Math.floor(d);
}
+ return result;
}
- public void timeGetExponentD(int reps) {
+ public int timeGetExponentD(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.getExponent(d);
+ result = Math.getExponent(d);
}
+ return result;
}
- public void timeGetExponentF(int reps) {
+ public int timeGetExponentF(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.getExponent(f);
+ result = Math.getExponent(f);
}
+ return result;
}
- public void timeHypot(int reps) {
+ public double timeHypot(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.hypot(d, d);
+ result = Math.hypot(d, d);
}
+ return result;
}
- public void timeIEEEremainder(int reps) {
+ public double timeIEEEremainder(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.IEEEremainder(d, d);
+ result = Math.IEEEremainder(d, d);
}
+ return result;
}
- public void timeLog(int reps) {
+ public double timeLog(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.log(d);
+ result = Math.log(d);
}
+ return result;
}
- public void timeLog10(int reps) {
+ public double timeLog10(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.log10(d);
+ result = Math.log10(d);
}
+ return result;
}
- public void timeLog1p(int reps) {
+ public double timeLog1p(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.log1p(d);
+ result = Math.log1p(d);
}
+ return result;
}
- public void timeMaxD(int reps) {
+ public double timeMaxD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.max(d, d);
+ result = Math.max(d, d);
}
+ return result;
}
- public void timeMaxF(int reps) {
+ public float timeMaxF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.max(f, f);
+ result = Math.max(f, f);
}
+ return result;
}
- public void timeMaxI(int reps) {
+ public int timeMaxI(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.max(i, i);
+ result = Math.max(i, i);
}
+ return result;
}
- public void timeMaxL(int reps) {
+ public long timeMaxL(int reps) {
+ long result = l;
for (int rep = 0; rep < reps; ++rep) {
- Math.max(l, l);
+ result = Math.max(l, l);
}
+ return result;
}
- public void timeMinD(int reps) {
+ public double timeMinD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.min(d, d);
+ result = Math.min(d, d);
}
+ return result;
}
- public void timeMinF(int reps) {
+ public float timeMinF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.min(f, f);
+ result = Math.min(f, f);
}
+ return result;
}
- public void timeMinI(int reps) {
+ public int timeMinI(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.min(i, i);
+ result = Math.min(i, i);
}
+ return result;
}
- public void timeMinL(int reps) {
+ public long timeMinL(int reps) {
+ long result = l;
for (int rep = 0; rep < reps; ++rep) {
- Math.min(l, l);
+ result = Math.min(l, l);
}
+ return result;
}
- public void timeNextAfterD(int reps) {
+ public double timeNextAfterD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.nextAfter(d, d);
+ result = Math.nextAfter(d, d);
}
+ return result;
}
- public void timeNextAfterF(int reps) {
+ public float timeNextAfterF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.nextAfter(f, f);
+ result = Math.nextAfter(f, f);
}
+ return result;
}
- public void timeNextUpD(int reps) {
+ public double timeNextUpD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.nextUp(d);
+ result = Math.nextUp(d);
}
+ return result;
}
- public void timeNextUpF(int reps) {
+ public float timeNextUpF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.nextUp(f);
+ result = Math.nextUp(f);
}
+ return result;
}
- public void timePow(int reps) {
+ public double timePow(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.pow(d, d);
+ result = Math.pow(d, d);
}
+ return result;
}
- public void timeRandom(int reps) {
+ public double timeRandom(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.random();
+ result = Math.random();
}
+ return result;
}
- public void timeRint(int reps) {
+ public double timeRint(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.rint(d);
+ result = Math.rint(d);
}
+ return result;
}
- public void timeRoundD(int reps) {
+ public long timeRoundD(int reps) {
+ long result = l;
for (int rep = 0; rep < reps; ++rep) {
- Math.round(d);
+ result = Math.round(d);
}
+ return result;
}
- public void timeRoundF(int reps) {
+ public int timeRoundF(int reps) {
+ int result = i;
for (int rep = 0; rep < reps; ++rep) {
- Math.round(f);
+ result = Math.round(f);
}
+ return result;
}
- public void timeScalbD(int reps) {
+ public double timeScalbD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.scalb(d, 5);
+ result = Math.scalb(d, 5);
}
+ return result;
}
- public void timeScalbF(int reps) {
+ public float timeScalbF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.scalb(f, 5);
+ result = Math.scalb(f, 5);
}
+ return result;
}
- public void timeSignumD(int reps) {
+ public double timeSignumD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.signum(d);
+ result = Math.signum(d);
}
+ return result;
}
- public void timeSignumF(int reps) {
+ public float timeSignumF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.signum(f);
+ result = Math.signum(f);
}
+ return result;
}
- public void timeSin(int reps) {
+ public double timeSin(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.sin(d);
+ result = Math.sin(d);
}
+ return result;
}
- public void timeSinh(int reps) {
+ public double timeSinh(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.sinh(d);
+ result = Math.sinh(d);
}
+ return result;
}
- public void timeSqrt(int reps) {
+ public double timeSqrt(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.sqrt(d);
+ result = Math.sqrt(d);
}
+ return result;
}
- public void timeTan(int reps) {
+ public double timeTan(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.tan(d);
+ result = Math.tan(d);
}
+ return result;
}
- public void timeTanh(int reps) {
+ public double timeTanh(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.tanh(d);
+ result = Math.tanh(d);
}
+ return result;
}
- public void timeToDegrees(int reps) {
+ public double timeToDegrees(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.toDegrees(d);
+ result = Math.toDegrees(d);
}
+ return result;
}
- public void timeToRadians(int reps) {
+ public double timeToRadians(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.toRadians(d);
+ result = Math.toRadians(d);
}
+ return result;
}
- public void timeUlpD(int reps) {
+ public double timeUlpD(int reps) {
+ double result = d;
for (int rep = 0; rep < reps; ++rep) {
- Math.ulp(d);
+ result = Math.ulp(d);
}
+ return result;
}
- public void timeUlpF(int reps) {
+ public float timeUlpF(int reps) {
+ float result = f;
for (int rep = 0; rep < reps; ++rep) {
- Math.ulp(f);
+ result = Math.ulp(f);
}
+ return result;
}
}
diff --git a/benchmarks/src/benchmarks/regression/SSLSocketFactoryBenchmark.java b/benchmarks/src/benchmarks/regression/SSLSocketFactoryBenchmark.java
new file mode 100644
index 0000000..d0448d6
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/SSLSocketFactoryBenchmark.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import com.google.caliper.Param;
+import com.google.caliper.SimpleBenchmark;
+import javax.net.ssl.SSLSocketFactory;
+
+public class SSLSocketFactoryBenchmark extends SimpleBenchmark {
+ public void time(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ SSLSocketFactory.getDefault();
+ }
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/DexClassLoader.java b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
index ac2a70a5..a645f42 100644
--- a/dalvik/src/main/java/dalvik/system/DexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
@@ -24,9 +24,9 @@
* installed as part of an application.
*
* <p>This class loader requires an application-private, writable directory to
- * cache optimized classes. Use {@code Context.getDir(String, int)} to create
+ * cache optimized classes. Use {@code Context.getCodeCacheDir()} to create
* such a directory: <pre> {@code
- * File dexOutputDir = context.getDir("dex", 0);
+ * File dexOutputDir = context.getCodeCacheDir();
* }</pre>
*
* <p><strong>Do not cache optimized classes on external storage.</strong>
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 5a9c01a..8c78312 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -281,21 +281,15 @@
}
}
- /*
- * Open a DEX file. The value returned is a magic VM cookie. On
- * failure, an IOException is thrown.
- */
- private static long openDexFile(String sourceName, String outputName, int flags) throws IOException {
- return openDexFileNative(new File(sourceName).getCanonicalPath(),
- (outputName == null) ? null : new File(outputName).getCanonicalPath(),
- flags);
- }
-
private static native void closeDexFile(long cookie);
private static native Class defineClassNative(String name, ClassLoader loader, long cookie)
throws ClassNotFoundException, NoClassDefFoundError;
private static native String[] getClassNameList(long cookie);
- private static native long openDexFileNative(String sourceName, String outputName, int flags);
+ /*
+ * Open a DEX file. The value returned is a magic VM cookie. On
+ * failure, an IOException is thrown.
+ */
+ private static native long openDexFile(String sourceName, String outputName, int flags);
/**
* Returns true if the VM believes that the apk/jar file is out of date
diff --git a/dex/src/main/java/com/android/dex/DexException.java b/dex/src/main/java/com/android/dex/DexException.java
index a30a46f..ee0af18 100644
--- a/dex/src/main/java/com/android/dex/DexException.java
+++ b/dex/src/main/java/com/android/dex/DexException.java
@@ -22,7 +22,7 @@
* Thrown when there's a format problem reading, writing, or generally
* processing a dex file.
*/
-public final class DexException extends ExceptionWithContext {
+public class DexException extends ExceptionWithContext {
public DexException(String message) {
super(message);
}
diff --git a/dex/src/main/java/com/android/dex/DexIndexOverflowException.java b/dex/src/main/java/com/android/dex/DexIndexOverflowException.java
new file mode 100644
index 0000000..3226207
--- /dev/null
+++ b/dex/src/main/java/com/android/dex/DexIndexOverflowException.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dex;
+
+/**
+ * Thrown when there's an index overflow writing a dex file.
+ */
+public final class DexIndexOverflowException extends DexException {
+ public DexIndexOverflowException(String message) {
+ super(message);
+ }
+
+ public DexIndexOverflowException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 5b5803d..5cebb63 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -98,21 +98,6 @@
]
},
{
- description: "Some DecimalFormat tests fail, treating tests as broken while investigate further.",
- bug: 12781028,
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.tests.java.text.DecimalFormatTest#testSerializationSelf",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatD",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDLjava_lang_StringBufferLjava_text_FieldPosition",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDLjava_lang_StringBufferLjava_text_FieldPosition_problem_cases",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatD_2",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatJLjava_lang_StringBufferLjava_text_FieldPosition",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatToCharacterIterator_very_large",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_format_minus_zero"
- ]
-},
-{
description: "Fails in CTS, passes in CoreTestRunner.",
result: EXEC_FAILED,
names: [
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 0924bd4..94b1a59 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1374,89 +1374,37 @@
]
},
{
- description: "Known failures in klp-modular-dev branch being suppressed for dory / molly.",
- bug: 14674275,
- names: [
- "libcore.java.lang.SystemTest#testArrayCopyConcurrentModification",
- "libcore.java.lang.ref.FinalizeTest#testSystemRunFinalizationReturnsEvenIfQueueIsNonEmpty",
- "libcore.java.lang.reflect.ClassLoaderReflectionTest#testConstructorsOfDifferentClassLoadersAreNotEqual",
- "libcore.java.lang.reflect.ClassLoaderReflectionTest#testFieldsOfDifferentClassLoadersAreNotEqual",
- "libcore.java.lang.reflect.MethodTest#testEqualMethodEqualsAndHashCode",
- "libcore.java.lang.reflect.MethodTest#testHashCodeSpec",
- "libcore.java.lang.reflect.ProxyTest#testDeclaredExceptionIntersectedByExactReturnTypes",
- "libcore.java.lang.reflect.ProxyTest#testReturnTypeDoesNotSatisfyAllConstraintsWithLenientCaller",
- "libcore.java.net.ConcurrentCloseTest#test_connect",
- "libcore.java.net.ConcurrentCloseTest#test_connect_nonBlocking",
- "libcore.java.net.ConcurrentCloseTest#test_connect_timeout",
- "libcore.java.net.InetAddressTest#test_isReachable",
- "libcore.java.net.OldCookieHandlerTest#test_get_put",
- "libcore.java.net.OldSocketTest#test_ConstructorLjava_lang_StringILjava_net_InetAddressI2",
- "libcore.java.net.OldSocketTest#test_connectLjava_net_SocketAddressI",
- "libcore.java.net.URLConnectionTest#testConnectViaHttpProxyToHttpsUsingBadProxyAndHttpResponseCache",
- "libcore.java.util.prefs.OldFilePreferencesImplTest#testSystemChildNodes",
- "libcore.java.util.prefs.OldNodeChangeEventTest#testGetChild",
- "libcore.java.util.prefs.OldNodeChangeEventTest#testGetParent",
- "org.apache.harmony.luni.tests.java.net.URLConnectionTest#test_getLastModified",
- "org.apache.harmony.tests.java.io.SerializationStressTest4#test_writeObject_Proxy",
- "org.apache.harmony.tests.java.lang.RuntimeTest#test_gc",
- "org.apache.harmony.tests.java.lang.ref.ReferenceQueueTest#test_removeJ",
- "org.apache.harmony.tests.java.lang.reflect.FieldTest#testProtectedFieldAccess",
- "org.apache.harmony.tests.java.lang.reflect.ProxyTest#test_ProxyClass_withParentAndSubInThrowList",
- "org.apache.harmony.tests.java.net.DatagramSocketTest#test_setBroadcastZ",
- "org.apache.harmony.tests.java.net.JarURLConnectionTest#test_getURLEncodedEntry",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_InetAddress_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_InetAddress_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_sendLjava_net_DatagramPacketB_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv4",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setLoopbackModeSendReceive_IPv6",
- "org.apache.harmony.tests.java.net.MulticastSocketTest#test_setNetworkInterfaceLjava_net_NetworkInterface_IPv4",
- "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_formatLjava_util_DateLjava_lang_StringBufferLjava_text_FieldPosition",
- "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parseLjava_lang_StringLjava_text_ParsePosition",
- "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testGetContentType",
- "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testGetInputStream",
- "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testHeaderFunctions",
- "tests.api.internal.net.www.protocol.file.FileURLConnectionTest#testHeader_BoundaryCheck"
- ]
-},
-{
description: "Known failure in GregorianCalendarTest",
bug: 12778197,
name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
},
{
- description: "Environment specific Console test suppressed for dory / molly",
- bug: 12491103,
- name: "org.apache.harmony.tests.java.io.ConsoleTest#test_readPassword_LString_LObject"
-},
-{
- description: "Some tests take too long on clockwork devices. Suppressed on klp-modular-dev.",
- bug: 5513723,
+ description: "SpdyConnection issue https://github.com/square/okhttp/issues/644 crashes the test app. Android does not provide SPDY/HTTP_2 connections by default so have been suppressed.",
+ bug: 14462336,
names: [
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider0",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider1",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider2",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider3",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider4",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider5",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider6",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider7",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider8",
- "libcore.java.security.KeyPairGeneratorTest#test_getInstance_provider9"
+ "com.squareup.okhttp.internal.spdy.SpdyConnectionTest",
+ "com.squareup.okhttp.internal.http.HttpOverHttp20Draft09Test",
+ "com.squareup.okhttp.internal.http.HttpOverSpdy3Test",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_SPDY_3",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_HTTP_2",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_SPDY_3",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_HTTP_2",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_SPDY_3",
+ "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_HTTP_2"
]
},
{
- description: "Suppression of a test that proves there is a known bug with Matcher",
- bug: 14865710,
- name: "org.apache.harmony.tests.java.util.ScannerParseLargeFileBenchmarkTest#testParseLargeFile"
+ description: "Okhttp test hardcodes the TLS version expected.",
+ bug: 14462336,
+ names: [
+ "com.squareup.okhttp.internal.http.URLConnectionTest#sslFallbackNotUsedWhenRecycledConnectionFails"
+ ]
+},
+{
+ description: "The test relies on SimpleDateFormat zzz producing GMT not GMT+00:00 as it does on Android. Android issue 66136.",
+ bug: 14462336,
+ names: [
+ "com.squareup.okhttp.internal.http.HttpResponseCacheTest#setIfModifiedSince"
+ ]
}
]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
index a029a51..959f83c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/InetAddressTest.java
@@ -349,9 +349,8 @@
} catch (IllegalArgumentException e) {
// correct
}
- // tests unreachable address. 192.0.2.1 is reserved by RFC 5737
- // and should not be used outside of example code / docs.
- ia = Inet4Address.getByName("192.0.2.1");
+ // tests nowhere
+ ia = Inet4Address.getByName("1.1.1.1");
assertFalse(ia.isReachable(1000));
assertFalse(ia.isReachable(null, 0, 1000));
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/CollationElementIteratorTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/CollationElementIteratorTest.java
index 0ca489c..081b446 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/CollationElementIteratorTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/CollationElementIteratorTest.java
@@ -125,7 +125,8 @@
public void testGetMaxExpansion() {
String text = "cha";
- RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(new Locale("es", "", "TRADITIONAL"));
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(
+ Locale.forLanguageTag("es-u-co-trad"));
CollationElementIterator iterator = rbColl.getCollationElementIterator(text);
int order = iterator.next();
while (order != CollationElementIterator.NULLORDER) {
@@ -177,7 +178,8 @@
}
public void testSetOffset() {
- RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(new Locale("es", "", "TRADITIONAL"));
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(
+ Locale.forLanguageTag("es-u-co-trad"));
String text = "cha";
CollationElementIterator iterator = rbColl.getCollationElementIterator(text);
iterator.setOffset(0);
@@ -189,7 +191,8 @@
}
public void testSetTextString() {
- RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(new Locale("es", "", "TRADITIONAL"));
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(
+ Locale.forLanguageTag("es-u-co-trad"));
String text = "caa";
CollationElementIterator iterator = rbColl.getCollationElementIterator(text);
iterator.setOffset(0);
@@ -208,7 +211,8 @@
}
public void testSetTextCharacterIterator() {
- RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(new Locale("es", "", "TRADITIONAL"));
+ RuleBasedCollator rbColl = (RuleBasedCollator) Collator.getInstance(
+ Locale.forLanguageTag("es-u-co-trad"));
String text = "caa";
CollationElementIterator iterator = rbColl.getCollationElementIterator(text);
iterator.setOffset(1);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
index 9fe3681..70e41a2 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
@@ -88,7 +88,7 @@
Locale locale = new Locale("not exist language", "not exist country");
DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
- assertNotNull(symbols);
+ assertEquals(DateFormatSymbols.getInstance(Locale.ROOT), symbols);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/RuleBasedCollatorTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/RuleBasedCollatorTest.java
index f5a8057..906857b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/RuleBasedCollatorTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/RuleBasedCollatorTest.java
@@ -105,7 +105,7 @@
public void testGetCollationElementIteratorString() throws Exception {
{
- Locale locale = new Locale("es", "", "TRADITIONAL");
+ Locale locale = Locale.forLanguageTag("es-u-co-trad");
RuleBasedCollator coll = (RuleBasedCollator) Collator.getInstance(locale);
String source = "cha";
CollationElementIterator iterator = coll.getCollationElementIterator(source);
@@ -147,7 +147,7 @@
public void testGetCollationElementIteratorCharacterIterator() throws Exception {
{
- Locale locale = new Locale("es", "", "TRADITIONAL");
+ Locale locale = Locale.forLanguageTag("es-u-co-trad");
RuleBasedCollator coll = (RuleBasedCollator) Collator.getInstance(locale);
String text = "cha";
StringCharacterIterator source = new StringCharacterIterator(text);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
index ed25241..a1629d2 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CollectionsTest.java
@@ -23,8 +23,9 @@
import tests.support.Support_ListTest;
import tests.support.Support_SetTest;
import tests.support.Support_UnmodifiableCollectionTest;
-import tests.support.Support_UnmodifiableMapTest;
+
import java.io.Serializable;
+import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayDeque;
@@ -38,6 +39,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -67,7 +69,7 @@
private HashMap hm;
- private Object[] objArray;
+ private Integer[] objArray;
private Object[] myobjArray;
@@ -125,10 +127,10 @@
colSize = c.size();
normalCountingList = new ArrayList(colSize);
offsetCountingList = new ArrayList(colSize);
- for (int counter = 0; counter < colSize; counter++)
- normalCountingList.add(new Integer(counter));
- for (int counter = 0; counter < colSize; counter++)
- offsetCountingList.add(new Integer(counter + colSize));
+ for (int i = 0; i < colSize; i++)
+ normalCountingList.add(new Integer(i));
+ for (int i = 0; i < colSize; i++)
+ offsetCountingList.add(new Integer(i + colSize));
col.clear();
if (offset)
col.addAll(offsetCountingList);
@@ -208,12 +210,12 @@
mapSize = m.size();
normalCountingMap = new HashMap(mapSize);
offsetCountingMap = new HashMap(mapSize);
- for (int counter = 0; counter < mapSize; counter++) {
- myInt = new Integer(counter);
+ for (int i = 0; i < mapSize; i++) {
+ myInt = new Integer(i);
normalCountingMap.put(myInt, myInt);
}
- for (int counter = 0; counter < mapSize; counter++) {
- myInt = new Integer(counter + mapSize);
+ for (int i = 0; i < mapSize; i++) {
+ myInt = new Integer(i + mapSize);
offsetCountingMap.put(myInt, myInt);
}
map.clear();
@@ -241,21 +243,6 @@
}
}
- public static class CollectionTest extends junit.framework.TestCase {
-
- Collection col; // must contain the Integers 0 to 99
-
- public CollectionTest(String p1) {
- super(p1);
- }
-
- public CollectionTest(String p1, Collection c) {
- super(p1);
- col = c;
- }
-
- }
-
static class MyInt {
int data;
@@ -268,10 +255,6 @@
}
}
- /**
- * java.util.Collections#binarySearch(java.util.List,
- * java.lang.Object)
- */
public void test_binarySearchLjava_util_ListLjava_lang_Object() {
// Test for method int
// java.util.Collections.binarySearch(java.util.List, java.lang.Object)
@@ -284,17 +267,13 @@
} catch (NullPointerException e) {
//Expected
}
- for (int counter = 0; counter < llSize; counter++) {
+ for (int i = 0; i < llSize; i++) {
assertEquals("Returned incorrect binary search item position", ll
- .get(counter), ll.get(Collections.binarySearch(ll, ll
- .get(counter))));
+ .get(i), ll.get(Collections.binarySearch(ll, ll
+ .get(i))));
}
}
- /**
- * java.util.Collections#binarySearch(java.util.List,
- * java.lang.Object, java.util.Comparator)
- */
public void test_binarySearchLjava_util_ListLjava_lang_ObjectLjava_util_Comparator() {
// Test for method int
// java.util.Collections.binarySearch(java.util.List, java.lang.Object,
@@ -310,12 +289,12 @@
} catch (NullPointerException e) {
//Expected
}
- for (int counter = 0; counter < rSize; counter++) {
+ for (int i = 0; i < rSize; i++) {
assertEquals(
"Returned incorrect binary search item position using custom comparator",
- myReversedLinkedList.get(counter), myReversedLinkedList
+ myReversedLinkedList.get(i), myReversedLinkedList
.get(Collections.binarySearch(myReversedLinkedList,
- myReversedLinkedList.get(counter), comp)));
+ myReversedLinkedList.get(i), comp)));
}
}
@@ -327,9 +306,6 @@
}
}
- /**
- * java.util.Collections#copy(java.util.List, java.util.List)
- */
public void test_copyLjava_util_ListLjava_util_List() {
// Test for method void java.util.Collections.copy(java.util.List,
// java.util.List)
@@ -355,9 +331,9 @@
al.add(extraElement);
al.add(extraElement2);
Collections.copy(al, ll);
- for (int counter = 0; counter < llSize; counter++) {
+ for (int i = 0; i < llSize; i++) {
assertEquals("Elements do not match after copying collection", ll
- .get(counter), al.get(counter));
+ .get(i), al.get(i));
}
assertTrue("Elements after copied elements affected by copy",
extraElement == al.get(llSize)
@@ -399,9 +375,6 @@
}
}
- /**
- * java.util.Collections#copy(java.util.List, java.util.List)
- */
public void test_copy_check_index() {
ArrayList a1 = new ArrayList();
a1.add("one");
@@ -420,9 +393,6 @@
assertEquals("aa", a2.get(0));
}
- /**
- * java.util.Collections#enumeration(java.util.Collection)
- */
public void test_enumerationLjava_util_Collection() {
// Test for method java.util.Enumeration
// java.util.Collections.enumeration(java.util.Collection)
@@ -438,9 +408,6 @@
count);
}
- /**
- * java.util.Collections#fill(java.util.List, java.lang.Object)
- */
public void test_fillLjava_util_ListLjava_lang_Object() {
// Test for method void java.util.Collections.fill(java.util.List,
// java.lang.Object)
@@ -476,9 +443,6 @@
}
}
- /**
- * java.util.Collections#max(java.util.Collection)
- */
public void test_maxLjava_util_Collection() {
// Test for method java.lang.Object
// java.util.Collections.max(java.util.Collection)
@@ -507,10 +471,6 @@
}
}
- /**
- * java.util.Collections#max(java.util.Collection,
- * java.util.Comparator)
- */
public void test_maxLjava_util_CollectionLjava_util_Comparator() {
// Test for method java.lang.Object
// java.util.Collections.max(java.util.Collection, java.util.Comparator)
@@ -523,9 +483,6 @@
myobjArray[0]);
}
- /**
- * java.util.Collections#min(java.util.Collection)
- */
public void test_minLjava_util_Collection() {
// Test for method java.lang.Object
// java.util.Collections.min(java.util.Collection)
@@ -534,10 +491,6 @@
objArray[0]);
}
- /**
- * java.util.Collections#min(java.util.Collection,
- * java.util.Comparator)
- */
public void test_minLjava_util_CollectionLjava_util_Comparator() {
// Test for method java.lang.Object
// java.util.Collections.min(java.util.Collection, java.util.Comparator)
@@ -550,16 +503,13 @@
myobjArray[objArray.length - 1]);
}
- /**
- * java.util.Collections#nCopies(int, java.lang.Object)
- */
public void test_nCopiesILjava_lang_Object() {
// Test for method java.util.List java.util.Collections.nCopies(int,
// java.lang.Object)
Object o = new Object();
List l = Collections.nCopies(100, o);
- Iterator i = l.iterator();
- Object first = i.next();
+ Iterator iterator = l.iterator();
+ Object first = iterator.next();
assertEquals("Returned list consists of copies not refs", first, o);
assertEquals("Returned list of incorrect size", 100, l.size());
assertTrue("Contains", l.contains(o));
@@ -569,10 +519,10 @@
assertTrue("null nCopies contains null", Collections.nCopies(2, null)
.contains(null));
l = Collections.nCopies(20, null);
- i = l.iterator();
- for (int counter = 0; i.hasNext(); counter++) {
- assertTrue("List is too large", counter < 20);
- assertNull("Element should be null: " + counter, i.next());
+ iterator = l.iterator();
+ for (int i = 0; iterator.hasNext(); i++) {
+ assertTrue("List is too large", i < 20);
+ assertNull("Element should be null: " + i, iterator.next());
}
try {
l.add(o);
@@ -588,9 +538,6 @@
}
}
- /**
- * java.util.Collections#reverse(java.util.List)
- */
public void test_reverseLjava_util_List() {
// Test for method void java.util.Collections.reverse(java.util.List)
try {
@@ -617,9 +564,6 @@
+ myList.get(1), myList.get(1));
}
- /**
- * java.util.Collections#reverseOrder()
- */
public void test_reverseOrder() {
// Test for method java.util.Comparator
// java.util.Collections.reverseOrder()
@@ -628,14 +572,11 @@
LinkedList list2 = new LinkedList(ll);
Collections.sort(list2, comp);
final int llSize = ll.size();
- for (int counter = 0; counter < llSize; counter++)
+ for (int i = 0; i < llSize; i++)
assertEquals("New comparator does not reverse sorting order", list2
- .get(llSize - counter - 1), ll.get(counter));
+ .get(llSize - i - 1), ll.get(i));
}
- /**
- * java.util.Collections#shuffle(java.util.List)
- */
public void test_shuffleLjava_util_List() {
// Test for method void java.util.Collections.shuffle(java.util.List)
// Assumes ll is sorted and has no duplicate keys and is large ( > 20
@@ -682,15 +623,15 @@
else
Collections.shuffle(list, new Random(200));
- for (int counter = 0; counter < size - 1; counter++) {
- if (((Integer) list.get(counter)).compareTo((Integer) list.get(counter + 1)) > 0) {
+ for (int i = 0; i < size - 1; i++) {
+ if (((Integer) list.get(i)).compareTo((Integer) list.get(i + 1)) > 0) {
sorted = false;
}
}
assertFalse("Shuffling sorted " + type
+ " list resulted in sorted list (should be unlikely)", sorted);
- for (int counter = 0; counter < 20; counter++) {
- index = 30031 * counter % (size + 1); // 30031 is a large prime
+ for (int i = 0; i < 20; i++) {
+ index = 30031 * i % (size + 1); // 30031 is a large prime
if (list.get(index) != ll.get(index))
allMatch = false;
}
@@ -698,9 +639,6 @@
+ " list", allMatch);
}
- /**
- * java.util.Collections#shuffle(java.util.List, java.util.Random)
- */
public void test_shuffleLjava_util_ListLjava_util_Random() {
// Test for method void java.util.Collections.shuffle(java.util.List,
// java.util.Random)
@@ -731,9 +669,6 @@
assertEquals("acb", l.get(0).toString() + l.get(1) + l.get(2));
}
- /**
- * java.util.Collections#singleton(java.lang.Object)
- */
public void test_singletonLjava_lang_Object() {
// Test for method java.util.Set
// java.util.Collections.singleton(java.lang.Object)
@@ -754,9 +689,6 @@
}
}
- /**
- * java.util.Collections#sort(java.util.List)
- */
public void test_sortLjava_util_List() {
// Test for method void java.util.Collections.sort(java.util.List)
// assumes no duplicate keys in ll
@@ -771,22 +703,19 @@
Collections.shuffle(ll);
Collections.sort(ll);
Collections.sort(reversedLinkedList);
- for (int counter = 0; counter < llSize - 1; counter++) {
+ for (int i = 0; i < llSize - 1; i++) {
assertTrue(
"Sorting shuffled list resulted in unsorted list",
- ((Integer) ll.get(counter)).compareTo((Integer) ll.get(counter + 1)) < 0);
+ ((Integer) ll.get(i)).compareTo((Integer) ll.get(i + 1)) < 0);
}
- for (int counter = 0; counter < rllSize - 1; counter++) {
+ for (int i = 0; i < rllSize - 1; i++) {
assertTrue("Sorting reversed list resulted in unsorted list",
- ((Integer) reversedLinkedList.get(counter))
- .compareTo((Integer) reversedLinkedList.get(counter + 1)) < 0);
+ ((Integer) reversedLinkedList.get(i))
+ .compareTo((Integer) reversedLinkedList.get(i + 1)) < 0);
}
}
- /**
- * java.util.Collections#sort(java.util.List, java.util.Comparator)
- */
public void test_sortLjava_util_ListLjava_util_Comparator() {
// Test for method void java.util.Collections.sort(java.util.List,
// java.util.Comparator)
@@ -801,11 +730,11 @@
Collections.sort(myll, comp);
final int llSize = myll.size();
- for (int counter = 0; counter < llSize - 1; counter++) {
+ for (int i = 0; i < llSize - 1; i++) {
assertTrue(
"Sorting shuffled list with custom comparator resulted in unsorted list",
- ((MyInt) myll.get(counter)).compareTo((MyInt) myll
- .get(counter + 1)) >= 0);
+ ((MyInt) myll.get(i)).compareTo((MyInt) myll
+ .get(i + 1)) >= 0);
}
ArrayList al = new ArrayList();
@@ -834,9 +763,6 @@
}
}
- /**
- * java.util.Collections#swap(java.util.List, int, int)
- */
public void test_swapLjava_util_ListII() {
// Test for method swap(java.util.List, int, int)
@@ -897,10 +823,6 @@
}
}
- /**
- * java.util.Collections#replaceAll(java.util.List, java.lang.Object,
- * java.lang.Object)
- */
public void test_replaceAllLjava_util_ListLjava_lang_ObjectLjava_lang_Object() {
// Test for method replaceAll(java.util.List, java.lang.Object,
// java.lang.Object)
@@ -998,9 +920,6 @@
}
}
- /**
- * java.util.Collections#rotate(java.util.List, int)
- */
public void test_rotateLjava_util_ListI() {
// Test for method rotate(java.util.List, int)
@@ -1081,9 +1000,6 @@
return buffer.toString();
}
- /**
- * java.util.Collections#rotate(java.util.List, int)
- */
public void test_rotate2() {
List list = new ArrayList();
try {
@@ -1112,10 +1028,6 @@
(String) list.get(4));
}
- /**
- * java.util.Collections#indexOfSubList(java.util.List,
- * java.util.List)
- */
public void test_indexOfSubListLjava_util_ListLjava_util_List() {
// Test for method int indexOfSubList(java.util.List, java.util.List)
List list = new ArrayList();
@@ -1146,10 +1058,6 @@
testwithCharList(8, "", "SUBLIST", true);
}
- /**
- * java.util.Collections#indexOfSubList(java.util.List,
- * java.util.List)
- */
public void test_indexOfSubList2() {
ArrayList sub = new ArrayList();
sub.add(new Integer(1));
@@ -1205,7 +1113,6 @@
.indexOfSubList(src, sub2));
}
-
private void testwithCharList(int count, String string1, String string2,
boolean first) {
char[] chars = string1.toCharArray();
@@ -1229,10 +1136,6 @@
sublist));
}
- /**
- * java.util.Collections#lastIndexOfSubList(java.util.List,
- * java.util.List)
- */
public void test_lastIndexOfSubListLjava_util_ListLjava_util_List() {
// Test for method int lastIndexOfSubList(java.util.List,
// java.util.List)
@@ -1264,10 +1167,6 @@
testwithCharList(8, "", "SUBLIST", false);
}
- /**
- * java.util.Collections#lastIndexOfSubList(java.util.List,
- * java.util.List)
- */
public void test_lastIndexOfSubList2() {
ArrayList sub = new ArrayList();
sub.add(new Integer(1));
@@ -1337,9 +1236,6 @@
Collections.lastIndexOfSubList(src, sub2));
}
- /**
- * java.util.Collections#list(java.util.Enumeration)
- */
public void test_listLjava_util_Enumeration() {
// Test for method java.util.ArrayList list(java.util.Enumeration)
@@ -1355,9 +1251,6 @@
}
}
- /**
- * java.util.Collections#synchronizedCollection(java.util.Collection)
- */
public void test_synchronizedCollectionLjava_util_Collection() {
// Test for method java.util.Collection
// java.util.Collections.synchronizedCollection(java.util.Collection)
@@ -1415,9 +1308,6 @@
assertTrue("should contain self ref", synchCol.toString().indexOf("(this") > -1);
}
- /**
- * java.util.Collections#synchronizedList(java.util.List)
- */
public void test_synchronizedListLjava_util_List() {
try {
Collections.synchronizedList(null);
@@ -1505,9 +1395,6 @@
synchList.get(25));
}
- /**
- * java.util.Collections#synchronizedMap(java.util.Map)
- */
public void test_synchronizedMapLjava_util_Map() {
// Test for method java.util.Map
// java.util.Collections.synchronizedMap(java.util.Map)
@@ -1561,7 +1448,7 @@
smallMap.put(objArray[i].toString(), objArray[i]);
}
synchMap = Collections.synchronizedMap(smallMap);
- new Support_UnmodifiableMapTest("", synchMap).runTest();
+ new MapTestSupport(synchMap).runTest();
synchMap.keySet().remove(objArray[50].toString());
assertNull(
"Removing a key from the keySet of the synchronized map did not remove it from the synchronized map: ",
@@ -1571,9 +1458,17 @@
smallMap.get(objArray[50].toString()));
}
- /**
- * java.util.Collections#synchronizedSet(java.util.Set)
- */
+ public void test_unmodifiableMap_LinkedHashMap() {
+ // LinkedHashMap has a well defined iteration order and shows ordering issues with
+ // entrySet() / keySet() methods: iterator(), toArray(T[]) and toArray(). See bug 72073.
+ LinkedHashMap<String, Integer> smallMap = new LinkedHashMap<String, Integer>();
+ for (int i = 0; i < 100; i++) {
+ Integer object = objArray[i];
+ smallMap.put(object.toString(), object);
+ }
+ new MapTestSupport(smallMap).runTest();
+ }
+
public void test_synchronizedSetLjava_util_Set() {
// Test for method java.util.Set
// java.util.Collections.synchronizedSet(java.util.Set)
@@ -1631,9 +1526,6 @@
assertTrue("should contain self ref", mySet.toString().indexOf("(this") > -1);
}
- /**
- * java.util.Collections#synchronizedSortedMap(java.util.SortedMap)
- */
public void test_synchronizedSortedMapLjava_util_SortedMap() {
// Test for method java.util.SortedMap
// java.util.Collections.synchronizedSortedMap(java.util.SortedMap)
@@ -1679,7 +1571,7 @@
smallMap.put(objArray[i].toString(), objArray[i]);
}
synchMap = Collections.synchronizedSortedMap(smallMap);
- new Support_UnmodifiableMapTest("", synchMap).runTest();
+ new MapTestSupport(synchMap).runTest();
synchMap.keySet().remove(objArray[50].toString());
assertNull(
"Removing a key from the keySet of the synchronized map did not remove it from the synchronized map",
@@ -1689,9 +1581,6 @@
smallMap.get(objArray[50].toString()));
}
- /**
- * java.util.Collections#synchronizedSortedSet(java.util.SortedSet)
- */
public void test_synchronizedSortedSetLjava_util_SortedSet() {
// Test for method java.util.SortedSet
// java.util.Collections.synchronizedSortedSet(java.util.SortedSet)
@@ -1733,9 +1622,6 @@
}
}
- /**
- * java.util.Collections#unmodifiableCollection(java.util.Collection)
- */
public void test_unmodifiableCollectionLjava_util_Collection() {
// Test for method java.util.Collection
// java.util.Collections.unmodifiableCollection(java.util.Collection)
@@ -1743,9 +1629,9 @@
Collection c = Collections.unmodifiableCollection(ll);
assertTrue("Returned collection is of incorrect size", c.size() == ll
.size());
- Iterator i = ll.iterator();
- while (i.hasNext())
- assertTrue("Returned list missing elements", c.contains(i.next()));
+ Iterator iterator = ll.iterator();
+ while (iterator.hasNext())
+ assertTrue("Returned list missing elements", c.contains(iterator.next()));
try {
c.add(new Object());
} catch (UnsupportedOperationException e) {
@@ -1772,16 +1658,13 @@
.contains(new Integer(20)));
myCollection = new ArrayList();
- for (int counter = 0; counter < 100; counter++) {
- myCollection.add(objArray[counter]);
+ for (int i = 0; i < 100; i++) {
+ myCollection.add(objArray[i]);
}
new Support_UnmodifiableCollectionTest("", Collections
.unmodifiableCollection(myCollection)).runTest();
}
- /**
- * java.util.Collections#unmodifiableList(java.util.List)
- */
public void test_unmodifiableListLjava_util_List() {
// Test for method java.util.List
// java.util.Collections.unmodifiableList(java.util.List)
@@ -1801,9 +1684,9 @@
"Returned List should not implement Random Access interface",
!(c instanceof RandomAccess));
- Iterator i = ll.iterator();
- while (i.hasNext())
- assertTrue("Returned list missing elements", c.contains(i.next()));
+ Iterator iterator = ll.iterator();
+ while (iterator.hasNext())
+ assertTrue("Returned list missing elements", c.contains(iterator.next()));
try {
c.add(new Object());
} catch (UnsupportedOperationException e) {
@@ -1833,8 +1716,8 @@
c instanceof RandomAccess);
smallList = new ArrayList();
- for (int counter = 0; counter < 100; counter++) {
- smallList.add(objArray[counter]);
+ for (int i = 0; i < 100; i++) {
+ smallList.add(objArray[i]);
}
List myList = Collections.unmodifiableList(smallList);
assertTrue("List should not contain null", !myList.contains(null));
@@ -1845,25 +1728,22 @@
assertTrue("get failed on unmodifiable list", myList.get(50).equals(
new Integer(50)));
ListIterator listIterator = myList.listIterator();
- for (int counter = 0; listIterator.hasNext(); counter++) {
+ for (int i = 0; listIterator.hasNext(); i++) {
assertTrue("List has wrong elements", ((Integer) listIterator
- .next()).intValue() == counter);
+ .next()).intValue() == i);
}
new Support_UnmodifiableCollectionTest("", smallList).runTest();
}
- /**
- * java.util.Collections#unmodifiableMap(java.util.Map)
- */
public void test_unmodifiableMapLjava_util_Map() {
// Test for method java.util.Map
// java.util.Collections.unmodifiableMap(java.util.Map)
boolean exception = false;
Map c = Collections.unmodifiableMap(hm);
assertTrue("Returned map is of incorrect size", c.size() == hm.size());
- Iterator i = hm.keySet().iterator();
- while (i.hasNext()) {
- Object x = i.next();
+ Iterator iterator = hm.keySet().iterator();
+ while (iterator.hasNext()) {
+ Object x = iterator.next();
assertTrue("Returned map missing elements", c.get(x).equals(
hm.get(x)));
}
@@ -1885,8 +1765,8 @@
assertTrue("Allowed modification of map", exception);
exception = false;
- Iterator it = c.entrySet().iterator();
- Map.Entry entry = (Map.Entry) it.next();
+ Iterator entrySetIterator = c.entrySet().iterator();
+ Map.Entry entry = (Map.Entry) entrySetIterator.next();
try {
entry.setValue("modified");
} catch (UnsupportedOperationException e) {
@@ -1927,26 +1807,21 @@
.equals(new Long(30)));
smallMap = new HashMap();
- for (int counter = 0; counter < 100; counter++) {
- smallMap.put(objArray[counter].toString(), objArray[counter]);
+ for (int i = 0; i < 100; i++) {
+ smallMap.put(objArray[i].toString(), objArray[i]);
}
- unmodMap = Collections.unmodifiableMap(smallMap);
- new Support_UnmodifiableMapTest("", unmodMap).runTest();
-
+ new MapTestSupport(smallMap).runTest();
}
- /**
- * java.util.Collections#unmodifiableSet(java.util.Set)
- */
public void test_unmodifiableSetLjava_util_Set() {
// Test for method java.util.Set
// java.util.Collections.unmodifiableSet(java.util.Set)
boolean exception = false;
Set c = Collections.unmodifiableSet(s);
assertTrue("Returned set is of incorrect size", c.size() == s.size());
- Iterator i = ll.iterator();
- while (i.hasNext())
- assertTrue("Returned set missing elements", c.contains(i.next()));
+ Iterator iterator = ll.iterator();
+ while (iterator.hasNext())
+ assertTrue("Returned set missing elements", c.contains(iterator.next()));
try {
c.add(new Object());
} catch (UnsupportedOperationException e) {
@@ -1969,16 +1844,13 @@
assertTrue("Should contain null", mySet.contains(null));
mySet = new TreeSet();
- for (int counter = 0; counter < 100; counter++) {
- mySet.add(objArray[counter]);
+ for (int i = 0; i < 100; i++) {
+ mySet.add(objArray[i]);
}
new Support_UnmodifiableCollectionTest("", Collections
.unmodifiableSet(mySet)).runTest();
}
- /**
- * java.util.Collections#unmodifiableSortedMap(java.util.SortedMap)
- */
public void test_unmodifiableSortedMapLjava_util_SortedMap() {
// Test for method java.util.SortedMap
// java.util.Collections.unmodifiableSortedMap(java.util.SortedMap)
@@ -2012,9 +1884,6 @@
fail("Allowed modification of map");
}
- /**
- * java.util.Collections#unmodifiableSortedSet(java.util.SortedSet)
- */
public void test_unmodifiableSortedSetLjava_util_SortedSet() {
// Test for method java.util.SortedSet
// java.util.Collections.unmodifiableSortedSet(java.util.SortedSet)
@@ -2115,10 +1984,6 @@
}
}
-
- /**
- * java.util.Collections#checkType(Object, Class)
- */
public void test_checkType_Ljava_lang_Object_Ljava_lang_Class() throws Exception {
Method m = Collections.class.getDeclaredMethod("checkType", Object.class, Class.class);
m.setAccessible(true);
@@ -2257,9 +2122,6 @@
SerializationTest.verifySelf(set);
}
- /**
- * {@link java.util.Collections#asLifoQueue(Deque)
- */
public void test_asLifoQueue() throws Exception {
Integer testInt[] = new Integer[100];
Integer test101 = new Integer(101);
@@ -2300,7 +2162,6 @@
@SuppressWarnings({ "unchecked", "boxing" })
public void testSerializationSelf_asLifoQueue() throws Exception {
Integer testInt[] = new Integer[100];
- Integer test101 = new Integer(101);
for (int i = 0; i < testInt.length; i++) {
testInt[i] = new Integer(i);
}
@@ -2320,23 +2181,18 @@
});
}
- /**
- * java.util.Collections#emptyList()
- */
public void test_emptyList() {
List<String> list = Collections.emptyList();
assertTrue("should be true", list.isEmpty());
}
- /**
- * Sets up the fixture, for example, open a network connection. This method
- * is called before a test is executed.
- */
- protected void setUp() {
- objArray = new Object[1000];
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ objArray = new Integer[1000];
myobjArray = new Object[1000];
for (int i = 0; i < objArray.length; i++) {
- objArray[i] = new Integer(i);
+ objArray[i] = i;
myobjArray[i] = new MyInt(i);
}
@@ -2360,23 +2216,170 @@
}
/**
- * Tears down the fixture, for example, close a network connection. This
- * method is called after a test is executed.
+ * A class shared by various Map-related tests that checks the properties and contents of a
+ * supplied Map and compares the some methods to the same map when wrapped with
+ * {@link Collections#unmodifiableMap(java.util.Map)}.
*/
- protected void tearDown() {
- objArray = null;
- myobjArray = null;
+ static class MapTestSupport {
- ll = null;
- myll = null;
- reversedLinkedList = null;
- myReversedLinkedList = null;
- s = null;
- mys = null;
- hm = null;
- }
+ // must be a map containing the string keys "0"-"99" paired with the Integer
+ // values Integer(0) to Integer(99)
+ private final Map<String, Integer> modifiableMap;
+ private final Map<String, Integer> unmodifiableMap;
- protected void doneSuite() {
- objArray = null;
+ public MapTestSupport(Map<String, Integer> modifiableMap) {
+ this.modifiableMap = modifiableMap;
+ unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
+ }
+
+ public void runTest() {
+ testContents(modifiableMap);
+ testContents(unmodifiableMap);
+
+ // values()
+ new Support_UnmodifiableCollectionTest("values() from map test", modifiableMap.values())
+ .runTest();
+ new Support_UnmodifiableCollectionTest("values() from unmodifiable map test",
+ unmodifiableMap.values()).runTest();
+
+ // entrySet()
+ testEntrySet(modifiableMap.entrySet(), unmodifiableMap.entrySet());
+
+ // keySet()
+ testKeySet(modifiableMap.keySet(), unmodifiableMap.keySet());
+ }
+
+ private static void testContents(Map<String, Integer> map) {
+ // size
+ assertTrue("Size should return 100, returned: " + map.size(), map.size() == 100);
+
+ // containsKey
+ assertTrue("Should contain the key \"0\"", map.containsKey("0"));
+ assertTrue("Should contain the key \"50\"", map.containsKey("50"));
+ assertTrue("Should not contain the key \"100\"", !map.containsKey("100"));
+
+ // containsValue
+ assertTrue("Should contain the value 0", map.containsValue(0));
+ assertTrue("Should contain the value 50", map.containsValue(50));
+ assertTrue("Should not contain value 100", !map.containsValue(100));
+
+ // get
+ assertTrue("getting \"0\" didn't return 0", map.get("0") == 0);
+ assertTrue("getting \"50\" didn't return 50", map.get("50") == 50);
+ assertNull("getting \"100\" didn't return null", map.get("100"));
+
+ // isEmpty
+ assertTrue("should have returned false to isEmpty", !map.isEmpty());
+ }
+
+ private static void testEntrySet(
+ Set<Map.Entry<String, Integer>> referenceEntrySet,
+ Set<Map.Entry<String, Integer>> entrySet) {
+ // entrySet should be a set of mappings {"0", 0}, {"1",1}... {"99", 99}
+ assertEquals(100, referenceEntrySet.size());
+ assertEquals(100, entrySet.size());
+
+ // The ordering may be undefined for a map implementation but the ordering must be the
+ // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
+ // modifiable and unmodifiable map.
+ crossCheckOrdering(referenceEntrySet, entrySet, Map.Entry.class);
+ }
+
+ private static void testKeySet(Set<String> referenceKeySet, Set<String> keySet) {
+ // keySet should be a set of the strings "0" to "99"
+ testKeySetContents(referenceKeySet);
+ testKeySetContents(keySet);
+
+ // The ordering may be undefined for a map implementation but the ordering must be the
+ // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
+ // modifiable and unmodifiable map.
+ crossCheckOrdering(referenceKeySet, keySet, String.class);
+ }
+
+ private static void testKeySetContents(Set<String> keySet) {
+ // contains
+ assertTrue("should contain \"0\"", keySet.contains("0"));
+ assertTrue("should contain \"50\"", keySet.contains("50"));
+ assertTrue("should not contain \"100\"", !keySet.contains("100"));
+
+ // containsAll
+ HashSet<String> hs = new HashSet<String>();
+ hs.add("0");
+ hs.add("25");
+ hs.add("99");
+ assertTrue("Should contain set of \"0\", \"25\", and \"99\"", keySet.containsAll(hs));
+ hs.add("100");
+ assertTrue("Should not contain set of \"0\", \"25\", \"99\" and \"100\"",
+ !keySet.containsAll(hs));
+
+ // isEmpty
+ assertTrue("Should not be empty", !keySet.isEmpty());
+
+ // size
+ assertEquals("Returned wrong size.", 100, keySet.size());
+ }
+
+ private static <T> void crossCheckOrdering(Set<T> set1, Set<T> set2, Class<?> elementType) {
+ Iterator<T> set1Iterator = set1.iterator();
+ Iterator<T> set2Iterator = set2.iterator();
+
+ T[] zeroLengthArray = createArray(elementType, 0);
+ T[] set1TypedArray1 = set1.toArray(zeroLengthArray);
+ assertEquals(set1.size(), set1TypedArray1.length);
+
+ // Compare set1.iterator(), set2.iterator() and set1.toArray(new T[0])
+ int entryCount = 0;
+ while (set1Iterator.hasNext()) {
+ T set1Entry = set1Iterator.next();
+ T set2Entry = set2Iterator.next();
+
+ // Compare set1 with set2
+ assertEquals(set1Entry, set2Entry);
+
+ // Compare the iterator with the array. The arrays will be checked against each other.
+ assertEquals(set1Entry, set1TypedArray1[entryCount]);
+
+ entryCount++;
+ }
+ assertFalse(set2Iterator.hasNext());
+ assertEquals(set1.size(), entryCount);
+
+ // Compare the various arrays with each other.
+
+ // set1.toArray(new T[size])
+ T[] parameterArray1 = createArray(elementType, set1.size());
+ T[] set1TypedArray2 = set1.toArray(parameterArray1);
+ assertSame(set1TypedArray2, parameterArray1);
+ assertArrayEquals(set1TypedArray1, set1TypedArray2);
+
+ // set1.toArray()
+ Object[] set1UntypedArray = set1.toArray();
+ assertEquals(set1.size(), set1UntypedArray.length);
+ assertArrayEquals(set1TypedArray1, set1UntypedArray);
+
+ // set2.toArray(new T[0])
+ T[] set2TypedArray1 = set2.toArray(zeroLengthArray);
+ assertEquals(set1.size(), set2TypedArray1.length);
+ assertArrayEquals(set1TypedArray1, set2TypedArray1);
+
+ // set2.toArray(new T[size])
+ T[] parameterArray2 = createArray(elementType, set2.size());
+ T[] set2TypedArray2 = set1.toArray(parameterArray2);
+ assertSame(set2TypedArray2, parameterArray2);
+ assertArrayEquals(set1TypedArray1, set1TypedArray2);
+
+ // set2.toArray()
+ Object[] set2UntypedArray = set2.toArray();
+ assertArrayEquals(set1TypedArray1, set2UntypedArray);
+ }
+
+ private static <T> void assertArrayEquals(T[] array1, T[] array2) {
+ assertTrue(Arrays.equals(array1, array2));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T[] createArray(Class<?> elementType, int size) {
+ return (T[]) Array.newInstance(elementType, size);
+ }
}
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 740340e..d5d8191 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.security.CodeSigner;
import java.security.Permission;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
@@ -98,6 +99,8 @@
private static final String INVALID_CHAIN_JAR = "hyts_signed_invalidChain.jar";
+ private static final String AMBIGUOUS_SIGNERS_JAR = "hyts_signed_ambiguousSignerArray.jar";
+
private File resources;
// custom security manager
@@ -647,13 +650,18 @@
+ jarName + "\"", foundCerts);
}
- private Certificate[] getSignedJarCerts(String jarName, boolean chainCheck) throws Exception {
+ private static class Results {
+ public Certificate[] certificates;
+ public CodeSigner[] signers;
+ }
+
+ private Results getSignedJarCerts(String jarName) throws Exception {
Support_Resources.copyFile(resources, null, jarName);
File file = new File(resources, jarName);
- Certificate[] foundCerts = null;
+ Results results = new Results();
- JarFile jarFile = new JarFile(file, true, ZipFile.OPEN_READ, chainCheck);
+ JarFile jarFile = new JarFile(file, true, ZipFile.OPEN_READ);
try {
Enumeration<JarEntry> e = jarFile.entries();
@@ -664,8 +672,10 @@
is.skip(entry.getSize());
is.close();
Certificate[] certs = entry.getCertificates();
+ CodeSigner[] signers = entry.getCodeSigners();
if (certs != null && certs.length > 0) {
- foundCerts = certs;
+ results.certificates = certs;
+ results.signers = signers;
break;
}
}
@@ -673,42 +683,38 @@
jarFile.close();
}
- return foundCerts;
+ return results;
}
- public void testJarFile_Signed_ValidChain_NoCheck() throws Exception {
- Certificate[] certs = getSignedJarCerts(VALID_CHAIN_JAR, false);
- assertNotNull(certs);
- assertEquals(Arrays.deepToString(certs), 3, certs.length);
- assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
- assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
- assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
+ public void testJarFile_Signed_ValidChain() throws Exception {
+ Results result = getSignedJarCerts(VALID_CHAIN_JAR);
+ assertNotNull(result);
+ assertEquals(Arrays.deepToString(result.certificates), 3, result.certificates.length);
+ assertEquals(Arrays.deepToString(result.signers), 1, result.signers.length);
+ assertEquals(3, result.signers[0].getSignerCertPath().getCertificates().size());
+ assertEquals("CN=fake-chain", ((X509Certificate) result.certificates[0]).getSubjectDN().toString());
+ assertEquals("CN=intermediate1", ((X509Certificate) result.certificates[1]).getSubjectDN().toString());
+ assertEquals("CN=root1", ((X509Certificate) result.certificates[2]).getSubjectDN().toString());
}
- public void testJarFile_Signed_ValidChain_Check() throws Exception {
- Certificate[] certs = getSignedJarCerts(VALID_CHAIN_JAR, true);
- assertNotNull(certs);
- assertEquals(Arrays.deepToString(certs), 3, certs.length);
- assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
- assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
- assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
+ public void testJarFile_Signed_InvalidChain() throws Exception {
+ Results result = getSignedJarCerts(INVALID_CHAIN_JAR);
+ assertNotNull(result);
+ assertEquals(Arrays.deepToString(result.certificates), 3, result.certificates.length);
+ assertEquals(Arrays.deepToString(result.signers), 1, result.signers.length);
+ assertEquals(3, result.signers[0].getSignerCertPath().getCertificates().size());
+ assertEquals("CN=fake-chain", ((X509Certificate) result.certificates[0]).getSubjectDN().toString());
+ assertEquals("CN=intermediate1", ((X509Certificate) result.certificates[1]).getSubjectDN().toString());
+ assertEquals("CN=root1", ((X509Certificate) result.certificates[2]).getSubjectDN().toString());
}
- public void testJarFile_Signed_InvalidChain_NoCheck() throws Exception {
- Certificate[] certs = getSignedJarCerts(INVALID_CHAIN_JAR, false);
- assertNotNull(certs);
- assertEquals(Arrays.deepToString(certs), 3, certs.length);
- assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
- assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
- assertEquals("CN=root1", ((X509Certificate) certs[2]).getSubjectDN().toString());
- }
-
- public void testJarFile_Signed_InvalidChain_Check() throws Exception {
- Certificate[] certs = getSignedJarCerts(INVALID_CHAIN_JAR, true);
- assertNotNull(certs);
- assertEquals(Arrays.deepToString(certs), 2, certs.length);
- assertEquals("CN=fake-chain", ((X509Certificate) certs[0]).getSubjectDN().toString());
- assertEquals("CN=intermediate1", ((X509Certificate) certs[1]).getSubjectDN().toString());
+ public void testJarFile_Signed_AmbiguousSigners() throws Exception {
+ Results result = getSignedJarCerts(AMBIGUOUS_SIGNERS_JAR);
+ assertNotNull(result);
+ assertEquals(Arrays.deepToString(result.certificates), 2, result.certificates.length);
+ assertEquals(Arrays.deepToString(result.signers), 2, result.signers.length);
+ assertEquals(1, result.signers[0].getSignerCertPath().getCertificates().size());
+ assertEquals(1, result.signers[1].getSignerCertPath().getCertificates().size());
}
/*
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 48b2dfa..a905c71 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -39,6 +39,7 @@
ABI_TO_INSTRUCTION_SET_MAP.put("armeabi", "arm");
ABI_TO_INSTRUCTION_SET_MAP.put("armeabi-v7a", "arm");
ABI_TO_INSTRUCTION_SET_MAP.put("mips", "mips");
+ ABI_TO_INSTRUCTION_SET_MAP.put("mips64", "mips64");
ABI_TO_INSTRUCTION_SET_MAP.put("x86", "x86");
ABI_TO_INSTRUCTION_SET_MAP.put("x86_64", "x86_64");
ABI_TO_INSTRUCTION_SET_MAP.put("arm64-v8a", "arm64");
@@ -325,4 +326,14 @@
return instructionSet;
}
+
+ public static boolean is64BitInstructionSet(String instructionSet) {
+ return "arm64".equals(instructionSet) ||
+ "x86_64".equals(instructionSet) ||
+ "mips64".equals(instructionSet);
+ }
+
+ public static boolean is64BitAbi(String abi) {
+ return is64BitInstructionSet(getInstructionSet(abi));
+ }
}
diff --git a/libart/src/main/java/java/lang/ref/Reference.java b/libart/src/main/java/java/lang/ref/Reference.java
index 3b03ff1..31ea588 100644
--- a/libart/src/main/java/java/lang/ref/Reference.java
+++ b/libart/src/main/java/java/lang/ref/Reference.java
@@ -98,6 +98,22 @@
public abstract class Reference<T> {
/**
+ * Forces JNI path.
+ * If GC is not in progress (ie: not going through slow path), the referent
+ * can be quickly returned through intrinsic without passing through JNI.
+ * This flag forces the JNI path so that it can be tested and benchmarked.
+ */
+ private static boolean disableIntrinsic = false;
+
+ /**
+ * Slow path flag for the reference processor.
+ * Used by the reference processor to determine whether or not the referent
+ * can be immediately returned. Because the referent might get swept during
+ * GC, the slow path, which passes through JNI, must be taken.
+ */
+ private static boolean slowPathEnabled = false;
+
+ /**
* The object to which this reference refers.
* VM requirement: this field <em>must</em> be called "referent"
* and be an object.
diff --git a/libdvm/src/main/java/dalvik/system/VMRuntime.java b/libdvm/src/main/java/dalvik/system/VMRuntime.java
index 1d58d8d..f117b70 100644
--- a/libdvm/src/main/java/dalvik/system/VMRuntime.java
+++ b/libdvm/src/main/java/dalvik/system/VMRuntime.java
@@ -370,4 +370,12 @@
return instructionSet;
}
+
+ public static boolean is64BitInstructionSet(String instructionSet) {
+ return false;
+ }
+
+ public static boolean is64BitAbi(String abi) {
+ return false;
+ }
}
diff --git a/luni/src/main/java/android/system/ErrnoException.java b/luni/src/main/java/android/system/ErrnoException.java
index 134d6a0..90155c8 100644
--- a/luni/src/main/java/android/system/ErrnoException.java
+++ b/luni/src/main/java/android/system/ErrnoException.java
@@ -24,8 +24,6 @@
* A checked exception thrown when {@link Os} methods fail. This exception contains the native
* errno value, for comparison against the constants in {@link OsConstants}, should sophisticated
* callers need to adjust their behavior based on the exact failure.
- *
- * @hide
*/
public final class ErrnoException extends Exception {
private final String functionName;
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index e7613df..0b80b52 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -47,8 +47,6 @@
* primitives used to implement the higher-level APIs.
*
* <p>The corresponding constants can be found in {@link OsConstants}.
- *
- * @hide
*/
public final class Os {
private Os() {}
@@ -63,6 +61,8 @@
*/
public static boolean access(String path, int mode) throws ErrnoException { return Libcore.os.access(path, mode); }
+ /** @hide */ public static InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return Libcore.os.android_getaddrinfo(node, hints, netId); }
+
/**
* See <a href="http://man7.org/linux/man-pages/man2/bind.2.html">bind(2)</a>.
*/
@@ -157,8 +157,6 @@
*/
public static String gai_strerror(int error) { return Libcore.os.gai_strerror(error); }
- /** @hide */ public static InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException { return Libcore.os.getaddrinfo(node, hints); }
-
/**
* See <a href="http://man7.org/linux/man-pages/man2/getegid.2.html">getegid(2)</a>.
*/
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index cfed2f6..c758eb7 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -18,7 +18,6 @@
/**
* Constants and helper functions for use with {@link Os}.
- * @hide
*/
public final class OsConstants {
private OsConstants() {
@@ -352,6 +351,8 @@
public static final int POLLRDNORM = placeholder();
public static final int POLLWRBAND = placeholder();
public static final int POLLWRNORM = placeholder();
+ public static final int PR_GET_DUMPABLE = placeholder();
+ public static final int PR_SET_DUMPABLE = placeholder();
public static final int PR_SET_NO_NEW_PRIVS = placeholder();
public static final int PROT_EXEC = placeholder();
public static final int PROT_NONE = placeholder();
diff --git a/luni/src/main/java/android/system/StructPollfd.java b/luni/src/main/java/android/system/StructPollfd.java
index 8bdecb2..b812612 100644
--- a/luni/src/main/java/android/system/StructPollfd.java
+++ b/luni/src/main/java/android/system/StructPollfd.java
@@ -22,8 +22,6 @@
/**
* Used as an in/out parameter to {@link Os#poll}.
* Corresponds to C's {@code struct pollfd} from {@code <poll.h>}.
- *
- * @hide
*/
public final class StructPollfd {
/** The file descriptor to poll. */
diff --git a/luni/src/main/java/android/system/StructStat.java b/luni/src/main/java/android/system/StructStat.java
index 87bd50c..a6958c1 100644
--- a/luni/src/main/java/android/system/StructStat.java
+++ b/luni/src/main/java/android/system/StructStat.java
@@ -21,8 +21,6 @@
/**
* File information returned by {@link Os#fstat}, {@link Os#lstat}, and {@link Os#stat}.
* Corresponds to C's {@code struct stat} from {@code <stat.h>}.
- *
- * @hide
*/
public final class StructStat {
/** Device ID of device containing file. */
diff --git a/luni/src/main/java/android/system/StructStatVfs.java b/luni/src/main/java/android/system/StructStatVfs.java
index b0b7802..942a39a 100644
--- a/luni/src/main/java/android/system/StructStatVfs.java
+++ b/luni/src/main/java/android/system/StructStatVfs.java
@@ -20,8 +20,6 @@
/**
* File information returned by {@link Os#fstatvfs} and {@link Os#statvfs}.
- *
- * @hide
*/
public final class StructStatVfs {
/** File system block size (used for block counts). */
diff --git a/luni/src/main/java/android/system/StructUtsname.java b/luni/src/main/java/android/system/StructUtsname.java
index c62dbfa..5d9127b 100644
--- a/luni/src/main/java/android/system/StructUtsname.java
+++ b/luni/src/main/java/android/system/StructUtsname.java
@@ -21,8 +21,6 @@
/**
* Information returned by {@link Os#uname}.
* Corresponds to C's {@code struct utsname} from {@code <sys/utsname.h>}.
- *
- * @hide
*/
public final class StructUtsname {
/** The OS name, such as "Linux". */
diff --git a/luni/src/main/java/android/util/MutableBoolean.java b/luni/src/main/java/android/util/MutableBoolean.java
index 90bf68c..5a8a200 100644
--- a/luni/src/main/java/android/util/MutableBoolean.java
+++ b/luni/src/main/java/android/util/MutableBoolean.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableBoolean {
public boolean value;
diff --git a/luni/src/main/java/android/util/MutableByte.java b/luni/src/main/java/android/util/MutableByte.java
index 65738b9..7397ba4 100644
--- a/luni/src/main/java/android/util/MutableByte.java
+++ b/luni/src/main/java/android/util/MutableByte.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableByte {
public byte value;
diff --git a/luni/src/main/java/android/util/MutableChar.java b/luni/src/main/java/android/util/MutableChar.java
index b59bab3..f435331 100644
--- a/luni/src/main/java/android/util/MutableChar.java
+++ b/luni/src/main/java/android/util/MutableChar.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableChar {
public char value;
diff --git a/luni/src/main/java/android/util/MutableDouble.java b/luni/src/main/java/android/util/MutableDouble.java
index 3e2cc3a..f62f47e 100644
--- a/luni/src/main/java/android/util/MutableDouble.java
+++ b/luni/src/main/java/android/util/MutableDouble.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableDouble {
public double value;
diff --git a/luni/src/main/java/android/util/MutableFloat.java b/luni/src/main/java/android/util/MutableFloat.java
index 6e30501..6b5441c 100644
--- a/luni/src/main/java/android/util/MutableFloat.java
+++ b/luni/src/main/java/android/util/MutableFloat.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableFloat {
public float value;
diff --git a/luni/src/main/java/android/util/MutableInt.java b/luni/src/main/java/android/util/MutableInt.java
index 8220c44..2f93030 100644
--- a/luni/src/main/java/android/util/MutableInt.java
+++ b/luni/src/main/java/android/util/MutableInt.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableInt {
public int value;
diff --git a/luni/src/main/java/android/util/MutableLong.java b/luni/src/main/java/android/util/MutableLong.java
index 5df6a0d..94beab5 100644
--- a/luni/src/main/java/android/util/MutableLong.java
+++ b/luni/src/main/java/android/util/MutableLong.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableLong {
public long value;
diff --git a/luni/src/main/java/android/util/MutableShort.java b/luni/src/main/java/android/util/MutableShort.java
index 3880fef..cdd9923 100644
--- a/luni/src/main/java/android/util/MutableShort.java
+++ b/luni/src/main/java/android/util/MutableShort.java
@@ -17,7 +17,6 @@
package android.util;
/**
- * @hide
*/
public final class MutableShort {
public short value;
diff --git a/luni/src/main/java/java/lang/StringToReal.java b/luni/src/main/java/java/lang/StringToReal.java
index 0f4eb09..4bd4fb1 100644
--- a/luni/src/main/java/java/lang/StringToReal.java
+++ b/luni/src/main/java/java/lang/StringToReal.java
@@ -122,20 +122,20 @@
result.e = -result.e;
}
} catch (NumberFormatException ex) {
- // We already checked the string, so the exponent must have been out of range for an int.
+ // We already checked the string, so the exponent must have been out of range for an
+ // int.
if (negativeExponent) {
result.zero = true;
} else {
result.infinity = true;
}
- return result;
+ // Fall through: We want to check the content of the mantissa and throw an
+ // exception if it contains invalid characters. For example: "JUNK" * 10^12 should
+ // be treated as an error, not as infinity.
}
} else {
end = length;
}
- if (length == 0) {
- throw invalidReal(s, isDouble);
- }
int start = 0;
c = s.charAt(start);
@@ -151,7 +151,19 @@
throw invalidReal(s, isDouble);
}
- int decimal = s.indexOf('.');
+ // Confirm that the mantissa should parse.
+ int decimal = -1;
+ for (int i = start; i < end; i++) {
+ char mc = s.charAt(i);
+ if (mc == '.') {
+ if (decimal != -1) {
+ throw invalidReal(s, isDouble);
+ }
+ decimal = i;
+ } else if (mc < '0' || mc > '9') {
+ throw invalidReal(s, isDouble);
+ }
+ }
if (decimal > -1) {
result.e -= end - decimal - 1;
s = s.substring(start, decimal) + s.substring(decimal + 1, end);
@@ -159,10 +171,17 @@
s = s.substring(start, end);
}
- if ((length = s.length()) == 0) {
+ length = s.length();
+ if (length == 0) {
throw invalidReal(s, isDouble);
}
+ // All syntactic checks that might throw an exception are above. If we have established
+ // one of the non-exception error conditions we can stop here.
+ if (result.infinity || result.zero) {
+ return result;
+ }
+
end = length;
while (end > 1 && s.charAt(end - 1) == '0') {
--end;
diff --git a/luni/src/main/java/java/lang/System.java b/luni/src/main/java/java/lang/System.java
index e6303dd..2c5d634 100644
--- a/luni/src/main/java/java/lang/System.java
+++ b/luni/src/main/java/java/lang/System.java
@@ -729,11 +729,6 @@
}
p.put("java.home", javaHome);
- String ldLibraryPath = getenv("LD_LIBRARY_PATH");
- if (ldLibraryPath != null) {
- p.put("java.library.path", ldLibraryPath);
- }
-
p.put("java.specification.name", "Dalvik Core Library");
p.put("java.specification.vendor", projectName);
p.put("java.specification.version", "0.9");
diff --git a/luni/src/main/java/java/net/AddressCache.java b/luni/src/main/java/java/net/AddressCache.java
index 194761a..2aba78b 100644
--- a/luni/src/main/java/java/net/AddressCache.java
+++ b/luni/src/main/java/java/net/AddressCache.java
@@ -37,8 +37,36 @@
private static final long TTL_NANOS = 2 * 1000000000L;
// The actual cache.
- private final BasicLruCache<String, AddressCacheEntry> cache
- = new BasicLruCache<String, AddressCacheEntry>(MAX_ENTRIES);
+ private final BasicLruCache<AddressCacheKey, AddressCacheEntry> cache
+ = new BasicLruCache<AddressCacheKey, AddressCacheEntry>(MAX_ENTRIES);
+
+ static class AddressCacheKey {
+ private final String mHostname;
+ private final int mNetId;
+
+ AddressCacheKey(String hostname, int netId) {
+ mHostname = hostname;
+ mNetId = netId;
+ }
+
+ @Override public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof AddressCacheKey)) {
+ return false;
+ }
+ AddressCacheKey lhs = (AddressCacheKey) o;
+ return mHostname.equals(lhs.mHostname) && mNetId == lhs.mNetId;
+ }
+
+ @Override public int hashCode() {
+ int result = 17;
+ result = 31 * result + mNetId;
+ result = 31 * result + mHostname.hashCode();
+ return result;
+ }
+ }
static class AddressCacheEntry {
// Either an InetAddress[] for a positive entry,
@@ -67,12 +95,12 @@
}
/**
- * Returns the cached InetAddress[] associated with 'hostname'. Returns null if nothing is known
- * about 'hostname'. Returns a String suitable for use as an UnknownHostException detail
- * message if 'hostname' is known not to exist.
+ * Returns the cached InetAddress[] for 'hostname' on network 'netId'. Returns null
+ * if nothing is known about 'hostname'. Returns a String suitable for use as an
+ * UnknownHostException detail message if 'hostname' is known not to exist.
*/
- public Object get(String hostname) {
- AddressCacheEntry entry = cache.get(hostname);
+ public Object get(String hostname, int netId) {
+ AddressCacheEntry entry = cache.get(new AddressCacheKey(hostname, netId));
// Do we have a valid cache entry?
if (entry != null && entry.expiryNanos >= System.nanoTime()) {
return entry.value;
@@ -86,15 +114,15 @@
* Associates the given 'addresses' with 'hostname'. The association will expire after a
* certain length of time.
*/
- public void put(String hostname, InetAddress[] addresses) {
- cache.put(hostname, new AddressCacheEntry(addresses));
+ public void put(String hostname, int netId, InetAddress[] addresses) {
+ cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(addresses));
}
/**
* Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
* negative cache entry.)
*/
- public void putUnknownHost(String hostname, String detailMessage) {
- cache.put(hostname, new AddressCacheEntry(detailMessage));
+ public void putUnknownHost(String hostname, int netId, String detailMessage) {
+ cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(detailMessage));
}
}
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index e31b4c3..5cfa15a 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -127,6 +127,9 @@
private static final long serialVersionUID = 3286316764910316507L;
+ /** Using NetID of NETID_UNSET indicates resolution should be done on default network. */
+ private static final int NETID_UNSET = 0;
+
private int family;
byte[] ipaddress;
@@ -209,14 +212,29 @@
* @throws UnknownHostException if the address lookup fails.
*/
public static InetAddress[] getAllByName(String host) throws UnknownHostException {
- return getAllByNameImpl(host).clone();
+ return getAllByNameImpl(host, NETID_UNSET).clone();
}
/**
- * Returns the InetAddresses for {@code host}. The returned array is shared
- * and must be cloned before it is returned to application code.
+ * Operates identically to {@code getAllByName} except host resolution is
+ * performed on the network designated by {@code netId}.
+ *
+ * @param host the hostname or literal IP string to be resolved.
+ * @param netId the network to use for host resolution.
+ * @return the array of addresses associated with the specified host.
+ * @throws UnknownHostException if the address lookup fails.
+ * @hide internal use only
*/
- private static InetAddress[] getAllByNameImpl(String host) throws UnknownHostException {
+ public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException {
+ return getAllByNameImpl(host, netId).clone();
+ }
+
+ /**
+ * Returns the InetAddresses for {@code host} on network {@code netId}. The
+ * returned array is shared and must be cloned before it is returned to
+ * application code.
+ */
+ private static InetAddress[] getAllByNameImpl(String host, int netId) throws UnknownHostException {
if (host == null || host.isEmpty()) {
return loopbackAddresses();
}
@@ -231,7 +249,7 @@
return new InetAddress[] { result };
}
- return lookupHostByName(host).clone();
+ return lookupHostByName(host, netId).clone();
}
private static InetAddress makeInetAddress(byte[] bytes, String hostName) throws UnknownHostException {
@@ -264,7 +282,7 @@
hints.ai_flags = AI_NUMERICHOST;
InetAddress[] addresses = null;
try {
- addresses = Libcore.os.getaddrinfo(address, hints);
+ addresses = Libcore.os.android_getaddrinfo(address, hints, NETID_UNSET);
} catch (GaiException ignored) {
}
return (addresses != null) ? addresses[0] : null;
@@ -284,7 +302,22 @@
* if the address lookup fails.
*/
public static InetAddress getByName(String host) throws UnknownHostException {
- return getAllByNameImpl(host)[0];
+ return getAllByNameImpl(host, NETID_UNSET)[0];
+ }
+
+ /**
+ * Operates identically to {@code getByName} except host resolution is
+ * performed on the network designated by {@code netId}.
+ *
+ * @param host
+ * the hostName to be resolved to an address or {@code null}.
+ * @param netId the network to use for host resolution.
+ * @return the {@code InetAddress} instance representing the host.
+ * @throws UnknownHostException if the address lookup fails.
+ * @hide internal use only
+ */
+ public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException {
+ return getAllByNameImpl(host, netId)[0];
}
/**
@@ -360,7 +393,7 @@
*/
public static InetAddress getLocalHost() throws UnknownHostException {
String host = Libcore.os.uname().nodename;
- return lookupHostByName(host)[0];
+ return lookupHostByName(host, NETID_UNSET)[0];
}
/**
@@ -377,12 +410,14 @@
* Resolves a hostname to its IP addresses using a cache.
*
* @param host the hostname to resolve.
+ * @param netId the network to perform resolution upon.
* @return the IP addresses of the host.
*/
- private static InetAddress[] lookupHostByName(String host) throws UnknownHostException {
+ private static InetAddress[] lookupHostByName(String host, int netId)
+ throws UnknownHostException {
BlockGuard.getThreadPolicy().onNetwork();
// Do we have a result cached?
- Object cachedResult = addressCache.get(host);
+ Object cachedResult = addressCache.get(host, netId);
if (cachedResult != null) {
if (cachedResult instanceof InetAddress[]) {
// A cached positive result.
@@ -400,12 +435,12 @@
// for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
// anyway, just pick one.
hints.ai_socktype = SOCK_STREAM;
- InetAddress[] addresses = Libcore.os.getaddrinfo(host, hints);
+ InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
// TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
for (InetAddress address : addresses) {
address.hostName = host;
}
- addressCache.put(host, addresses);
+ addressCache.put(host, netId, addresses);
return addresses;
} catch (GaiException gaiException) {
// If the failure appears to have been a lack of INTERNET permission, throw a clear
@@ -418,7 +453,7 @@
}
// Otherwise, throw an UnknownHostException.
String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
- addressCache.putUnknownHost(host, detailMessage);
+ addressCache.putUnknownHost(host, netId, detailMessage);
throw gaiException.rethrowAsUnknownHostException(detailMessage);
}
}
diff --git a/luni/src/main/java/java/nio/ByteBuffer.java b/luni/src/main/java/java/nio/ByteBuffer.java
index 5873590..61093fa 100644
--- a/luni/src/main/java/java/nio/ByteBuffer.java
+++ b/luni/src/main/java/java/nio/ByteBuffer.java
@@ -69,7 +69,11 @@
if (capacity < 0) {
throw new IllegalArgumentException("capacity < 0: " + capacity);
}
- return new DirectByteBuffer(MemoryBlock.allocate(capacity), capacity, 0, false, null);
+ // Ensure alignment by 8.
+ MemoryBlock memoryBlock = MemoryBlock.allocate(capacity + 7);
+ long address = memoryBlock.toLong();
+ long alignedAddress = (address + 7) & ~(long)7;
+ return new DirectByteBuffer(memoryBlock, capacity, (int)(alignedAddress - address), false, null);
}
/**
diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java
index e736c40..9008637 100644
--- a/luni/src/main/java/java/nio/DatagramChannelImpl.java
+++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java
@@ -130,7 +130,6 @@
}
}
- /** @hide Until ready for a public API change */
@Override
synchronized public boolean isConnected() {
return connected;
diff --git a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
index 7185c32..ae33672 100644
--- a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
@@ -55,7 +55,6 @@
return socket;
}
- /** @hide Until ready for a public API change */
@Override
public SocketChannel accept() throws IOException {
if (!isOpen()) {
diff --git a/luni/src/main/java/java/security/Security.java b/luni/src/main/java/java/security/Security.java
index 81bafbd..b859f9a 100644
--- a/luni/src/main/java/java/security/Security.java
+++ b/luni/src/main/java/java/security/Security.java
@@ -348,6 +348,7 @@
* Sets the value of the specified security property.
*/
public static void setProperty(String key, String value) {
+ Services.setNeedRefresh();
secprops.put(key, value);
}
diff --git a/luni/src/main/java/java/text/DateFormatSymbols.java b/luni/src/main/java/java/text/DateFormatSymbols.java
index 0d33d75..cb9fdac 100644
--- a/luni/src/main/java/java/text/DateFormatSymbols.java
+++ b/luni/src/main/java/java/text/DateFormatSymbols.java
@@ -102,7 +102,7 @@
* the locale.
*/
public DateFormatSymbols(Locale locale) {
- this.locale = locale;
+ this.locale = LocaleData.mapInvalidAndNullLocales(locale);
this.localPatternChars = SimpleDateFormat.PATTERN_CHARS;
this.localeData = LocaleData.get(locale);
@@ -152,7 +152,12 @@
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
- this.localeData = LocaleData.get(locale);
+
+ // NOTE: We don't serialize the locale we were created with, so we can't
+ // get back the localeData object we want. This is broken for callers that
+ // access this field directly (i.e, SimpleDateFormat). We should ideally
+ // have serialized the locale we were created with.
+ this.localeData = LocaleData.get(Locale.getDefault());
}
private void writeObject(ObjectOutputStream oos) throws IOException {
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 1611594..6e25c1b 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -81,6 +81,7 @@
* the locale.
*/
public DecimalFormatSymbols(Locale locale) {
+ locale = LocaleData.mapInvalidAndNullLocales(locale);
LocaleData localeData = LocaleData.get(locale);
this.zeroDigit = localeData.zeroDigit;
this.digit = '#';
diff --git a/luni/src/main/java/java/util/Collections.java b/luni/src/main/java/java/util/Collections.java
index ce4e579..4541d64 100644
--- a/luni/src/main/java/java/util/Collections.java
+++ b/luni/src/main/java/java/util/Collections.java
@@ -1212,7 +1212,7 @@
int length = c.size();
Object[] result = new Object[length];
Iterator<?> it = iterator();
- for (int i = length; --i >= 0;) {
+ for (int i = 0; i < length; i++) {
result[i] = it.next();
}
return result;
diff --git a/luni/src/main/java/java/util/GregorianCalendar.java b/luni/src/main/java/java/util/GregorianCalendar.java
index 71b79dd..be96684 100644
--- a/luni/src/main/java/java/util/GregorianCalendar.java
+++ b/luni/src/main/java/java/util/GregorianCalendar.java
@@ -331,7 +331,16 @@
setTimeInMillis(System.currentTimeMillis());
}
- GregorianCalendar(boolean ignored) {
+ /**
+ * A minimum-cost constructor that does not initialize the current time or perform any date
+ * calculations. For use internally when the time will be set later. Other constructors, such as
+ * {@link GregorianCalendar#GregorianCalendar()}, set the time to the current system clock
+ * and recalculate the fields incurring unnecessary cost when the time or fields will be set
+ * later.
+ *
+ * @hide used internally
+ */
+ public GregorianCalendar(boolean ignored) {
super(TimeZone.getDefault());
setFirstDayOfWeek(SUNDAY);
setMinimalDaysInFirstWeek(1);
diff --git a/luni/src/main/java/java/util/IllformedLocaleException.java b/luni/src/main/java/java/util/IllformedLocaleException.java
index db1754e..3dec1cd 100644
--- a/luni/src/main/java/java/util/IllformedLocaleException.java
+++ b/luni/src/main/java/java/util/IllformedLocaleException.java
@@ -21,7 +21,6 @@
*
* See {@link Locale} and {@link Locale.Builder}.
*
- * @hide
* @since 1.7
*/
public class IllformedLocaleException extends RuntimeException {
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index a3eaf21..a8ff15d 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -253,7 +253,6 @@
*
* See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
*
- * @hide
* @since 1.7
*/
public static final char PRIVATE_USE_EXTENSION = 'x';
@@ -264,12 +263,16 @@
*
* See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
*
- * @hide
* @since 1.7
*/
public static final char UNICODE_LOCALE_EXTENSION = 'u';
/**
+ * ISO 639-3 generic code for undetermined languages.
+ */
+ private static final String UNDETERMINED_LANGUAGE = "und";
+
+ /**
* The current default locale. It is temporarily assigned to US because we
* need a default locale to lookup the real default locale.
*/
@@ -297,7 +300,6 @@
* the structured state (keywords and attributes) specified therein.
*
* @since 1.7
- * @hide
*/
public static final class Builder {
private String language;
@@ -340,18 +342,22 @@
* @throws IllformedLocaleException if the language was invalid.
*/
public Builder setLanguage(String language) {
- this.language = normalizeAndValidateLanguage(language);
+ this.language = normalizeAndValidateLanguage(language, true /* strict */);
return this;
}
- private static String normalizeAndValidateLanguage(String language) {
+ private static String normalizeAndValidateLanguage(String language, boolean strict) {
if (language == null || language.isEmpty()) {
return "";
}
final String lowercaseLanguage = language.toLowerCase(Locale.ROOT);
if (!isValidBcp47Alpha(lowercaseLanguage, 2, 3)) {
- throw new IllformedLocaleException("Invalid language: " + language);
+ if (strict) {
+ throw new IllformedLocaleException("Invalid language: " + language);
+ } else {
+ return UNDETERMINED_LANGUAGE;
+ }
}
return lowercaseLanguage;
@@ -377,7 +383,7 @@
return this;
}
- final Locale fromIcu = ICU.forLanguageTag(languageTag, true /* strict */);
+ final Locale fromIcu = forLanguageTag(languageTag, true /* strict */);
// When we ask ICU for strict parsing, it might return a null locale
// if the language tag is malformed.
if (fromIcu == null) {
@@ -400,11 +406,11 @@
* @throws IllformedLocaleException if {@code} region is invalid.
*/
public Builder setRegion(String region) {
- this.region = normalizeAndValidateRegion(region);
+ this.region = normalizeAndValidateRegion(region, true /* strict */);
return this;
}
- private static String normalizeAndValidateRegion(String region) {
+ private static String normalizeAndValidateRegion(String region, boolean strict) {
if (region == null || region.isEmpty()) {
return "";
}
@@ -412,7 +418,11 @@
final String uppercaseRegion = region.toUpperCase(Locale.ROOT);
if (!isValidBcp47Alpha(uppercaseRegion, 2, 2) &&
!isUnM49AreaCode(uppercaseRegion)) {
- throw new IllformedLocaleException("Invalid region: " + region);
+ if (strict) {
+ throw new IllformedLocaleException("Invalid region: " + region);
+ } else {
+ return "";
+ }
}
return uppercaseRegion;
@@ -453,27 +463,32 @@
String[] subTags = normalizedVariant.split("_");
for (String subTag : subTags) {
- // The BCP-47 spec states that :
- // - Subtags can be between [5, 8] alphanumeric chars in length.
- // - Subtags that start with a number are allowed to be 4 chars in length.
- if (subTag.length() >= 5 && subTag.length() <= 8) {
- if (!isAsciiAlphaNum(subTag)) {
- throw new IllformedLocaleException("Invalid variant: " + variant);
- }
- } else if (subTag.length() == 4) {
- final char firstChar = subTag.charAt(0);
- if (!(firstChar >= '0' && firstChar <= '9') || !isAsciiAlphaNum(subTag)) {
- throw new IllformedLocaleException("Invalid variant: " + variant);
- }
- } else {
+ if (!isValidVariantSubtag(subTag)) {
throw new IllformedLocaleException("Invalid variant: " + variant);
}
}
-
return normalizedVariant;
}
+ private static boolean isValidVariantSubtag(String subTag) {
+ // The BCP-47 spec states that :
+ // - Subtags can be between [5, 8] alphanumeric chars in length.
+ // - Subtags that start with a number are allowed to be 4 chars in length.
+ if (subTag.length() >= 5 && subTag.length() <= 8) {
+ if (isAsciiAlphaNum(subTag)) {
+ return true;
+ }
+ } else if (subTag.length() == 4) {
+ final char firstChar = subTag.charAt(0);
+ if ((firstChar >= '0' && firstChar <= '9') && isAsciiAlphaNum(subTag)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Sets the locale script. If {@code script} is {@code null} or empty,
* the previous value is cleared.
@@ -489,17 +504,24 @@
* @throws IllformedLocaleException if {@code script} is invalid.
*/
public Builder setScript(String script) {
+ this.script = normalizeAndValidateScript(script, true /* strict */);
+ return this;
+ }
+
+ private static String normalizeAndValidateScript(String script, boolean strict) {
if (script == null || script.isEmpty()) {
- this.script = "";
- return this;
+ return "";
}
if (!isValidBcp47Alpha(script, 4, 4)) {
- throw new IllformedLocaleException("Invalid script: " + script);
+ if (strict) {
+ throw new IllformedLocaleException("Invalid script: " + script);
+ } else {
+ return "";
+ }
}
- this.script = titleCaseAsciiWord(script);
- return this;
+ return titleCaseAsciiWord(script);
}
/**
@@ -787,7 +809,6 @@
*
* @throws NullPointerException if {@code languageTag} is {@code null}.
*
- * @hide
* @since 1.7
*/
public static Locale forLanguageTag(String languageTag) {
@@ -795,7 +816,7 @@
throw new NullPointerException("languageTag == null");
}
- return ICU.forLanguageTag(languageTag, false /* strict */);
+ return forLanguageTag(languageTag, false /* strict */);
}
private transient String countryCode;
@@ -1005,9 +1026,9 @@
return "";
}
- try {
- Builder.normalizeAndValidateRegion(countryCode);
- } catch (IllformedLocaleException ex) {
+ final String normalizedRegion = Builder.normalizeAndValidateRegion(
+ countryCode, false /* strict */);
+ if (normalizedRegion.isEmpty()) {
return countryCode;
}
@@ -1041,9 +1062,9 @@
// display language for the indeterminate language code.
//
// Sigh... ugh... and what not.
- try {
- Builder.normalizeAndValidateLanguage(languageCode);
- } catch (IllformedLocaleException ex) {
+ final String normalizedLanguage = Builder.normalizeAndValidateLanguage(
+ languageCode, false /* strict */);
+ if (UNDETERMINED_LANGUAGE.equals(normalizedLanguage)) {
return languageCode;
}
@@ -1125,6 +1146,8 @@
* Returns the full variant name in the default {@code Locale} for the variant code of
* this {@code Locale}. If there is no matching variant name, the variant code is
* returned.
+ *
+ * @since 1.7
*/
public final String getDisplayVariant() {
return getDisplayVariant(getDefault());
@@ -1134,6 +1157,8 @@
* Returns the full variant name in the specified {@code Locale} for the variant code
* of this {@code Locale}. If there is no matching variant name, the variant code is
* returned.
+ *
+ * @since 1.7
*/
public String getDisplayVariant(Locale locale) {
if (variantCode.isEmpty()) {
@@ -1238,7 +1263,6 @@
* If set, the script code will be a title cased string of length 4, as per the ISO 15924
* specification.
*
- * @hide
* @since 1.7
*/
public String getScript() {
@@ -1248,7 +1272,6 @@
/**
* Equivalent to {@code getDisplayScript(Locale.getDefault()))}
*
- * @hide
* @since 1.7
*/
public String getDisplayScript() {
@@ -1260,7 +1283,6 @@
* script code is unknown, the return value of this method is the same as that of
* {@link #getScript()}.
*
- * @hide
* @since 1.7
*/
public String getDisplayScript(Locale locale) {
@@ -1296,7 +1318,6 @@
* For example, we do not require scripts to be a registered ISO 15924 scripts or
* languages to appear in the ISO-639-2 code list.
*
- * @hide
* @since 1.7
*/
public String toLanguageTag() {
@@ -1331,17 +1352,8 @@
// in the builder, but we must use hyphens in the BCP-47 language tag.
variant = variantCode.replace('_', '-');
} else {
- try {
- language = Builder.normalizeAndValidateLanguage(languageCode);
- } catch (IllformedLocaleException ilfe) {
- // Ignored, continue processing with "".
- }
-
- try {
- region = Builder.normalizeAndValidateRegion(countryCode);
- } catch (IllformedLocaleException ilfe) {
- // Ignored, continue processing with "".
- }
+ language = Builder.normalizeAndValidateLanguage(languageCode, false /* strict */);
+ region = Builder.normalizeAndValidateRegion(countryCode, false /* strict */);
try {
variant = Builder.normalizeAndValidateVariant(variantCode);
@@ -1358,7 +1370,7 @@
}
if (language.isEmpty()) {
- language = "und";
+ language = UNDETERMINED_LANGUAGE;
}
if ("no".equals(language) && "NO".equals(region) && "NY".equals(variant)) {
@@ -1497,7 +1509,7 @@
private static String concatenateRange(String[] array, int start, int end) {
StringBuilder builder = new StringBuilder(32);
for (int i = start; i < end; ++i) {
- if (i != 0) {
+ if (i != start) {
builder.append('-');
}
builder.append(array[i]);
@@ -1512,7 +1524,6 @@
* See <a href="https://tools.ietf.org/html/bcp47#section-2.1">
* the IETF BCP-47 specification</a> (Section 2.2.6) for details.
*
- * @hide
* @since 1.7
*/
public Set<Character> getExtensionKeys() {
@@ -1527,7 +1538,6 @@
* locale extension can be fetched using {@link #getUnicodeLocaleAttributes()},
* {@link #getUnicodeLocaleKeys()} and {@link #getUnicodeLocaleType}.
*
- * @hide
* @since 1.7
*/
public String getExtension(char extensionKey) {
@@ -1540,7 +1550,6 @@
* For more information about types and keywords, see {@link Builder#setUnicodeLocaleKeyword}
* and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
*
- * @hide
* @since 1.7
*/
public String getUnicodeLocaleType(String keyWord) {
@@ -1553,7 +1562,6 @@
* For more information about attributes, see {@link Builder#addUnicodeLocaleAttribute}
* and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
*
- * @hide
* @since 1.7
*/
public Set<String> getUnicodeLocaleAttributes() {
@@ -1566,7 +1574,6 @@
* For more information about types and keywords, see {@link Builder#setUnicodeLocaleKeyword}
* and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
*
- * @hide
* @since 1.7
*/
public Set<String> getUnicodeLocaleKeys() {
@@ -1922,8 +1929,10 @@
while (true) {
final Map.Entry<String, String> keyWord = keywordsIterator.next();
sb.append(keyWord.getKey());
- sb.append('-');
- sb.append(keyWord.getValue());
+ if (!keyWord.getValue().isEmpty()) {
+ sb.append('-');
+ sb.append(keyWord.getValue());
+ }
if (keywordsIterator.hasNext()) {
sb.append('-');
} else {
@@ -1970,6 +1979,8 @@
if (subtagsForKeyword.size() > 0) {
keywords.put(lastKeyword, joinBcp47Subtags(subtagsForKeyword));
+ } else {
+ keywords.put(lastKeyword, "");
}
}
@@ -1991,7 +2002,10 @@
return sb.toString();
}
- private static String adjustLanguageCode(String languageCode) {
+ /**
+ * @hide for internal use only.
+ */
+ public static String adjustLanguageCode(String languageCode) {
String adjusted = languageCode.toLowerCase(Locale.US);
// Map new language codes to the obsolete language
// codes so the correct resource bundles will be used.
@@ -2005,4 +2019,230 @@
return adjusted;
}
+
+ /**
+ * Map of grandfathered language tags to their modern replacements.
+ */
+ private static final TreeMap<String, String> GRANDFATHERED_LOCALES;
+
+ static {
+ GRANDFATHERED_LOCALES = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+
+ // From http://tools.ietf.org/html/bcp47
+ //
+ // grandfathered = irregular ; non-redundant tags registered
+ // / regular ; during the RFC 3066 era
+ // irregular =
+ GRANDFATHERED_LOCALES.put("en-GB-oed", "en-GB-x-oed");
+ GRANDFATHERED_LOCALES.put("i-ami", "ami");
+ GRANDFATHERED_LOCALES.put("i-bnn", "bnn");
+ GRANDFATHERED_LOCALES.put("i-default", "en-x-i-default");
+ GRANDFATHERED_LOCALES.put("i-enochian", "und-x-i-enochian");
+ GRANDFATHERED_LOCALES.put("i-hak", "hak");
+ GRANDFATHERED_LOCALES.put("i-klingon", "tlh");
+ GRANDFATHERED_LOCALES.put("i-lux", "lb");
+ GRANDFATHERED_LOCALES.put("i-mingo", "see-x-i-mingo");
+ GRANDFATHERED_LOCALES.put("i-navajo", "nv");
+ GRANDFATHERED_LOCALES.put("i-pwn", "pwn");
+ GRANDFATHERED_LOCALES.put("i-tao", "tao");
+ GRANDFATHERED_LOCALES.put("i-tay", "tay");
+ GRANDFATHERED_LOCALES.put("i-tsu", "tsu");
+ GRANDFATHERED_LOCALES.put("sgn-BE-FR", "sfb");
+ GRANDFATHERED_LOCALES.put("sgn-BE-NL", "vgt");
+ GRANDFATHERED_LOCALES.put("sgn-CH-DE", "sgg");
+
+ // regular =
+ GRANDFATHERED_LOCALES.put("art-lojban", "jbo");
+ GRANDFATHERED_LOCALES.put("cel-gaulish", "xtg-x-cel-gaulish");
+ GRANDFATHERED_LOCALES.put("no-bok", "nb");
+ GRANDFATHERED_LOCALES.put("no-nyn", "nn");
+ GRANDFATHERED_LOCALES.put("zh-guoyu", "cmn");
+ GRANDFATHERED_LOCALES.put("zh-hakka", "hak");
+ GRANDFATHERED_LOCALES.put("zh-min", "nan-x-zh-min");
+ GRANDFATHERED_LOCALES.put("zh-min-nan", "nan");
+ GRANDFATHERED_LOCALES.put("zh-xiang", "hsn");
+ }
+
+ private static String convertGrandfatheredTag(String original) {
+ final String converted = GRANDFATHERED_LOCALES.get(original);
+ return converted != null ? converted : original;
+ }
+
+ /**
+ * Scans elements of {@code subtags} in the range {@code [startIndex, endIndex)}
+ * and appends valid variant subtags upto the first invalid subtag (if any) to
+ * {@code normalizedVariants}. All appended variant subtags are converted to uppercase.
+ */
+ private static void extractVariantSubtags(String[] subtags, int startIndex, int endIndex,
+ List<String> normalizedVariants) {
+ for (int i = startIndex; i < endIndex; i++) {
+ final String subtag = subtags[i];
+
+ if (Builder.isValidVariantSubtag(subtag)) {
+ normalizedVariants.add(subtag.toUpperCase(Locale.ROOT));
+ } else {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Scans elements of {@code subtags} in the range {@code [startIndex, endIndex)}
+ * and inserts valid extensions into {@code extensions}. The scan is aborted
+ * when an invalid extension is encountered. Returns the index of the first
+ * unparsable element of {@code subtags}.
+ */
+ private static int extractExtensions(String[] subtags, int startIndex, int endIndex,
+ Map<Character, String> extensions) {
+ int privateUseExtensionIndex = -1;
+ int extensionKeyIndex = -1;
+
+ int i = startIndex;
+ for (; i < endIndex; i++) {
+ final String subtag = subtags[i];
+
+ final boolean parsingPrivateUse = (privateUseExtensionIndex != -1) &&
+ (extensionKeyIndex == privateUseExtensionIndex);
+
+ // Note that private use extensions allow subtags of length 1.
+ // Private use extensions *must* come last, so there's no ambiguity
+ // in that case.
+ if (subtag.length() == 1 && !parsingPrivateUse) {
+ // Emit the last extension we encountered if any. First check
+ // whether we encountered two keys in a row (which is an error).
+ // Also checks if we already have an extension with the same key,
+ // which is again an error.
+ if (extensionKeyIndex != -1) {
+ if ((i - 1) == extensionKeyIndex) {
+ return extensionKeyIndex;
+ }
+
+ final String key = subtags[extensionKeyIndex];
+ if (extensions.containsKey(key.charAt(0))) {
+ return extensionKeyIndex;
+ }
+
+ final String value = concatenateRange(subtags, extensionKeyIndex + 1, i);
+ extensions.put(key.charAt(0), value.toLowerCase(Locale.ROOT));
+ }
+
+ // Mark the start of the next extension. Also keep track of whether this
+ // is a private use extension, and throw an error if it doesn't come last.
+ extensionKeyIndex = i;
+ if ("x".equals(subtag)) {
+ privateUseExtensionIndex = i;
+ } else if (privateUseExtensionIndex != -1) {
+ // The private use extension must come last.
+ return privateUseExtensionIndex;
+ }
+ } else if (extensionKeyIndex != -1) {
+ // We must have encountered a valid key in order to start parsing
+ // its subtags.
+ if (!isValidBcp47Alphanum(subtag, parsingPrivateUse ? 1 : 2, 8)) {
+ return i;
+ }
+ } else {
+ // Encountered a value without a preceding key.
+ return i;
+ }
+ }
+
+ if (extensionKeyIndex != -1) {
+ if ((i - 1) == extensionKeyIndex) {
+ return extensionKeyIndex;
+ }
+
+ final String key = subtags[extensionKeyIndex];
+ if (extensions.containsKey(key.charAt(0))) {
+ return extensionKeyIndex;
+ }
+
+ final String value = concatenateRange(subtags, extensionKeyIndex + 1, i);
+ extensions.put(key.charAt(0), value.toLowerCase(Locale.ROOT));
+ }
+
+ return i;
+ }
+
+ private static Locale forLanguageTag(/* @Nonnull */ String tag, boolean strict) {
+ final String converted = convertGrandfatheredTag(tag);
+ final String[] subtags = converted.split("-");
+
+ int lastSubtag = subtags.length;
+ for (int i = 0; i < subtags.length; ++i) {
+ final String subtag = subtags[i];
+ if (subtag.isEmpty() || subtag.length() > 8) {
+ if (strict) {
+ throw new IllformedLocaleException("Invalid subtag at index: " + i
+ + " in tag: " + tag);
+ } else {
+ lastSubtag = (i - 1);
+ }
+
+ break;
+ }
+ }
+
+ final String languageCode = Builder.normalizeAndValidateLanguage(subtags[0], strict);
+ String scriptCode = "";
+ int nextSubtag = 1;
+ if (lastSubtag > nextSubtag) {
+ scriptCode = Builder.normalizeAndValidateScript(subtags[nextSubtag], false /* strict */);
+ if (!scriptCode.isEmpty()) {
+ nextSubtag++;
+ }
+ }
+
+ String regionCode = "";
+ if (lastSubtag > nextSubtag) {
+ regionCode = Builder.normalizeAndValidateRegion(subtags[nextSubtag], false /* strict */);
+ if (!regionCode.isEmpty()) {
+ nextSubtag++;
+ }
+ }
+
+ List<String> variants = null;
+ if (lastSubtag > nextSubtag) {
+ variants = new ArrayList<String>();
+ extractVariantSubtags(subtags, nextSubtag, lastSubtag, variants);
+ nextSubtag += variants.size();
+ }
+
+ Map<Character, String> extensions = Collections.EMPTY_MAP;
+ if (lastSubtag > nextSubtag) {
+ extensions = new TreeMap<Character, String>();
+ nextSubtag = extractExtensions(subtags, nextSubtag, lastSubtag, extensions);
+ }
+
+ if (nextSubtag != lastSubtag) {
+ if (strict) {
+ throw new IllformedLocaleException("Unparseable subtag: " + subtags[nextSubtag]
+ + " from language tag: " + tag);
+ }
+ }
+
+ Set<String> unicodeKeywords = Collections.EMPTY_SET;
+ Map<String, String> unicodeAttributes = Collections.EMPTY_MAP;
+ if (extensions.containsKey(UNICODE_LOCALE_EXTENSION)) {
+ unicodeKeywords = new TreeSet<String>();
+ unicodeAttributes = new TreeMap<String, String>();
+ parseUnicodeExtension(extensions.get(UNICODE_LOCALE_EXTENSION).split("-"),
+ unicodeAttributes, unicodeKeywords);
+ }
+
+ String variantCode = "";
+ if (variants != null && !variants.isEmpty()) {
+ StringBuilder variantsBuilder = new StringBuilder(variants.size() * 8);
+ for (int i = 0; i < variants.size(); ++i) {
+ if (i != 0) {
+ variantsBuilder.append('_');
+ }
+ variantsBuilder.append(variants.get(i));
+ }
+ variantCode = variantsBuilder.toString();
+ }
+
+ return new Locale(languageCode, regionCode, variantCode, scriptCode,
+ unicodeKeywords, unicodeAttributes, extensions, true /* has validated fields */);
+ }
}
diff --git a/luni/src/main/java/java/util/TimeZone.java b/luni/src/main/java/java/util/TimeZone.java
index c024e8d..e4c68c5 100644
--- a/luni/src/main/java/java/util/TimeZone.java
+++ b/luni/src/main/java/java/util/TimeZone.java
@@ -329,7 +329,6 @@
}
// Special cases? These can clone an existing instance.
- // TODO: should we just add a cache to ZoneInfoDB instead?
if (id.length() == 3) {
if (id.equals("GMT")) {
return (TimeZone) GMT.clone();
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 54b53ae..b38d6a5 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -56,8 +56,6 @@
* actions subsequent to the access or removal of that element from
* the {@code ConcurrentLinkedDeque} in another thread.
*
- * @hide
- *
* @since 1.7
* @author Doug Lea
* @author Martin Buchholz
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 5ac01c8..9448616 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -39,7 +39,7 @@
* ForkJoinPool}s may also be appropriate for use with event-style
* tasks that are never joined.
*
- * <p>A static {@link #commonPool()} is available and appropriate for
+ * <p>A static {@code commonPool()} is available and appropriate for
* most applications. The common pool is used by any ForkJoinTask that
* is not explicitly submitted to a specified pool. Using the common
* pool normally reduces resource usage (its threads are slowly
@@ -127,7 +127,6 @@
* or internal resources have been exhausted.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public class ForkJoinPool extends AbstractExecutorService {
@@ -213,8 +212,7 @@
* choosing existing queues, and may be randomly repositioned upon
* contention with other submitters. In essence, submitters act
* like workers except that they are restricted to executing local
- * tasks that they submitted (or in the case of CountedCompleters,
- * others with the same root task). However, because most
+ * tasks that they submitted. However, because most
* shared/external queue operations are more expensive than
* internal, and because, at steady state, external submitters
* will compete for CPU with workers, ForkJoinTask.join and
@@ -419,12 +417,6 @@
* to find work (see MAX_HELP) and fall back to suspending the
* worker and if necessary replacing it with another.
*
- * Helping actions for CountedCompleters are much simpler: Method
- * helpComplete can take and execute any task with the same root
- * as the task being waited on. However, this still entails some
- * traversal of completer chains, so is less efficient than using
- * CountedCompleters without explicit joins.
- *
* It is impossible to keep exactly the target parallelism number
* of threads running at any given time. Determining the
* existence of conservatively safe helping targets, the
@@ -2907,7 +2899,7 @@
* Possibly initiates an orderly shutdown in which previously
* submitted tasks are executed, but no new tasks will be
* accepted. Invocation has no effect on execution state if this
- * is the {@link #commonPool()}, and no additional effect if
+ * is the {@code commonPool()}, and no additional effect if
* already shut down. Tasks that are in the process of being
* submitted concurrently during the course of this method may or
* may not be rejected.
@@ -2920,7 +2912,7 @@
/**
* Possibly attempts to cancel and/or stop all tasks, and reject
* all subsequently submitted tasks. Invocation has no effect on
- * execution state if this is the {@link #commonPool()}, and no
+ * execution state if this is the {@code commonPool()}, and no
* additional effect if already shut down. Otherwise, tasks that
* are in the process of being submitted or executed concurrently
* during the course of this method may or may not be
@@ -2979,8 +2971,8 @@
/**
* Blocks until all tasks have completed execution after a
* shutdown request, or the timeout occurs, or the current thread
- * is interrupted, whichever happens first. Because the {@link
- * #commonPool()} never terminates until program shutdown, when
+ * is interrupted, whichever happens first. Because the {@code
+ * commonPool()} never terminates until program shutdown, when
* applied to the common pool, this method is equivalent to {@link
* #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
*
@@ -3064,7 +3056,7 @@
/**
* Waits and/or attempts to assist performing tasks indefinitely
- * until the {@link #commonPool()} {@link #isQuiescent}.
+ * until the {@code commonPool()} {@link #isQuiescent}.
*/
static void quiesceCommonPool() {
common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
index 6d25775..c6bc6de 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -32,8 +32,8 @@
*
* <p>A "main" {@code ForkJoinTask} begins execution when it is
* explicitly submitted to a {@link ForkJoinPool}, or, if not already
- * engaged in a ForkJoin computation, commenced in the {@link
- * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * engaged in a ForkJoin computation, commenced in the {@code
+ * ForkJoinPool.commonPool()} via {@link #fork}, {@link #invoke}, or
* related methods. Once started, it will usually in turn start other
* subtasks. As indicated by the name of this class, many programs
* using {@code ForkJoinTask} employ only methods {@link #fork} and
@@ -74,10 +74,9 @@
* but doing do requires three further considerations: (1) Completion
* of few if any <em>other</em> tasks should be dependent on a task
* that blocks on external synchronization or I/O. Event-style async
- * tasks that are never joined (for example, those subclassing {@link
- * CountedCompleter}) often fall into this category. (2) To minimize
- * resource impact, tasks should be small; ideally performing only the
- * (possibly) blocking action. (3) Unless the {@link
+ * tasks that are never joined often fall into this category.
+ * (2) To minimize resource impact, tasks should be small; ideally
+ * performing only the (possibly) blocking action. (3) Unless the {@link
* ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
* blocked tasks is known to be less than the pool's {@link
* ForkJoinPool#getParallelism} level, the pool cannot guarantee that
@@ -120,13 +119,11 @@
* <p>The ForkJoinTask class is not usually directly subclassed.
* Instead, you subclass one of the abstract classes that support a
* particular style of fork/join processing, typically {@link
- * RecursiveAction} for most computations that do not return results,
- * {@link RecursiveTask} for those that do, and {@link
- * CountedCompleter} for those in which completed actions trigger
- * other actions. Normally, a concrete ForkJoinTask subclass declares
- * fields comprising its parameters, established in a constructor, and
- * then defines a {@code compute} method that somehow uses the control
- * methods supplied by this base class.
+ * RecursiveAction} for most computations that do not return results
+ * and {@link RecursiveTask} for those that do. Normally, a concrete
+ * ForkJoinTask subclass declares fields comprising its parameters,
+ * established in a constructor, and then defines a {@code compute}
+ * method that somehow uses the control methods supplied by this base class.
*
* <p>Method {@link #join} and its variants are appropriate for use
* only when completion dependencies are acyclic; that is, the
@@ -138,9 +135,9 @@
* may be of use in constructing custom subclasses for problems that
* are not statically structured as DAGs. To support such usages, a
* ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
- * value using {@link #setForkJoinTaskTag} or {@link
- * #compareAndSetForkJoinTaskTag} and checked using {@link
- * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * value using {@code setForkJoinTaskTag} or {@code
+ * compareAndSetForkJoinTaskTag} and checked using {@code
+ * getForkJoinTaskTag}. The ForkJoinTask implementation does not use
* these {@code protected} methods or tags for any purpose, but they
* may be of use in the construction of specialized subclasses. For
* example, parallel graph traversals can use the supplied methods to
@@ -178,7 +175,6 @@
* execution. Serialization is not relied on during execution itself.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
@@ -645,8 +641,8 @@
/**
* Arranges to asynchronously execute this task in the pool the
- * current task is running in, if applicable, or using the {@link
- * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}. While
+ * current task is running in, if applicable, or using the {@code
+ * ForkJoinPool.commonPool()} if not {@link #inForkJoinPool}. While
* it is not necessarily enforced, it is a usage error to fork a
* task more than once unless it has completed and been
* reinitialized. Subsequent modifications to the state of this
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index 5f2799b..ae28700 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -18,7 +18,6 @@
* {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public class ForkJoinWorkerThread extends Thread {
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index cff5dbf..a041fb1 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -50,7 +50,6 @@
* the {@code LinkedTransferQueue} in another thread.
*
* @since 1.7
- * @hide
* @author Doug Lea
* @param <E> the type of elements held in this collection
*/
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
index a9adbe5..a97d187 100644
--- a/luni/src/main/java/java/util/concurrent/Phaser.java
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -227,7 +227,6 @@
* of participants.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public class Phaser {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
index 8d666f6..e3a6340 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveAction.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
@@ -131,7 +131,6 @@
* }}</pre>
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public abstract class RecursiveAction extends ForkJoinTask<Void> {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
index 421c9d3..80baa52 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -34,7 +34,6 @@
* sequentially solve rather than subdividing.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index a52351b..483981d 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -690,7 +690,6 @@
* @param value if {@code true}, remove on cancellation, else don't
* @see #getRemoveOnCancelPolicy
* @since 1.7
- * @hide
*/
public void setRemoveOnCancelPolicy(boolean value) {
removeOnCancel = value;
@@ -705,7 +704,6 @@
* from the queue
* @see #setRemoveOnCancelPolicy
* @since 1.7
- * @hide
*/
public boolean getRemoveOnCancelPolicy() {
return removeOnCancel;
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index a559321..5baf75f 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -30,7 +30,6 @@
* generation methods.
*
* @since 1.7
- * @hide
* @author Doug Lea
*/
public class ThreadLocalRandom extends Random {
diff --git a/luni/src/main/java/java/util/concurrent/TransferQueue.java b/luni/src/main/java/java/util/concurrent/TransferQueue.java
index 9cd5773..4c2be6f 100644
--- a/luni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -33,7 +33,6 @@
* and {@code transfer} are effectively synonymous.
*
* @since 1.7
- * @hide
* @author Doug Lea
* @param <E> the type of elements held in this collection
*/
diff --git a/luni/src/main/java/java/util/concurrent/atomic/Fences.java b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
index 7ecf45a..5714ba0 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/Fences.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
@@ -453,7 +453,6 @@
*
* </dl>
*
- * @since 1.7
* @hide
* @author Doug Lea
*/
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 4c5e280..37aa9d0 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -1255,7 +1255,6 @@
* current thread, and {@code false} if the current thread
* is at the head of the queue or the queue is empty
* @since 1.7
- * @hide
*/
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 0350060..e711da5 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -1485,7 +1485,6 @@
* current thread, and {@code false} if the current thread
* is at the head of the queue or the queue is empty
* @since 1.7
- * @hide
*/
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/jar/JarEntry.java b/luni/src/main/java/java/util/jar/JarEntry.java
index 85c8678..bceef63 100644
--- a/luni/src/main/java/java/util/jar/JarEntry.java
+++ b/luni/src/main/java/java/util/jar/JarEntry.java
@@ -17,16 +17,16 @@
package java.util.jar;
-import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.security.CodeSigner;
import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
import java.util.zip.ZipEntry;
/**
@@ -114,8 +114,12 @@
* entry or {@code null} if none exists. Make sure that the everything is
* read from the input stream before calling this method, or else the method
* returns {@code null}.
+ * <p>
+ * This method returns all the signers' unverified chains concatenated
+ * together in one array. To know which certificates were tied to the
+ * private keys that made the signatures on this entry, see
+ * {@link #getCodeSigners()} instead.
*
- * @return the certificate for this entry.
* @see java.security.cert.Certificate
*/
public Certificate[] getCertificates() {
@@ -126,7 +130,27 @@
if (jarVerifier == null) {
return null;
}
- return jarVerifier.getCertificates(getName());
+
+ Certificate[][] certChains = jarVerifier.getCertificateChains(getName());
+ if (certChains == null) {
+ return null;
+ }
+
+ // Measure number of certs.
+ int count = 0;
+ for (Certificate[] chain : certChains) {
+ count += chain.length;
+ }
+
+ // Create new array and copy all the certs into it.
+ Certificate[] certs = new Certificate[count];
+ int i = 0;
+ for (Certificate[] chain : certChains) {
+ System.arraycopy(chain, 0, certs, i, chain.length);
+ i += chain.length;
+ }
+
+ return certs;
}
void setAttributes(Attributes attrib) {
@@ -138,68 +162,60 @@
* JAR file. If there is no such code signer, it returns {@code null}. Make
* sure that the everything is read from the input stream before calling
* this method, or else the method returns {@code null}.
+ * <p>
+ * Only the digital signature on the entry is cryptographically verified.
+ * None of the certificates in the the {@link CertPath} returned from
+ * {@link CodeSigner#getSignerCertPath()} are verified and must be verified
+ * by the caller if needed. See {@link CertPathValidator} for more
+ * information.
*
- * @return the code signers for the JAR entry.
+ * @return an array of CodeSigner for this JAR entry.
* @see CodeSigner
*/
public CodeSigner[] getCodeSigners() {
+ if (parentJar == null) {
+ return null;
+ }
+
+ JarVerifier jarVerifier = parentJar.verifier;
+ if (jarVerifier == null) {
+ return null;
+ }
+
if (signers == null) {
- signers = getCodeSigners(getCertificates());
+ signers = getCodeSigners(jarVerifier.getCertificateChains(getName()));
}
if (signers == null) {
return null;
}
- CodeSigner[] tmp = new CodeSigner[signers.length];
- System.arraycopy(signers, 0, tmp, 0, tmp.length);
- return tmp;
+ return signers.clone();
}
- private CodeSigner[] getCodeSigners(Certificate[] certs) {
- if (certs == null) {
+ private CodeSigner[] getCodeSigners(Certificate[][] certChains) {
+ if (certChains == null) {
return null;
}
- X500Principal prevIssuer = null;
- ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length);
- ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>();
+ ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>(certChains.length);
- for (Certificate element : certs) {
- if (!(element instanceof X509Certificate)) {
- // Only X509Certificate-s are taken into account - see API spec.
- continue;
- }
- X509Certificate x509 = (X509Certificate) element;
- if (prevIssuer != null) {
- X500Principal subj = x509.getSubjectX500Principal();
- if (!prevIssuer.equals(subj)) {
- // Ok, this ends the previous chain,
- // so transform this one into CertPath ...
- addCodeSigner(asigners, list);
- // ... and start a new one
- list.clear();
- }// else { it's still the same chain }
-
- }
- prevIssuer = x509.getIssuerX500Principal();
- list.add(x509);
- }
- if (!list.isEmpty()) {
- addCodeSigner(asigners, list);
- }
- if (asigners.isEmpty()) {
- // 'signers' is 'null' already
- return null;
+ for (Certificate[] chain : certChains) {
+ addCodeSigner(asigners, chain);
}
CodeSigner[] tmp = new CodeSigner[asigners.size()];
asigners.toArray(tmp);
return tmp;
-
}
- private void addCodeSigner(ArrayList<CodeSigner> asigners,
- List<Certificate> list) {
+ private void addCodeSigner(ArrayList<CodeSigner> asigners, Certificate[] certs) {
+ for (Certificate cert : certs) {
+ // Only X509Certificate instances are counted. See API spec.
+ if (!(cert instanceof X509Certificate)) {
+ return;
+ }
+ }
+
CertPath certPath = null;
if (!isFactoryChecked) {
try {
@@ -214,7 +230,7 @@
return;
}
try {
- certPath = factory.generateCertPath(list);
+ certPath = factory.generateCertPath(Arrays.asList(certs));
} catch (CertificateException ex) {
// do nothing
}
diff --git a/luni/src/main/java/java/util/jar/JarFile.java b/luni/src/main/java/java/util/jar/JarFile.java
index a089019..6b147f6 100644
--- a/luni/src/main/java/java/util/jar/JarFile.java
+++ b/luni/src/main/java/java/util/jar/JarFile.java
@@ -196,16 +196,6 @@
* If the file cannot be read.
*/
public JarFile(File file, boolean verify, int mode) throws IOException {
- this(file, verify, mode, false);
- }
-
- /**
- * See previous constructor for other parameter definitions.
- * @param chainCheck
- * whether or not to check certificate chain signatures
- * @hide
- */
- public JarFile(File file, boolean verify, int mode, boolean chainCheck) throws IOException {
super(file, mode);
// Step 1: Scan the central directory for meta entries (MANIFEST.mf
@@ -225,7 +215,7 @@
// We create the manifest straight away, so that we can create
// the jar verifier as well.
manifest = new Manifest(metaEntries.get(MANIFEST_NAME), true);
- verifier = new JarVerifier(getName(), manifest, metaEntries, chainCheck);
+ verifier = new JarVerifier(getName(), manifest, metaEntries);
} else {
verifier = null;
manifestBytes = metaEntries.get(MANIFEST_NAME);
@@ -257,17 +247,7 @@
* If file cannot be opened or read.
*/
public JarFile(String filename, boolean verify) throws IOException {
- this(filename, verify, false);
- }
-
- /**
- * See previous constructor for other parameter definitions.
- * @param chainCheck
- * whether or not to check certificate chain signatures
- * @hide
- */
- public JarFile(String filename, boolean verify, boolean chainCheck) throws IOException {
- this(new File(filename), verify, ZipFile.OPEN_READ, chainCheck);
+ this(new File(filename), verify, ZipFile.OPEN_READ);
}
/**
diff --git a/luni/src/main/java/java/util/jar/JarVerifier.java b/luni/src/main/java/java/util/jar/JarVerifier.java
index f78cbe8..467e298 100644
--- a/luni/src/main/java/java/util/jar/JarVerifier.java
+++ b/luni/src/main/java/java/util/jar/JarVerifier.java
@@ -27,7 +27,6 @@
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
@@ -72,11 +71,8 @@
private final Hashtable<String, Certificate[]> certificates =
new Hashtable<String, Certificate[]>(5);
- private final Hashtable<String, Certificate[]> verifiedEntries =
- new Hashtable<String, Certificate[]>();
-
- /** Whether or not to check certificate chain signatures. */
- private final boolean chainCheck;
+ private final Hashtable<String, Certificate[][]> verifiedEntries =
+ new Hashtable<String, Certificate[][]>();
/**
* Stores and a hash and a message digest and verifies that massage digest
@@ -90,16 +86,16 @@
private final byte[] hash;
- private final Certificate[] certificates;
+ private final Certificate[][] certChains;
- private final Hashtable<String, Certificate[]> verifiedEntries;
+ private final Hashtable<String, Certificate[][]> verifiedEntries;
VerifierEntry(String name, MessageDigest digest, byte[] hash,
- Certificate[] certificates, Hashtable<String, Certificate[]> verifedEntries) {
+ Certificate[][] certChains, Hashtable<String, Certificate[][]> verifedEntries) {
this.name = name;
this.digest = digest;
this.hash = hash;
- this.certificates = certificates;
+ this.certChains = certChains;
this.verifiedEntries = verifedEntries;
}
@@ -135,7 +131,7 @@
if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
throw invalidDigest(JarFile.MANIFEST_NAME, name, name);
}
- verifiedEntries.put(name, certificates);
+ verifiedEntries.put(name, certChains);
}
}
@@ -150,27 +146,16 @@
}
/**
- * Convenience constructor for backward compatibility.
- */
- JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries) {
- this(name, manifest, metaEntries, false);
- }
-
- /**
* Constructs and returns a new instance of {@code JarVerifier}.
*
* @param name
* the name of the JAR file being verified.
- * @param chainCheck
- * whether to check the certificate chain signatures
*/
- JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries,
- boolean chainCheck) {
+ JarVerifier(String name, Manifest manifest, HashMap<String, byte[]> metaEntries) {
jarName = name;
this.manifest = manifest;
this.metaEntries = metaEntries;
this.mainAttributesEnd = manifest.getMainAttributesEnd();
- this.chainCheck = chainCheck;
}
/**
@@ -199,7 +184,7 @@
return null;
}
- ArrayList<Certificate> certs = new ArrayList<Certificate>();
+ ArrayList<Certificate[]> certChains = new ArrayList<Certificate[]>();
Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
@@ -209,16 +194,16 @@
String signatureFile = entry.getKey();
Certificate[] certChain = certificates.get(signatureFile);
if (certChain != null) {
- Collections.addAll(certs, certChain);
+ certChains.add(certChain);
}
}
}
// entry is not signed
- if (certs.isEmpty()) {
+ if (certChains.isEmpty()) {
return null;
}
- Certificate[] certificatesArray = certs.toArray(new Certificate[certs.size()]);
+ Certificate[][] certChainsArray = certChains.toArray(new Certificate[certChains.size()][]);
for (int i = 0; i < DIGEST_ALGORITHMS.length; i++) {
final String algorithm = DIGEST_ALGORITHMS[i];
@@ -230,9 +215,8 @@
try {
return new VerifierEntry(name, MessageDigest.getInstance(algorithm), hashBytes,
- certificatesArray, verifiedEntries);
- } catch (NoSuchAlgorithmException e) {
- // ignored
+ certChainsArray, verifiedEntries);
+ } catch (NoSuchAlgorithmException ignored) {
}
}
return null;
@@ -309,15 +293,7 @@
try {
Certificate[] signerCertChain = JarUtils.verifySignature(
new ByteArrayInputStream(sfBytes),
- new ByteArrayInputStream(sBlockBytes),
- chainCheck);
- /*
- * Recursive call in loading security provider related class which
- * is in a signed JAR.
- */
- if (metaEntries == null) {
- return;
- }
+ new ByteArrayInputStream(sBlockBytes));
if (signerCertChain != null) {
certificates.put(signatureFile, signerCertChain);
}
@@ -418,20 +394,16 @@
}
/**
- * Returns all of the {@link java.security.cert.Certificate} instances that
+ * Returns all of the {@link java.security.cert.Certificate} chains that
* were used to verify the signature on the JAR entry called
- * {@code name}.
+ * {@code name}. Callers must not modify the returned arrays.
*
* @param name
* the name of a JAR entry.
- * @return an array of {@link java.security.cert.Certificate}.
+ * @return an array of {@link java.security.cert.Certificate} chains.
*/
- Certificate[] getCertificates(String name) {
- Certificate[] verifiedCerts = verifiedEntries.get(name);
- if (verifiedCerts == null) {
- return null;
- }
- return verifiedCerts.clone();
+ Certificate[][] getCertificateChains(String name) {
+ return verifiedEntries.get(name);
}
/**
diff --git a/luni/src/main/java/java/util/jar/StrictJarFile.java b/luni/src/main/java/java/util/jar/StrictJarFile.java
index 80b4fe9..4a8af5f 100644
--- a/luni/src/main/java/java/util/jar/StrictJarFile.java
+++ b/luni/src/main/java/java/util/jar/StrictJarFile.java
@@ -63,7 +63,7 @@
// or manifests, so it's best to throw as early as possible.
HashMap<String, byte[]> metaEntries = getMetaEntries();
this.manifest = new Manifest(metaEntries.get(JarFile.MANIFEST_NAME), true);
- this.verifier = new JarVerifier(fileName, manifest, metaEntries, true);
+ this.verifier = new JarVerifier(fileName, manifest, metaEntries);
isSigned = verifier.readCertificates() && verifier.isSignedJar();
} catch (IOException ioe) {
@@ -87,16 +87,51 @@
}
/**
- * Return all certificates for a given {@link ZipEntry} belonging to this jar.
+ * Return all certificate chains for a given {@link ZipEntry} belonging to this jar.
* This method MUST be called only after fully exhausting the InputStream belonging
* to this entry.
*
* Returns {@code null} if this jar file isn't signed or if this method is
* called before the stream is processed.
*/
+ public Certificate[][] getCertificateChains(ZipEntry ze) {
+ if (isSigned) {
+ return verifier.getCertificateChains(ze.getName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return all certificates for a given {@link ZipEntry} belonging to this jar.
+ * This method MUST be called only after fully exhausting the InputStream belonging
+ * to this entry.
+ *
+ * Returns {@code null} if this jar file isn't signed or if this method is
+ * called before the stream is processed.
+ *
+ * @deprecated Switch callers to use getCertificateChains instead
+ */
+ @Deprecated
public Certificate[] getCertificates(ZipEntry ze) {
if (isSigned) {
- return verifier.getCertificates(ze.getName());
+ Certificate[][] certChains = verifier.getCertificateChains(ze.getName());
+
+ // Measure number of certs.
+ int count = 0;
+ for (Certificate[] chain : certChains) {
+ count += chain.length;
+ }
+
+ // Create new array and copy all the certs into it.
+ Certificate[] certs = new Certificate[count];
+ int i = 0;
+ for (Certificate[] chain : certChains) {
+ System.arraycopy(chain, 0, certs, i, chain.length);
+ i += chain.length;
+ }
+
+ return certs;
}
return null;
diff --git a/luni/src/main/java/javax/crypto/SealedObject.java b/luni/src/main/java/javax/crypto/SealedObject.java
index cfb970b..4b91184 100644
--- a/luni/src/main/java/javax/crypto/SealedObject.java
+++ b/luni/src/main/java/javax/crypto/SealedObject.java
@@ -19,6 +19,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -29,6 +30,7 @@
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
+import libcore.io.IoUtils;
/**
* A {@code SealedObject} is a wrapper around a {@code serializable} object
@@ -57,14 +59,21 @@
private String paramsAlg;
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
- // We do unshared reads here to ensure we have our own clones of the byte[]s.
- encodedParams = (byte[]) s.readUnshared();
- encryptedContent = (byte[]) s.readUnshared();
- // These are regular shared reads because the algorithms used by a given stream are
- // almost certain to the be same for each object, and String is immutable anyway,
- // so there's no security concern about sharing.
- sealAlg = (String) s.readObject();
- paramsAlg = (String) s.readObject();
+ // This implementation is based on the latest recommendations for safe deserialization at
+ // the time of writing. See the Serialization spec section A.6.
+ ObjectInputStream.GetField fields = s.readFields();
+
+ // The mutable byte arrays are cloned and the immutable strings are not.
+ this.encodedParams = getSafeCopy(fields, "encodedParams");
+ this.encryptedContent = getSafeCopy(fields, "encryptedContent");
+ this.paramsAlg = (String) fields.get("paramsAlg", null);
+ this.sealAlg = (String) fields.get("sealAlg", null);
+ }
+
+ private static byte[] getSafeCopy(ObjectInputStream.GetField fields, String fieldName)
+ throws IOException {
+ byte[] fieldValue = (byte[]) fields.get(fieldName, null);
+ return fieldValue != null ? fieldValue.clone() : null;
}
/**
@@ -87,13 +96,14 @@
* if the cipher is {@code null}.
*/
public SealedObject(Serializable object, Cipher c)
- throws IOException, IllegalBlockSizeException {
+ throws IOException, IllegalBlockSizeException {
if (c == null) {
throw new NullPointerException("c == null");
}
+ ObjectOutputStream oos = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
AlgorithmParameters ap = c.getParameters();
@@ -105,6 +115,8 @@
// should be never thrown because the cipher
// should be initialized for encryption
throw new IOException(e.toString());
+ } finally {
+ IoUtils.closeQuietly(oos);
}
}
@@ -119,8 +131,10 @@
if (so == null) {
throw new NullPointerException("so == null");
}
- this.encryptedContent = so.encryptedContent;
- this.encodedParams = so.encodedParams;
+ // For safety: clone the mutable arrays so that each object has its own independent copy of
+ // the data.
+ this.encryptedContent = so.encryptedContent != null ? so.encryptedContent.clone() : null;
+ this.encodedParams = so.encodedParams != null ? so.encodedParams.clone() : null;
this.sealAlg = so.sealAlg;
this.paramsAlg = so.paramsAlg;
}
@@ -158,18 +172,14 @@
try {
Cipher cipher = Cipher.getInstance(sealAlg);
if ((paramsAlg != null) && (paramsAlg.length() != 0)) {
- AlgorithmParameters params =
- AlgorithmParameters.getInstance(paramsAlg);
+ AlgorithmParameters params = AlgorithmParameters.getInstance(paramsAlg);
params.init(encodedParams);
cipher.init(Cipher.DECRYPT_MODE, key, params);
} else {
cipher.init(Cipher.DECRYPT_MODE, key);
}
byte[] serialized = cipher.doFinal(encryptedContent);
- ObjectInputStream ois =
- new ObjectInputStream(
- new ByteArrayInputStream(serialized));
- return ois.readObject();
+ return readSerialized(serialized);
} catch (NoSuchPaddingException e) {
// should not be thrown because cipher text was made
// with existing padding
@@ -186,7 +196,7 @@
// should not be thrown because the cipher text
// was correctly made
throw new NoSuchAlgorithmException(e.toString());
- } catch (IllegalStateException e) {
+ } catch (IllegalStateException e) {
// should never be thrown because cipher is initialized
throw new NoSuchAlgorithmException(e.toString());
}
@@ -217,10 +227,7 @@
throw new NullPointerException("c == null");
}
byte[] serialized = c.doFinal(encryptedContent);
- ObjectInputStream ois =
- new ObjectInputStream(
- new ByteArrayInputStream(serialized));
- return ois.readObject();
+ return readSerialized(serialized);
}
/**
@@ -253,18 +260,14 @@
try {
Cipher cipher = Cipher.getInstance(sealAlg, provider);
if ((paramsAlg != null) && (paramsAlg.length() != 0)) {
- AlgorithmParameters params =
- AlgorithmParameters.getInstance(paramsAlg);
+ AlgorithmParameters params = AlgorithmParameters.getInstance(paramsAlg);
params.init(encodedParams);
cipher.init(Cipher.DECRYPT_MODE, key, params);
} else {
cipher.init(Cipher.DECRYPT_MODE, key);
}
byte[] serialized = cipher.doFinal(encryptedContent);
- ObjectInputStream ois =
- new ObjectInputStream(
- new ByteArrayInputStream(serialized));
- return ois.readObject();
+ return readSerialized(serialized);
} catch (NoSuchPaddingException e) {
// should not be thrown because cipher text was made
// with existing padding
@@ -286,4 +289,15 @@
throw new NoSuchAlgorithmException(e.toString());
}
}
+
+ private static Object readSerialized(byte[] serialized)
+ throws IOException, ClassNotFoundException {
+ ObjectInputStream ois = null;
+ try {
+ ois = new ObjectInputStream(new ByteArrayInputStream(serialized));
+ return ois.readObject();
+ } finally {
+ IoUtils.closeQuietly(ois);
+ }
+ }
}
diff --git a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
index fa11371..65c8b03 100644
--- a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
+++ b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
@@ -154,10 +154,7 @@
int suffixLength = cn.length() - (asterisk + 1);
int suffixStart = hostName.length() - suffixLength;
if (hostName.indexOf('.', asterisk) < suffixStart) {
- // TODO: remove workaround for *.clients.google.com http://b/5426333
- if (!hostName.endsWith(".clients.google.com")) {
- return false; // wildcard '*' can't match a '.'
- }
+ return false; // wildcard '*' can't match a '.'
}
if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) {
diff --git a/luni/src/main/java/javax/net/ssl/SSLEngine.java b/luni/src/main/java/javax/net/ssl/SSLEngine.java
index 59cdf62..3ba3450 100644
--- a/luni/src/main/java/javax/net/ssl/SSLEngine.java
+++ b/luni/src/main/java/javax/net/ssl/SSLEngine.java
@@ -542,14 +542,14 @@
* <td>20+</td>
* </tr>
* <tr>
- * <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
- * <td></td>
+ * <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA</td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
- * <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
- * <td></td>
+ * <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA</td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_NULL_WITH_NULL_NULL</td>
@@ -558,22 +558,22 @@
* </tr>
* <tr>
* <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>21+</td>
* <td></td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_AES_128_CBC_SHA</td>
- * <td>20+</td>
- * <td></td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_AES_256_CBC_SHA</td>
- * <td>20+</td>
- * <td></td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>21+</td>
* <td></td>
* </tr>
* <tr>
@@ -639,6 +639,9 @@
* </tbody>
* </table>
*
+ * <p><em>NOTE</em>: PSK cipher suites are enabled by default only if the {@code SSLContext} through
+ * which the engine was created has been initialized with a {@code PSKKeyManager}.
+ *
* @since 1.5
*/
public abstract class SSLEngine {
diff --git a/luni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java b/luni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
index cce72cd..03b8828 100644
--- a/luni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
+++ b/luni/src/main/java/javax/net/ssl/SSLServerSocketFactory.java
@@ -20,6 +20,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.net.ServerSocketFactory;
+import org.apache.harmony.security.fortress.Services;
/**
* The factory for SSL server sockets.
@@ -32,6 +33,8 @@
private static String defaultName;
+ private static int lastCacheVersion = -1;
+
/**
* Returns the default {@code SSLServerSocketFactory} instance. The default
* implementation is defined by the security property
@@ -40,6 +43,12 @@
* @return the default {@code SSLServerSocketFactory} instance.
*/
public static synchronized ServerSocketFactory getDefault() {
+ int newCacheVersion = Services.getCacheVersion();
+ if (lastCacheVersion != newCacheVersion) {
+ defaultServerSocketFactory = null;
+ defaultName = null;
+ lastCacheVersion = newCacheVersion;
+ }
if (defaultServerSocketFactory != null) {
return defaultServerSocketFactory;
}
diff --git a/luni/src/main/java/javax/net/ssl/SSLSocket.java b/luni/src/main/java/javax/net/ssl/SSLSocket.java
index 72e1dbe..33a88b6 100644
--- a/luni/src/main/java/javax/net/ssl/SSLSocket.java
+++ b/luni/src/main/java/javax/net/ssl/SSLSocket.java
@@ -346,14 +346,14 @@
* <td>11+</td>
* </tr>
* <tr>
- * <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256</td>
- * <td>20+</td>
- * <td></td>
+ * <td>TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA</td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
- * <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384</td>
- * <td>20+</td>
- * <td></td>
+ * <td>TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA</td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA</td>
@@ -522,22 +522,22 @@
* </tr>
* <tr>
* <td>TLS_PSK_WITH_3DES_EDE_CBC_SHA</td>
- * <td>20+</td>
+ * <td>21+</td>
* <td></td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_AES_128_CBC_SHA</td>
- * <td>20+</td>
- * <td></td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_AES_256_CBC_SHA</td>
- * <td>20+</td>
- * <td></td>
+ * <td>21+</td>
+ * <td>21+</td>
* </tr>
* <tr>
* <td>TLS_PSK_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>21+</td>
* <td></td>
* </tr>
* <tr>
@@ -578,6 +578,9 @@
* </tbody>
* </table>
*
+ * <p><em>NOTE</em>: PSK cipher suites are enabled by default only if the {@code SSLContext} through
+ * which the socket was created has been initialized with a {@code PSKKeyManager}.
+ *
* <p>API Levels 1 to 8 use OpenSSL names for cipher suites. The table below
* lists these OpenSSL names and their corresponding standard names used in API
* Levels 9 and newer.
diff --git a/luni/src/main/java/javax/net/ssl/SSLSocketFactory.java b/luni/src/main/java/javax/net/ssl/SSLSocketFactory.java
index b07d0fd..b506fa62 100644
--- a/luni/src/main/java/javax/net/ssl/SSLSocketFactory.java
+++ b/luni/src/main/java/javax/net/ssl/SSLSocketFactory.java
@@ -22,6 +22,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.net.SocketFactory;
+import org.apache.harmony.security.fortress.Services;
/**
* The abstract factory implementation to create {@code SSLSocket}s.
@@ -32,7 +33,7 @@
// The default SSL socket factory
private static SocketFactory defaultSocketFactory;
- private static String defaultName;
+ private static int lastCacheVersion = -1;
/**
* Returns the default {@code SSLSocketFactory} instance. The default is
@@ -41,23 +42,39 @@
* @return the default ssl socket factory instance.
*/
public static synchronized SocketFactory getDefault() {
- if (defaultSocketFactory != null) {
+ int newCacheVersion = Services.getCacheVersion();
+ if (defaultSocketFactory != null && lastCacheVersion == newCacheVersion) {
return defaultSocketFactory;
}
- if (defaultName == null) {
- defaultName = Security.getProperty("ssl.SocketFactory.provider");
- if (defaultName != null) {
- ClassLoader cl = Thread.currentThread().getContextClassLoader();
- if (cl == null) {
- cl = ClassLoader.getSystemClassLoader();
- }
- try {
- final Class<?> sfc = Class.forName(defaultName, true, cl);
- defaultSocketFactory = (SocketFactory) sfc.newInstance();
- } catch (Exception e) {
- System.logE("Problem creating " + defaultName, e);
+ lastCacheVersion = newCacheVersion;
+
+ String newName = Security.getProperty("ssl.SocketFactory.provider");
+ if (newName != null) {
+ /* The cache could have been invalidated, but the provider name didn't change. This
+ * will be the most common state, so check for it early without resetting the default
+ * SocketFactory.
+ */
+ if (defaultSocketFactory != null) {
+ if (newName.equals(defaultSocketFactory.getClass().getName())) {
+ return defaultSocketFactory;
+ } else {
+ defaultSocketFactory = null;
}
}
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ if (cl == null) {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ try {
+ final Class<?> sfc = Class.forName(newName, true, cl);
+ defaultSocketFactory = (SocketFactory) sfc.newInstance();
+ } catch (Exception e) {
+ System.logW("Could not create " + newName + " with ClassLoader "
+ + cl.toString() + ": " + e.getMessage());
+ }
+ } else {
+ defaultSocketFactory = null;
}
if (defaultSocketFactory == null) {
@@ -71,10 +88,12 @@
defaultSocketFactory = context.getSocketFactory();
}
}
+
if (defaultSocketFactory == null) {
// Use internal implementation
defaultSocketFactory = new DefaultSSLSocketFactory("No SSLSocketFactory installed");
}
+
return defaultSocketFactory;
}
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index 33c899e..06e2205 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -58,18 +58,6 @@
return isoCountries.clone();
}
- public static Locale forLanguageTag(String languageTag, boolean strict) {
- final String icuLocaleId = localeForLanguageTag(languageTag, strict);
- if (icuLocaleId == null) {
- // TODO: We should probably return "und" here. From what I can tell,
- // this happens only when the language in the languageTag is bad.
- // Investigate this a bit more.
- return null;
- }
-
- return localeFromIcuLocaleId(icuLocaleId);
- }
-
private static final int IDX_LANGUAGE = 0;
private static final int IDX_SCRIPT = 1;
private static final int IDX_REGION = 2;
@@ -444,9 +432,7 @@
private static native String[] getISOLanguagesNative();
private static native String[] getISOCountriesNative();
- private static native String localeForLanguageTag(String languageTag, boolean strict);
-
- static native boolean initLocaleDataNative(String locale, LocaleData result);
+ static native boolean initLocaleDataNative(String languageTag, LocaleData result);
/**
* Takes a BCP-47 language tag (Locale.toLanguageTag()). e.g. en-US, not en_US
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index 845ba32..ec05b53 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -112,27 +112,36 @@
private LocaleData() {
}
+ public static Locale mapInvalidAndNullLocales(Locale locale) {
+ if (locale == null) {
+ return Locale.getDefault();
+ }
+
+ if ("und".equals(locale.toLanguageTag())) {
+ return Locale.ROOT;
+ }
+
+ return locale;
+ }
+
/**
* Returns a shared LocaleData for the given locale.
*/
public static LocaleData get(Locale locale) {
- if (locale == null) {
- locale = Locale.getDefault();
- }
- String localeName = locale.toString();
+ final String languageTag = locale.toLanguageTag();
synchronized (localeDataCache) {
- LocaleData localeData = localeDataCache.get(localeName);
+ LocaleData localeData = localeDataCache.get(languageTag);
if (localeData != null) {
return localeData;
}
}
LocaleData newLocaleData = initLocaleData(locale);
synchronized (localeDataCache) {
- LocaleData localeData = localeDataCache.get(localeName);
+ LocaleData localeData = localeDataCache.get(languageTag);
if (localeData != null) {
return localeData;
}
- localeDataCache.put(localeName, newLocaleData);
+ localeDataCache.put(languageTag, newLocaleData);
return newLocaleData;
}
}
@@ -171,7 +180,7 @@
private static LocaleData initLocaleData(Locale locale) {
LocaleData localeData = new LocaleData();
- if (!ICU.initLocaleDataNative(locale.toString(), localeData)) {
+ if (!ICU.initLocaleDataNative(locale.toLanguageTag(), localeData)) {
throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
}
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index d09e442..bf4b448 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -52,6 +52,7 @@
public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { return os.accept(fd, peerAddress); }
public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
+ public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return os.android_getaddrinfo(node, hints, netId); }
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
@@ -73,7 +74,6 @@
public void fsync(FileDescriptor fd) throws ErrnoException { os.fsync(fd); }
public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { os.ftruncate(fd, length); }
public String gai_strerror(int error) { return os.gai_strerror(error); }
- public InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException { return os.getaddrinfo(node, hints); }
public int getegid() { return os.getegid(); }
public int geteuid() { return os.geteuid(); }
public int getgid() { return os.getgid(); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index a537aeb..511bb27 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -43,6 +43,7 @@
public interface Os {
public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
public boolean access(String path, int mode) throws ErrnoException;
+ public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
public void chmod(String path, int mode) throws ErrnoException;
public void chown(String path, int uid, int gid) throws ErrnoException;
@@ -64,7 +65,6 @@
public void fsync(FileDescriptor fd) throws ErrnoException;
public void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
public String gai_strerror(int error);
- public InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException;
public int getegid();
public int geteuid();
public int getgid();
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 7551190..f5eaaa3 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -46,6 +46,7 @@
public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
public native boolean access(String path, int mode) throws ErrnoException;
+ public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
public native void chmod(String path, int mode) throws ErrnoException;
public native void chown(String path, int uid, int gid) throws ErrnoException;
@@ -67,7 +68,6 @@
public native void fsync(FileDescriptor fd) throws ErrnoException;
public native void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
public native String gai_strerror(int error);
- public native InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException;
public native int getegid();
public native int geteuid();
public native int getgid();
diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java
index 54ee667..fbd120b 100644
--- a/luni/src/main/java/libcore/util/ZoneInfo.java
+++ b/luni/src/main/java/libcore/util/ZoneInfo.java
@@ -13,11 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+/*
+ * Elements of the WallTime class are a port of Bionic's localtime.c to Java. That code had the
+ * following header:
+ *
+ * This file is in the public domain, so clarified as of
+ * 1996-06-05 by Arthur David Olson.
+ */
package libcore.util;
import java.util.Arrays;
+import java.util.Calendar;
import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.TimeZone;
import libcore.io.BufferIterator;
@@ -51,7 +59,7 @@
private final byte[] mTypes;
private final byte[] mIsDsts;
- public static TimeZone makeTimeZone(String id, BufferIterator it) {
+ public static ZoneInfo makeTimeZone(String id, BufferIterator it) {
// Variable names beginning tzh_ correspond to those in "tzfile.h".
// Check tzh_magic.
@@ -301,4 +309,664 @@
",transitions=" + mTransitions.length +
"]";
}
+
+ @Override
+ public Object clone() {
+ // Overridden for documentation. The default clone() behavior is exactly what we want.
+ // Though mutable, the arrays of offset data are treated as immutable. Only ID and
+ // mRawOffset are mutable in this class, and those are an immutable object and a primitive
+ // respectively.
+ return super.clone();
+ }
+
+ /**
+ * A class that represents a "wall time". This class is modeled on the C tm struct and
+ * is used to support android.text.format.Time behavior. Unlike the tm struct the year is
+ * represented as the full year, not the years since 1900.
+ *
+ * <p>This class contains a rewrite of various native functions that android.text.format.Time
+ * once relied on such as mktime_tz and localtime_tz. This replacement does not support leap
+ * seconds but does try to preserve behavior around ambiguous date/times found in the BSD
+ * version of mktime that was previously used.
+ *
+ * <p>The original native code used a 32-bit value for time_t on 32-bit Android, which
+ * was the only variant of Android available at the time. To preserve old behavior this code
+ * deliberately uses {@code int} rather than {@code long} for most things and performs
+ * calculations in seconds. This creates deliberate truncation issues for date / times before
+ * 1901 and after 2038. This is intentional but might be fixed in future if all the knock-ons
+ * can be resolved: Application code may have come to rely on the range so previously values
+ * like zero for year could indicate an invalid date but if we move to long the year zero would
+ * be valid.
+ *
+ * <p>All offsets are considered to be safe for addition / subtraction / multiplication without
+ * worrying about overflow. All absolute time arithmetic is checked for overflow / underflow.
+ */
+ public static class WallTime {
+
+ // We use a GregorianCalendar (set to UTC) to handle all the date/time normalization logic
+ // and to convert from a broken-down date/time to a millis value.
+ // Unfortunately, it cannot represent an initial state with a zero day and would
+ // automatically normalize it, so we must copy values into and out of it as needed.
+ private final GregorianCalendar calendar;
+
+ private int year;
+ private int month;
+ private int monthDay;
+ private int hour;
+ private int minute;
+ private int second;
+ private int weekDay;
+ private int yearDay;
+ private int isDst;
+ private int gmtOffsetSeconds;
+
+ public WallTime() {
+ this.calendar = new GregorianCalendar(false);
+ calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+ }
+
+ /**
+ * Sets the wall time to a point in time using the time zone information provided. This
+ * is a replacement for the old native localtime_tz() function.
+ *
+ * <p>When going from an instant to a wall time it is always unambiguous because there
+ * is only one offset rule acting at any given instant. We do not consider leap seconds.
+ */
+ public void localtime(int timeSeconds, ZoneInfo zoneInfo) {
+ try {
+ int offsetSeconds = zoneInfo.mRawOffset / 1000;
+
+ // Find out the timezone DST state and adjustment.
+ byte isDst;
+ if (zoneInfo.mTransitions.length == 0) {
+ isDst = 0;
+ } else {
+ // transitionIndex can be in the range -1..zoneInfo.mTransitions.length - 1
+ int transitionIndex = findTransitionIndex(zoneInfo, timeSeconds);
+ if (transitionIndex < 0) {
+ // -1 means timeSeconds is "before the first recorded transition". The first
+ // recorded transition is treated as a transition from non-DST and the raw
+ // offset.
+ isDst = 0;
+ } else {
+ byte transitionType = zoneInfo.mTypes[transitionIndex];
+ offsetSeconds += zoneInfo.mOffsets[transitionType];
+ isDst = zoneInfo.mIsDsts[transitionType];
+ }
+ }
+
+ // Perform arithmetic that might underflow before setting fields.
+ int wallTimeSeconds = checkedAdd(timeSeconds, offsetSeconds);
+
+ // Set fields.
+ calendar.setTimeInMillis(wallTimeSeconds * 1000L);
+ copyFieldsFromCalendar();
+ this.isDst = isDst;
+ this.gmtOffsetSeconds = offsetSeconds;
+ } catch (CheckedArithmeticException e) {
+ // Just stop, leaving fields untouched.
+ }
+ }
+
+ /**
+ * Returns the time in seconds since beginning of the Unix epoch for the wall time using the
+ * time zone information provided. This is a replacement for an old native mktime_tz() C
+ * function.
+ *
+ * <p>When going from a wall time to an instant the answer can be ambiguous. A wall
+ * time can map to zero, one or two instants given sane date/time transitions. Sane
+ * in this case means that transitions occur less frequently than the offset
+ * differences between them (which could cause all sorts of craziness like the
+ * skipping out of transitions).
+ *
+ * <p>For example, this is not fully supported:
+ * <ul>
+ * <li>t1 { time = 1, offset = 0 }
+ * <li>t2 { time = 2, offset = -1 }
+ * <li>t3 { time = 3, offset = -2 }
+ * </ul>
+ * A wall time in this case might map to t1, t2 or t3.
+ *
+ * <p>We do not handle leap seconds.
+ * <p>We assume that no timezone offset transition has an absolute offset > 24 hours.
+ * <p>We do not assume that adjacent transitions modify the DST state; adjustments can
+ * occur for other reasons such as when a zone changes its raw offset.
+ */
+ public int mktime(ZoneInfo zoneInfo) {
+ // Normalize isDst to -1, 0 or 1 to simplify isDst equality checks below.
+ this.isDst = this.isDst > 0 ? this.isDst = 1 : this.isDst < 0 ? this.isDst = -1 : 0;
+
+ copyFieldsToCalendar();
+ final long longWallTimeSeconds = calendar.getTimeInMillis() / 1000;
+ if (Integer.MIN_VALUE > longWallTimeSeconds
+ || longWallTimeSeconds > Integer.MAX_VALUE) {
+ // For compatibility with the old native 32-bit implementation we must treat
+ // this as an error. Note: -1 could be confused with a real time.
+ return -1;
+ }
+
+ try {
+ final int wallTimeSeconds = (int) longWallTimeSeconds;
+ final int rawOffsetSeconds = zoneInfo.mRawOffset / 1000;
+ final int rawTimeSeconds = checkedSubtract(wallTimeSeconds, rawOffsetSeconds);
+
+ if (zoneInfo.mTransitions.length == 0) {
+ // There is no transition information. There is just a raw offset for all time.
+ if (this.isDst > 0) {
+ // Caller has asserted DST, but there is no DST information available.
+ return -1;
+ }
+ copyFieldsFromCalendar();
+ this.isDst = 0;
+ this.gmtOffsetSeconds = rawOffsetSeconds;
+ return rawTimeSeconds;
+ }
+
+ // We cannot know for sure what instant the wall time will map to. Unfortunately, in
+ // order to know for sure we need the timezone information, but to get the timezone
+ // information we need an instant. To resolve this we use the raw offset to find an
+ // OffsetInterval; this will get us the OffsetInterval we need or very close.
+
+ // The initialTransition can be between -1 and (zoneInfo.mTransitions - 1). -1
+ // indicates the rawTime is before the first transition and is handled gracefully by
+ // createOffsetInterval().
+ final int initialTransitionIndex = findTransitionIndex(zoneInfo, rawTimeSeconds);
+
+ if (isDst < 0) {
+ // This is treated as a special case to get it out of the way:
+ // When a caller has set isDst == -1 it means we can return the first match for
+ // the wall time we find. If the caller has specified a wall time that cannot
+ // exist this always returns -1.
+
+ Integer result = doWallTimeSearch(zoneInfo, initialTransitionIndex,
+ wallTimeSeconds, true /* mustMatchDst */);
+ return result == null ? -1 : result;
+ }
+
+ // If the wall time asserts a DST (isDst == 0 or 1) the search is performed twice:
+ // 1) The first attempts to find a DST offset that matches isDst exactly.
+ // 2) If it fails, isDst is assumed to be incorrect and adjustments are made to see
+ // if a valid wall time can be created. The result can be somewhat arbitrary.
+
+ Integer result = doWallTimeSearch(zoneInfo, initialTransitionIndex, wallTimeSeconds,
+ true /* mustMatchDst */);
+ if (result == null) {
+ result = doWallTimeSearch(zoneInfo, initialTransitionIndex, wallTimeSeconds,
+ false /* mustMatchDst */);
+ }
+ if (result == null) {
+ result = -1;
+ }
+ return result;
+ } catch (CheckedArithmeticException e) {
+ return -1;
+ }
+ }
+
+ /**
+ * Attempt to apply DST adjustments to {@code oldWallTimeSeconds} to create a wall time in
+ * {@code targetInterval}.
+ *
+ * <p>This is used when a caller has made an assertion about standard time / DST that cannot
+ * be matched to any offset interval that exists. We must therefore assume that the isDst
+ * assertion is incorrect and the invalid wall time is the result of some modification the
+ * caller made to a valid wall time that pushed them outside of the offset interval they
+ * were in. We must correct for any DST change that should have been applied when they did
+ * so.
+ *
+ * <p>Unfortunately, we have no information about what adjustment they made and so cannot
+ * know which offset interval they were previously in. For example, they may have added a
+ * second or a year to a valid time to arrive at what they have.
+ *
+ * <p>We try all offset types that are not the same as the isDst the caller asserted. For
+ * each possible offset we work out the offset difference between that and
+ * {@code targetInterval}, apply it, and see if we are still in {@code targetInterval}. If
+ * we are, then we have found an adjustment.
+ */
+ private Integer tryOffsetAdjustments(ZoneInfo zoneInfo, int oldWallTimeSeconds,
+ OffsetInterval targetInterval, int transitionIndex, int isDstToFind)
+ throws CheckedArithmeticException {
+
+ int[] offsetsToTry = getOffsetsOfType(zoneInfo, transitionIndex, isDstToFind);
+ for (int j = 0; j < offsetsToTry.length; j++) {
+ int rawOffsetSeconds = zoneInfo.mRawOffset / 1000;
+ int jOffsetSeconds = rawOffsetSeconds + offsetsToTry[j];
+ int targetIntervalOffsetSeconds = targetInterval.getTotalOffsetSeconds();
+ int adjustmentSeconds = targetIntervalOffsetSeconds - jOffsetSeconds;
+ int adjustedWallTimeSeconds = checkedAdd(oldWallTimeSeconds, adjustmentSeconds);
+ if (targetInterval.containsWallTime(adjustedWallTimeSeconds)) {
+ // Perform any arithmetic that might overflow.
+ int returnValue = checkedSubtract(adjustedWallTimeSeconds,
+ targetIntervalOffsetSeconds);
+
+ // Modify field state and return the result.
+ calendar.setTimeInMillis(adjustedWallTimeSeconds * 1000L);
+ copyFieldsFromCalendar();
+ this.isDst = targetInterval.getIsDst();
+ this.gmtOffsetSeconds = targetIntervalOffsetSeconds;
+ return returnValue;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return an array of offsets that have the requested {@code isDst} value.
+ * The {@code startIndex} is used as a starting point so transitions nearest
+ * to that index are returned first.
+ */
+ private static int[] getOffsetsOfType(ZoneInfo zoneInfo, int startIndex, int isDst) {
+ // +1 to account for the synthetic transition we invent before the first recorded one.
+ int[] offsets = new int[zoneInfo.mOffsets.length + 1];
+ boolean[] seen = new boolean[zoneInfo.mOffsets.length];
+ int numFound = 0;
+
+ int delta = 0;
+ boolean clampTop = false;
+ boolean clampBottom = false;
+ do {
+ // delta = { 1, -1, 2, -2, 3, -3...}
+ delta *= -1;
+ if (delta >= 0) {
+ delta++;
+ }
+
+ int transitionIndex = startIndex + delta;
+ if (delta < 0 && transitionIndex < -1) {
+ clampBottom = true;
+ continue;
+ } else if (delta > 0 && transitionIndex >= zoneInfo.mTypes.length) {
+ clampTop = true;
+ continue;
+ }
+
+ if (transitionIndex == -1) {
+ if (isDst == 0) {
+ // Synthesize a non-DST transition before the first transition we have
+ // data for.
+ offsets[numFound++] = 0; // offset of 0 from raw offset
+ }
+ continue;
+ }
+ byte type = zoneInfo.mTypes[transitionIndex];
+ if (!seen[type]) {
+ if (zoneInfo.mIsDsts[type] == isDst) {
+ offsets[numFound++] = zoneInfo.mOffsets[type];
+ }
+ seen[type] = true;
+ }
+ } while (!(clampTop && clampBottom));
+
+ int[] toReturn = new int[numFound];
+ System.arraycopy(offsets, 0, toReturn, 0, numFound);
+ return toReturn;
+ }
+
+ /**
+ * Find a time <em>in seconds</em> the same or close to {@code wallTimeSeconds} that
+ * satisfies {@code mustMatchDst}. The search begins around the timezone offset transition
+ * with {@code initialTransitionIndex}.
+ *
+ * <p>If {@code mustMatchDst} is {@code true} the method can only return times that
+ * use timezone offsets that satisfy the {@code this.isDst} requirements.
+ * If {@code this.isDst == -1} it means that any offset can be used.
+ *
+ * <p>If {@code mustMatchDst} is {@code false} any offset that covers the
+ * currently set time is acceptable. That is: if {@code this.isDst} == -1, any offset
+ * transition can be used, if it is 0 or 1 the offset used must match {@code this.isDst}.
+ *
+ * <p>Note: This method both uses and can modify field state. It returns the matching time
+ * in seconds if a match has been found and modifies fields, or it returns {@code null} and
+ * leaves the field state unmodified.
+ */
+ private Integer doWallTimeSearch(ZoneInfo zoneInfo, int initialTransitionIndex,
+ int wallTimeSeconds, boolean mustMatchDst) throws CheckedArithmeticException {
+
+ // The loop below starts at the initialTransitionIndex and radiates out from that point
+ // up to 24 hours in either direction by applying transitionIndexDelta to inspect
+ // adjacent transitions (0, -1, +1, -2, +2). 24 hours is used because we assume that no
+ // total offset from UTC is ever > 24 hours. clampTop and clampBottom are used to
+ // indicate whether the search has either searched > 24 hours or exhausted the
+ // transition data in that direction. The search stops when a match is found or if
+ // clampTop and clampBottom are both true.
+ // The match logic employed is determined by the mustMatchDst parameter.
+ final int MAX_SEARCH_SECONDS = 24 * 60 * 60;
+ boolean clampTop = false, clampBottom = false;
+ int loop = 0;
+ do {
+ // transitionIndexDelta = { 0, -1, 1, -2, 2,..}
+ int transitionIndexDelta = (loop + 1) / 2;
+ if (loop % 2 == 1) {
+ transitionIndexDelta *= -1;
+ }
+ loop++;
+
+ // Only do any work in this iteration if we need to.
+ if (transitionIndexDelta > 0 && clampTop
+ || transitionIndexDelta < 0 && clampBottom) {
+ continue;
+ }
+
+ // Obtain the OffsetInterval to use.
+ int currentTransitionIndex = initialTransitionIndex + transitionIndexDelta;
+ OffsetInterval offsetInterval =
+ OffsetInterval.create(zoneInfo, currentTransitionIndex);
+ if (offsetInterval == null) {
+ // No transition exists with the index we tried: Stop searching in the
+ // current direction.
+ clampTop |= (transitionIndexDelta > 0);
+ clampBottom |= (transitionIndexDelta < 0);
+ continue;
+ }
+
+ // Match the wallTimeSeconds against the OffsetInterval.
+ if (mustMatchDst) {
+ // Work out if the interval contains the wall time the caller specified and
+ // matches their isDst value.
+ if (offsetInterval.containsWallTime(wallTimeSeconds)) {
+ if (this.isDst == -1 || offsetInterval.getIsDst() == this.isDst) {
+ // This always returns the first OffsetInterval it finds that matches
+ // the wall time and isDst requirements. If this.isDst == -1 this means
+ // the result might be a DST or a non-DST answer for wall times that can
+ // exist in two OffsetIntervals.
+ int totalOffsetSeconds = offsetInterval.getTotalOffsetSeconds();
+ int returnValue = checkedSubtract(wallTimeSeconds,
+ totalOffsetSeconds);
+
+ copyFieldsFromCalendar();
+ this.isDst = offsetInterval.getIsDst();
+ this.gmtOffsetSeconds = totalOffsetSeconds;
+ return returnValue;
+ }
+ }
+ } else {
+ // To retain similar behavior to the old native implementation: if the caller is
+ // asserting the same isDst value as the OffsetInterval we are looking at we do
+ // not try to find an adjustment from another OffsetInterval of the same isDst
+ // type. If you remove this you get different results in situations like a
+ // DST -> DST transition or STD -> STD transition that results in an interval of
+ // "skipped" wall time. For example: if 01:30 (DST) is invalid and between two
+ // DST intervals, and the caller has passed isDst == 1, this results in a -1
+ // being returned.
+ if (isDst != offsetInterval.getIsDst()) {
+ final int isDstToFind = isDst;
+ Integer returnValue = tryOffsetAdjustments(zoneInfo, wallTimeSeconds,
+ offsetInterval, currentTransitionIndex, isDstToFind);
+ if (returnValue != null) {
+ return returnValue;
+ }
+ }
+ }
+
+ // See if we can avoid another loop in the current direction.
+ if (transitionIndexDelta > 0) {
+ // If we are searching forward and the OffsetInterval we have ends
+ // > MAX_SEARCH_SECONDS after the wall time, we don't need to look any further
+ // forward.
+ boolean endSearch = offsetInterval.getEndWallTimeSeconds() - wallTimeSeconds
+ > MAX_SEARCH_SECONDS;
+ if (endSearch) {
+ clampTop = true;
+ }
+ } else if (transitionIndexDelta < 0) {
+ boolean endSearch = wallTimeSeconds - offsetInterval.getStartWallTimeSeconds()
+ >= MAX_SEARCH_SECONDS;
+ if (endSearch) {
+ // If we are searching backward and the OffsetInterval starts
+ // > MAX_SEARCH_SECONDS before the wall time, we don't need to look any
+ // further backwards.
+ clampBottom = true;
+ }
+ }
+ } while (!(clampTop && clampBottom));
+ return null;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+
+ public void setMonth(int month) {
+ this.month = month;
+ }
+
+ public void setMonthDay(int monthDay) {
+ this.monthDay = monthDay;
+ }
+
+ public void setHour(int hour) {
+ this.hour = hour;
+ }
+
+ public void setMinute(int minute) {
+ this.minute = minute;
+ }
+
+ public void setSecond(int second) {
+ this.second = second;
+ }
+
+ public void setWeekDay(int weekDay) {
+ this.weekDay = weekDay;
+ }
+
+ public void setYearDay(int yearDay) {
+ this.yearDay = yearDay;
+ }
+
+ public void setIsDst(int isDst) {
+ this.isDst = isDst;
+ }
+
+ public void setGmtOffset(int gmtoff) {
+ this.gmtOffsetSeconds = gmtoff;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ public int getMonthDay() {
+ return monthDay;
+ }
+
+ public int getHour() {
+ return hour;
+ }
+
+ public int getMinute() {
+ return minute;
+ }
+
+ public int getSecond() {
+ return second;
+ }
+
+ public int getWeekDay() {
+ return weekDay;
+ }
+
+ public int getYearDay() {
+ return yearDay;
+ }
+
+ public int getGmtOffset() {
+ return gmtOffsetSeconds;
+ }
+
+ public int getIsDst() {
+ return isDst;
+ }
+
+ private void copyFieldsToCalendar() {
+ calendar.set(Calendar.YEAR, year);
+ calendar.set(Calendar.MONTH, month);
+ calendar.set(Calendar.DAY_OF_MONTH, monthDay);
+ calendar.set(Calendar.HOUR_OF_DAY, hour);
+ calendar.set(Calendar.MINUTE, minute);
+ calendar.set(Calendar.SECOND, second);
+ }
+
+ private void copyFieldsFromCalendar() {
+ year = calendar.get(Calendar.YEAR);
+ month = calendar.get(Calendar.MONTH);
+ monthDay = calendar.get(Calendar.DAY_OF_MONTH);
+ hour = calendar.get(Calendar.HOUR_OF_DAY);
+ minute = calendar.get(Calendar.MINUTE);
+ second = calendar.get(Calendar.SECOND);
+
+ // Calendar uses Sunday == 1. Android Time uses Sunday = 0.
+ weekDay = calendar.get(Calendar.DAY_OF_WEEK) - 1;
+ // Calendar enumerates from 1, Android Time enumerates from 0.
+ yearDay = calendar.get(Calendar.DAY_OF_YEAR) - 1;
+ }
+
+ /**
+ * Find the transition in the {@code timezone} in effect at {@code timeSeconds}.
+ *
+ * <p>Returns an index in the range -1..timeZone.mTransitions.length - 1. -1 is used to
+ * indicate the time is before the first transition. Other values are an index into
+ * timeZone.mTransitions.
+ */
+ private static int findTransitionIndex(ZoneInfo timeZone, int timeSeconds) {
+ int matchingRawTransition = Arrays.binarySearch(timeZone.mTransitions, timeSeconds);
+ if (matchingRawTransition < 0) {
+ matchingRawTransition = ~matchingRawTransition - 1;
+ }
+ return matchingRawTransition;
+ }
+ }
+
+ /**
+ * A wall-time representation of a timezone offset interval.
+ *
+ * <p>Wall-time means "as it would appear locally in the timezone in which it applies".
+ * For example in 2007:
+ * PST was a -8:00 offset that ran until Mar 11, 2:00 AM.
+ * PDT was a -7:00 offset and ran from Mar 11, 3:00 AM to Nov 4, 2:00 AM.
+ * PST was a -8:00 offset and ran from Nov 4, 1:00 AM.
+ * Crucially this means that there was a "gap" after PST when PDT started, and an overlap when
+ * PDT ended and PST began.
+ *
+ * <p>For convenience all wall-time values are represented as the number of seconds since the
+ * beginning of the Unix epoch <em>in UTC</em>. To convert from a wall-time to the actual time
+ * in the offset it is necessary to <em>subtract</em> the {@code totalOffsetSeconds}.
+ * For example: If the offset in PST is -07:00 hours, then:
+ * timeInPstSeconds = wallTimeUtcSeconds - offsetSeconds
+ * i.e. 13:00 UTC - (-07:00) = 20:00 UTC = 13:00 PST
+ */
+ static class OffsetInterval {
+
+ private final int startWallTimeSeconds;
+ private final int endWallTimeSeconds;
+ private final int isDst;
+ private final int totalOffsetSeconds;
+
+ /**
+ * Creates an {@link OffsetInterval}.
+ *
+ * <p>If {@code transitionIndex} is -1, the transition is synthesized to be a non-DST offset
+ * that runs from the beginning of time until the first transition in {@code timeZone} and
+ * has an offset of {@code timezone.mRawOffset}. If {@code transitionIndex} is the last
+ * transition that transition is considered to run until the end of representable time.
+ * Otherwise, the information is extracted from {@code timeZone.mTransitions},
+ * {@code timeZone.mOffsets} an {@code timeZone.mIsDsts}.
+ */
+ public static OffsetInterval create(ZoneInfo timeZone, int transitionIndex)
+ throws CheckedArithmeticException {
+
+ if (transitionIndex < -1 || transitionIndex >= timeZone.mTransitions.length) {
+ return null;
+ }
+
+ int rawOffsetSeconds = timeZone.mRawOffset / 1000;
+ if (transitionIndex == -1) {
+ int endWallTimeSeconds = checkedAdd(timeZone.mTransitions[0], rawOffsetSeconds);
+ return new OffsetInterval(Integer.MIN_VALUE, endWallTimeSeconds, 0 /* isDst */,
+ rawOffsetSeconds);
+ }
+
+ byte type = timeZone.mTypes[transitionIndex];
+ int totalOffsetSeconds = timeZone.mOffsets[type] + rawOffsetSeconds;
+ int endWallTimeSeconds;
+ if (transitionIndex == timeZone.mTransitions.length - 1) {
+ // If this is the last transition, make up the end time.
+ endWallTimeSeconds = Integer.MAX_VALUE;
+ } else {
+ endWallTimeSeconds = checkedAdd(timeZone.mTransitions[transitionIndex + 1],
+ totalOffsetSeconds);
+ }
+ int isDst = timeZone.mIsDsts[type];
+ int startWallTimeSeconds =
+ checkedAdd(timeZone.mTransitions[transitionIndex], totalOffsetSeconds);
+ return new OffsetInterval(
+ startWallTimeSeconds, endWallTimeSeconds, isDst, totalOffsetSeconds);
+ }
+
+ private OffsetInterval(int startWallTimeSeconds, int endWallTimeSeconds, int isDst,
+ int totalOffsetSeconds) {
+ this.startWallTimeSeconds = startWallTimeSeconds;
+ this.endWallTimeSeconds = endWallTimeSeconds;
+ this.isDst = isDst;
+ this.totalOffsetSeconds = totalOffsetSeconds;
+ }
+
+ public boolean containsWallTime(long wallTimeSeconds) {
+ return wallTimeSeconds >= startWallTimeSeconds && wallTimeSeconds < endWallTimeSeconds;
+ }
+
+ public int getIsDst() {
+ return isDst;
+ }
+
+ public int getTotalOffsetSeconds() {
+ return totalOffsetSeconds;
+ }
+
+ public long getEndWallTimeSeconds() {
+ return endWallTimeSeconds;
+ }
+
+ public long getStartWallTimeSeconds() {
+ return startWallTimeSeconds;
+ }
+ }
+
+ /**
+ * An exception used to indicate an arithmetic overflow or underflow.
+ */
+ private static class CheckedArithmeticException extends Exception {
+ }
+
+ /**
+ * Calculate (a + b).
+ *
+ * @throws CheckedArithmeticException if overflow or underflow occurs
+ */
+ private static int checkedAdd(int a, int b) throws CheckedArithmeticException {
+ // Adapted from Guava IntMath.checkedAdd();
+ long result = (long) a + b;
+ if (result != (int) result) {
+ throw new CheckedArithmeticException();
+ }
+ return (int) result;
+ }
+
+ /**
+ * Calculate (a - b).
+ *
+ * @throws CheckedArithmeticException if overflow or underflow occurs
+ */
+ private static int checkedSubtract(int a, int b) throws CheckedArithmeticException {
+ // Adapted from Guava IntMath.checkedSubtract();
+ long result = (long) a - b;
+ if (result != (int) result) {
+ throw new CheckedArithmeticException();
+ }
+ return (int) result;
+ }
}
diff --git a/luni/src/main/java/libcore/util/ZoneInfoDB.java b/luni/src/main/java/libcore/util/ZoneInfoDB.java
index 7ff377c..07aaf04 100644
--- a/luni/src/main/java/libcore/util/ZoneInfoDB.java
+++ b/luni/src/main/java/libcore/util/ZoneInfoDB.java
@@ -68,6 +68,28 @@
private int[] byteOffsets;
private int[] rawUtcOffsets;
+ /**
+ * ZoneInfo objects are worth caching because they are expensive to create.
+ * See http://b/8270865 for context.
+ */
+ private final static int CACHE_SIZE = 1;
+ private final BasicLruCache<String, ZoneInfo> cache =
+ new BasicLruCache<String, ZoneInfo>(CACHE_SIZE) {
+ @Override
+ protected ZoneInfo create(String id) {
+ // Work out where in the big data file this time zone is.
+ int index = Arrays.binarySearch(ids, id);
+ if (index < 0) {
+ return null;
+ }
+
+ BufferIterator it = mappedFile.bigEndianIterator();
+ it.skip(byteOffsets[index]);
+
+ return ZoneInfo.makeTimeZone(id, it);
+ }
+ };
+
public TzData(String... paths) {
for (String path : paths) {
if (loadData(path)) {
@@ -206,17 +228,10 @@
return zoneTab;
}
- public TimeZone makeTimeZone(String id) throws IOException {
- // Work out where in the big data file this time zone is.
- int index = Arrays.binarySearch(ids, id);
- if (index < 0) {
- return null;
- }
-
- BufferIterator it = mappedFile.bigEndianIterator();
- it.skip(byteOffsets[index]);
-
- return ZoneInfo.makeTimeZone(id, it);
+ public ZoneInfo makeTimeZone(String id) throws IOException {
+ ZoneInfo zoneInfo = cache.get(id);
+ // The object from the cache is cloned because TimeZone / ZoneInfo are mutable.
+ return zoneInfo == null ? null : (ZoneInfo) zoneInfo.clone();
}
}
diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
index b9056353..d11c8dd 100644
--- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
+++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java
@@ -54,27 +54,18 @@
new int[] {1, 2, 840, 113549, 1, 9, 4};
/**
- * @see #verifySignature(InputStream, InputStream, boolean)
- */
- public static Certificate[] verifySignature(InputStream signature, InputStream signatureBlock)
- throws IOException, GeneralSecurityException {
- return verifySignature(signature, signatureBlock, false);
- }
-
- /**
* This method handle all the work with PKCS7, ASN1 encoding, signature verifying,
* and certification path building.
* See also PKCS #7: Cryptographic Message Syntax Standard:
* http://www.ietf.org/rfc/rfc2315.txt
* @param signature - the input stream of signature file to be verified
* @param signatureBlock - the input stream of corresponding signature block file
- * @param chainCheck - whether to validate certificate chain signatures
* @return array of certificates used to verify the signature file
* @throws IOException - if some errors occurs during reading from the stream
* @throws GeneralSecurityException - if signature verification process fails
*/
public static Certificate[] verifySignature(InputStream signature, InputStream
- signatureBlock, boolean chainCheck) throws IOException, GeneralSecurityException {
+ signatureBlock) throws IOException, GeneralSecurityException {
BerInputStream bis = new BerInputStream(signatureBlock);
ContentInfo info = (ContentInfo)ContentInfo.ASN1.decode(bis);
@@ -232,11 +223,11 @@
throw new SecurityException("Incorrect signature");
}
- return createChain(certs[issuerSertIndex], certs, chainCheck);
+ return createChain(certs[issuerSertIndex], certs);
}
private static X509Certificate[] createChain(X509Certificate signer,
- X509Certificate[] candidates, boolean chainCheck) {
+ X509Certificate[] candidates) {
Principal issuer = signer.getIssuerDN();
// Signer is self-signed
@@ -248,11 +239,10 @@
chain.add(0, signer);
X509Certificate issuerCert;
- X509Certificate subjectCert = signer;
int count = 1;
while (true) {
- issuerCert = findCert(issuer, candidates, subjectCert, chainCheck);
- if( issuerCert == null) {
+ issuerCert = findCert(issuer, candidates);
+ if (issuerCert == null) {
break;
}
chain.add(issuerCert);
@@ -261,22 +251,13 @@
if (issuerCert.getSubjectDN().equals(issuer)) {
break;
}
- subjectCert = issuerCert;
}
return chain.toArray(new X509Certificate[count]);
}
- private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates,
- X509Certificate subjectCert, boolean chainCheck) {
+ private static X509Certificate findCert(Principal issuer, X509Certificate[] candidates) {
for (int i = 0; i < candidates.length; i++) {
if (issuer.equals(candidates[i].getSubjectDN())) {
- if (chainCheck) {
- try {
- subjectCert.verify(candidates[i].getPublicKey());
- } catch (Exception e) {
- continue;
- }
- }
return candidates[i];
}
}
diff --git a/luni/src/main/native/Portability.h b/luni/src/main/native/Portability.h
index fb60ed4..1520311 100644
--- a/luni/src/main/native/Portability.h
+++ b/luni/src/main/native/Portability.h
@@ -65,7 +65,7 @@
#include <sys/param.h>
#include <sys/mount.h>
-#else
+#else // defined(__APPLE__)
// Bionic or glibc.
@@ -73,6 +73,15 @@
#include <sys/sendfile.h>
#include <sys/statvfs.h>
-#endif
+#endif // defined(__APPLE__)
+
+#if !defined(__BIONIC__)
+#include <netdb.h>
+#include "../../bionic/libc/dns/include/resolv_netid.h"
+inline int android_getaddrinfofornet(const char *hostname, const char *servname,
+ const struct addrinfo *hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo **res) {
+ return getaddrinfo(hostname, servname, hints, res);
+}
+#endif // !defined(__BIONIC__)
#endif // PORTABILITY_H_included
diff --git a/luni/src/main/native/android_system_OsConstants.cpp b/luni/src/main/native/android_system_OsConstants.cpp
index 87ebc21..92212b9 100644
--- a/luni/src/main/native/android_system_OsConstants.cpp
+++ b/luni/src/main/native/android_system_OsConstants.cpp
@@ -382,6 +382,12 @@
initConstant(env, c, "POLLRDNORM", POLLRDNORM);
initConstant(env, c, "POLLWRBAND", POLLWRBAND);
initConstant(env, c, "POLLWRNORM", POLLWRNORM);
+#if defined(PR_GET_DUMPABLE)
+ initConstant(env, c, "PR_GET_DUMPABLE", PR_GET_DUMPABLE);
+#endif
+#if defined(PR_SET_DUMPABLE)
+ initConstant(env, c, "PR_SET_DUMPABLE", PR_SET_DUMPABLE);
+#endif
#if defined(PR_SET_NO_NEW_PRIVS)
initConstant(env, c, "PR_SET_NO_NEW_PRIVS", PR_SET_NO_NEW_PRIVS);
#endif
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 163d19c..df26b39 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -116,56 +116,6 @@
return env->NewStringUTF(icuLocale.locale().getScript());
}
-static jstring ICU_localeForLanguageTag(JNIEnv* env, jclass, jstring languageTag, jboolean strict) {
- ScopedUtfChars languageTagChars(env, languageTag);
- if (languageTagChars.c_str() == NULL) {
- return NULL;
- }
-
- // Naively assume that in the average case, the size of
- // the normalized language tag will be very nearly the same as the
- // size of the input. This is generally true for language
- // tags that are "simple" language-region-variant combinations
- // that don't contain any grandfathered tags.
- const size_t initialBufferSize = languageTagChars.size() + 32;
- std::vector<char> buffer(initialBufferSize);
- int32_t parsedLength = 0;
-
- UErrorCode status = U_ZERO_ERROR;
- size_t outputLength = uloc_forLanguageTag(languageTagChars.c_str(), &buffer[0],
- buffer.size(), &parsedLength, &status);
- // Note that we always allocate 1 char more than ICU asks us for,
- // so that we can cleanly assert that it didn't overflow after the
- // second call to uloc_forLanguageTag.
- if (status == U_STRING_NOT_TERMINATED_WARNING) {
- const size_t unterminated_size = buffer.size();
- buffer.resize(unterminated_size + 1);
- buffer[unterminated_size] = '\0';
- } else if (status == U_BUFFER_OVERFLOW_ERROR) {
- buffer.resize(outputLength + 1);
- status = U_ZERO_ERROR;
- outputLength = uloc_forLanguageTag(languageTagChars.c_str(), &buffer[0], buffer.size(),
- &parsedLength, &status);
- }
-
- if (U_FAILURE(status) || outputLength >= buffer.size()) {
- return NULL;
- }
-
- // By default, ICU will ignore all subtags starting at the first unparseable
- // or invalid subtag. Our "strict" mode is specified to throw an error if
- // that happens.
- //
- // NOTE: The cast is safe because parsedLength can never be negative thanks
- // to the check above. ICU does not document any negative return values for
- // that field, but check for it anyway.
- if ((strict == JNI_TRUE) && (static_cast<uint32_t>(parsedLength) != languageTagChars.size())) {
- return NULL;
- }
-
- return env->NewStringUTF(&buffer[0]);
-}
-
static jint ICU_getCurrencyFractionDigits(JNIEnv* env, jclass, jstring javaCurrencyCode) {
ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
if (!currencyCode.valid()) {
@@ -563,16 +513,16 @@
return true;
}
-static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocaleName, jobject localeData) {
- ScopedUtfChars localeName(env, javaLocaleName);
- if (localeName.c_str() == NULL) {
+static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLanguageTag, jobject localeData) {
+ ScopedUtfChars languageTag(env, javaLanguageTag);
+ if (languageTag.c_str() == NULL) {
return JNI_FALSE;
}
- if (localeName.size() >= ULOC_FULLNAME_CAPACITY) {
+ if (languageTag.size() >= ULOC_FULLNAME_CAPACITY) {
return JNI_FALSE; // ICU has a fixed-length limit.
}
- ScopedIcuLocale icuLocale(env, javaLocaleName);
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
if (!icuLocale.valid()) {
return JNI_FALSE;
}
@@ -580,27 +530,27 @@
// Get the DateTimePatterns.
UErrorCode status = U_ZERO_ERROR;
bool foundDateTimePatterns = false;
- for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+ for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
if (getDateTimePatterns(env, localeData, it.Get())) {
foundDateTimePatterns = true;
break;
}
}
if (!foundDateTimePatterns) {
- ALOGE("Couldn't find ICU DateTimePatterns for %s", localeName.c_str());
+ ALOGE("Couldn't find ICU DateTimePatterns for %s", languageTag.c_str());
return JNI_FALSE;
}
// Get the "Yesterday", "Today", and "Tomorrow" strings.
bool foundYesterdayTodayAndTomorrow = false;
- for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+ for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
foundYesterdayTodayAndTomorrow = true;
break;
}
}
if (!foundYesterdayTodayAndTomorrow) {
- ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", localeName.c_str());
+ ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", languageTag.c_str());
return JNI_FALSE;
}
@@ -671,14 +621,14 @@
setNumberPatterns(env, localeData, icuLocale.locale());
setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
- jstring countryCode = env->NewStringUTF(Locale::createFromName(localeName.c_str()).getCountry());
+ jstring countryCode = env->NewStringUTF(icuLocale.locale().getCountry());
jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
env->DeleteLocalRef(countryCode);
countryCode = NULL;
jstring currencySymbol = NULL;
if (internationalCurrencySymbol != NULL) {
- currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLocaleName, internationalCurrencySymbol);
+ currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLanguageTag, internationalCurrencySymbol);
} else {
internationalCurrencySymbol = env->NewStringUTF("XXX");
}
@@ -820,7 +770,6 @@
NATIVE_METHOD(ICU, getIcuVersion, "()Ljava/lang/String;"),
NATIVE_METHOD(ICU, getScript, "(Ljava/lang/String;)Ljava/lang/String;"),
NATIVE_METHOD(ICU, getUnicodeVersion, "()Ljava/lang/String;"),
- NATIVE_METHOD(ICU, localeForLanguageTag, "(Ljava/lang/String;Z)Ljava/lang/String;"),
NATIVE_METHOD(ICU, initLocaleDataNative, "(Ljava/lang/String;Llibcore/icu/LocaleData;)Z"),
NATIVE_METHOD(ICU, setDefaultLocale, "(Ljava/lang/String;)V"),
NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 51dd8a1..e8e8efb 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -25,6 +25,7 @@
#include "NetworkUtilities.h"
#include "Portability.h"
#include "readlink.h"
+#include "../../bionic/libc/dns/include/resolv_netid.h" // For android_getaddrinfofornet.
#include "ScopedBytes.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
@@ -661,7 +662,8 @@
return env->NewStringUTF(gai_strerror(error));
}
-static jobjectArray Posix_getaddrinfo(JNIEnv* env, jobject, jstring javaNode, jobject javaHints) {
+static jobjectArray Posix_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
+ jobject javaHints, jint netId) {
ScopedUtfChars node(env, javaNode);
if (node.c_str() == NULL) {
return NULL;
@@ -681,10 +683,10 @@
addrinfo* addressList = NULL;
errno = 0;
- int rc = getaddrinfo(node.c_str(), NULL, &hints, &addressList);
+ int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
UniquePtr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
if (rc != 0) {
- throwGaiException(env, "getaddrinfo", rc);
+ throwGaiException(env, "android_getaddrinfo", rc);
return NULL;
}
@@ -694,7 +696,7 @@
if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
++addressCount;
} else {
- ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+ ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
}
}
if (addressCount == 0) {
@@ -712,7 +714,7 @@
for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
// Unknown address family. Skip this address.
- ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+ ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
continue;
}
@@ -1537,6 +1539,7 @@
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)Ljava/io/FileDescriptor;"),
NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
+ NATIVE_METHOD(Posix, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
NATIVE_METHOD(Posix, chown, "(Ljava/lang/String;II)V"),
@@ -1558,7 +1561,6 @@
NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"),
NATIVE_METHOD(Posix, gai_strerror, "(I)Ljava/lang/String;"),
- NATIVE_METHOD(Posix, getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;)[Ljava/net/InetAddress;"),
NATIVE_METHOD(Posix, getegid, "()I"),
NATIVE_METHOD(Posix, geteuid, "()I"),
NATIVE_METHOD(Posix, getgid, "()I"),
diff --git a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
index 6d033d3..1475a63 100644
--- a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
+++ b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
@@ -109,6 +109,24 @@
"3xQAyMuOHm72exJljYFqIsiNvGE0KufCqCuH1PD97IXMrLlwGmKKg5jP349lySBpJjm6RDqCTT+6" +
"dUl2jkVbeNmco99Y7AOdtLsOdXBMCo5x8lK8zwQWFrzEms0joHXCpWfGWA==";
+ public static final String ANSSI = "" +
+ "MIIDbDCCAlSgAwIBAgIDAx2nMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNVBAYTAkZSMQ4wDAYDVQQK" +
+ "EwVER1RQRTEsMCoGA1UEAxMjQUMgREdUUEUgU2lnbmF0dXJlIEF1dGhlbnRpZmljYXRpb24wHhcN" +
+ "MTMwNzE4MTAwNTI4WhcNMTQwNzE4MTAwNTI4WjA+MQswCQYDVQQGEwJGUjETMBEGA1UECgwKREcg" +
+ "VHLDqXNvcjEaMBgGA1UEAwwRQUMgREcgVHLDqXNvciBTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IB" +
+ "DwAwggEKAoIBAQDI0WFSUyY+MmtFkqFjTefoFyDgh9b1C/2YvSIvT8oCH62JWT5rpeTCZwaXbqWc" +
+ "jaNfzggqaFsokqfhBif43HNHNtNJmvKE32VcuLB0SpsLR/1VeTd9F99C1JeHVa+nelumOHEfouX8" +
+ "rRFrxNXNIYTVeiENT8Y2YqRb/XAril9g7i674uFzLiNR/t/N/F8Exujv9U8m8rmgud/+tG9WDRaD" +
+ "Jwoj3ZFCOnL5qLnSUEcS6TzWpozLmC2JVO5GZKGGd7qC9FjdBkVilkbVIEGSrYvz2Uz2v5IGqMBI" +
+ "QaFL/kSYWxGTaedTOk2drFEApp9AEPTfv1NwCWBfegsGQrHUROM3AgMBAAGjZjBkMBIGA1UdEwEB" +
+ "/wQIMAYBAf8CAQQwHQYDVR0OBBYEFAAMW8lJqJW0DtAv5p3Mjogxvh9lMB8GA1UdIwQYMBaAFOnb" +
+ "kI/9W5nkFTvwYlyn5A1Y6IeZMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAtDfG" +
+ "HkHOLW2d9fiMtwtkEwDauISJLJyCjoRmawzmQbIZXq7HaLliVfE0sdfKUm0iQ0im1/CpnJLPoTeK" +
+ "yBHvNu1ubLc2m+9dabAYhF3pVdKC+gNaAzBXZ9Gt0p1CLk1lf8Hg+R10HN2IPCv7V/crz2Ga+c23" +
+ "4P3pfwYW8+Nd7alGCuvqot6UYXOlheF7zWUkHn6z6tvY+9oMDHKSUAthhA/FB50JgJU89zyTv1eg" +
+ "Y3ldKwvYBW3W3yNZdTHbPyNsPJdhqA55mDNsteE5YTp1PyySDb1MSVrbxDEruoH6ZE99Hob4Ih8A" +
+ "mn7MHZatGClECgjXWFZ2Gxa7OUCaQpcH8g==";
+
public CertBlacklistTest() throws IOException {
tmpFile = File.createTempFile("test", "");
DEFAULT_PUBKEYS = getDefaultPubkeys();
@@ -415,6 +433,20 @@
assertEquals(bl.isPublicKeyBlackListed(pk), true);
}
+ public void testANSSISerialBlacklist() throws Exception {
+ CertBlacklist bl = new CertBlacklist();
+ assertEquals(bl.isSerialNumberBlackListed(createSerialNumber(ANSSI)), true);
+ }
+
+ public void testANSSIIntermediatePubkeyBlacklist() throws Exception {
+ // build the public key
+ PublicKey pk = createPublicKey(ANSSI);
+ // set our blacklist path
+ CertBlacklist bl = new CertBlacklist();
+ // check to make sure it isn't blacklisted
+ assertEquals(bl.isPublicKeyBlackListed(pk), true);
+ }
+
private static void printHash(String cert) throws Exception {
System.out.println("CERTIFICATE PUBLIC KEY HASH: " + getHash(createPublicKey(cert)));
}
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index 3fa1f46..525d372 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -198,12 +198,6 @@
Collator.getInstance(sr_Latn_BA);
Collator.getInstance(sr_Latn_ME);
- // TODO: This needs to be fixed. We shouldn't output attribute key
- // expansions in the language tag or the toString output. The tests
- // will fail with something like:
- //
- // expected:<de-u-co[-phonebk-kf-upper-kn]> but was:
- // <de-u-co[lcasefirst-upper-collation-phonebook-colnumeric-yes]>
Locale l = Locale.forLanguageTag("de-u-co-phonebk-kf-upper-kn");
assertEquals("de__#u-co-phonebk-kf-upper-kn", l.toString());
assertEquals("de-u-co-phonebk-kf-upper-kn", l.toLanguageTag());
diff --git a/luni/src/test/java/libcore/java/lang/DoubleTest.java b/luni/src/test/java/libcore/java/lang/DoubleTest.java
index 687d3e3..85281ba 100644
--- a/luni/src/test/java/libcore/java/lang/DoubleTest.java
+++ b/luni/src/test/java/libcore/java/lang/DoubleTest.java
@@ -127,4 +127,19 @@
assertEquals(2.2250738585072014E-308, Double.parseDouble("2.22507385850720129978001e-308"));
assertEquals(-2.2250738585072014E-308, Double.parseDouble("-2.2250738585072012e-308"));
}
+
+ // https://code.google.com/p/android/issues/detail?id=71216
+ public void testParse_bug71216() {
+ try {
+ Double.parseDouble("73706943-9580-4406-a02f-0304e4324844");
+ fail();
+ } catch (NumberFormatException expected) {
+ }
+
+ try {
+ Double.parseDouble("bade999999999999999999999999999999");
+ fail();
+ } catch (NumberFormatException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/BufferTest.java b/luni/src/test/java/libcore/java/nio/BufferTest.java
index 613c6fa..c936cdf 100644
--- a/luni/src/test/java/libcore/java/nio/BufferTest.java
+++ b/luni/src/test/java/libcore/java/nio/BufferTest.java
@@ -20,6 +20,8 @@
import java.io.File;
import java.io.RandomAccessFile;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.nio.Buffer;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
@@ -600,17 +602,31 @@
assertTrue(b.isDirect());
// Check the buffer has an array of the right size.
assertTrue(b.hasArray());
- assertEquals(0, b.arrayOffset());
byte[] array = b.array();
- assertEquals(10, array.length);
+ assertTrue(array.length >= b.capacity());
+ assertEquals(10, b.capacity());
// Check that writes to the array show up in the buffer.
assertEquals(0, b.get(0));
- array[0] = 1;
+ array[b.arrayOffset()] = 1;
assertEquals(1, b.get(0));
// Check that writes to the buffer show up in the array.
- assertEquals(1, array[0]);
+ assertEquals(1, array[b.arrayOffset()]);
b.put(0, (byte) 0);
- assertEquals(0, array[0]);
+ assertEquals(0, array[b.arrayOffset()]);
+ }
+
+ // Test that direct byte buffers are 8 byte aligned.
+ // http://b/16449607
+ public void testDirectByteBufferAlignment() throws Exception {
+ ByteBuffer b = ByteBuffer.allocateDirect(10);
+ Field addressField = Buffer.class.getDeclaredField("effectiveDirectAddress");
+ assertTrue(addressField != null);
+ addressField.setAccessible(true);
+ long address = addressField.getLong(b);
+ // Check that the address field is aligned by 8.
+ // Normally reading this field happens in native code by calling
+ // GetDirectBufferAddress.
+ assertEquals(0, address % 8);
}
public void testSliceOffset() throws Exception {
@@ -618,14 +634,12 @@
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.get();
ByteBuffer slice = buffer.slice();
- assertEquals(0, buffer.arrayOffset());
- assertEquals(1, slice.arrayOffset());
+ assertEquals(buffer.arrayOffset() + 1, slice.arrayOffset());
ByteBuffer directBuffer = ByteBuffer.allocateDirect(10);
directBuffer.get();
ByteBuffer directSlice = directBuffer.slice();
- assertEquals(0, directBuffer.arrayOffset());
- assertEquals(1, directSlice.arrayOffset());
+ assertEquals(directBuffer.arrayOffset() + 1, directSlice.arrayOffset());
}
// http://code.google.com/p/android/issues/detail?id=16184
diff --git a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
index 09a18e2..eb0e3d0 100644
--- a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
@@ -47,6 +47,8 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import junit.framework.TestCase;
@@ -54,63 +56,28 @@
public class KeyPairGeneratorTest extends TestCase {
public void test_providerCount() {
- Provider[] providers = Security.getProviders();
- // We expect there to be at least one provider.
- assertTrue(providers.length > 0);
- // If this fails remember to add _provider methods below. This test is sharded because it
- // takes a long time to execute.
- assertTrue(providers.length < 10);
+ // If this fails remember to add/remove _provider methods below. This test is sharded
+ // because it takes so long.
+ assertEquals(4, Security.getProviders().length);
}
public void test_getInstance_provider0() throws Exception {
- test_getInstance(0);
+ test_getInstance(Security.getProviders()[0]);
}
public void test_getInstance_provider1() throws Exception {
- test_getInstance(1);
+ test_getInstance(Security.getProviders()[1]);
}
public void test_getInstance_provider2() throws Exception {
- test_getInstance(2);
+ test_getInstance(Security.getProviders()[2]);
}
public void test_getInstance_provider3() throws Exception {
- test_getInstance(3);
+ test_getInstance(Security.getProviders()[3]);
}
- public void test_getInstance_provider4() throws Exception {
- test_getInstance(4);
- }
-
- public void test_getInstance_provider5() throws Exception {
- test_getInstance(5);
- }
-
- public void test_getInstance_provider6() throws Exception {
- test_getInstance(6);
- }
-
- public void test_getInstance_provider7() throws Exception {
- test_getInstance(7);
- }
-
- public void test_getInstance_provider8() throws Exception {
- test_getInstance(8);
- }
-
- public void test_getInstance_provider9() throws Exception {
- test_getInstance(9);
- }
-
- private void test_getInstance(int providerIndex) throws Exception {
- Provider[] providers = Security.getProviders();
- if (providerIndex >= providers.length) {
- // Providers can be added by vendors and other tests. We do not
- // specify a fixed number and silenty pass if the provider at the
- // specified index does not exist.
- return;
- }
- Provider provider = providers[providerIndex];
+ private void test_getInstance(Provider provider) throws Exception {
Set<Provider.Service> services = provider.getServices();
for (Provider.Service service : services) {
String type = service.getType();
@@ -126,12 +93,8 @@
AlgorithmParameterSpec params = null;
- // TODO: detect if we're running in vogar and run the full test
if ("DH".equals(algorithm)) {
- // Disabled because this takes too long on devices.
- // TODO: Re-enable DH test. http://b/5513723.
- // params = getDHParams();
- continue;
+ params = getDHParams();
}
try {
@@ -218,6 +181,14 @@
test_KeyPair(kpg, kpg.generateKeyPair());
String algorithm = kpg.getAlgorithm();
+
+ // TODO: detect if we're running in vogar and run the full test
+ if ("DH".equals(algorithm)) {
+ // Disabled because this takes too long on devices.
+ // TODO: Re-enable DH test. http://b/5513723.
+ return;
+ }
+
List<Integer> keySizes = getKeySizes(algorithm);
for (int keySize : keySizes) {
kpg.initialize(keySize);
@@ -263,6 +234,17 @@
expectedAlgorithm = "DH";
}
assertEquals(expectedAlgorithm, k.getAlgorithm().toUpperCase());
+ if (expectedAlgorithm.equals("DH")) {
+ if (k instanceof DHPublicKey) {
+ DHPublicKey dhPub = (DHPublicKey) k;
+ assertEquals(dhPub.getParams().getP(), getDHParams().getP());
+ } else if (k instanceof DHPrivateKey) {
+ DHPrivateKey dhPriv = (DHPrivateKey) k;
+ assertEquals(dhPriv.getParams().getP(), getDHParams().getP());
+ } else {
+ fail("not a public or private key!?");
+ }
+ }
assertNotNull(k.getEncoded());
assertNotNull(k.getFormat());
@@ -344,7 +326,7 @@
*
* openssl gendh 512 | openssl dhparams -C
*/
- private static AlgorithmParameterSpec getDHParams() {
+ private static DHParameterSpec getDHParams() {
BigInteger p = new BigInteger("E7AB1768BD75CD24700960FFA32D3F1557344E587101237532CC641646ED7A7C104743377F6D46251698B665CE2A6CBAB6714C2569A7D2CA22C0CF03FA40AC93", 16);
BigInteger g = new BigInteger("02", 16);
return new DHParameterSpec(p, g, 512);
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index 94bf363..23a4f28 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -541,13 +541,6 @@
assertEquals("eng", l.getLanguage());
assertEquals("419", l.getCountry());
- // IND is an invalid region code so ICU helpfully tries to parse it as
- // a 3 letter language code, even if it isn't a valid ISO-639-3 code
- // either.
- l = fromLanguageTag("en-USB", useBuilder);
- assertEquals("usb", l.getLanguage());
- assertEquals("", l.getCountry());
-
// Script tags shouldn't be mis-recognized as regions.
l = fromLanguageTag("en-Latn", useBuilder);
assertEquals("en", l.getLanguage());
@@ -612,16 +605,24 @@
} catch (IllformedLocaleException expected) {
}
- // Ill-formed extension with long subtag.
+ // Two extension keys in a row (i.e, another case of an ill-formed
+ // empty exception).
try {
- fromLanguageTag("en-f-fooobaaaz", true);
+ fromLanguageTag("en-f-g-fo-baar", true);
fail();
} catch (IllformedLocaleException expected) {
}
- // Ill-formed extension key.
+ // Dangling empty key after a well formed extension.
try {
- fromLanguageTag("en-9-baa", true);
+ fromLanguageTag("en-f-fo-baar-g", true);
+ fail();
+ } catch (IllformedLocaleException expected) {
+ }
+
+ // Ill-formed extension with long subtag.
+ try {
+ fromLanguageTag("en-f-fooobaaaz", true);
fail();
} catch (IllformedLocaleException expected) {
}
@@ -700,7 +701,7 @@
assertEquals("en", l.getLanguage());
assertEquals("Latn", l.getScript());
assertEquals("GB", l.getCountry());
- assertEquals("FOOOO_POSIX", l.getVariant());
+ assertEquals("FOOOO", l.getVariant());
assertEquals("fo-bar-baaz", l.getExtension('g'));
// Multiple extensions
@@ -708,7 +709,7 @@
assertEquals("en", l.getLanguage());
assertEquals("Latn", l.getScript());
assertEquals("US", l.getCountry());
- assertEquals("FOOOO_POSIX", l.getVariant());
+ assertEquals("FOOOO", l.getVariant());
assertEquals("fo-bar", l.getExtension('g'));
assertEquals("go-gaz", l.getExtension('h'));
@@ -738,6 +739,13 @@
assertEquals("", l.getScript());
assertEquals("", l.getCountry());
assertEquals("fo", l.getExtension('f'));
+
+ l = fromLanguageTag("en-f-fo-x-a-b-c-d-e-fo", useBuilder);
+ assertEquals("en", l.getLanguage());
+ assertEquals("", l.getScript());
+ assertEquals("", l.getCountry());
+ assertEquals("fo", l.getExtension('f'));
+ assertEquals("a-b-c-d-e-fo", l.getExtension('x'));
}
public void test_forLanguageTag() {
@@ -782,7 +790,7 @@
public void test_setLanguageTag_malformedTags() {
Locale l = fromLanguageTag("a", false);
- assertEquals("", l.getLanguage());
+ assertEquals("und", l.getLanguage());
assertEquals("", l.getCountry());
assertEquals("", l.getVariant());
assertEquals("", l.getScript());
@@ -1113,4 +1121,22 @@
.build();
assertEquals("en-US-POSIX", posix.toLanguageTag());
}
+
+ public void test_forLanguageTag_grandFatheredLocale() {
+ // Regular grandfathered locale.
+ Locale gaulish = Locale.forLanguageTag("cel-gaulish");
+ assertEquals("xtg", gaulish.getLanguage());
+ assertEquals("cel-gaulish", gaulish.getExtension(Locale.PRIVATE_USE_EXTENSION));
+ assertEquals("", gaulish.getCountry());
+ assertEquals("", gaulish.getScript());
+ assertEquals("", gaulish.getVariant());
+
+ // Irregular grandfathered locale.
+ Locale enochian = Locale.forLanguageTag("i-enochian");
+ assertEquals("und", enochian.getLanguage());
+ assertEquals("i-enochian", enochian.getExtension(Locale.PRIVATE_USE_EXTENSION));
+ assertEquals("", enochian.getCountry());
+ assertEquals("", enochian.getScript());
+ assertEquals("", enochian.getVariant());
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java b/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
index fa761d3..87f2f9d 100644
--- a/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/OldAndroidLocaleTest.java
@@ -76,9 +76,16 @@
// This one makes sure we have all necessary locales installed.
public void testICULocales() {
- String[] locales = new String[] {
- // List of locales currently required for Android.
- "en_US", "es_US", "en_GB", "fr_FR", "de_DE", "de_AT", "cs_CZ", "nl_NL" };
+ // List of locales currently required for Android.
+ Locale[] locales = new Locale[] {
+ new Locale("en", "US"),
+ new Locale("es", "US"),
+ new Locale("en", "GB"),
+ new Locale("fr", "FR"),
+ new Locale("de", "DE"),
+ new Locale("de", "AT"),
+ new Locale("cs", "CZ"),
+ new Locale("nl", "NL") };
String[] mondays = new String[] {
"Monday", "lunes", "Monday", "lundi", "Montag", "Montag", "pond\u011bl\u00ed", "maandag" };
@@ -87,14 +94,12 @@
"USD", "USD", "GBP", "EUR", "EUR", "EUR", "CZK", "EUR"};
for (int i = 0; i < locales.length; i++) {
- Locale l = new Locale(locales[i].substring(0, 2), locales[i].substring(3));
+ final Locale l = locales[i];
- // Check language part of locale.
DateFormatSymbols d = new DateFormatSymbols(l);
assertEquals("Monday name for " + locales[i] + " must match",
mondays[i], d.getWeekdays()[2]);
- // Check country part of locale.
Currency c = Currency.getInstance(l);
assertEquals("Currency code for " + locales[i] + " must match",
currencies[i], c.getCurrencyCode());
diff --git a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
index 0b194f5..e5a6cd8 100644
--- a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
@@ -122,6 +122,7 @@
jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
if ("Test.class".equals(zipEntry.getName())) {
assertNotNull(jarFile.getCertificates(zipEntry));
+ assertNotNull(jarFile.getCertificateChains(zipEntry));
}
}
}
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index f7a0a72..c89886c 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -1213,11 +1213,19 @@
if (!isOnlyWrappingAlgorithm(algorithm)) {
c.init(Cipher.ENCRYPT_MODE, encryptKey, encryptSpec);
byte[] cipherText = c.doFinal(getActualPlainText(algorithm));
+ byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
+ assertEquals(cipherID,
+ Arrays.toString(cipherText),
+ Arrays.toString(cipherText2));
c.init(Cipher.DECRYPT_MODE, getDecryptKey(algorithm), decryptSpec);
byte[] decryptedPlainText = c.doFinal(cipherText);
assertEquals(cipherID,
Arrays.toString(getExpectedPlainText(algorithm, providerName)),
Arrays.toString(decryptedPlainText));
+ byte[] decryptedPlainText2 = c.doFinal(cipherText);
+ assertEquals(cipherID,
+ Arrays.toString(decryptedPlainText),
+ Arrays.toString(decryptedPlainText2));
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
index 0e13fb0..dccadbd 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
@@ -24,7 +24,12 @@
import java.security.Provider;
import java.security.Security;
import java.security.UnrecoverableKeyException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.Callable;
+import libcore.io.IoUtils;
import libcore.java.security.StandardNames;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
@@ -34,12 +39,15 @@
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.TrustManagerFactorySpi;
+import javax.net.ssl.X509KeyManager;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
@@ -85,6 +93,94 @@
}
}
+ public void test_SSLContext_pskOnlyConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where only a PSKKeyManager is provided and no TrustManagers are
+ // provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(
+ new KeyManager[] {
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy())
+ },
+ new TrustManager[0],
+ null);
+ List<String> expectedCipherSuites =
+ new ArrayList<String>(StandardNames.CIPHER_SUITES_DEFAULT_PSK);
+ expectedCipherSuites.add(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+ }
+
+ public void test_SSLContext_x509AndPskConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where an X509TrustManager and PSKKeyManager are provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(
+ new KeyManager[] {
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy())
+ },
+ null, // Use default trust managers, one of which is an X.509 one.
+ null);
+ List<String> expectedCipherSuites =
+ new ArrayList<String>(StandardNames.CIPHER_SUITES_DEFAULT_PSK);
+ expectedCipherSuites.addAll(StandardNames.CIPHER_SUITES_DEFAULT);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+
+ // Test the scenario where an X509KeyManager and PSKKeyManager are provided.
+ sslContext = SSLContext.getInstance("TLS");
+ // Just an arbitrary X509KeyManager -- it won't be invoked in this test.
+ X509KeyManager x509KeyManager = new RandomPrivateKeyX509ExtendedKeyManager(null);
+ sslContext.init(
+ new KeyManager[] {
+ x509KeyManager,
+ PSKKeyManagerProxy.getConscryptPSKKeyManager(new PSKKeyManagerProxy())
+ },
+ new TrustManager[0],
+ null);
+ assertEnabledCipherSuites(expectedCipherSuites, sslContext);
+ }
+
+ public void test_SSLContext_emptyConfiguration_defaultProviderOnly() throws Exception {
+ // Test the scenario where neither X.509 nor PSK KeyManagers or TrustManagers are provided.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(
+ new KeyManager[0],
+ new TrustManager[0],
+ null);
+ assertEnabledCipherSuites(
+ Arrays.asList(StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION),
+ sslContext);
+ }
+
+ private static void assertEnabledCipherSuites(
+ List<String> expectedCipherSuites, SSLContext sslContext) throws Exception {
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.createSSLEngine().getEnabledCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites,
+ sslContext.createSSLEngine().getSSLParameters().getCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.getSocketFactory().getDefaultCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslContext.getServerSocketFactory().getDefaultCipherSuites());
+
+ SSLSocket sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket();
+ try {
+ assertContentsInOrder(
+ expectedCipherSuites, sslSocket.getEnabledCipherSuites());
+ assertContentsInOrder(
+ expectedCipherSuites, sslSocket.getSSLParameters().getCipherSuites());
+ } finally {
+ IoUtils.closeQuietly(sslSocket);
+ }
+
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket) sslContext.getServerSocketFactory().createServerSocket();
+ try {
+ assertContentsInOrder(
+ expectedCipherSuites, sslServerSocket.getEnabledCipherSuites());
+ } finally {
+ IoUtils.closeQuietly(sslSocket);
+ }
+ }
+
public void test_SSLContext_getInstance() throws Exception {
try {
SSLContext.getInstance(null);
@@ -463,4 +559,16 @@
assertTrue(testContext.port != 0);
testContext.close();
}
+
+ private static void assertContentsInOrder(List<String> expected, String... actual) {
+ if (expected.size() != actual.length) {
+ fail("Unexpected length. Expected len <" + expected.size()
+ + ">, actual len <" + actual.length + ">, expected <" + expected
+ + ">, actual <" + Arrays.asList(actual) + ">");
+ }
+ if (!expected.equals(Arrays.asList(actual))) {
+ fail("Unexpected element(s). Expected <" + expected
+ + ">, actual <" + Arrays.asList(actual) + ">" );
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
index 86e96ff..acf69c0 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketFactoryTest.java
@@ -16,24 +16,199 @@
package libcore.javax.net.ssl;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
+import java.security.KeyManagementException;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Properties;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
import junit.framework.TestCase;
+import libcore.java.security.StandardNames;
public class SSLSocketFactoryTest extends TestCase {
+ private static final String SSL_PROPERTY = "ssl.SocketFactory.provider";
+
public void test_SSLSocketFactory_getDefault() {
SocketFactory sf = SSLSocketFactory.getDefault();
assertNotNull(sf);
assertTrue(SSLSocketFactory.class.isAssignableFrom(sf.getClass()));
}
+ public static class FakeSSLSocketProvider extends Provider {
+ public FakeSSLSocketProvider() {
+ super("FakeSSLSocketProvider", 1.0, "Testing provider");
+ put("SSLContext.Default", FakeSSLContextSpi.class.getName());
+ }
+ }
+
+ public static final class FakeSSLContextSpi extends SSLContextSpi {
+ @Override
+ protected void engineInit(KeyManager[] keyManagers, TrustManager[] trustManagers,
+ SecureRandom secureRandom) throws KeyManagementException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected SSLSocketFactory engineGetSocketFactory() {
+ return new FakeSSLSocketFactory();
+ }
+
+ @Override
+ protected SSLServerSocketFactory engineGetServerSocketFactory() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine(String s, int i) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected SSLEngine engineCreateSSLEngine() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected SSLSessionContext engineGetServerSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected SSLSessionContext engineGetClientSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class FakeSSLSocketFactory extends SSLSocketFactory {
+ public FakeSSLSocketFactory() {
+ }
+
+ @Override
+ public String[] getDefaultCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(Socket s, String host, int port, boolean autoClose) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
+ int localPort) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(InetAddress host, int port) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Socket createSocket(String host, int port) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public void test_SSLSocketFactory_getDefault_cacheInvalidate() throws Exception {
+ String origProvider = resetSslProvider();
+ try {
+ SocketFactory sf1 = SSLSocketFactory.getDefault();
+ assertNotNull(sf1);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf1.getClass()));
+
+ Provider fakeProvider = new FakeSSLSocketProvider();
+ SocketFactory sf4 = null;
+ SSLContext origContext = null;
+ try {
+ origContext = SSLContext.getDefault();
+ Security.insertProviderAt(fakeProvider, 1);
+ SSLContext.setDefault(SSLContext.getInstance("Default", fakeProvider));
+
+ sf4 = SSLSocketFactory.getDefault();
+ assertNotNull(sf4);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf4.getClass()));
+
+ assertFalse(sf1.getClass() + " should not be " + sf4.getClass(),
+ sf1.getClass().equals(sf4.getClass()));
+ } finally {
+ SSLContext.setDefault(origContext);
+ Security.removeProvider(fakeProvider.getName());
+ }
+
+ SocketFactory sf3 = SSLSocketFactory.getDefault();
+ assertNotNull(sf3);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf3.getClass()));
+
+ assertTrue(sf1.getClass() + " should be " + sf3.getClass(),
+ sf1.getClass().equals(sf3.getClass()));
+
+ if (!StandardNames.IS_RI) {
+ Security.setProperty(SSL_PROPERTY, FakeSSLSocketFactory.class.getName());
+ SocketFactory sf2 = SSLSocketFactory.getDefault();
+ assertNotNull(sf2);
+ assertTrue(SSLSocketFactory.class.isAssignableFrom(sf2.getClass()));
+
+ assertFalse(sf2.getClass().getName() + " should not be " + Security.getProperty(SSL_PROPERTY),
+ sf1.getClass().equals(sf2.getClass()));
+ assertTrue(sf2.getClass().equals(sf4.getClass()));
+
+ resetSslProvider();
+ }
+ } finally {
+ Security.setProperty(SSL_PROPERTY, origProvider);
+ }
+ }
+
+ private String resetSslProvider() {
+ String origProvider = Security.getProperty(SSL_PROPERTY);
+
+ try {
+ Field field_secprops = Security.class.getDeclaredField("secprops");
+ field_secprops.setAccessible(true);
+ Properties secprops = (Properties) field_secprops.get(null);
+ secprops.remove(SSL_PROPERTY);
+
+ Class<?> class_services =
+ Class.forName("org.apache.harmony.security.fortress.Services");
+ Method m_setNeedRefresh = class_services.getMethod("setNeedRefresh");
+ m_setNeedRefresh.invoke(null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail("Cannot find a way to clear out the SocketFactory provider");
+ }
+
+ assertNull(Security.getProperty(SSL_PROPERTY));
+ return origProvider;
+ }
+
public void test_SSLSocketFactory_defaultConfiguration() throws Exception {
SSLDefaultConfigurationAsserts.assertSSLSocketFactory(
(SSLSocketFactory) SSLSocketFactory.getDefault());
diff --git a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
index 215821d..9875647 100644
--- a/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
+++ b/luni/src/test/java/libcore/util/ZoneInfoDBTest.java
@@ -77,6 +77,29 @@
}
}
+ // Confirms any caching that exists correctly handles TimeZone mutability.
+ public void testMakeTimeZone_timeZoneMutability() throws Exception {
+ ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ String tzId = "Europe/London";
+ ZoneInfo first = data.makeTimeZone(tzId);
+ ZoneInfo second = data.makeTimeZone(tzId);
+ assertNotSame(first, second);
+
+ assertTrue(first.hasSameRules(second));
+
+ first.setID("Not Europe/London");
+
+ assertFalse(first.getID().equals(second.getID()));
+
+ first.setRawOffset(3600);
+ assertFalse(first.getRawOffset() == second.getRawOffset());
+ }
+
+ public void testMakeTimeZone_notFound() throws Exception {
+ ZoneInfoDB.TzData data = new ZoneInfoDB.TzData(TZDATA_IN_ROOT);
+ assertNull(data.makeTimeZone("THIS_TZ_DOES_NOT_EXIST"));
+ }
+
private static String makeCorruptFile() throws Exception {
return makeTemporaryFile("invalid content".getBytes());
}
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
index 3ea57bf..5cbdab3 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/SealedObjectTest.java
@@ -165,6 +165,34 @@
+ "in cipher.", algorithm, so.getAlgorithm());
}
+ // https://code.google.com/p/android/issues/detail?id=73235
+ public void testGetAlgorithmAfterSerialization() throws Exception {
+ String secret = "secret string";
+ String algorithm = "DES";
+ KeyGenerator kg = KeyGenerator.getInstance(algorithm);
+ Key key = kg.generateKey();
+
+ Cipher cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ SealedObject so = new SealedObject(secret, cipher);
+
+ assertEquals("The algorithm name should be the same as used "
+ + "in cipher.", algorithm, so.getAlgorithm());
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(so);
+ oos.close();
+
+ ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
+ SealedObject readSo = (SealedObject) ois.readObject();
+ ois.close();
+
+ // Bug 73235 would swap the Cipher algorithm and parameters. Parameters is not public but
+ // algorithm is so we check that.
+ assertEquals(so.getAlgorithm(), readSo.getAlgorithm());
+ }
+
/**
* getObject(Key key) method testing. Tests if the object sealed with
* encryption algorithm and specified parameters can be retrieved by
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 719c3b7..a526c2e 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -863,6 +863,15 @@
"SSL_RSA_WITH_RC4_128_SHA",
CIPHER_SUITE_SECURE_RENEGOTIATION);
+ // NOTE: This list needs to be kept in sync with Javadoc of javax.net.ssl.SSLSocket and
+ // javax.net.ssl.SSLEngine.
+ public static final List<String> CIPHER_SUITES_DEFAULT_PSK = Arrays.asList(
+ "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
+ "TLS_PSK_WITH_AES_128_CBC_SHA",
+ "TLS_PSK_WITH_AES_256_CBC_SHA"
+ );
+
private static final Set<String> PERMITTED_DEFAULT_KEY_EXCHANGE_ALGS =
new HashSet<String>(Arrays.asList("RSA",
"DHE_RSA",
diff --git a/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar b/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar
new file mode 100644
index 0000000..7da4b59
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar
Binary files differ
diff --git a/support/src/test/java/tests/support/Support_MapTest.java b/support/src/test/java/tests/support/Support_MapTest.java
new file mode 100644
index 0000000..5dfc69d
--- /dev/null
+++ b/support/src/test/java/tests/support/Support_MapTest.java
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.support;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import junit.framework.TestCase;
+
+public class Support_MapTest extends TestCase {
+
+ // must be a map containing the string keys "0"-"99" paired with the Integer
+ // values Integer(0) to Integer(99)
+ private final Map<String, Integer> modifiableMap;
+ private final Map<String, Integer> unmodifiableMap;
+
+ public Support_MapTest(String p1, Map<String, Integer> modifiableMap) {
+ super(p1);
+ this.modifiableMap = modifiableMap;
+ unmodifiableMap = Collections.unmodifiableMap(modifiableMap);
+ }
+
+ @Override
+ public void runTest() {
+ testContents(modifiableMap);
+ testContents(unmodifiableMap);
+
+ // values()
+ new Support_UnmodifiableCollectionTest("values() from map test", modifiableMap.values())
+ .runTest();
+ new Support_UnmodifiableCollectionTest("values() from unmodifiable map test",
+ unmodifiableMap.values()).runTest();
+
+ // entrySet()
+ testEntrySet(modifiableMap.entrySet(), unmodifiableMap.entrySet());
+
+ // keySet()
+ testKeySet(modifiableMap.keySet(), unmodifiableMap.keySet());
+ }
+
+ private void testContents(Map<String, Integer> map) {
+ // size
+ assertTrue("Size should return 100, returned: " + map.size(), map.size() == 100);
+
+ // containsKey
+ assertTrue("Should contain the key \"0\"", map.containsKey("0"));
+ assertTrue("Should contain the key \"50\"", map.containsKey("50"));
+ assertTrue("Should not contain the key \"100\"", !map.containsKey("100"));
+
+ // containsValue
+ assertTrue("Should contain the value 0", map.containsValue(0));
+ assertTrue("Should contain the value 50", map.containsValue(50));
+ assertTrue("Should not contain value 100", !map.containsValue(100));
+
+ // get
+ assertTrue("getting \"0\" didn't return 0", map.get("0") == 0);
+ assertTrue("getting \"50\" didn't return 50", map.get("50") == 50);
+ assertNull("getting \"100\" didn't return null", map.get("100"));
+
+ // isEmpty
+ assertTrue("should have returned false to isEmpty", !map.isEmpty());
+ }
+
+ private static void testEntrySet(
+ Set<Map.Entry<String, Integer>> referenceEntrySet,
+ Set<Map.Entry<String, Integer>> entrySet) {
+ // entrySet should be a set of mappings {"0", 0}, {"1",1}... {"99", 99}
+ assertEquals(100, referenceEntrySet.size());
+ assertEquals(100, entrySet.size());
+
+ // The ordering may be undefined for a map implementation but the ordering must be the
+ // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
+ // modifiable and unmodifiable map.
+ crossCheckOrdering(referenceEntrySet, entrySet, Map.Entry.class);
+ }
+
+ private static void testKeySet(Set<String> referenceKeySet, Set<String> keySet) {
+ // keySet should be a set of the strings "0" to "99"
+ testKeySetContents(referenceKeySet);
+ testKeySetContents(keySet);
+
+ // The ordering may be undefined for a map implementation but the ordering must be the
+ // same across iterator(), toArray() and toArray(T[]) for a given map *and* the same for the
+ // modifiable and unmodifiable map.
+ crossCheckOrdering(referenceKeySet, keySet, String.class);
+ }
+
+ private static void testKeySetContents(Set<String> keySet) {
+ // contains
+ assertTrue("should contain \"0\"", keySet.contains("0"));
+ assertTrue("should contain \"50\"", keySet.contains("50"));
+ assertTrue("should not contain \"100\"", !keySet.contains("100"));
+
+ // containsAll
+ HashSet<String> hs = new HashSet<String>();
+ hs.add("0");
+ hs.add("25");
+ hs.add("99");
+ assertTrue("Should contain set of \"0\", \"25\", and \"99\"", keySet.containsAll(hs));
+ hs.add("100");
+ assertTrue("Should not contain set of \"0\", \"25\", \"99\" and \"100\"",
+ !keySet.containsAll(hs));
+
+ // isEmpty
+ assertTrue("Should not be empty", !keySet.isEmpty());
+
+ // size
+ assertEquals("Returned wrong size.", 100, keySet.size());
+ }
+
+ private static <T> void crossCheckOrdering(Set<T> set1, Set<T> set2, Class<?> elementType) {
+ Iterator<T> set1Iterator = set1.iterator();
+ Iterator<T> set2Iterator = set2.iterator();
+
+ T[] zeroLengthArray = createArray(elementType, 0);
+ T[] set1TypedArray1 = set1.toArray(zeroLengthArray);
+ assertEquals(set1.size(), set1TypedArray1.length);
+
+ // Compare set1.iterator(), set2.iterator() and set1.toArray(new T[0])
+ int entryCount = 0;
+ while (set1Iterator.hasNext()) {
+ T set1Entry = set1Iterator.next();
+ T set2Entry = set2Iterator.next();
+
+ // Compare set1 with set2
+ assertEquals(set1Entry, set2Entry);
+
+ // Compare the iterator with the array. The arrays will be checked against each other.
+ assertEquals(set1Entry, set1TypedArray1[entryCount]);
+
+ entryCount++;
+ }
+ assertFalse(set2Iterator.hasNext());
+ assertEquals(set1.size(), entryCount);
+
+ // Compare the various arrays with each other.
+
+ // set1.toArray(new T[size])
+ T[] parameterArray1 = createArray(elementType, set1.size());
+ T[] set1TypedArray2 = set1.toArray(parameterArray1);
+ assertSame(set1TypedArray2, parameterArray1);
+ assertArrayEquals(set1TypedArray1, set1TypedArray2);
+
+ // set1.toArray()
+ Object[] set1UntypedArray = set1.toArray();
+ assertEquals(set1.size(), set1UntypedArray.length);
+ assertArrayEquals(set1TypedArray1, set1UntypedArray);
+
+ // set2.toArray(new T[0])
+ T[] set2TypedArray1 = set2.toArray(zeroLengthArray);
+ assertEquals(set1.size(), set2TypedArray1.length);
+ assertArrayEquals(set1TypedArray1, set2TypedArray1);
+
+ // set2.toArray(new T[size])
+ T[] parameterArray2 = createArray(elementType, set2.size());
+ T[] set2TypedArray2 = set1.toArray(parameterArray2);
+ assertSame(set2TypedArray2, parameterArray2);
+ assertArrayEquals(set1TypedArray1, set1TypedArray2);
+
+ // set2.toArray()
+ Object[] set2UntypedArray = set2.toArray();
+ assertArrayEquals(set1TypedArray1, set2UntypedArray);
+ }
+
+ private static <T> void assertArrayEquals(T[] array1, T[] array2) {
+ assertTrue(Arrays.equals(array1, array2));
+ }
+
+ private static <T> T[] createArray(Class<?> elementType, int size) {
+ return (T[]) Array.newInstance(elementType, size);
+ }
+}
diff --git a/support/src/test/java/tests/support/Support_UnmodifiableMapTest.java b/support/src/test/java/tests/support/Support_UnmodifiableMapTest.java
deleted file mode 100644
index e7a1620..0000000
--- a/support/src/test/java/tests/support/Support_UnmodifiableMapTest.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package tests.support;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import junit.framework.TestCase;
-
-public class Support_UnmodifiableMapTest extends TestCase {
-
- Map<String, Integer> map;
-
- // must be a map containing the string keys "0"-"99" paired with the Integer
- // values Integer(0) to Integer(99)
-
- public Support_UnmodifiableMapTest(String p1) {
- super(p1);
- }
-
- public Support_UnmodifiableMapTest(String p1, Map<String, Integer> m) {
- super(p1);
- map = m;
- }
-
- @Override
- public void runTest() {
- // containsKey
- assertTrue("UnmodifiableMapTest - Should contain the key \"0\"", map
- .containsKey("0"));
- assertTrue("UnmodifiableMapTest - Should contain the key \"50\"", map
- .containsKey("50"));
- assertTrue("UnmodifiableMapTest - Should not contain the key \"100\"",
- !map.containsKey("100"));
-
- // containsValue
- assertTrue("UnmodifiableMapTest - Should contain the value 0", map
- .containsValue(new Integer(0)));
- assertTrue("UnmodifiableMapTest - Should contain the value 50", map
- .containsValue(new Integer(50)));
- assertTrue("UnmodifiableMapTest - Should not contain value 100", !map
- .containsValue(new Integer(100)));
-
- // entrySet
- Set<?> entrySet = map.entrySet();
- Iterator<?> entrySetIterator = entrySet.iterator();
- int myCounter = 0;
- while (entrySetIterator.hasNext()) {
- Map.Entry<?, ?> me = (Map.Entry<?, ?>) entrySetIterator.next();
- assertTrue("UnmodifiableMapTest - Incorrect Map.Entry returned",
- map.get(me.getKey()).equals(me.getValue()));
- myCounter++;
- }
- assertEquals("UnmodifiableMapTest - Incorrect number of map entries returned",
- 100, myCounter);
-
- // get
- assertTrue("UnmodifiableMapTest - getting \"0\" didn't return 0",
- map.get("0").intValue() == 0);
- assertTrue("UnmodifiableMapTest - getting \"50\" didn't return 0",
- map.get("0").intValue() == 0);
- assertNull("UnmodifiableMapTest - getting \"100\" didn't return null",
- map.get("100"));
-
- // isEmpty
- assertTrue(
- "UnmodifiableMapTest - should have returned false to isEmpty",
- !map.isEmpty());
-
- // keySet
- Set<?> keySet = map.keySet();
- t_KeySet(keySet);
-
- // size
- assertTrue("Size should return 100, returned: " + map.size(), map
- .size() == 100);
-
- // values
- new Support_UnmodifiableCollectionTest("Unmod--from map test", map
- .values());
-
- }
-
- void t_KeySet(Set<?> keySet) {
- // keySet should be a set of the strings "0" to "99"
-
- // contains
- assertTrue("UnmodifiableMapTest - keySetTest - should contain \"0\"",
- keySet.contains("0"));
- assertTrue("UnmodifiableMapTest - keySetTest - should contain \"50\"",
- keySet.contains("50"));
- assertTrue(
- "UnmodifiableMapTest - keySetTest - should not contain \"100\"",
- !keySet.contains("100"));
-
- // containsAll
- HashSet<String> hs = new HashSet<String>();
- hs.add("0");
- hs.add("25");
- hs.add("99");
- assertTrue(
- "UnmodifiableMapTest - keySetTest - should contain set of \"0\", \"25\", and \"99\"",
- keySet.containsAll(hs));
- hs.add("100");
- assertTrue(
- "UnmodifiableMapTest - keySetTest - should not contain set of \"0\", \"25\", \"99\" and \"100\"",
- !keySet.containsAll(hs));
-
- // isEmpty
- assertTrue("UnmodifiableMapTest - keySetTest - should not be empty",
- !keySet.isEmpty());
-
- // iterator
- Iterator<?> it = keySet.iterator();
- while (it.hasNext()) {
- assertTrue(
- "UnmodifiableMapTest - keySetTest - Iterator returned wrong values",
- keySet.contains(it.next()));
- }
-
- // size
- assertTrue(
- "UnmodifiableMapTest - keySetTest - returned wrong size. Wanted 100, got: "
- + keySet.size(), keySet.size() == 100);
-
- // toArray
- Object[] objArray;
- objArray = keySet.toArray();
- for (int counter = 0; it.hasNext(); counter++) {
- assertTrue(
- "UnmodifiableMapTest - keySetTest - toArray returned incorrect array",
- objArray[counter] == it.next());
- }
-
- // toArray (Object[])
- objArray = new Object[100];
- keySet.toArray(objArray);
- for (int counter = 0; it.hasNext(); counter++) {
- assertTrue(
- "UnmodifiableMapTest - keySetTest - toArray(Object) filled array incorrectly",
- objArray[counter] == it.next());
- }
- }
-
-}