Merge "sun.security.validator: delete this package"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 470484e..ef7703e 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -188,7 +188,7 @@
LOCAL_SRC_FILES := $(test_src_files)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs okhttp core-junit junit4-target bouncycastle mockito-target
+LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp core-junit junit4-target bouncycastle mockito-target
LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support sqlite-jdbc mockwebserver nist-pkix-tests
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -217,7 +217,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under, jsr166-tests)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs core-junit junit4-target
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit junit4-target
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := jsr166-tests
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -229,7 +229,7 @@
ifeq ($(LIBCORE_SKIP_TESTS),)
include $(CLEAR_VARS)
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs okhttp bouncycastle
+ LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := testng
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
@@ -249,7 +249,7 @@
# Include source code as part of JAR
LOCAL_JAVA_RESOURCE_DIRS := ojluni/src/test/dist
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs okhttp bouncycastle testng
+ LOCAL_JAVA_LIBRARIES := core-oj core-libart okhttp bouncycastle testng
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -335,7 +335,7 @@
LOCAL_SRC_FILES := $(test_src_files)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-lambda-stubs-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex junit4-target-hostdex core-tests-support-hostdex mockito-api-hostdex
+ LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex junit4-target-hostdex core-tests-support-hostdex mockito-api-hostdex
LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-host nist-pkix-tests-host
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
@@ -365,7 +365,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(ojtest_src_files)
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-lambda-stubs-hostdex okhttp-hostdex bouncycastle-hostdex
+ LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex okhttp-hostdex bouncycastle-hostdex
LOCAL_STATIC_JAVA_LIBRARIES := testng-hostdex
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
diff --git a/NativeCode.mk b/NativeCode.mk
index cc31819..7c3efbc 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -229,7 +229,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libjavacore
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/NativeCode.mk
-LOCAL_SHARED_LIBRARIES += $(core_shared_libraries) libexpat libicuuc-host libicui18n-host libcrypto libz-host libziparchive
+LOCAL_SHARED_LIBRARIES += $(core_shared_libraries) libexpat libicuuc libicui18n libcrypto libz-host libziparchive
LOCAL_STATIC_LIBRARIES += $(core_static_libraries)
LOCAL_MULTILIB := both
LOCAL_CXX_STL := libc++
@@ -241,7 +241,7 @@
LOCAL_C_INCLUDES := $(core_c_includes)
LOCAL_CFLAGS := -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -DLINUX -D__GLIBC__ # Sigh.
LOCAL_CFLAGS += $(openjdk_cflags)
-LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libicuuc-host libcrypto libz-host
+LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libicuuc libcrypto libz-host
LOCAL_SHARED_LIBRARIES += libopenjdkjvmd libnativehelper
LOCAL_STATIC_LIBRARIES := $(core_static_libraries) libfdlibm
LOCAL_MODULE_TAGS := optional
@@ -256,7 +256,7 @@
LOCAL_C_INCLUDES := $(core_c_includes)
LOCAL_CFLAGS := -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -DLINUX -D__GLIBC__ # Sigh.
LOCAL_CFLAGS += $(openjdk_cflags)
-LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libicuuc-host libcrypto libz-host
+LOCAL_SHARED_LIBRARIES := $(core_shared_libraries) libicuuc libcrypto libz-host
LOCAL_SHARED_LIBRARIES += libopenjdkjvm libnativehelper
LOCAL_STATIC_LIBRARIES := $(core_static_libraries) libfdlibm
LOCAL_MODULE_TAGS := optional
diff --git a/benchmarks/src/benchmarks/regression/NativeMethodBenchmark.java b/benchmarks/src/benchmarks/regression/NativeMethodBenchmark.java
index c30ea08..dbb6308 100644
--- a/benchmarks/src/benchmarks/regression/NativeMethodBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/NativeMethodBenchmark.java
@@ -32,11 +32,6 @@
}
}
- public void time_emptyJniStaticMethod0(int reps) throws Exception {
- for (int i = 0; i < reps; ++i) {
- NativeTestTarget.emptyJniStaticMethod0();
- }
- }
public void time_emptyJniMethod0(int reps) throws Exception {
NativeTestTarget n = new NativeTestTarget();
@@ -45,14 +40,6 @@
}
}
- public void time_emptyJniStaticMethod6(int reps) throws Exception {
- int a = -1;
- int b = 0;
- for (int i = 0; i < reps; ++i) {
- NativeTestTarget.emptyJniStaticMethod6(a, b, 1, 2, 3, i);
- }
- }
-
public void time_emptyJniMethod6(int reps) throws Exception {
int a = -1;
int b = 0;
@@ -62,12 +49,6 @@
}
}
- public void time_emptyJniStaticMethod6L(int reps) throws Exception {
- for (int i = 0; i < reps; ++i) {
- NativeTestTarget.emptyJniStaticMethod6L(null, null, null, null, null, null);
- }
- }
-
public void time_emptyJniMethod6L(int reps) throws Exception {
NativeTestTarget n = new NativeTestTarget();
for (int i = 0; i < reps; ++i) {
@@ -75,4 +56,78 @@
}
}
+ public void time_emptyJniStaticMethod6L(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod6L(null, null, null, null, null, null);
+ }
+ }
+ public void time_emptyJniStaticMethod0(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod0();
+ }
+ }
+
+ public void time_emptyJniStaticMethod6(int reps) throws Exception {
+ int a = -1;
+ int b = 0;
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod6(a, b, 1, 2, 3, i);
+ }
+ }
+
+ public void time_emptyJniMethod0_Fast(int reps) throws Exception {
+ NativeTestTarget n = new NativeTestTarget();
+ for (int i = 0; i < reps; ++i) {
+ n.emptyJniMethod0_Fast();
+ }
+ }
+
+ public void time_emptyJniMethod6_Fast(int reps) throws Exception {
+ int a = -1;
+ int b = 0;
+ NativeTestTarget n = new NativeTestTarget();
+ for (int i = 0; i < reps; ++i) {
+ n.emptyJniMethod6_Fast(a, b, 1, 2, 3, i);
+ }
+ }
+
+ public void time_emptyJniMethod6L_Fast(int reps) throws Exception {
+ NativeTestTarget n = new NativeTestTarget();
+ for (int i = 0; i < reps; ++i) {
+ n.emptyJniMethod6L_Fast(null, null, null, null, null, null);
+ }
+ }
+
+ public void time_emptyJniStaticMethod6L_Fast(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod6L_Fast(null, null, null, null, null, null);
+ }
+ }
+ public void time_emptyJniStaticMethod0_Fast(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod0_Fast();
+ }
+ }
+
+ public void time_emptyJniStaticMethod6_Fast(int reps) throws Exception {
+ int a = -1;
+ int b = 0;
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod6_Fast(a, b, 1, 2, 3, i);
+ }
+ }
+
+ public void time_emptyJniStaticMethod0_Critical(int reps) throws Exception {
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod0_Critical();
+ }
+ }
+
+ public void time_emptyJniStaticMethod6_Critical(int reps) throws Exception {
+ int a = -1;
+ int b = 0;
+ for (int i = 0; i < reps; ++i) {
+ NativeTestTarget.emptyJniStaticMethod6_Critical(a, b, 1, 2, 3, i);
+ }
+ }
}
diff --git a/dalvik/src/main/java/dalvik/annotation/MethodParameters.java b/dalvik/src/main/java/dalvik/annotation/MethodParameters.java
new file mode 100644
index 0000000..ef30197
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/MethodParameters.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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 dalvik.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Parameter;
+
+/**
+ * A "system annotation" that can optionally be used to provide parameter metadata such as
+ * parameter names and modifiers.
+ *
+ * <p>The annotation can be omitted from a method / constructor safely when the parameter metadata
+ * is not needed / desired at runtime. {@link Parameter#isNamePresent()} can be used to check
+ * whether metadata is present for a parameter, and the associated reflection methods like
+ * {@link java.lang.reflect.Parameter#getName()} will fall back to default behavior at runtime if
+ * the information is not present.
+ *
+ * <p>When including parameter metadata, compilers should include parameter metadata for generated
+ * classes like enums, since the parameter metadata includes whether or not a parameter is
+ * synthetic or mandated.
+ *
+ * <p>MethodParameters currently only describes individual method parameters and there is no
+ * mechanism to detect whether parameter method data is <em>generally</em> present for an
+ * {@link java.lang.reflect.Executable}. Therefore, it is code-size and runtime efficient to omit
+ * the annotation entirely for constructors and methods that have no parameters.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
+@interface MethodParameters {
+
+ /*
+ * This annotation is never used in source code; it is expected to be generated in .dex
+ * files by tools like compilers. Commented definitions for the annotation members expected
+ * by the runtime / reflection code can be found below for reference.
+ *
+ * The arrays documented below must be the same size as for the method_id_item dex structure
+ * associated with the method otherwise a java.lang.reflect.MalformedParametersException will
+ * be thrown at runtime.
+ *
+ * That is: method_id_item.proto_idx -> proto_id_item.parameters_off -> type_list.size must
+ * be the same as names().length and accessFlags().length.
+ *
+ * Because MethodParameters describes all formal method parameters, even those not explicitly
+ * or implicitly declared in source code, the size of the arrays may differ from the Signature
+ * or other metadata information that can be based only on explicit parameters declared in
+ * source code. MethodParameters will also not include any information about type annotation
+ * receiver parameters that do not exist in the actual method signature.
+ */
+
+
+ /*
+ * The names of formal parameters for the associated method. The array cannot be null, but can
+ * be empty if there are no formal parameters. A value in the array can be null if the formal
+ * parameter with that index has no name.
+ *
+ * If parameter name Strings are empty or contain '.', ';', '[' or '/' then a
+ * java.lang.reflect.MalformedParametersException will be thrown at runtime.
+ */
+ // String[] names();
+
+ /*
+ * The access flags of the formal parameters for the associated method. The array cannot be
+ * null, but can be empty if there are no formal parameters.
+ *
+ * The value is a bit mask with the follow values:
+ * 0x0010 : final, the parameter was declared final
+ * 0x1000 : synthetic, the parameter was introduced by the compiler.
+ * 0x8000 : mandated, the parameter is synthetic but also implied by the language
+ * specification.
+ *
+ * If any bits are set outside of this set then a java.lang.reflect.MalformedParametersException
+ * will be thrown at runtime.
+ */
+ // int[] accessFlags();
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index b9de236..6426bd8 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -66,6 +66,11 @@
void onNetwork();
/**
+ * Called on unbuffered input/ouput operations.
+ */
+ void onUnbufferedIO();
+
+ /**
* Returns the policy bitmask, for shipping over Binder calls
* to remote threads/processes and reinstantiating the policy
* there. The bits in the mask are from the DISALLOW_* and
@@ -118,6 +123,7 @@
public void onWriteToDisk() {}
public void onReadFromDisk() {}
public void onNetwork() {}
+ public void onUnbufferedIO() {}
public int getPolicyMask() {
return 0;
}
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
index 5daf6a0..a9efabe 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
@@ -16,6 +16,9 @@
package org.apache.harmony.dalvik;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Methods used to test calling into native code. The methods in this
* class are all effectively no-ops and may be used to test the mechanisms
@@ -25,30 +28,6 @@
public NativeTestTarget() {
}
- public static native synchronized void emptyJniStaticSynchronizedMethod0();
-
- public native synchronized void emptyJniSynchronizedMethod0();
-
- public static native void emptyJniStaticMethod0();
-
- public native void emptyJniMethod0();
-
- public static native void emptyJniStaticMethod6(int a, int b, int c, int d, int e, int f);
-
- public native void emptyJniMethod6(int a, int b, int c, int d, int e, int f);
-
- /**
- * This is an empty native static method with six args, hooked up
- * using JNI. These have more complex args to show the cost of
- * parsing the signature. All six values should be null
- * references.
- */
- public static native void emptyJniStaticMethod6L(String a, String[] b,
- int[][] c, Object d, Object[] e, Object[][][][] f);
-
- public native void emptyJniMethod6L(String a, String[] b,
- int[][] c, Object d, Object[] e, Object[][][][] f);
-
/**
* This is used to benchmark dalvik's inline natives.
*/
@@ -59,4 +38,64 @@
* This is used to benchmark dalvik's inline natives.
*/
public static native void emptyInternalStaticMethod();
+
+ // Synchronized methods. Test normal JNI only.
+ public static native synchronized void emptyJniStaticSynchronizedMethod0();
+ public native synchronized void emptyJniSynchronizedMethod0();
+
+ // Static methods without object parameters. Test all optimization combinations.
+
+ // Normal native.
+ public static native void emptyJniStaticMethod0();
+ // Normal native.
+ public static native void emptyJniStaticMethod6(int a, int b, int c, int d, int e, int f);
+
+ @FastNative
+ public static native void emptyJniStaticMethod0_Fast();
+ @FastNative
+ public static native void emptyJniStaticMethod6_Fast(int a, int b, int c, int d, int e, int f);
+
+ @CriticalNative
+ public static native void emptyJniStaticMethod0_Critical();
+ @CriticalNative
+ public static native void emptyJniStaticMethod6_Critical(int a, int b, int c, int d, int e, int f);
+ // Instance methods or methods with object parameters. Test {Normal, @FastNative} combinations.
+
+ // Normal native.
+ public native void emptyJniMethod0();
+ // Normal native.
+ public native void emptyJniMethod6(int a, int b, int c, int d, int e, int f);
+
+ /**
+ * This is an empty native static method with six args, hooked up
+ * using JNI. These have more complex args to show the cost of
+ * parsing the signature. All six values should be null
+ * references.
+ */
+ // Normal native.
+ public static native void emptyJniStaticMethod6L(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
+
+ // Normal native.
+ public native void emptyJniMethod6L(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
+
+ @FastNative
+ public native void emptyJniMethod0_Fast();
+ @FastNative
+ public native void emptyJniMethod6_Fast(int a, int b, int c, int d, int e, int f);
+
+ /**
+ * This is an empty native static method with six args, hooked up
+ * using JNI. These have more complex args to show the cost of
+ * parsing the signature. All six values should be null
+ * references.
+ */
+ @FastNative
+ public static native void emptyJniStaticMethod6L_Fast(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
+
+ @FastNative
+ public native void emptyJniMethod6L_Fast(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
}
diff --git a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
index 52f22a8..9a934f6 100644
--- a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
+++ b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.cpp
@@ -19,25 +19,62 @@
#include "JNIHelp.h"
#include "JniConstants.h"
-static void NativeTestTarget_emptyJniMethod0(JNIEnv*, jobject) { }
-static void NativeTestTarget_emptyJniMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
-static void NativeTestTarget_emptyJniMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
-static void NativeTestTarget_emptyJniStaticMethod0(JNIEnv*, jclass) { }
-static void NativeTestTarget_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
-static void NativeTestTarget_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
static void NativeTestTarget_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
static void NativeTestTarget_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
+static JNINativeMethod gMethods_NormalOnly[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticSynchronizedMethod0, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniSynchronizedMethod0, "()V"),
+};
+
+
+static void NativeTestTarget_emptyJniMethod0(JNIEnv*, jobject) { }
+static void NativeTestTarget_emptyJniMethod6(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeTestTarget_emptyJniMethod6L(JNIEnv*, jobject, jobject, jarray, jarray, jobject, jarray, jarray) { }
+static void NativeTestTarget_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
+
+static void NativeTestTarget_emptyJniStaticMethod0(JNIEnv*, jclass) { }
+static void NativeTestTarget_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(NativeTestTarget, emptyJniMethod0, "()V"),
NATIVE_METHOD(NativeTestTarget, emptyJniMethod6, "(IIIIII)V"),
NATIVE_METHOD(NativeTestTarget, emptyJniMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0, "()V"),
NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6, "(IIIIII)V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniStaticSynchronizedMethod0, "()V"),
- NATIVE_METHOD(NativeTestTarget, emptyJniSynchronizedMethod0, "()V"),
+};
+
+static void NativeTestTarget_emptyJniMethod0_Fast(JNIEnv*, jobject) { }
+static void NativeTestTarget_emptyJniMethod6_Fast(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeTestTarget_emptyJniMethod6L_Fast(JNIEnv*, jobject, jobject, jarray, jarray, jobject, jarray, jarray) { }
+static void NativeTestTarget_emptyJniStaticMethod6L_Fast(JNIEnv*, jclass, jobject, jarray, jarray, jobject, jarray, jarray) { }
+
+static void NativeTestTarget_emptyJniStaticMethod0_Fast(JNIEnv*, jclass) { }
+static void NativeTestTarget_emptyJniStaticMethod6_Fast(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Fast[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod6_Fast, "(IIIIII)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6_Fast, "(IIIIII)V"),
+};
+
+
+static void NativeTestTarget_emptyJniStaticMethod0_Critical() { }
+static void NativeTestTarget_emptyJniStaticMethod6_Critical( int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Critical[] = {
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod0_Critical, "()V"),
+ NATIVE_METHOD(NativeTestTarget, emptyJniStaticMethod6_Critical, "(IIIIII)V"),
};
int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_NormalOnly, NELEM(gMethods_NormalOnly));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_Fast, NELEM(gMethods_Fast));
+ jniRegisterNativeMethods(env, "org/apache/harmony/dalvik/NativeTestTarget", gMethods_Critical, NELEM(gMethods_Critical));
+
+ return 0;
}
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 1cf37c9..a2ff4ee 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1548,5 +1548,13 @@
names: [
"com.android.org.apache.harmony.luni.tests.java.net.URLClassLoaderImplTest#test_Constructor$Ljava_net_URLLjava_lang_ClassLoaderLjava_net_URLStreamHandlerFactory"
]
+},
+{
+ description: "Waiting for ICU 58 to be merged",
+ bug: 31516121,
+ result: EXEC_FAILED,
+ names: [
+ "libcore.java.text.OldBidiTest#testUnicode9EmojisAreLtrNeutral"
+ ]
}
]
diff --git a/expectations/virtualdeviceknownfailures.txt b/expectations/virtualdeviceknownfailures.txt
new file mode 100644
index 0000000..f427a71
--- /dev/null
+++ b/expectations/virtualdeviceknownfailures.txt
@@ -0,0 +1,11 @@
+/*
+ * This file contains expectations for tests known to fail on virtual device
+ */
+[
+{
+ description: "IPv6 connectivity not yet supported in virtual device testing infra",
+ result: EXEC_FAILED,
+ name: "libcore.java.net.SocketTest#testSocketTestAllAddresses",
+ bug: 30965313
+}
+]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
index 948059b..6253b6b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
@@ -18,6 +18,7 @@
package org.apache.harmony.tests.java.io;
import dalvik.system.DexFile;
+import dalvik.system.VMRuntime;
import java.io.Externalizable;
import java.io.File;
import java.io.IOException;
@@ -28,6 +29,7 @@
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.file.Files;
@@ -227,20 +229,43 @@
// http://b/28106822
public void testBug28106822() throws Exception {
- Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
- "getConstructorId", Class.class);
- getConstructorId.setAccessible(true);
+ int savedTargetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ try {
+ // Assert behavior up to 24
+ VMRuntime.getRuntime().setTargetSdkVersion(24);
+ Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
+ "getConstructorId", Class.class);
+ getConstructorId.setAccessible(true);
- assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class));
- assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class));
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class));
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class));
- Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
- Class.class, Long.TYPE);
- newInstance.setAccessible(true);
+ Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
+ Class.class, Long.TYPE);
+ newInstance.setAccessible(true);
- Object obj = newInstance.invoke(null, String.class, 0 /* ignored */);
- assertNotNull(obj);
- assertTrue(obj instanceof String);
+ Object obj = newInstance.invoke(null, String.class, 0 /* ignored */);
+ assertNotNull(obj);
+ assertTrue(obj instanceof String);
+
+ // Assert behavior from API 25
+ VMRuntime.getRuntime().setTargetSdkVersion(25);
+ try {
+ getConstructorId.invoke(null, Object.class);
+ fail();
+ } catch (InvocationTargetException expected) {
+ assertTrue(expected.getCause() instanceof UnsupportedOperationException);
+ }
+ try {
+ newInstance.invoke(null, String.class, 0 /* ignored */);
+ fail();
+ } catch (InvocationTargetException expected) {
+ assertTrue(expected.getCause() instanceof UnsupportedOperationException);
+ }
+
+ } finally {
+ VMRuntime.getRuntime().setTargetSdkVersion(savedTargetSdkVersion);
+ }
}
// Class without <clinit> method
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
index a32845c..6d62cbb 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/CurrencyTest.java
@@ -131,6 +131,18 @@
fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) {
}
+
+ try {
+ Currency.getInstance((Locale) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Currency.getInstance((String) null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException expected) {
+ }
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java
deleted file mode 100644
index 10bb50e..0000000
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/InvalidPropertiesFormatExceptionTest.java
+++ /dev/null
@@ -1,50 +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 org.apache.harmony.tests.java.util;
-
-import java.io.NotSerializableException;
-import java.util.InvalidPropertiesFormatException;
-
-import org.apache.harmony.testframework.serialization.SerializationTest;
-
-public class InvalidPropertiesFormatExceptionTest extends
- junit.framework.TestCase {
-
- /**
- * java.util.InvalidPropertiesFormatException#SerializationTest()
- */
- public void test_Serialization() throws Exception {
- InvalidPropertiesFormatException ipfe = new InvalidPropertiesFormatException(
- "Hey, this is InvalidPropertiesFormatException");
- try {
- SerializationTest.verifySelf(ipfe);
- } catch (NotSerializableException e) {
- // expected
- }
- }
-
- /**
- * {@link java.util.InvalidPropertiesFormatException#InvalidPropertiesFormatException(Throwable)}
- */
- public void test_Constructor_Ljava_lang_Throwable() {
- Throwable throwable = new Throwable();
- InvalidPropertiesFormatException exception = new InvalidPropertiesFormatException(
- throwable);
- assertEquals("the casue did not equals argument passed in constructor",
- throwable, exception.getCause());
- }
-
-}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
index 27cae4e..038cc7b 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/PropertiesTest.java
@@ -20,15 +20,18 @@
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.CharArrayReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.PrintWriter;
+import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.InvalidPropertiesFormatException;
@@ -389,21 +392,21 @@
prop = new Properties();
Properties expected = new Properties();
- expected.put("a", "\u0000");
+ expected.put("a", "");
prop.load(new ByteArrayInputStream("a=\\".getBytes()));
- assertEquals("Failed to read trailing slash value", expected, prop);
+ assertEquals("Failed to trim trailing slash value", expected, prop);
prop = new Properties();
expected = new Properties();
- expected.put("a", "\u1234\u0000");
+ expected.put("a", "\u1234");
prop.load(new ByteArrayInputStream("a=\\u1234\\".getBytes()));
- assertEquals("Failed to read trailing slash value #2", expected, prop);
+ assertEquals("Failed to trim trailing slash value #2", expected, prop);
prop = new Properties();
expected = new Properties();
expected.put("a", "q");
prop.load(new ByteArrayInputStream("a=\\q".getBytes()));
- assertEquals("Failed to read slash value #3", expected, prop);
+ assertEquals("Failed to skip slash value #3", expected, prop);
}
/**
@@ -1087,6 +1090,47 @@
}
/**
+ * Checks the example given in the documentation of a single property split over
+ * multiple lines separated by a backslash and newline character.
+ */
+ public void testSingleProperty_multipleLinesJoinedByBackslash() throws Exception {
+ String propertyString = "fruits apple, banana, pear, \\\n"
+ + " cantaloupe, watermelon, \\\n"
+ + " kiwi, mango";
+ checkSingleProperty("fruits", "apple, banana, pear, cantaloupe, watermelon, kiwi, mango",
+ propertyString);
+ }
+
+ /**
+ * Checks that a trailing backslash at the end of the single line of input is ignored.
+ * This is similar to a check in {@link #test_loadLjava_io_Reader()} that uses an
+ * InputStream and {@link Properties#equals(Object)} .
+ */
+ public void testSingleProperty_oneLineWithTrailingBackslash() throws Exception {
+ checkSingleProperty("key", "value", "key=value\\");
+ }
+
+ /**
+ * Checks that a trailing backslash at the end of the single line of input is ignored,
+ * even when that line has a newline.
+ */
+ public void testSingleProperty_oneLineWithTrailingBackslash_newline() throws Exception {
+ checkSingleProperty("key", "value", "key=value\\\r");
+ checkSingleProperty("key", "value", "key=value\\\n");
+ checkSingleProperty("key", "value", "key=value\\\r\n");
+ }
+
+ private static void checkSingleProperty(String key, String value, String serialized)
+ throws IOException {
+ Properties properties = new Properties();
+ try (Reader reader = new CharArrayReader(serialized.toCharArray())) {
+ properties.load(reader);
+ assertEquals(Collections.singleton(key), properties.keySet());
+ assertEquals(value, properties.getProperty(key));
+ }
+ }
+
+ /**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
index db2ee7a..5d35e4c 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
@@ -39,6 +39,17 @@
assertEquals("[de_CH, de, ]", c.getCandidateLocales("base", new Locale("de", "CH")).toString());
}
+ public void test_getBaseName() {
+ String name = "tests.support.Support_TestResource";
+ ResourceBundle bundle = ResourceBundle.getBundle(name);
+ assertEquals(name, bundle.getBaseBundleName());
+
+ bundle = ResourceBundle.getBundle(name, Locale.getDefault());
+ assertEquals(name, bundle.getBaseBundleName());
+
+ assertNull(new Mock_ResourceBundle().getBaseBundleName());
+ }
+
/**
* java.util.ResourceBundle#getBundle(java.lang.String,
* java.util.Locale)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
index 8fae7b8..aa50676 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/SSLEngineTest.java
@@ -894,8 +894,8 @@
SSLEngine sse = getEngine(host, port);
try {
- // TODO: decide whether OpenSSLEngineImpl should throw ISE (it doesn't) b/31301555
SSLEngineResult result = sse.wrap(bbs, bbd);
+ fail();
} catch (IllegalStateException expected) {
}
}
@@ -993,8 +993,11 @@
ByteBuffer[] bbA = { ByteBuffer.allocate(5), ByteBuffer.allocate(10), ByteBuffer.allocate(5) };
SSLEngine sse = getEngine(host, port);
- SSLEngineResult result = sse.wrap(bbA, bb);
- assertEquals(Status.BUFFER_OVERFLOW, result.getStatus());
+ try {
+ SSLEngineResult result = sse.wrap(bbA, bb);
+ fail();
+ } catch (IllegalStateException expected) {
+ }
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
index f2ef564..6d775ec 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/SubjectTest.java
@@ -19,12 +19,18 @@
import junit.framework.TestCase;
import javax.security.auth.Subject;
+import javax.security.auth.x500.X500Principal;
+
import java.security.AccessControlContext;
import java.security.AccessController;
+import java.security.Principal;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
+import java.util.HashSet;
+import java.util.Set;
+
import org.apache.harmony.testframework.serialization.SerializationTest;
/**
@@ -48,6 +54,29 @@
}
}
+ public void test_Constructor_failsWithNullArguments() {
+ try {
+ new Subject(false /* readOnly */,
+ null /* principals */,
+ new HashSet<Object>() /* pubCredentials */,
+ new HashSet<Object>() /* privCredentials */);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ new Subject(false , new HashSet<Principal>(), null, new HashSet<Object>());
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ new Subject(false , new HashSet<Principal>(), new HashSet<Object>(), null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
/**
* javax.security.auth.Subject#doAs(Subject subject, PrivilegedAction action)
*/
@@ -234,6 +263,36 @@
SerializationTest.verifyGolden(this, getSerializationData());
}
+ public void testSerialization_nullPrincipalsAllowed() throws Exception {
+ Set<Principal> principalsSet = new HashSet<>();
+ principalsSet.add(new X500Principal("CN=SomePrincipal"));
+ principalsSet.add(null);
+ principalsSet.add(new X500Principal("CN=SomeOtherPrincipal"));
+ Subject subject = new Subject(
+ false /* readOnly */, principalsSet, new HashSet<Object>(), new HashSet<Object>());
+ SerializationTest.verifySelf(subject);
+ }
+
+ public void testSecureTest_removeAllNull_throwsException() throws Exception {
+ Subject subject = new Subject(
+ false, new HashSet<Principal>(), new HashSet<Object>(), new HashSet<Object>());
+ try {
+ subject.getPrincipals().removeAll(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testSecureTest_retainAllNull_throwsException() throws Exception {
+ Subject subject = new Subject(
+ false, new HashSet<Principal>(), new HashSet<Object>(), new HashSet<Object>());
+ try {
+ subject.getPrincipals().retainAll(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
private Object[] getSerializationData() {
Subject subject = new Subject();
return new Object[] { subject, subject.getPrincipals(),
diff --git a/include/LocalArray.h b/include/LocalArray.h
deleted file mode 100644
index 2ab708a..0000000
--- a/include/LocalArray.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#ifndef LOCAL_ARRAY_H_included
-#define LOCAL_ARRAY_H_included
-
-#include <cstddef>
-#include <new>
-
-/**
- * A fixed-size array with a size hint. That number of bytes will be allocated
- * on the stack, and used if possible, but if more bytes are requested at
- * construction time, a buffer will be allocated on the heap (and deallocated
- * by the destructor).
- *
- * The API is intended to be a compatible subset of C++0x's std::array.
- */
-template <size_t STACK_BYTE_COUNT>
-class LocalArray {
-public:
- /**
- * Allocates a new fixed-size array of the given size. If this size is
- * less than or equal to the template parameter STACK_BYTE_COUNT, an
- * internal on-stack buffer will be used. Otherwise a heap buffer will
- * be allocated.
- */
- LocalArray(size_t desiredByteCount) : mSize(desiredByteCount) {
- if (desiredByteCount > STACK_BYTE_COUNT) {
- mPtr = new char[mSize];
- } else {
- mPtr = &mOnStackBuffer[0];
- }
- }
-
- /**
- * Frees the heap-allocated buffer, if there was one.
- */
- ~LocalArray() {
- if (mPtr != &mOnStackBuffer[0]) {
- delete[] mPtr;
- }
- }
-
- // Capacity.
- size_t size() { return mSize; }
- bool empty() { return mSize == 0; }
-
- // Element access.
- char& operator[](size_t n) { return mPtr[n]; }
- const char& operator[](size_t n) const { return mPtr[n]; }
-
-private:
- char mOnStackBuffer[STACK_BYTE_COUNT];
- char* mPtr;
- size_t mSize;
-
- // Disallow copy and assignment.
- LocalArray(const LocalArray&);
- void operator=(const LocalArray&);
-};
-
-#endif // LOCAL_ARRAY_H_included
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
deleted file mode 100644
index 6e3e181..0000000
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ /dev/null
@@ -1,306 +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.
- */
-/*
- * Copyright (C) 2012 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 java.lang.reflect;
-
-import com.android.dex.Dex;
-
-import java.lang.annotation.Annotation;
-import libcore.reflect.GenericSignatureParser;
-import libcore.reflect.ListOfTypes;
-import libcore.reflect.Types;
-import libcore.util.EmptyArray;
-
-/**
- * This class represents an abstract method. Abstract methods are either methods or constructors.
- * @hide
- */
-public abstract class AbstractMethod extends Executable {
- /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
- @SuppressWarnings("unused") // set by runtime
- private int accessFlags;
-
- /**
- * The ArtMethod associated with this Method, required for dispatching due to entrypoints
- * Classloader is held live by the declaring class.
- * Hidden to workaround b/16828157.
- * @hide
- */
- @SuppressWarnings("unused") // set by runtime
- private long artMethod;
-
- /** Method's declaring class */
- @SuppressWarnings("unused") // set by runtime
- private Class<?> declaringClass;
-
- /** Overriden method's declaring class (same as declaringClass unless declaringClass
- * is a proxy class)
- */
- @SuppressWarnings("unused") // set by runtime
- private Class<?> declaringClassOfOverriddenMethod;
-
- /** The method index of this method within its defining dex file */
- @SuppressWarnings("unused") // set by runtime
- private int dexMethodIndex;
-
- /**
- * Hidden to workaround b/16828157.
- * @hide
- */
- protected AbstractMethod() {
- }
-
- /**
- * We insert native method stubs for abstract methods so we don't have to
- * check the access flags at the time of the method call. This results in
- * "native abstract" methods, which can't exist. If we see the "abstract"
- * flag set, clear the "native" flag.
- *
- * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
- * position, because the callers of this function are trying to convey
- * the "traditional" meaning of the flags to their callers.
- */
- private static int fixMethodFlags(int flags) {
- if ((flags & Modifier.ABSTRACT) != 0) {
- flags &= ~Modifier.NATIVE;
- }
- flags &= ~Modifier.SYNCHRONIZED;
- int ACC_DECLARED_SYNCHRONIZED = 0x00020000;
- if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
- flags |= Modifier.SYNCHRONIZED;
- }
- return flags & 0xffff; // mask out bits not used by Java
- }
-
- // Overrides {@link Executable#getModifiers()} - for ART behavior see fixMethodFlags().
- @Override
- public int getModifiers() {
- return fixMethodFlags(accessFlags);
- }
-
- // Overrides {@link Executable#isSynthetic()} - we can do it cheaply here.
- @Override
- public boolean isSynthetic() {
- return (accessFlags & Modifier.SYNTHETIC) != 0;
- }
-
- // Overrides {@link Executable#isVarArgs()} - we can do it cheaply here.
- @Override
- public boolean isVarArgs() {
- return (accessFlags & Modifier.VARARGS) != 0;
- }
-
- @Override
- public Class<?> getDeclaringClass() {
- return declaringClass;
- }
-
- /**
- * Returns an array of {@code Class} objects associated with the parameter types of this
- * abstract method. If the method was declared with no parameters, an
- * empty array will be returned.
- *
- * @return the parameter types
- */
- @Override
- public Class<?>[] getParameterTypes() {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- if (types.length == 0) {
- return EmptyArray.CLASS;
- }
- Class<?>[] parametersArray = new Class[types.length];
- for (int i = 0; i < types.length; i++) {
- // Note, in the case of a Proxy the dex cache types are equal.
- parametersArray[i] = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
- }
- return parametersArray;
- }
-
- @Override
- public int getParameterCount() {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- return types.length;
- }
-
- @Override
- public Type[] getGenericParameterTypes() {
- return Types.getTypeArray(
- getMethodOrConstructorGenericInfoInternal().genericParameterTypes, false);
- }
-
- @Override
- public Type[] getGenericExceptionTypes() {
- return Types.getTypeArray(
- getMethodOrConstructorGenericInfoInternal().genericExceptionTypes, false);
- }
-
- @Override public native Annotation[] getDeclaredAnnotations();
-
- @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
- if (annotationType == null) {
- throw new NullPointerException("annotationType == null");
- }
- return isAnnotationPresentNative(annotationType);
- }
- private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
-
- @Override
- public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
- if (annotationClass == null) {
- throw new NullPointerException("annotationClass == null");
- }
- return getAnnotationNative(annotationClass);
- }
- private native <T extends Annotation> T getAnnotationNative(Class<T> annotationClass);
-
- @Override
- public Annotation[][] getParameterAnnotations() {
- Annotation[][] parameterAnnotations = getParameterAnnotationsNative();
- if (parameterAnnotations == null) {
- parameterAnnotations = new Annotation[getParameterTypes().length][0];
- }
- return parameterAnnotations;
- }
- private native Annotation[][] getParameterAnnotationsNative();
-
- /**
- * @hide
- */
- public final int getAccessFlags() {
- return accessFlags;
- }
-
- static final class GenericInfo {
- final ListOfTypes genericExceptionTypes;
- final ListOfTypes genericParameterTypes;
- final Type genericReturnType;
- final TypeVariable<?>[] formalTypeParameters;
-
- GenericInfo(ListOfTypes exceptions, ListOfTypes parameters, Type ret,
- TypeVariable<?>[] formal) {
- genericExceptionTypes = exceptions;
- genericParameterTypes = parameters;
- genericReturnType = ret;
- formalTypeParameters = formal;
- }
- }
-
- /**
- * Returns generic information associated with this method/constructor member.
- */
- final GenericInfo getMethodOrConstructorGenericInfoInternal() {
- String signatureAttribute = getSignatureAttribute();
- Class<?>[] exceptionTypes = this.getExceptionTypes();
- GenericSignatureParser parser =
- new GenericSignatureParser(this.getDeclaringClass().getClassLoader());
- if (this instanceof Method) {
- parser.parseForMethod(this, signatureAttribute, exceptionTypes);
- } else {
- parser.parseForConstructor(this, signatureAttribute, exceptionTypes);
- }
- return new GenericInfo(parser.exceptionTypes, parser.parameterTypes,
- parser.returnType, parser.formalTypeParameters);
- }
-
- private String getSignatureAttribute() {
- String[] annotation = getSignatureAnnotation();
- if (annotation == null) {
- return null;
- }
- StringBuilder result = new StringBuilder();
- for (String s : annotation) {
- result.append(s);
- }
- return result.toString();
- }
- private native String[] getSignatureAnnotation();
-
- final boolean equalNameAndParametersInternal(Method m) {
- return getName().equals(m.getName()) && equalMethodParameters(m.getParameterTypes());
- }
-
- private boolean equalMethodParameters(Class<?>[] params) {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- if (types.length != params.length) {
- return false;
- }
- for (int i = 0; i < types.length; i++) {
- if (declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]) != params[i]) {
- return false;
- }
- }
- return true;
- }
-
- final int compareMethodParametersInternal(Class<?>[] params) {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
- int length = Math.min(types.length, params.length);
- for (int i = 0; i < length; i++) {
- Class<?> aType = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
- Class<?> bType = params[i];
- if (aType != bType) {
- int comparison = aType.getName().compareTo(bType.getName());
- if (comparison != 0) {
- return comparison;
- }
- }
- }
- return types.length - params.length;
- }
-
- final String getMethodNameInternal() {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- int nameIndex = dex.nameIndexFromMethodIndex(dexMethodIndex);
- return declaringClassOfOverriddenMethod.getDexCacheString(dex, nameIndex);
- }
-
- final Class<?> getMethodReturnTypeInternal() {
- Dex dex = declaringClassOfOverriddenMethod.getDex();
- int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(dexMethodIndex);
- // Note, in the case of a Proxy the dex cache types are equal.
- return declaringClassOfOverriddenMethod.getDexCacheType(dex, returnTypeIndex);
- }
-
- /** A cheap implementation for {@link Method#isDefault()}. */
- final boolean isDefaultMethodInternal() {
- return (accessFlags & Modifier.DEFAULT) != 0;
- }
-
- /** A cheap implementation for {@link Method#isBridge()}. */
- final boolean isBridgeMethodInternal() {
- return (accessFlags & Modifier.BRIDGE) != 0;
- }
-}
diff --git a/luni/src/main/java/libcore/io/IoTracker.java b/luni/src/main/java/libcore/io/IoTracker.java
new file mode 100644
index 0000000..4623b6a
--- /dev/null
+++ b/luni/src/main/java/libcore/io/IoTracker.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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 libcore.io;
+
+import dalvik.system.BlockGuard;
+
+/**
+ * Used to detect unbuffered I/O.
+ * @hide
+ */
+public final class IoTracker {
+ private int opCount;
+ private int totalByteCount;
+ private boolean isOpen = true;
+ private Mode mode = Mode.READ;
+
+ public void trackIo(int byteCount) {
+ ++opCount;
+ totalByteCount += byteCount;
+ if (isOpen && opCount > 10 && totalByteCount < 10*512) {
+ BlockGuard.getThreadPolicy().onUnbufferedIO();
+ isOpen = false;
+ }
+ }
+
+ public void trackIo(int byteCount, Mode mode) {
+ if (this.mode != mode) {
+ reset();
+ this.mode = mode;
+ }
+ trackIo(byteCount);
+ }
+
+ /**
+ * Resets the state of the IoTracker, except {@link #isOpen} as it is not required to notify
+ * again and again about the same stream.
+ * This is primarily used by RandomAccessFile to consider a case when {@link
+ * java.io.RandomAccessFile#seek seek} is called.
+ */
+ public void reset() {
+ opCount = 0;
+ totalByteCount = 0;
+ }
+
+ public enum Mode {
+ READ,
+ WRITE
+ }
+}
diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp
index 5fd4a7d..52df40e 100644
--- a/luni/src/main/native/Register.cpp
+++ b/luni/src/main/native/Register.cpp
@@ -53,3 +53,20 @@
return JNI_VERSION_1_6;
}
+
+// DalvikVM calls this on shutdown, do any global cleanup here.
+// -- Very important if we restart multiple DalvikVMs in the same process to reset the state.
+void JNI_OnUnload(JavaVM* vm, void*) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("JavaVM::GetEnv() failed");
+ abort();
+ }
+ ALOGV("libjavacore JNI_OnUnload");
+
+ ScopedLocalFrame localFrame(env);
+
+#define UNREGISTER(FN) extern void FN(JNIEnv*); FN(env)
+ UNREGISTER(unregister_libcore_icu_ICU);
+#undef UNREGISTER
+}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 3eda923..e6f378e 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -838,56 +838,110 @@
NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
};
+//
+// Global initialization & Teardown for ICU Setup
+// - Contains handlers for JNI_OnLoad and JNI_OnUnload
+//
+
#define FAIL_WITH_STRERROR(s) \
- ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
+ ALOGE("Couldn't " s " '%s': %s", path_.c_str(), strerror(errno)); \
return FALSE;
#define MAYBE_FAIL_WITH_ICU_ERROR(s) \
if (status != U_ZERO_ERROR) {\
- ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
+ ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path_.c_str()); \
return FALSE; \
}
-static bool mapIcuData(const std::string& path) {
+// Contain the memory map for ICU data files.
+// Automatically adds the data file to ICU's list of data files upon constructing.
+//
+// - Automatically unmaps in the destructor.
+struct IcuDataMap {
+ // Map in ICU data at the path, returning null if it failed (prints error to ALOGE).
+ static std::unique_ptr<IcuDataMap> Create(const std::string& path) {
+ std::unique_ptr<IcuDataMap> map(new IcuDataMap(path));
+
+ if (!map->TryMap()) {
+ // madvise or ICU could fail but mmap still succeeds.
+ // Destructor will take care of cleaning up a partial init.
+ return nullptr;
+ }
+
+ return map;
+ }
+
+ // Unmap the ICU data.
+ ~IcuDataMap() {
+ TryUnmap();
+ }
+
+ private:
+ IcuDataMap(const std::string& path)
+ : path_(path),
+ data_(MAP_FAILED),
+ data_length_(0)
+ {}
+
+ bool TryMap() {
// Open the file and get its length.
- android::base::unique_fd fd(open(path.c_str(), O_RDONLY));
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path_.c_str(), O_RDONLY)));
+
if (fd.get() == -1) {
FAIL_WITH_STRERROR("open");
}
+
struct stat sb;
if (fstat(fd.get(), &sb) == -1) {
FAIL_WITH_STRERROR("stat");
}
+ data_length_ = sb.st_size;
+
// Map it.
- void* data = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
- if (data == MAP_FAILED) {
+ data_ = mmap(NULL, data_length_, PROT_READ, MAP_SHARED, fd.get(), 0 /* offset */);
+ if (data_ == MAP_FAILED) {
FAIL_WITH_STRERROR("mmap");
}
// Tell the kernel that accesses are likely to be random rather than sequential.
- if (madvise(data, sb.st_size, MADV_RANDOM) == -1) {
+ if (madvise(data_, data_length_, MADV_RANDOM) == -1) {
FAIL_WITH_STRERROR("madvise(MADV_RANDOM)");
}
UErrorCode status = U_ZERO_ERROR;
// Tell ICU to use our memory-mapped data.
- udata_setCommonData(data, &status);
+ udata_setCommonData(data_, &status);
MAYBE_FAIL_WITH_ICU_ERROR("udata_setCommonData");
- return TRUE;
-}
+ return true;
+ }
-void register_libcore_icu_ICU(JNIEnv* env) {
- // Check the timezone override file exists. If it does, map it first so we use it in preference
- // to the one that shipped with the device.
- const char* dataPathPrefix = getenv("ANDROID_DATA");
- if (dataPathPrefix == NULL) {
- ALOGE("ANDROID_DATA environment variable not set"); \
- abort();
+ bool TryUnmap() {
+ // Don't need to do opposite of udata_setCommonData,
+ // u_cleanup (performed in unregister_libcore_icu_ICU) takes care of it.
+
+ // Don't need to opposite of madvise, munmap will take care of it.
+
+ if (data_ != MAP_FAILED) {
+ if (munmap(data_, data_length_) == -1) {
+ FAIL_WITH_STRERROR("munmap");
+ }
}
+ // Don't need to close the file, it was closed automatically during TryMap.
+ return true;
+ }
+
+ std::string path_; // Save for error messages.
+ void* data_; // Save for munmap.
+ size_t data_length_; // Save for munmap.
+};
+
+struct ICURegistration {
+ // Init ICU, configuring it and loading the data files.
+ ICURegistration(JNIEnv* env) {
UErrorCode status = U_ZERO_ERROR;
// Tell ICU it can *only* use our memory-mapped data.
udata_setFileAccess(UDATA_NO_FILES, &status);
@@ -896,15 +950,13 @@
abort();
}
- // Map in optional TZ data files.
- std::string dataPath;
- dataPath = dataPathPrefix;
- dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
+ std::string dataPath = getTzDataOverridePath();
+ // Map in optional TZ data files.
struct stat sb;
if (stat(dataPath.c_str(), &sb) == 0) {
ALOGD("Timezone override file found: %s", dataPath.c_str());
- if (!mapIcuData(dataPath)) {
+ if ((icu_datamap_from_data_ = IcuDataMap::Create(dataPath)) == nullptr) {
ALOGW("TZ override file %s exists but could not be loaded. Skipping.", dataPath.c_str());
}
} else {
@@ -912,18 +964,7 @@
}
// Use the ICU data files that shipped with the device for everything else.
- const char* systemPathPrefix = getenv("ANDROID_ROOT");
- if (systemPathPrefix == NULL) {
- ALOGE("ANDROID_ROOT environment variable not set"); \
- abort();
- }
- std::string systemPath;
- systemPath = systemPathPrefix;
- systemPath += "/usr/icu/";
- systemPath += U_ICUDATA_NAME;
- systemPath += ".dat";
-
- if (!mapIcuData(systemPath)) {
+ if ((icu_datamap_from_system_ = IcuDataMap::Create(getSystemPath())) == nullptr) {
abort();
}
@@ -937,4 +978,69 @@
}
jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
+ }
+
+ // De-init ICU, unloading the data files. Do the opposite of the above function.
+ ~ICURegistration() {
+ // Skip unregistering JNI methods explicitly, class unloading takes care of it.
+
+ // Reset libicu state to before it was loaded.
+ u_cleanup();
+
+ // Unmap ICU data files that shipped with the device for everything else.
+ icu_datamap_from_system_.reset();
+
+ // Unmap optional TZ data files.
+ icu_datamap_from_data_.reset();
+
+ // We don't need to call udata_setFileAccess because u_cleanup takes care of it.
+ }
+
+ // Check the timezone override file exists. If it does, map it first so we use it in preference
+ // to the one that shipped with the device.
+ static std::string getTzDataOverridePath() {
+ const char* dataPathPrefix = getenv("ANDROID_DATA");
+ if (dataPathPrefix == NULL) {
+ ALOGE("ANDROID_DATA environment variable not set"); \
+ abort();
+ }
+ std::string dataPath;
+ dataPath = dataPathPrefix;
+ dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
+
+ return dataPath;
+ }
+
+ static std::string getSystemPath() {
+ const char* systemPathPrefix = getenv("ANDROID_ROOT");
+ if (systemPathPrefix == NULL) {
+ ALOGE("ANDROID_ROOT environment variable not set"); \
+ abort();
+ }
+
+ std::string systemPath;
+ systemPath = systemPathPrefix;
+ systemPath += "/usr/icu/";
+ systemPath += U_ICUDATA_NAME;
+ systemPath += ".dat";
+ return systemPath;
+ }
+
+ std::unique_ptr<IcuDataMap> icu_datamap_from_data_;
+ std::unique_ptr<IcuDataMap> icu_datamap_from_system_;
+};
+
+// Use RAII-style initialization/teardown so that we can get unregistered
+// when dlclose is called (even if JNI_OnUnload is not).
+static std::unique_ptr<ICURegistration> sIcuRegistration;
+
+// Init ICU, configuring it and loading the data files.
+void register_libcore_icu_ICU(JNIEnv* env) {
+ sIcuRegistration.reset(new ICURegistration(env));
+}
+
+// De-init ICU, unloading the data files. Do the opposite of the above function.
+void unregister_libcore_icu_ICU(JNIEnv*) {
+ // Explicitly calling this is optional. Dlclose will take care of it as well.
+ sIcuRegistration.reset();
}
diff --git a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 820bda62..e27af69 100644
--- a/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/luni/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -19,7 +19,6 @@
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
-#include "LocalArray.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedStringChars.h"
@@ -33,6 +32,8 @@
#include <string.h>
#include <expat.h>
+#include <android-base/stringprintf.h>
+
#define BUCKET_COUNT 128
/**
@@ -519,9 +520,8 @@
}
// return prefix + ":" + localName
- ::LocalArray<1024> qName(strlen(mPrefix) + 1 + strlen(mLocalName) + 1);
- snprintf(&qName[0], qName.size(), "%s:%s", mPrefix, mLocalName);
- return internString(mEnv, mParsingContext, &qName[0]);
+ auto qName = android::base::StringPrintf("%s:%s", mPrefix, mLocalName);
+ return internString(mEnv, mParsingContext, qName.c_str());
}
/**
diff --git a/luni/src/test/java/dalvik/system/BlockGuardTest.java b/luni/src/test/java/dalvik/system/BlockGuardTest.java
index 24313cd..ca29e77 100644
--- a/luni/src/test/java/dalvik/system/BlockGuardTest.java
+++ b/luni/src/test/java/dalvik/system/BlockGuardTest.java
@@ -21,8 +21,11 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.RandomAccessFile;
import java.util.ArrayList;
+import java.util.EnumSet;
import java.util.List;
+import java.util.Set;
/**
* Created by narayan on 1/7/16.
@@ -34,6 +37,7 @@
@Override
public void setUp() {
+ recorder.setChecks(EnumSet.allOf(RecordingPolicy.Check.class));
oldPolicy = BlockGuard.getThreadPolicy();
BlockGuard.setThreadPolicy(recorder);
}
@@ -138,23 +142,142 @@
recorder.expectNoViolations();
}
+ public void testUnbufferedIO() throws Exception {
+ File f = File.createTempFile("foo", "bar");
+ recorder.setChecks(EnumSet.of(RecordingPolicy.Check.UNBUFFERED_IO));
+ recorder.clear();
+
+ try (FileOutputStream fos = new FileOutputStream(f)) {
+ recorder.expectNoViolations();
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ fos.write("a".getBytes());
+ }
+ recorder.expectAndClear("onUnbufferedIO");
+ }
+
+ try (FileInputStream fis = new FileInputStream(new File("/dev/null"))) {
+ recorder.expectNoViolations();
+ byte[] b = new byte[1];
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ fis.read(b);
+ }
+ recorder.expectAndClear("onUnbufferedIO");
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ // seek should reset the IoTracker.
+ ras.seek(0);
+ recorder.expectNoViolations();
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ ras.read("a".getBytes());
+ }
+ recorder.expectAndClear("onUnbufferedIO");
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ // No violation is expected as a write is called while reading which should reset the
+ // IoTracker counter.
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ if (i == 5) {
+ ras.write("a".getBytes());
+ }
+ ras.read("a".getBytes());
+ }
+ recorder.expectNoViolations();
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ // No violation is expected as a seek is called while reading which should reset the
+ // IoTracker counter.
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ if (i == 5) {
+ ras.seek(0);
+ }
+ ras.read("a".getBytes());
+ }
+ recorder.expectNoViolations();
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ // seek should reset the IoTracker.
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ ras.write("a".getBytes());
+ }
+ recorder.expectAndClear("onUnbufferedIO");
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ // No violation is expected as a read is called while writing which should reset the
+ // IoTracker counter.
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ if (i == 5) {
+ ras.read("a".getBytes());
+ }
+ ras.write("a".getBytes());
+ }
+ recorder.expectNoViolations();
+ }
+
+ try (RandomAccessFile ras = new RandomAccessFile(f, "rw")) {
+ for (int i = 0; i < 11; i++) {
+ recorder.expectNoViolations();
+ if (i == 5) {
+ ras.seek(0);
+ }
+ ras.write("a".getBytes());
+ }
+ recorder.expectNoViolations();
+ }
+ }
public static class RecordingPolicy implements BlockGuard.Policy {
private final List<String> violations = new ArrayList<>();
+ private Set<Check> checksList;
+
+ public enum Check {
+ WRITE_TO_DISK,
+ READ_FROM_DISK,
+ NETWORK,
+ UNBUFFERED_IO,
+ }
+
+ public void setChecks(EnumSet<Check> checksList) {
+ this.checksList = checksList;
+ }
@Override
public void onWriteToDisk() {
- addViolation("onWriteToDisk");
+ if (checksList != null && checksList.contains(Check.WRITE_TO_DISK)) {
+ addViolation("onWriteToDisk");
+ }
}
@Override
public void onReadFromDisk() {
- addViolation("onReadFromDisk");
+ if (checksList != null && checksList.contains(Check.READ_FROM_DISK)) {
+ addViolation("onReadFromDisk");
+ }
}
@Override
public void onNetwork() {
- addViolation("onNetwork");
+ if (checksList != null && checksList.contains(Check.NETWORK)) {
+ addViolation("onNetwork");
+ }
+ }
+
+ @Override
+ public void onUnbufferedIO() {
+ if (checksList != null && checksList.contains(Check.UNBUFFERED_IO)) {
+ addViolation("onUnbufferedIO");
+ }
}
private void addViolation(String type) {
diff --git a/luni/src/test/java/libcore/io/OsTest.java b/luni/src/test/java/libcore/io/OsTest.java
index 648ac2a..687d903 100644
--- a/luni/src/test/java/libcore/io/OsTest.java
+++ b/luni/src/test/java/libcore/io/OsTest.java
@@ -596,8 +596,6 @@
}
public void test_xattr_Errno() throws Exception {
- File file = File.createTempFile("xattr", "test");
- final String path = file.getAbsolutePath();
final String NAME_TEST = "user.meow";
final byte[] VALUE_CAKE = "cake cake cake".getBytes(StandardCharsets.UTF_8);
@@ -606,53 +604,54 @@
Libcore.os.getxattr("", NAME_TEST);
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOENT, e.errno);
+ assertEquals(ENOENT, e.errno);
}
try {
Libcore.os.listxattr("");
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOENT, e.errno);
+ assertEquals(ENOENT, e.errno);
}
try {
Libcore.os.removexattr("", NAME_TEST);
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOENT, e.errno);
+ assertEquals(ENOENT, e.errno);
}
try {
Libcore.os.setxattr("", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOENT, e.errno);
+ assertEquals(ENOENT, e.errno);
}
// ENOTSUP, Extended attributes are not supported by the filesystem, or are disabled.
+ final boolean root = (Libcore.os.getuid() == 0);
+ final String path = "/proc/self/stat";
try {
- Libcore.os.getxattr("/proc/version", NAME_TEST);
+ Libcore.os.setxattr(path, NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOTSUP, e.errno);
+ // setxattr(2) requires root permission for writing to this file, will get EACCES otherwise.
+ assertEquals(root ? ENOTSUP : EACCES, e.errno);
+ }
+ try {
+ Libcore.os.getxattr(path, NAME_TEST);
+ fail();
+ } catch (ErrnoException e) {
+ assertEquals(ENOTSUP, e.errno);
}
try {
// Linux listxattr does not set errno.
- Libcore.os.listxattr("/proc/version");
+ Libcore.os.listxattr(path);
} catch (ErrnoException e) {
fail();
}
try {
- Libcore.os.removexattr("/proc/version", "security.selinux");
+ Libcore.os.removexattr(path, NAME_TEST);
fail();
} catch (ErrnoException e) {
- assertEquals(OsConstants.ENOTSUP, e.errno);
- }
- try {
- Libcore.os.setxattr("/proc/version", NAME_TEST, VALUE_CAKE, OsConstants.XATTR_CREATE);
- fail();
- } catch (ErrnoException e) {
- // For setxattr, EACCES or ENOTSUP is set depending on whether running with root permission.
- assertTrue(e.errno == OsConstants.EACCES ||
- e.errno == OsConstants.ENOTSUP);
+ assertEquals(ENOTSUP, e.errno);
}
}
diff --git a/luni/src/test/java/libcore/java/io/OldBufferedReaderTest.java b/luni/src/test/java/libcore/java/io/OldBufferedReaderTest.java
index 00c5389..71b9517 100644
--- a/luni/src/test/java/libcore/java/io/OldBufferedReaderTest.java
+++ b/luni/src/test/java/libcore/java/io/OldBufferedReaderTest.java
@@ -393,4 +393,37 @@
BufferedReader br = new BufferedReader(new InputStreamReader(pis));
assertEquals("hello, world", br.readLine());
}
+
+ public void test_closeException() throws Exception {
+ final IOException testException = new IOException("kaboom!");
+ Reader thrower = new Reader() {
+ @Override
+ public int read(char cbuf[], int off, int len) throws IOException {
+ // Not used
+ return 0;
+ }
+
+ @Override
+ public void close() throws IOException {
+ throw testException;
+ }
+ };
+ BufferedReader br = new BufferedReader(thrower);
+
+ try {
+ br.close();
+ fail();
+ } catch(IOException expected) {
+ assertSame(testException, expected);
+ }
+
+ try {
+ // Pre-openJdk8 BufferedReader#close() with exception wouldn't
+ // reset the input reader to null. This would still allow ready()
+ // to succeed.
+ br.ready();
+ fail();
+ } catch(IOException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/io/OldBufferedWriterTest.java b/luni/src/test/java/libcore/java/io/OldBufferedWriterTest.java
index ed5b862..5e157d2 100644
--- a/luni/src/test/java/libcore/java/io/OldBufferedWriterTest.java
+++ b/luni/src/test/java/libcore/java/io/OldBufferedWriterTest.java
@@ -17,6 +17,7 @@
package libcore.java.io;
+import java.io.Writer;
import java.io.BufferedWriter;
import java.io.IOException;
import tests.support.Support_ASimpleWriter;
@@ -300,6 +301,43 @@
}
}
+ public void test_closeException() throws Exception {
+ final IOException testException = new IOException("kaboom!");
+ Writer thrower = new Writer() {
+ @Override
+ public void write(char cbuf[], int off, int len) throws IOException {
+ // Not used
+ }
+
+ @Override
+ public void flush() throws IOException {
+ // Not used
+ }
+
+ @Override
+ public void close() throws IOException {
+ throw testException;
+ }
+ };
+ BufferedWriter bw = new BufferedWriter(thrower);
+
+ try {
+ bw.close();
+ fail();
+ } catch(IOException expected) {
+ assertSame(testException, expected);
+ }
+
+ try {
+ // Pre-openJdk8 BufferedWriter#close() with exception wouldn't
+ // reset the output writer to null. This would still allow write()
+ // to succeed.
+ bw.write(1);
+ fail();
+ } catch(IOException expected) {
+ }
+ }
+
protected void setUp() {
sw = new Support_StringWriter();
ssw = new Support_ASimpleWriter(true);
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
new file mode 100644
index 0000000..e7799e9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.lang.invoke;
+
+import junit.framework.TestCase;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.Vector;
+
+import static java.lang.invoke.MethodHandles.Lookup.*;
+
+public class MethodHandlesTest extends TestCase {
+ private static final int ALL_LOOKUP_MODES = (PUBLIC | PRIVATE | PACKAGE | PROTECTED);
+
+ public void test_publicLookupClassAndModes() {
+ MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
+ assertSame(Object.class, publicLookup.lookupClass());
+ assertEquals(PUBLIC, publicLookup.lookupModes());
+ }
+
+ public void test_defaultLookupClassAndModes() {
+ MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
+ assertSame(MethodHandlesTest.class, defaultLookup.lookupClass());
+ assertEquals(ALL_LOOKUP_MODES, defaultLookup.lookupModes());
+ }
+
+ public void test_LookupIn() {
+ MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
+
+ // A class in the same package loses the privilege to lookup protected and private
+ // members.
+ MethodHandles.Lookup siblingLookup = defaultLookup.in(PackageSibling.class);
+ assertEquals(ALL_LOOKUP_MODES & ~(PROTECTED | PRIVATE), siblingLookup.lookupModes());
+
+ // The new lookup isn't in the same package, so it loses all its privileges except
+ // for public.
+ MethodHandles.Lookup nonSibling = defaultLookup.in(Vector.class);
+ assertEquals(PUBLIC, nonSibling.lookupModes());
+
+ // Special case, sibling inner classes in the same parent class
+ MethodHandles.Lookup inner2 = Inner1.lookup.in(Inner2.class);
+ assertEquals(PUBLIC | PRIVATE | PACKAGE, inner2.lookupModes());
+
+ try {
+ MethodHandles.lookup().in(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ // Callers cannot change the lookup context to anything within the java.lang.invoke package.
+ try {
+ MethodHandles.lookup().in(MethodHandle.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void test_findStatic() throws Exception {
+ MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
+
+ // Handle for String String#valueOf(char[]).
+ MethodHandle handle = defaultLookup.findStatic(String.class, "valueOf",
+ MethodType.methodType(String.class, char[].class));
+ assertNotNull(handle);
+
+ assertEquals(String.class, handle.type().returnType());
+ assertEquals(1, handle.type().parameterCount());
+ assertEquals(char[].class, handle.type().parameterArray()[0]);
+ assertEquals(MethodHandle.INVOKE_STATIC, handle.getHandleKind());
+
+ MethodHandles.Lookup inUtil = defaultLookup.in(Vector.class);
+
+ // Package private in a public class in a different package from the lookup.
+ try {
+ inUtil.findStatic(MethodHandlesTest.class, "packagePrivateStaticMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Protected in a public class in a different package from the lookup.
+ try {
+ inUtil.findStatic(MethodHandlesTest.class, "protectedStaticMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Private in a public class in a different package from the lookup.
+ try {
+ inUtil.findStatic(MethodHandlesTest.class, "privateStaticMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Public method in a package private class in a different package from the lookup.
+ try {
+ inUtil.findStatic(PackageSibling.class, "publicStaticMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Public virtual method should not discoverable via findStatic.
+ try {
+ inUtil.findStatic(MethodHandlesTest.class, "publicMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+ }
+
+ public void test_findConstructor() throws Exception {
+ MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
+
+ // Handle for String.<init>(String). The requested type of the constructor declares
+ // a void return type (to match the bytecode) but the handle that's created will declare
+ // a return type that's equal to the type being constructed.
+ MethodHandle handle = defaultLookup.findConstructor(String.class,
+ MethodType.methodType(void.class, String.class));
+ assertNotNull(handle);
+
+ assertEquals(String.class, handle.type().returnType());
+ assertEquals(1, handle.type().parameterCount());
+
+ assertEquals(String.class, handle.type().parameterArray()[0]);
+ assertEquals(MethodHandle.INVOKE_DIRECT, handle.getHandleKind());
+
+ MethodHandles.Lookup inUtil = defaultLookup.in(Vector.class);
+
+ // Package private in a public class in a different package from the lookup.
+ try {
+ inUtil.findConstructor(ConstructorTest.class,
+ MethodType.methodType(void.class, String.class, int.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Protected in a public class in a different package from the lookup.
+ try {
+ inUtil.findConstructor(ConstructorTest.class,
+ MethodType.methodType(void.class, String.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Private in a public class in a different package from the lookup.
+ try {
+ inUtil.findConstructor(ConstructorTest.class,
+ MethodType.methodType(void.class, String.class, char.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Protected constructor in a package private class in a different package from the lookup.
+ try {
+ inUtil.findConstructor(PackageSibling.class,
+ MethodType.methodType(void.class, String.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Public constructor in a package private class in a different package from the lookup.
+ try {
+ inUtil.findConstructor(PackageSibling.class,
+ MethodType.methodType(void.class, String.class, char.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+ }
+
+ public void test_findVirtual() throws Exception {
+ MethodHandles.Lookup defaultLookup = MethodHandles.lookup();
+
+ // String.replaceAll(String, String);
+ MethodHandle handle = defaultLookup.findVirtual(String.class, "replaceAll",
+ MethodType.methodType(String.class, String.class, String.class));
+ assertNotNull(handle);
+
+ assertEquals(String.class, handle.type().returnType());
+ // Note that the input type was (String,String)String but the handle's type is
+ // (String, String, String)String - since it's a non static call, we prepend the
+ // receiver to the type.
+ assertEquals(3, handle.type().parameterCount());
+ MethodType expectedType = MethodType.methodType(String.class,
+ new Class<?>[] { String.class, String.class, String.class});
+
+ assertEquals(expectedType, handle.type());
+ assertEquals(MethodHandle.INVOKE_VIRTUAL, handle.getHandleKind());
+
+ MethodHandles.Lookup inUtil = defaultLookup.in(Vector.class);
+
+ // Package private in a public class in a different package from the lookup.
+ try {
+ inUtil.findVirtual(MethodHandlesTest.class, "packagePrivateMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Protected in a public class in a different package from the lookup.
+ try {
+ inUtil.findVirtual(MethodHandlesTest.class, "protectedMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Protected in a public class in a different package from the lookup.
+ try {
+ inUtil.findVirtual(MethodHandlesTest.class, "privateMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Public method in a package private class in a different package from the lookup.
+ try {
+ inUtil.findVirtual(PackageSibling.class, "publicMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+
+ // Public static method should not discoverable via findVirtual.
+ try {
+ inUtil.findVirtual(MethodHandlesTest.class, "publicStaticMethod",
+ MethodType.methodType(void.class));
+ fail();
+ } catch (IllegalAccessException expected) {
+ }
+ }
+
+ public static class Inner1 {
+ public static MethodHandles.Lookup lookup = MethodHandles.lookup();
+ }
+
+ public static class Inner2 {
+ }
+
+ private static void privateStaticMethod() {}
+ public static void publicStaticMethod() {}
+ static void packagePrivateStaticMethod() {}
+ protected static void protectedStaticMethod() {}
+
+ public void publicMethod() {}
+ private void privateMethod() {}
+ void packagePrivateMethod() {}
+ protected void protectedMethod() {}
+
+ public static class ConstructorTest {
+ ConstructorTest(String unused, int unused2) {}
+ protected ConstructorTest(String unused) {}
+ private ConstructorTest(String unused, char unused2) {}
+ }
+}
+
+class PackageSibling {
+ public void publicMethod() {}
+ public static void publicStaticMethod() {}
+
+ protected PackageSibling(String unused) {}
+ public PackageSibling(String unused, char unused2) {}
+}
+
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java b/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
index 3093bbd..8d7ed71 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/ConstructorTest.java
@@ -17,6 +17,8 @@
package libcore.java.lang.reflect;
import java.lang.reflect.Constructor;
+import java.lang.reflect.Parameter;
+
import junit.framework.TestCase;
public final class ConstructorTest extends TestCase {
@@ -33,8 +35,12 @@
}
public void test_getParameterTypes() throws Exception {
- Class[] expectedParameters = new Class[] { Object.class };
+ Class[] expectedParameters = new Class[0];
Constructor<?> constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
+ assertEquals(0, constructor.getParameterTypes().length);
+
+ expectedParameters = new Class[] { Object.class };
+ constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
Class[] parameters = constructor.getParameterTypes();
assertEquals(1, parameters.length);
assertEquals(expectedParameters[0], parameters[0]);
@@ -46,12 +52,37 @@
}
public void test_getParameterCount() throws Exception {
- Class[] expectedParameters = new Class[] { Object.class };
+ Class[] expectedParameters = new Class[0];
Constructor<?> constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
+ assertEquals(0, constructor.getParameterCount());
+
+ expectedParameters = new Class[] { Object.class };
+ constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
int count = constructor.getParameterCount();
assertEquals(1, count);
}
+ public void test_getParameters() throws Exception {
+ Class[] expectedParameters = new Class[0];
+ Constructor<?> constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
+ assertEquals(0, constructor.getParameters().length);
+
+ expectedParameters = new Class[] { Object.class };
+ constructor = ConstructorTestHelper.class.getConstructor(expectedParameters);
+
+ // Test the information available via other Constructor methods. See ParameterTest and
+ // annotations.ParameterTest for more in-depth Parameter testing.
+ Parameter[] parameters = constructor.getParameters();
+ assertEquals(1, parameters.length);
+ assertEquals(Object.class, parameters[0].getType());
+
+ // Check that corrupting our array doesn't affect other callers.
+ parameters[0] = null;
+ parameters = constructor.getParameters();
+ assertEquals(1, parameters.length);
+ assertEquals(Object.class, parameters[0].getType());
+ }
+
public void testGetConstructorWithNullArgumentsArray() throws Exception {
Constructor<?> constructor = ConstructorTestHelper.class.getConstructor((Class[]) null);
assertEquals(0, constructor.getParameterTypes().length);
diff --git a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
index 5cb88d6..315a885 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/MethodTest.java
@@ -19,6 +19,7 @@
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Comparator;
@@ -41,8 +42,12 @@
}
public void test_getParameterTypes() throws Exception {
- Class[] expectedParameters = new Class[] { Object.class };
- Method method = MethodTestHelper.class.getMethod("m2", expectedParameters);
+ Class[] expectedParameters = new Class[0];
+ Method method = MethodTestHelper.class.getMethod("m1", expectedParameters);
+ assertEquals(0, method.getParameterTypes().length);
+
+ expectedParameters = new Class[] { Object.class };
+ method = MethodTestHelper.class.getMethod("m2", expectedParameters);
Class[] parameters = method.getParameterTypes();
assertEquals(1, parameters.length);
assertEquals(expectedParameters[0], parameters[0]);
@@ -54,12 +59,37 @@
}
public void test_getParameterCount() throws Exception {
- Class[] expectedParameters = new Class[] { Object.class };
- Method method = MethodTestHelper.class.getMethod("m2", expectedParameters);
+ Class[] expectedParameters = new Class[0];
+ Method method = MethodTestHelper.class.getMethod("m1", expectedParameters);
+ assertEquals(0, method.getParameterCount());
+
+ expectedParameters = new Class[] { Object.class };
+ method = MethodTestHelper.class.getMethod("m2", expectedParameters);
int count = method.getParameterCount();
assertEquals(1, count);
}
+ public void test_getParameters() throws Exception {
+ Class[] expectedParameters = new Class[0];
+ Method method = MethodTestHelper.class.getMethod("m1", expectedParameters);
+ assertEquals(0, method.getParameters().length);
+
+ expectedParameters = new Class[] { Object.class };
+ method = MethodTestHelper.class.getMethod("m2", expectedParameters);
+
+ // Test the information available via other Method methods. See ParameterTest and
+ // annotations.ParameterTest for more in-depth Parameter testing.
+ Parameter[] parameters = method.getParameters();
+ assertEquals(1, parameters.length);
+ assertEquals(Object.class, parameters[0].getType());
+
+ // Check that corrupting our array doesn't affect other callers.
+ parameters[0] = null;
+ parameters = method.getParameters();
+ assertEquals(1, parameters.length);
+ assertEquals(Object.class, parameters[0].getType());
+ }
+
public void testGetMethodWithPrivateMethodAndInterfaceMethod() throws Exception {
assertEquals(InterfaceA.class, Sub.class.getMethod("a").getDeclaringClass());
}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/ParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/ParameterTest.java
new file mode 100644
index 0000000..1a45497
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/ParameterTest.java
@@ -0,0 +1,1146 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.lang.reflect;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.MalformedParametersException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
+import java.text.NumberFormat;
+import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+import libcore.io.Streams;
+
+import dalvik.system.PathClassLoader;
+
+/**
+ * Tests for {@link Parameter}. For annotation-related tests see
+ * {@link libcore.java.lang.reflect.annotations.AnnotatedElementParameterTest} and
+ * {@link libcore.java.lang.reflect.annotations.ExecutableParameterTest}.
+ *
+ * <p>Tests suffixed with _withMetadata() require parameter metadata compiled in to work properly.
+ * These are handled by loading pre-compiled .dex files.
+ * See also {@link DependsOnParameterMetadata}.
+ */
+public class ParameterTest extends TestCase {
+
+ /**
+ * A ClassLoader that can be used to load the
+ * libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses class and its nested
+ * classes. The loaded classes has valid metadata that could be created by a valid Android
+ * compiler.
+ */
+ private ClassLoader classesWithMetadataClassLoader;
+
+ /**
+ * A ClassLoader that can be used to load the
+ * libcore.java.lang.reflect.parameter.MetadataVariations class.
+ * The loaded class has invalid metadata that could not be created by a valid Android
+ * compiler.
+ */
+ private ClassLoader metadataVariationsClassLoader;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ File dexDir = File.createTempFile("dexDir", "");
+ assertTrue(dexDir.delete());
+ assertTrue(dexDir.mkdirs());
+
+ classesWithMetadataClassLoader =
+ createClassLoaderForDexResource(dexDir, "parameter_metadata_test_classes.dex");
+ metadataVariationsClassLoader =
+ createClassLoaderForDexResource(dexDir, "metadata_variations.dex");
+ }
+
+ /**
+ * A source annotation used to mark code below with behavior that is highly dependent on
+ * parameter metadata. It is intended to bring readers here for the following:
+ *
+ * <p>Unless the compiler supports (and is configured to enable) storage of metadata
+ * for parameters, the runtime does not have access to the parameter name from the source and
+ * some modifier information like "implicit" (AKA "mandated"), "synthetic" and "final".
+ *
+ * <p>This test class is expected to be compiled <em>without</em> requesting that the metadata
+ * be compiled in. dex files that contains classes with metadata are loaded in setUp() and
+ * used from the tests suffixed with "_withMetadata".
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target(ElementType.METHOD)
+ private @interface DependsOnParameterMetadata {}
+
+ private static class SingleParameter {
+ @SuppressWarnings("unused")
+ SingleParameter(String p0) {}
+
+ @SuppressWarnings("unused")
+ void oneParameter(String p0) {}
+ }
+
+ public void testSingleParameterConstructor() throws Exception {
+ Constructor<?> constructor = SingleParameter.class.getDeclaredConstructor(String.class);
+ checkSingleStringParameter(constructor);
+ }
+
+ public void testSingleParameterMethod() throws Exception {
+ Method method = SingleParameter.class.getDeclaredMethod("oneParameter", String.class);
+ checkSingleStringParameter(method);
+ }
+
+ private static void checkSingleStringParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ public void testSingleParameterConstructor_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("SingleParameter");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
+ checkSingleStringParameter_withMetadata(constructor);
+ }
+
+ public void testSingleParameterMethod_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("SingleParameter");
+ Method method = clazz.getDeclaredMethod("oneParameter", String.class);
+ checkSingleStringParameter_withMetadata(method);
+ }
+
+ private static void checkSingleStringParameter_withMetadata(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String p0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkName(true /* expectedNameIsPresent */, "p0")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ private static class GenericParameter {
+ @SuppressWarnings("unused")
+ GenericParameter(Function<String, Integer> p0) {}
+
+ @SuppressWarnings("unused")
+ void genericParameter(Function<String, Integer> p0) {}
+ }
+
+ public void testGenericParameterConstructor() throws Exception {
+ Constructor<?> constructor = GenericParameter.class.getDeclaredConstructor(Function.class);
+ checkGenericParameter(constructor);
+ }
+
+ public void testGenericParameterMethod() throws Exception {
+ Method method = GenericParameter.class.getDeclaredMethod(
+ "genericParameter", Function.class);
+ checkGenericParameter(method);
+ }
+
+ private static void checkGenericParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString(
+ "[java.util.function.Function<java.lang.String, java.lang.Integer> arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(Function.class)
+ .checkGetParameterizedType(
+ "java.util.function.Function<java.lang.String, java.lang.Integer>");
+ }
+
+ public void testGenericParameterConstructor_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("GenericParameter");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(Function.class);
+ checkGenericParameter_withMetadata(constructor);
+ }
+
+ public void testGenericParameterMethod_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("GenericParameter");
+ Method method = clazz.getDeclaredMethod("genericParameter", Function.class);
+ checkGenericParameter_withMetadata(method);
+ }
+
+ private static void checkGenericParameter_withMetadata(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString(
+ "[java.util.function.Function<java.lang.String, java.lang.Integer> p0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(Function.class)
+ .checkName(true /* expectedNameIsPresent */, "p0")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetParameterizedType(
+ "java.util.function.Function<java.lang.String, java.lang.Integer>");
+ }
+
+ private static class TwoParameters {
+ @SuppressWarnings("unused")
+ TwoParameters(String p0, Integer p1) {}
+ @SuppressWarnings("unused")
+ void twoParameters(String p0, Integer p1) {}
+ }
+
+ public void testTwoParameterConstructor() throws Exception {
+ Constructor<?> constructor =
+ TwoParameters.class.getDeclaredConstructor(String.class, Integer.class);
+ checkTwoParameters(constructor);
+ }
+
+ public void testTwoParameterMethod() throws Exception {
+ Method method = TwoParameters.class.getDeclaredMethod(
+ "twoParameters", String.class, Integer.class);
+ checkTwoParameters(method);
+ }
+
+ private static void checkTwoParameters(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String arg0, java.lang.Integer arg1]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(Integer.class)
+ .checkGetParameterizedType("class java.lang.Integer");
+ }
+
+ public void testTwoParameterConstructor_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("TwoParameters");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
+ checkTwoParameters_withMetadata(constructor);
+ }
+
+ public void testTwoParameterMethod_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("TwoParameters");
+ Method method = clazz.getDeclaredMethod("twoParameters", String.class, Integer.class);
+ checkTwoParameters_withMetadata(method);
+ }
+
+ private static void checkTwoParameters_withMetadata(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String p0, java.lang.Integer p1]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkName(true /* expectedNameIsPresent */, "p0")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetParameterizedType("class java.lang.String");
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(Integer.class)
+ .checkName(true /* expectedNameIsPresent */, "p1")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetParameterizedType("class java.lang.Integer");
+ }
+
+ private static class FinalParameter {
+ @SuppressWarnings("unused")
+ FinalParameter(final String p0) {}
+ @SuppressWarnings("unused")
+ void finalParameter(final String p0) {}
+ }
+
+ public void testFinalParameterConstructor() throws Exception {
+ Constructor<?> constructor = FinalParameter.class.getDeclaredConstructor(String.class);
+ checkFinalParameter(constructor);
+ }
+
+ public void testFinalParameterMethod() throws Exception {
+ Method method = FinalParameter.class.getDeclaredMethod("finalParameter", String.class);
+ checkFinalParameter(method);
+ }
+
+ private static void checkFinalParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ public void testFinalParameterConstructor_withMetdata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("FinalParameter");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
+ checkFinalParameter_withMetadata(constructor);
+ }
+
+ public void testFinalParameterMethod_withMetdata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("FinalParameter");
+ Method method = clazz.getDeclaredMethod("finalParameter", String.class);
+ checkFinalParameter_withMetadata(method);
+ }
+
+ private static void checkFinalParameter_withMetadata(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[final java.lang.String p0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkName(true /* expectedNameIsPresent */, "p0")
+ .checkModifiers(Modifier.FINAL)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ /**
+ * An inner class, used for checking compiler-inserted parameters: The first parameter is an
+ * instance of the surrounding class.
+ */
+ private class InnerClass {
+ @SuppressWarnings("unused")
+ public InnerClass() {}
+ @SuppressWarnings("unused")
+ public InnerClass(String p1) {}
+ @SuppressWarnings("unused")
+ public InnerClass(Function<String, Integer> p1) {}
+ }
+
+ public void testInnerClassSingleParameter() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = InnerClass.class;
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[" + outerClass.getName() + " arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ public void testInnerClassSingleParameter_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[final " + outerClass.getName() + " this$0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkName(true /* expectedNameIsPresent */, "this$0")
+ .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetParameterizedType("class " + outerClass.getName());
+ }
+
+ public void testInnerClassTwoParameters() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = InnerClass.class;
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, String.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString(
+ "[" + outerClass.getName() + " arg0, java.lang.String arg1]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName());
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ public void testInnerClassTwoParameters_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, String.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString(
+ "[final " + outerClass.getName() + " this$0, java.lang.String p1]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "this$0")
+ .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+
+ helper.getParameterTestHelper(1)
+ .checkName(true /* expectedNameIsPresent */, "p1")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ public void testInnerClassGenericParameter() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = InnerClass.class;
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, Function.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString(
+ "[" + outerClass.getName() + " arg0, java.util.function.Function arg1]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(Function.class)
+ .checkGetParameterizedType("interface java.util.function.Function");
+
+ // The non-genericised string above is probably the result of a spec bug due to a mismatch
+ // between the generic signature for the constructor (which suggests a single parameter)
+ // and the actual parameters (which suggests two). In the absence of parameter metadata
+ // to identify the synthetic parameter the code reverts to using non-Signature (type erased)
+ // information.
+ }
+
+ public void testInnerClassGenericParameter_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Class<?> innerClass = loadTestInnerClassWithMetadata("InnerClass");
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass, Function.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[final " + outerClass.getName() + " this$0, "
+ + "java.util.function.Function<java.lang.String, java.lang.Integer> p1]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "this$0")
+ .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+
+ helper.getParameterTestHelper(1)
+ .checkName(true /* expectedNameIsPresent */, "p1")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetType(Function.class)
+ .checkGetParameterizedType(
+ "java.util.function.Function<java.lang.String, java.lang.Integer>");
+ }
+
+ @SuppressWarnings("unused")
+ enum TestEnum { ONE, TWO }
+
+ /**
+ * Enums are a documented example of a type of class with synthetic constructor parameters and
+ * generated methods. This test may be brittle as it may rely on the compiler's implementation
+ * of enums.
+ */
+ public void testEnumConstructor() throws Exception {
+ Constructor<?> constructor = TestEnum.class.getDeclaredConstructor(String.class, int.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String arg0, int arg1]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(int.class)
+ .checkGetParameterizedType("int");
+ }
+
+ public void testEnumConstructor_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("TestEnum");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ // The extra spaces below are the result of a trivial upstream bug in
+ // Parameter.toString() due to Modifier.toString(int) outputting nothing for
+ // "SYNTHETIC".
+ .checkParametersToString("[ java.lang.String $enum$name, int $enum$ordinal]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "$enum$name")
+ .checkModifiers(4096) // 4096 == Modifier.SYNTHETIC
+ .checkImplicitAndSynthetic(false, true)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+
+ helper.getParameterTestHelper(1)
+ .checkName(true /* expectedNameIsPresent */, "$enum$ordinal")
+ .checkModifiers(4096) // 4096 == Modifier.SYNTHETIC
+ .checkImplicitAndSynthetic(false, true)
+ .checkGetType(int.class)
+ .checkGetParameterizedType("int");
+ }
+
+ public void testEnumValueOf() throws Exception {
+ Method method = TestEnum.class.getDeclaredMethod("valueOf", String.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(method);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ public void testEnumValueOf_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("TestEnum");
+ Method method = clazz.getDeclaredMethod("valueOf", String.class);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(method);
+ helper.checkStandardParametersBehavior()
+ // The extra space below are the result of a trivial upstream bug in
+ // Parameter.toString() due to Modifier.toString(int) outputting nothing for
+ // "MANDATED".
+ .checkParametersToString("[ java.lang.String name]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "name")
+ .checkModifiers(32768) // 32768 == Modifier.MANDATED
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetType(String.class)
+ .checkGetParameterizedType("class java.lang.String");
+ }
+
+ private static class SingleVarArgs {
+ @SuppressWarnings("unused")
+ SingleVarArgs(String... p0) {}
+
+ @SuppressWarnings("unused")
+ void varArgs(String... p0) {}
+ }
+
+ public void testSingleVarArgsConstructor() throws Exception {
+ Constructor<?> constructor = SingleVarArgs.class.getDeclaredConstructor(String[].class);
+ checkSingleVarArgsParameter(constructor);
+ }
+
+ public void testSingleVarArgsMethod() throws Exception {
+ Method method = SingleVarArgs.class.getDeclaredMethod("varArgs", String[].class);
+ checkSingleVarArgsParameter(method);
+ }
+
+ private static void checkSingleVarArgsParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String... arg0]")
+ .checkParametersMetadataNotAvailable();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(String[].class)
+ .checkIsVarArg(true)
+ .checkGetParameterizedType("class [Ljava.lang.String;");
+ }
+
+ public void testSingleVarArgsConstructor_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("SingleVarArgs");
+ Constructor<?> constructor = clazz.getDeclaredConstructor(String[].class);
+ checkSingleVarArgsParameter_withMetadata(constructor);
+ }
+
+ public void testSingleVarArgsMethod_withMetadata() throws Exception {
+ Class<?> clazz = loadTestInnerClassWithMetadata("SingleVarArgs");
+ Method method = clazz.getDeclaredMethod("varArgs", String[].class);
+ checkSingleVarArgsParameter_withMetadata(method);
+ }
+
+ private static void checkSingleVarArgsParameter_withMetadata(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.String... p0]");
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "p0")
+ .checkModifiers(0)
+ .checkImplicitAndSynthetic(false, false)
+ .checkGetType(String[].class)
+ .checkIsVarArg(true)
+ .checkGetParameterizedType("class [Ljava.lang.String;");
+ }
+
+ private static class MixedVarArgs {
+ @SuppressWarnings("unused")
+ MixedVarArgs(Integer[] p0, String... p1) {}
+ @SuppressWarnings("unused")
+ void both(Integer[] p0, String... p1) {}
+ }
+
+ public void testMixedVarArgsConstructor() throws Exception {
+ Constructor<?> constructor =
+ MixedVarArgs.class.getDeclaredConstructor(Integer[].class, String[].class);
+ checkMixedVarArgsParameter(constructor);
+ }
+
+ public void testMixedVarArgsMethod() throws Exception {
+ Method method = MixedVarArgs.class.getDeclaredMethod("both", Integer[].class, String[].class);
+ checkMixedVarArgsParameter(method);
+ }
+
+ private static void checkMixedVarArgsParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.Integer[] arg0, java.lang.String... arg1]")
+ .checkParametersMetadataNotAvailable();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(Integer[].class)
+ .checkIsVarArg(false)
+ .checkGetParameterizedType("class [Ljava.lang.Integer;");
+
+ helper.getParameterTestHelper(1)
+ .checkGetType(String[].class)
+ .checkIsVarArg(true)
+ .checkGetParameterizedType("class [Ljava.lang.String;");
+ }
+
+ private static class NonVarArgs {
+ @SuppressWarnings("unused")
+ NonVarArgs(Integer[] p0) {}
+ @SuppressWarnings("unused")
+ void notVarArgs(Integer[] p0) {}
+ }
+
+ public void testNonVarsArgsConstructor() throws Exception {
+ Constructor<?> constructor = NonVarArgs.class.getDeclaredConstructor(Integer[].class);
+ checkNonVarsArgsParameter(constructor);
+ }
+
+ public void testNonVarsArgsMethod() throws Exception {
+ Method method = NonVarArgs.class.getDeclaredMethod("notVarArgs", Integer[].class);
+ checkNonVarsArgsParameter(method);
+ }
+
+ private static void checkNonVarsArgsParameter(Executable executable) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(executable);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[java.lang.Integer[] arg0]")
+ .checkParametersMetadataNotAvailable();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(Integer[].class)
+ .checkIsVarArg(false)
+ .checkGetParameterizedType("class [Ljava.lang.Integer;");
+ }
+
+ public void testAnonymousClassConstructor() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = getAnonymousClassWith1ParameterConstructor();
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[" + outerClass.getName() + " arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ private Class<?> getAnonymousClassWith1ParameterConstructor() {
+ // Deliberately not implemented with a lambda. Do not refactor.
+ Callable<String> anonymousClassObject = new Callable<String>() {
+ @Override
+ public String call() throws Exception {
+ return ParameterTest.this.outerClassMethod();
+ }
+ };
+ return anonymousClassObject.getClass();
+ }
+
+ public void testAnonymousClassConstructor_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Object outer = outerClass.newInstance();
+ Class<?> innerClass = (Class<?>) outerClass.getDeclaredMethod(
+ "getAnonymousClassWith1ParameterConstructor").invoke(outer);
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[final " + outerClass.getName() + " this$0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "this$0")
+ .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ public void testMethodClassConstructor() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = getMethodClassWith1ImplicitParameterConstructor();
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[" + outerClass.getName() + " arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ private Class<?> getMethodClassWith1ImplicitParameterConstructor() {
+ class MethodClass {
+ MethodClass() {
+ ParameterTest.this.outerClassMethod();
+ }
+ }
+ return MethodClass.class;
+ }
+
+ public void testMethodClassConstructor_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Object outer = outerClass.newInstance();
+ Class<?> innerClass = (Class<?>) outerClass.getDeclaredMethod(
+ "getMethodClassWith1ImplicitParameterConstructor").invoke(outer);
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[final " + outerClass.getName() + " this$0]")
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkName(true /* expectedNameIsPresent */, "this$0")
+ .checkModifiers(32784) // 32784 == Modifier.MANDATED & Modifier.FINAL
+ .checkImplicitAndSynthetic(true, false)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ public void testLambdaClassConstructor() throws Exception {
+ Class<?> outerClass = ParameterTest.class;
+ Class<?> innerClass = getLambdaClassWith1ParameterConstructor();
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ checkLambdaClassConstructor(outerClass, constructor);
+ }
+
+ private Class<?> getLambdaClassWith1ParameterConstructor() {
+ return ((Callable<?>) ParameterTest.this::outerClassMethod).getClass();
+ }
+
+ public void testLambdaClassConstructor_withMetadata() throws Exception {
+ Class<?> outerClass = loadTestOuterClassWithMetadata();
+ Object outer = outerClass.newInstance();
+ Class<?> innerClass = (Class<?>) outerClass.getDeclaredMethod(
+ "getLambdaClassWith1ParameterConstructor").invoke(outer);
+ Constructor<?> constructor = innerClass.getDeclaredConstructor(outerClass);
+
+ // There should be no parameter metadata for lambda classes.
+ checkLambdaClassConstructor(outerClass, constructor);
+ }
+
+ // This behavior is likely to be quite brittle and may not be specified.
+ private void checkLambdaClassConstructor(Class<?> outerClass, Constructor<?> constructor) {
+ ExecutableTestHelper helper = new ExecutableTestHelper(constructor);
+ helper.checkStandardParametersBehavior()
+ .checkParametersToString("[" + outerClass.getName() + " arg0]")
+ .checkParametersMetadataNotAvailable()
+ .checkParametersNoVarArgs();
+
+ helper.getParameterTestHelper(0)
+ .checkGetType(outerClass)
+ .checkGetParameterizedType("class " + outerClass.getName() + "");
+ }
+
+ private static class NonIdenticalParameters {
+ @SuppressWarnings("unused")
+ void method0(String p0) {}
+ @SuppressWarnings("unused")
+ void method1(String p0) {}
+ }
+
+ public void testEquals_checksExecutable() throws Exception {
+ Method method0 = NonIdenticalParameters.class.getDeclaredMethod("method0", String.class);
+ Method method1 = NonIdenticalParameters.class.getDeclaredMethod("method1", String.class);
+ Parameter method0P0 = method0.getParameters()[0];
+ Parameter method1P0 = method1.getParameters()[0];
+ assertFalse(method0P0.equals(method1P0));
+ assertFalse(method1P0.equals(method0P0));
+ assertTrue(method0P0.equals(method0P0));
+ }
+
+ public void testManyParameters_withMetadata() throws Exception {
+ int expectedParameterCount = 300;
+ Class<?>[] parameterTypes = new Class[expectedParameterCount];
+ Arrays.fill(parameterTypes, int.class);
+ Method method = getMetadataVariationsMethod("manyParameters", parameterTypes);
+ Parameter[] parameters = method.getParameters();
+ assertEquals(expectedParameterCount, parameters.length);
+
+ NumberFormat format = NumberFormat.getIntegerInstance();
+ format.setMinimumIntegerDigits(3);
+ for (int i = 0; i < parameters.length; i++) {
+ assertEquals(true, parameters[i].isNamePresent());
+ assertEquals(Modifier.FINAL, parameters[i].getModifiers());
+ assertEquals("a" + format.format(i), parameters[i].getName());
+ }
+ }
+
+ public void testEmptyMethodParametersAnnotation_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("emptyMethodParametersAnnotation");
+ assertEquals(0, method.getParameters().length);
+ }
+
+ public void testTooManyAccessFlags_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("tooManyAccessFlags", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testTooFewAccessFlags_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod(
+ "tooFewAccessFlags", String.class, String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testTooManyNames_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("tooManyNames", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testTooFewNames_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("tooFewNames", String.class, String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testTooManyBoth_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("tooManyBoth", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testTooFewBoth_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("tooFewBoth", String.class, String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testNullName_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("nullName", String.class);
+ Parameter parameter0 = method.getParameters()[0];
+ assertEquals("arg0", parameter0.getName());
+ assertEquals(Modifier.FINAL, parameter0.getModifiers());
+ }
+
+ public void testEmptyName_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("emptyName", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testNameWithSemicolon_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("nameWithSemicolon", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testNameWithSlash_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("nameWithSlash", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testNameWithPeriod_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("nameWithPeriod", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testNameWithOpenSquareBracket_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("nameWithOpenSquareBracket", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testBadAccessModifier_withMetadata() throws Exception {
+ Method method = getMetadataVariationsMethod("badAccessModifier", String.class);
+ checkGetParametersThrowsMalformedParametersException(method);
+ }
+
+ public void testBadlyFormedAnnotation() throws Exception {
+ Method method = getMetadataVariationsMethod("badlyFormedAnnotation", String.class);
+ // Badly formed annotations are treated as if the annotation is entirely absent.
+ Parameter parameter0 = method.getParameters()[0];
+ assertFalse(parameter0.isNamePresent());
+ }
+
+ /** A non-static method that exists to be called by inner classes, lambdas, etc. */
+ private String outerClassMethod() {
+ return "Howdy";
+ }
+
+ private static class ExecutableTestHelper {
+ private final Executable executable;
+
+ ExecutableTestHelper(Executable executable) {
+ this.executable = executable;
+ }
+
+ @DependsOnParameterMetadata
+ ExecutableTestHelper checkParametersToString(String expectedString) {
+ assertEquals(expectedString, Arrays.toString(executable.getParameters()));
+ return this;
+ }
+
+ /**
+ * Combines checks that should be true of any result from
+ * {@link Executable#getParameters()}
+ */
+ ExecutableTestHelper checkStandardParametersBehavior() {
+ return checkGetParametersClonesArray()
+ .checkParametersGetDeclaringExecutable()
+ .checkParametersEquals()
+ .checkParametersHashcode();
+ }
+
+ ExecutableTestHelper checkParametersGetDeclaringExecutable() {
+ for (Parameter p : executable.getParameters()) {
+ assertSame(executable, p.getDeclaringExecutable());
+ }
+ return this;
+ }
+
+ ExecutableTestHelper checkGetParametersClonesArray() {
+ Parameter[] parameters1 = executable.getParameters();
+ Parameter[] parameters2 = executable.getParameters();
+ assertNotSame(parameters1, parameters2);
+
+ assertEquals(parameters1.length, parameters2.length);
+ for (int i = 0; i < parameters1.length; i++) {
+ assertSame(parameters1[i], parameters2[i]);
+ }
+ return this;
+ }
+
+ ExecutableTestHelper checkParametersEquals() {
+ Parameter[] parameters = executable.getParameters();
+ for (int i = 0; i < parameters.length; i++) {
+ assertEquals(parameters[i], parameters[i]);
+ if (i > 0) {
+ assertFalse(parameters[0].equals(parameters[i]));
+ assertFalse(parameters[i].equals(parameters[0]));
+ }
+ }
+ return this;
+ }
+
+ ExecutableTestHelper checkParametersHashcode() {
+ for (Parameter parameter : executable.getParameters()) {
+ // Not much to assert. Just call the method and check it is consistent.
+ assertEquals(parameter.hashCode(), parameter.hashCode());
+ }
+ return this;
+ }
+
+ @DependsOnParameterMetadata
+ ExecutableTestHelper checkParametersMetadataNotAvailable() {
+ ParameterTestHelper[] parameterTestHelpers = getParameterTestHelpers();
+ for (int i = 0; i < parameterTestHelpers.length; i++) {
+ ParameterTestHelper parameterTestHelper = parameterTestHelpers[i];
+ parameterTestHelper.checkName(false, "arg" + i)
+ .checkImplicitAndSynthetic(false, false)
+ .checkModifiers(0);
+ }
+ return this;
+ }
+
+ /**
+ * Checks that non of the parameters return {@code true} for {@link Parameter#isVarArgs()}.
+ */
+ ExecutableTestHelper checkParametersNoVarArgs() {
+ for (ParameterTestHelper parameterTestHelper : getParameterTestHelpers()) {
+ parameterTestHelper.checkIsVarArg(false);
+ }
+ return this;
+ }
+
+ ParameterTestHelper getParameterTestHelper(int index) {
+ return new ParameterTestHelper(executable.getParameters()[index]);
+ }
+
+ private ParameterTestHelper[] getParameterTestHelpers() {
+ final int parameterCount = executable.getParameterCount();
+ ParameterTestHelper[] parameterTestHelpers = new ParameterTestHelper[parameterCount];
+ for (int i = 0; i < parameterCount; i++) {
+ parameterTestHelpers[i] = getParameterTestHelper(i);
+ }
+ return parameterTestHelpers;
+ }
+
+ private static class ParameterTestHelper {
+ private final Parameter parameter;
+
+ ParameterTestHelper(Parameter parameter) {
+ this.parameter = parameter;
+ }
+
+ ParameterTestHelper checkGetType(Class<?> expectedType) {
+ assertEquals(expectedType, parameter.getType());
+ return this;
+ }
+
+ @DependsOnParameterMetadata
+ ParameterTestHelper checkName(boolean expectedIsNamePresent, String expectedName) {
+ assertEquals(expectedIsNamePresent, parameter.isNamePresent());
+ assertEquals(expectedName, parameter.getName());
+ return this;
+ }
+
+ @DependsOnParameterMetadata
+ ParameterTestHelper checkModifiers(int expectedModifiers) {
+ assertEquals(expectedModifiers, parameter.getModifiers());
+ return this;
+ }
+
+ ParameterTestHelper checkGetParameterizedType(String expectedParameterizedTypeString) {
+ assertEquals(
+ expectedParameterizedTypeString,
+ parameter.getParameterizedType().toString());
+ return this;
+ }
+
+ @DependsOnParameterMetadata
+ ParameterTestHelper checkImplicitAndSynthetic(
+ boolean expectedIsImplicit, boolean expectedIsSynthetic) {
+ assertEquals(expectedIsImplicit, parameter.isImplicit());
+ assertEquals(expectedIsSynthetic, parameter.isSynthetic());
+ return this;
+ }
+
+ ParameterTestHelper checkIsVarArg(boolean expectedIsVarArg) {
+ assertEquals(expectedIsVarArg, parameter.isVarArgs());
+ return this;
+ }
+ }
+ }
+
+ private static ClassLoader createClassLoaderForDexResource(File dexDir, String resourceName)
+ throws Exception {
+ File dexFile = new File(dexDir, resourceName);
+ copyResource(resourceName, dexFile);
+ return new PathClassLoader(dexFile.getAbsolutePath(), ClassLoader.getSystemClassLoader());
+ }
+
+ /**
+ * Copy a resource in the libcore/java/lang/reflect/parameter/ resource path to the indicated
+ * target file.
+ */
+ private static void copyResource(String resourceName, File destination) throws Exception {
+ assertFalse(destination.exists());
+ ClassLoader classLoader = ParameterTest.class.getClassLoader();
+ assertNotNull(classLoader);
+
+ final String RESOURCE_PATH = "libcore/java/lang/reflect/parameter/";
+ String fullResourcePath = RESOURCE_PATH + resourceName;
+ try (InputStream in = classLoader.getResourceAsStream(fullResourcePath);
+ FileOutputStream out = new FileOutputStream(destination)) {
+ if (in == null) {
+ throw new IllegalStateException("Resource not found: " + fullResourcePath);
+ }
+ Streams.copy(in, out);
+ }
+ }
+
+ /**
+ * Loads an inner class from the ParameterMetadataTestClasses class defined in a separate dex
+ * file. See src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
+ */
+ private Class<?> loadTestInnerClassWithMetadata(String name) throws Exception {
+ return classesWithMetadataClassLoader.loadClass(
+ "libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses$" + name);
+ }
+
+ /**
+ * Loads the ParameterMetadataTestClasses class defined in a separate dex file.
+ * See src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
+ */
+ private Class<?> loadTestOuterClassWithMetadata() throws Exception {
+ return classesWithMetadataClassLoader.loadClass(
+ "libcore.java.lang.reflect.parameter.ParameterMetadataTestClasses");
+ }
+
+ /**
+ * Loads a method from the MetadataVariations class defined in a separate dex file. See
+ * src/test/java/libcore/java/lang/reflect/parameter/ for the associated source code.
+ */
+ private Method getMetadataVariationsMethod(String methodName, Class<?>... parameterTypes)
+ throws Exception {
+ Class<?> metadataVariationsClass = metadataVariationsClassLoader.loadClass(
+ "libcore.java.lang.reflect.parameter.MetadataVariations");
+ return metadataVariationsClass.getDeclaredMethod(methodName, parameterTypes);
+ }
+
+ private static void checkGetParametersThrowsMalformedParametersException(Method method) {
+ try {
+ method.getParameters();
+ fail();
+ } catch (MalformedParametersException expected) {}
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
new file mode 100644
index 0000000..aa14bd3
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementParameterTest.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.lang.reflect.annotations;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
+
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertGetDeclaredAnnotation;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertIsAnnotationPresent;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.checkAnnotatedElementPresentMethods;
+
+/**
+ * Tests for the {@link java.lang.reflect.AnnotatedElement} methods from the {@link Parameter}
+ * objects obtained from both {@link Constructor} and {@link Method}.
+ */
+public class AnnotatedElementParameterTest extends TestCase {
+
+ private static class MethodClass {
+ public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {}
+
+ public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1,
+ @AnnotationC @AnnotationD String parameter2) {}
+ }
+
+ public void testMethodParameterAnnotations() throws Exception {
+ Class<?> c = MethodClass.class;
+ {
+ Parameter[] parameters = c.getDeclaredMethod(
+ "methodWithoutAnnotatedParameters", String.class, String.class).getParameters();
+ Parameter parameter0 = parameters[0];
+ checkAnnotatedElementPresentMethods(parameter0);
+
+ Parameter parameter1 = parameters[1];
+ checkAnnotatedElementPresentMethods(parameter1);
+ }
+ {
+ Parameter[] parameters = c.getDeclaredMethod(
+ "methodWithAnnotatedParameters", String.class, String.class).getParameters();
+
+ Parameter parameter0 = parameters[0];
+ checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class);
+
+ Parameter parameter1 = parameters[1];
+ checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class);
+ }
+ }
+
+ private static class ConstructorClass {
+ // No annotations.
+ public ConstructorClass(Integer parameter1, Integer parameter2) {}
+
+ // Annotations.
+ public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
+ @AnnotationC @AnnotationD String parameter2) {}
+ }
+
+ public void testConstructorParameterAnnotations() throws Exception {
+ Class<?> c = ConstructorClass.class;
+ {
+ Parameter[] parameters =
+ c.getDeclaredConstructor(Integer.class, Integer.class).getParameters();
+ Parameter parameter0 = parameters[0];
+ checkAnnotatedElementPresentMethods(parameter0);
+
+ Parameter parameter1 = parameters[1];
+ checkAnnotatedElementPresentMethods(parameter1);
+ }
+ {
+ Parameter[] parameters =
+ c.getDeclaredConstructor(String.class, String.class).getParameters();
+
+ Parameter parameter0 = parameters[0];
+ checkAnnotatedElementPresentMethods(parameter0, AnnotationB.class, AnnotationD.class);
+
+ Parameter parameter1 = parameters[1];
+ checkAnnotatedElementPresentMethods(parameter1, AnnotationC.class, AnnotationD.class);
+ }
+ }
+
+ private static class AnnotatedMethodClass {
+ void noAnnotation(String p0) {}
+
+ void multipleAnnotationOddity(
+ @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {}
+
+ void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {}
+
+ void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {}
+
+ void singleAnnotation(@Repeated(1) String p0) {}
+
+ static Method getMethodWithoutAnnotations() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
+ }
+
+ static Method getMethodMultipleAnnotationOddity() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod(
+ "multipleAnnotationOddity", String.class);
+ }
+
+ static Method getMethodMultipleAnnotationExplicitSingle() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod(
+ "multipleAnnotationExplicitSingle", String.class);
+ }
+
+ static Method getMethodMultipleAnnotation() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class);
+ }
+
+ static Method getMethodSingleAnnotation() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
+ }
+ }
+
+ // Tests for isAnnotationPresent and getDeclaredAnnotation.
+ public void testMethodDeclaredAnnotation() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ container, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ container, null);
+ }
+
+ private static class AnnotatedConstructorClass {
+ public AnnotatedConstructorClass(Boolean p0) {}
+
+ public AnnotatedConstructorClass(
+ @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {}
+
+ public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {}
+
+ public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {}
+
+ public AnnotatedConstructorClass(@Repeated(1) String p0) {}
+
+ static Constructor<?> getConstructorWithoutAnnotations() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotationExplicitSingle()
+ throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class);
+ }
+
+ static Constructor<?> getConstructorSingleAnnotation() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotation() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class);
+ }
+ }
+
+ // Tests for isAnnotationPresent and getDeclaredAnnotation.
+ public void testConstructorDeclaredAnnotation() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ repeated, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ container, null);
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0DeclaredAnnotation(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ container, null);
+ }
+
+ private static void checkParameter0DeclaredAnnotation(
+ Executable executable, Class<? extends Annotation> annotationType,
+ String expectedAnnotationString) throws Exception {
+ Parameter parameter = executable.getParameters()[0];
+
+ // isAnnotationPresent
+ assertIsAnnotationPresent(parameter, annotationType, expectedAnnotationString != null);
+
+ // getDeclaredAnnotation
+ assertGetDeclaredAnnotation(parameter, annotationType, expectedAnnotationString);
+ }
+
+ public void testMethodGetDeclaredAnnotationsByType() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ repeated, EXPECT_EMPTY);
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ repeated, "@Repeated(1)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ repeated, "@Repeated(1)", "@Repeated(2)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ container, EXPECT_EMPTY);
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ container, EXPECT_EMPTY);
+ }
+
+ public void testConstructorGetDeclaredAnnotationsByType() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ repeated, EXPECT_EMPTY);
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ repeated, "@Repeated(1)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ repeated, "@Repeated(1)", "@Repeated(2)");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ container, EXPECT_EMPTY);
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0GetDeclaredAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ container, EXPECT_EMPTY);
+ }
+
+ private static void checkParameter0GetDeclaredAnnotationsByType(
+ Executable executable, Class<? extends Annotation> annotationType,
+ String... expectedAnnotationStrings) throws Exception {
+ Parameter parameter = executable.getParameters()[0];
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter, annotationType, expectedAnnotationStrings);
+ }
+
+ public void testMethodGetAnnotationsByType() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ repeated, EXPECT_EMPTY);
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ repeated, "@Repeated(1)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ repeated, "@Repeated(1)", "@Repeated(2)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(),
+ container, EXPECT_EMPTY);
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ container, EXPECT_EMPTY);
+ }
+
+ public void testConstructorGetAnnotationsByType() throws Exception {
+ Class<? extends Annotation> repeated = Repeated.class;
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ repeated, EXPECT_EMPTY);
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ repeated, "@Repeated(1)", "@Repeated(2)", "@Repeated(3)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ repeated, "@Repeated(1)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ repeated, "@Repeated(1)", "@Repeated(2)");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ repeated, "@Repeated(1)");
+
+ Class<? extends Annotation> container = Container.class;
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ container, EXPECT_EMPTY);
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ container, "@Container({@Repeated(2), @Repeated(3)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ container, "@Container({@Repeated(1)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ container, "@Container({@Repeated(1), @Repeated(2)})");
+ checkParameter0GetAnnotationsByType(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ container, EXPECT_EMPTY);
+ }
+
+ private static void checkParameter0GetAnnotationsByType(
+ Executable executable, Class<? extends Annotation> annotationType,
+ String... expectedAnnotationStrings) throws Exception {
+ Parameter parameter = executable.getParameters()[0];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter, annotationType, expectedAnnotationStrings);
+ }
+
+ /**
+ * As an inner class the constructor will actually have two parameters: the first, referencing
+ * the enclosing object, is inserted by the compiler.
+ */
+ class InnerClass {
+ InnerClass(@Repeated(1) String p1) {}
+ }
+
+ /** Special case testing for a compiler-generated constructor parameter. */
+ public void testImplicitConstructorParameters_singleAnnotation() throws Exception {
+ Constructor<InnerClass> constructor =
+ InnerClass.class.getDeclaredConstructor(
+ AnnotatedElementParameterTest.class, String.class);
+ Parameter[] parameters = constructor.getParameters();
+
+ // The compiler-generated constructor should have no annotations.
+ Parameter parameter0 = parameters[0];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter0, Repeated.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter0, Repeated.class, new String[0]);
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
+ parameter0, Repeated.class, null);
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(parameter0, Repeated.class, false);
+
+ // The annotation should remain on the correct parameter.
+ Parameter parameter1 = parameters[1];
+ AnnotatedElementTestSupport.assertGetAnnotationsByType(
+ parameter1, Repeated.class, new String[] {"@Repeated(1)"});
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotationsByType(
+ parameter1, Repeated.class, new String[] {"@Repeated(1)"});
+ AnnotatedElementTestSupport.assertGetDeclaredAnnotation(
+ parameter1, Repeated.class, "@Repeated(1)");
+ AnnotatedElementTestSupport.assertIsAnnotationPresent(
+ parameter1, Repeated.class, true);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
index ec57469..b17fbff 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/AnnotatedElementTestSupport.java
@@ -95,8 +95,8 @@
* returns annotations of the supplied expected classes.
*
* <p>Where the expected classes contains some subset from
- * {@link AnnotationA}, {@link AnnotationB} and {@link AnnotationC}, this method also asserts
- * that {@link AnnotatedElement#isAnnotationPresent(Class)} and
+ * {@link AnnotationA}, {@link AnnotationB}, {@link AnnotationC}, {@link AnnotationD} this
+ * method also asserts that {@link AnnotatedElement#isAnnotationPresent(Class)} and
* {@link AnnotatedElement#getAnnotation(Class)} works as expected.
*
* <p>This method also confirms that {@link AnnotatedElement#isAnnotationPresent(Class)} and
@@ -112,6 +112,7 @@
assertPresent(expectedTypes.contains(AnnotationA.class), element, AnnotationA.class);
assertPresent(expectedTypes.contains(AnnotationB.class), element, AnnotationB.class);
assertPresent(expectedTypes.contains(AnnotationC.class), element, AnnotationC.class);
+ assertPresent(expectedTypes.contains(AnnotationD.class), element, AnnotationD.class);
try {
element.isAnnotationPresent(null);
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
new file mode 100644
index 0000000..a07f2b3
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/annotations/ExecutableParameterTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.lang.reflect.annotations;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Method;
+
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container;
+import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
+
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch;
+import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set;
+
+/**
+ * Tests for {@link Executable#getParameterAnnotations()} via the {@link Constructor} and
+ * {@link Method} classes. See {@link AnnotatedElementParameterTest} for testing of the
+ * {@link java.lang.reflect.AnnotatedElement} methods.
+ */
+public class ExecutableParameterTest extends TestCase {
+ private static class MethodClass {
+ public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {}
+
+ public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1,
+ @AnnotationC @AnnotationD String parameter2) {}
+ }
+
+ public void testMethodGetParameterAnnotations() throws Exception {
+ Method methodWithoutAnnotatedParameters = MethodClass.class.getMethod(
+ "methodWithoutAnnotatedParameters", String.class, String.class);
+ Annotation[][] noParameterAnnotations =
+ methodWithoutAnnotatedParameters.getParameterAnnotations();
+ assertEquals(2, noParameterAnnotations.length);
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
+
+ Method methodWithAnnotatedParameters = MethodClass.class.getMethod(
+ "methodWithAnnotatedParameters", String.class, String.class);
+ Annotation[][] parameterAnnotations =
+ methodWithAnnotatedParameters.getParameterAnnotations();
+ assertEquals(2, parameterAnnotations.length);
+ assertEquals(set(AnnotationB.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[0]));
+ assertEquals(set(AnnotationC.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[1]));
+ }
+
+ private static class ConstructorClass {
+ // No annotations.
+ public ConstructorClass(Integer parameter1, Integer parameter2) {}
+
+ // Annotations.
+ public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
+ @AnnotationC @AnnotationD String parameter2) {}
+ }
+
+ public void testConstructorGetParameterAnnotations() throws Exception {
+ Constructor constructorWithoutAnnotatedParameters =
+ ConstructorClass.class.getDeclaredConstructor(Integer.class, Integer.class);
+ Annotation[][] noParameterAnnotations =
+ constructorWithoutAnnotatedParameters.getParameterAnnotations();
+ assertEquals(2, noParameterAnnotations.length);
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
+ assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
+
+ Constructor constructorWithAnnotatedParameters =
+ ConstructorClass.class.getDeclaredConstructor(String.class, String.class);
+ Annotation[][] parameterAnnotations =
+ constructorWithAnnotatedParameters.getParameterAnnotations();
+ assertEquals(2, parameterAnnotations.length);
+ assertEquals(set(AnnotationB.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[0]));
+ assertEquals(set(AnnotationC.class, AnnotationD.class),
+ annotationsToTypes(parameterAnnotations[1]));
+ }
+
+ private static class AnnotatedMethodClass {
+ void noAnnotation(String p0) {}
+
+ void multipleAnnotationOddity(
+ @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {}
+
+ void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {}
+
+ void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {}
+
+ void singleAnnotation(@Repeated(1) String p0) {}
+
+ static Method getMethodWithoutAnnotations() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
+ }
+
+ static Method getMethodMultipleAnnotationOddity() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod(
+ "multipleAnnotationOddity", String.class);
+ }
+
+ static Method getMethodMultipleAnnotationExplicitSingle() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod(
+ "multipleAnnotationExplicitSingle", String.class);
+ }
+
+ static Method getMethodMultipleAnnotation() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class);
+ }
+
+ static Method getMethodSingleAnnotation() throws Exception {
+ return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
+ }
+ }
+
+ public void testMethodGetParameterAnnotations_repeated() throws Exception {
+ assertParameter0Annotations(
+ AnnotatedMethodClass.getMethodWithoutAnnotations(), EXPECT_EMPTY);
+ assertParameter0Annotations(
+ AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
+ "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
+ assertParameter0Annotations(
+ AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
+ "@Container({@Repeated(1)})");
+ assertParameter0Annotations(
+ AnnotatedMethodClass.getMethodMultipleAnnotation(),
+ "@Container({@Repeated(1), @Repeated(2)})");
+ assertParameter0Annotations(
+ AnnotatedMethodClass.getMethodSingleAnnotation(),
+ "@Repeated(1)");
+ }
+
+ private static class AnnotatedConstructorClass {
+ public AnnotatedConstructorClass(Boolean p0) {}
+
+ public AnnotatedConstructorClass(
+ @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {}
+
+ public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {}
+
+ public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {}
+
+ public AnnotatedConstructorClass(@Repeated(1) String p0) {}
+
+ static Constructor<?> getConstructorWithoutAnnotations() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotationExplicitSingle()
+ throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class);
+ }
+
+ static Constructor<?> getConstructorMultipleAnnotation() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class);
+ }
+
+ static Constructor<?> getConstructorSingleAnnotation() throws Exception {
+ return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class);
+ }
+ }
+
+ public void testConstructorGetParameterAnnotations_repeated() throws Exception {
+ assertParameter0Annotations(
+ AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
+ EXPECT_EMPTY);
+ assertParameter0Annotations(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
+ "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
+ assertParameter0Annotations(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
+ "@Container({@Repeated(1)})");
+ assertParameter0Annotations(
+ AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
+ "@Container({@Repeated(1), @Repeated(2)})");
+ assertParameter0Annotations(
+ AnnotatedConstructorClass.getConstructorSingleAnnotation(),
+ "@Repeated(1)");
+ }
+
+ private static void assertParameter0Annotations(
+ Executable executable, String... expectedAnnotationStrings) throws Exception {
+ Annotation[][] allAnnotations = executable.getParameterAnnotations();
+ final int expectedParameterCount = 1;
+ assertEquals(expectedParameterCount, allAnnotations.length);
+
+ Annotation[] p0Annotations = allAnnotations[0];
+ assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java b/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java
deleted file mode 100644
index f40ac9f..0000000
--- a/luni/src/test/java/libcore/java/lang/reflect/annotations/ParameterTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 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 libcore.java.lang.reflect.annotations;
-
-import junit.framework.TestCase;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
-import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
-import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
-import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container;
-import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
-
-import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY;
-import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes;
-import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch;
-import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set;
-
-public class ParameterTest extends TestCase {
- private static class Type {
- @AnnotationB
- @AnnotationC
- public void method(String parameter1, String parameter2) {}
-
- @AnnotationB
- @AnnotationC
- public void parameters(@AnnotationB @AnnotationD String parameter1,
- @AnnotationC @AnnotationD String parameter2) {}
- }
-
- public void testParameterAnnotations() throws Exception {
- Method method = Type.class.getMethod("method", String.class, String.class);
- Annotation[][] noParameterAnnotations = method.getParameterAnnotations();
- assertEquals(2, noParameterAnnotations.length);
- assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
- assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
-
- Method parameters = Type.class.getMethod("parameters", String.class, String.class);
- Annotation[][] parameterAnnotations = parameters.getParameterAnnotations();
- assertEquals(2, parameterAnnotations.length);
- assertEquals(set(AnnotationB.class, AnnotationD.class),
- annotationsToTypes(parameterAnnotations[0]));
- assertEquals(set(AnnotationC.class, AnnotationD.class),
- annotationsToTypes(parameterAnnotations[1]));
- }
-
- private static class AnnotatedClass {
- public void singleAnnotation(@Repeated(1) String p0) {}
-
- public void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {}
-
- public void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {}
-
- public void multipleAnnotationOddity(
- @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {}
-
- public void noAnnotation(String p0) {}
- }
-
- public void testGetParameterAnnotations() throws Exception {
- Class<?> c = AnnotatedClass.class;
-
- assertParameter0Annotations(c, "noAnnotation", EXPECT_EMPTY);
- assertParameter0Annotations(c, "multipleAnnotationOddity",
- "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
- assertParameter0Annotations(c, "multipleAnnotationExplicitSingle",
- "@Container({@Repeated(1)})");
- assertParameter0Annotations(c, "multipleAnnotation",
- "@Container({@Repeated(1), @Repeated(2)})");
- assertParameter0Annotations(c, "singleAnnotation",
- "@Repeated(1)");
- }
-
- private static void assertParameter0Annotations(
- Class<?> c, String methodName, String... expectedAnnotationStrings) throws Exception {
- Annotation[][] allAnnotations =
- c.getDeclaredMethod(methodName, String.class).getParameterAnnotations();
- final int expectedParameterCount = 1;
- assertEquals(expectedParameterCount, allAnnotations.length);
-
- Annotation[] p0Annotations = allAnnotations[0];
- assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings);
- }
-}
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/MetadataVariations.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/MetadataVariations.smali
new file mode 100644
index 0000000..9d76dc9
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/MetadataVariations.smali
@@ -0,0 +1,779 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class public interface abstract Llibcore/java/lang/reflect/parameter/MetadataVariations;
+.super Ljava/lang/Object;
+.source "MetadataVariations.java"
+
+
+# virtual methods
+.method public abstract badAccessModifier(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0xFF
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+.end method
+
+.method public abstract badlyFormedAnnotation(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0xFF
+ }
+ .end annotation
+.end method
+
+.method public abstract emptyMethodParametersAnnotation()V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {}
+ names = {}
+ .end annotation
+.end method
+
+.method public abstract emptyName(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ ""
+ }
+ .end annotation
+.end method
+
+.method public abstract manyParameters(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10,
+ 0x10
+ }
+ names = {
+ "a000",
+ "a001",
+ "a002",
+ "a003",
+ "a004",
+ "a005",
+ "a006",
+ "a007",
+ "a008",
+ "a009",
+ "a010",
+ "a011",
+ "a012",
+ "a013",
+ "a014",
+ "a015",
+ "a016",
+ "a017",
+ "a018",
+ "a019",
+ "a020",
+ "a021",
+ "a022",
+ "a023",
+ "a024",
+ "a025",
+ "a026",
+ "a027",
+ "a028",
+ "a029",
+ "a030",
+ "a031",
+ "a032",
+ "a033",
+ "a034",
+ "a035",
+ "a036",
+ "a037",
+ "a038",
+ "a039",
+ "a040",
+ "a041",
+ "a042",
+ "a043",
+ "a044",
+ "a045",
+ "a046",
+ "a047",
+ "a048",
+ "a049",
+ "a050",
+ "a051",
+ "a052",
+ "a053",
+ "a054",
+ "a055",
+ "a056",
+ "a057",
+ "a058",
+ "a059",
+ "a060",
+ "a061",
+ "a062",
+ "a063",
+ "a064",
+ "a065",
+ "a066",
+ "a067",
+ "a068",
+ "a069",
+ "a070",
+ "a071",
+ "a072",
+ "a073",
+ "a074",
+ "a075",
+ "a076",
+ "a077",
+ "a078",
+ "a079",
+ "a080",
+ "a081",
+ "a082",
+ "a083",
+ "a084",
+ "a085",
+ "a086",
+ "a087",
+ "a088",
+ "a089",
+ "a090",
+ "a091",
+ "a092",
+ "a093",
+ "a094",
+ "a095",
+ "a096",
+ "a097",
+ "a098",
+ "a099",
+ "a100",
+ "a101",
+ "a102",
+ "a103",
+ "a104",
+ "a105",
+ "a106",
+ "a107",
+ "a108",
+ "a109",
+ "a110",
+ "a111",
+ "a112",
+ "a113",
+ "a114",
+ "a115",
+ "a116",
+ "a117",
+ "a118",
+ "a119",
+ "a120",
+ "a121",
+ "a122",
+ "a123",
+ "a124",
+ "a125",
+ "a126",
+ "a127",
+ "a128",
+ "a129",
+ "a130",
+ "a131",
+ "a132",
+ "a133",
+ "a134",
+ "a135",
+ "a136",
+ "a137",
+ "a138",
+ "a139",
+ "a140",
+ "a141",
+ "a142",
+ "a143",
+ "a144",
+ "a145",
+ "a146",
+ "a147",
+ "a148",
+ "a149",
+ "a150",
+ "a151",
+ "a152",
+ "a153",
+ "a154",
+ "a155",
+ "a156",
+ "a157",
+ "a158",
+ "a159",
+ "a160",
+ "a161",
+ "a162",
+ "a163",
+ "a164",
+ "a165",
+ "a166",
+ "a167",
+ "a168",
+ "a169",
+ "a170",
+ "a171",
+ "a172",
+ "a173",
+ "a174",
+ "a175",
+ "a176",
+ "a177",
+ "a178",
+ "a179",
+ "a180",
+ "a181",
+ "a182",
+ "a183",
+ "a184",
+ "a185",
+ "a186",
+ "a187",
+ "a188",
+ "a189",
+ "a190",
+ "a191",
+ "a192",
+ "a193",
+ "a194",
+ "a195",
+ "a196",
+ "a197",
+ "a198",
+ "a199",
+ "a200",
+ "a201",
+ "a202",
+ "a203",
+ "a204",
+ "a205",
+ "a206",
+ "a207",
+ "a208",
+ "a209",
+ "a210",
+ "a211",
+ "a212",
+ "a213",
+ "a214",
+ "a215",
+ "a216",
+ "a217",
+ "a218",
+ "a219",
+ "a220",
+ "a221",
+ "a222",
+ "a223",
+ "a224",
+ "a225",
+ "a226",
+ "a227",
+ "a228",
+ "a229",
+ "a230",
+ "a231",
+ "a232",
+ "a233",
+ "a234",
+ "a235",
+ "a236",
+ "a237",
+ "a238",
+ "a239",
+ "a240",
+ "a241",
+ "a242",
+ "a243",
+ "a244",
+ "a245",
+ "a246",
+ "a247",
+ "a248",
+ "a249",
+ "a250",
+ "a251",
+ "a252",
+ "a253",
+ "a254",
+ "a255",
+ "a256",
+ "a257",
+ "a258",
+ "a259",
+ "a260",
+ "a261",
+ "a262",
+ "a263",
+ "a264",
+ "a265",
+ "a266",
+ "a267",
+ "a268",
+ "a269",
+ "a270",
+ "a271",
+ "a272",
+ "a273",
+ "a274",
+ "a275",
+ "a276",
+ "a277",
+ "a278",
+ "a279",
+ "a280",
+ "a281",
+ "a282",
+ "a283",
+ "a284",
+ "a285",
+ "a286",
+ "a287",
+ "a288",
+ "a289",
+ "a290",
+ "a291",
+ "a292",
+ "a293",
+ "a294",
+ "a295",
+ "a296",
+ "a297",
+ "a298",
+ "a299"
+ }
+ .end annotation
+.end method
+
+.method public abstract nameWithOpenSquareBracket(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = { 0x1 }
+ names = { "a[a" }
+ .end annotation
+.end method
+
+.method public abstract nameWithPeriod(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = { 0x1 }
+ names = { "a.a" }
+ .end annotation
+.end method
+
+.method public abstract nameWithSemicolon(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = { 0x1 }
+ names = { "a;a" }
+ .end annotation
+.end method
+
+.method public abstract nameWithSlash(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = { 0x1 }
+ names = { "a/a" }
+ .end annotation
+.end method
+
+.method public abstract nullName(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ null
+ }
+ .end annotation
+.end method
+
+.method public abstract tooFewAccessFlags(Ljava/lang/String;Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+.end method
+
+.method public abstract tooFewBoth(Ljava/lang/String;Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+.end method
+
+.method public abstract tooFewNames(Ljava/lang/String;Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10,
+ 0x10
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+.end method
+
+.method public abstract tooManyAccessFlags(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10,
+ 0x10
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+.end method
+
+.method public abstract tooManyBoth(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10,
+ 0x10
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+.end method
+
+.method public abstract tooManyNames(Ljava/lang/String;)V
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0.smali
new file mode 100644
index 0000000..f872cef
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0.smali
@@ -0,0 +1,64 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class final synthetic Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+# interfaces
+.implements Ljava/util/concurrent/Callable;
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x1010
+ name = "-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0"
+.end annotation
+
+
+# instance fields
+.field private synthetic val$this:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+
+# direct methods
+.method public synthetic constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+ .registers 2
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;->val$this:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ return-void
+.end method
+
+
+# virtual methods
+.method public call()Ljava/lang/Object;
+ .registers 2
+
+ iget-object v0, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;->val$this:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-virtual {v0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->-libcore_java_lang_reflect_parameter_ParameterMetadataTestClasses-mthref-0()Ljava/lang/String;
+
+ move-result-object v0
+
+ return-object v0
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1.smali
new file mode 100644
index 0000000..b46b487
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1.smali
@@ -0,0 +1,108 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+# interfaces
+.implements Ljava/util/concurrent/Callable;
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingMethod;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->getAnonymousClassWith1ParameterConstructor()Ljava/lang/Class;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x0
+ name = null
+.end annotation
+
+.annotation system Ldalvik/annotation/Signature;
+ value = {
+ "Ljava/lang/Object;",
+ "Ljava/util/concurrent/Callable",
+ "<",
+ "Ljava/lang/String;",
+ ">;"
+ }
+.end annotation
+
+
+# instance fields
+.field final synthetic this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+
+# direct methods
+.method constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8010
+ }
+ names = {
+ "this$0"
+ }
+ .end annotation
+
+ .prologue
+ .line 70
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method public bridge synthetic call()Ljava/lang/Object;
+ .registers 2
+ .annotation system Ldalvik/annotation/Throws;
+ value = {
+ Ljava/lang/Exception;
+ }
+ .end annotation
+
+ .prologue
+ .line 72
+ invoke-virtual {p0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;->call()Ljava/lang/String;
+
+ move-result-object v0
+
+ return-object v0
+.end method
+
+.method public call()Ljava/lang/String;
+ .registers 2
+ .annotation system Ldalvik/annotation/Throws;
+ value = {
+ Ljava/lang/Exception;
+ }
+ .end annotation
+
+ .prologue
+ .line 73
+ iget-object v0, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-static {v0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->-wrap0(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)Ljava/lang/String;
+
+ move-result-object v0
+
+ return-object v0
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass.smali
new file mode 100644
index 0000000..c026225
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass.smali
@@ -0,0 +1,61 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingMethod;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->getMethodClassWith1ImplicitParameterConstructor()Ljava/lang/Class;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x0
+ name = "MethodClass"
+.end annotation
+
+
+# instance fields
+.field final synthetic this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+
+# direct methods
+.method constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8010
+ }
+ names = {
+ "this$0"
+ }
+ .end annotation
+
+ .prologue
+ .line 81
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ .line 82
+ invoke-static {p1}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->-wrap0(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)Ljava/lang/String;
+
+ .line 81
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$FinalParameter.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$FinalParameter.smali
new file mode 100644
index 0000000..6d0ff2d
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$FinalParameter.smali
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$FinalParameter;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "FinalParameter"
+.end annotation
+
+
+# direct methods
+.method constructor <init>(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 26
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method finalParameter(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x10
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 28
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$GenericParameter.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$GenericParameter.smali
new file mode 100644
index 0000000..2e7a6fb
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$GenericParameter.smali
@@ -0,0 +1,91 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$GenericParameter;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "GenericParameter"
+.end annotation
+
+
+# direct methods
+.method constructor <init>(Ljava/util/function/Function;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "(",
+ "Ljava/util/function/Function",
+ "<",
+ "Ljava/lang/String;",
+ "Ljava/lang/Integer;",
+ ">;)V"
+ }
+ .end annotation
+
+ .prologue
+ .line 14
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method genericParameter(Ljava/util/function/Function;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "(",
+ "Ljava/util/function/Function",
+ "<",
+ "Ljava/lang/String;",
+ "Ljava/lang/Integer;",
+ ">;)V"
+ }
+ .end annotation
+
+ .prologue
+ .line 16
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass.smali
new file mode 100644
index 0000000..6ed4514
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass.smali
@@ -0,0 +1,109 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x0
+ name = "InnerClass"
+.end annotation
+
+
+# instance fields
+.field final synthetic this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+
+# direct methods
+.method public constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8010
+ }
+ names = {
+ "this$0"
+ }
+ .end annotation
+
+
+ .prologue
+ .line 32
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+.method public constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;Ljava/lang/String;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8010, 0x0
+ }
+ names = {
+ "this$0", "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 34
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+.method public constructor <init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;Ljava/util/function/Function;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8010, 0x0
+ }
+ names = {
+ "this$0", "p1"
+ }
+ .end annotation
+
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "(",
+ "Ljava/util/function/Function",
+ "<",
+ "Ljava/lang/String;",
+ "Ljava/lang/Integer;",
+ ">;)V"
+ }
+ .end annotation
+
+ .prologue
+ .line 36
+ iput-object p1, p0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass;->this$0:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$MixedVarArgs.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$MixedVarArgs.smali
new file mode 100644
index 0000000..ad404b0
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$MixedVarArgs.smali
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$MixedVarArgs;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "MixedVarArgs"
+.end annotation
+
+
+# direct methods
+.method varargs constructor <init>([Ljava/lang/Integer;[Ljava/lang/String;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 48
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method varargs both([Ljava/lang/Integer;[Ljava/lang/String;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 50
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonIdenticalParameters.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonIdenticalParameters.smali
new file mode 100644
index 0000000..91be02a
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonIdenticalParameters.smali
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonIdenticalParameters;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "NonIdenticalParameters"
+.end annotation
+
+
+# direct methods
+.method constructor <init>()V
+ .registers 1
+
+ .prologue
+ .line 59
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method method0(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 60
+ return-void
+.end method
+
+.method method1(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 61
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonVarArgs.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonVarArgs.smali
new file mode 100644
index 0000000..37e4aca
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonVarArgs.smali
@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonVarArgs;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "NonVarArgs"
+.end annotation
+
+
+# direct methods
+.method constructor <init>([Ljava/lang/Integer;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 54
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method notVarArgs([Ljava/lang/Integer;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 56
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleParameter.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleParameter.smali
new file mode 100644
index 0000000..cfaff4a
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleParameter.smali
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleParameter;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "SingleParameter"
+.end annotation
+
+
+# direct methods
+.method constructor <init>(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 8
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method oneParameter(Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 10
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleVarArgs.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleVarArgs.smali
new file mode 100644
index 0000000..7f020e7
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleVarArgs.smali
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleVarArgs;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "SingleVarArgs"
+.end annotation
+
+
+# direct methods
+.method varargs constructor <init>([Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 42
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method varargs varArgs([Ljava/lang/String;)V
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0
+ }
+ names = {
+ "p0"
+ }
+ .end annotation
+
+ .prologue
+ .line 44
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum.smali
new file mode 100644
index 0000000..c564635
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum.smali
@@ -0,0 +1,144 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class final enum Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+.super Ljava/lang/Enum;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x4018
+ name = "TestEnum"
+.end annotation
+
+.annotation system Ldalvik/annotation/Signature;
+ value = {
+ "Ljava/lang/Enum",
+ "<",
+ "Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;",
+ ">;"
+ }
+.end annotation
+
+
+# static fields
+.field private static final synthetic $VALUES:[Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+.field public static final enum ONE:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+.field public static final enum TWO:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+
+# direct methods
+.method static constructor <clinit>()V
+ .registers 4
+
+ .prologue
+ const/4 v3, 0x1
+
+ const/4 v2, 0x0
+
+ .line 39
+ new-instance v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ const-string/jumbo v1, "ONE"
+
+ invoke-direct {v0, v1, v2}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;-><init>(Ljava/lang/String;I)V
+
+ sput-object v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->ONE:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ new-instance v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ const-string/jumbo v1, "TWO"
+
+ invoke-direct {v0, v1, v3}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;-><init>(Ljava/lang/String;I)V
+
+ sput-object v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->TWO:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ const/4 v0, 0x2
+
+ new-array v0, v0, [Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ sget-object v1, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->ONE:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ aput-object v1, v0, v2
+
+ sget-object v1, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->TWO:Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ aput-object v1, v0, v3
+
+ sput-object v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->$VALUES:[Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ return-void
+.end method
+
+.method private constructor <init>(Ljava/lang/String;I)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x1000, 0x1000
+ }
+ names = {
+ "$enum$name", "$enum$ordinal"
+ }
+ .end annotation
+
+ .prologue
+ .line 39
+ invoke-direct {p0, p1, p2}, Ljava/lang/Enum;-><init>(Ljava/lang/String;I)V
+
+ return-void
+.end method
+
+.method public static valueOf(Ljava/lang/String;)Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+ .registers 2
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x8000
+ }
+ names = {
+ "name"
+ }
+ .end annotation
+
+ .prologue
+ .line 39
+ const-class v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ invoke-static {v0, p0}, Ljava/lang/Enum;->valueOf(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
+
+ move-result-object v0
+
+ check-cast v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ return-object v0
+.end method
+
+.method public static values()[Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+ .registers 1
+
+ .prologue
+ .line 39
+ sget-object v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;->$VALUES:[Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;
+
+ return-object v0
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TwoParameters.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TwoParameters.smali
new file mode 100644
index 0000000..ce4f299
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TwoParameters.smali
@@ -0,0 +1,73 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TwoParameters;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/EnclosingClass;
+ value = Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.end annotation
+
+.annotation system Ldalvik/annotation/InnerClass;
+ accessFlags = 0x8
+ name = "TwoParameters"
+.end annotation
+
+
+# direct methods
+.method constructor <init>(Ljava/lang/String;Ljava/lang/Integer;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 20
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+
+# virtual methods
+.method twoParameters(Ljava/lang/String;Ljava/lang/Integer;)V
+ .registers 3
+ .annotation system Ldalvik/annotation/MethodParameters;
+ accessFlags = {
+ 0x0,
+ 0x0
+ }
+ names = {
+ "p0",
+ "p1"
+ }
+ .end annotation
+
+ .prologue
+ .line 22
+ return-void
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses.smali b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses.smali
new file mode 100644
index 0000000..f7de5b8
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses.smali
@@ -0,0 +1,148 @@
+#
+# Copyright (C) 2016 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.
+
+# Originally generated using baksmali and edited. See README.txt in this directory.
+
+.class public Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;
+.super Ljava/lang/Object;
+.source "ParameterMetadataTestClasses.java"
+
+
+# annotations
+.annotation system Ldalvik/annotation/MemberClasses;
+ value = {
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$FinalParameter;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$GenericParameter;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$InnerClass;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$MixedVarArgs;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonIdenticalParameters;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$NonVarArgs;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleParameter;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$SingleVarArgs;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TestEnum;,
+ Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$TwoParameters;
+ }
+.end annotation
+
+
+# direct methods
+.method static synthetic -wrap0(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)Ljava/lang/String;
+ .registers 2
+
+ invoke-direct {p0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->outerClassMethod()Ljava/lang/String;
+
+ move-result-object v0
+
+ return-object v0
+.end method
+
+.method public constructor <init>()V
+ .registers 1
+
+ .prologue
+ .line 6
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+
+ return-void
+.end method
+
+.method private outerClassMethod()Ljava/lang/String;
+ .registers 2
+
+ .prologue
+ .line 191
+ const-string/jumbo v0, "Howdy"
+
+ return-object v0
+.end method
+
+
+# virtual methods
+.method synthetic -libcore_java_lang_reflect_parameter_ParameterMetadataTestClasses-mthref-0()Ljava/lang/String;
+ .registers 2
+
+ .prologue
+ .line 89
+ invoke-direct {p0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;->outerClassMethod()Ljava/lang/String;
+
+ move-result-object v0
+
+ return-object v0
+.end method
+
+.method public getAnonymousClassWith1ParameterConstructor()Ljava/lang/Class;
+ .registers 2
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "()",
+ "Ljava/lang/Class",
+ "<*>;"
+ }
+ .end annotation
+
+ .prologue
+ .line 70
+ new-instance v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;
+
+ invoke-direct {v0, p0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1;-><init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+
+ .line 76
+ invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+
+ move-result-object v0
+
+ return-object v0
+.end method
+
+.method public getLambdaClassWith1ParameterConstructor()Ljava/lang/Class;
+ .registers 2
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "()",
+ "Ljava/lang/Class",
+ "<*>;"
+ }
+ .end annotation
+
+ .prologue
+ .line 89
+ new-instance v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;
+
+ invoke-direct {v0, p0}, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$-java_lang_Class_getLambdaClassWith1ParameterConstructor__LambdaImpl0;-><init>(Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses;)V
+
+ invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+
+ move-result-object v0
+
+ return-object v0
+.end method
+
+.method public getMethodClassWith1ImplicitParameterConstructor()Ljava/lang/Class;
+ .registers 2
+ .annotation system Ldalvik/annotation/Signature;
+ value = {
+ "()",
+ "Ljava/lang/Class",
+ "<*>;"
+ }
+ .end annotation
+
+ .prologue
+ .line 85
+ const-class v0, Llibcore/java/lang/reflect/parameter/ParameterMetadataTestClasses$1MethodClass;
+
+ return-object v0
+.end method
diff --git a/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt b/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt
new file mode 100644
index 0000000..6d5a6c2
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/reflect/parameter/README.txt
@@ -0,0 +1,212 @@
+This directory contains the .smali files used to generate .dex files used
+by libcore.java.lang.reflect.ParameterTest.
+
+The use of .smali files allows construction of valid and invalid
+system annotations for parameter metadata that are then tested in
+ParameterTest.
+
+Regenerate the .dex files with:
+
+make smali
+smali libcore/luni/src/test/java/libcore/java/lang/reflect/parameter/ParameterMetdataTestClasses*.smali \
+ -o libcore/luni/src/test/resources/libcore/java/lang/reflect/parameter/parameter_metadata_test_classes.dex
+
+For reference, the valid smali code should be (roughly) the equivalent of the
+following Java code when compiled using a compiler with .dex parameter metadata support
+enabled.
+
+The smali was generated using Jack to create a .dex file.
+
+For example:
+
+jack -D jack.java.source.version=1.8 \
+ --output-dex . \
+ -cp ${ANDROID_BUILD_TOP}/out/target/common/obj/JAVA_LIBRARIES/core-all_intermediates/classes.jack \
+ src/test/java/libcore/java/lang/reflect/parameter/ParameterMetadataTestClasses.java
+
+It was then decompiled using baksmali, hand modified, and a .dex generated from it using smali.
+
+ParameterMetadataTestClasses* contain valid metadata.
+MetadataVariations* contain variations on valid and invalid metdata that would be difficult to
+generate from a .java file (i.e. invalid cases, null/empty parameter names).
+
+---------------------
+
+package libcore.java.lang.reflect.parameter;
+
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+
+public class ParameterMetadataTestClasses {
+ static class SingleParameter {
+ SingleParameter(String p0) {}
+
+ void oneParameter(String p0) {}
+ }
+
+ static class GenericParameter {
+ GenericParameter(Function<String, Integer> p0) {}
+
+ void genericParameter(Function<String, Integer> p0) {}
+ }
+
+ static class TwoParameters {
+ TwoParameters(String p0, Integer p1) {}
+
+ void twoParameters(String p0, Integer p1) {}
+ }
+
+ static class FinalParameter {
+ FinalParameter(final String p0) {}
+
+ void finalParameter(final String p0) {}
+ }
+
+ class InnerClass {
+ public InnerClass() {}
+
+ public InnerClass(String p1) {}
+
+ public InnerClass(Function<String, Integer> p1) {}
+ }
+
+ enum TestEnum { ONE, TWO }
+
+ static class SingleVarArgs {
+ SingleVarArgs(String... p0) {}
+
+ void varArgs(String... p0) {}
+ }
+
+ static class MixedVarArgs {
+ MixedVarArgs(Integer[] p0, String... p1) {}
+
+ void both(Integer[] p0, String... p1) {}
+ }
+
+ static class NonVarArgs {
+ NonVarArgs(Integer[] p0) {}
+
+ void notVarArgs(Integer[] p0) {}
+ }
+
+ static class NonIdenticalParameters {
+ void method0(String p1) {}
+
+ void method1(String p1) {}
+ }
+
+ private String outerClassMethod() {
+ return "Howdy";
+ }
+
+ public Class<?> getAnonymousClassWith1ParameterConstructor() {
+ // Deliberately not implemented with a lambda. Do not refactor.
+ Callable<String> anonymousClassObject = new Callable<String>() {
+ @Override
+ public String call() throws Exception {
+ return ParameterMetadataTestClasses.this.outerClassMethod();
+ }
+ };
+ return anonymousClassObject.getClass();
+ }
+
+ public Class<?> getMethodClassWith1ImplicitParameterConstructor() {
+ class MethodClass {
+ MethodClass() {
+ ParameterMetadataTestClasses.this.outerClassMethod();
+ }
+ }
+ return MethodClass.class;
+ }
+
+ public Class<?> getLambdaClassWith1ParameterConstructor() {
+ return ((Callable<String>) ParameterMetadataTestClasses.this::outerClassMethod).getClass();
+ }
+}
+
+----------------
+
+package libcore.java.lang.reflect.parameter;
+
+public interface MetadataVariations {
+
+ void emptyMethodParametersAnnotation();
+ void tooManyAccessFlags(final String p0);
+ void tooFewAccessFlags(final String p0, final String p1);
+ void tooManyNames(final String p0);
+ void tooFewNames(final String p0, final String p1);
+ void tooManyBoth(final String p0);
+ void tooFewBoth(final String p0, final String p1);
+ void nullName(final String p0);
+ void emptyName(final String p0);
+ void nameWithSemicolon(final String p0);
+ void nameWithSlash(final String p0);
+ void nameWithPeriod(final String p0);
+ void nameWithOpenSquareBracket(final String p0);
+ void badAccessModifier(final String p0);
+ void badlyFormedAnnotation(final String p0);
+
+ void manyParameters(
+ final int a000, final int a001, final int a002, final int a003, final int a004,
+ final int a005, final int a006, final int a007, final int a008, final int a009,
+ final int a010, final int a011, final int a012, final int a013, final int a014,
+ final int a015, final int a016, final int a017, final int a018, final int a019,
+ final int a020, final int a021, final int a022, final int a023, final int a024,
+ final int a025, final int a026, final int a027, final int a028, final int a029,
+ final int a030, final int a031, final int a032, final int a033, final int a034,
+ final int a035, final int a036, final int a037, final int a038, final int a039,
+ final int a040, final int a041, final int a042, final int a043, final int a044,
+ final int a045, final int a046, final int a047, final int a048, final int a049,
+ final int a050, final int a051, final int a052, final int a053, final int a054,
+ final int a055, final int a056, final int a057, final int a058, final int a059,
+ final int a060, final int a061, final int a062, final int a063, final int a064,
+ final int a065, final int a066, final int a067, final int a068, final int a069,
+ final int a070, final int a071, final int a072, final int a073, final int a074,
+ final int a075, final int a076, final int a077, final int a078, final int a079,
+ final int a080, final int a081, final int a082, final int a083, final int a084,
+ final int a085, final int a086, final int a087, final int a088, final int a089,
+ final int a090, final int a091, final int a092, final int a093, final int a094,
+ final int a095, final int a096, final int a097, final int a098, final int a099,
+ final int a100, final int a101, final int a102, final int a103, final int a104,
+ final int a105, final int a106, final int a107, final int a108, final int a109,
+ final int a110, final int a111, final int a112, final int a113, final int a114,
+ final int a115, final int a116, final int a117, final int a118, final int a119,
+ final int a120, final int a121, final int a122, final int a123, final int a124,
+ final int a125, final int a126, final int a127, final int a128, final int a129,
+ final int a130, final int a131, final int a132, final int a133, final int a134,
+ final int a135, final int a136, final int a137, final int a138, final int a139,
+ final int a140, final int a141, final int a142, final int a143, final int a144,
+ final int a145, final int a146, final int a147, final int a148, final int a149,
+ final int a150, final int a151, final int a152, final int a153, final int a154,
+ final int a155, final int a156, final int a157, final int a158, final int a159,
+ final int a160, final int a161, final int a162, final int a163, final int a164,
+ final int a165, final int a166, final int a167, final int a168, final int a169,
+ final int a170, final int a171, final int a172, final int a173, final int a174,
+ final int a175, final int a176, final int a177, final int a178, final int a179,
+ final int a180, final int a181, final int a182, final int a183, final int a184,
+ final int a185, final int a186, final int a187, final int a188, final int a189,
+ final int a190, final int a191, final int a192, final int a193, final int a194,
+ final int a195, final int a196, final int a197, final int a198, final int a199,
+ final int a200, final int a201, final int a202, final int a203, final int a204,
+ final int a205, final int a206, final int a207, final int a208, final int a209,
+ final int a210, final int a211, final int a212, final int a213, final int a214,
+ final int a215, final int a216, final int a217, final int a218, final int a219,
+ final int a220, final int a221, final int a222, final int a223, final int a224,
+ final int a225, final int a226, final int a227, final int a228, final int a229,
+ final int a230, final int a231, final int a232, final int a233, final int a234,
+ final int a235, final int a236, final int a237, final int a238, final int a239,
+ final int a240, final int a241, final int a242, final int a243, final int a244,
+ final int a245, final int a246, final int a247, final int a248, final int a249,
+ final int a250, final int a251, final int a252, final int a253, final int a254,
+ final int a255, final int a256, final int a257, final int a258, final int a259,
+ final int a260, final int a261, final int a262, final int a263, final int a264,
+ final int a265, final int a266, final int a267, final int a268, final int a269,
+ final int a270, final int a271, final int a272, final int a273, final int a274,
+ final int a275, final int a276, final int a277, final int a278, final int a279,
+ final int a280, final int a281, final int a282, final int a283, final int a284,
+ final int a285, final int a286, final int a287, final int a288, final int a289,
+ final int a290, final int a291, final int a292, final int a293, final int a294,
+ final int a295, final int a296, final int a297, final int a298, final int a299
+ );
+}
diff --git a/luni/src/test/java/libcore/java/net/DatagramSocketTest.java b/luni/src/test/java/libcore/java/net/DatagramSocketTest.java
index 85526cc..3277385 100644
--- a/luni/src/test/java/libcore/java/net/DatagramSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/DatagramSocketTest.java
@@ -21,8 +21,10 @@
import java.lang.reflect.Field;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
+import java.net.DatagramSocketImpl;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.SocketAddress;
import java.net.SocketException;
public class DatagramSocketTest extends TestCase {
@@ -64,37 +66,90 @@
final int port = 9999;
try (DatagramSocket s = new DatagramSocket()) {
- s.connect(InetAddress.getLocalHost(), port);
+ forceConnectToThrowSocketException(s);
- // connect may set pendingConnectException on internal failure; since we have no reliable way
- // to make connect fail, set pendingConnectException through reflection.
- Field pendingConnectException = s.getClass().getDeclaredField("pendingConnectException");
- pendingConnectException.setAccessible(true);
- pendingConnectException.set(s, new SocketException());
+ s.connect(InetAddress.getLocalHost(), port);
byte[] data = new byte[100];
DatagramPacket p = new DatagramPacket(data, data.length);
+ // Confirm send() throws the pendingConnectException.
try {
s.send(p);
fail();
} catch (SocketException expected) {
+ assertTrue(expected.getMessage().contains("Pending connect failure"));
}
+ // Confirm receive() throws the pendingConnectException.
try {
s.receive(p);
fail();
} catch (SocketException expected) {
+ assertTrue(expected.getMessage().contains("Pending connect failure"));
}
+
+ // Confirm that disconnect() doesn't throw a runtime exception.
+ s.disconnect();
}
}
public void test_setTrafficClass() throws Exception {
- DatagramSocket s = new DatagramSocket();
-
- for (int i = 0; i <= 255; ++i) {
- s.setTrafficClass(i);
- assertEquals(i, s.getTrafficClass());
+ try (DatagramSocket s = new DatagramSocket()) {
+ for (int i = 0; i <= 255; ++i) {
+ s.setTrafficClass(i);
+ assertEquals(i, s.getTrafficClass());
+ }
}
}
+
+ // DatagramSocket should "become connected" even when impl.connect() fails and throws an
+ // exception.
+ public void test_b31218085() throws Exception {
+ final int port = 9999;
+
+ try (DatagramSocket s = new DatagramSocket()) {
+ forceConnectToThrowSocketException(s);
+
+ s.connect(InetAddress.getLocalHost(), port);
+ assertTrue(s.isConnected());
+
+ // Confirm that disconnect() doesn't throw a runtime exception.
+ s.disconnect();
+ }
+ }
+
+ public void testForceConnectToThrowSocketException() throws Exception {
+ // Unlike connect(InetAddress, int), connect(SocketAddress) can (and should) throw an
+ // exception after a call to forceConnectToThrowSocketException(). The
+ // forceConnectToThrowSocketException() method is used in various tests for
+ // connect(InetAddress, int) and this test exists to confirm it stays working.
+
+ SocketAddress validAddress = new InetSocketAddress(InetAddress.getLocalHost(), 9999);
+
+ try (DatagramSocket s1 = new DatagramSocket()) {
+ s1.connect(validAddress);
+ s1.disconnect();
+ }
+
+ try (DatagramSocket s2 = new DatagramSocket()) {
+ forceConnectToThrowSocketException(s2);
+ try {
+ s2.connect(validAddress);
+ } catch (SocketException expected) {
+ }
+ s2.disconnect();
+ }
+ }
+
+ private static void forceConnectToThrowSocketException(DatagramSocket s) throws Exception {
+ // Set fd of DatagramSocketImpl to null, forcing impl.connect() to throw a SocketException
+ // (Socket closed).
+ Field f = DatagramSocket.class.getDeclaredField("impl");
+ f.setAccessible(true);
+ DatagramSocketImpl impl = (DatagramSocketImpl) f.get(s);
+ f = DatagramSocketImpl.class.getDeclaredField("fd");
+ f.setAccessible(true);
+ f.set(impl, null);
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/SocketTest.java b/luni/src/test/java/libcore/java/net/SocketTest.java
index f273f8e..1952286 100644
--- a/luni/src/test/java/libcore/java/net/SocketTest.java
+++ b/luni/src/test/java/libcore/java/net/SocketTest.java
@@ -16,6 +16,7 @@
package libcore.java.net;
+import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -43,7 +44,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
-import java.io.FileDescriptor;
public class SocketTest extends junit.framework.TestCase {
@@ -379,33 +379,43 @@
public void testCloseDuringConnect() throws Exception {
final CountDownLatch signal = new CountDownLatch(1);
-
final Socket s = new Socket();
- new Thread() {
- @Override
- public void run() {
- try {
- // This address is reserved for documentation: should never be reachable.
- InetSocketAddress unreachableIp = new InetSocketAddress("192.0.2.0", 80);
- // This should never return.
- s.connect(unreachableIp, 0 /* infinite */);
- fail("Connect returned unexpectedly for: " + unreachableIp);
- } catch (SocketException expected) {
- assertTrue(expected.getMessage().contains("Socket closed"));
- signal.countDown();
- } catch (IOException e) {
- fail("Unexpected exception: " + e);
- }
- }
- }.start();
- // Wait for the connect() thread to run and start connect()
+ // Executes a connect() that should block.
+ Callable<String> connectWorker = () -> {
+ try {
+ // This address is reserved for documentation: should never be reachable.
+ InetSocketAddress unreachableIp = new InetSocketAddress("192.0.2.0", 80);
+ // This should never return.
+ s.connect(unreachableIp, 0 /* infinite */);
+ return "Connect returned unexpectedly for: " + unreachableIp;
+ } catch (SocketException expected) {
+ signal.countDown();
+ return expected.getMessage().contains("Socket closed")
+ ? null
+ : "Unexpected SocketException message: " + expected.getMessage();
+ } catch (IOException e) {
+ return "Unexpected exception: " + e;
+ }
+ };
+ Future<String> connectResult =
+ Executors.newSingleThreadScheduledExecutor().submit(connectWorker);
+
+ // Wait sufficient time for the connectWorker thread to run and start connect().
Thread.sleep(2000);
+ // Close the socket that connectWorker should currently be blocked in connect().
s.close();
+ // connectWorker should have been unblocked so await() should return true.
boolean connectUnblocked = signal.await(2000, TimeUnit.MILLISECONDS);
- assertTrue(connectUnblocked);
+
+ // connectWorker should have returned null if everything went as expected.
+ String workerFailure = connectResult.get(2000, TimeUnit.MILLISECONDS);
+
+ assertTrue("connectUnblocked=[" + connectUnblocked
+ + "], workerFailure=[" + workerFailure + "]",
+ connectUnblocked && workerFailure == null);
}
// http://b/29092095
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index d1d26a8..3f750e4 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -2723,7 +2723,7 @@
public void testSslFallback_allSupportedProtocols() throws Exception {
TestSSLContext testSSLContext = createDefaultTestSSLContext();
- String[] allSupportedProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3" };
+ String[] allSupportedProtocols = { "TLSv1.2", "TLSv1.1", "TLSv1" };
SSLSocketFactory serverSocketFactory =
new LimitedProtocolsSocketFactory(
testSSLContext.serverContext.getSocketFactory(),
@@ -2731,7 +2731,6 @@
server.useHttps(serverSocketFactory, false);
server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
- server.enqueue(new MockResponse().setSocketPolicy(FAIL_HANDSHAKE));
server.enqueue(new MockResponse().setBody("This required fallbacks"));
server.play();
@@ -2749,28 +2748,24 @@
// Confirm the server accepted a single connection.
RecordedRequest retry = server.takeRequest();
assertEquals(0, retry.getSequenceNumber());
- assertEquals("SSLv3", retry.getSslProtocol());
+ assertEquals("TLSv1", retry.getSslProtocol());
// Confirm the client fallback looks ok.
List<SSLSocket> createdSockets = clientSocketFactory.getCreatedSockets();
- assertEquals(4, createdSockets.size());
+ assertEquals(3, createdSockets.size());
TlsFallbackDisabledScsvSSLSocket clientSocket1 =
(TlsFallbackDisabledScsvSSLSocket) createdSockets.get(0);
assertSslSocket(clientSocket1,
- false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3");
+ false /* expectedWasFallbackScsvSet */, "TLSv1.2", "TLSv1.1", "TLSv1");
TlsFallbackDisabledScsvSSLSocket clientSocket2 =
(TlsFallbackDisabledScsvSSLSocket) createdSockets.get(1);
assertSslSocket(clientSocket2,
- true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1", "SSLv3");
+ true /* expectedWasFallbackScsvSet */, "TLSv1.1", "TLSv1");
TlsFallbackDisabledScsvSSLSocket clientSocket3 =
(TlsFallbackDisabledScsvSSLSocket) createdSockets.get(2);
- assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1", "SSLv3");
-
- TlsFallbackDisabledScsvSSLSocket clientSocket4 =
- (TlsFallbackDisabledScsvSSLSocket) createdSockets.get(3);
- assertSslSocket(clientSocket4, true /* expectedWasFallbackScsvSet */, "SSLv3");
+ assertSslSocket(clientSocket3, true /* expectedWasFallbackScsvSet */, "TLSv1");
}
public void testSslFallback_defaultProtocols() throws Exception {
diff --git a/luni/src/test/java/libcore/java/net/URLStreamHandlerFactoryTest.java b/luni/src/test/java/libcore/java/net/URLStreamHandlerFactoryTest.java
index de50e16..21c2971 100644
--- a/luni/src/test/java/libcore/java/net/URLStreamHandlerFactoryTest.java
+++ b/luni/src/test/java/libcore/java/net/URLStreamHandlerFactoryTest.java
@@ -21,6 +21,8 @@
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
import libcore.java.net.customstreamhandler.http.Handler;
@@ -61,13 +63,23 @@
try {
URL.setURLStreamHandlerFactory(shf);
fail();
+ } catch (AssertionFailedError error) {
+ // Rethrow the error thrown by fail to avoid it being caught by the more general catch
+ // statement below.
+ throw error;
} catch (Error expected) {
+ // The setURLStreamHandlerFactory is behaving correctly by throwing an Error.
}
try {
URL.setURLStreamHandlerFactory(null);
fail();
+ } catch (AssertionFailedError error) {
+ // Rethrow the error thrown by fail to avoid it being caught by the more general catch
+ // statement below.
+ throw error;
} catch (Error expected) {
+ // The setURLStreamHandlerFactory is behaving correctly by throwing an Error.
}
}
diff --git a/luni/src/test/java/libcore/java/net/URLTest.java b/luni/src/test/java/libcore/java/net/URLTest.java
index 789e3e9..566c314 100644
--- a/luni/src/test/java/libcore/java/net/URLTest.java
+++ b/luni/src/test/java/libcore/java/net/URLTest.java
@@ -735,6 +735,11 @@
}
@Override
+ public void onUnbufferedIO() {
+ fail("Blockguard.Policy.onUnbufferedIO");
+ }
+
+ @Override
public int getPolicyMask() {
return 0;
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
index 0951302..52146ee 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelMulticastTest.java
@@ -490,6 +490,7 @@
assertTrue(key.isValid());
assertSame(networkInterface, key.networkInterface());
assertNull(key.sourceAddress());
+ dc.close();
}
public void test_dropAnySource_twice_IPv4() throws Exception {
diff --git a/luni/src/test/java/libcore/java/security/PrivilegedActionExceptionTest.java b/luni/src/test/java/libcore/java/security/PrivilegedActionExceptionTest.java
index 99799bf..6f74dd8 100644
--- a/luni/src/test/java/libcore/java/security/PrivilegedActionExceptionTest.java
+++ b/luni/src/test/java/libcore/java/security/PrivilegedActionExceptionTest.java
@@ -30,7 +30,7 @@
* b/31360928
*/
@Test
- public void test() {
+ public void testGetException() {
Exception e = new Exception();
PrivilegedActionException pae = new PrivilegedActionException(e);
diff --git a/luni/src/test/java/libcore/java/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 35712e0..8d1af37 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -238,32 +238,28 @@
@Override
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
- throw new UnsupportedOperationException();
}
@Override
protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
- throw new UnsupportedOperationException();
}
@Override
protected void engineUpdate(byte b) throws SignatureException {
- throw new UnsupportedOperationException();
}
@Override
protected void engineUpdate(byte[] b, int off, int len) throws SignatureException {
- throw new UnsupportedOperationException();
}
@Override
protected byte[] engineSign() throws SignatureException {
- throw new UnsupportedOperationException();
+ return new byte[10];
}
@Override
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
- throw new UnsupportedOperationException();
+ return true;
}
@Override
@@ -277,6 +273,153 @@
}
}
+ public void testSignature_signArray_nullArray_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.sign(null /* outbuf */, 1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_signArray_negativeOffset_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.sign(new byte[4], -1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_signArray_negativeLength_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.sign(new byte[4], 1 /* offset */ , -1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_signArray_invalidLengths_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ // Start at offset 3 with length 2, thus attempting to overread from an array of size 4.
+ s.sign(new byte[4], 3 /* offset */ , 2 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ private static PublicKey createPublicKey() throws Exception {
+ X509EncodedKeySpec keySpec = new X509EncodedKeySpec(PK_BYTES);
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePublic(keySpec);
+ }
+
+ public void testSignature_verifyArray_nullArray_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.verify(null /* outbuf */, 1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_verifyArray_negativeOffset_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.verify(new byte[4], -1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_verifyArray_negativeLength_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.verify(new byte[4], 1 /* offset */ , -1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_verifyArray_invalidLengths_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ // Start at offset 3 with length 2, thus attempting to overread from an array of size 4.
+ s.verify(new byte[4], 3 /* offset */ , 2 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_verifyArray_correctParameters_ok() throws Exception {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ // Start at offset 3 with length 2, thus attempting to overread from an array of size 4.
+ s.verify(new byte[4], 1 /* offset */, 2 /* length */);
+ }
+
+ public void testSignature_updateArray_nullArray_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.update(null /* outbuf */, 1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_updateArray_negativeOffset_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.update(new byte[4], -1 /* offset */, 1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_updateArray_negativeLength_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.update(new byte[4], 1 /* offset */ , -1 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_updateArray_invalidLengths_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ // Start at offset 3 with length 2, thus attempting to overread from an array of size 4.
+ s.update(new byte[4], 3 /* offset */ , 2 /* length */);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ public void testSignature_updateArray_wrongState_throws() throws Exception {
+ try {
+ Signature s = new MySignature("FOO");
+ s.update(new byte[4], 0 /* offset */ , 1 /* length */);
+ fail();
+ } catch (SignatureException expected) {
+ }
+ }
+
+ public void testSignature_updateArray_correctStateAndParameters_ok() throws Exception {
+ Signature s = new MySignature("FOO");
+ s.initVerify(createPublicKey());
+ s.update(new byte[4], 0 /* offset */ , 1 /* length */);
+ }
+
public void testSignature_getProvider_Subclass() throws Exception {
Provider mockProviderNonSpi = new MockProvider("MockProviderNonSpi") {
public void setup() {
diff --git a/luni/src/test/java/libcore/java/text/OldBidiTest.java b/luni/src/test/java/libcore/java/text/OldBidiTest.java
index fbf68ea..fe8b6cb 100644
--- a/luni/src/test/java/libcore/java/text/OldBidiTest.java
+++ b/luni/src/test/java/libcore/java/text/OldBidiTest.java
@@ -17,6 +17,7 @@
package libcore.java.text;
+import java.text.AttributedCharacterIterator;
import java.text.Bidi;
import junit.framework.TestCase;
@@ -192,4 +193,16 @@
}
}
+ // http://b/30652865
+ public void testUnicode9EmojisAreLtrNeutral() {
+ String callMeHand = "\uD83E\uDD19"; // U+1F919 in UTF-16
+ String hebrewAndEmoji = "\u05e9\u05dc" + callMeHand + "\u05d5\u05dd";
+ String latinAndEmoji = "Hel" + callMeHand + "lo";
+ Bidi hebrew = new Bidi(hebrewAndEmoji, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertFalse("Hebrew bidi is mixed: " + hebrew, hebrew.isMixed());
+ assertTrue("Hebrew bidi is not right to left: " + hebrew, hebrew.isRightToLeft());
+ Bidi latin = new Bidi(latinAndEmoji, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT);
+ assertFalse("Latin bidi is mixed: " + latin, latin.isMixed());
+ assertTrue("latin bidi is not left to right: " + latin, latin.isLeftToRight());
+ }
}
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index d9656a0..47c2365 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -513,4 +513,23 @@
assertEquals("torstai", formatDate(fi, "cccc"));
assertEquals("torstaina", formatDate(fi, "EEEE"));
}
+
+ public void testDayNumberOfWeek() throws Exception {
+ TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
+ Locale en = Locale.ENGLISH;
+ Locale pl = new Locale("pl");
+
+ assertEquals("4", formatDate(en, "u"));
+ assertEquals("04", formatDate(en, "uu"));
+ assertEquals("4", formatDate(pl, "u"));
+ assertEquals("04", formatDate(pl, "uu"));
+
+ assertEquals(Calendar.THURSDAY, parseDate(en, "u", "4").get(Calendar.DAY_OF_WEEK));
+ assertEquals(Calendar.MONDAY, parseDate(en, "uu", "1").get(Calendar.DAY_OF_WEEK));
+ }
+
+ // http://b/20879084
+ public void testFormatUtc() {
+ assertEquals("UTC", formatDate(Locale.ENGLISH, "z", TimeZone.getTimeZone("Etc/UTC")));
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CurrencyTest.java b/luni/src/test/java/libcore/java/util/CurrencyTest.java
index 58c958a..91584de 100644
--- a/luni/src/test/java/libcore/java/util/CurrencyTest.java
+++ b/luni/src/test/java/libcore/java/util/CurrencyTest.java
@@ -18,10 +18,14 @@
import java.util.Currency;
import java.util.Locale;
+import java.util.Objects;
import java.util.Set;
import libcore.util.SerializationTester;
+import static java.util.Locale.Category.DISPLAY;
+import static java.util.Locale.Category.FORMAT;
+
public class CurrencyTest extends junit.framework.TestCase {
// Regression test to ensure that Currency.getSymbol(Locale) returns the
// currency code if ICU doesn't have a localization of the symbol. The
@@ -35,6 +39,30 @@
assertEquals("AED", Currency.getInstance("AED").getSymbol(Locale.CANADA));
}
+ public void test_getSymbol_locale() {
+ Currency currency = Currency.getInstance("DEM");
+ assertEquals("DEM", currency.getSymbol(Locale.FRANCE));
+ assertEquals("DM", currency.getSymbol(Locale.GERMANY));
+ assertEquals("DEM", currency.getSymbol(Locale.US));
+ }
+
+ /**
+ * Checks that the no-argument version of {@link Currency#getSymbol()} uses the
+ * default DISPLAY locale as opposed to the default locale or the default FORMAT
+ * locale.
+ */
+ public void test_getSymbol_noLocaleArgument() {
+ Currency currency = Currency.getInstance("DEM");
+ Locales locales = getDefaultLocales();
+ try {
+ // Locales(locale, displayLocale, formatLocale)
+ setDefaultLocales(new Locales(Locale.US, Locale.GERMANY, Locale.FRANCE));
+ assertEquals("DM", currency.getSymbol());
+ } finally {
+ setDefaultLocales(locales);
+ }
+ }
+
// Regression test to ensure that Currency.getInstance(String) throws if
// given an invalid ISO currency code.
public void test_getInstance_illegal_currency_code() throws Exception {
@@ -56,11 +84,45 @@
assertTrue(all.toString(), all.contains(Currency.getInstance("USD")));
}
- public void test_getDisplayName() throws Exception {
- assertEquals("Swiss Franc", Currency.getInstance("CHF").getDisplayName(Locale.US));
- assertEquals("Schweizer Franken", Currency.getInstance("CHF").getDisplayName(new Locale("de", "CH")));
- assertEquals("franc suisse", Currency.getInstance("CHF").getDisplayName(new Locale("fr", "CH")));
- assertEquals("franco svizzero", Currency.getInstance("CHF").getDisplayName(new Locale("it", "CH")));
+ public void test_getDisplayName_locale_chf() throws Exception {
+ Currency currency = Currency.getInstance("CHF");
+ assertEquals("Swiss Franc", currency.getDisplayName(Locale.US));
+ assertEquals("Schweizer Franken", currency.getDisplayName(new Locale("de", "CH")));
+ assertEquals("franc suisse", currency.getDisplayName(new Locale("fr", "CH")));
+ assertEquals("franco svizzero", currency.getDisplayName(new Locale("it", "CH")));
+ }
+
+ public void test_getDisplayName_locale_dem() throws Exception {
+ Currency currency = Currency.getInstance("DEM");
+ assertEquals("Deutsche Mark", currency.getDisplayName(Locale.GERMANY));
+ assertEquals("German Mark", currency.getDisplayName(Locale.US));
+ assertEquals("mark allemand", currency.getDisplayName(Locale.FRANCE));
+ }
+
+ public void test_getDisplayName_null() {
+ Currency currency = Currency.getInstance("CHF");
+ try {
+ currency.getDisplayName(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ /**
+ * Checks that the no-argument version of {@link Currency#getDisplayName()} uses
+ * the default DISPLAY locale, as opposed to the default locale or the default
+ * FORMAT locale.
+ */
+ public void test_getDisplayName_noLocaleArgument() {
+ Currency currency = Currency.getInstance("DEM");
+ Locales locales = getDefaultLocales();
+ try {
+ // Locales(uncategorizedLocale, displayLocale, formatLocale)
+ setDefaultLocales(new Locales(Locale.US, Locale.GERMANY, Locale.FRANCE));
+ assertEquals("Deutsche Mark", currency.getDisplayName());
+ } finally {
+ setDefaultLocales(locales);
+ }
}
public void test_getDefaultFractionDigits() throws Exception {
@@ -108,4 +170,54 @@
assertEquals(999, Currency.getInstance("XXX").getNumericCode());
assertEquals(0, Currency.getInstance("XFU").getNumericCode());
}
+
+ static Locales getDefaultLocales() {
+ return new Locales(
+ Locale.getDefault(), Locale.getDefault(DISPLAY), Locale.getDefault(FORMAT));
+ }
+
+ static void setDefaultLocales(Locales locales) {
+ // The lines below must set the Locales in this order because setDefault(Locale)
+ // overwrites the other ones.
+ Locale.setDefault(locales.uncategorizedLocale);
+ Locale.setDefault(DISPLAY, locales.displayLocale);
+ Locale.setDefault(FORMAT, locales.formatLocale);
+
+ assertEquals(locales, getDefaultLocales()); // sanity check
+ }
+
+ static class Locales {
+ final Locale uncategorizedLocale;
+ final Locale displayLocale;
+ final Locale formatLocale;
+
+ public Locales(Locale uncategorizedLocale, Locale displayLocale, Locale formatLocale) {
+ this.uncategorizedLocale = uncategorizedLocale;
+ this.displayLocale = displayLocale;
+ this.formatLocale = formatLocale;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Locales)) {
+ return false;
+ }
+ Locales that = (Locales) obj;
+ return uncategorizedLocale.equals(that.uncategorizedLocale)
+ && displayLocale.equals(that.displayLocale)
+ && formatLocale.equals(that.formatLocale);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(uncategorizedLocale, displayLocale, formatLocale);
+ }
+
+ @Override
+ public String toString() {
+ return "Locales[displayLocale=" + displayLocale + ", locale=" + uncategorizedLocale +
+ ", formatLocale=" + formatLocale + ']';
+ }
+ }
+
}
diff --git a/luni/src/test/java/libcore/java/util/InvalidPropertiesFormatExceptionTest.java b/luni/src/test/java/libcore/java/util/InvalidPropertiesFormatExceptionTest.java
new file mode 100644
index 0000000..694c069
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/InvalidPropertiesFormatExceptionTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 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 libcore.java.util;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.InvalidPropertiesFormatException;
+import libcore.util.SerializationTester;
+
+public class InvalidPropertiesFormatExceptionTest extends TestCase {
+
+ public void testConstructorArgs() {
+ InvalidPropertiesFormatException e = new InvalidPropertiesFormatException("testing");
+ assertEquals("testing", e.getMessage());
+ assertNull(e.getCause());
+
+ InvalidPropertiesFormatException e2 = new InvalidPropertiesFormatException(e);
+ assertSame(e, e2.getCause());
+ assertEquals(e.toString(), e2.getMessage());
+ }
+
+ public void testDeserialize_notSupported() throws Exception {
+ // Result of
+ // SerializationTester.serializeHex(new InvalidPropertiesFormatException("testing"))
+ // using a InvalidPropertiesFormatException class that had its
+ // writeObject() method commented out.
+ String hex = "aced00057372002a6a6176612e7574696c2e496e76616c696450726f"
+ + "70657274696573466f726d6174457863657074696f6e6bbbea5ee5f9cb5"
+ + "b020000787200136a6176612e696f2e494f457863657074696f6e6c8073"
+ + "646525f0ab020000787200136a6176612e6c616e672e457863657074696"
+ + "f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e546872"
+ + "6f7761626c65d5c635273977b8cb0300044c000563617573657400154c6"
+ + "a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d"
+ + "6573736167657400124c6a6176612f6c616e672f537472696e673b5b000"
+ + "a737461636b547261636574001e5b4c6a6176612f6c616e672f53746163"
+ + "6b5472616365456c656d656e743b4c00147375707072657373656445786"
+ + "3657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071"
+ + "007e000874000774657374696e677572001e5b4c6a6176612e6c616e672"
+ + "e537461636b5472616365456c656d656e743b02462a3c3cfd2239020000"
+ + "78700000000a7372001b6a6176612e6c616e672e537461636b547261636"
+ + "5456c656d656e746109c59a2636dd8502000449000a6c696e654e756d62"
+ + "65724c000e6465636c6172696e67436c61737371007e00054c000866696"
+ + "c654e616d6571007e00054c000a6d6574686f644e616d6571007e000578"
+ + "70000000457400366c6962636f72652e6a6176612e7574696c2e496e766"
+ + "16c696450726f70657274696573466f726d6174457863657074696f6e54"
+ + "657374740029496e76616c696450726f70657274696573466f726d61744"
+ + "57863657074696f6e546573742e6a61766174001a746573745365726961"
+ + "6c697a655f6e6f74537570706f727465647371007e000cfffffffe74001"
+ + "86a6176612e6c616e672e7265666c6563742e4d6574686f6474000b4d65"
+ + "74686f642e6a617661740006696e766f6b657371007e000c000000c2740"
+ + "028766f6761722e7461726765742e6a756e69742e4a756e69743324566f"
+ + "6761724a556e69745465737474000b4a756e6974332e6a6176617400037"
+ + "2756e7371007e000c0000003b740024766f6761722e7461726765742e6a"
+ + "756e69742e566f6761725465737452756e6e65722431740014566f67617"
+ + "25465737452756e6e65722e6a6176617400086576616c75617465737100"
+ + "7e000c0000004874002b766f6761722e7461726765742e6a756e69742e5"
+ + "4696d656f7574416e6441626f727452756e52756c65243274001b54696d"
+ + "656f7574416e6441626f727452756e52756c652e6a61766174000463616"
+ + "c6c7371007e000c0000004474002b766f6761722e7461726765742e6a75"
+ + "6e69742e54696d656f7574416e6441626f727452756e52756c652432740"
+ + "01b54696d656f7574416e6441626f727452756e52756c652e6a61766174"
+ + "000463616c6c7371007e000c000000ed74001f6a6176612e7574696c2e6"
+ + "36f6e63757272656e742e4675747572655461736b74000f467574757265"
+ + "5461736b2e6a61766174000372756e7371007e000c0000046d7400276a6"
+ + "176612e7574696c2e636f6e63757272656e742e546872656164506f6f6c"
+ + "4578656375746f72740017546872656164506f6f6c4578656375746f722"
+ + "e6a61766174000972756e576f726b65727371007e000c0000025f74002e"
+ + "6a6176612e7574696c2e636f6e63757272656e742e546872656164506f6"
+ + "f6c4578656375746f7224576f726b6572740017546872656164506f6f6c"
+ + "4578656375746f722e6a61766174000372756e7371007e000c000002f87"
+ + "400106a6176612e6c616e672e54687265616474000b5468726561642e6a"
+ + "61766174000372756e7372001f6a6176612e7574696c2e436f6c6c65637"
+ + "4696f6e7324456d7074794c6973747ab817b43ca79ede020000787078";
+ try {
+ Object obj = SerializationTester.deserializeHex(hex);
+ fail("Deserialized to " + obj);
+ } catch (NotSerializableException expected) {
+ // Sanity check that this is the right exception that we expected.
+ assertEquals("Not serializable.", expected.getMessage());
+ }
+ }
+
+ public void testSerialize_notSupported() throws Exception {
+ Serializable notActuallySerializable = new InvalidPropertiesFormatException("testing");
+ try {
+ try (ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream())) {
+ out.writeObject(notActuallySerializable);
+ }
+ fail();
+ } catch (NotSerializableException expected) {
+ // Sanity check that this is the right exception that we expected.
+ assertEquals("Not serializable.", expected.getMessage());
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/ResourceLeakageDetectorTest.java b/luni/src/test/java/libcore/java/util/ResourceLeakageDetectorTest.java
index d86c9f2..5509f73 100644
--- a/luni/src/test/java/libcore/java/util/ResourceLeakageDetectorTest.java
+++ b/luni/src/test/java/libcore/java/util/ResourceLeakageDetectorTest.java
@@ -26,17 +26,24 @@
* This test will not work on RI as it does not support the <code>CloseGuard</code> or similar
* mechanism.
*/
- public void testDetectsUnclosedCloseGuard() throws Exception {
+ // TODO(paulduffin): b/31542223 - Work out why this is failing in CTS, fix and reenable.
+ public void notestDetectsUnclosedCloseGuard() throws Exception {
ResourceLeakageDetector detector = ResourceLeakageDetector.newDetector();
try {
CloseGuard closeGuard = createCloseGuard();
closeGuard.open("open");
} finally {
+ boolean leaksDetected = true;
try {
System.logI("Checking for leaks");
detector.checkForLeaks();
- fail();
+ leaksDetected = false;
} catch (AssertionError expected) {
+ // The leak detector should throw this error.
+ }
+
+ if (!leaksDetected) {
+ fail("Did not detect any leaks");
}
}
}
diff --git a/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java b/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
index b69a2dd..f17eb22 100644
--- a/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
+++ b/luni/src/test/java/libcore/java/util/ServiceLoaderTest.java
@@ -44,7 +44,7 @@
ServiceLoader.load(ServiceLoaderTestInterfaceMissingClass.class).iterator().next();
fail();
} catch (ServiceConfigurationError expected) {
- assertTrue(expected.getCause() instanceof ClassNotFoundException);
+ assertTrue(expected.toString(), expected.getCause() instanceof ClassNotFoundException);
}
}
@@ -55,7 +55,7 @@
ServiceLoader.load(ServiceLoaderTestInterfaceWrongType.class).iterator().next();
fail();
} catch (ServiceConfigurationError expected) {
- assertTrue(expected.getCause() instanceof ClassCastException);
+ assertTrue(expected.toString(), expected.getCause() instanceof ClassCastException);
}
}
diff --git a/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java b/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
index 785b265..ead0b2e 100644
--- a/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
+++ b/luni/src/test/java/libcore/java/util/logging/OldFileHandlerTest.java
@@ -33,6 +33,7 @@
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
public class OldFileHandlerTest extends TestCase {
@@ -162,11 +163,15 @@
FileHandler h7 = new FileHandler("%t/log/string%u.log");
h7.publish(r);
h7.close();
+ boolean assertionPassed = false;
try {
- assertFileContent(TEMPPATH + SEP + "log", "string0.log", h
- .getFormatter());
- fail("should assertion failed");
- } catch (Error e) {
+ assertFileContent(TEMPPATH + SEP + "log", "string0.log", h.getFormatter());
+ assertionPassed = true;
+ } catch (AssertionFailedError e) {
+ // Assertion failed as expected.
+ }
+ if (assertionPassed) {
+ fail("assertion should have failed");
}
File file = new File(TEMPPATH + SEP + "log");
assertTrue("length list of file is incorrect", file.list().length <= 2);
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 1127559..c5260328 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -36,7 +36,8 @@
import java.security.Security;
import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.ArrayList;
import java.util.Arrays;
@@ -57,8 +58,10 @@
import javax.crypto.ShortBufferException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import junit.framework.TestCase;
import libcore.java.security.StandardNames;
@@ -243,42 +246,65 @@
|| algorithm.contains("/CFB");
}
+ private static boolean isRandomizedEncryption(String algorithm) {
+ return algorithm.endsWith("/PKCS1PADDING") || algorithm.endsWith("/OAEPPADDING")
+ || algorithm.contains("/OAEPWITH");
+ }
+
private static Map<String, Key> ENCRYPT_KEYS = new HashMap<String, Key>();
- private synchronized static Key getEncryptKey(String algorithm) throws Exception {
+
+ /**
+ * Returns the key meant for enciphering for {@code algorithm}.
+ */
+ private synchronized static Key getEncryptKey(String algorithm) {
Key key = ENCRYPT_KEYS.get(algorithm);
if (key != null) {
return key;
}
- if (algorithm.startsWith("RSA")) {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
- key = kf.generatePrivate(keySpec);
- } else if (isPBE(algorithm)) {
- SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
- key = skf.generateSecret(new PBEKeySpec("secret".toCharArray()));
- } else {
- KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(algorithm));
- key = kg.generateKey();
+ try {
+ if (algorithm.startsWith("RSA")) {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent);
+ key = kf.generatePublic(keySpec);
+ } else if (isPBE(algorithm)) {
+ SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
+ key = skf.generateSecret(new PBEKeySpec("secret".toCharArray()));
+ } else {
+ KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(algorithm));
+ key = kg.generateKey();
+ }
+ } catch (Exception e) {
+ throw new AssertionError("Error generating keys for test setup", e);
}
ENCRYPT_KEYS.put(algorithm, key);
return key;
}
private static Map<String, Key> DECRYPT_KEYS = new HashMap<String, Key>();
- private synchronized static Key getDecryptKey(String algorithm) throws Exception {
+
+ /**
+ * Returns the key meant for deciphering for {@code algorithm}.
+ */
+ private synchronized static Key getDecryptKey(String algorithm) {
Key key = DECRYPT_KEYS.get(algorithm);
if (key != null) {
return key;
}
- if (algorithm.startsWith("RSA")) {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus,
- RSA_2048_publicExponent);
- key = kf.generatePublic(keySpec);
- } else {
- assertFalse(algorithm, isAsymmetric(algorithm));
- key = getEncryptKey(algorithm);
+ try {
+ if (algorithm.startsWith("RSA")) {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ RSAPrivateCrtKeySpec keySpec = new RSAPrivateCrtKeySpec(RSA_2048_modulus,
+ RSA_2048_publicExponent, RSA_2048_privateExponent, RSA_2048_primeP,
+ RSA_2048_primeQ, RSA_2048_primeExponentP, RSA_2048_primeExponentQ,
+ RSA_2048_crtCoefficient);
+ key = kf.generatePrivate(keySpec);
+ } else {
+ assertFalse(algorithm, isAsymmetric(algorithm));
+ key = getEncryptKey(algorithm);
+ }
+ } catch (Exception e) {
+ throw new AssertionError("Error generating keys for test setup", e);
}
DECRYPT_KEYS.put(algorithm, key);
return key;
@@ -1395,7 +1421,7 @@
test_Cipher_init_Decrypt_NullParameters(c, decryptMode, encryptKey, decryptSpec != null);
- c.init(decryptMode, encryptKey, decryptSpec);
+ c.init(decryptMode, getDecryptKey(algorithm), decryptSpec);
assertEquals(cipherID + " getBlockSize() decryptMode",
getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
assertEquals(cipherID + " getOutputSize(0) decryptMode",
@@ -1484,13 +1510,10 @@
c.updateAAD(new byte[24]);
}
byte[] cipherText = c.doFinal(getActualPlainText(algorithm));
- if (isAEAD(algorithm)) {
- c.updateAAD(new byte[24]);
+ if (!isRandomizedEncryption(algorithm) && !isAEAD(algorithm)) {
+ byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
+ assertEquals(cipherID, Arrays.toString(cipherText), Arrays.toString(cipherText2));
}
- byte[] cipherText2 = c.doFinal(getActualPlainText(algorithm));
- assertEquals(cipherID,
- Arrays.toString(cipherText),
- Arrays.toString(cipherText2));
c.init(Cipher.DECRYPT_MODE, getDecryptKey(algorithm), decryptSpec);
if (isAEAD(algorithm)) {
c.updateAAD(new byte[24]);
@@ -1602,18 +1625,21 @@
}
private void testInputPKCS1Padding(String provider) throws Exception {
- testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ // Type 1 is for signatures (PrivateKey to "encrypt")
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
try {
- testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
fail();
} catch (BadPaddingException expected) {
}
+
+ // Type 2 is for enciphering (PublicKey to "encrypt")
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
try {
- testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
fail();
} catch (BadPaddingException expected) {
}
- testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
}
private void testInputPKCS1Padding(String provider, byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception {
@@ -1645,8 +1671,10 @@
}
private void testOutputPKCS1Padding(String provider) throws Exception {
- testOutputPKCS1Padding(provider, (byte) 1, getEncryptKey("RSA"), getDecryptKey("RSA"));
- testOutputPKCS1Padding(provider, (byte) 2, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ // Type 1 is for signatures (PrivateKey to "encrypt")
+ testOutputPKCS1Padding(provider, (byte) 1, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ // Type 2 is for enciphering (PublicKey to "encrypt")
+ testOutputPKCS1Padding(provider, (byte) 2, getEncryptKey("RSA"), getDecryptKey("RSA"));
}
private void testOutputPKCS1Padding(String provider, byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception {
@@ -1918,6 +1946,63 @@
(byte) 0x39,
});
+ private static final BigInteger RSA_2048_primeExponentP = new BigInteger(1, new byte[] {
+ (byte) 0x51, (byte) 0x82, (byte) 0x8F, (byte) 0x1E, (byte) 0xC6, (byte) 0xFD, (byte) 0x99, (byte) 0x60,
+ (byte) 0x29, (byte) 0x90, (byte) 0x1B, (byte) 0xAF, (byte) 0x1D, (byte) 0x7E, (byte) 0x33, (byte) 0x7B,
+ (byte) 0xA5, (byte) 0xF0, (byte) 0xAF, (byte) 0x27, (byte) 0xE9, (byte) 0x84, (byte) 0xEA, (byte) 0xD8,
+ (byte) 0x95, (byte) 0xAC, (byte) 0xE6, (byte) 0x2B, (byte) 0xD7, (byte) 0xDF, (byte) 0x4E, (byte) 0xE4,
+ (byte) 0x5A, (byte) 0x22, (byte) 0x40, (byte) 0x89, (byte) 0xF2, (byte) 0xCC, (byte) 0x15, (byte) 0x1A,
+ (byte) 0xF3, (byte) 0xCD, (byte) 0x17, (byte) 0x3F, (byte) 0xCE, (byte) 0x04, (byte) 0x74, (byte) 0xBC,
+ (byte) 0xB0, (byte) 0x4F, (byte) 0x38, (byte) 0x6A, (byte) 0x2C, (byte) 0xDC, (byte) 0xC0, (byte) 0xE0,
+ (byte) 0x03, (byte) 0x6B, (byte) 0xA2, (byte) 0x41, (byte) 0x9F, (byte) 0x54, (byte) 0x57, (byte) 0x92,
+ (byte) 0x62, (byte) 0xD4, (byte) 0x71, (byte) 0x00, (byte) 0xBE, (byte) 0x93, (byte) 0x19, (byte) 0x84,
+ (byte) 0xA3, (byte) 0xEF, (byte) 0xA0, (byte) 0x5B, (byte) 0xEC, (byte) 0xF1, (byte) 0x41, (byte) 0x57,
+ (byte) 0x4D, (byte) 0xC0, (byte) 0x79, (byte) 0xB3, (byte) 0xA9, (byte) 0x5C, (byte) 0x4A, (byte) 0x83,
+ (byte) 0xE6, (byte) 0xC4, (byte) 0x3F, (byte) 0x32, (byte) 0x14, (byte) 0xD6, (byte) 0xDF, (byte) 0x32,
+ (byte) 0xD5, (byte) 0x12, (byte) 0xDE, (byte) 0x19, (byte) 0x80, (byte) 0x85, (byte) 0xE5, (byte) 0x31,
+ (byte) 0xE6, (byte) 0x16, (byte) 0xB8, (byte) 0x3F, (byte) 0xD7, (byte) 0xDD, (byte) 0x9D, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x26, (byte) 0x07, (byte) 0xC3, (byte) 0x33, (byte) 0x3D, (byte) 0x07, (byte) 0xC5,
+ (byte) 0x5D, (byte) 0x10, (byte) 0x7D, (byte) 0x1D, (byte) 0x38, (byte) 0x93, (byte) 0x58, (byte) 0x71,
+ });
+
+ private static final BigInteger RSA_2048_primeExponentQ = new BigInteger(1, new byte[] {
+ (byte) 0xDB, (byte) 0x4F, (byte) 0xB5, (byte) 0x0F, (byte) 0x50, (byte) 0xDE, (byte) 0x8E, (byte) 0xDB,
+ (byte) 0x53, (byte) 0xFF, (byte) 0x34, (byte) 0xC8, (byte) 0x09, (byte) 0x31, (byte) 0x88, (byte) 0xA0,
+ (byte) 0x51, (byte) 0x28, (byte) 0x67, (byte) 0xDA, (byte) 0x2C, (byte) 0xCA, (byte) 0x04, (byte) 0x89,
+ (byte) 0x77, (byte) 0x59, (byte) 0xE5, (byte) 0x87, (byte) 0xC2, (byte) 0x44, (byte) 0x01, (byte) 0x0D,
+ (byte) 0xAF, (byte) 0x86, (byte) 0x64, (byte) 0xD5, (byte) 0x9E, (byte) 0x80, (byte) 0x83, (byte) 0xD1,
+ (byte) 0x6C, (byte) 0x16, (byte) 0x47, (byte) 0x89, (byte) 0x30, (byte) 0x1F, (byte) 0x67, (byte) 0xA9,
+ (byte) 0xF0, (byte) 0x78, (byte) 0x06, (byte) 0x0D, (byte) 0x83, (byte) 0x4A, (byte) 0x2A, (byte) 0xDB,
+ (byte) 0xD3, (byte) 0x67, (byte) 0x57, (byte) 0x5B, (byte) 0x68, (byte) 0xA8, (byte) 0xA8, (byte) 0x42,
+ (byte) 0xC2, (byte) 0xB0, (byte) 0x2A, (byte) 0x89, (byte) 0xB3, (byte) 0xF3, (byte) 0x1F, (byte) 0xCC,
+ (byte) 0xEC, (byte) 0x8A, (byte) 0x22, (byte) 0xFE, (byte) 0x39, (byte) 0x57, (byte) 0x95, (byte) 0xC5,
+ (byte) 0xC6, (byte) 0xC7, (byte) 0x42, (byte) 0x2B, (byte) 0x4E, (byte) 0x5D, (byte) 0x74, (byte) 0xA1,
+ (byte) 0xE9, (byte) 0xA8, (byte) 0xF3, (byte) 0x0E, (byte) 0x77, (byte) 0x59, (byte) 0xB9, (byte) 0xFC,
+ (byte) 0x2D, (byte) 0x63, (byte) 0x9C, (byte) 0x1F, (byte) 0x15, (byte) 0x67, (byte) 0x3E, (byte) 0x84,
+ (byte) 0xE9, (byte) 0x3A, (byte) 0x5E, (byte) 0xF1, (byte) 0x50, (byte) 0x6F, (byte) 0x43, (byte) 0x15,
+ (byte) 0x38, (byte) 0x3C, (byte) 0x38, (byte) 0xD4, (byte) 0x5C, (byte) 0xBD, (byte) 0x1B, (byte) 0x14,
+ (byte) 0x04, (byte) 0x8F, (byte) 0x47, (byte) 0x21, (byte) 0xDC, (byte) 0x82, (byte) 0x32, (byte) 0x61,
+ });
+
+ private static final BigInteger RSA_2048_crtCoefficient = new BigInteger(1, new byte[] {
+ (byte) 0xD8, (byte) 0x11, (byte) 0x45, (byte) 0x93, (byte) 0xAF, (byte) 0x41, (byte) 0x5F, (byte) 0xB6,
+ (byte) 0x12, (byte) 0xDB, (byte) 0xF1, (byte) 0x92, (byte) 0x37, (byte) 0x10, (byte) 0xD5, (byte) 0x4D,
+ (byte) 0x07, (byte) 0x48, (byte) 0x62, (byte) 0x05, (byte) 0xA7, (byte) 0x6A, (byte) 0x3B, (byte) 0x43,
+ (byte) 0x19, (byte) 0x49, (byte) 0x68, (byte) 0xC0, (byte) 0xDF, (byte) 0xF1, (byte) 0xF1, (byte) 0x1E,
+ (byte) 0xF0, (byte) 0xF6, (byte) 0x1A, (byte) 0x4A, (byte) 0x33, (byte) 0x7D, (byte) 0x5F, (byte) 0xD3,
+ (byte) 0x74, (byte) 0x1B, (byte) 0xBC, (byte) 0x96, (byte) 0x40, (byte) 0xE4, (byte) 0x47, (byte) 0xB8,
+ (byte) 0xB6, (byte) 0xB6, (byte) 0xC4, (byte) 0x7C, (byte) 0x3A, (byte) 0xC1, (byte) 0x20, (byte) 0x43,
+ (byte) 0x57, (byte) 0xD3, (byte) 0xB0, (byte) 0xC5, (byte) 0x5B, (byte) 0xA9, (byte) 0x28, (byte) 0x6B,
+ (byte) 0xDA, (byte) 0x73, (byte) 0xF6, (byte) 0x29, (byte) 0x29, (byte) 0x6F, (byte) 0x5F, (byte) 0xA9,
+ (byte) 0x14, (byte) 0x6D, (byte) 0x89, (byte) 0x76, (byte) 0x35, (byte) 0x7D, (byte) 0x3C, (byte) 0x75,
+ (byte) 0x1E, (byte) 0x75, (byte) 0x14, (byte) 0x86, (byte) 0x96, (byte) 0xA4, (byte) 0x0B, (byte) 0x74,
+ (byte) 0x68, (byte) 0x5C, (byte) 0x82, (byte) 0xCE, (byte) 0x30, (byte) 0x90, (byte) 0x2D, (byte) 0x63,
+ (byte) 0x9D, (byte) 0x72, (byte) 0x4F, (byte) 0xF2, (byte) 0x4D, (byte) 0x5E, (byte) 0x2E, (byte) 0x94,
+ (byte) 0x07, (byte) 0xEE, (byte) 0x34, (byte) 0xED, (byte) 0xED, (byte) 0x2E, (byte) 0x3B, (byte) 0x4D,
+ (byte) 0xF6, (byte) 0x5A, (byte) 0xA9, (byte) 0xBC, (byte) 0xFE, (byte) 0xB6, (byte) 0xDF, (byte) 0x28,
+ (byte) 0xD0, (byte) 0x7B, (byte) 0xA6, (byte) 0x90, (byte) 0x3F, (byte) 0x16, (byte) 0x57, (byte) 0x68,
+ });
+
/**
* Test data is PKCS#1 padded "Android.\n" which can be generated by:
* echo "Android." | openssl rsautl -inkey rsa.key -sign | openssl rsautl -inkey rsa.key -raw -verify | recode ../x1
@@ -2119,6 +2204,319 @@
(byte) 0x4b, (byte) 0x98, (byte) 0x3f, (byte) 0xae, (byte) 0x20, (byte) 0xfd,
(byte) 0x8a, (byte) 0x50, (byte) 0x73, (byte) 0xe4,
};
+ /*
+ * echo -n 'This is a test of OAEP' | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_Plaintext = new byte[] {
+ (byte) 0x54, (byte) 0x68, (byte) 0x69, (byte) 0x73, (byte) 0x20, (byte) 0x69,
+ (byte) 0x73, (byte) 0x20, (byte) 0x61, (byte) 0x20, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x6f, (byte) 0x66, (byte) 0x20,
+ (byte) 0x4f, (byte) 0x41, (byte) 0x45, (byte) 0x50
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem \
+ * -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA1_MGF1_SHA1 = new byte[] {
+ (byte) 0x53, (byte) 0x71, (byte) 0x84, (byte) 0x2e, (byte) 0x01, (byte) 0x74,
+ (byte) 0x82, (byte) 0xb3, (byte) 0x01, (byte) 0xac, (byte) 0x2b, (byte) 0xbd,
+ (byte) 0x40, (byte) 0xa7, (byte) 0x5b, (byte) 0x60, (byte) 0xf1, (byte) 0xde,
+ (byte) 0x54, (byte) 0x1d, (byte) 0x94, (byte) 0xc1, (byte) 0x10, (byte) 0x31,
+ (byte) 0x6f, (byte) 0xa3, (byte) 0xd8, (byte) 0x41, (byte) 0x2e, (byte) 0x82,
+ (byte) 0xad, (byte) 0x07, (byte) 0x6f, (byte) 0x25, (byte) 0x6c, (byte) 0xb5,
+ (byte) 0xef, (byte) 0xc6, (byte) 0xa6, (byte) 0xfb, (byte) 0xb1, (byte) 0x9d,
+ (byte) 0x75, (byte) 0x67, (byte) 0xb0, (byte) 0x97, (byte) 0x21, (byte) 0x3c,
+ (byte) 0x17, (byte) 0x04, (byte) 0xdc, (byte) 0x4e, (byte) 0x7e, (byte) 0x3f,
+ (byte) 0x5c, (byte) 0x13, (byte) 0x5e, (byte) 0x15, (byte) 0x0f, (byte) 0xe2,
+ (byte) 0xa7, (byte) 0x62, (byte) 0x6a, (byte) 0x08, (byte) 0xb1, (byte) 0xbc,
+ (byte) 0x2f, (byte) 0xcb, (byte) 0xb5, (byte) 0x96, (byte) 0x2d, (byte) 0xec,
+ (byte) 0x71, (byte) 0x4d, (byte) 0x59, (byte) 0x6e, (byte) 0x27, (byte) 0x85,
+ (byte) 0x87, (byte) 0x9b, (byte) 0xcc, (byte) 0x40, (byte) 0x32, (byte) 0x09,
+ (byte) 0x06, (byte) 0xe6, (byte) 0x7d, (byte) 0xdf, (byte) 0xeb, (byte) 0x2f,
+ (byte) 0xa8, (byte) 0x1c, (byte) 0x53, (byte) 0xdb, (byte) 0xa7, (byte) 0x48,
+ (byte) 0xf5, (byte) 0xbf, (byte) 0x2f, (byte) 0xbb, (byte) 0xee, (byte) 0xc7,
+ (byte) 0x55, (byte) 0x5e, (byte) 0xc4, (byte) 0x1c, (byte) 0x84, (byte) 0xed,
+ (byte) 0x97, (byte) 0x7e, (byte) 0xce, (byte) 0xa5, (byte) 0x69, (byte) 0x73,
+ (byte) 0xb3, (byte) 0xe0, (byte) 0x8c, (byte) 0x2a, (byte) 0xf2, (byte) 0xc7,
+ (byte) 0x65, (byte) 0xff, (byte) 0x10, (byte) 0xed, (byte) 0x25, (byte) 0xf0,
+ (byte) 0xf8, (byte) 0xda, (byte) 0x2f, (byte) 0x7f, (byte) 0xe0, (byte) 0x69,
+ (byte) 0xed, (byte) 0xb1, (byte) 0x0e, (byte) 0xcb, (byte) 0x43, (byte) 0xe4,
+ (byte) 0x31, (byte) 0xe6, (byte) 0x52, (byte) 0xfd, (byte) 0xa7, (byte) 0xe5,
+ (byte) 0x21, (byte) 0xd0, (byte) 0x67, (byte) 0x0a, (byte) 0xc1, (byte) 0xa1,
+ (byte) 0xb9, (byte) 0x04, (byte) 0xdb, (byte) 0x98, (byte) 0x4f, (byte) 0xf9,
+ (byte) 0x5c, (byte) 0x60, (byte) 0x4d, (byte) 0xac, (byte) 0x7a, (byte) 0x69,
+ (byte) 0xbd, (byte) 0x63, (byte) 0x0d, (byte) 0xb2, (byte) 0x01, (byte) 0x83,
+ (byte) 0xd7, (byte) 0x22, (byte) 0x5d, (byte) 0xed, (byte) 0xbd, (byte) 0x32,
+ (byte) 0x98, (byte) 0xd1, (byte) 0x4a, (byte) 0x2e, (byte) 0xb7, (byte) 0xb1,
+ (byte) 0x6d, (byte) 0x8a, (byte) 0x8f, (byte) 0xef, (byte) 0xc3, (byte) 0x89,
+ (byte) 0xdf, (byte) 0xa5, (byte) 0xac, (byte) 0xfb, (byte) 0x38, (byte) 0x61,
+ (byte) 0x32, (byte) 0xc5, (byte) 0x19, (byte) 0x83, (byte) 0x1f, (byte) 0x9c,
+ (byte) 0x45, (byte) 0x58, (byte) 0xdd, (byte) 0xa3, (byte) 0x57, (byte) 0xe4,
+ (byte) 0x91, (byte) 0xd2, (byte) 0x11, (byte) 0xf8, (byte) 0x96, (byte) 0x36,
+ (byte) 0x67, (byte) 0x99, (byte) 0x2b, (byte) 0x62, (byte) 0x21, (byte) 0xe3,
+ (byte) 0xa8, (byte) 0x5e, (byte) 0xa4, (byte) 0x2e, (byte) 0x0c, (byte) 0x29,
+ (byte) 0xf9, (byte) 0xcd, (byte) 0xfa, (byte) 0xbe, (byte) 0x3f, (byte) 0xd8,
+ (byte) 0xec, (byte) 0x6b, (byte) 0x32, (byte) 0xb3, (byte) 0x40, (byte) 0x4f,
+ (byte) 0x48, (byte) 0xe3, (byte) 0x14, (byte) 0x87, (byte) 0xa7, (byte) 0x5c,
+ (byte) 0xba, (byte) 0xdf, (byte) 0x0e, (byte) 0x64, (byte) 0xdc, (byte) 0xe2,
+ (byte) 0x51, (byte) 0xf4, (byte) 0x41, (byte) 0x25, (byte) 0x23, (byte) 0xc8,
+ (byte) 0x50, (byte) 0x1e, (byte) 0x9e, (byte) 0xb0
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha1 | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA256_MGF1_SHA1 = new byte[] {
+ (byte) 0x25, (byte) 0x9f, (byte) 0xc3, (byte) 0x69, (byte) 0xbc, (byte) 0x3f,
+ (byte) 0xe7, (byte) 0x9e, (byte) 0x76, (byte) 0xef, (byte) 0x6c, (byte) 0xd2,
+ (byte) 0x2b, (byte) 0x7b, (byte) 0xf0, (byte) 0xeb, (byte) 0xc2, (byte) 0x28,
+ (byte) 0x40, (byte) 0x4e, (byte) 0x9b, (byte) 0x2a, (byte) 0x4e, (byte) 0xa4,
+ (byte) 0x79, (byte) 0x66, (byte) 0xf1, (byte) 0x10, (byte) 0x96, (byte) 0x8c,
+ (byte) 0x58, (byte) 0x92, (byte) 0xb7, (byte) 0x70, (byte) 0xed, (byte) 0x3a,
+ (byte) 0xe0, (byte) 0x99, (byte) 0xd1, (byte) 0x80, (byte) 0x4b, (byte) 0x53,
+ (byte) 0x70, (byte) 0x9b, (byte) 0x51, (byte) 0xbf, (byte) 0xc1, (byte) 0x3a,
+ (byte) 0x70, (byte) 0xc5, (byte) 0x79, (byte) 0x21, (byte) 0x6e, (byte) 0xb3,
+ (byte) 0xf7, (byte) 0xa9, (byte) 0xe6, (byte) 0xcb, (byte) 0x70, (byte) 0xe4,
+ (byte) 0xf3, (byte) 0x4f, (byte) 0x45, (byte) 0xcf, (byte) 0xb7, (byte) 0x2b,
+ (byte) 0x38, (byte) 0xfd, (byte) 0x5d, (byte) 0x9a, (byte) 0x53, (byte) 0xc5,
+ (byte) 0x05, (byte) 0x74, (byte) 0x8d, (byte) 0x1d, (byte) 0x6e, (byte) 0x83,
+ (byte) 0xaa, (byte) 0x71, (byte) 0xc5, (byte) 0xe1, (byte) 0xa1, (byte) 0xa6,
+ (byte) 0xf3, (byte) 0xee, (byte) 0x5f, (byte) 0x9e, (byte) 0x4f, (byte) 0xe8,
+ (byte) 0x15, (byte) 0xd5, (byte) 0xa9, (byte) 0x1b, (byte) 0xa6, (byte) 0x41,
+ (byte) 0x2b, (byte) 0x18, (byte) 0x13, (byte) 0x20, (byte) 0x9f, (byte) 0x6b,
+ (byte) 0xf1, (byte) 0xd8, (byte) 0xf4, (byte) 0x87, (byte) 0xfa, (byte) 0x80,
+ (byte) 0xec, (byte) 0x0e, (byte) 0xa4, (byte) 0x4b, (byte) 0x24, (byte) 0x03,
+ (byte) 0x14, (byte) 0x25, (byte) 0xf2, (byte) 0x20, (byte) 0xfc, (byte) 0x52,
+ (byte) 0xf9, (byte) 0xd6, (byte) 0x7a, (byte) 0x4a, (byte) 0x45, (byte) 0x33,
+ (byte) 0xec, (byte) 0xde, (byte) 0x3c, (byte) 0x5b, (byte) 0xf2, (byte) 0xdc,
+ (byte) 0x8e, (byte) 0xc6, (byte) 0xb3, (byte) 0x26, (byte) 0xd3, (byte) 0x68,
+ (byte) 0xa7, (byte) 0xd8, (byte) 0x3a, (byte) 0xde, (byte) 0xa9, (byte) 0x25,
+ (byte) 0x1d, (byte) 0x42, (byte) 0x75, (byte) 0x66, (byte) 0x16, (byte) 0x29,
+ (byte) 0xad, (byte) 0x09, (byte) 0x74, (byte) 0x41, (byte) 0xbb, (byte) 0x45,
+ (byte) 0x39, (byte) 0x04, (byte) 0x7a, (byte) 0x93, (byte) 0xad, (byte) 0x1c,
+ (byte) 0xa6, (byte) 0x38, (byte) 0xf4, (byte) 0xac, (byte) 0xca, (byte) 0x5a,
+ (byte) 0xab, (byte) 0x92, (byte) 0x76, (byte) 0x26, (byte) 0x3c, (byte) 0xeb,
+ (byte) 0xda, (byte) 0xfc, (byte) 0x25, (byte) 0x93, (byte) 0x23, (byte) 0x01,
+ (byte) 0xe2, (byte) 0xac, (byte) 0x5e, (byte) 0x4c, (byte) 0xb7, (byte) 0xbc,
+ (byte) 0x5b, (byte) 0xaa, (byte) 0x14, (byte) 0xe9, (byte) 0xbf, (byte) 0x2d,
+ (byte) 0x3a, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x4d, (byte) 0x0e,
+ (byte) 0x0a, (byte) 0x82, (byte) 0x3c, (byte) 0xd9, (byte) 0x32, (byte) 0xc1,
+ (byte) 0xc4, (byte) 0xa2, (byte) 0x46, (byte) 0x71, (byte) 0x10, (byte) 0x54,
+ (byte) 0x1a, (byte) 0xa6, (byte) 0xaa, (byte) 0x64, (byte) 0xe7, (byte) 0xc2,
+ (byte) 0xae, (byte) 0xbc, (byte) 0x3d, (byte) 0xa4, (byte) 0xa8, (byte) 0xd1,
+ (byte) 0xb7, (byte) 0x27, (byte) 0xef, (byte) 0x5f, (byte) 0xe7, (byte) 0xa7,
+ (byte) 0x5d, (byte) 0xa0, (byte) 0xcd, (byte) 0x57, (byte) 0xf1, (byte) 0xe0,
+ (byte) 0xd8, (byte) 0x42, (byte) 0x10, (byte) 0x77, (byte) 0xc3, (byte) 0xa7,
+ (byte) 0x1e, (byte) 0x0c, (byte) 0x37, (byte) 0x16, (byte) 0x11, (byte) 0x94,
+ (byte) 0x21, (byte) 0xf2, (byte) 0xca, (byte) 0x60, (byte) 0xce, (byte) 0xca,
+ (byte) 0x59, (byte) 0xf9, (byte) 0xe5, (byte) 0xe4
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey rsakey.pem \
+ * -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha224 -pkeyopt rsa_mgf1_md:sha224 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA224_MGF1_SHA224 = new byte[] {
+ (byte) 0xae, (byte) 0xdd, (byte) 0xe6, (byte) 0xab, (byte) 0x00, (byte) 0xd6,
+ (byte) 0x1e, (byte) 0x7e, (byte) 0x85, (byte) 0x63, (byte) 0xab, (byte) 0x51,
+ (byte) 0x79, (byte) 0x92, (byte) 0xf1, (byte) 0xb9, (byte) 0x4f, (byte) 0x23,
+ (byte) 0xae, (byte) 0xf7, (byte) 0x1b, (byte) 0x5f, (byte) 0x10, (byte) 0x5b,
+ (byte) 0xa5, (byte) 0x15, (byte) 0x87, (byte) 0xa3, (byte) 0xbb, (byte) 0x26,
+ (byte) 0xfe, (byte) 0x7f, (byte) 0xc0, (byte) 0xa3, (byte) 0x67, (byte) 0x95,
+ (byte) 0xda, (byte) 0xc4, (byte) 0x6f, (byte) 0x6e, (byte) 0x08, (byte) 0x23,
+ (byte) 0x28, (byte) 0x0b, (byte) 0xdd, (byte) 0x29, (byte) 0x29, (byte) 0xdc,
+ (byte) 0xb0, (byte) 0x35, (byte) 0x16, (byte) 0x2e, (byte) 0x0f, (byte) 0xb9,
+ (byte) 0x1d, (byte) 0x90, (byte) 0x27, (byte) 0x68, (byte) 0xc7, (byte) 0x92,
+ (byte) 0x52, (byte) 0x8a, (byte) 0x1d, (byte) 0x48, (byte) 0x6a, (byte) 0x7d,
+ (byte) 0x0b, (byte) 0xf6, (byte) 0x35, (byte) 0xca, (byte) 0xe1, (byte) 0x57,
+ (byte) 0xdd, (byte) 0x36, (byte) 0x3b, (byte) 0x51, (byte) 0x45, (byte) 0x77,
+ (byte) 0x28, (byte) 0x4f, (byte) 0x98, (byte) 0xc0, (byte) 0xe0, (byte) 0xa7,
+ (byte) 0x51, (byte) 0x98, (byte) 0x84, (byte) 0x7a, (byte) 0x29, (byte) 0x05,
+ (byte) 0x9f, (byte) 0x60, (byte) 0x66, (byte) 0xf6, (byte) 0x83, (byte) 0xcd,
+ (byte) 0x03, (byte) 0x3e, (byte) 0x82, (byte) 0x0f, (byte) 0x57, (byte) 0x4b,
+ (byte) 0x27, (byte) 0x14, (byte) 0xf6, (byte) 0xc8, (byte) 0x5b, (byte) 0xed,
+ (byte) 0xc3, (byte) 0x77, (byte) 0x6f, (byte) 0xec, (byte) 0x0e, (byte) 0xae,
+ (byte) 0x59, (byte) 0xbe, (byte) 0x68, (byte) 0x76, (byte) 0x16, (byte) 0x17,
+ (byte) 0x77, (byte) 0xe2, (byte) 0xbd, (byte) 0xe0, (byte) 0x5a, (byte) 0x14,
+ (byte) 0xd9, (byte) 0xf4, (byte) 0x3f, (byte) 0x50, (byte) 0x31, (byte) 0xf0,
+ (byte) 0x0c, (byte) 0x82, (byte) 0x6c, (byte) 0xcc, (byte) 0x81, (byte) 0x84,
+ (byte) 0x3e, (byte) 0x63, (byte) 0x93, (byte) 0xe7, (byte) 0x12, (byte) 0x2d,
+ (byte) 0xc9, (byte) 0xa3, (byte) 0xe3, (byte) 0xce, (byte) 0xfd, (byte) 0xc7,
+ (byte) 0xe1, (byte) 0xef, (byte) 0xa4, (byte) 0x16, (byte) 0x5c, (byte) 0x60,
+ (byte) 0xb1, (byte) 0x80, (byte) 0x31, (byte) 0x15, (byte) 0x5c, (byte) 0x35,
+ (byte) 0x25, (byte) 0x0b, (byte) 0x89, (byte) 0xe4, (byte) 0x56, (byte) 0x74,
+ (byte) 0x8b, (byte) 0xaf, (byte) 0x8e, (byte) 0xe9, (byte) 0xe2, (byte) 0x37,
+ (byte) 0x17, (byte) 0xe6, (byte) 0x7b, (byte) 0x78, (byte) 0xd8, (byte) 0x2c,
+ (byte) 0x27, (byte) 0x52, (byte) 0x21, (byte) 0x96, (byte) 0xa0, (byte) 0x92,
+ (byte) 0x95, (byte) 0x64, (byte) 0xc3, (byte) 0x7f, (byte) 0x45, (byte) 0xfc,
+ (byte) 0x3d, (byte) 0x48, (byte) 0x4a, (byte) 0xd5, (byte) 0xa4, (byte) 0x0a,
+ (byte) 0x57, (byte) 0x07, (byte) 0x57, (byte) 0x95, (byte) 0x9f, (byte) 0x2f,
+ (byte) 0x75, (byte) 0x32, (byte) 0x2a, (byte) 0x4d, (byte) 0x64, (byte) 0xbd,
+ (byte) 0xb1, (byte) 0xe0, (byte) 0x46, (byte) 0x4f, (byte) 0xe8, (byte) 0x6c,
+ (byte) 0x4b, (byte) 0x77, (byte) 0xcc, (byte) 0x36, (byte) 0x87, (byte) 0x05,
+ (byte) 0x56, (byte) 0x9a, (byte) 0xe4, (byte) 0x2c, (byte) 0x43, (byte) 0xfd,
+ (byte) 0x34, (byte) 0x97, (byte) 0xf8, (byte) 0xd7, (byte) 0x91, (byte) 0xff,
+ (byte) 0x56, (byte) 0x86, (byte) 0x17, (byte) 0x49, (byte) 0x0a, (byte) 0x52,
+ (byte) 0xfb, (byte) 0xe5, (byte) 0x49, (byte) 0xdf, (byte) 0xc1, (byte) 0x28,
+ (byte) 0x9d, (byte) 0x85, (byte) 0x66, (byte) 0x9d, (byte) 0x1d, (byte) 0xa4,
+ (byte) 0x7e, (byte) 0x9a, (byte) 0x5b, (byte) 0x30
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA256_MGF1_SHA256 = new byte[] {
+ (byte) 0x6a, (byte) 0x2b, (byte) 0xb2, (byte) 0xa3, (byte) 0x26, (byte) 0xa6,
+ (byte) 0x7a, (byte) 0x4a, (byte) 0x1f, (byte) 0xe5, (byte) 0xc8, (byte) 0x94,
+ (byte) 0x11, (byte) 0x1a, (byte) 0x92, (byte) 0x07, (byte) 0x0a, (byte) 0xf4,
+ (byte) 0x07, (byte) 0x0b, (byte) 0xd6, (byte) 0x37, (byte) 0xa5, (byte) 0x5d,
+ (byte) 0x16, (byte) 0x0a, (byte) 0x7d, (byte) 0x13, (byte) 0x27, (byte) 0x32,
+ (byte) 0x5a, (byte) 0xc3, (byte) 0x0d, (byte) 0x7a, (byte) 0x54, (byte) 0xfe,
+ (byte) 0x02, (byte) 0x28, (byte) 0xc6, (byte) 0x8e, (byte) 0x32, (byte) 0x7b,
+ (byte) 0x0a, (byte) 0x52, (byte) 0xf8, (byte) 0xe6, (byte) 0xab, (byte) 0x16,
+ (byte) 0x77, (byte) 0x7c, (byte) 0x53, (byte) 0xcd, (byte) 0xb0, (byte) 0xb6,
+ (byte) 0x90, (byte) 0xce, (byte) 0x7b, (byte) 0xa5, (byte) 0xdb, (byte) 0xab,
+ (byte) 0xfd, (byte) 0xf5, (byte) 0xbb, (byte) 0x49, (byte) 0x63, (byte) 0xb7,
+ (byte) 0xa8, (byte) 0x3e, (byte) 0x53, (byte) 0xf1, (byte) 0x00, (byte) 0x4d,
+ (byte) 0x72, (byte) 0x15, (byte) 0x34, (byte) 0xa8, (byte) 0x5b, (byte) 0x00,
+ (byte) 0x01, (byte) 0x75, (byte) 0xdc, (byte) 0xb6, (byte) 0xd1, (byte) 0xdf,
+ (byte) 0xcb, (byte) 0x93, (byte) 0xf3, (byte) 0x31, (byte) 0x04, (byte) 0x7e,
+ (byte) 0x48, (byte) 0x3e, (byte) 0xc9, (byte) 0xaf, (byte) 0xd7, (byte) 0xbd,
+ (byte) 0x9e, (byte) 0x73, (byte) 0x01, (byte) 0x79, (byte) 0xf8, (byte) 0xdc,
+ (byte) 0x46, (byte) 0x31, (byte) 0x55, (byte) 0x83, (byte) 0x21, (byte) 0xd1,
+ (byte) 0x19, (byte) 0x0b, (byte) 0x57, (byte) 0xf1, (byte) 0x06, (byte) 0xb9,
+ (byte) 0x32, (byte) 0x0e, (byte) 0x9d, (byte) 0x38, (byte) 0x53, (byte) 0x94,
+ (byte) 0x96, (byte) 0xd4, (byte) 0x6d, (byte) 0x18, (byte) 0xe2, (byte) 0xe3,
+ (byte) 0xcd, (byte) 0xfa, (byte) 0xfe, (byte) 0xb3, (byte) 0xe3, (byte) 0x27,
+ (byte) 0xd7, (byte) 0x45, (byte) 0xe8, (byte) 0x46, (byte) 0x6b, (byte) 0x06,
+ (byte) 0x0f, (byte) 0x5e, (byte) 0x24, (byte) 0x02, (byte) 0xef, (byte) 0xa2,
+ (byte) 0x69, (byte) 0xe6, (byte) 0x15, (byte) 0xb3, (byte) 0x8f, (byte) 0x71,
+ (byte) 0x97, (byte) 0x39, (byte) 0xfb, (byte) 0x32, (byte) 0xe0, (byte) 0xe5,
+ (byte) 0xac, (byte) 0x46, (byte) 0xb4, (byte) 0xe7, (byte) 0x3d, (byte) 0x89,
+ (byte) 0xba, (byte) 0xd9, (byte) 0x4c, (byte) 0x25, (byte) 0x97, (byte) 0xef,
+ (byte) 0xe6, (byte) 0x17, (byte) 0x23, (byte) 0x4e, (byte) 0xc8, (byte) 0xdb,
+ (byte) 0x18, (byte) 0x9b, (byte) 0xba, (byte) 0xb5, (byte) 0x7e, (byte) 0x19,
+ (byte) 0x4d, (byte) 0x95, (byte) 0x7d, (byte) 0x60, (byte) 0x1b, (byte) 0xa7,
+ (byte) 0x06, (byte) 0x1e, (byte) 0x99, (byte) 0x4a, (byte) 0xf2, (byte) 0x82,
+ (byte) 0x71, (byte) 0x62, (byte) 0x41, (byte) 0xa4, (byte) 0xa7, (byte) 0xdb,
+ (byte) 0x88, (byte) 0xb0, (byte) 0x4a, (byte) 0xc7, (byte) 0x3b, (byte) 0xce,
+ (byte) 0x91, (byte) 0x4f, (byte) 0xc7, (byte) 0xca, (byte) 0x6f, (byte) 0x89,
+ (byte) 0xac, (byte) 0x1a, (byte) 0x36, (byte) 0x84, (byte) 0x0c, (byte) 0x97,
+ (byte) 0xa0, (byte) 0x1a, (byte) 0x08, (byte) 0x6f, (byte) 0x70, (byte) 0xf3,
+ (byte) 0x94, (byte) 0xa0, (byte) 0x0f, (byte) 0x44, (byte) 0xdd, (byte) 0x86,
+ (byte) 0x9d, (byte) 0x2c, (byte) 0xac, (byte) 0x43, (byte) 0xed, (byte) 0xb8,
+ (byte) 0xa1, (byte) 0x66, (byte) 0xf3, (byte) 0xd3, (byte) 0x5c, (byte) 0xe5,
+ (byte) 0xe2, (byte) 0x4c, (byte) 0x7e, (byte) 0xda, (byte) 0x20, (byte) 0xbd,
+ (byte) 0x5a, (byte) 0x75, (byte) 0x12, (byte) 0x31, (byte) 0x23, (byte) 0x02,
+ (byte) 0xb5, (byte) 0x1f, (byte) 0x38, (byte) 0x98
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha384 -pkeyopt rsa_mgf1_md:sha384 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA384_MGF1_SHA384 = new byte[] {
+ (byte) 0xa1, (byte) 0xb3, (byte) 0x3b, (byte) 0x34, (byte) 0x69, (byte) 0x9e,
+ (byte) 0xd8, (byte) 0xa0, (byte) 0x37, (byte) 0x2c, (byte) 0xeb, (byte) 0xef,
+ (byte) 0xf2, (byte) 0xaf, (byte) 0xfa, (byte) 0x63, (byte) 0x5d, (byte) 0x88,
+ (byte) 0xac, (byte) 0x51, (byte) 0xd4, (byte) 0x7f, (byte) 0x85, (byte) 0xf0,
+ (byte) 0x5e, (byte) 0xb4, (byte) 0x81, (byte) 0x7c, (byte) 0x82, (byte) 0x4f,
+ (byte) 0x92, (byte) 0xf7, (byte) 0x77, (byte) 0x48, (byte) 0x4c, (byte) 0xb1,
+ (byte) 0x42, (byte) 0xb3, (byte) 0x0e, (byte) 0x94, (byte) 0xc8, (byte) 0x5a,
+ (byte) 0xae, (byte) 0xed, (byte) 0x8d, (byte) 0x51, (byte) 0x72, (byte) 0x6b,
+ (byte) 0xa9, (byte) 0xd4, (byte) 0x1e, (byte) 0xbe, (byte) 0x38, (byte) 0x2c,
+ (byte) 0xd0, (byte) 0x43, (byte) 0xae, (byte) 0xb4, (byte) 0x30, (byte) 0xa9,
+ (byte) 0x93, (byte) 0x47, (byte) 0xb5, (byte) 0x9d, (byte) 0x03, (byte) 0x92,
+ (byte) 0x25, (byte) 0x74, (byte) 0xed, (byte) 0xfa, (byte) 0xfe, (byte) 0xf1,
+ (byte) 0xba, (byte) 0x04, (byte) 0x3a, (byte) 0x4d, (byte) 0x6d, (byte) 0x9a,
+ (byte) 0x0d, (byte) 0x95, (byte) 0x02, (byte) 0xb0, (byte) 0xac, (byte) 0x77,
+ (byte) 0x11, (byte) 0x44, (byte) 0xeb, (byte) 0xd2, (byte) 0x02, (byte) 0x90,
+ (byte) 0xea, (byte) 0x2f, (byte) 0x68, (byte) 0x2a, (byte) 0x69, (byte) 0xcf,
+ (byte) 0x45, (byte) 0x34, (byte) 0xff, (byte) 0x00, (byte) 0xc6, (byte) 0x3c,
+ (byte) 0x0b, (byte) 0x2c, (byte) 0x5f, (byte) 0x8c, (byte) 0x2c, (byte) 0xbf,
+ (byte) 0xc2, (byte) 0x4b, (byte) 0x16, (byte) 0x07, (byte) 0x84, (byte) 0x74,
+ (byte) 0xf0, (byte) 0x7a, (byte) 0x01, (byte) 0x7e, (byte) 0x74, (byte) 0x01,
+ (byte) 0x88, (byte) 0xce, (byte) 0xda, (byte) 0xe4, (byte) 0x21, (byte) 0x89,
+ (byte) 0xfc, (byte) 0xac, (byte) 0x68, (byte) 0xdb, (byte) 0xfc, (byte) 0x5f,
+ (byte) 0x3f, (byte) 0x00, (byte) 0xd9, (byte) 0x32, (byte) 0x1d, (byte) 0xa5,
+ (byte) 0xec, (byte) 0x72, (byte) 0x46, (byte) 0x23, (byte) 0xe5, (byte) 0x7f,
+ (byte) 0x49, (byte) 0x0e, (byte) 0x3e, (byte) 0xf2, (byte) 0x2b, (byte) 0x16,
+ (byte) 0x52, (byte) 0x9f, (byte) 0x9d, (byte) 0x0c, (byte) 0xfe, (byte) 0xab,
+ (byte) 0xdd, (byte) 0x77, (byte) 0x77, (byte) 0x94, (byte) 0xa4, (byte) 0x92,
+ (byte) 0xa2, (byte) 0x41, (byte) 0x0d, (byte) 0x4b, (byte) 0x57, (byte) 0x80,
+ (byte) 0xd6, (byte) 0x74, (byte) 0x63, (byte) 0xd5, (byte) 0xbf, (byte) 0x5c,
+ (byte) 0xa0, (byte) 0xda, (byte) 0x3c, (byte) 0xe6, (byte) 0xbf, (byte) 0xa4,
+ (byte) 0xc3, (byte) 0xfb, (byte) 0x46, (byte) 0x3b, (byte) 0x73, (byte) 0x30,
+ (byte) 0x4b, (byte) 0x57, (byte) 0x27, (byte) 0x0c, (byte) 0x81, (byte) 0xde,
+ (byte) 0x8a, (byte) 0x01, (byte) 0xe5, (byte) 0x7e, (byte) 0xe0, (byte) 0x16,
+ (byte) 0x11, (byte) 0x24, (byte) 0x34, (byte) 0x22, (byte) 0x01, (byte) 0x9f,
+ (byte) 0xe6, (byte) 0xa9, (byte) 0xfb, (byte) 0xad, (byte) 0x55, (byte) 0x17,
+ (byte) 0x2a, (byte) 0x92, (byte) 0x87, (byte) 0xf3, (byte) 0x72, (byte) 0xc9,
+ (byte) 0x3d, (byte) 0xc9, (byte) 0x2e, (byte) 0x32, (byte) 0x8e, (byte) 0xbb,
+ (byte) 0xdc, (byte) 0x1b, (byte) 0xa7, (byte) 0x7b, (byte) 0x73, (byte) 0xd7,
+ (byte) 0xf4, (byte) 0xad, (byte) 0xa9, (byte) 0x3a, (byte) 0xf7, (byte) 0xa8,
+ (byte) 0x82, (byte) 0x92, (byte) 0x40, (byte) 0xd4, (byte) 0x51, (byte) 0x87,
+ (byte) 0xe1, (byte) 0xb7, (byte) 0x4f, (byte) 0x91, (byte) 0x75, (byte) 0x5b,
+ (byte) 0x03, (byte) 0x9d, (byte) 0xa1, (byte) 0xd4, (byte) 0x00, (byte) 0x05,
+ (byte) 0x79, (byte) 0x42, (byte) 0x93, (byte) 0x76
+ };
+
+ /*
+ * echo -n 'This is a test of OAEP' | openssl pkeyutl -encrypt -inkey /tmp/rsakey.txt \
+ * -pkeyopt rsa_padding_mode:oaep -pkey rsa_oaep_md:sha512 -pkeyopt rsa_mgf1_md:sha512 \
+ * | xxd -p -i | sed 's/0x/(byte) 0x/g'
+ */
+ public static final byte[] RSA_Vector2_OAEP_SHA512_MGF1_SHA512 = new byte[] {
+ (byte) 0x75, (byte) 0x0f, (byte) 0xf9, (byte) 0x21, (byte) 0xca, (byte) 0xcc,
+ (byte) 0x0e, (byte) 0x13, (byte) 0x9e, (byte) 0x38, (byte) 0xa4, (byte) 0xa7,
+ (byte) 0xee, (byte) 0x61, (byte) 0x6d, (byte) 0x56, (byte) 0xea, (byte) 0x36,
+ (byte) 0xeb, (byte) 0xec, (byte) 0xfa, (byte) 0x1a, (byte) 0xeb, (byte) 0x0c,
+ (byte) 0xb2, (byte) 0x58, (byte) 0x9d, (byte) 0xde, (byte) 0x47, (byte) 0x27,
+ (byte) 0x2d, (byte) 0xbd, (byte) 0x8b, (byte) 0xa7, (byte) 0xf1, (byte) 0x8b,
+ (byte) 0xba, (byte) 0x4c, (byte) 0xab, (byte) 0x39, (byte) 0x6a, (byte) 0x82,
+ (byte) 0x0d, (byte) 0xaf, (byte) 0x4c, (byte) 0xde, (byte) 0xdb, (byte) 0x5e,
+ (byte) 0xdb, (byte) 0x08, (byte) 0x98, (byte) 0x06, (byte) 0xc5, (byte) 0x99,
+ (byte) 0xb6, (byte) 0x6d, (byte) 0xbc, (byte) 0x5b, (byte) 0xf9, (byte) 0xe4,
+ (byte) 0x97, (byte) 0x0b, (byte) 0xba, (byte) 0xe3, (byte) 0x17, (byte) 0xa9,
+ (byte) 0x3c, (byte) 0x4b, (byte) 0x21, (byte) 0xd8, (byte) 0x29, (byte) 0xf8,
+ (byte) 0xa7, (byte) 0x1c, (byte) 0x15, (byte) 0xd7, (byte) 0xf6, (byte) 0xfc,
+ (byte) 0x53, (byte) 0x64, (byte) 0x97, (byte) 0x9e, (byte) 0x22, (byte) 0xb1,
+ (byte) 0x93, (byte) 0x26, (byte) 0x80, (byte) 0xdc, (byte) 0xaa, (byte) 0x1b,
+ (byte) 0xae, (byte) 0x69, (byte) 0x0f, (byte) 0x74, (byte) 0x3d, (byte) 0x61,
+ (byte) 0x80, (byte) 0x68, (byte) 0xb8, (byte) 0xaf, (byte) 0x63, (byte) 0x72,
+ (byte) 0x37, (byte) 0x4f, (byte) 0xf3, (byte) 0x29, (byte) 0x4a, (byte) 0x75,
+ (byte) 0x4f, (byte) 0x29, (byte) 0x40, (byte) 0x01, (byte) 0xd3, (byte) 0xc6,
+ (byte) 0x56, (byte) 0x1a, (byte) 0xaf, (byte) 0xc3, (byte) 0xb3, (byte) 0xd2,
+ (byte) 0xb9, (byte) 0x91, (byte) 0x35, (byte) 0x1b, (byte) 0x89, (byte) 0x4c,
+ (byte) 0x61, (byte) 0xa2, (byte) 0x8e, (byte) 0x6f, (byte) 0x12, (byte) 0x4a,
+ (byte) 0x10, (byte) 0xc2, (byte) 0xcc, (byte) 0xab, (byte) 0x51, (byte) 0xec,
+ (byte) 0x1b, (byte) 0xb5, (byte) 0xfe, (byte) 0x20, (byte) 0x16, (byte) 0xb2,
+ (byte) 0xc5, (byte) 0x0f, (byte) 0xe1, (byte) 0x6a, (byte) 0xb4, (byte) 0x6c,
+ (byte) 0x27, (byte) 0xd9, (byte) 0x42, (byte) 0xb9, (byte) 0xb6, (byte) 0x55,
+ (byte) 0xa8, (byte) 0xbc, (byte) 0x1c, (byte) 0x32, (byte) 0x54, (byte) 0x84,
+ (byte) 0xec, (byte) 0x1e, (byte) 0x95, (byte) 0xd8, (byte) 0xae, (byte) 0xca,
+ (byte) 0xc1, (byte) 0xad, (byte) 0x4c, (byte) 0x65, (byte) 0xd6, (byte) 0xc2,
+ (byte) 0x19, (byte) 0x66, (byte) 0xad, (byte) 0x9f, (byte) 0x55, (byte) 0x15,
+ (byte) 0xe1, (byte) 0x5d, (byte) 0x8f, (byte) 0xab, (byte) 0x18, (byte) 0x68,
+ (byte) 0x42, (byte) 0x7c, (byte) 0x48, (byte) 0xb7, (byte) 0x2c, (byte) 0xfd,
+ (byte) 0x1a, (byte) 0x07, (byte) 0xa1, (byte) 0x6a, (byte) 0xfb, (byte) 0x81,
+ (byte) 0xc6, (byte) 0x93, (byte) 0xbf, (byte) 0xa3, (byte) 0x5d, (byte) 0xfd,
+ (byte) 0xce, (byte) 0xf3, (byte) 0x17, (byte) 0x26, (byte) 0xf0, (byte) 0xda,
+ (byte) 0x0e, (byte) 0xd1, (byte) 0x86, (byte) 0x9d, (byte) 0x61, (byte) 0xd1,
+ (byte) 0x8a, (byte) 0xdb, (byte) 0x36, (byte) 0x39, (byte) 0x1c, (byte) 0xd4,
+ (byte) 0x99, (byte) 0x53, (byte) 0x30, (byte) 0x5a, (byte) 0x01, (byte) 0xf4,
+ (byte) 0xa0, (byte) 0xca, (byte) 0x94, (byte) 0x72, (byte) 0x3d, (byte) 0xe3,
+ (byte) 0x50, (byte) 0x95, (byte) 0xcb, (byte) 0xa9, (byte) 0x37, (byte) 0xeb,
+ (byte) 0x66, (byte) 0x21, (byte) 0x20, (byte) 0x2e, (byte) 0xf2, (byte) 0xfd,
+ (byte) 0xfa, (byte) 0x54, (byte) 0xbf, (byte) 0x17, (byte) 0x23, (byte) 0xbb,
+ (byte) 0x9e, (byte) 0x77, (byte) 0xe0, (byte) 0xaa
+ };
public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success() throws Exception {
for (String provider : RSA_PROVIDERS) {
@@ -2127,11 +2525,7 @@
}
private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2158,11 +2552,7 @@
}
private void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2193,11 +2583,7 @@
private void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(String provider)
throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2231,10 +2617,7 @@
}
private void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2268,10 +2651,7 @@
}
private void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
-
- final PublicKey privKey = kf.generatePublic(keySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2280,11 +2660,11 @@
* distinction made here. It's all keyed off of what kind of key you're
* using. ENCRYPT_MODE and DECRYPT_MODE are the same.
*/
- c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
- c.init(Cipher.DECRYPT_MODE, privKey);
+ c.init(Cipher.DECRYPT_MODE, pubKey);
encrypted = c.doFinal(RSA_Vector1_Encrypt_Private);
assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
}
@@ -2296,10 +2676,7 @@
}
private void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
-
- final PublicKey pubKey = kf.generatePublic(keySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2334,10 +2711,7 @@
}
private void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
-
- final PublicKey privKey = kf.generatePublic(keySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2346,12 +2720,12 @@
* distinction made here. It's all keyed off of what kind of key you're
* using. ENCRYPT_MODE and DECRYPT_MODE are the same.
*/
- c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
c.update(RSA_Vector1_Encrypt_Private);
byte[] encrypted = c.doFinal();
assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
- c.init(Cipher.DECRYPT_MODE, privKey);
+ c.init(Cipher.DECRYPT_MODE, pubKey);
c.update(RSA_Vector1_Encrypt_Private);
encrypted = c.doFinal();
assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted);
@@ -2366,10 +2740,7 @@
private void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(String provider)
throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
-
- final PublicKey privKey = kf.generatePublic(keySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2378,7 +2749,7 @@
* distinction made here. It's all keyed off of what kind of key you're
* using. ENCRYPT_MODE and DECRYPT_MODE are the same.
*/
- c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
int i;
for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
c.update(RSA_Vector1_Encrypt_Private, i, 1);
@@ -2386,7 +2757,7 @@
byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i);
assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted);
- c.init(Cipher.DECRYPT_MODE, privKey);
+ c.init(Cipher.DECRYPT_MODE, pubKey);
for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) {
c.update(RSA_Vector1_Encrypt_Private, i, 1);
}
@@ -2401,10 +2772,7 @@
}
private void testRSA_ECB_NoPadding_Public_TooSmall_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent);
-
- final PublicKey privKey = kf.generatePublic(keySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2413,12 +2781,12 @@
* distinction made here. It's all keyed off of what kind of key you're
* using. ENCRYPT_MODE and DECRYPT_MODE are the same.
*/
- c.init(Cipher.ENCRYPT_MODE, privKey);
+ c.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] encrypted = c.doFinal(TooShort_Vector);
assertTrue("Encrypted should match expected",
Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
- c.init(Cipher.DECRYPT_MODE, privKey);
+ c.init(Cipher.DECRYPT_MODE, pubKey);
encrypted = c.doFinal(TooShort_Vector);
assertTrue("Encrypted should match expected",
Arrays.equals(RSA_Vector1_ZeroPadded_Encrypted, encrypted));
@@ -2431,11 +2799,7 @@
}
private void testRSA_ECB_NoPadding_Private_TooSmall_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2481,11 +2845,7 @@
private void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(String provider)
throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2516,11 +2876,7 @@
private void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(String provider)
throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2552,11 +2908,7 @@
}
private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
- RSA_2048_privateExponent);
-
- final PrivateKey privKey = kf.generatePrivate(keySpec);
+ final PrivateKey privKey = (PrivateKey) getDecryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
@@ -2601,10 +2953,7 @@
}
}
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
- RSA_2048_publicExponent);
- final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
c.init(Cipher.ENCRYPT_MODE, pubKey);
assertEquals(getExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, provider), c.getBlockSize());
}
@@ -2631,10 +2980,7 @@
}
private void testRSA_ECB_NoPadding_GetOutputSize_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
- RSA_2048_publicExponent);
- final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
c.init(Cipher.ENCRYPT_MODE, pubKey);
@@ -2652,10 +2998,7 @@
}
private void testRSA_ECB_NoPadding_GetIV_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
- RSA_2048_publicExponent);
- final PublicKey pubKey = kf.generatePublic(pubKeySpec);
+ final PublicKey pubKey = (PublicKey) getEncryptKey("RSA");
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
assertNull("ECB mode has no IV and should be null", c.getIV());
@@ -2672,11 +3015,6 @@
}
private void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(String provider) throws Exception {
- KeyFactory kf = KeyFactory.getInstance("RSA");
- RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus,
- RSA_2048_publicExponent);
- final PublicKey pubKey = kf.generatePublic(pubKeySpec);
-
Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider);
assertNull("Parameters should be null", c.getParameters());
}
@@ -2685,85 +3023,77 @@
* Test vector generation:
* openssl rand -hex 16 | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] DES_112_KEY = new byte[] {
+ private static final SecretKeySpec DES_112_KEY = new SecretKeySpec(new byte[] {
(byte) 0x6b, (byte) 0xb3, (byte) 0x85, (byte) 0x1c, (byte) 0x3d, (byte) 0x50,
(byte) 0xd4, (byte) 0x95, (byte) 0x39, (byte) 0x48, (byte) 0x77, (byte) 0x30,
(byte) 0x1a, (byte) 0xd7, (byte) 0x86, (byte) 0x57,
- };
+ }, "DESede");
/*
* Test vector generation:
* openssl rand -hex 24 | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] DES_168_KEY = new byte[] {
+ private static final SecretKeySpec DES_168_KEY = new SecretKeySpec(new byte[] {
(byte) 0xfe, (byte) 0xd4, (byte) 0xd7, (byte) 0xc9, (byte) 0x8a, (byte) 0x13,
(byte) 0x6a, (byte) 0xa8, (byte) 0x5a, (byte) 0xb8, (byte) 0x19, (byte) 0xb8,
(byte) 0xcf, (byte) 0x3c, (byte) 0x5f, (byte) 0xe0, (byte) 0xa2, (byte) 0xf7,
(byte) 0x7b, (byte) 0x65, (byte) 0x43, (byte) 0xc0, (byte) 0xc4, (byte) 0xe1,
- };
+ }, "DESede");
/*
* Test vector generation:
* openssl rand -hex 5 | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] ARC4_40BIT_KEY = new byte[] {
+ private static final SecretKeySpec ARC4_40BIT_KEY = new SecretKeySpec(new byte[] {
(byte) 0x9c, (byte) 0xc8, (byte) 0xb9, (byte) 0x94, (byte) 0x98,
- };
+ }, "ARC4");
/*
* Test vector generation:
* openssl rand -hex 24 | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] ARC4_128BIT_KEY = new byte[] {
+ private static final SecretKeySpec ARC4_128BIT_KEY = new SecretKeySpec(new byte[] {
(byte) 0xbc, (byte) 0x0a, (byte) 0x3c, (byte) 0xca, (byte) 0xb5, (byte) 0x42,
(byte) 0xfa, (byte) 0x5d, (byte) 0x86, (byte) 0x5b, (byte) 0x44, (byte) 0x87,
(byte) 0x83, (byte) 0xd8, (byte) 0xcb, (byte) 0xd4,
- };
+ }, "ARC4");
/*
* Test vector generation:
* openssl rand -hex 16
* echo '3d4f8970b1f27537f40a39298a41555f' | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] AES_128_KEY = new byte[] {
+ private static final SecretKeySpec AES_128_KEY = new SecretKeySpec(new byte[] {
(byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2,
(byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29,
(byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f,
- };
+ }, "AES");
/*
* Test key generation:
* openssl rand -hex 24
* echo '5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342' | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] AES_192_KEY = new byte[] {
+ private static final SecretKeySpec AES_192_KEY = new SecretKeySpec(new byte[] {
(byte) 0x5a, (byte) 0x7a, (byte) 0x3d, (byte) 0x7e, (byte) 0x40, (byte) 0xb6,
(byte) 0x4e, (byte) 0xd9, (byte) 0x96, (byte) 0xf7, (byte) 0xaf, (byte) 0xa1,
(byte) 0x5f, (byte) 0x97, (byte) 0xfd, (byte) 0x59, (byte) 0x5e, (byte) 0x27,
(byte) 0xdb, (byte) 0x6a, (byte) 0xf4, (byte) 0x28, (byte) 0xe3, (byte) 0x42,
- };
+ }, "AES");
/*
* Test key generation:
* openssl rand -hex 32
* echo 'ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935' | sed 's/\(..\)/(byte) 0x\1, /g'
*/
- private static final byte[] AES_256_KEY = new byte[] {
+ private static final SecretKeySpec AES_256_KEY = new SecretKeySpec(new byte[] {
(byte) 0xec, (byte) 0x53, (byte) 0xc6, (byte) 0xd5, (byte) 0x1d, (byte) 0x2c,
(byte) 0x49, (byte) 0x73, (byte) 0x58, (byte) 0x5f, (byte) 0xb0, (byte) 0xb8,
(byte) 0xe5, (byte) 0x1c, (byte) 0xd2, (byte) 0xe3, (byte) 0x99, (byte) 0x15,
(byte) 0xff, (byte) 0x07, (byte) 0xa1, (byte) 0x83, (byte) 0x78, (byte) 0x72,
(byte) 0x71, (byte) 0x5d, (byte) 0x61, (byte) 0x21, (byte) 0xbf, (byte) 0x86,
(byte) 0x19, (byte) 0x35,
- };
-
- private static final String[] AES_MODES = new String[] {
- "AES/ECB",
- "AES/CBC",
- "AES/CFB",
- "AES/CTR",
- "AES/OFB",
- };
+ }, "AES");
/*
* Test vector generation:
@@ -2887,11 +3217,11 @@
/*
* Taken from BoringSSL test vectors.
*/
- private static final byte[] AES_128_GCM_TestVector_1_Key = new byte[] {
+ private static final SecretKeySpec AES_128_GCM_TestVector_1_Key = new SecretKeySpec(new byte[] {
(byte) 0xca, (byte) 0xbd, (byte) 0xcf, (byte) 0x54, (byte) 0x1a, (byte) 0xeb,
(byte) 0xf9, (byte) 0x17, (byte) 0xba, (byte) 0xc0, (byte) 0x19, (byte) 0xf1,
(byte) 0x39, (byte) 0x25, (byte) 0xd2, (byte) 0x67,
- };
+ }, "AES");
/*
* Taken from BoringSSL test vectors.
@@ -3058,11 +3388,11 @@
private static class CipherTestParam {
public final String transformation;
- public final byte[] key;
+ public final AlgorithmParameterSpec spec;
- public final String keyAlgorithm;
+ public final Key encryptKey;
- public final byte[] iv;
+ public final Key decryptKey;
public final byte[] aad;
@@ -3074,13 +3404,13 @@
public final boolean isStreamCipher;
- public CipherTestParam(String transformation, String keyAlgorithm, byte[] key, byte[] iv,
- byte[] aad, byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext,
- boolean isStreamCipher) {
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key encryptKey,
+ Key decryptKey, byte[] aad, byte[] plaintext, byte[] plaintextPadded,
+ byte[] ciphertext, boolean isStreamCipher) {
this.transformation = transformation.toUpperCase(Locale.ROOT);
- this.keyAlgorithm = keyAlgorithm;
- this.key = key;
- this.iv = iv;
+ this.spec = spec;
+ this.encryptKey = encryptKey;
+ this.decryptKey = decryptKey;
this.aad = aad;
this.plaintext = plaintext;
this.plaintextPadded = plaintextPadded;
@@ -3088,20 +3418,34 @@
this.isStreamCipher = isStreamCipher;
}
- public CipherTestParam(String transformation, String keyAlgorithm, byte[] key, byte[] iv,
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key key,
+ byte[] aad, byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext,
+ boolean isStreamCipher) {
+ this(transformation, spec, key, key, aad, plaintext, plaintextPadded, ciphertext,
+ isStreamCipher);
+ }
+
+ public CipherTestParam(String transformation, AlgorithmParameterSpec spec, Key key,
byte[] aad, byte[] plaintext, byte[] plaintextPadded, byte[] ciphertext) {
- this(transformation, keyAlgorithm, key, iv, aad, plaintext, plaintextPadded, ciphertext,
+ this(transformation, spec, key, aad, plaintext, plaintextPadded, ciphertext,
false /* isStreamCipher */);
}
}
+ private static class OAEPCipherTestParam extends CipherTestParam {
+ public OAEPCipherTestParam(String transformation, OAEPParameterSpec spec,
+ PublicKey encryptKey, PrivateKey decryptKey, byte[] plaintext, byte[] ciphertext) {
+ super(transformation, spec, encryptKey, decryptKey, null, plaintext, plaintext, ciphertext,
+ false);
+ }
+ }
+
private static List<CipherTestParam> DES_CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
static {
DES_CIPHER_TEST_PARAMS.add(new CipherTestParam(
"DESede/CBC/PKCS5Padding",
- "DESede",
+ new IvParameterSpec(DES_IV1),
DES_112_KEY,
- DES_IV1,
null,
DES_Plaintext1,
DES_Plaintext1_PKCS5_Padded,
@@ -3109,9 +3453,8 @@
));
DES_CIPHER_TEST_PARAMS.add(new CipherTestParam(
"DESede/CBC/PKCS5Padding",
- "DESede",
+ new IvParameterSpec(DES_IV1),
DES_168_KEY,
- DES_IV1,
null,
DES_Plaintext1,
DES_Plaintext1_PKCS5_Padded,
@@ -3123,9 +3466,8 @@
static {
ARC4_CIPHER_TEST_PARAMS.add(new CipherTestParam(
"ARC4",
- "ARC4",
+ null,
ARC4_40BIT_KEY,
- null, // IV,
null, // aad
ARC4_Plaintext1,
null, // padded
@@ -3134,9 +3476,8 @@
));
ARC4_CIPHER_TEST_PARAMS.add(new CipherTestParam(
"ARC4",
- "ARC4",
+ null,
ARC4_128BIT_KEY,
- null, // IV,
null, // aad
ARC4_Plaintext1,
null, // padded
@@ -3147,42 +3488,55 @@
private static List<CipherTestParam> CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
static {
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS5Padding", "AES", AES_128_KEY,
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/ECB/PKCS5Padding",
null,
+ AES_128_KEY,
null,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
// PKCS#5 is assumed to be equivalent to PKCS#7 -- same test vectors are thus used for both.
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB/PKCS7Padding", "AES", AES_128_KEY,
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/ECB/PKCS7Padding",
null,
+ AES_128_KEY,
null,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/GCM/NOPADDING",
- "AES",
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/GCM/NOPADDING",
+ new GCMParameterSpec(
+ (AES_128_GCM_TestVector_1_Encrypted.length -
+ AES_128_GCM_TestVector_1_Plaintext.length) * 8,
+ AES_128_GCM_TestVector_1_IV),
AES_128_GCM_TestVector_1_Key,
- AES_128_GCM_TestVector_1_IV,
AES_128_GCM_TestVector_1_AAD,
AES_128_GCM_TestVector_1_Plaintext,
AES_128_GCM_TestVector_1_Plaintext,
AES_128_GCM_TestVector_1_Encrypted));
if (IS_UNLIMITED) {
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CTR/NoPadding", "AES", AES_192_KEY,
- AES_192_CTR_NoPadding_TestVector_1_IV,
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CTR/NoPadding",
+ new IvParameterSpec(AES_192_CTR_NoPadding_TestVector_1_IV),
+ AES_192_KEY,
null,
AES_192_CTR_NoPadding_TestVector_1_Plaintext,
AES_192_CTR_NoPadding_TestVector_1_Plaintext,
AES_192_CTR_NoPadding_TestVector_1_Ciphertext));
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS5Padding", "AES", AES_256_KEY,
- AES_256_CBC_PKCS5Padding_TestVector_1_IV,
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CBC/PKCS5Padding",
+ new IvParameterSpec(AES_256_CBC_PKCS5Padding_TestVector_1_IV),
+ AES_256_KEY,
null,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext));
- CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC/PKCS7Padding", "AES", AES_256_KEY,
- AES_256_CBC_PKCS5Padding_TestVector_1_IV,
+ CIPHER_TEST_PARAMS.add(new CipherTestParam(
+ "AES/CBC/PKCS7Padding",
+ new IvParameterSpec(AES_256_CBC_PKCS5Padding_TestVector_1_IV),
+ AES_256_KEY,
null,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext,
AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded,
@@ -3190,6 +3544,44 @@
}
}
+ private static final List<CipherTestParam> RSA_OAEP_CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ addRsaOaepTest("SHA-1", MGF1ParameterSpec.SHA1, RSA_Vector2_OAEP_SHA1_MGF1_SHA1);
+ addRsaOaepTest("SHA-256", MGF1ParameterSpec.SHA1, RSA_Vector2_OAEP_SHA256_MGF1_SHA1);
+ addRsaOaepTest("SHA-224", MGF1ParameterSpec.SHA224, RSA_Vector2_OAEP_SHA224_MGF1_SHA224);
+ addRsaOaepTest("SHA-256", MGF1ParameterSpec.SHA256, RSA_Vector2_OAEP_SHA256_MGF1_SHA256);
+ addRsaOaepTest("SHA-384", MGF1ParameterSpec.SHA384, RSA_Vector2_OAEP_SHA384_MGF1_SHA384);
+ addRsaOaepTest("SHA-512", MGF1ParameterSpec.SHA512, RSA_Vector2_OAEP_SHA512_MGF1_SHA512);
+ }
+
+ private static void addRsaOaepTest(String digest, MGF1ParameterSpec mgf1Spec, byte[] vector) {
+ if (mgf1Spec.getDigestAlgorithm().equals(digest)) {
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPWith" + digest + "AndMGF1Padding",
+ null,
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPWith" + digest + "AndMGF1Padding",
+ new OAEPParameterSpec(digest, "MGF1", mgf1Spec, PSource.PSpecified.DEFAULT),
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+ }
+
+ RSA_OAEP_CIPHER_TEST_PARAMS.add(new OAEPCipherTestParam(
+ "RSA/ECB/OAEPPadding",
+ new OAEPParameterSpec(digest, "MGF1", mgf1Spec, PSource.PSpecified.DEFAULT),
+ (PublicKey) getEncryptKey("RSA"),
+ (PrivateKey) getDecryptKey("RSA"),
+ RSA_Vector2_Plaintext,
+ vector));
+ }
+
public void testCipher_Success() throws Exception {
for (String provider : AES_PROVIDERS) {
testCipher_Success(provider);
@@ -3199,6 +3591,8 @@
DES_CIPHER_TEST_PARAMS);
testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
ARC4_CIPHER_TEST_PARAMS);
+ testCipher_Success_ForAllSupportingProviders_AtLeastOneProviderRequired(
+ RSA_OAEP_CIPHER_TEST_PARAMS);
}
/**
@@ -3211,19 +3605,39 @@
ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
PrintStream out = new PrintStream(errBuffer);
for (CipherTestParam testVector : testVectors) {
- Provider[] providers = Security.getProviders("Cipher." + testVector.transformation);
- if ((providers == null) || (providers.length == 0)) {
+ ArrayList<Provider> providers = new ArrayList<>();
+
+ Provider[] providerArray = Security.getProviders("Cipher." + testVector.transformation);
+ if (providerArray != null) {
+ Collections.addAll(providers, providerArray);
+ }
+
+ if (testVector.transformation.indexOf('/') > 0) {
+ Provider[] baseTransformProviderArray = Security.getProviders("Cipher."
+ + testVector.transformation.substring(
+ 0, testVector.transformation.indexOf('/')));
+ if (baseTransformProviderArray != null) {
+ Collections.addAll(providers, baseTransformProviderArray);
+ }
+ }
+
+ if (providers.isEmpty()) {
out.append("No providers offer " + testVector.transformation + "\n");
continue;
}
+
for (Provider provider : providers) {
+ // Do not test AndroidKeyStore's Signature. It needs an AndroidKeyStore-specific key.
+ // It's OKish not to test AndroidKeyStore's Signature here because it's tested
+ // by cts/tests/test/keystore.
+ if (provider.getName().startsWith("AndroidKeyStore")) {
+ continue;
+ }
+
try {
checkCipher(testVector, provider.getName());
} catch (Throwable e) {
- out.append("Error encountered checking " + testVector.transformation
- + ", keySize=" + (testVector.key.length * 8) + " with provider "
- + provider.getName() + "\n");
- e.printStackTrace(out);
+ logTestFailure(out, provider.getName(), testVector, e);
}
}
}
@@ -3239,12 +3653,8 @@
for (CipherTestParam p : CIPHER_TEST_PARAMS) {
try {
checkCipher(p, provider);
- } catch (Exception e) {
- out.append("Error encountered checking " + p.transformation + ", keySize="
- + (p.key.length * 8)
- + " with provider " + provider + "\n");
-
- e.printStackTrace(out);
+ } catch (Throwable e) {
+ logTestFailure(out, provider, p, e);
}
}
out.flush();
@@ -3253,34 +3663,49 @@
}
}
- private void checkCipher(CipherTestParam p, String provider) throws Exception {
- SecretKey key = new SecretKeySpec(p.key, p.keyAlgorithm);
- Cipher c = Cipher.getInstance(p.transformation, provider);
+ private void logTestFailure(PrintStream logStream, String provider, CipherTestParam params,
+ Throwable e) {
+ logStream.append("Error encountered checking " + params.transformation);
- AlgorithmParameterSpec spec = null;
- if (p.iv != null) {
- if (isAEAD(p.transformation)) {
- spec = new GCMParameterSpec((p.ciphertext.length - p.plaintext.length) * 8, p.iv);
- } else {
- spec = new IvParameterSpec(p.iv);
- }
+ if (params.encryptKey instanceof SecretKey) {
+ logStream.append(", keySize=" + (params.encryptKey.getEncoded().length * 8));
}
- c.init(Cipher.ENCRYPT_MODE, key, spec);
+ if (params.spec instanceof OAEPParameterSpec) {
+ OAEPParameterSpec oaepSpec = (OAEPParameterSpec) params.spec;
+ logStream.append(", OAEPSpec{digest=" + oaepSpec.getDigestAlgorithm() + ", mgfAlg="
+ + oaepSpec.getMGFAlgorithm());
+ if (oaepSpec.getMGFParameters() instanceof MGF1ParameterSpec) {
+ MGF1ParameterSpec mgf1Spec = (MGF1ParameterSpec) oaepSpec.getMGFParameters();
+ logStream.append(", mgf1Hash=" + mgf1Spec.getDigestAlgorithm());
+ }
+ logStream.append('}');
+ }
+
+ logStream.append(" with provider " + provider + "\n");
+ e.printStackTrace(logStream);
+ }
+
+ private void checkCipher(CipherTestParam p, String provider) throws Exception {
+ Cipher c = Cipher.getInstance(p.transformation, provider);
+
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey, p.spec);
if (p.aad != null) {
c.updateAAD(p.aad);
}
final byte[] actualCiphertext = c.doFinal(p.plaintext);
- assertEquals(p.transformation + " " + provider, Arrays.toString(p.ciphertext),
- Arrays.toString(actualCiphertext));
+ if (!isRandomizedEncryption(p.transformation)) {
+ assertEquals(p.transformation + " " + provider, Arrays.toString(p.ciphertext),
+ Arrays.toString(actualCiphertext));
+ }
c = Cipher.getInstance(p.transformation, provider);
- c.init(Cipher.ENCRYPT_MODE, key, spec);
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey, p.spec);
byte[] emptyCipherText = c.doFinal();
assertNotNull(emptyCipherText);
- c.init(Cipher.DECRYPT_MODE, key, spec);
+ c.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
if (!isAEAD(p.transformation)) {
try {
@@ -3293,9 +3718,14 @@
try {
byte[] emptyPlainText = c.doFinal(emptyCipherText);
assertEquals(Arrays.toString(new byte[0]), Arrays.toString(emptyPlainText));
- } catch (AEADBadTagException e) {
+ } catch (AEADBadTagException maybe) {
if (!"AndroidOpenSSL".equals(provider) || !isAEAD(p.transformation)) {
- throw e;
+ throw maybe;
+ }
+ } catch (BadPaddingException maybe) {
+ // BC's OAEP has a bug where it doesn't support empty decrypt
+ if (!("BC".equals(provider) && p.transformation.contains("OAEP"))) {
+ throw maybe;
}
}
@@ -3323,6 +3753,11 @@
if (!isAEAD(p.transformation)) {
throw maybe;
}
+ } catch (BadPaddingException maybe) {
+ // BC's OAEP has a bug where it doesn't support empty decrypt
+ if (!("BC".equals(provider) && p.transformation.contains("OAEP"))) {
+ throw maybe;
+ }
}
try {
c.update(new byte[0]);
@@ -3336,6 +3771,11 @@
if (!isAEAD(p.transformation)) {
throw maybe;
}
+ } catch (BadPaddingException maybe) {
+ // BC's OAEP has a bug where it doesn't support empty decrypt
+ if (!("BC".equals(provider) && p.transformation.contains("OAEP"))) {
+ throw maybe;
+ }
}
} else {
throw new AssertionError("Define your behavior here for " + provider);
@@ -3343,7 +3783,7 @@
}
// Cipher might be in unspecified state from failures above.
- c.init(Cipher.DECRYPT_MODE, key, spec);
+ c.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
// .doFinal(input)
{
@@ -3392,10 +3832,11 @@
Arrays.toString(Arrays.copyOfRange(actualPlaintext, 1, p.plaintext.length + 1)));
}
- if (!p.isStreamCipher && !p.transformation.endsWith("NOPADDING")) {
+ if (!p.isStreamCipher && !p.transformation.endsWith("NOPADDING")
+ && !isRandomizedEncryption(p.transformation)) {
Cipher cNoPad = Cipher.getInstance(
getCipherTransformationWithNoPadding(p.transformation), provider);
- cNoPad.init(Cipher.DECRYPT_MODE, key, spec);
+ cNoPad.init(Cipher.DECRYPT_MODE, p.decryptKey, p.spec);
if (p.aad != null) {
c.updateAAD(p.aad);
@@ -3414,11 +3855,11 @@
// Wrap it
c = Cipher.getInstance(p.transformation, provider);
- c.init(Cipher.WRAP_MODE, key, spec);
+ c.init(Cipher.WRAP_MODE, p.encryptKey, p.spec);
byte[] cipherText = c.wrap(sk);
// Unwrap it
- c.init(Cipher.UNWRAP_MODE, key, spec);
+ c.init(Cipher.UNWRAP_MODE, p.decryptKey, p.spec);
Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY);
assertEquals(
@@ -3556,10 +3997,7 @@
try {
checkCipher_ShortBlock_Failure(p, provider);
} catch (Exception e) {
- out.append("Error encountered checking " + p.transformation + ", keySize="
- + (p.key.length * 8)
- + " with provider " + provider + "\n");
- e.printStackTrace(out);
+ logTestFailure(out, provider, p, e);
}
}
out.flush();
@@ -3639,9 +4077,8 @@
}
public void testCipher_Update_WithZeroLengthInput_ReturnsNull() throws Exception {
- SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
- c.init(Cipher.ENCRYPT_MODE, key);
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
assertNull(c.update(new byte[0]));
assertNull(c.update(new byte[c.getBlockSize() * 2], 0, 0));
@@ -3713,7 +4150,6 @@
return;
}
- SecretKey key = new SecretKeySpec(p.key, "AES");
Cipher c = Cipher.getInstance(
getCipherTransformationWithNoPadding(p.transformation), provider);
if (c.getBlockSize() == 0) {
@@ -3721,7 +4157,7 @@
}
if (!p.transformation.endsWith("NOPADDING")) {
- c.init(Cipher.ENCRYPT_MODE, key);
+ c.init(Cipher.ENCRYPT_MODE, p.encryptKey);
try {
c.doFinal(new byte[] { 0x01, 0x02, 0x03 });
fail("Should throw IllegalBlockSizeException on wrong-sized block; transform="
@@ -3761,9 +4197,8 @@
}
private void testAES_ECB_PKCS5Padding_ShortBuffer_Failure(String provider) throws Exception {
- SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding", provider);
- c.init(Cipher.ENCRYPT_MODE, key);
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
final byte[] fragmentOutput = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext);
if (fragmentOutput != null) {
@@ -3815,10 +4250,9 @@
}
private void testAES_ECB_NoPadding_IncrementalUpdate_Success(String provider) throws Exception {
- SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider);
assertEquals(provider, c.getProvider().getName());
- c.init(Cipher.ENCRYPT_MODE, key);
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY);
for (int i = 0; i < AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1; i++) {
final byte[] outputFragment = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, i, 1);
@@ -3849,12 +4283,11 @@
}
private void testAES_ECB_NoPadding_IvParameters_Failure(String provider) throws Exception {
- SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider);
AlgorithmParameterSpec spec = new IvParameterSpec(AES_IV_ZEROES);
try {
- c.init(Cipher.ENCRYPT_MODE, key, spec);
+ c.init(Cipher.ENCRYPT_MODE, AES_128_KEY, spec);
fail("Should not accept an IV in ECB mode; provider=" + provider);
} catch (InvalidAlgorithmParameterException expected) {
}
@@ -4122,17 +4555,27 @@
assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
- // .doFinal should also reset the state, so check that as well.
+ // .doFinal should also not allow reuse without re-initialization
byte[] aad2 = new byte[] {
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
};
+ try {
+ c1.updateAAD(aad2);
+ fail("Should not allow updateAAD without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
- Cipher c3 = Cipher.getInstance("AES/GCM/NoPadding");
- c3.init(Cipher.ENCRYPT_MODE, key, spec);
+ try {
+ c1.update(new byte[8]);
+ fail("Should not allow update without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
- c1.updateAAD(aad2);
- c3.updateAAD(aad2);
- assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c3.doFinal()));
+ try {
+ c1.doFinal();
+ fail("Should not allow doFinal without re-initialization");
+ } catch (IllegalStateException expected) {
+ }
}
/**
@@ -4205,9 +4648,8 @@
private static Cipher createAesCipher(int opmode) {
try {
- SecretKey key = new SecretKeySpec(AES_128_KEY, "AES");
final Cipher c = Cipher.getInstance("AES/ECB/NoPadding");
- c.init(opmode, key);
+ c.init(opmode, AES_128_KEY);
return c;
} catch (Exception e) {
fail("Unexpected Exception: " + e.getMessage());
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 603baa1..f23c48b 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLContextTest.java
@@ -582,6 +582,20 @@
testContext.close();
}
+ public void test_SSLContext_SSLv3Unsupported() throws Exception {
+ try {
+ SSLContext context = SSLContext.getInstance("SSLv3");
+ fail("SSLv3 should not be supported");
+ } catch (NoSuchAlgorithmException expected) {
+ }
+
+ try {
+ SSLContext context = SSLContext.getInstance("SSL");
+ fail("SSL should not be supported");
+ } catch (NoSuchAlgorithmException expected) {
+ }
+ }
+
private static void assertContentsInOrder(List<String> expected, String... actual) {
if (expected.size() != actual.length) {
fail("Unexpected length. Expected len <" + expected.size()
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
index 8990f62..1628260 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLEngineTest.java
@@ -220,8 +220,7 @@
assertConnected(pair);
boolean needsRecordSplit =
- ("TLS".equalsIgnoreCase(c.clientContext.getProtocol())
- || "SSLv3".equalsIgnoreCase(c.clientContext.getProtocol()))
+ "TLS".equalsIgnoreCase(c.clientContext.getProtocol())
&& cipherSuite.contains("_CBC_");
assertSendsCorrectly("This is the client. Hello!".getBytes(),
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 5e94b21..d2ad9fd 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -1992,14 +1992,14 @@
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Void> s = executor.submit(new Callable<Void>() {
public Void call() throws Exception {
- server.setEnabledProtocols(new String[] { "TLSv1", "SSLv3" });
+ server.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1.1" });
server.startHandshake();
return null;
}
});
Future<Void> c = executor.submit(new Callable<Void>() {
public Void call() throws Exception {
- client.setEnabledProtocols(new String[] { "SSLv3" });
+ client.setEnabledProtocols(new String[] { "TLSv1.1" });
client.startHandshake();
return null;
}
@@ -2035,7 +2035,7 @@
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Void> s = executor.submit(new Callable<Void>() {
public Void call() throws Exception {
- server.setEnabledProtocols(new String[] { "TLSv1", "SSLv3" });
+ server.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1" });
server.setEnabledCipherSuites(serverCipherSuites);
try {
server.startHandshake();
@@ -2050,7 +2050,7 @@
});
Future<Void> c = executor.submit(new Callable<Void>() {
public Void call() throws Exception {
- client.setEnabledProtocols(new String[] { "SSLv3" });
+ client.setEnabledProtocols(new String[] { "TLSv1" });
client.setEnabledCipherSuites(clientCipherSuites);
try {
client.startHandshake();
@@ -2219,6 +2219,25 @@
context.close();
}
+ public void test_SSLSocket_SSLv3Unsupported() throws Exception {
+ TestSSLContext context = TestSSLContext.create();
+
+ final SSLSocket client = (SSLSocket)
+ context.clientContext.getSocketFactory().createSocket();
+
+ try {
+ client.setEnabledProtocols(new String[] {"SSLv3"});
+ fail("SSLSocket should not support SSLv3 protocol");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ client.setEnabledProtocols(new String[] {"SSL"});
+ fail("SSLSocket should not support SSL protocol");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
/**
* Not run by default by JUnit, but can be run by Vogar by
* specifying it explicitly (or with main method below)
diff --git a/luni/src/test/java/libcore/sun/invoke/util/VerifyAccessTest.java b/luni/src/test/java/libcore/sun/invoke/util/VerifyAccessTest.java
new file mode 100644
index 0000000..0c02754
--- /dev/null
+++ b/luni/src/test/java/libcore/sun/invoke/util/VerifyAccessTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 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 libcore.sun.invoke.util;
+
+
+import junit.framework.TestCase;
+import sun.invoke.util.VerifyAccess;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.Locale;
+import java.util.Vector;
+
+
+public class VerifyAccessTest extends TestCase {
+ public void testIsClassAccessible() {
+ // Always returns false when allowedModes == 0. Note that the "modes" allowed here
+ // are different from the ones used in MethodHandles.
+ assertFalse(VerifyAccess.isClassAccessible(Inner1.class, Inner2.class, 0));
+
+ // Classes in the same package are accessible when Lookup.PACKAGE is specified.
+ assertTrue(VerifyAccess.isClassAccessible(Inner1.class, Inner2.class,
+ MethodHandles.Lookup.PACKAGE));
+ assertTrue(VerifyAccess.isClassAccessible(Inner1.class, Sibling.class,
+ MethodHandles.Lookup.PACKAGE));
+
+ // Public classes are always accessible.
+ assertTrue(VerifyAccess.isClassAccessible(String.class, Inner1.class,
+ MethodHandles.Lookup.PACKAGE));
+ }
+
+ public static class Inner1 {
+ }
+
+ public static class Inner2 {
+ }
+
+ public void testIsSamePackageMember() {
+ assertTrue(VerifyAccess.isSamePackageMember(Inner1.class, Inner2.class));
+ assertTrue(VerifyAccess.isSamePackageMember(Inner1.class, VerifyAccessTest.class));
+
+ assertFalse(VerifyAccess.isSamePackageMember(Sibling.class, Inner1.class));
+ }
+
+ public void testIsSamePackage() {
+ // Both classes are in package java.util.
+ assertTrue(VerifyAccess.isSamePackage(Vector.class, List.class));
+ // Make sure this works for inner classes.
+ assertTrue(VerifyAccess.isSamePackage(Vector.class, Locale.Builder.class));
+ // Differing packages: java.lang vs java.util.
+ assertFalse(VerifyAccess.isSamePackage(Vector.class, String.class));
+
+ try {
+ VerifyAccess.isSamePackage(String[].class, List.class);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
+
+class Sibling {
+}
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherOutputStream1Test.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherOutputStream1Test.java
index 359ac66..5c88e71 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherOutputStream1Test.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherOutputStream1Test.java
@@ -23,20 +23,27 @@
package org.apache.harmony.crypto.tests.javax.crypto;
import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.Security;
+import java.security.spec.AlgorithmParameterSpec;
import java.util.Arrays;
+import javax.crypto.BadPaddingException;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.NullCipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.Cipher;
+import javax.crypto.ShortBufferException;
import junit.framework.TestCase;
@@ -205,5 +212,121 @@
assertNotNull(cos);
}
+
+ private static class CipherSpiThatThrowsOnSecondDoFinal extends CipherSpi {
+
+ private boolean wasDoFinalCalled = false;
+
+ @Override
+ protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+
+ }
+
+ @Override
+ protected void engineSetPadding(String padding) throws NoSuchPaddingException {
+
+ }
+
+ @Override
+ protected int engineGetBlockSize() {
+ return 0;
+ }
+
+ @Override
+ protected int engineGetOutputSize(int inputLen) {
+ return 0;
+ }
+
+ @Override
+ protected byte[] engineGetIV() {
+ return new byte[0];
+ }
+
+ @Override
+ protected AlgorithmParameters engineGetParameters() {
+ return null;
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, SecureRandom random)
+ throws InvalidKeyException {
+
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+ }
+
+ @Override
+ protected void engineInit(int opmode, Key key, AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+
+ }
+
+ @Override
+ protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+ return new byte[0];
+ }
+
+ @Override
+ protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset) throws ShortBufferException {
+ return 0;
+ }
+
+ @Override
+ protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException {
+ // Just call the other overriding for engineDoFinal.
+ try {
+ engineDoFinal(input, inputOffset, inputLen, new byte[10], 0);
+ } catch (ShortBufferException e) {
+ throw new RuntimeException(e);
+ }
+ return new byte[0];
+ }
+
+ @Override
+ protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+ int outputOffset)
+ throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
+ if (wasDoFinalCalled) {
+ throw new UnsupportedOperationException(
+ "doFinal not supposed to be called two times");
+ }
+ wasDoFinalCalled = true;
+ return 0;
+ }
+ };
+
+
+ public void test_close_doubleCloseDoesntCallDoFinal() throws Exception {
+ CipherSpi cipherSpiThatThrowsOnSecondDoFinal = new CipherSpiThatThrowsOnSecondDoFinal();
+ Cipher cipherThatThrowsOnSecondDoFinal = new Cipher(
+ cipherSpiThatThrowsOnSecondDoFinal,
+ Security.getProviders()[0],
+ "SomeTransformation") {
+ };
+
+ TestOutputStream testOutputStream = new TestOutputStream();
+ CipherOutputStream cipherOutputStream = new CipherOutputStream(
+ testOutputStream, cipherThatThrowsOnSecondDoFinal);
+
+ cipherThatThrowsOnSecondDoFinal.init(Cipher.ENCRYPT_MODE, (Key) null);
+
+ cipherOutputStream.close();
+ // Should just check that it's already closed and return, without calling doFinal, thus
+ // throwing any exception
+ cipherOutputStream.close();
+
+ // Check that the spi didn't change, as it might be changed dynamically by the Cipher
+ // methods.
+ assertEquals(cipherSpiThatThrowsOnSecondDoFinal,
+ cipherThatThrowsOnSecondDoFinal.getCurrentSpi());
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java
index d90c8ec..2fc09c6 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/DigestOutputStreamTest.java
@@ -594,6 +594,67 @@
Arrays.equals(digestResult, expected));
}
+ private class MessageDigestWithUnsupportedUpdate extends MessageDigest {
+ private MessageDigestWithUnsupportedUpdate() {
+ super("SomeAlgorithm");
+ }
+
+ @Override
+ protected void engineUpdate(byte input) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected void engineUpdate(byte[] input, int offset, int len) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected byte[] engineDigest() {
+ return new byte[0];
+ }
+
+ @Override
+ protected void engineReset() {
+
+ }
+ }
+
+ public void test_write_writeToUnderlyingStreamBeforeUpdatingDigest() {
+ MessageDigest messageDigestWithUnsupportedUpdate = new MessageDigestWithUnsupportedUpdate();
+ OutputStream outputStreamThatThrowsIOException = new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ throw new IOException();
+ }
+ };
+
+ DigestOutputStream digestOutputStream = new DigestOutputStream(
+ outputStreamThatThrowsIOException, messageDigestWithUnsupportedUpdate);
+
+ // Writing throws an IOException (and not an UnsupportedOperationException) meaning than
+ // it tried to write to the underlying stream before updating the digest.
+ digestOutputStream.on(true);
+ try {
+ digestOutputStream.write(3);
+ fail();
+ } catch (IOException expected) {
+ }
+
+ digestOutputStream.on(true);
+ try {
+ digestOutputStream.write(new byte[10], 0, 10);
+ fail();
+ } catch (IOException expected) {
+ }
+
+ digestOutputStream.on(true);
+ try {
+ digestOutputStream.write(new byte[10]);
+ fail();
+ } catch (IOException expected) {
+ }
+ }
private class MyOutputStream extends OutputStream {
@Override
diff --git a/luni/src/test/resources/libcore/java/lang/reflect/parameter/metadata_variations.dex b/luni/src/test/resources/libcore/java/lang/reflect/parameter/metadata_variations.dex
new file mode 100644
index 0000000..2cade45
--- /dev/null
+++ b/luni/src/test/resources/libcore/java/lang/reflect/parameter/metadata_variations.dex
Binary files differ
diff --git a/luni/src/test/resources/libcore/java/lang/reflect/parameter/parameter_metadata_test_classes.dex b/luni/src/test/resources/libcore/java/lang/reflect/parameter/parameter_metadata_test_classes.dex
new file mode 100644
index 0000000..ad7a53d
--- /dev/null
+++ b/luni/src/test/resources/libcore/java/lang/reflect/parameter/parameter_metadata_test_classes.dex
Binary files differ
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index 9a3ef03..81f78b9 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -32,6 +32,7 @@
dalvik/src/main/java/dalvik/annotation/InnerClass.java \
dalvik/src/main/java/dalvik/annotation/KnownFailure.java \
dalvik/src/main/java/dalvik/annotation/MemberClasses.java \
+ dalvik/src/main/java/dalvik/annotation/MethodParameters.java \
dalvik/src/main/java/dalvik/annotation/Signature.java \
dalvik/src/main/java/dalvik/annotation/TestTarget.java \
dalvik/src/main/java/dalvik/annotation/TestTargetClass.java \
@@ -66,7 +67,6 @@
luni/src/main/java/java/lang/FindBugsSuppressWarnings.java \
libart/src/main/java/java/lang/VMClassLoader.java \
luni/src/main/java/java/lang/ref/FinalizerReference.java \
- libart/src/main/java/java/lang/reflect/AbstractMethod.java \
luni/src/main/java/java/math/BigDecimal.java \
luni/src/main/java/java/math/BigInt.java \
luni/src/main/java/java/math/BigInteger.java \
@@ -378,6 +378,7 @@
luni/src/main/java/libcore/io/EventLogger.java \
luni/src/main/java/libcore/io/ForwardingOs.java \
luni/src/main/java/libcore/io/IoBridge.java \
+ luni/src/main/java/libcore/io/IoTracker.java \
luni/src/main/java/libcore/io/IoUtils.java \
luni/src/main/java/libcore/io/Libcore.java \
luni/src/main/java/libcore/io/Memory.java \
diff --git a/ojluni/src/main/java/java/io/BufferedInputStream.java b/ojluni/src/main/java/java/io/BufferedInputStream.java
index fcc7e70..e39c20c 100644
--- a/ojluni/src/main/java/java/io/BufferedInputStream.java
+++ b/ojluni/src/main/java/java/io/BufferedInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,7 +50,17 @@
public
class BufferedInputStream extends FilterInputStream {
- private static int defaultBufferSize = 8192;
+ // Android-changed: made final
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ // Android-changed: made final
+ private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
/**
* The internal buffer array where the data is stored. When necessary,
@@ -172,7 +182,7 @@
* @param in the underlying input stream.
*/
public BufferedInputStream(InputStream in) {
- this(in, defaultBufferSize);
+ this(in, DEFAULT_BUFFER_SIZE);
}
/**
@@ -185,7 +195,7 @@
*
* @param in the underlying input stream.
* @param size the buffer size.
- * @exception IllegalArgumentException if size <= 0.
+ * @exception IllegalArgumentException if {@code size <= 0}.
*/
public BufferedInputStream(InputStream in, int size) {
super(in);
@@ -215,8 +225,11 @@
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
+ } else if (buffer.length >= MAX_BUFFER_SIZE) {
+ throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */
- int nsz = pos * 2;
+ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
+ pos * 2 : MAX_BUFFER_SIZE;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
diff --git a/ojluni/src/main/java/java/io/BufferedReader.java b/ojluni/src/main/java/java/io/BufferedReader.java
index 5a45f4b..d00209e 100644
--- a/ojluni/src/main/java/java/io/BufferedReader.java
+++ b/ojluni/src/main/java/java/io/BufferedReader.java
@@ -96,7 +96,7 @@
* @param in A Reader
* @param sz Input-buffer size
*
- * @exception IllegalArgumentException If sz is <= 0
+ * @exception IllegalArgumentException If {@code sz <= 0}
*/
public BufferedReader(Reader in, int sz) {
super(in);
@@ -495,7 +495,7 @@
* whose size is no smaller than limit.
* Therefore large values should be used with care.
*
- * @exception IllegalArgumentException If readAheadLimit is < 0
+ * @exception IllegalArgumentException If {@code readAheadLimit < 0}
* @exception IOException If an I/O error occurs
*/
public void mark(int readAheadLimit) throws IOException {
@@ -532,9 +532,12 @@
synchronized (lock) {
if (in == null)
return;
- in.close();
- in = null;
- cb = null;
+ try {
+ in.close();
+ } finally {
+ in = null;
+ cb = null;
+ }
}
}
diff --git a/ojluni/src/main/java/java/io/BufferedWriter.java b/ojluni/src/main/java/java/io/BufferedWriter.java
index 220a47e..a5d810a 100644
--- a/ojluni/src/main/java/java/io/BufferedWriter.java
+++ b/ojluni/src/main/java/java/io/BufferedWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -95,7 +95,7 @@
* @param out A Writer
* @param sz Output-buffer size, a positive integer
*
- * @exception IllegalArgumentException If sz is <= 0
+ * @exception IllegalArgumentException If {@code sz <= 0}
*/
public BufferedWriter(Writer out, int sz) {
super(out);
@@ -255,15 +255,15 @@
}
}
+ @SuppressWarnings("try")
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
- try {
+ try (Writer w = out) {
flushBuffer();
} finally {
- out.close();
out = null;
cb = null;
}
diff --git a/ojluni/src/main/java/java/io/ByteArrayInputStream.java b/ojluni/src/main/java/java/io/ByteArrayInputStream.java
index e58c6e6..d07f074 100644
--- a/ojluni/src/main/java/java/io/ByteArrayInputStream.java
+++ b/ojluni/src/main/java/java/io/ByteArrayInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -275,7 +275,6 @@
* Closing a <tt>ByteArrayInputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
- * <p>
*/
public void close() throws IOException {
}
diff --git a/ojluni/src/main/java/java/io/ByteArrayOutputStream.java b/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
index c4df675..f1d429b 100644
--- a/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
+++ b/ojluni/src/main/java/java/io/ByteArrayOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,6 +94,14 @@
}
/**
+ * The maximum size of array to allocate.
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
@@ -105,14 +113,19 @@
int newCapacity = oldCapacity << 1;
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
- if (newCapacity < 0) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- newCapacity = Integer.MAX_VALUE;
- }
+ if (newCapacity - MAX_ARRAY_SIZE > 0)
+ newCapacity = hugeCapacity(minCapacity);
buf = Arrays.copyOf(buf, newCapacity);
}
+ private static int hugeCapacity(int minCapacity) {
+ if (minCapacity < 0) // overflow
+ throw new OutOfMemoryError();
+ return (minCapacity > MAX_ARRAY_SIZE) ?
+ Integer.MAX_VALUE :
+ MAX_ARRAY_SIZE;
+ }
+
/**
* Writes the specified byte to this byte array output stream.
*
@@ -210,21 +223,21 @@
/**
* Converts the buffer's contents into a string by decoding the bytes using
- * the specified {@link java.nio.charset.Charset charsetName}. The length of
- * the new <tt>String</tt> is a function of the charset, and hence may not be
- * equal to the length of the byte array.
+ * the named {@link java.nio.charset.Charset charset}. The length of the new
+ * <tt>String</tt> is a function of the charset, and hence may not be equal
+ * to the length of the byte array.
*
* <p> This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required.
*
- * @param charsetName the name of a supported
- * {@linkplain java.nio.charset.Charset </code>charset<code>}
- * @return String decoded from the buffer's contents.
+ * @param charsetName the name of a supported
+ * {@link java.nio.charset.Charset charset}
+ * @return String decoded from the buffer's contents.
* @exception UnsupportedEncodingException
* If the named charset is not supported
- * @since JDK1.1
+ * @since JDK1.1
*/
public synchronized String toString(String charsetName)
throws UnsupportedEncodingException
@@ -263,8 +276,6 @@
* Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an <tt>IOException</tt>.
- * <p>
- *
*/
public void close() throws IOException {
}
diff --git a/ojluni/src/main/java/java/io/Closeable.java b/ojluni/src/main/java/java/io/Closeable.java
index 7f3cc8d..b4a1c81 100644
--- a/ojluni/src/main/java/java/io/Closeable.java
+++ b/ojluni/src/main/java/java/io/Closeable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@
*
* @since 1.5
*/
-
public interface Closeable extends AutoCloseable {
/**
@@ -42,6 +41,12 @@
* with it. If the stream is already closed then invoking this
* method has no effect.
*
+ * <p> As noted in {@link AutoCloseable#close()}, cases where the
+ * close may fail require careful attention. It is strongly advised
+ * to relinquish the underlying resources and to internally
+ * <em>mark</em> the {@code Closeable} as closed, prior to throwing
+ * the {@code IOException}.
+ *
* @throws IOException if an I/O error occurs
*/
public void close() throws IOException;
diff --git a/ojluni/src/main/java/java/io/Console.java b/ojluni/src/main/java/java/io/Console.java
index 4eca41c..3cab03e 100644
--- a/ojluni/src/main/java/java/io/Console.java
+++ b/ojluni/src/main/java/java/io/Console.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -76,7 +76,7 @@
* manually zero the returned character array after processing to minimize the
* lifetime of sensitive data in memory.
*
- * <blockquote><pre>
+ * <blockquote><pre>{@code
* Console cons;
* char[] passwd;
* if ((cons = System.console()) != null &&
@@ -84,7 +84,7 @@
* ...
* java.util.Arrays.fill(passwd, ' ');
* }
- * </pre></blockquote>
+ * }</pre></blockquote>
*
* @author Xueming Shen
* @since 1.6
@@ -125,9 +125,11 @@
* {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
* on the returned object will not read in characters beyond the line
* bound for each invocation, even if the destination buffer has space for
- * more characters. A line bound is considered to be any one of a line feed
- * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
- * followed immediately by a linefeed, or an end of stream.
+ * more characters. The {@code Reader}'s {@code read} methods may block if a
+ * line bound has not been entered or reached on the console's input device.
+ * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+ * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+ * by a linefeed, or an end of stream.
*
* @return The reader associated with this console
*/
diff --git a/ojluni/src/main/java/java/io/DataOutput.java b/ojluni/src/main/java/java/io/DataOutput.java
index 07fbc3a..c6692a6 100644
--- a/ojluni/src/main/java/java/io/DataOutput.java
+++ b/ojluni/src/main/java/java/io/DataOutput.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -134,11 +134,11 @@
* Writes two bytes to the output
* stream to represent the value of the argument.
* The byte values to be written, in the order
- * shown, are: <p>
- * <pre><code>
- * (byte)(0xff & (v >> 8))
- * (byte)(0xff & v)
- * </code> </pre> <p>
+ * shown, are:
+ * <pre>{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre> <p>
* The bytes written by this method may be
* read by the <code>readShort</code> method
* of interface <code>DataInput</code> , which
@@ -156,10 +156,10 @@
* output stream.
* The byte values to be written, in the order
* shown, are:
- * <p><pre><code>
- * (byte)(0xff & (v >> 8))
- * (byte)(0xff & v)
- * </code></pre><p>
+ * <pre>{@code
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
* The bytes written by this method may be
* read by the <code>readChar</code> method
* of interface <code>DataInput</code> , which
@@ -176,12 +176,12 @@
* comprised of four bytes, to the output stream.
* The byte values to be written, in the order
* shown, are:
- * <p><pre><code>
- * (byte)(0xff & (v >> 24))
- * (byte)(0xff & (v >> 16))
- * (byte)(0xff & (v >>    8))
- * (byte)(0xff & v)
- * </code></pre><p>
+ * <pre>{@code
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
* The bytes written by this method may be read
* by the <code>readInt</code> method of interface
* <code>DataInput</code> , which will then
@@ -197,16 +197,16 @@
* comprised of eight bytes, to the output stream.
* The byte values to be written, in the order
* shown, are:
- * <p><pre><code>
- * (byte)(0xff & (v >> 56))
- * (byte)(0xff & (v >> 48))
- * (byte)(0xff & (v >> 40))
- * (byte)(0xff & (v >> 32))
- * (byte)(0xff & (v >> 24))
- * (byte)(0xff & (v >> 16))
- * (byte)(0xff & (v >> 8))
- * (byte)(0xff & v)
- * </code></pre><p>
+ * <pre>{@code
+ * (byte)(0xff & (v >> 56))
+ * (byte)(0xff & (v >> 48))
+ * (byte)(0xff & (v >> 40))
+ * (byte)(0xff & (v >> 32))
+ * (byte)(0xff & (v >> 24))
+ * (byte)(0xff & (v >> 16))
+ * (byte)(0xff & (v >> 8))
+ * (byte)(0xff & v)
+ * }</pre><p>
* The bytes written by this method may be
* read by the <code>readLong</code> method
* of interface <code>DataInput</code> , which
@@ -314,24 +314,24 @@
* If a character <code>c</code>
* is in the range <code>\u0001</code> through
* <code>\u007f</code>, it is represented
- * by one byte:<p>
+ * by one byte:
* <pre>(byte)c </pre> <p>
* If a character <code>c</code> is <code>\u0000</code>
* or is in the range <code>\u0080</code>
* through <code>\u07ff</code>, then it is
* represented by two bytes, to be written
- * in the order shown:<p> <pre><code>
- * (byte)(0xc0 | (0x1f & (c >> 6)))
- * (byte)(0x80 | (0x3f & c))
- * </code></pre> <p> If a character
+ * in the order shown: <pre>{@code
+ * (byte)(0xc0 | (0x1f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }</pre> <p> If a character
* <code>c</code> is in the range <code>\u0800</code>
* through <code>uffff</code>, then it is
* represented by three bytes, to be written
- * in the order shown:<p> <pre><code>
- * (byte)(0xe0 | (0x0f & (c >> 12)))
- * (byte)(0x80 | (0x3f & (c >> 6)))
- * (byte)(0x80 | (0x3f & c))
- * </code></pre> <p> First,
+ * in the order shown: <pre>{@code
+ * (byte)(0xe0 | (0x0f & (c >> 12)))
+ * (byte)(0x80 | (0x3f & (c >> 6)))
+ * (byte)(0x80 | (0x3f & c))
+ * }</pre> <p> First,
* the total number of bytes needed to represent
* all the characters of <code>s</code> is
* calculated. If this number is larger than
diff --git a/ojluni/src/main/native/FileSystem_md.c b/ojluni/src/main/java/java/io/DefaultFileSystem.java
similarity index 63%
rename from ojluni/src/main/native/FileSystem_md.c
rename to ojluni/src/main/java/java/io/DefaultFileSystem.java
index 33a3652..8e8cf08 100644
--- a/ojluni/src/main/native/FileSystem_md.c
+++ b/ojluni/src/main/java/java/io/DefaultFileSystem.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,24 +23,18 @@
* questions.
*/
-#include "jni.h"
-#include "jni_util.h"
-#include "JNIHelp.h"
+package java.io;
-#define NATIVE_METHOD(className, functionName, signature) \
-{ #functionName, signature, (void*)(className ## _ ## functionName) }
+/**
+ *
+ * @since 1.8
+ */
+class DefaultFileSystem {
-JNIEXPORT jobject JNICALL
-FileSystem_getFileSystem(JNIEnv *env, jclass ignored)
-{
- return JNU_NewObjectByName(env, "java/io/UnixFileSystem", "()V");
-}
-
-
-static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FileSystem, getFileSystem, "()Ljava/io/FileSystem;"),
-};
-
-void register_java_io_FileSystem(JNIEnv* env) {
- jniRegisterNativeMethods(env, "java/io/FileSystem", gMethods, NELEM(gMethods));
+ /**
+ * Return the FileSystem object for Unix-based platform.
+ */
+ public static FileSystem getFileSystem() {
+ return new UnixFileSystem();
+ }
}
diff --git a/ojluni/src/main/java/java/io/EOFException.java b/ojluni/src/main/java/java/io/EOFException.java
index ed6ca0f..536669f 100644
--- a/ojluni/src/main/java/java/io/EOFException.java
+++ b/ojluni/src/main/java/java/io/EOFException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,6 @@
* This exception is mainly used by data input streams to signal end of
* stream. Note that many other input operations return a special value on
* end of stream rather than throwing an exception.
- * <p>
*
* @author Frank Yellin
* @see java.io.DataInputStream
diff --git a/ojluni/src/main/java/java/io/ExpiringCache.java b/ojluni/src/main/java/java/io/ExpiringCache.java
index 8c07afb..02fd222 100644
--- a/ojluni/src/main/java/java/io/ExpiringCache.java
+++ b/ojluni/src/main/java/java/io/ExpiringCache.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,7 +35,7 @@
class ExpiringCache {
private long millisUntilExpiration;
- private Map map;
+ private Map<String,Entry> map;
// Clear out old entries every few queries
private int queryCount;
private int queryOverflow = 300;
@@ -61,9 +61,11 @@
this(30000);
}
+ @SuppressWarnings("serial")
ExpiringCache(long millisUntilExpiration) {
this.millisUntilExpiration = millisUntilExpiration;
- map = new LinkedHashMap() {
+ map = new LinkedHashMap<String,Entry>() {
+ @Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}
@@ -99,7 +101,7 @@
}
private Entry entryFor(String key) {
- Entry entry = (Entry) map.get(key);
+ Entry entry = map.get(key);
if (entry != null) {
long delta = System.currentTimeMillis() - entry.timestamp();
if (delta < 0 || delta >= millisUntilExpiration) {
@@ -111,12 +113,11 @@
}
private void cleanup() {
- Set keySet = map.keySet();
+ Set<String> keySet = map.keySet();
// Avoid ConcurrentModificationExceptions
String[] keys = new String[keySet.size()];
int i = 0;
- for (Iterator iter = keySet.iterator(); iter.hasNext(); ) {
- String key = (String) iter.next();
+ for (String key: keySet) {
keys[i++] = key;
}
for (int j = 0; j < keys.length; j++) {
diff --git a/ojluni/src/main/java/java/io/File.java b/ojluni/src/main/java/java/io/File.java
index 0b152cc..01e41f1 100644
--- a/ojluni/src/main/java/java/io/File.java
+++ b/ojluni/src/main/java/java/io/File.java
@@ -32,8 +32,10 @@
import java.net.URISyntaxException;
import java.util.List;
import java.util.ArrayList;
+import java.security.AccessController;
import java.nio.file.Path;
import java.nio.file.FileSystems;
+import sun.security.action.GetPropertyAction;
/**
* An abstract representation of file and directory pathnames.
@@ -127,7 +129,7 @@
* created, the abstract pathname represented by a <code>File</code> object
* will never change.
*
- * <h4>Interoperability with {@code java.nio.file} package</h4>
+ * <h3>Interoperability with {@code java.nio.file} package</h3>
*
* <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
* package defines interfaces and classes for the Java virtual machine to access
@@ -156,7 +158,7 @@
/**
* The FileSystem object representing the platform's local file system.
*/
- static private final FileSystem fs = FileSystem.getFileSystem();
+ private static final FileSystem fs = DefaultFileSystem.getFileSystem();
/**
* This abstract pathname's normalized pathname string. A normalized
@@ -165,7 +167,7 @@
*
* @serial
*/
- private String path;
+ private final String path;
/**
* Enum type that indicates the status of a file path.
@@ -197,7 +199,7 @@
* The length of this abstract pathname's prefix, or zero if it has no
* prefix.
*/
- private transient int prefixLength;
+ private final transient int prefixLength;
/**
* Returns the length of this abstract pathname's prefix.
@@ -728,6 +730,8 @@
/* -- Attribute accessors -- */
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Tests whether the application can read the file denoted by this
* abstract pathname.
@@ -752,6 +756,8 @@
return fs.checkAccess(this, FileSystem.ACCESS_READ);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Tests whether the application can modify the file denoted by this
* abstract pathname.
@@ -1434,11 +1440,13 @@
return fs.setLastModifiedTime(this, time);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Marks the file or directory named by this abstract pathname so that
- * only read operations are allowed. After invoking this method the file
- * or directory is guaranteed not to change until it is either deleted or
- * marked to allow write access. Whether or not a read-only file or
+ * only read operations are allowed. After invoking this method the file
+ * or directory will not change until it is either deleted or marked
+ * to allow write access. Whether or not a read-only file or
* directory may be deleted depends upon the underlying system.
*
* @return <code>true</code> if and only if the operation succeeded;
@@ -1462,6 +1470,8 @@
return fs.setReadOnly(this);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Sets the owner's or everybody's write permission for this abstract
* pathname.
@@ -1503,6 +1513,8 @@
return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* A convenience method to set the owner's write permission for this abstract
* pathname.
@@ -1532,6 +1544,8 @@
return setWritable(writable, true);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Sets the owner's or everybody's read permission for this abstract
* pathname.
@@ -1576,6 +1590,8 @@
return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* A convenience method to set the owner's read permission for this abstract
* pathname.
@@ -1608,6 +1624,8 @@
return setReadable(readable, true);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Sets the owner's or everybody's execute permission for this abstract
* pathname.
@@ -1652,9 +1670,11 @@
return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
- * A convenience method to set the owner's execute permission for this abstract
- * pathname.
+ * A convenience method to set the owner's execute permission for this
+ * abstract pathname.
*
* <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
* behaves in exactly the same way as the invocation
@@ -1670,7 +1690,7 @@
* operation will fail if the user does not have permission to
* change the access permissions of this abstract pathname. If
* <code>executable</code> is <code>false</code> and the underlying
- * file system does not implement an excute permission, then the
+ * file system does not implement an execute permission, then the
* operation will fail.
*
* @throws SecurityException
@@ -1684,6 +1704,8 @@
return setExecutable(executable, true);
}
+ // Android-changed. Removed javadoc comment about special privileges
+ // that doesn't make sense on android
/**
* Tests whether the application can execute the file denoted by this
* abstract pathname.
@@ -1836,24 +1858,45 @@
}
/* -- Temporary files -- */
+ private static class TempDirectory {
+ private TempDirectory() { }
- // file name generation
- private static File generateTempFile(String prefix, String suffix, File dir)
+ // Android-changed: Don't cache java.io.tmpdir value
+ // temporary directory location
+ // private static final File tmpdir = new File(AccessController
+ // .doPrivileged(new GetPropertyAction("java.io.tmpdir")));
+ // static File location() {
+ // return tmpdir;
+ // }
+
+ // file name generation
+ static File generateFile(String prefix, String suffix, File dir)
throws IOException
- {
- // Android-changed: Use Math.randomIntInternal. This (pseudo) random number
- // is initialized post-fork
- int n = Math.randomIntInternal();
- if (n == Integer.MIN_VALUE) {
- n = 0; // corner case
- } else {
- n = Math.abs(n);
+ {
+ // Android-changed: Use Math.randomIntInternal. This (pseudo) random number
+ // is initialized post-fork
+
+ long n = Math.randomLongInternal();
+ if (n == Long.MIN_VALUE) {
+ n = 0; // corner case
+ } else {
+ n = Math.abs(n);
+ }
+
+ // Android changed: Reject invalid file prefixes
+ // Use only the file name from the supplied prefix
+ //prefix = (new File(prefix)).getName();
+
+ String name = prefix + Long.toString(n) + suffix;
+ File f = new File(dir, name);
+ if (!name.equals(f.getName()) || f.isInvalid()) {
+ if (System.getSecurityManager() != null)
+ throw new IOException("Unable to create temporary file");
+ else
+ throw new IOException("Unable to create temporary file, " + f);
+ }
+ return f;
}
- String name = prefix + Integer.toString(n) + suffix;
- File f = new File(dir, name);
- if (!name.equals(f.getName()))
- throw new IOException("Unable to create temporary file");
- return f;
}
/**
@@ -1934,21 +1977,30 @@
if (suffix == null)
suffix = ".tmp";
+
File tmpdir = (directory != null) ? directory
: new File(System.getProperty("java.io.tmpdir", "."));
+ //SecurityManager sm = System.getSecurityManager();
File f;
- try {
- do {
- f = generateTempFile(prefix, suffix, tmpdir);
- } while (f.exists());
- if (!f.createNewFile())
- throw new IOException("Unable to create temporary file");
- } catch (SecurityException se) {
- // don't reveal temporary directory location
- if (directory == null)
- throw new SecurityException("Unable to create temporary file");
- throw se;
- }
+ do {
+ f = TempDirectory.generateFile(prefix, suffix, tmpdir);
+
+ // Android change: sm is always null on android
+ // if (sm != null) {
+ // try {
+ // sm.checkWrite(f.getPath());
+ // } catch (SecurityException se) {
+ // // don't reveal temporary directory location
+ // if (directory == null)
+ // throw new SecurityException("Unable to create temporary file");
+ // throw se;
+ // }
+ // }
+ } while ((fs.getBooleanAttributes(f) & FileSystem.BA_EXISTS) != 0);
+
+ if (!fs.createFileExclusively(f.getPath()))
+ throw new IOException("Unable to create temporary file");
+
return f;
}
@@ -2078,7 +2130,7 @@
throws IOException
{
s.defaultWriteObject();
- s.writeChar(this.separatorChar); // Add the separator character
+ s.writeChar(separatorChar); // Add the separator character
}
/**
@@ -2095,10 +2147,28 @@
char sep = s.readChar(); // read the previous separator char
if (sep != separatorChar)
pathField = pathField.replace(sep, separatorChar);
- this.path = fs.normalize(pathField);
- this.prefixLength = fs.prefixLength(this.path);
+ String path = fs.normalize(pathField);
+ UNSAFE.putObject(this, PATH_OFFSET, path);
+ UNSAFE.putIntVolatile(this, PREFIX_LENGTH_OFFSET, fs.prefixLength(path));
}
+ private static final long PATH_OFFSET;
+ private static final long PREFIX_LENGTH_OFFSET;
+ private static final sun.misc.Unsafe UNSAFE;
+ static {
+ try {
+ sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+ PATH_OFFSET = unsafe.objectFieldOffset(
+ File.class.getDeclaredField("path"));
+ PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset(
+ File.class.getDeclaredField("prefixLength"));
+ UNSAFE = unsafe;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
+
+
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 301077366599181567L;
diff --git a/ojluni/src/main/java/java/io/FileDescriptor.java b/ojluni/src/main/java/java/io/FileDescriptor.java
index fb2f43e..7c82505 100644
--- a/ojluni/src/main/java/java/io/FileDescriptor.java
+++ b/ojluni/src/main/java/java/io/FileDescriptor.java
@@ -46,6 +46,8 @@
* @see java.io.FileOutputStream
* @since JDK1.0
*/
+// Android-changed: Removed parent reference counting. Creator is responsible for closing
+// the file descriptor.
public final class FileDescriptor {
private int descriptor;
diff --git a/ojluni/src/main/java/java/io/FileFilter.java b/ojluni/src/main/java/java/io/FileFilter.java
index 15f00d6..f973d77 100644
--- a/ojluni/src/main/java/java/io/FileFilter.java
+++ b/ojluni/src/main/java/java/io/FileFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
*
* @since 1.2
*/
+@FunctionalInterface
public interface FileFilter {
/**
@@ -46,5 +47,4 @@
* should be included
*/
boolean accept(File pathname);
-
}
diff --git a/ojluni/src/main/java/java/io/FileInputStream.java b/ojluni/src/main/java/java/io/FileInputStream.java
old mode 100644
new mode 100755
index 9191f28..a286aaa
--- a/ojluni/src/main/java/java/io/FileInputStream.java
+++ b/ojluni/src/main/java/java/io/FileInputStream.java
@@ -31,8 +31,8 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
import sun.nio.ch.FileChannelImpl;
-import sun.misc.IoTrace;
import libcore.io.IoBridge;
+import libcore.io.IoTracker;
/**
@@ -57,7 +57,10 @@
/* File Descriptor - handle to the open file */
private final FileDescriptor fd;
- /* The path of the referenced file (null if the stream is created with a file descriptor) */
+ /**
+ * The path of the referenced file
+ * (null if the stream is created with a file descriptor)
+ */
private final String path;
private FileChannel channel = null;
@@ -67,6 +70,7 @@
private final boolean isFdOwner;
private final CloseGuard guard = CloseGuard.get();
+ private final IoTracker tracker = new IoTracker();
/**
* Creates a <code>FileInputStream</code> by
@@ -185,7 +189,16 @@
* Opens the specified file for reading.
* @param name the name of the file
*/
- private native void open(String name) throws FileNotFoundException;
+ private native void open0(String name) throws FileNotFoundException;
+
+ // wrap native call to allow instrumentation
+ /**
+ * Opens the specified file for reading.
+ * @param name the name of the file
+ */
+ private void open(String name) throws FileNotFoundException {
+ open0(name);
+ }
/**
* Reads a byte of data from this input stream. This method blocks
@@ -196,16 +209,8 @@
* @exception IOException if an I/O error occurs.
*/
public int read() throws IOException {
- Object traceContext = IoTrace.fileReadBegin(path);
-
byte[] b = new byte[1];
- int res = -1;
- try {
- res = read(b, 0, 1);
- } finally {
- IoTrace.fileReadEnd(traceContext, res);
- }
- return (res != -1) ? b[0] & 0xff : -1;
+ return (read(b, 0, 1) != -1) ? b[0] & 0xff : -1;
}
/**
@@ -245,15 +250,8 @@
if (closed && len > 0) {
throw new IOException("Stream Closed");
}
-
- Object traceContext = IoTrace.fileReadBegin(path);
- int bytesRead = 0;
- try {
- bytesRead = IoBridge.read(fd, b, off, len);
- } finally {
- IoTrace.fileReadEnd(traceContext, bytesRead == -1 ? 0 : bytesRead);
- }
- return bytesRead;
+ tracker.trackIo(len);
+ return IoBridge.read(fd, b, off, len);
}
/**
@@ -262,13 +260,15 @@
*
* <p>The <code>skip</code> method may, for a variety of
* reasons, end up skipping over some smaller number of bytes,
- * possibly <code>0</code>. If <code>n</code> is negative, an
- * <code>IOException</code> is thrown, even though the <code>skip</code>
- * method of the {@link InputStream} superclass does nothing in this case.
- * The actual number of bytes skipped is returned.
+ * possibly <code>0</code>. If <code>n</code> is negative, the method
+ * will try to skip backwards. In case the backing file does not support
+ * backward skip at its current position, an <code>IOException</code> is
+ * thrown. The actual number of bytes skipped is returned. If it skips
+ * forwards, it returns a positive value. If it skips backwards, it
+ * returns a negative value.
*
- * <p>This method may skip more bytes than are remaining in the backing
- * file. This produces no exception and the number of bytes skipped
+ * <p>This method may skip more bytes than what are remaining in the
+ * backing file. This produces no exception and the number of bytes skipped
* may include some number of bytes that were beyond the EOF of the
* backing file. Attempting to read from the stream after skipping past
* the end will result in -1 indicating the end of the file.
@@ -302,9 +302,10 @@
/**
* Returns an estimate of the number of remaining bytes that can be read (or
* skipped over) from this input stream without blocking by the next
- * invocation of a method for this input stream. The next invocation might be
- * the same thread or another thread. A single read or skip of this
- * many bytes will not block, but may read or skip fewer bytes.
+ * invocation of a method for this input stream. Returns 0 when the file
+ * position is beyond EOF. The next invocation might be the same thread
+ * or another thread. A single read or skip of this many bytes will not
+ * block, but may read or skip fewer bytes.
*
* <p> In some cases, a non-blocking read (or skip) may appear to be
* blocked when it is merely slow, for example when reading large
@@ -372,7 +373,9 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
@@ -381,7 +384,7 @@
* object associated with this file input stream.
*
* <p> The initial {@link java.nio.channels.FileChannel#position()
- * </code>position<code>} of the returned channel will be equal to the
+ * position} of the returned channel will be equal to the
* number of bytes read from the file so far. Reading bytes from this
* stream will increment the channel's position. Changing the channel's
* position, either explicitly or by reading, will change this stream's
diff --git a/ojluni/src/main/java/java/io/FileOutputStream.java b/ojluni/src/main/java/java/io/FileOutputStream.java
old mode 100644
new mode 100755
index 9691c24..249e337
--- a/ojluni/src/main/java/java/io/FileOutputStream.java
+++ b/ojluni/src/main/java/java/io/FileOutputStream.java
@@ -31,8 +31,8 @@
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
import sun.nio.ch.FileChannelImpl;
-import sun.misc.IoTrace;
import libcore.io.IoBridge;
+import libcore.io.IoTracker;
/**
* A file output stream is an output stream for writing data to a
@@ -63,25 +63,27 @@
private final FileDescriptor fd;
/**
- * The path of the referenced file (null if the stream is created with a file descriptor)
- */
- private final String path;
-
- /**
* True if the file is opened for append.
*/
private final boolean append;
/**
- * The associated channel, initalized lazily.
+ * The associated channel, initialized lazily.
*/
private FileChannel channel;
private final Object closeLock = new Object();
private volatile boolean closed = false;
+ /**
+ * The path of the referenced file
+ * (null if the stream is created with a file descriptor)
+ */
+ private final String path;
+
private final CloseGuard guard = CloseGuard.get();
private final boolean isFdOwner;
+ private final IoTracker tracker = new IoTracker();
/**
* Creates a file output stream to write to the file with the
@@ -271,9 +273,20 @@
* @param name name of file to be opened
* @param append whether the file is to be opened in append mode
*/
- private native void open(String name, boolean append)
+ private native void open0(String name, boolean append)
throws FileNotFoundException;
+ // wrap native call to allow instrumentation
+ /**
+ * Opens a file, with the specified name, for overwriting or appending.
+ * @param name name of file to be opened
+ * @param append whether the file is to be opened in append mode
+ */
+ private void open(String name, boolean append)
+ throws FileNotFoundException {
+ open0(name, append);
+ }
+
/**
* Writes the specified byte to this file output stream. Implements
* the <code>write</code> method of <code>OutputStream</code>.
@@ -309,15 +322,8 @@
if (closed && len > 0) {
throw new IOException("Stream Closed");
}
-
- Object traceContext = IoTrace.fileWriteBegin(path);
- int bytesWritten = 0;
- try {
- IoBridge.write(fd, b, off, len);
- bytesWritten = len;
- } finally {
- IoTrace.fileWriteEnd(traceContext, bytesWritten);
- }
+ tracker.trackIo(len);
+ IoBridge.write(fd, b, off, len);
}
/**
@@ -369,16 +375,18 @@
* @see java.io.FileDescriptor
*/
public final FileDescriptor getFD() throws IOException {
- if (fd != null) return fd;
+ if (fd != null) {
+ return fd;
+ }
throw new IOException();
}
/**
* Returns the unique {@link java.nio.channels.FileChannel FileChannel}
- * object associated with this file output stream. </p>
+ * object associated with this file output stream.
*
* <p> The initial {@link java.nio.channels.FileChannel#position()
- * </code>position<code>} of the returned channel will be equal to the
+ * position} of the returned channel will be equal to the
* number of bytes written to the file so far unless this stream is in
* append mode, in which case it will be equal to the size of the file.
* Writing bytes to this stream will increment the channel's position
diff --git a/ojluni/src/main/java/java/io/FilePermission.java b/ojluni/src/main/java/java/io/FilePermission.java
index 21b0a1e..814a695 100644
--- a/ojluni/src/main/java/java/io/FilePermission.java
+++ b/ojluni/src/main/java/java/io/FilePermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,5 @@
public FilePermission(String path, String actions) { super(""); }
public boolean implies(Permission p) { return true; }
-
public String getActions() { return null; }
}
diff --git a/ojluni/src/main/java/java/io/FileSystem.java b/ojluni/src/main/java/java/io/FileSystem.java
index aa00fa9..4b0260d 100644
--- a/ojluni/src/main/java/java/io/FileSystem.java
+++ b/ojluni/src/main/java/java/io/FileSystem.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
package java.io;
+import java.lang.annotation.Native;
/**
* Package-private abstract class for the local filesystem abstraction.
@@ -33,13 +34,6 @@
abstract class FileSystem {
- /**
- * Return the FileSystem object representing this platform's local
- * filesystem.
- */
- public static native FileSystem getFileSystem();
-
-
/* -- Normalization and construction -- */
/**
@@ -106,10 +100,10 @@
/* -- Attribute accessors -- */
/* Constants for simple boolean attributes */
- public static final int BA_EXISTS = 0x01;
- public static final int BA_REGULAR = 0x02;
- public static final int BA_DIRECTORY = 0x04;
- public static final int BA_HIDDEN = 0x08;
+ @Native public static final int BA_EXISTS = 0x01;
+ @Native public static final int BA_REGULAR = 0x02;
+ @Native public static final int BA_DIRECTORY = 0x04;
+ @Native public static final int BA_HIDDEN = 0x08;
/**
* Return the simple boolean attributes for the file or directory denoted
@@ -118,9 +112,9 @@
*/
public abstract int getBooleanAttributes(File f);
- public static final int ACCESS_READ = 0x04;
- public static final int ACCESS_WRITE = 0x02;
- public static final int ACCESS_EXECUTE = 0x01;
+ @Native public static final int ACCESS_READ = 0x04;
+ @Native public static final int ACCESS_WRITE = 0x02;
+ @Native public static final int ACCESS_EXECUTE = 0x01;
public static final int ACCESS_OK = 0x08;
/**
@@ -212,9 +206,9 @@
public abstract File[] listRoots();
/* -- Disk usage -- */
- public static final int SPACE_TOTAL = 0;
- public static final int SPACE_FREE = 1;
- public static final int SPACE_USABLE = 2;
+ @Native public static final int SPACE_TOTAL = 0;
+ @Native public static final int SPACE_FREE = 1;
+ @Native public static final int SPACE_USABLE = 2;
public abstract long getSpace(File f, int t);
diff --git a/ojluni/src/main/java/java/io/FilenameFilter.java b/ojluni/src/main/java/java/io/FilenameFilter.java
index 915adf5..71b88af 100644
--- a/ojluni/src/main/java/java/io/FilenameFilter.java
+++ b/ojluni/src/main/java/java/io/FilenameFilter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,8 +39,8 @@
* @see java.io.File#list(java.io.FilenameFilter)
* @since JDK1.0
*/
-public
-interface FilenameFilter {
+@FunctionalInterface
+public interface FilenameFilter {
/**
* Tests if a specified file should be included in a file list.
*
diff --git a/ojluni/src/main/java/java/io/FilterOutputStream.java b/ojluni/src/main/java/java/io/FilterOutputStream.java
index 6de18f0..209e63b 100644
--- a/ojluni/src/main/java/java/io/FilterOutputStream.java
+++ b/ojluni/src/main/java/java/io/FilterOutputStream.java
@@ -152,11 +152,10 @@
* @see java.io.FilterOutputStream#flush()
* @see java.io.FilterOutputStream#out
*/
+ @SuppressWarnings("try")
public void close() throws IOException {
- try {
- flush();
- } catch (IOException ignored) {
+ try (OutputStream ostream = out) {
+ flush();
}
- out.close();
}
}
diff --git a/ojluni/src/main/java/java/io/Flushable.java b/ojluni/src/main/java/java/io/Flushable.java
index e598ea8..fe90fbd 100644
--- a/ojluni/src/main/java/java/io/Flushable.java
+++ b/ojluni/src/main/java/java/io/Flushable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,6 @@
*
* @since 1.5
*/
-
public interface Flushable {
/**
diff --git a/ojluni/src/main/java/java/io/ObjectStreamClass.java b/ojluni/src/main/java/java/io/ObjectStreamClass.java
index ffbde98..08096c4 100644
--- a/ojluni/src/main/java/java/io/ObjectStreamClass.java
+++ b/ojluni/src/main/java/java/io/ObjectStreamClass.java
@@ -2274,24 +2274,36 @@
// **** THESE METHODS WILL BE REMOVED IN A FUTURE ANDROID RELEASE ****.
//
private static long getConstructorId(Class<?> clazz) {
- System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" +
- "will be removed in a future Android release.");
- // NOTE: This method is a stub that returns a fixed value. It's meant to be used
- // with newInstance(Class<?>, long) and our current implementation of that method ignores
- // the "constructorId" argument. We return :
- //
- // oh one one eight nine nine nine
- // eight eight one nine nine
- // nine one one nine seven two five
- // three
- //
- // in all cases.
- return 1189998819991197253L;
+ final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+ System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" +
+ "will be removed in a future Android release.");
+ // NOTE: This method is a stub that returns a fixed value. It's meant to be used
+ // with newInstance(Class<?>, long) and our current implementation of that method ignores
+ // the "constructorId" argument. We return :
+ //
+ // oh one one eight nine nine nine
+ // eight eight one nine nine
+ // nine one one nine seven two five
+ // three
+ //
+ // in all cases.
+ return 1189998819991197253L;
+ }
+
+ throw new UnsupportedOperationException("ObjectStreamClass.getConstructorId(Class<?>) is " +
+ "not supported on SDK " + targetSdkVersion);
}
private static Object newInstance(Class<?> clazz, long constructorId) {
- System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" +
- "will be removed in a future Android release.");
- return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz);
+ final int targetSdkVersion = VMRuntime.getRuntime().getTargetSdkVersion();
+ if (targetSdkVersion > 0 && targetSdkVersion <= 24) {
+ System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" +
+ "will be removed in a future Android release.");
+ return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz);
+ }
+
+ throw new UnsupportedOperationException("ObjectStreamClass.newInstance(Class<?>, long) " +
+ "is not supported on SDK " + targetSdkVersion);
}
/**
diff --git a/ojluni/src/main/java/java/io/RandomAccessFile.java b/ojluni/src/main/java/java/io/RandomAccessFile.java
old mode 100644
new mode 100755
index fc645cf..80ffb95
--- a/ojluni/src/main/java/java/io/RandomAccessFile.java
+++ b/ojluni/src/main/java/java/io/RandomAccessFile.java
@@ -31,6 +31,7 @@
import android.system.ErrnoException;
import dalvik.system.CloseGuard;
import libcore.io.IoBridge;
+import libcore.io.IoTracker;
import libcore.io.Libcore;
import static android.system.OsConstants.*;
@@ -81,6 +82,11 @@
private Object closeLock = new Object();
private volatile boolean closed = false;
+ /**
+ * A single tracker to track both read and write. The tracker resets when the operation
+ * performed is different from the operation last performed.
+ */
+ private final IoTracker ioTracker = new IoTracker();
/**
* Creates a random access file stream to read from, and optionally
@@ -326,6 +332,7 @@
* @exception IOException If an I/O error has occurred.
*/
private int readBytes(byte b[], int off, int len) throws IOException {
+ ioTracker.trackIo(len, IoTracker.Mode.READ);
return IoBridge.read(fd, b, off, len);
}
@@ -479,6 +486,7 @@
* @exception IOException If an I/O error has occurred.
*/
private void writeBytes(byte b[], int off, int len) throws IOException {
+ ioTracker.trackIo(len, IoTracker.Mode.WRITE);
IoBridge.write(fd, b, off, len);
// if we are in "rws" mode, attempt to sync file+metadata
if (syncMetadata) {
@@ -547,6 +555,7 @@
}
try {
Libcore.os.lseek(fd, offset, SEEK_SET);
+ ioTracker.reset();
} catch (ErrnoException errnoException) {
throw errnoException.rethrowAsIOException();
}
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index e96cc58..930d6c2 100644
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -754,6 +754,13 @@
}
/**
+ * @hide for internal use only.
+ */
+ public static long randomLongInternal() {
+ return RandomNumberGeneratorHolder.randomNumberGenerator.nextLong();
+ }
+
+ /**
* Returns the sum of its arguments,
* throwing an exception if the result overflows an {@code int}.
*
diff --git a/ojluni/src/main/java/java/lang/annotation/ElementType.java b/ojluni/src/main/java/java/lang/annotation/ElementType.java
index 9dd2851..13b48f6 100644
--- a/ojluni/src/main/java/java/lang/annotation/ElementType.java
+++ b/ojluni/src/main/java/java/lang/annotation/ElementType.java
@@ -65,7 +65,6 @@
* Type parameter declaration
*
* @since 1.8
- * @hide 1.8
*/
TYPE_PARAMETER,
@@ -73,7 +72,6 @@
* Use of a type
*
* @since 1.8
- * @hide 1.8
*/
TYPE_USE
}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandle.java b/ojluni/src/main/java/java/lang/invoke/MethodHandle.java
index ffbc401..ef4f7fe 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandle.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandle.java
@@ -446,6 +446,38 @@
private final MethodType type;
/*private*/ MethodHandle asTypeCache;
// asTypeCache is not private so that invokers can easily fetch it
+ // Used by the runtime.
+
+ /**
+ * The INVOKE* constants and SGET/SPUT and IGET/IPUT constants specify the behaviour of this
+ * method handle with respect to the ArtField* or the ArtMethod* that it operates on. These
+ * behaviours are equivalent to the dex bytecode behaviour on the respective method_id or
+ * field_id in the equivalent instruction.
+ */
+
+ /** @hide */ public static final int INVOKE_VIRTUAL = 0x6e;
+ /** @hide */ public static final int INVOKE_SUPER = 0x6f;
+ /** @hide */ public static final int INVOKE_DIRECT = 0x70;
+ /** @hide */ public static final int INVOKE_STATIC = 0x71;
+ /** @hide */ public static final int INVOKE_INTERFACE = 0x72;
+
+ /** @hide */ public static final int SGET = 0x60;
+ /** @hide */ public static final int SPUT = 0x67;
+ /** @hide */ public static final int IGET = 0x52;
+ /** @hide */ public static final int IPUT = 0x59;
+
+ // The kind of this method handle (used by the runtime). This is one of the INVOKE_*
+ // constants or SGET/SPUT, IGET/IPUT.
+ private final int handleKind;
+
+ // The ArtMethod* or ArtField* associated with this method handle (used by the runtime).
+ private final long artFieldOrMethod;
+
+ protected MethodHandle(long artFieldOrMethod, int handleKind, MethodType type) {
+ this.artFieldOrMethod = artFieldOrMethod;
+ this.handleKind = handleKind;
+ this.type = type;
+ }
/**
* Reports the type of this method handle.
@@ -457,19 +489,6 @@
}
/**
- * Package-private constructor for the method handle implementation hierarchy.
- * Method handle inheritance will be contained completely within
- * the {@code java.lang.invoke} package.
- */
- // @param type type (permanently assigned) of the new method handle
- /*non-public*/ MethodHandle(MethodType type) {
- type.getClass(); // explicit NPE
- this.type = type;
-
- // Android-changed: No LambdaForms associated with this MH.
- }
-
- /**
* Invokes the method handle, allowing any caller type descriptor, but requiring an exact type match.
* The symbolic type descriptor at the call site of {@code invokeExact} must
* exactly match this method handle's {@link #type type}.
@@ -1262,6 +1281,11 @@
return "MethodHandle"+type;
}
+ /** @hide */
+ public int getHandleKind() {
+ return handleKind;
+ }
+
// Android-changed: Removed implementation details :
//
// String standardString();
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java b/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java
new file mode 100644
index 0000000..06ff553
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Google designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Google in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * A method handle that's directly associated with an ArtField or an ArtMethod and
+ * specifies no additional transformations.
+ *
+ * @hide
+ */
+public class MethodHandleImpl extends MethodHandle {
+
+ MethodHandleImpl(long artFieldOrMethod, int handleKind, MethodType type) {
+ super(artFieldOrMethod, handleKind, type);
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java b/ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java
index 6928c22..17d7882 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java
@@ -25,8 +25,6 @@
package java.lang.invoke;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
import sun.misc.Unsafe;
/**
@@ -41,56 +39,8 @@
static final Unsafe UNSAFE = Unsafe.getUnsafe();
- static final boolean DEBUG_METHOD_HANDLE_NAMES;
- static final boolean DUMP_CLASS_FILES;
- static final boolean TRACE_INTERPRETER;
- static final boolean TRACE_METHOD_LINKAGE;
- static final int COMPILE_THRESHOLD;
- static final int DONT_INLINE_THRESHOLD;
- static final int PROFILE_LEVEL;
- static final boolean PROFILE_GWT;
- static final int CUSTOMIZE_THRESHOLD;
-
- static {
- final Object[] values = new Object[9];
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
- values[1] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DUMP_CLASS_FILES");
- values[2] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_INTERPRETER");
- values[3] = Boolean.getBoolean("java.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE");
- values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
- values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
- values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
- values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true"));
- values[8] = Integer.getInteger("java.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD", 127);
- return null;
- }
- });
- DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
- DUMP_CLASS_FILES = (Boolean) values[1];
- TRACE_INTERPRETER = (Boolean) values[2];
- TRACE_METHOD_LINKAGE = (Boolean) values[3];
- COMPILE_THRESHOLD = (Integer) values[4];
- DONT_INLINE_THRESHOLD = (Integer) values[5];
- PROFILE_LEVEL = (Integer) values[6];
- PROFILE_GWT = (Boolean) values[7];
- CUSTOMIZE_THRESHOLD = (Integer) values[8];
-
- if (CUSTOMIZE_THRESHOLD < -1 || CUSTOMIZE_THRESHOLD > 127) {
- throw newInternalError("CUSTOMIZE_THRESHOLD should be in [-1...127] range");
- }
- }
-
- /** Tell if any of the debugging switches are turned on.
- * If this is the case, it is reasonable to perform extra checks or save extra information.
- */
- /*non-public*/ static boolean debugEnabled() {
- return (DEBUG_METHOD_HANDLE_NAMES |
- DUMP_CLASS_FILES |
- TRACE_INTERPRETER |
- TRACE_METHOD_LINKAGE);
- }
+ // Android-changed: Remove debugging related static fields. They are unused and have
+ // no equivalent on Android.
// Android-changed: Temporarily hide methods that operate on MethodHandles until the
// MethodHandle class is imported.
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
new file mode 100644
index 0000000..bd2f60d
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -0,0 +1,2672 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.List;
+import java.util.Arrays;
+import java.util.NoSuchElementException;
+
+import dalvik.system.VMStack;
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/**
+ * This class consists exclusively of static methods that operate on or return
+ * method handles. They fall into several categories:
+ * <ul>
+ * <li>Lookup methods which help create method handles for methods and fields.
+ * <li>Combinator methods, which combine or transform pre-existing method handles into new ones.
+ * <li>Other factory methods to create method handles that emulate other common JVM operations or control flow patterns.
+ * </ul>
+ * <p>
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class MethodHandles {
+
+ private MethodHandles() { } // do not instantiate
+
+ // Android-changed: We do not use MemberName / MethodHandleImpl.
+ //
+ // private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
+ // static { MethodHandleImpl.initStatics(); }
+ // See IMPL_LOOKUP below.
+
+ //// Method handle creation from ordinary methods.
+
+ /**
+ * Returns a {@link Lookup lookup object} with
+ * full capabilities to emulate all supported bytecode behaviors of the caller.
+ * These capabilities include <a href="MethodHandles.Lookup.html#privacc">private access</a> to the caller.
+ * Factory methods on the lookup object can create
+ * <a href="MethodHandleInfo.html#directmh">direct method handles</a>
+ * for any member that the caller has access to via bytecodes,
+ * including protected and private fields and methods.
+ * This lookup object is a <em>capability</em> which may be delegated to trusted agents.
+ * Do not store it in place where untrusted code can access it.
+ * <p>
+ * This method is caller sensitive, which means that it may return different
+ * values to different callers.
+ * <p>
+ * For any given caller class {@code C}, the lookup object returned by this call
+ * has equivalent capabilities to any lookup object
+ * supplied by the JVM to the bootstrap method of an
+ * <a href="package-summary.html#indyinsn">invokedynamic instruction</a>
+ * executing in the same caller class {@code C}.
+ * @return a lookup object for the caller of this method, with private access
+ */
+ // Android-changed: Remove caller sensitive.
+ // @CallerSensitive
+ public static Lookup lookup() {
+ // Android-changed: Do not use Reflection.getCallerClass().
+ return new Lookup(VMStack.getStackClass1());
+ }
+
+ /**
+ * Returns a {@link Lookup lookup object} which is trusted minimally.
+ * It can only be used to create method handles to
+ * publicly accessible fields and methods.
+ * <p>
+ * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+ * of this lookup object will be {@link java.lang.Object}.
+ *
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * The lookup class can be changed to any other class {@code C} using an expression of the form
+ * {@link Lookup#in publicLookup().in(C.class)}.
+ * Since all classes have equal access to public names,
+ * such a change would confer no new access rights.
+ * A public lookup object is always subject to
+ * <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
+ * Also, it cannot access
+ * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
+ * @return a lookup object which is trusted minimally
+ */
+ public static Lookup publicLookup() {
+ return Lookup.PUBLIC_LOOKUP;
+ }
+
+ /**
+ * Performs an unchecked "crack" of a
+ * <a href="MethodHandleInfo.html#directmh">direct method handle</a>.
+ * The result is as if the user had obtained a lookup object capable enough
+ * to crack the target method handle, called
+ * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+ * on the target to obtain its symbolic reference, and then called
+ * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+ * to resolve the symbolic reference to a member.
+ * <p>
+ * If there is a security manager, its {@code checkPermission} method
+ * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+ * @param <T> the desired type of the result, either {@link Member} or a subtype
+ * @param target a direct method handle to crack into symbolic reference components
+ * @param expected a class object representing the desired result type {@code T}
+ * @return a reference to the method, constructor, or field object
+ * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+ * @exception NullPointerException if either argument is {@code null}
+ * @exception IllegalArgumentException if the target is not a direct method handle
+ * @exception ClassCastException if the member is not of the expected type
+ * @since 1.8
+ */
+ public static <T extends Member> T
+ reflectAs(Class<T> expected, MethodHandle target) {
+ throw new UnsupportedOperationException("MethodHandles.reflectAs is not implemented.");
+ }
+
+ /**
+ * A <em>lookup object</em> is a factory for creating method handles,
+ * when the creation requires access checking.
+ * Method handles do not perform
+ * access checks when they are called, but rather when they are created.
+ * Therefore, method handle access
+ * restrictions must be enforced when a method handle is created.
+ * The caller class against which those restrictions are enforced
+ * is known as the {@linkplain #lookupClass lookup class}.
+ * <p>
+ * A lookup class which needs to create method handles will call
+ * {@link MethodHandles#lookup MethodHandles.lookup} to create a factory for itself.
+ * When the {@code Lookup} factory object is created, the identity of the lookup class is
+ * determined, and securely stored in the {@code Lookup} object.
+ * The lookup class (or its delegates) may then use factory methods
+ * on the {@code Lookup} object to create method handles for access-checked members.
+ * This includes all methods, constructors, and fields which are allowed to the lookup class,
+ * even private ones.
+ *
+ * <h1><a name="lookups"></a>Lookup Factory Methods</h1>
+ * The factory methods on a {@code Lookup} object correspond to all major
+ * use cases for methods, constructors, and fields.
+ * Each method handle created by a factory method is the functional
+ * equivalent of a particular <em>bytecode behavior</em>.
+ * (Bytecode behaviors are described in section 5.4.3.5 of the Java Virtual Machine Specification.)
+ * Here is a summary of the correspondence between these factory methods and
+ * the behavior the resulting method handles:
+ * <table border=1 cellpadding=5 summary="lookup method behaviors">
+ * <tr>
+ * <th><a name="equiv"></a>lookup expression</th>
+ * <th>member</th>
+ * <th>bytecode behavior</th>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findGetter lookup.findGetter(C.class,"f",FT.class)}</td>
+ * <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticGetter lookup.findStaticGetter(C.class,"f",FT.class)}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSetter lookup.findSetter(C.class,"f",FT.class)}</td>
+ * <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStaticSetter lookup.findStaticSetter(C.class,"f",FT.class)}</td>
+ * <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findVirtual lookup.findVirtual(C.class,"m",MT)}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findStatic lookup.findStatic(C.class,"m",MT)}</td>
+ * <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findSpecial lookup.findSpecial(C.class,"m",MT,this.class)}</td>
+ * <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#findConstructor lookup.findConstructor(C.class,MT)}</td>
+ * <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectGetter lookup.unreflectGetter(aField)}</td>
+ * <td>({@code static})?<br>{@code FT f;}</td><td>{@code (FT) aField.get(thisOrNull);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectSetter lookup.unreflectSetter(aField)}</td>
+ * <td>({@code static})?<br>{@code FT f;}</td><td>{@code aField.set(thisOrNull, arg);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+ * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflectConstructor lookup.unreflectConstructor(aConstructor)}</td>
+ * <td>{@code C(A*);}</td><td>{@code (C) aConstructor.newInstance(arg*);}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link java.lang.invoke.MethodHandles.Lookup#unreflect lookup.unreflect(aMethod)}</td>
+ * <td>({@code static})?<br>{@code T m(A*);}</td><td>{@code (T) aMethod.invoke(thisOrNull, arg*);}</td>
+ * </tr>
+ * </table>
+ *
+ * Here, the type {@code C} is the class or interface being searched for a member,
+ * documented as a parameter named {@code refc} in the lookup methods.
+ * The method type {@code MT} is composed from the return type {@code T}
+ * and the sequence of argument types {@code A*}.
+ * The constructor also has a sequence of argument types {@code A*} and
+ * is deemed to return the newly-created object of type {@code C}.
+ * Both {@code MT} and the field type {@code FT} are documented as a parameter named {@code type}.
+ * The formal parameter {@code this} stands for the self-reference of type {@code C};
+ * if it is present, it is always the leading argument to the method handle invocation.
+ * (In the case of some {@code protected} members, {@code this} may be
+ * restricted in type to the lookup class; see below.)
+ * The name {@code arg} stands for all the other method handle arguments.
+ * In the code examples for the Core Reflection API, the name {@code thisOrNull}
+ * stands for a null reference if the accessed method or field is static,
+ * and {@code this} otherwise.
+ * The names {@code aMethod}, {@code aField}, and {@code aConstructor} stand
+ * for reflective objects corresponding to the given members.
+ * <p>
+ * In cases where the given member is of variable arity (i.e., a method or constructor)
+ * the returned method handle will also be of {@linkplain MethodHandle#asVarargsCollector variable arity}.
+ * In all other cases, the returned method handle will be of fixed arity.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * The equivalence between looked-up method handles and underlying
+ * class members and bytecode behaviors
+ * can break down in a few ways:
+ * <ul style="font-size:smaller;">
+ * <li>If {@code C} is not symbolically accessible from the lookup class's loader,
+ * the lookup can still succeed, even when there is no equivalent
+ * Java expression or bytecoded constant.
+ * <li>Likewise, if {@code T} or {@code MT}
+ * is not symbolically accessible from the lookup class's loader,
+ * the lookup can still succeed.
+ * For example, lookups for {@code MethodHandle.invokeExact} and
+ * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
+ * <li>If there is a security manager installed, it can forbid the lookup
+ * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
+ * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
+ * constant is not subject to security manager checks.
+ * <li>If the looked-up method has a
+ * <a href="MethodHandle.html#maxarity">very large arity</a>,
+ * the method handle creation may fail, due to the method handle
+ * type having too many parameters.
+ * </ul>
+ *
+ * <h1><a name="access"></a>Access checking</h1>
+ * Access checks are applied in the factory methods of {@code Lookup},
+ * when a method handle is created.
+ * This is a key difference from the Core Reflection API, since
+ * {@link java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * performs access checking against every caller, on every call.
+ * <p>
+ * All access checks start from a {@code Lookup} object, which
+ * compares its recorded lookup class against all requests to
+ * create method handles.
+ * A single {@code Lookup} object can be used to create any number
+ * of access-checked method handles, all checked against a single
+ * lookup class.
+ * <p>
+ * A {@code Lookup} object can be shared with other trusted code,
+ * such as a metaobject protocol.
+ * A shared {@code Lookup} object delegates the capability
+ * to create method handles on private members of the lookup class.
+ * Even if privileged code uses the {@code Lookup} object,
+ * the access checking is confined to the privileges of the
+ * original lookup class.
+ * <p>
+ * A lookup can fail, because
+ * the containing class is not accessible to the lookup class, or
+ * because the desired class member is missing, or because the
+ * desired class member is not accessible to the lookup class, or
+ * because the lookup object is not trusted enough to access the member.
+ * In any of these cases, a {@code ReflectiveOperationException} will be
+ * thrown from the attempted lookup. The exact class will be one of
+ * the following:
+ * <ul>
+ * <li>NoSuchMethodException — if a method is requested but does not exist
+ * <li>NoSuchFieldException — if a field is requested but does not exist
+ * <li>IllegalAccessException — if the member exists but an access check fails
+ * </ul>
+ * <p>
+ * In general, the conditions under which a method handle may be
+ * looked up for a method {@code M} are no more restrictive than the conditions
+ * under which the lookup class could have compiled, verified, and resolved a call to {@code M}.
+ * Where the JVM would raise exceptions like {@code NoSuchMethodError},
+ * a method handle lookup will generally raise a corresponding
+ * checked exception, such as {@code NoSuchMethodException}.
+ * And the effect of invoking the method handle resulting from the lookup
+ * is <a href="MethodHandles.Lookup.html#equiv">exactly equivalent</a>
+ * to executing the compiled, verified, and resolved call to {@code M}.
+ * The same point is true of fields and constructors.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * Access checks only apply to named and reflected methods,
+ * constructors, and fields.
+ * Other method handle creation methods, such as
+ * {@link MethodHandle#asType MethodHandle.asType},
+ * do not require any access checks, and are used
+ * independently of any {@code Lookup} object.
+ * <p>
+ * If the desired member is {@code protected}, the usual JVM rules apply,
+ * including the requirement that the lookup class must be either be in the
+ * same package as the desired member, or must inherit that member.
+ * (See the Java Virtual Machine Specification, sections 4.9.2, 5.4.3.5, and 6.4.)
+ * In addition, if the desired member is a non-static field or method
+ * in a different package, the resulting method handle may only be applied
+ * to objects of the lookup class or one of its subclasses.
+ * This requirement is enforced by narrowing the type of the leading
+ * {@code this} parameter from {@code C}
+ * (which will necessarily be a superclass of the lookup class)
+ * to the lookup class itself.
+ * <p>
+ * The JVM imposes a similar requirement on {@code invokespecial} instruction,
+ * that the receiver argument must match both the resolved method <em>and</em>
+ * the current class. Again, this requirement is enforced by narrowing the
+ * type of the leading parameter to the resulting method handle.
+ * (See the Java Virtual Machine Specification, section 4.10.1.9.)
+ * <p>
+ * The JVM represents constructors and static initializer blocks as internal methods
+ * with special names ({@code "<init>"} and {@code "<clinit>"}).
+ * The internal syntax of invocation instructions allows them to refer to such internal
+ * methods as if they were normal methods, but the JVM bytecode verifier rejects them.
+ * A lookup of such an internal method will produce a {@code NoSuchMethodException}.
+ * <p>
+ * In some cases, access between nested classes is obtained by the Java compiler by creating
+ * an wrapper method to access a private method of another class
+ * in the same top-level declaration.
+ * For example, a nested class {@code C.D}
+ * can access private members within other related classes such as
+ * {@code C}, {@code C.D.E}, or {@code C.B},
+ * but the Java compiler may need to generate wrapper methods in
+ * those related classes. In such cases, a {@code Lookup} object on
+ * {@code C.E} would be unable to those private members.
+ * A workaround for this limitation is the {@link Lookup#in Lookup.in} method,
+ * which can transform a lookup on {@code C.E} into one on any of those other
+ * classes, without special elevation of privilege.
+ * <p>
+ * The accesses permitted to a given lookup object may be limited,
+ * according to its set of {@link #lookupModes lookupModes},
+ * to a subset of members normally accessible to the lookup class.
+ * For example, the {@link MethodHandles#publicLookup publicLookup}
+ * method produces a lookup object which is only allowed to access
+ * public members in public classes.
+ * The caller sensitive method {@link MethodHandles#lookup lookup}
+ * produces a lookup object with full capabilities relative to
+ * its caller class, to emulate all supported bytecode behaviors.
+ * Also, the {@link Lookup#in Lookup.in} method may produce a lookup object
+ * with fewer access modes than the original lookup object.
+ *
+ * <p style="font-size:smaller;">
+ * <a name="privacc"></a>
+ * <em>Discussion of private access:</em>
+ * We say that a lookup has <em>private access</em>
+ * if its {@linkplain #lookupModes lookup modes}
+ * include the possibility of accessing {@code private} members.
+ * As documented in the relevant methods elsewhere,
+ * only lookups with private access possess the following capabilities:
+ * <ul style="font-size:smaller;">
+ * <li>access private fields, methods, and constructors of the lookup class
+ * <li>create method handles which invoke <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a> methods,
+ * such as {@code Class.forName}
+ * <li>create method handles which {@link Lookup#findSpecial emulate invokespecial} instructions
+ * <li>avoid <a href="MethodHandles.Lookup.html#secmgr">package access checks</a>
+ * for classes accessible to the lookup class
+ * <li>create {@link Lookup#in delegated lookup objects} which have private access to other classes
+ * within the same package member
+ * </ul>
+ * <p style="font-size:smaller;">
+ * Each of these permissions is a consequence of the fact that a lookup object
+ * with private access can be securely traced back to an originating class,
+ * whose <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> and Java language access permissions
+ * can be reliably determined and emulated by method handles.
+ *
+ * <h1><a name="secmgr"></a>Security manager interactions</h1>
+ * Although bytecode instructions can only refer to classes in
+ * a related class loader, this API can search for methods in any
+ * class, as long as a reference to its {@code Class} object is
+ * available. Such cross-loader references are also possible with the
+ * Core Reflection API, and are impossible to bytecode instructions
+ * such as {@code invokestatic} or {@code getfield}.
+ * There is a {@linkplain java.lang.SecurityManager security manager API}
+ * to allow applications to check such cross-loader references.
+ * These checks apply to both the {@code MethodHandles.Lookup} API
+ * and the Core Reflection API
+ * (as found on {@link java.lang.Class Class}).
+ * <p>
+ * If a security manager is present, member lookups are subject to
+ * additional checks.
+ * From one to three calls are made to the security manager.
+ * Any of these calls can refuse access by throwing a
+ * {@link java.lang.SecurityException SecurityException}.
+ * Define {@code smgr} as the security manager,
+ * {@code lookc} as the lookup class of the current lookup object,
+ * {@code refc} as the containing class in which the member
+ * is being sought, and {@code defc} as the class in which the
+ * member is actually defined.
+ * The value {@code lookc} is defined as <em>not present</em>
+ * if the current lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>.
+ * The calls are made according to the following rules:
+ * <ul>
+ * <li><b>Step 1:</b>
+ * If {@code lookc} is not present, or if its class loader is not
+ * the same as or an ancestor of the class loader of {@code refc},
+ * then {@link SecurityManager#checkPackageAccess
+ * smgr.checkPackageAccess(refcPkg)} is called,
+ * where {@code refcPkg} is the package of {@code refc}.
+ * <li><b>Step 2:</b>
+ * If the retrieved member is not public and
+ * {@code lookc} is not present, then
+ * {@link SecurityManager#checkPermission smgr.checkPermission}
+ * with {@code RuntimePermission("accessDeclaredMembers")} is called.
+ * <li><b>Step 3:</b>
+ * If the retrieved member is not public,
+ * and if {@code lookc} is not present,
+ * and if {@code defc} and {@code refc} are different,
+ * then {@link SecurityManager#checkPackageAccess
+ * smgr.checkPackageAccess(defcPkg)} is called,
+ * where {@code defcPkg} is the package of {@code defc}.
+ * </ul>
+ * Security checks are performed after other access checks have passed.
+ * Therefore, the above rules presuppose a member that is public,
+ * or else that is being accessed from a lookup class that has
+ * rights to access the member.
+ *
+ * <h1><a name="callsens"></a>Caller sensitive methods</h1>
+ * A small number of Java methods have a special property called caller sensitivity.
+ * A <em>caller-sensitive</em> method can behave differently depending on the
+ * identity of its immediate caller.
+ * <p>
+ * If a method handle for a caller-sensitive method is requested,
+ * the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
+ * but they take account of the lookup class in a special way.
+ * The resulting method handle behaves as if it were called
+ * from an instruction contained in the lookup class,
+ * so that the caller-sensitive method detects the lookup class.
+ * (By contrast, the invoker of the method handle is disregarded.)
+ * Thus, in the case of caller-sensitive methods,
+ * different lookup classes may give rise to
+ * differently behaving method handles.
+ * <p>
+ * In cases where the lookup object is
+ * {@link MethodHandles#publicLookup() publicLookup()},
+ * or some other lookup object without
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>,
+ * the lookup class is disregarded.
+ * In such cases, no caller-sensitive method handle can be created,
+ * access is forbidden, and the lookup fails with an
+ * {@code IllegalAccessException}.
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * For example, the caller-sensitive method
+ * {@link java.lang.Class#forName(String) Class.forName(x)}
+ * can return varying classes or throw varying exceptions,
+ * depending on the class loader of the class that calls it.
+ * A public lookup of {@code Class.forName} will fail, because
+ * there is no reasonable way to determine its bytecode behavior.
+ * <p style="font-size:smaller;">
+ * If an application caches method handles for broad sharing,
+ * it should use {@code publicLookup()} to create them.
+ * If there is a lookup of {@code Class.forName}, it will fail,
+ * and the application must take appropriate action in that case.
+ * It may be that a later lookup, perhaps during the invocation of a
+ * bootstrap method, can incorporate the specific identity
+ * of the caller, making the method accessible.
+ * <p style="font-size:smaller;">
+ * The function {@code MethodHandles.lookup} is caller sensitive
+ * so that there can be a secure foundation for lookups.
+ * Nearly all other methods in the JSR 292 API rely on lookup
+ * objects to check access requests.
+ */
+ public static final
+ class Lookup {
+ /** The class on behalf of whom the lookup is being performed. */
+ /* @NonNull */ private final Class<?> lookupClass;
+
+ /** The allowed sorts of members which may be looked up (PUBLIC, etc.). */
+ private final int allowedModes;
+
+ /** A single-bit mask representing {@code public} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x01}, happens to be the same as the value of the
+ * {@code public} {@linkplain java.lang.reflect.Modifier#PUBLIC modifier bit}.
+ */
+ public static final int PUBLIC = Modifier.PUBLIC;
+
+ /** A single-bit mask representing {@code private} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x02}, happens to be the same as the value of the
+ * {@code private} {@linkplain java.lang.reflect.Modifier#PRIVATE modifier bit}.
+ */
+ public static final int PRIVATE = Modifier.PRIVATE;
+
+ /** A single-bit mask representing {@code protected} access,
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value, {@code 0x04}, happens to be the same as the value of the
+ * {@code protected} {@linkplain java.lang.reflect.Modifier#PROTECTED modifier bit}.
+ */
+ public static final int PROTECTED = Modifier.PROTECTED;
+
+ /** A single-bit mask representing {@code package} access (default access),
+ * which may contribute to the result of {@link #lookupModes lookupModes}.
+ * The value is {@code 0x08}, which does not correspond meaningfully to
+ * any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+ */
+ public static final int PACKAGE = Modifier.STATIC;
+
+ private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE);
+
+ // Android-note: Android has no notion of a trusted lookup. If required, such lookups
+ // are performed by the runtime. As a result, we always use lookupClass, which will always
+ // be non-null in our implementation.
+ //
+ // private static final int TRUSTED = -1;
+
+ private static int fixmods(int mods) {
+ mods &= (ALL_MODES - PACKAGE);
+ return (mods != 0) ? mods : PACKAGE;
+ }
+
+ /** Tells which class is performing the lookup. It is this class against
+ * which checks are performed for visibility and access permissions.
+ * <p>
+ * The class implies a maximum level of access permission,
+ * but the permissions may be additionally limited by the bitmask
+ * {@link #lookupModes lookupModes}, which controls whether non-public members
+ * can be accessed.
+ * @return the lookup class, on behalf of which this lookup object finds members
+ */
+ public Class<?> lookupClass() {
+ return lookupClass;
+ }
+
+ /** Tells which access-protection classes of members this lookup object can produce.
+ * The result is a bit-mask of the bits
+ * {@linkplain #PUBLIC PUBLIC (0x01)},
+ * {@linkplain #PRIVATE PRIVATE (0x02)},
+ * {@linkplain #PROTECTED PROTECTED (0x04)},
+ * and {@linkplain #PACKAGE PACKAGE (0x08)}.
+ * <p>
+ * A freshly-created lookup object
+ * on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
+ * has all possible bits set, since the caller class can access all its own members.
+ * A lookup object on a new lookup class
+ * {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
+ * may have some mode bits set to zero.
+ * The purpose of this is to restrict access via the new lookup object,
+ * so that it can access only names which can be reached by the original
+ * lookup object, and also by the new lookup class.
+ * @return the lookup modes, which limit the kinds of access performed by this lookup object
+ */
+ public int lookupModes() {
+ return allowedModes & ALL_MODES;
+ }
+
+ /** Embody the current class (the lookupClass) as a lookup class
+ * for method handle creation.
+ * Must be called by from a method in this package,
+ * which in turn is called by a method not in this package.
+ */
+ Lookup(Class<?> lookupClass) {
+ this(lookupClass, ALL_MODES);
+ // make sure we haven't accidentally picked up a privileged class:
+ checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
+ }
+
+ private Lookup(Class<?> lookupClass, int allowedModes) {
+ this.lookupClass = lookupClass;
+ this.allowedModes = allowedModes;
+ }
+
+ /**
+ * Creates a lookup on the specified new lookup class.
+ * The resulting object will report the specified
+ * class as its own {@link #lookupClass lookupClass}.
+ * <p>
+ * However, the resulting {@code Lookup} object is guaranteed
+ * to have no more access capabilities than the original.
+ * In particular, access capabilities can be lost as follows:<ul>
+ * <li>If the new lookup class differs from the old one,
+ * protected members will not be accessible by virtue of inheritance.
+ * (Protected members may continue to be accessible because of package sharing.)
+ * <li>If the new lookup class is in a different package
+ * than the old one, protected and default (package) members will not be accessible.
+ * <li>If the new lookup class is not within the same package member
+ * as the old one, private members will not be accessible.
+ * <li>If the new lookup class is not accessible to the old lookup class,
+ * then no members, not even public members, will be accessible.
+ * (In all other cases, public members will continue to be accessible.)
+ * </ul>
+ *
+ * @param requestedLookupClass the desired lookup class for the new lookup object
+ * @return a lookup object which reports the desired lookup class
+ * @throws NullPointerException if the argument is null
+ */
+ public Lookup in(Class<?> requestedLookupClass) {
+ requestedLookupClass.getClass(); // null check
+ // Android-changed: There's no notion of a trusted lookup.
+ // if (allowedModes == TRUSTED) // IMPL_LOOKUP can make any lookup at all
+ // return new Lookup(requestedLookupClass, ALL_MODES);
+
+ if (requestedLookupClass == this.lookupClass)
+ return this; // keep same capabilities
+ int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+ if ((newModes & PACKAGE) != 0
+ && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
+ newModes &= ~(PACKAGE|PRIVATE);
+ }
+ // Allow nestmate lookups to be created without special privilege:
+ if ((newModes & PRIVATE) != 0
+ && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
+ newModes &= ~PRIVATE;
+ }
+ if ((newModes & PUBLIC) != 0
+ && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
+ // The requested class it not accessible from the lookup class.
+ // No permissions.
+ newModes = 0;
+ }
+ checkUnprivilegedlookupClass(requestedLookupClass, newModes);
+ return new Lookup(requestedLookupClass, newModes);
+ }
+
+ // Make sure outer class is initialized first.
+ //
+ // Android-changed: Removed unnecessary reference to IMPL_NAMES.
+ // static { IMPL_NAMES.getClass(); }
+
+ /** Version of lookup which is trusted minimally.
+ * It can only be used to create method handles to
+ * publicly accessible members.
+ */
+ static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
+
+ private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
+ String name = lookupClass.getName();
+ if (name.startsWith("java.lang.invoke."))
+ throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
+
+ // For caller-sensitive MethodHandles.lookup()
+ // disallow lookup more restricted packages
+ //
+ // Android-changed: The bootstrap classloader isn't null.
+ if (allowedModes == ALL_MODES &&
+ lookupClass.getClassLoader() == Object.class.getClassLoader()) {
+ if (name.startsWith("java.") ||
+ (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) {
+ throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
+ }
+ }
+ }
+
+ /**
+ * Displays the name of the class from which lookups are to be made.
+ * (The name is the one reported by {@link java.lang.Class#getName() Class.getName}.)
+ * If there are restrictions on the access permitted to this lookup,
+ * this is indicated by adding a suffix to the class name, consisting
+ * of a slash and a keyword. The keyword represents the strongest
+ * allowed access, and is chosen as follows:
+ * <ul>
+ * <li>If no access is allowed, the suffix is "/noaccess".
+ * <li>If only public access is allowed, the suffix is "/public".
+ * <li>If only public and package access are allowed, the suffix is "/package".
+ * <li>If only public, package, and private access are allowed, the suffix is "/private".
+ * </ul>
+ * If none of the above cases apply, it is the case that full
+ * access (public, package, private, and protected) is allowed.
+ * In this case, no suffix is added.
+ * This is true only of an object obtained originally from
+ * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}.
+ * Objects created by {@link java.lang.invoke.MethodHandles.Lookup#in Lookup.in}
+ * always have restricted access, and will display a suffix.
+ * <p>
+ * (It may seem strange that protected access should be
+ * stronger than private access. Viewed independently from
+ * package access, protected access is the first to be lost,
+ * because it requires a direct subclass relationship between
+ * caller and callee.)
+ * @see #in
+ */
+ @Override
+ public String toString() {
+ String cname = lookupClass.getName();
+ switch (allowedModes) {
+ case 0: // no privileges
+ return cname + "/noaccess";
+ case PUBLIC:
+ return cname + "/public";
+ case PUBLIC|PACKAGE:
+ return cname + "/package";
+ case ALL_MODES & ~PROTECTED:
+ return cname + "/private";
+ case ALL_MODES:
+ return cname;
+ // Android-changed: No support for TRUSTED callers.
+ // case TRUSTED:
+ // return "/trusted"; // internal only; not exported
+ default: // Should not happen, but it's a bitfield...
+ cname = cname + "/" + Integer.toHexString(allowedModes);
+ assert(false) : cname;
+ return cname;
+ }
+ }
+
+ /**
+ * Produces a method handle for a static method.
+ * The type of the method handle will be that of the method.
+ * (Since static methods do not take receivers, there is no
+ * additional receiver argument inserted into the method handle type,
+ * as there would be with {@link #findVirtual findVirtual} or {@link #findSpecial findSpecial}.)
+ * The method and all its argument types must be accessible to the lookup object.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_asList = publicLookup().findStatic(Arrays.class,
+ "asList", methodType(List.class, Object[].class));
+assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
+ * }</pre></blockquote>
+ * @param refc the class from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails,
+ * or if the method is not {@code static},
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public
+ MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ // TODO: Support varargs methods. The returned method handle must be a var-args
+ // collector in that case.
+ if (refc == MethodHandle.class) {
+ MethodHandle mh = findVirtualForMH(name, type);
+ if (mh != null) {
+ return mh;
+ }
+ }
+
+ Method method = refc.getDeclaredMethod(name, type.ptypes());
+ final int modifiers = method.getModifiers();
+ if (!Modifier.isStatic(modifiers)) {
+ throw new IllegalAccessException("Method" + method + " is not static");
+ }
+
+ checkAccess(refc, method.getDeclaringClass(), modifiers, method.getName());
+ return new MethodHandleImpl(method.getArtMethod(), MethodHandle.INVOKE_STATIC, type);
+ }
+ private MethodHandle findVirtualForMH(String name, MethodType type) {
+ // these names require special lookups because of the implicit MethodType argument
+ if ("invoke".equals(name))
+ return invoker(type);
+ if ("invokeExact".equals(name))
+ return exactInvoker(type);
+ return null;
+ }
+
+ /**
+ * Produces a method handle for a virtual method.
+ * The type of the method handle will be that of the method,
+ * with the receiver type (usually {@code refc}) prepended.
+ * The method and all its argument types must be accessible to the lookup object.
+ * <p>
+ * When called, the handle will treat the first argument as a receiver
+ * and dispatch on the receiver's type to determine which method
+ * implementation to enter.
+ * (The dispatching action is identical with that performed by an
+ * {@code invokevirtual} or {@code invokeinterface} instruction.)
+ * <p>
+ * The first argument will be of type {@code refc} if the lookup
+ * class has full privileges to access the member. Otherwise
+ * the member must be {@code protected} and the first argument
+ * will be restricted in type to the lookup class.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * Because of the general <a href="MethodHandles.Lookup.html#equiv">equivalence</a> between {@code invokevirtual}
+ * instructions and method handles produced by {@code findVirtual},
+ * if the class is {@code MethodHandle} and the name string is
+ * {@code invokeExact} or {@code invoke}, the resulting
+ * method handle is equivalent to one produced by
+ * {@link java.lang.invoke.MethodHandles#exactInvoker MethodHandles.exactInvoker} or
+ * {@link java.lang.invoke.MethodHandles#invoker MethodHandles.invoker}
+ * with the same {@code type} argument.
+ *
+ * <b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_concat = publicLookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_hashCode = publicLookup().findVirtual(Object.class,
+ "hashCode", methodType(int.class));
+MethodHandle MH_hashCode_String = publicLookup().findVirtual(String.class,
+ "hashCode", methodType(int.class));
+assertEquals("xy", (String) MH_concat.invokeExact("x", "y"));
+assertEquals("xy".hashCode(), (int) MH_hashCode.invokeExact((Object)"xy"));
+assertEquals("xy".hashCode(), (int) MH_hashCode_String.invokeExact("xy"));
+// interface method:
+MethodHandle MH_subSequence = publicLookup().findVirtual(CharSequence.class,
+ "subSequence", methodType(CharSequence.class, int.class, int.class));
+assertEquals("def", MH_subSequence.invoke("abcdefghi", 3, 6).toString());
+// constructor "internal method" must be accessed differently:
+MethodType MT_newString = methodType(void.class); //()V for new String()
+try { assertEquals("impossible", lookup()
+ .findVirtual(String.class, "<init>", MT_newString));
+ } catch (NoSuchMethodException ex) { } // OK
+MethodHandle MH_newString = publicLookup()
+ .findConstructor(String.class, MT_newString);
+assertEquals("", (String) MH_newString.invokeExact());
+ * }</pre></blockquote>
+ *
+ * @param refc the class or interface from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails,
+ * or if the method is {@code static}
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ // TODO: Support varargs methods. The returned method handle must be a var-args
+ // collector in that case.
+
+ Method method = refc.getDeclaredMethod(name, type.ptypes());
+ final int modifiers = method.getModifiers();
+ if (Modifier.isStatic(modifiers)) {
+ throw new IllegalAccessException("Method" + method + " is static.");
+ }
+
+ checkAccess(refc, method.getDeclaringClass(), method.getModifiers(), method.getName());
+
+ // Insert the leading reference parameter.
+ MethodType handleType = type.insertParameterTypes(0, refc);
+ return new MethodHandleImpl(method.getArtMethod(), MethodHandle.INVOKE_VIRTUAL,
+ handleType);
+ }
+
+ /**
+ * Produces a method handle which creates an object and initializes it, using
+ * the constructor of the specified type.
+ * The parameter types of the method handle will be those of the constructor,
+ * while the return type will be a reference to the constructor's class.
+ * The constructor and all its argument types must be accessible to the lookup object.
+ * <p>
+ * The requested type must have a return type of {@code void}.
+ * (This is consistent with the JVM's treatment of constructor type descriptors.)
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle MH_newArrayList = publicLookup().findConstructor(
+ ArrayList.class, methodType(void.class, Collection.class));
+Collection orig = Arrays.asList("x", "y");
+Collection copy = (ArrayList) MH_newArrayList.invokeExact(orig);
+assert(orig != copy);
+assertEquals(orig, copy);
+// a variable-arity constructor:
+MethodHandle MH_newProcessBuilder = publicLookup().findConstructor(
+ ProcessBuilder.class, methodType(void.class, String[].class));
+ProcessBuilder pb = (ProcessBuilder)
+ MH_newProcessBuilder.invoke("x", "y", "z");
+assertEquals("[x, y, z]", pb.command().toString());
+ * }</pre></blockquote>
+ * @param refc the class or interface from which the method is accessed
+ * @param type the type of the method, with the receiver argument omitted, and a void return type
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the constructor does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ // TODO: Support varargs methods. The returned method handle must be a var-args
+ // collector in that case.
+
+ if (type.returnType() != void.class) {
+ throw new NoSuchElementException("Unable to find constructor of type: " + type);
+ }
+
+ Constructor constructor = refc.getDeclaredConstructor(type.ptypes());
+ checkAccess(refc, constructor.getDeclaringClass(), constructor.getModifiers(),
+ constructor.getName());
+
+ MethodType handleType = type.changeReturnType(refc);
+ return new MethodHandleImpl(constructor.getArtMethod(), MethodHandle.INVOKE_DIRECT, handleType);
+ }
+
+ /**
+ * Produces an early-bound method handle for a virtual method.
+ * It will bypass checks for overriding methods on the receiver,
+ * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
+ * The type of the method handle will be that of the method,
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
+ * The method and all its argument types must be accessible
+ * to the lookup object.
+ * <p>
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+ * privileges, the access fails.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p style="font-size:smaller;">
+ * <em>(Note: JVM internal methods named {@code "<init>"} are not visible to this API,
+ * even though the {@code invokespecial} instruction can refer to them
+ * in special circumstances. Use {@link #findConstructor findConstructor}
+ * to access instance initialization methods in a safe manner.)</em>
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+static class Listie extends ArrayList {
+ public String toString() { return "[wee Listie]"; }
+ static Lookup lookup() { return MethodHandles.lookup(); }
+}
+...
+// no access to constructor via invokeSpecial:
+MethodHandle MH_newListie = Listie.lookup()
+ .findConstructor(Listie.class, methodType(void.class));
+Listie l = (Listie) MH_newListie.invokeExact();
+try { assertEquals("impossible", Listie.lookup().findSpecial(
+ Listie.class, "<init>", methodType(void.class), Listie.class));
+ } catch (NoSuchMethodException ex) { } // OK
+// access to super and self methods via invokeSpecial:
+MethodHandle MH_super = Listie.lookup().findSpecial(
+ ArrayList.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_this = Listie.lookup().findSpecial(
+ Listie.class, "toString" , methodType(String.class), Listie.class);
+MethodHandle MH_duper = Listie.lookup().findSpecial(
+ Object.class, "toString" , methodType(String.class), Listie.class);
+assertEquals("[]", (String) MH_super.invokeExact(l));
+assertEquals(""+l, (String) MH_this.invokeExact(l));
+assertEquals("[]", (String) MH_duper.invokeExact(l)); // ArrayList method
+try { assertEquals("inaccessible", Listie.lookup().findSpecial(
+ String.class, "toString", methodType(String.class), Listie.class));
+ } catch (IllegalAccessException ex) { } // OK
+Listie subl = new Listie() { public String toString() { return "[subclass]"; } };
+assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
+ * }</pre></blockquote>
+ *
+ * @param refc the class or interface from which the method is accessed
+ * @param name the name of the method (which must not be "<init>")
+ * @param type the type of the method, with the receiver argument omitted
+ * @param specialCaller the proposed calling class to perform the {@code invokespecial}
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
+ Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.findSpecial is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving read access to a non-static field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * The method handle's single argument will be the instance containing
+ * the field.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can load values from the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.findGetter is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving write access to a non-static field.
+ * The type of the method handle will have a void return type.
+ * The method handle will take two arguments, the instance containing
+ * the field, and the value to be stored.
+ * The second argument will be of the field's value type.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can store values into the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.findSetter is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving read access to a static field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * The method handle will take no arguments.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can load values from the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.findStaticGetter is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving write access to a static field.
+ * The type of the method handle will have a void return type.
+ * The method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param refc the class or interface from which the method is accessed
+ * @param name the field's name
+ * @param type the field's type
+ * @return a method handle which can store values into the field
+ * @throws NoSuchFieldException if the field does not exist
+ * @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.findStaticSetter is not implemented");
+ }
+
+ /**
+ * Produces an early-bound method handle for a non-static method.
+ * The receiver must have a supertype {@code defc} in which a method
+ * of the given name and type is accessible to the lookup class.
+ * The method and all its argument types must be accessible to the lookup object.
+ * The type of the method handle will be that of the method,
+ * without any insertion of an additional receiver parameter.
+ * The given receiver will be bound into the method handle,
+ * so that every call to the method handle will invoke the
+ * requested method on the given receiver.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set
+ * <em>and</em> the trailing array argument is not the only argument.
+ * (If the trailing array argument is the only argument,
+ * the given receiver value will be bound to it.)
+ * <p>
+ * This is equivalent to the following code:
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle mh0 = lookup().findVirtual(defc, name, type);
+MethodHandle mh1 = mh0.bindTo(receiver);
+MethodType mt1 = mh1.type();
+if (mh0.isVarargsCollector())
+ mh1 = mh1.asVarargsCollector(mt1.parameterType(mt1.parameterCount()-1));
+return mh1;
+ * }</pre></blockquote>
+ * where {@code defc} is either {@code receiver.getClass()} or a super
+ * type of that class, in which the requested method is accessible
+ * to the lookup class.
+ * (Note that {@code bindTo} does not preserve variable arity.)
+ * @param receiver the object from which the method is accessed
+ * @param name the name of the method
+ * @param type the type of the method, with the receiver argument omitted
+ * @return the desired method handle
+ * @throws NoSuchMethodException if the method does not exist
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws NullPointerException if any argument is null
+ * @see MethodHandle#bindTo
+ * @see #findVirtual
+ */
+ public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.bind is not implemented");
+ }
+
+ /**
+ * Makes a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+ * to <i>m</i>, if the lookup class has permission.
+ * If <i>m</i> is non-static, the receiver argument is treated as an initial argument.
+ * If <i>m</i> is virtual, overriding is respected on every call.
+ * Unlike the Core Reflection API, exceptions are <em>not</em> wrapped.
+ * The type of the method handle will be that of the method,
+ * with the receiver type prepended (but only if it is non-static).
+ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * If <i>m</i> is not public, do not share the resulting handle with untrusted parties.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If <i>m</i> is static, and
+ * if the returned method handle is invoked, the method's class will
+ * be initialized, if it has not already been initialized.
+ * @param m the reflected method
+ * @return a method handle which can invoke the reflected method
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflect(Method m) throws IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.unreflect is not implemented");
+ }
+
+ /**
+ * Produces a method handle for a reflected method.
+ * It will bypass checks for overriding methods on the receiver,
+ * <a href="MethodHandles.Lookup.html#equiv">as if called</a> from an {@code invokespecial}
+ * instruction from within the explicitly specified {@code specialCaller}.
+ * The type of the method handle will be that of the method,
+ * with a suitably restricted receiver type prepended.
+ * (The receiver type will be {@code specialCaller} or a subtype.)
+ * If the method's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class,
+ * as if {@code invokespecial} instruction were being linked.
+ * <p>
+ * Before method resolution,
+ * if the explicitly specified caller class is not identical with the
+ * lookup class, or if this lookup object does not have
+ * <a href="MethodHandles.Lookup.html#privacc">private access</a>
+ * privileges, the access fails.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the method's variable arity modifier bit ({@code 0x0080}) is set.
+ * @param m the reflected method
+ * @param specialCaller the class nominally calling the method
+ * @return a method handle which can invoke the reflected method
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if any argument is null
+ */
+ public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.unreflectSpecial is not implemented");
+ }
+
+ /**
+ * Produces a method handle for a reflected constructor.
+ * The type of the method handle will be that of the constructor,
+ * with the return type changed to the declaring class.
+ * The method handle will perform a {@code newInstance} operation,
+ * creating a new instance of the constructor's class on the
+ * arguments passed to the method handle.
+ * <p>
+ * If the constructor's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * The returned method handle will have
+ * {@linkplain MethodHandle#asVarargsCollector variable arity} if and only if
+ * the constructor's variable arity modifier bit ({@code 0x0080}) is set.
+ * <p>
+ * If the returned method handle is invoked, the constructor's class will
+ * be initialized, if it has not already been initialized.
+ * @param c the reflected constructor
+ * @return a method handle which can invoke the reflected constructor
+ * @throws IllegalAccessException if access checking fails
+ * or if the method's variable arity modifier bit
+ * is set and {@code asVarargsCollector} fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.unreflectConstructor is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving read access to a reflected field.
+ * The type of the method handle will have a return type of the field's
+ * value type.
+ * If the field is static, the method handle will take no arguments.
+ * Otherwise, its single argument will be the instance containing
+ * the field.
+ * If the field's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can load values from the reflected field
+ * @throws IllegalAccessException if access checking fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.unreflectGetter is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving write access to a reflected field.
+ * The type of the method handle will have a void return type.
+ * If the field is static, the method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Otherwise, the two arguments will be the instance containing
+ * the field, and the value to be stored.
+ * If the field's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ * <p>
+ * If the field is static, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can store values into the reflected field
+ * @throws IllegalAccessException if access checking fails
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.Lookup.unreflectSetter is not implemented");
+ }
+
+ /**
+ * Cracks a <a href="MethodHandleInfo.html#directmh">direct method handle</a>
+ * created by this lookup object or a similar one.
+ * Security and access checks are performed to ensure that this lookup object
+ * is capable of reproducing the target method handle.
+ * This means that the cracking may fail if target is a direct method handle
+ * but was created by an unrelated lookup object.
+ * This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
+ * and was created by a lookup object for a different class.
+ * @param target a direct method handle to crack into symbolic reference components
+ * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+ * @exception SecurityException if a security manager is present and it
+ * <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+ * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+ * @exception NullPointerException if the target is {@code null}
+ * @see MethodHandleInfo
+ * @since 1.8
+ */
+ public MethodHandleInfo revealDirect(MethodHandle target) {
+ // TODO(narayan): Implement this method.
+ //
+ // Notes: Only works for direct method handles. Must check access.
+ //
+ throw new UnsupportedOperationException("MethodHandles.Lookup.revealDirect is not implemented");
+ }
+
+ private boolean hasPrivateAccess() {
+ return (allowedModes & PRIVATE) != 0;
+ }
+
+ /** Check public/protected/private bits on the symbolic reference class and its member. */
+ void checkAccess(Class<?> refc, Class<?> defc, int mods, String methName)
+ throws IllegalAccessException {
+ int allowedModes = this.allowedModes;
+
+ if (Modifier.isProtected(mods) &&
+ defc == Object.class &&
+ "clone".equals(methName) &&
+ refc.isArray()) {
+ // The JVM does this hack also.
+ // (See ClassVerifier::verify_invoke_instructions
+ // and LinkResolver::check_method_accessability.)
+ // Because the JVM does not allow separate methods on array types,
+ // there is no separate method for int[].clone.
+ // All arrays simply inherit Object.clone.
+ // But for access checking logic, we make Object.clone
+ // (normally protected) appear to be public.
+ // Later on, when the DirectMethodHandle is created,
+ // its leading argument will be restricted to the
+ // requested array type.
+ // N.B. The return type is not adjusted, because
+ // that is *not* the bytecode behavior.
+ mods ^= Modifier.PROTECTED | Modifier.PUBLIC;
+ }
+
+ if (Modifier.isProtected(mods) && Modifier.isConstructor(mods)) {
+ // cannot "new" a protected ctor in a different package
+ mods ^= Modifier.PROTECTED;
+ }
+
+ if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0)
+ return; // common case
+ int requestedModes = fixmods(mods); // adjust 0 => PACKAGE
+ if ((requestedModes & allowedModes) != 0) {
+ if (VerifyAccess.isMemberAccessible(refc, defc, mods, lookupClass(), allowedModes))
+ return;
+ } else {
+ // Protected members can also be checked as if they were package-private.
+ if ((requestedModes & PROTECTED) != 0 && (allowedModes & PACKAGE) != 0
+ && VerifyAccess.isSamePackage(defc, lookupClass()))
+ return;
+ }
+
+ throwMakeAccessException(accessFailedMessage(refc, defc, mods), this);
+ }
+
+ String accessFailedMessage(Class<?> refc, Class<?> defc, int mods) {
+ // check the class first:
+ boolean classOK = (Modifier.isPublic(defc.getModifiers()) &&
+ (defc == refc ||
+ Modifier.isPublic(refc.getModifiers())));
+ if (!classOK && (allowedModes & PACKAGE) != 0) {
+ classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
+ (defc == refc ||
+ VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
+ }
+ if (!classOK)
+ return "class is not public";
+ if (Modifier.isPublic(mods))
+ return "access to public member failed"; // (how?)
+ if (Modifier.isPrivate(mods))
+ return "member is private";
+ if (Modifier.isProtected(mods))
+ return "member is protected";
+ return "member is private to package";
+ }
+
+ private static final boolean ALLOW_NESTMATE_ACCESS = false;
+
+ private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
+ int allowedModes = this.allowedModes;
+ // Android-changed: No support for TRUSTED lookups.
+ // if (allowedModes == TRUSTED) return;
+ if (!hasPrivateAccess()
+ || (specialCaller != lookupClass()
+ && !(ALLOW_NESTMATE_ACCESS &&
+ VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
+ throwMakeAccessException("no private access for invokespecial", this);
+ }
+
+ public void throwMakeAccessException(String message, Object from) throws
+ IllegalAccessException{
+ message = message + ": "+ toString();
+ if (from != null) message += ", from " + from;
+ throw new IllegalAccessException(message);
+ }
+ }
+
+ /**
+ * Produces a method handle giving read access to elements of an array.
+ * The type of the method handle will have a return type of the array's
+ * element type. Its first argument will be the array type,
+ * and the second will be {@code int}.
+ * @param arrayClass an array type
+ * @return a method handle which can load values from the given array type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ */
+ public static
+ MethodHandle arrayElementGetter(Class<?> arrayClass) throws IllegalArgumentException {
+ // return MethodHandleImpl.makeArrayElementAccessor(arrayClass, false);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.arrayElementGetter is not implemented");
+ }
+
+ /**
+ * Produces a method handle giving write access to elements of an array.
+ * The type of the method handle will have a void return type.
+ * Its last argument will be the array's element type.
+ * The first and second arguments will be the array type and int.
+ * @param arrayClass the class of an array
+ * @return a method handle which can store values into the array type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if arrayClass is not an array type
+ */
+ public static
+ MethodHandle arrayElementSetter(Class<?> arrayClass) throws IllegalArgumentException {
+ // return MethodHandleImpl.makeArrayElementAccessor(arrayClass, true);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.arrayElementSetter is not implemented");
+ }
+
+ /// method handle invocation (reflective style)
+
+ /**
+ * Produces a method handle which will invoke any method handle of the
+ * given {@code type}, with a given number of trailing arguments replaced by
+ * a single trailing {@code Object[]} array.
+ * The resulting invoker will be a method handle with the following
+ * arguments:
+ * <ul>
+ * <li>a single {@code MethodHandle} target
+ * <li>zero or more leading values (counted by {@code leadingArgCount})
+ * <li>an {@code Object[]} array containing trailing arguments
+ * </ul>
+ * <p>
+ * The invoker will invoke its target like a call to {@link MethodHandle#invoke invoke} with
+ * the indicated {@code type}.
+ * That is, if the target is exactly of the given {@code type}, it will behave
+ * like {@code invokeExact}; otherwise it behave as if {@link MethodHandle#asType asType}
+ * is used to convert the target to the required {@code type}.
+ * <p>
+ * The type of the returned invoker will not be the given {@code type}, but rather
+ * will have all parameters except the first {@code leadingArgCount}
+ * replaced by a single array of type {@code Object[]}, which will be
+ * the final parameter.
+ * <p>
+ * Before invoking its target, the invoker will spread the final array, apply
+ * reference casts as necessary, and unbox and widen primitive arguments.
+ * If, when the invoker is called, the supplied array argument does
+ * not have the correct number of elements, the invoker will throw
+ * an {@link IllegalArgumentException} instead of invoking the target.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * <blockquote><pre>{@code
+MethodHandle invoker = MethodHandles.invoker(type);
+int spreadArgCount = type.parameterCount() - leadingArgCount;
+invoker = invoker.asSpreader(Object[].class, spreadArgCount);
+return invoker;
+ * }</pre></blockquote>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @param leadingArgCount number of fixed arguments, to be passed unchanged to the target
+ * @return a method handle suitable for invoking any method handle of the given type
+ * @throws NullPointerException if {@code type} is null
+ * @throws IllegalArgumentException if {@code leadingArgCount} is not in
+ * the range from 0 to {@code type.parameterCount()} inclusive,
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle spreadInvoker(MethodType type, int leadingArgCount) {
+ if (leadingArgCount < 0 || leadingArgCount > type.parameterCount())
+ throw newIllegalArgumentException("bad argument count", leadingArgCount);
+ type = type.asSpreaderType(Object[].class, type.parameterCount() - leadingArgCount);
+ // return type.invokers().spreadInvoker(leadingArgCount);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.spreadInvoker is not implemented");
+ }
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke any method handle of the given type, as if by {@link MethodHandle#invokeExact invokeExact}.
+ * The resulting invoker will have a type which is
+ * exactly equal to the desired type, except that it will accept
+ * an additional leading argument of type {@code MethodHandle}.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invokeExact", type)}
+ *
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * Invoker method handles can be useful when working with variable method handles
+ * of unknown types.
+ * For example, to emulate an {@code invokeExact} call to a variable method
+ * handle {@code M}, extract its type {@code T},
+ * look up the invoker method {@code X} for {@code T},
+ * and call the invoker method, as {@code X.invoke(T, A...)}.
+ * (It would not work to call {@code X.invokeExact}, since the type {@code T}
+ * is unknown.)
+ * If spreading, collecting, or other argument transformations are required,
+ * they can be applied once to the invoker {@code X} and reused on many {@code M}
+ * method handle values, as long as they are compatible with the type of {@code X}.
+ * <p style="font-size:smaller;">
+ * <em>(Note: The invoker method is not available via the Core Reflection API.
+ * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * on the declared {@code invokeExact} or {@code invoke} method will raise an
+ * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+ * <p>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @return a method handle suitable for invoking any method handle of the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle exactInvoker(MethodType type) {
+ // return type.invokers().exactInvoker();
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.exactInvoker is not implemented");
+ }
+
+ /**
+ * Produces a special <em>invoker method handle</em> which can be used to
+ * invoke any method handle compatible with the given type, as if by {@link MethodHandle#invoke invoke}.
+ * The resulting invoker will have a type which is
+ * exactly equal to the desired type, except that it will accept
+ * an additional leading argument of type {@code MethodHandle}.
+ * <p>
+ * Before invoking its target, if the target differs from the expected type,
+ * the invoker will apply reference casts as
+ * necessary and box, unbox, or widen primitive values, as if by {@link MethodHandle#asType asType}.
+ * Similarly, the return value will be converted as necessary.
+ * If the target is a {@linkplain MethodHandle#asVarargsCollector variable arity method handle},
+ * the required arity conversion will be made, again as if by {@link MethodHandle#asType asType}.
+ * <p>
+ * This method is equivalent to the following code (though it may be more efficient):
+ * {@code publicLookup().findVirtual(MethodHandle.class, "invoke", type)}
+ * <p style="font-size:smaller;">
+ * <em>Discussion:</em>
+ * A {@linkplain MethodType#genericMethodType general method type} is one which
+ * mentions only {@code Object} arguments and return values.
+ * An invoker for such a type is capable of calling any method handle
+ * of the same arity as the general type.
+ * <p style="font-size:smaller;">
+ * <em>(Note: The invoker method is not available via the Core Reflection API.
+ * An attempt to call {@linkplain java.lang.reflect.Method#invoke java.lang.reflect.Method.invoke}
+ * on the declared {@code invokeExact} or {@code invoke} method will raise an
+ * {@link java.lang.UnsupportedOperationException UnsupportedOperationException}.)</em>
+ * <p>
+ * This method throws no reflective or security exceptions.
+ * @param type the desired target type
+ * @return a method handle suitable for invoking any method handle convertible to the given type
+ * @throws IllegalArgumentException if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ static public
+ MethodHandle invoker(MethodType type) {
+ // return type.invokers().genericInvoker();
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.invoker is not implemented");
+ }
+
+ // Android-changed: Basic invokers are not supported.
+ //
+ // static /*non-public*/
+ // MethodHandle basicInvoker(MethodType type) {
+ // return type.invokers().basicInvoker();
+ // }
+
+ /// method handle modification (creation from other method handles)
+
+ /**
+ * Produces a method handle which adapts the type of the
+ * given method handle to a new type by pairwise argument and return type conversion.
+ * The original type and new type must have the same number of arguments.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ * <p>
+ * If the original type and new type are equal, returns target.
+ * <p>
+ * The same conversions are allowed as for {@link MethodHandle#asType MethodHandle.asType},
+ * and some additional conversions are also applied if those conversions fail.
+ * Given types <em>T0</em>, <em>T1</em>, one of the following conversions is applied
+ * if possible, before or instead of any conversions done by {@code asType}:
+ * <ul>
+ * <li>If <em>T0</em> and <em>T1</em> are references, and <em>T1</em> is an interface type,
+ * then the value of type <em>T0</em> is passed as a <em>T1</em> without a cast.
+ * (This treatment of interfaces follows the usage of the bytecode verifier.)
+ * <li>If <em>T0</em> is boolean and <em>T1</em> is another primitive,
+ * the boolean is converted to a byte value, 1 for true, 0 for false.
+ * (This treatment follows the usage of the bytecode verifier.)
+ * <li>If <em>T1</em> is boolean and <em>T0</em> is another primitive,
+ * <em>T0</em> is converted to byte via Java casting conversion (JLS 5.5),
+ * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}.
+ * <li>If <em>T0</em> and <em>T1</em> are primitives other than boolean,
+ * then a Java casting conversion (JLS 5.5) is applied.
+ * (Specifically, <em>T0</em> will convert to <em>T1</em> by
+ * widening and/or narrowing.)
+ * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive, an unboxing
+ * conversion will be applied at runtime, possibly followed
+ * by a Java casting conversion (JLS 5.5) on the primitive value,
+ * possibly followed by a conversion from byte to boolean by testing
+ * the low-order bit.
+ * <li>If <em>T0</em> is a reference and <em>T1</em> a primitive,
+ * and if the reference is null at runtime, a zero value is introduced.
+ * </ul>
+ * @param target the method handle to invoke after arguments are retyped
+ * @param newType the expected type of the new method handle
+ * @return a method handle which delegates to the target after performing
+ * any necessary argument conversions, and arranges for any
+ * necessary return value conversions
+ * @throws NullPointerException if either argument is null
+ * @throws WrongMethodTypeException if the conversion cannot be made
+ * @see MethodHandle#asType
+ */
+ public static
+ MethodHandle explicitCastArguments(MethodHandle target, MethodType newType) {
+ explicitCastArgumentsChecks(target, newType);
+ // use the asTypeCache when possible:
+ MethodType oldType = target.type();
+ if (oldType == newType) return target;
+ if (oldType.explicitCastEquivalentToAsType(newType)) {
+ return target.asFixedArity().asType(newType);
+ }
+
+ // return MethodHandleImpl.makePairwiseConvert(target, newType, false);
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.explicitCastArguments is not implemented");
+ }
+
+ private static void explicitCastArgumentsChecks(MethodHandle target, MethodType newType) {
+ if (target.type().parameterCount() != newType.parameterCount()) {
+ throw new WrongMethodTypeException("cannot explicitly cast " + target + " to " + newType);
+ }
+ }
+
+ /**
+ * Produces a method handle which adapts the calling sequence of the
+ * given method handle to a new type, by reordering the arguments.
+ * The resulting method handle is guaranteed to report a type
+ * which is equal to the desired new type.
+ * <p>
+ * The given array controls the reordering.
+ * Call {@code #I} the number of incoming parameters (the value
+ * {@code newType.parameterCount()}, and call {@code #O} the number
+ * of outgoing parameters (the value {@code target.type().parameterCount()}).
+ * Then the length of the reordering array must be {@code #O},
+ * and each element must be a non-negative number less than {@code #I}.
+ * For every {@code N} less than {@code #O}, the {@code N}-th
+ * outgoing argument will be taken from the {@code I}-th incoming
+ * argument, where {@code I} is {@code reorder[N]}.
+ * <p>
+ * No argument or return value conversions are applied.
+ * The type of each incoming argument, as determined by {@code newType},
+ * must be identical to the type of the corresponding outgoing parameter
+ * or parameters in the target method handle.
+ * The return type of {@code newType} must be identical to the return
+ * type of the original target.
+ * <p>
+ * The reordering array need not specify an actual permutation.
+ * An incoming argument will be duplicated if its index appears
+ * more than once in the array, and an incoming argument will be dropped
+ * if its index does not appear in the array.
+ * As in the case of {@link #dropArguments(MethodHandle,int,List) dropArguments},
+ * incoming arguments which are not mentioned in the reordering array
+ * are may be any type, as determined only by {@code newType}.
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodType intfn1 = methodType(int.class, int.class);
+MethodType intfn2 = methodType(int.class, int.class, int.class);
+MethodHandle sub = ... (int x, int y) -> (x-y) ...;
+assert(sub.type().equals(intfn2));
+MethodHandle sub1 = permuteArguments(sub, intfn2, 0, 1);
+MethodHandle rsub = permuteArguments(sub, intfn2, 1, 0);
+assert((int)rsub.invokeExact(1, 100) == 99);
+MethodHandle add = ... (int x, int y) -> (x+y) ...;
+assert(add.type().equals(intfn2));
+MethodHandle twice = permuteArguments(add, intfn1, 0, 0);
+assert(twice.type().equals(intfn1));
+assert((int)twice.invokeExact(21) == 42);
+ * }</pre></blockquote>
+ * @param target the method handle to invoke after arguments are reordered
+ * @param newType the expected type of the new method handle
+ * @param reorder an index array which controls the reordering
+ * @return a method handle which delegates to the target after it
+ * drops unused arguments and moves and/or duplicates the other arguments
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if the index array length is not equal to
+ * the arity of the target, or if any index array element
+ * not a valid index for a parameter of {@code newType},
+ * or if two corresponding parameter types in
+ * {@code target.type()} and {@code newType} are not identical,
+ */
+ public static
+ MethodHandle permuteArguments(MethodHandle target, MethodType newType, int... reorder) {
+ reorder = reorder.clone(); // get a private copy
+ MethodType oldType = target.type();
+ permuteArgumentChecks(reorder, newType, oldType);
+
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.permuteArguments is not implemented");
+ }
+
+ // Android-changed: findFirstDupOrDrop is unused and removed.
+ // private static int findFirstDupOrDrop(int[] reorder, int newArity);
+
+ private static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodType oldType) {
+ if (newType.returnType() != oldType.returnType())
+ throw newIllegalArgumentException("return types do not match",
+ oldType, newType);
+ if (reorder.length == oldType.parameterCount()) {
+ int limit = newType.parameterCount();
+ boolean bad = false;
+ for (int j = 0; j < reorder.length; j++) {
+ int i = reorder[j];
+ if (i < 0 || i >= limit) {
+ bad = true; break;
+ }
+ Class<?> src = newType.parameterType(i);
+ Class<?> dst = oldType.parameterType(j);
+ if (src != dst)
+ throw newIllegalArgumentException("parameter types do not match after reorder",
+ oldType, newType);
+ }
+ if (!bad) return true;
+ }
+ throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder));
+ }
+
+ /**
+ * Produces a method handle of the requested return type which returns the given
+ * constant value every time it is invoked.
+ * <p>
+ * Before the method handle is returned, the passed-in value is converted to the requested type.
+ * If the requested type is primitive, widening primitive conversions are attempted,
+ * else reference conversions are attempted.
+ * <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
+ * @param type the return type of the desired method handle
+ * @param value the value to return
+ * @return a method handle of the given return type and no arguments, which always returns the given value
+ * @throws NullPointerException if the {@code type} argument is null
+ * @throws ClassCastException if the value cannot be converted to the required return type
+ * @throws IllegalArgumentException if the given type is {@code void.class}
+ */
+ public static
+ MethodHandle constant(Class<?> type, Object value) {
+ if (type.isPrimitive()) {
+ if (type == void.class)
+ throw newIllegalArgumentException("void type");
+ Wrapper w = Wrapper.forPrimitiveType(type);
+ value = w.convert(value, type);
+ if (w.zero().equals(value))
+ return zero(w, type);
+ return insertArguments(identity(type), 0, value);
+ } else {
+ if (value == null)
+ return zero(Wrapper.OBJECT, type);
+ return identity(type).bindTo(value);
+ }
+ }
+
+ /**
+ * Produces a method handle which returns its sole argument when invoked.
+ * @param type the type of the sole parameter and return value of the desired method handle
+ * @return a unary method handle which accepts and returns the given type
+ * @throws NullPointerException if the argument is null
+ * @throws IllegalArgumentException if the given type is {@code void.class}
+ */
+ public static
+ MethodHandle identity(Class<?> type) {
+ Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
+ int pos = btw.ordinal();
+ MethodHandle ident = IDENTITY_MHS[pos];
+ if (ident == null) {
+ ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
+ }
+ if (ident.type().returnType() == type)
+ return ident;
+ // something like identity(Foo.class); do not bother to intern these
+ assert(btw == Wrapper.OBJECT);
+ return makeIdentity(type);
+ }
+ private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
+ private static MethodHandle makeIdentity(Class<?> ptype) {
+ // MethodType mtype = MethodType.methodType(ptype, ptype);
+ // LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
+ // return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.makeIdentity is not implemented");
+ }
+
+ private static MethodHandle zero(Wrapper btw, Class<?> rtype) {
+ int pos = btw.ordinal();
+ MethodHandle zero = ZERO_MHS[pos];
+ if (zero == null) {
+ zero = setCachedMethodHandle(ZERO_MHS, pos, makeZero(btw.primitiveType()));
+ }
+ if (zero.type().returnType() == rtype)
+ return zero;
+ assert(btw == Wrapper.OBJECT);
+ return makeZero(rtype);
+ }
+ private static final MethodHandle[] ZERO_MHS = new MethodHandle[Wrapper.values().length];
+ private static MethodHandle makeZero(Class<?> rtype) {
+ // MethodType mtype = MethodType.methodType(rtype);
+ // LambdaForm lform = LambdaForm.zeroForm(BasicType.basicType(rtype));
+ // return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.ZERO);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.makeZero is not implemented");
+ }
+
+ synchronized private static MethodHandle setCachedMethodHandle(MethodHandle[] cache, int pos, MethodHandle value) {
+ // Simulate a CAS, to avoid racy duplication of results.
+ MethodHandle prev = cache[pos];
+ if (prev != null) return prev;
+ return cache[pos] = value;
+ }
+
+ /**
+ * Provides a target method handle with one or more <em>bound arguments</em>
+ * in advance of the method handle's invocation.
+ * The formal parameters to the target corresponding to the bound
+ * arguments are called <em>bound parameters</em>.
+ * Returns a new method handle which saves away the bound arguments.
+ * When it is invoked, it receives arguments for any non-bound parameters,
+ * binds the saved arguments to their corresponding parameters,
+ * and calls the original target.
+ * <p>
+ * The type of the new method handle will drop the types for the bound
+ * parameters from the original target type, since the new method handle
+ * will no longer require those arguments to be supplied by its callers.
+ * <p>
+ * Each given argument object must match the corresponding bound parameter type.
+ * If a bound parameter type is a primitive, the argument object
+ * must be a wrapper, and will be unboxed to produce the primitive value.
+ * <p>
+ * The {@code pos} argument selects which parameters are to be bound.
+ * It may range between zero and <i>N-L</i> (inclusively),
+ * where <i>N</i> is the arity of the target method handle
+ * and <i>L</i> is the length of the values array.
+ * @param target the method handle to invoke after the argument is inserted
+ * @param pos where to insert the argument (zero for the first)
+ * @param values the series of arguments to insert
+ * @return a method handle which inserts an additional argument,
+ * before calling the original method handle
+ * @throws NullPointerException if the target or the {@code values} array is null
+ * @see MethodHandle#bindTo
+ */
+ public static
+ MethodHandle insertArguments(MethodHandle target, int pos, Object... values) {
+ int insCount = values.length;
+ Class<?>[] ptypes = insertArgumentsChecks(target, insCount, pos);
+ if (insCount == 0) return target;
+
+ // BoundMethodHandle result = target.rebind();
+ // for (int i = 0; i < insCount; i++) {
+ // Object value = values[i];
+ // Class<?> ptype = ptypes[pos+i];
+ // if (ptype.isPrimitive()) {
+ // result = insertArgumentPrimitive(result, pos, ptype, value);
+ // } else {
+ // value = ptype.cast(value); // throw CCE if needed
+ // result = result.bindArgumentL(pos, value);
+ // }
+ // }
+ // return result;
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.insertArguments is not implemented");
+ }
+
+ // Android-changed: insertArgumentPrimitive is unused.
+ //
+ // private static BoundMethodHandle insertArgumentPrimitive(BoundMethodHandle result, int pos,
+ // Class<?> ptype, Object value) {
+ // Wrapper w = Wrapper.forPrimitiveType(ptype);
+ // // perform unboxing and/or primitive conversion
+ // value = w.convert(value, ptype);
+ // switch (w) {
+ // case INT: return result.bindArgumentI(pos, (int)value);
+ // case LONG: return result.bindArgumentJ(pos, (long)value);
+ // case FLOAT: return result.bindArgumentF(pos, (float)value);
+ // case DOUBLE: return result.bindArgumentD(pos, (double)value);
+ // default: return result.bindArgumentI(pos, ValueConversions.widenSubword(value));
+ // }
+ // }
+
+ private static Class<?>[] insertArgumentsChecks(MethodHandle target, int insCount, int pos) throws RuntimeException {
+ MethodType oldType = target.type();
+ int outargs = oldType.parameterCount();
+ int inargs = outargs - insCount;
+ if (inargs < 0)
+ throw newIllegalArgumentException("too many values to insert");
+ if (pos < 0 || pos > inargs)
+ throw newIllegalArgumentException("no argument type to append");
+ return oldType.ptypes();
+ }
+
+ /**
+ * Produces a method handle which will discard some dummy arguments
+ * before calling some other specified <i>target</i> method handle.
+ * The type of the new method handle will be the same as the target's type,
+ * except it will also include the dummy argument types,
+ * at some given position.
+ * <p>
+ * The {@code pos} argument may range between zero and <i>N</i>,
+ * where <i>N</i> is the arity of the target.
+ * If {@code pos} is zero, the dummy arguments will precede
+ * the target's real arguments; if {@code pos} is <i>N</i>
+ * they will come after.
+ * <p>
+ * <b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodType bigType = cat.type().insertParameterTypes(0, int.class, String.class);
+MethodHandle d0 = dropArguments(cat, 0, bigType.parameterList().subList(0,2));
+assertEquals(bigType, d0.type());
+assertEquals("yz", (String) d0.invokeExact(123, "x", "y", "z"));
+ * }</pre></blockquote>
+ * <p>
+ * This method is also equivalent to the following code:
+ * <blockquote><pre>
+ * {@link #dropArguments(MethodHandle,int,Class...) dropArguments}{@code (target, pos, valueTypes.toArray(new Class[0]))}
+ * </pre></blockquote>
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
+ * before calling the original method handle
+ * @throws NullPointerException if the target is null,
+ * or if the {@code valueTypes} list or any of its elements is null
+ * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+ * or if {@code pos} is negative or greater than the arity of the target,
+ * or if the new method handle's type would have too many parameters
+ */
+ public static
+ MethodHandle dropArguments(MethodHandle target, int pos, List<Class<?>> valueTypes) {
+ MethodType oldType = target.type(); // get NPE
+ int dropped = dropArgumentChecks(oldType, pos, valueTypes);
+
+ MethodType newType = oldType.insertParameterTypes(pos, valueTypes);
+ // if (dropped == 0) return target;
+ // BoundMethodHandle result = target.rebind();
+ // LambdaForm lform = result.form;
+ // int insertFormArg = 1 + pos;
+ // for (Class<?> ptype : valueTypes) {
+ // lform = lform.editor().addArgumentForm(insertFormArg++, BasicType.basicType(ptype));
+ // }
+ // result = result.copyWith(newType, lform);
+ // return result;
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.dropArguments is not implemented");
+ }
+
+ private static int dropArgumentChecks(MethodType oldType, int pos, List<Class<?>> valueTypes) {
+ int dropped = valueTypes.size();
+ MethodType.checkSlotCount(dropped);
+ int outargs = oldType.parameterCount();
+ int inargs = outargs + dropped;
+ if (pos < 0 || pos > outargs)
+ throw newIllegalArgumentException("no argument type to remove"
+ + Arrays.asList(oldType, pos, valueTypes, inargs, outargs)
+ );
+ return dropped;
+ }
+
+ /**
+ * Produces a method handle which will discard some dummy arguments
+ * before calling some other specified <i>target</i> method handle.
+ * The type of the new method handle will be the same as the target's type,
+ * except it will also include the dummy argument types,
+ * at some given position.
+ * <p>
+ * The {@code pos} argument may range between zero and <i>N</i>,
+ * where <i>N</i> is the arity of the target.
+ * If {@code pos} is zero, the dummy arguments will precede
+ * the target's real arguments; if {@code pos} is <i>N</i>
+ * they will come after.
+ * <p>
+ * <b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle d0 = dropArguments(cat, 0, String.class);
+assertEquals("yz", (String) d0.invokeExact("x", "y", "z"));
+MethodHandle d1 = dropArguments(cat, 1, String.class);
+assertEquals("xz", (String) d1.invokeExact("x", "y", "z"));
+MethodHandle d2 = dropArguments(cat, 2, String.class);
+assertEquals("xy", (String) d2.invokeExact("x", "y", "z"));
+MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+assertEquals("xz", (String) d12.invokeExact("x", 12, true, "z"));
+ * }</pre></blockquote>
+ * <p>
+ * This method is also equivalent to the following code:
+ * <blockquote><pre>
+ * {@link #dropArguments(MethodHandle,int,List) dropArguments}{@code (target, pos, Arrays.asList(valueTypes))}
+ * </pre></blockquote>
+ * @param target the method handle to invoke after the arguments are dropped
+ * @param valueTypes the type(s) of the argument(s) to drop
+ * @param pos position of first argument to drop (zero for the leftmost)
+ * @return a method handle which drops arguments of the given types,
+ * before calling the original method handle
+ * @throws NullPointerException if the target is null,
+ * or if the {@code valueTypes} array or any of its elements is null
+ * @throws IllegalArgumentException if any element of {@code valueTypes} is {@code void.class},
+ * or if {@code pos} is negative or greater than the arity of the target,
+ * or if the new method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ public static
+ MethodHandle dropArguments(MethodHandle target, int pos, Class<?>... valueTypes) {
+ return dropArguments(target, pos, Arrays.asList(valueTypes));
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * one or more of its arguments, each with its own unary filter function,
+ * and then calling the target with each pre-processed argument
+ * replaced by the result of its corresponding filter function.
+ * <p>
+ * The pre-processing is performed by one or more method handles,
+ * specified in the elements of the {@code filters} array.
+ * The first element of the filter array corresponds to the {@code pos}
+ * argument of the target, and so on in sequence.
+ * <p>
+ * Null arguments in the array are treated as identity functions,
+ * and the corresponding arguments left unchanged.
+ * (If there are no non-null elements in the array, the original target is returned.)
+ * Each filter is applied to the corresponding argument of the adapter.
+ * <p>
+ * If a filter {@code F} applies to the {@code N}th argument of
+ * the target, then {@code F} must be a method handle which
+ * takes exactly one argument. The type of {@code F}'s sole argument
+ * replaces the corresponding argument type of the target
+ * in the resulting adapted method handle.
+ * The return type of {@code F} must be identical to the corresponding
+ * parameter type of the target.
+ * <p>
+ * It is an error if there are elements of {@code filters}
+ * (null or not)
+ * which do not correspond to argument positions in the target.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle upcase = lookup().findVirtual(String.class,
+ "toUpperCase", methodType(String.class));
+assertEquals("xy", (String) cat.invokeExact("x", "y"));
+MethodHandle f0 = filterArguments(cat, 0, upcase);
+assertEquals("Xy", (String) f0.invokeExact("x", "y")); // Xy
+MethodHandle f1 = filterArguments(cat, 1, upcase);
+assertEquals("xY", (String) f1.invokeExact("x", "y")); // xY
+MethodHandle f2 = filterArguments(cat, 0, upcase, upcase);
+assertEquals("XY", (String) f2.invokeExact("x", "y")); // XY
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * V target(P... p, A[i]... a[i], B... b);
+ * A[i] filter[i](V[i]);
+ * T adapter(P... p, V[i]... v[i], B... b) {
+ * return target(p..., f[i](v[i])..., b...);
+ * }
+ * }</pre></blockquote>
+ *
+ * @param target the method handle to invoke after arguments are filtered
+ * @param pos the position of the first argument to filter
+ * @param filters method handles to call initially on filtered arguments
+ * @return method handle which incorporates the specified argument filtering logic
+ * @throws NullPointerException if the target is null
+ * or if the {@code filters} array is null
+ * @throws IllegalArgumentException if a non-null element of {@code filters}
+ * does not match a corresponding argument type of target as described above,
+ * or if the {@code pos+filters.length} is greater than {@code target.type().parameterCount()},
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ */
+ public static
+ MethodHandle filterArguments(MethodHandle target, int pos, MethodHandle... filters) {
+ filterArgumentsCheckArity(target, pos, filters);
+ MethodHandle adapter = target;
+ int curPos = pos-1; // pre-incremented
+ for (MethodHandle filter : filters) {
+ curPos += 1;
+ if (filter == null) continue; // ignore null elements of filters
+ adapter = filterArgument(adapter, curPos, filter);
+ }
+ return adapter;
+ }
+
+ /*non-public*/ static
+ MethodHandle filterArgument(MethodHandle target, int pos, MethodHandle filter) {
+ filterArgumentChecks(target, pos, filter);
+ // MethodType targetType = target.type();
+ // MethodType filterType = filter.type();
+ // BoundMethodHandle result = target.rebind();
+ // Class<?> newParamType = filterType.parameterType(0);
+ // LambdaForm lform = result.editor().filterArgumentForm(1 + pos, BasicType.basicType(newParamType));
+ // MethodType newType = targetType.changeParameterType(pos, newParamType);
+ // result = result.copyWithExtendL(newType, lform, filter);
+ // return result;
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.filterArgument is not implemented");
+ }
+
+ private static void filterArgumentsCheckArity(MethodHandle target, int pos, MethodHandle[] filters) {
+ MethodType targetType = target.type();
+ int maxPos = targetType.parameterCount();
+ if (pos + filters.length > maxPos)
+ throw newIllegalArgumentException("too many filters");
+ }
+
+ private static void filterArgumentChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ if (filterType.parameterCount() != 1
+ || filterType.returnType() != targetType.parameterType(pos))
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * a sub-sequence of its arguments with a filter (another method handle).
+ * The pre-processed arguments are replaced by the result (if any) of the
+ * filter function.
+ * The target is then called on the modified (usually shortened) argument list.
+ * <p>
+ * If the filter returns a value, the target must accept that value as
+ * its argument in position {@code pos}, preceded and/or followed by
+ * any arguments not passed to the filter.
+ * If the filter returns void, the target must accept all arguments
+ * not passed to the filter.
+ * No arguments are reordered, and a result returned from the filter
+ * replaces (in order) the whole subsequence of arguments originally
+ * passed to the adapter.
+ * <p>
+ * The argument types (if any) of the filter
+ * replace zero or one argument types of the target, at position {@code pos},
+ * in the resulting adapted method handle.
+ * The return type of the filter (if any) must be identical to the
+ * argument type of the target at position {@code pos}, and that target argument
+ * is supplied by the return value of the filter.
+ * <p>
+ * In all cases, {@code pos} must be greater than or equal to zero, and
+ * {@code pos} must also be less than or equal to the target's arity.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle deepToString = publicLookup()
+ .findStatic(Arrays.class, "deepToString", methodType(String.class, Object[].class));
+
+MethodHandle ts1 = deepToString.asCollector(String[].class, 1);
+assertEquals("[strange]", (String) ts1.invokeExact("strange"));
+
+MethodHandle ts2 = deepToString.asCollector(String[].class, 2);
+assertEquals("[up, down]", (String) ts2.invokeExact("up", "down"));
+
+MethodHandle ts3 = deepToString.asCollector(String[].class, 3);
+MethodHandle ts3_ts2 = collectArguments(ts3, 1, ts2);
+assertEquals("[top, [up, down], strange]",
+ (String) ts3_ts2.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts1 = collectArguments(ts3_ts2, 3, ts1);
+assertEquals("[top, [up, down], [strange]]",
+ (String) ts3_ts2_ts1.invokeExact("top", "up", "down", "strange"));
+
+MethodHandle ts3_ts2_ts3 = collectArguments(ts3_ts2, 1, ts3);
+assertEquals("[top, [[up, down, strange], charm], bottom]",
+ (String) ts3_ts2_ts3.invokeExact("top", "up", "down", "strange", "charm", "bottom"));
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * T target(A...,V,C...);
+ * V filter(B...);
+ * T adapter(A... a,B... b,C... c) {
+ * V v = filter(b...);
+ * return target(a...,v,c...);
+ * }
+ * // and if the filter has no arguments:
+ * T target2(A...,V,C...);
+ * V filter2();
+ * T adapter2(A... a,C... c) {
+ * V v = filter2();
+ * return target2(a...,v,c...);
+ * }
+ * // and if the filter has a void return:
+ * T target3(A...,C...);
+ * void filter3(B...);
+ * void adapter3(A... a,B... b,C... c) {
+ * filter3(b...);
+ * return target3(a...,c...);
+ * }
+ * }</pre></blockquote>
+ * <p>
+ * A collection adapter {@code collectArguments(mh, 0, coll)} is equivalent to
+ * one which first "folds" the affected arguments, and then drops them, in separate
+ * steps as follows:
+ * <blockquote><pre>{@code
+ * mh = MethodHandles.dropArguments(mh, 1, coll.type().parameterList()); //step 2
+ * mh = MethodHandles.foldArguments(mh, coll); //step 1
+ * }</pre></blockquote>
+ * If the target method handle consumes no arguments besides than the result
+ * (if any) of the filter {@code coll}, then {@code collectArguments(mh, 0, coll)}
+ * is equivalent to {@code filterReturnValue(coll, mh)}.
+ * If the filter method handle {@code coll} consumes one argument and produces
+ * a non-void result, then {@code collectArguments(mh, N, coll)}
+ * is equivalent to {@code filterArguments(mh, N, coll)}.
+ * Other equivalences are possible but would require argument permutation.
+ *
+ * @param target the method handle to invoke after filtering the subsequence of arguments
+ * @param pos the position of the first adapter argument to pass to the filter,
+ * and/or the target argument which receives the result of the filter
+ * @param filter method handle to call on the subsequence of arguments
+ * @return method handle which incorporates the specified argument subsequence filtering logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if the return type of {@code filter}
+ * is non-void and is not the same as the {@code pos} argument of the target,
+ * or if {@code pos} is not between 0 and the target's arity, inclusive,
+ * or if the resulting method handle's type would have
+ * <a href="MethodHandle.html#maxarity">too many parameters</a>
+ * @see MethodHandles#foldArguments
+ * @see MethodHandles#filterArguments
+ * @see MethodHandles#filterReturnValue
+ */
+ public static
+ MethodHandle collectArguments(MethodHandle target, int pos, MethodHandle filter) {
+ MethodType newType = collectArgumentsChecks(target, pos, filter);
+ MethodType collectorType = filter.type();
+
+ // BoundMethodHandle result = target.rebind();
+ // LambdaForm lform;
+ // if (collectorType.returnType().isArray() && filter.intrinsicName() == Intrinsic.NEW_ARRAY) {
+ // lform = result.editor().collectArgumentArrayForm(1 + pos, filter);
+ // if (lform != null) {
+ // return result.copyWith(newType, lform);
+ // }
+ // }
+ // lform = result.editor().collectArgumentsForm(1 + pos, collectorType.basicType());
+ // return result.copyWithExtendL(newType, lform, filter);
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.collectArguments is not implemented");
+ }
+
+ private static MethodType collectArgumentsChecks(MethodHandle target, int pos, MethodHandle filter) throws RuntimeException {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ Class<?> rtype = filterType.returnType();
+ List<Class<?>> filterArgs = filterType.parameterList();
+ if (rtype == void.class) {
+ return targetType.insertParameterTypes(pos, filterArgs);
+ }
+ if (rtype != targetType.parameterType(pos)) {
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+ return targetType.dropParameterTypes(pos, pos+1).insertParameterTypes(pos, filterArgs);
+ }
+
+ /**
+ * Adapts a target method handle by post-processing
+ * its return value (if any) with a filter (another method handle).
+ * The result of the filter is returned from the adapter.
+ * <p>
+ * If the target returns a value, the filter must accept that value as
+ * its only argument.
+ * If the target returns void, the filter must accept no arguments.
+ * <p>
+ * The return type of the filter
+ * replaces the return type of the target
+ * in the resulting adapted method handle.
+ * The argument type of the filter (if any) must be identical to the
+ * return type of the target.
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle length = lookup().findVirtual(String.class,
+ "length", methodType(int.class));
+System.out.println((String) cat.invokeExact("x", "y")); // xy
+MethodHandle f0 = filterReturnValue(cat, length);
+System.out.println((int) f0.invokeExact("x", "y")); // 2
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * V target(A...);
+ * T filter(V);
+ * T adapter(A... a) {
+ * V v = target(a...);
+ * return filter(v);
+ * }
+ * // and if the target has a void return:
+ * void target2(A...);
+ * T filter2();
+ * T adapter2(A... a) {
+ * target2(a...);
+ * return filter2();
+ * }
+ * // and if the filter has a void return:
+ * V target3(A...);
+ * void filter3(V);
+ * void adapter3(A... a) {
+ * V v = target3(a...);
+ * filter3(v);
+ * }
+ * }</pre></blockquote>
+ * @param target the method handle to invoke before filtering the return value
+ * @param filter method handle to call on the return value
+ * @return method handle which incorporates the specified return value filtering logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if the argument list of {@code filter}
+ * does not match the return type of target as described above
+ */
+ public static
+ MethodHandle filterReturnValue(MethodHandle target, MethodHandle filter) {
+ MethodType targetType = target.type();
+ MethodType filterType = filter.type();
+ filterReturnValueChecks(targetType, filterType);
+
+ // BoundMethodHandle result = target.rebind();
+ // BasicType rtype = BasicType.basicType(filterType.returnType());
+ // LambdaForm lform = result.editor().filterReturnForm(rtype, false);
+ // MethodType newType = targetType.changeReturnType(filterType.returnType());
+ // result = result.copyWithExtendL(newType, lform, filter);
+ // return result;
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.filterReturnValue is not implemented");
+ }
+
+ private static void filterReturnValueChecks(MethodType targetType, MethodType filterType) throws RuntimeException {
+ Class<?> rtype = targetType.returnType();
+ int filterValues = filterType.parameterCount();
+ if (filterValues == 0
+ ? (rtype != void.class)
+ : (rtype != filterType.parameterType(0)))
+ throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
+ }
+
+ /**
+ * Adapts a target method handle by pre-processing
+ * some of its arguments, and then calling the target with
+ * the result of the pre-processing, inserted into the original
+ * sequence of arguments.
+ * <p>
+ * The pre-processing is performed by {@code combiner}, a second method handle.
+ * Of the arguments passed to the adapter, the first {@code N} arguments
+ * are copied to the combiner, which is then called.
+ * (Here, {@code N} is defined as the parameter count of the combiner.)
+ * After this, control passes to the target, with any result
+ * from the combiner inserted before the original {@code N} incoming
+ * arguments.
+ * <p>
+ * If the combiner returns a value, the first parameter type of the target
+ * must be identical with the return type of the combiner, and the next
+ * {@code N} parameter types of the target must exactly match the parameters
+ * of the combiner.
+ * <p>
+ * If the combiner has a void return, no result will be inserted,
+ * and the first {@code N} parameter types of the target
+ * must exactly match the parameters of the combiner.
+ * <p>
+ * The resulting adapter is the same type as the target, except that the
+ * first parameter type is dropped,
+ * if it corresponds to the result of the combiner.
+ * <p>
+ * (Note that {@link #dropArguments(MethodHandle,int,List) dropArguments} can be used to remove any arguments
+ * that either the combiner or the target does not wish to receive.
+ * If some of the incoming arguments are destined only for the combiner,
+ * consider using {@link MethodHandle#asCollector asCollector} instead, since those
+ * arguments will not need to be live on the stack on entry to the
+ * target.)
+ * <p><b>Example:</b>
+ * <blockquote><pre>{@code
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+...
+MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+ "println", methodType(void.class, String.class))
+ .bindTo(System.out);
+MethodHandle cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+MethodHandle catTrace = foldArguments(cat, trace);
+// also prints "boo":
+assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+ * }</pre></blockquote>
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * // there are N arguments in A...
+ * T target(V, A[N]..., B...);
+ * V combiner(A...);
+ * T adapter(A... a, B... b) {
+ * V v = combiner(a...);
+ * return target(v, a..., b...);
+ * }
+ * // and if the combiner has a void return:
+ * T target2(A[N]..., B...);
+ * void combiner2(A...);
+ * T adapter2(A... a, B... b) {
+ * combiner2(a...);
+ * return target2(a..., b...);
+ * }
+ * }</pre></blockquote>
+ * @param target the method handle to invoke after arguments are combined
+ * @param combiner method handle to call initially on the incoming arguments
+ * @return method handle which incorporates the specified argument folding logic
+ * @throws NullPointerException if either argument is null
+ * @throws IllegalArgumentException if {@code combiner}'s return type
+ * is non-void and not the same as the first argument type of
+ * the target, or if the initial {@code N} argument types
+ * of the target
+ * (skipping one matching the {@code combiner}'s return type)
+ * are not identical with the argument types of {@code combiner}
+ */
+ public static
+ MethodHandle foldArguments(MethodHandle target, MethodHandle combiner) {
+ int foldPos = 0;
+ MethodType targetType = target.type();
+ MethodType combinerType = combiner.type();
+ Class<?> rtype = foldArgumentChecks(foldPos, targetType, combinerType);
+
+ // BoundMethodHandle result = target.rebind();
+ // boolean dropResult = (rtype == void.class);
+ // // Note: This may cache too many distinct LFs. Consider backing off to varargs code.
+ // LambdaForm lform = result.editor().foldArgumentsForm(1 + foldPos, dropResult, combinerType.basicType());
+ // MethodType newType = targetType;
+ // if (!dropResult)
+ // newType = newType.dropParameterTypes(foldPos, foldPos + 1);
+ // result = result.copyWithExtendL(newType, lform, combiner);
+ // return result;
+
+ // TODO(narayan): Implement this method.
+ throw new UnsupportedOperationException("MethodHandles.foldArguments is not implemented");
+ }
+
+ private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
+ int foldArgs = combinerType.parameterCount();
+ Class<?> rtype = combinerType.returnType();
+ int foldVals = rtype == void.class ? 0 : 1;
+ int afterInsertPos = foldPos + foldVals;
+ boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs);
+ if (ok && !(combinerType.parameterList()
+ .equals(targetType.parameterList().subList(afterInsertPos,
+ afterInsertPos + foldArgs))))
+ ok = false;
+ if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(0))
+ ok = false;
+ if (!ok)
+ throw misMatchedTypes("target and combiner types", targetType, combinerType);
+ return rtype;
+ }
+
+ /**
+ * Makes a method handle which adapts a target method handle,
+ * by guarding it with a test, a boolean-valued method handle.
+ * If the guard fails, a fallback handle is called instead.
+ * All three method handles must have the same corresponding
+ * argument and return types, except that the return type
+ * of the test must be boolean, and the test is allowed
+ * to have fewer arguments than the other two method handles.
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * boolean test(A...);
+ * T target(A...,B...);
+ * T fallback(A...,B...);
+ * T adapter(A... a,B... b) {
+ * if (test(a...))
+ * return target(a..., b...);
+ * else
+ * return fallback(a..., b...);
+ * }
+ * }</pre></blockquote>
+ * Note that the test arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the test, and so are passed unchanged
+ * from the caller to the target or fallback as appropriate.
+ * @param test method handle used for test, must return boolean
+ * @param target method handle to call if test passes
+ * @param fallback method handle to call if test fails
+ * @return method handle which incorporates the specified if/then/else logic
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code test} does not return boolean,
+ * or if all three method types do not match (with the return
+ * type of {@code test} changed to match that of the target).
+ */
+ public static
+ MethodHandle guardWithTest(MethodHandle test,
+ MethodHandle target,
+ MethodHandle fallback) {
+ MethodType gtype = test.type();
+ MethodType ttype = target.type();
+ MethodType ftype = fallback.type();
+ if (!ttype.equals(ftype))
+ throw misMatchedTypes("target and fallback types", ttype, ftype);
+ if (gtype.returnType() != boolean.class)
+ throw newIllegalArgumentException("guard type is not a predicate "+gtype);
+ List<Class<?>> targs = ttype.parameterList();
+ List<Class<?>> gargs = gtype.parameterList();
+ if (!targs.equals(gargs)) {
+ int gpc = gargs.size(), tpc = targs.size();
+ if (gpc >= tpc || !targs.subList(0, gpc).equals(gargs))
+ throw misMatchedTypes("target and test types", ttype, gtype);
+ test = dropArguments(test, gpc, targs.subList(gpc, tpc));
+ gtype = test.type();
+ }
+
+ // TODO(narayan): Implement this method.
+ // return MethodHandleImpl.makeGuardWithTest(test, target, fallback);
+ throw new UnsupportedOperationException("MethodHandles.guardWithTest is not implemented");
+ }
+
+ static RuntimeException misMatchedTypes(String what, MethodType t1, MethodType t2) {
+ return newIllegalArgumentException(what + " must match: " + t1 + " != " + t2);
+ }
+
+ /**
+ * Makes a method handle which adapts a target method handle,
+ * by running it inside an exception handler.
+ * If the target returns normally, the adapter returns that value.
+ * If an exception matching the specified type is thrown, the fallback
+ * handle is called instead on the exception, plus the original arguments.
+ * <p>
+ * The target and handler must have the same corresponding
+ * argument and return types, except that handler may omit trailing arguments
+ * (similarly to the predicate in {@link #guardWithTest guardWithTest}).
+ * Also, the handler must have an extra leading parameter of {@code exType} or a supertype.
+ * <p> Here is pseudocode for the resulting adapter:
+ * <blockquote><pre>{@code
+ * T target(A..., B...);
+ * T handler(ExType, A...);
+ * T adapter(A... a, B... b) {
+ * try {
+ * return target(a..., b...);
+ * } catch (ExType ex) {
+ * return handler(ex, a...);
+ * }
+ * }
+ * }</pre></blockquote>
+ * Note that the saved arguments ({@code a...} in the pseudocode) cannot
+ * be modified by execution of the target, and so are passed unchanged
+ * from the caller to the handler, if the handler is invoked.
+ * <p>
+ * The target and handler must return the same type, even if the handler
+ * always throws. (This might happen, for instance, because the handler
+ * is simulating a {@code finally} clause).
+ * To create such a throwing handler, compose the handler creation logic
+ * with {@link #throwException throwException},
+ * in order to create a method handle of the correct return type.
+ * @param target method handle to call
+ * @param exType the type of exception which the handler will catch
+ * @param handler method handle to call if a matching exception is thrown
+ * @return method handle which incorporates the specified try/catch logic
+ * @throws NullPointerException if any argument is null
+ * @throws IllegalArgumentException if {@code handler} does not accept
+ * the given exception type, or if the method handle types do
+ * not match in their return types and their
+ * corresponding parameters
+ */
+ public static
+ MethodHandle catchException(MethodHandle target,
+ Class<? extends Throwable> exType,
+ MethodHandle handler) {
+ MethodType ttype = target.type();
+ MethodType htype = handler.type();
+ if (htype.parameterCount() < 1 ||
+ !htype.parameterType(0).isAssignableFrom(exType))
+ throw newIllegalArgumentException("handler does not accept exception type "+exType);
+ if (htype.returnType() != ttype.returnType())
+ throw misMatchedTypes("target and handler return types", ttype, htype);
+ List<Class<?>> targs = ttype.parameterList();
+ List<Class<?>> hargs = htype.parameterList();
+ hargs = hargs.subList(1, hargs.size()); // omit leading parameter from handler
+ if (!targs.equals(hargs)) {
+ int hpc = hargs.size(), tpc = targs.size();
+ if (hpc >= tpc || !targs.subList(0, hpc).equals(hargs))
+ throw misMatchedTypes("target and handler types", ttype, htype);
+ handler = dropArguments(handler, 1+hpc, targs.subList(hpc, tpc));
+ htype = handler.type();
+ }
+
+ // TODO(narayan): Implement this method.
+ // return MethodHandleImpl.makeGuardWithCatch(target, exType, handler);
+ throw new UnsupportedOperationException("MethodHandles.catchException is not implemented");
+ }
+
+ /**
+ * Produces a method handle which will throw exceptions of the given {@code exType}.
+ * The method handle will accept a single argument of {@code exType},
+ * and immediately throw it as an exception.
+ * The method type will nominally specify a return of {@code returnType}.
+ * The return type may be anything convenient: It doesn't matter to the
+ * method handle's behavior, since it will never return normally.
+ * @param returnType the return type of the desired method handle
+ * @param exType the parameter type of the desired method handle
+ * @return method handle which can throw the given exceptions
+ * @throws NullPointerException if either argument is null
+ */
+ public static
+ MethodHandle throwException(Class<?> returnType, Class<? extends Throwable> exType) {
+ if (!Throwable.class.isAssignableFrom(exType))
+ throw new ClassCastException(exType.getName());
+
+ // TODO(narayan): Implement this method.
+ // return MethodHandleImpl.throwException(MethodType.methodType(returnType, exType));
+ throw new UnsupportedOperationException("MethodHandles.throwException is not implemented");
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java b/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
index ddfbc1d..a88d6c1 100644
--- a/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
+++ b/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
@@ -344,7 +344,7 @@
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
- default <T extends Annotation> Annotation getDeclaredAnnotation(Class<T> annotationClass) {
+ default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
// Loop over all directly-present annotations looking for a matching one
for (Annotation annotation : getDeclaredAnnotations()) {
diff --git a/ojluni/src/main/java/java/lang/reflect/Constructor.java b/ojluni/src/main/java/java/lang/reflect/Constructor.java
index 3e26cbb..7e3a71d 100644
--- a/ojluni/src/main/java/java/lang/reflect/Constructor.java
+++ b/ojluni/src/main/java/java/lang/reflect/Constructor.java
@@ -26,10 +26,8 @@
package java.lang.reflect;
-import java.util.Comparator;
-import libcore.reflect.Types;
-
import java.lang.annotation.Annotation;
+import java.util.Comparator;
/**
* {@code Constructor} provides information about, and access to, a single
@@ -51,7 +49,7 @@
* @author Kenneth Russell
* @author Nakul Saraiya
*/
-public final class Constructor<T> extends AbstractMethod {
+public final class Constructor<T> extends Executable {
private static final Comparator<Method> ORDER_BY_SIGNATURE = null; // Unused; must match Method.
private final Class<?> serializationClass;
@@ -74,14 +72,20 @@
return new Constructor<T>(ctor, cl);
}
+ @Override
+ boolean hasGenericInformation() {
+ // Android-changed: Signature retrieval is handled in Executable.
+ return super.hasGenericInformationInternal();
+ }
+
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public Class<T> getDeclaringClass() {
- // Android-changed: This is handled by AbstractMethod.
- return (Class<T>) super.getDeclaringClass();
+ // Android-changed: This is handled by Executable.
+ return (Class<T>) super.getDeclaringClassInternal();
}
/**
@@ -98,8 +102,8 @@
*/
@Override
public int getModifiers() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getModifiers();
+ // Android-changed: This is handled by Executable.
+ return super.getModifiersInternal();
}
/**
@@ -110,7 +114,7 @@
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public TypeVariable<Constructor<T>>[] getTypeParameters() {
- // Android-changed: This is mostly handled by AbstractMethod.
+ // Android-changed: This is mostly handled by Executable.
GenericInfo info = getMethodOrConstructorGenericInfoInternal();
return (TypeVariable<Constructor<T>>[]) info.formalTypeParameters.clone();
}
@@ -121,16 +125,16 @@
*/
@Override
public Class<?>[] getParameterTypes() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterTypes();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterTypesInternal();
}
/**
* {@inheritDoc}
*/
public int getParameterCount() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterCount();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterCountInternal();
}
/**
@@ -371,7 +375,7 @@
*/
@Override
public Annotation[][] getParameterAnnotations() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterAnnotations();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterAnnotationsInternal();
}
}
diff --git a/ojluni/src/main/java/java/lang/reflect/Executable.java b/ojluni/src/main/java/java/lang/reflect/Executable.java
index 1840566..539716f 100644
--- a/ojluni/src/main/java/java/lang/reflect/Executable.java
+++ b/ojluni/src/main/java/java/lang/reflect/Executable.java
@@ -25,8 +25,15 @@
package java.lang.reflect;
+import com.android.dex.Dex;
+
import java.lang.annotation.Annotation;
+import java.util.Objects;
import libcore.reflect.AnnotatedElements;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.ListOfTypes;
+import libcore.reflect.Types;
+import libcore.util.EmptyArray;
/**
* A shared superclass for the common functionality of {@link Method}
@@ -41,6 +48,11 @@
*/
Executable() {}
+ /**
+ * Does the Executable have generic information.
+ */
+ abstract boolean hasGenericInformation();
+
boolean equalParamTypes(Class<?>[] params1, Class<?>[] params2) {
/* Avoid unnecessary cloning */
if (params1.length == params2.length) {
@@ -108,7 +120,6 @@
*/
abstract void specificToStringHeader(StringBuilder sb);
-
String sharedToGenericString(int modifierMask, boolean isDefault) {
try {
StringBuilder sb = new StringBuilder();
@@ -250,12 +261,168 @@
* type that cannot be instantiated for any reason
*/
public Type[] getGenericParameterTypes() {
- // Android-changed: Implemented in AbstractMethod instead.
- throw new UnsupportedOperationException(
- "Executable.getGenericParameterTypes() not implemented");
+ // Android-changed: Changed to use Types / getMethodOrConstructorGenericInfoInternal()
+ return Types.getTypeArray(
+ getMethodOrConstructorGenericInfoInternal().genericParameterTypes, false);
}
/**
+ * Behaves like {@code getGenericParameterTypes}, but returns type
+ * information for all parameters, including synthetic parameters.
+ */
+ Type[] getAllGenericParameterTypes() {
+ final boolean genericInfo = hasGenericInformation();
+
+ // Easy case: we don't have generic parameter information. In
+ // this case, we just return the result of
+ // getParameterTypes().
+ if (!genericInfo) {
+ return getParameterTypes();
+ } else {
+ final boolean realParamData = hasRealParameterData();
+ final Type[] genericParamTypes = getGenericParameterTypes();
+ final Type[] nonGenericParamTypes = getParameterTypes();
+ final Type[] out = new Type[nonGenericParamTypes.length];
+ final Parameter[] params = getParameters();
+ int fromidx = 0;
+ // If we have real parameter data, then we use the
+ // synthetic and mandate flags to our advantage.
+ if (realParamData) {
+ for (int i = 0; i < out.length; i++) {
+ final Parameter param = params[i];
+ if (param.isSynthetic() || param.isImplicit()) {
+ // If we hit a synthetic or mandated parameter,
+ // use the non generic parameter info.
+ out[i] = nonGenericParamTypes[i];
+ } else {
+ // Otherwise, use the generic parameter info.
+ out[i] = genericParamTypes[fromidx];
+ fromidx++;
+ }
+ }
+ } else {
+ // Otherwise, use the non-generic parameter data.
+ // Without method parameter reflection data, we have
+ // no way to figure out which parameters are
+ // synthetic/mandated, thus, no way to match up the
+ // indexes.
+ return genericParamTypes.length == nonGenericParamTypes.length ?
+ genericParamTypes : nonGenericParamTypes;
+ }
+ return out;
+ }
+ }
+
+ /**
+ * Returns an array of {@code Parameter} objects that represent
+ * all the parameters to the underlying executable represented by
+ * this object. Returns an array of length 0 if the executable
+ * has no parameters.
+ *
+ * <p>The parameters of the underlying executable do not necessarily
+ * have unique names, or names that are legal identifiers in the
+ * Java programming language (JLS 3.8).
+ *
+ * @since 1.8
+ * @throws MalformedParametersException if the class file contains
+ * a MethodParameters attribute that is improperly formatted.
+ * @return an array of {@code Parameter} objects representing all
+ * the parameters to the executable this object represents.
+ */
+ public Parameter[] getParameters() {
+ // TODO: This may eventually need to be guarded by security
+ // mechanisms similar to those in Field, Method, etc.
+ //
+ // Need to copy the cached array to prevent users from messing
+ // with it. Since parameters are immutable, we can
+ // shallow-copy.
+ return privateGetParameters().clone();
+ }
+
+ private Parameter[] synthesizeAllParams() {
+ final int realparams = getParameterCount();
+ final Parameter[] out = new Parameter[realparams];
+ for (int i = 0; i < realparams; i++)
+ // TODO: is there a way to synthetically derive the
+ // modifiers? Probably not in the general case, since
+ // we'd have no way of knowing about them, but there
+ // may be specific cases.
+ out[i] = new Parameter("arg" + i, 0, this, i);
+ return out;
+ }
+
+ private void verifyParameters(final Parameter[] parameters) {
+ final int mask = Modifier.FINAL | Modifier.SYNTHETIC | Modifier.MANDATED;
+
+ if (getParameterTypes().length != parameters.length)
+ throw new MalformedParametersException("Wrong number of parameters in MethodParameters attribute");
+
+ for (Parameter parameter : parameters) {
+ final String name = parameter.getRealName();
+ final int mods = parameter.getModifiers();
+
+ if (name != null) {
+ if (name.isEmpty() || name.indexOf('.') != -1 ||
+ name.indexOf(';') != -1 || name.indexOf('[') != -1 ||
+ name.indexOf('/') != -1) {
+ throw new MalformedParametersException("Invalid parameter name \"" + name + "\"");
+ }
+ }
+
+ if (mods != (mods & mask)) {
+ throw new MalformedParametersException("Invalid parameter modifiers");
+ }
+ }
+ }
+
+ private Parameter[] privateGetParameters() {
+ // Use tmp to avoid multiple writes to a volatile.
+ Parameter[] tmp = parameters;
+
+ if (tmp == null) {
+ // Otherwise, go to the JVM to get them
+ try {
+ tmp = getParameters0();
+ } catch(IllegalArgumentException e) {
+ // Rethrow ClassFormatErrors
+ // Android-changed: Exception changed to be more descriptive.
+ MalformedParametersException e2 =
+ new MalformedParametersException(
+ "Invalid parameter metadata in class file");
+ e2.initCause(e);
+ throw e2;
+ }
+
+ // If we get back nothing, then synthesize parameters
+ if (tmp == null) {
+ hasRealParameterData = false;
+ tmp = synthesizeAllParams();
+ } else {
+ hasRealParameterData = true;
+ verifyParameters(tmp);
+ }
+
+ parameters = tmp;
+ }
+
+ return tmp;
+ }
+
+ boolean hasRealParameterData() {
+ // If this somehow gets called before parameters gets
+ // initialized, force it into existence.
+ if (parameters == null) {
+ privateGetParameters();
+ }
+ return hasRealParameterData;
+ }
+
+ private transient volatile boolean hasRealParameterData;
+ private transient volatile Parameter[] parameters;
+
+ private native Parameter[] getParameters0();
+
+ /**
* Returns an array of {@code Class} objects that represent the
* types of exceptions declared to be thrown by the underlying
* executable represented by this object. Returns an array of
@@ -289,9 +456,9 @@
* parameterized type that cannot be instantiated for any reason
*/
public Type[] getGenericExceptionTypes() {
- // Android-changed: Implemented in AbstractMethod instead.
- throw new UnsupportedOperationException(
- "Executable.getGenericExceptionTypes() not implemented");
+ // Android-changed: Changed to use Types / getMethodOrConstructorGenericInfoInternal()
+ return Types.getTypeArray(
+ getMethodOrConstructorGenericInfoInternal().genericExceptionTypes, false);
}
/**
@@ -310,7 +477,8 @@
* to take a variable number of arguments.
*/
public boolean isVarArgs() {
- return (getModifiers() & Modifier.VARARGS) != 0;
+ // Android-changed: Slightly more efficient.
+ return (accessFlags & Modifier.VARARGS) != 0;
}
/**
@@ -323,7 +491,8 @@
* @jls 13.1 The Form of a Binary
*/
public boolean isSynthetic() {
- return Modifier.isSynthetic(getModifiers());
+ // Android-changed: Slightly more efficient.
+ return (accessFlags & Modifier.SYNTHETIC) != 0;
}
/**
@@ -345,8 +514,11 @@
* A compiler may add extra parameters that are implicitly
* declared in source ("mandated"), as well as parameters that
* are neither implicitly nor explicitly declared in source
- * ("synthetic") to the parameter list for a method.
+ * ("synthetic") to the parameter list for a method. See {@link
+ * java.lang.reflect.Parameter} for more information.
*
+ * @see java.lang.reflect.Parameter
+ * @see java.lang.reflect.Parameter#getAnnotations
* @return an array of arrays that represent the annotations on
* the formal and implicit parameters, in declaration order, of
* the executable represented by this object
@@ -358,9 +530,11 @@
* @throws NullPointerException {@inheritDoc}
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
- // Android-changed: Implemented in AbstractMethod instead.
- throw new UnsupportedOperationException("Executable.getAnnotation(Class) not implemented");
+ Objects.requireNonNull(annotationClass);
+ // Android-changed: Implemented natively.
+ return getAnnotationNative(annotationClass);
}
+ private native <T extends Annotation> T getAnnotationNative(Class<T> annotationClass);
/**
* {@inheritDoc}
@@ -377,8 +551,233 @@
* {@inheritDoc}
*/
public Annotation[] getDeclaredAnnotations() {
- // Android-changed: Implemented in AbstractMethod instead.
- throw new UnsupportedOperationException(
- "Executable.getDeclaredAnnotations() not implemented");
+ // Android-changed: Implemented natively.
+ return getDeclaredAnnotationsNative();
+ }
+ private native Annotation[] getDeclaredAnnotationsNative();
+
+ // Android-changed: Additional ART-related fields and logic below that is shared between
+ // Method and Constructor.
+
+ /** Bits encoding access (e.g. public, private) as well as other runtime specific flags */
+ @SuppressWarnings("unused") // set by runtime
+ private int accessFlags;
+
+ /**
+ * The ArtMethod associated with this Executable, required for dispatching due to entrypoints
+ * Classloader is held live by the declaring class.
+ */
+ @SuppressWarnings("unused") // set by runtime
+ private long artMethod;
+
+ /** Executable's declaring class */
+ @SuppressWarnings("unused") // set by runtime
+ private Class<?> declaringClass;
+
+ /**
+ * Overriden method's declaring class (same as declaringClass unless declaringClass is a proxy
+ * class).
+ */
+ @SuppressWarnings("unused") // set by runtime
+ private Class<?> declaringClassOfOverriddenMethod;
+
+ /** The method index of this method within its defining dex file */
+ @SuppressWarnings("unused") // set by runtime
+ private int dexMethodIndex;
+
+ /**
+ * We insert native method stubs for abstract methods so we don't have to
+ * check the access flags at the time of the method call. This results in
+ * "native abstract" methods, which can't exist. If we see the "abstract"
+ * flag set, clear the "native" flag.
+ *
+ * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
+ * position, because the callers of this function are trying to convey
+ * the "traditional" meaning of the flags to their callers.
+ */
+ private static int fixMethodFlags(int flags) {
+ if ((flags & Modifier.ABSTRACT) != 0) {
+ flags &= ~Modifier.NATIVE;
+ }
+ flags &= ~Modifier.SYNCHRONIZED;
+ int ACC_DECLARED_SYNCHRONIZED = 0x00020000;
+ if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
+ flags |= Modifier.SYNCHRONIZED;
+ }
+ return flags & 0xffff; // mask out bits not used by Java
+ }
+
+ final int getModifiersInternal() {
+ return fixMethodFlags(accessFlags);
+ }
+
+ final Class<?> getDeclaringClassInternal() {
+ return declaringClass;
+ }
+
+ /**
+ * Returns an array of {@code Class} objects associated with the parameter types of this
+ * Executable. If the Executable was declared with no parameters, an empty array will be
+ * returned.
+ *
+ * @return the parameter types
+ */
+ final Class<?>[] getParameterTypesInternal() {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ if (types.length == 0) {
+ return EmptyArray.CLASS;
+ }
+ Class<?>[] parametersArray = new Class[types.length];
+ for (int i = 0; i < types.length; i++) {
+ // Note, in the case of a Proxy the dex cache types are equal.
+ parametersArray[i] = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
+ }
+ return parametersArray;
+ }
+
+ final int getParameterCountInternal() {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ return types.length;
+ }
+
+ // Android provides a more efficient implementation of this method for Executable than the one
+ // implemented in AnnotatedElement.
+ @Override
+ public final boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+ Objects.requireNonNull(annotationType);
+ return isAnnotationPresentNative(annotationType);
+ }
+ private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
+
+ final Annotation[][] getParameterAnnotationsInternal() {
+ Annotation[][] parameterAnnotations = getParameterAnnotationsNative();
+ if (parameterAnnotations == null) {
+ parameterAnnotations = new Annotation[getParameterTypes().length][0];
+ }
+ return parameterAnnotations;
+ }
+ private native Annotation[][] getParameterAnnotationsNative();
+
+ /**
+ * @hide - exposed for use by {@link Class}.
+ */
+ public final int getAccessFlags() {
+ return accessFlags;
+ }
+
+ /**
+ * @hide - exposed for use by {@code java.lang.invoke.*}.
+ */
+ public final long getArtMethod() {
+ return artMethod;
+ }
+
+ static final class GenericInfo {
+ final ListOfTypes genericExceptionTypes;
+ final ListOfTypes genericParameterTypes;
+ final Type genericReturnType;
+ final TypeVariable<?>[] formalTypeParameters;
+
+ GenericInfo(ListOfTypes exceptions, ListOfTypes parameters, Type ret,
+ TypeVariable<?>[] formal) {
+ genericExceptionTypes = exceptions;
+ genericParameterTypes = parameters;
+ genericReturnType = ret;
+ formalTypeParameters = formal;
+ }
+ }
+
+ final boolean hasGenericInformationInternal() {
+ return getSignatureAnnotation() != null;
+ }
+
+ /**
+ * Returns generic information associated with this method/constructor member.
+ */
+ final GenericInfo getMethodOrConstructorGenericInfoInternal() {
+ String signatureAttribute = getSignatureAttribute();
+ Class<?>[] exceptionTypes = this.getExceptionTypes();
+ GenericSignatureParser parser =
+ new GenericSignatureParser(this.getDeclaringClass().getClassLoader());
+ if (this instanceof Method) {
+ parser.parseForMethod(this, signatureAttribute, exceptionTypes);
+ } else {
+ parser.parseForConstructor(this, signatureAttribute, exceptionTypes);
+ }
+ return new GenericInfo(parser.exceptionTypes, parser.parameterTypes,
+ parser.returnType, parser.formalTypeParameters);
+ }
+
+ private String getSignatureAttribute() {
+ String[] annotation = getSignatureAnnotation();
+ if (annotation == null) {
+ return null;
+ }
+ StringBuilder result = new StringBuilder();
+ for (String s : annotation) {
+ result.append(s);
+ }
+ return result.toString();
+ }
+ private native String[] getSignatureAnnotation();
+
+ final boolean equalNameAndParametersInternal(Method m) {
+ return getName().equals(m.getName()) && equalMethodParameters(m.getParameterTypes());
+ }
+
+ private boolean equalMethodParameters(Class<?>[] params) {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ if (types.length != params.length) {
+ return false;
+ }
+ for (int i = 0; i < types.length; i++) {
+ if (declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]) != params[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ final int compareMethodParametersInternal(Class<?>[] params) {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
+ int length = Math.min(types.length, params.length);
+ for (int i = 0; i < length; i++) {
+ Class<?> aType = declaringClassOfOverriddenMethod.getDexCacheType(dex, types[i]);
+ Class<?> bType = params[i];
+ if (aType != bType) {
+ int comparison = aType.getName().compareTo(bType.getName());
+ if (comparison != 0) {
+ return comparison;
+ }
+ }
+ }
+ return types.length - params.length;
+ }
+
+ final String getMethodNameInternal() {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ int nameIndex = dex.nameIndexFromMethodIndex(dexMethodIndex);
+ return declaringClassOfOverriddenMethod.getDexCacheString(dex, nameIndex);
+ }
+
+ final Class<?> getMethodReturnTypeInternal() {
+ Dex dex = declaringClassOfOverriddenMethod.getDex();
+ int returnTypeIndex = dex.returnTypeIndexFromMethodIndex(dexMethodIndex);
+ // Note, in the case of a Proxy the dex cache types are equal.
+ return declaringClassOfOverriddenMethod.getDexCacheType(dex, returnTypeIndex);
+ }
+
+ /** A cheap implementation for {@link Method#isDefault()}. */
+ final boolean isDefaultMethodInternal() {
+ return (accessFlags & Modifier.DEFAULT) != 0;
+ }
+
+ /** A cheap implementation for {@link Method#isBridge()}. */
+ final boolean isBridgeMethodInternal() {
+ return (accessFlags & Modifier.BRIDGE) != 0;
}
}
diff --git a/ojluni/src/main/java/java/lang/reflect/MalformedParametersException.java b/ojluni/src/main/java/java/lang/reflect/MalformedParametersException.java
new file mode 100644
index 0000000..6b14b15
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/reflect/MalformedParametersException.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+/**
+ * Thrown when {@link java.lang.reflect.Executable#getParameters the
+ * java.lang.reflect package} attempts to read method parameters from
+ * a class file and determines that one or more parameters are
+ * malformed.
+ *
+ * <p>The following is a list of conditions under which this exception
+ * can be thrown:
+ * <ul>
+ * <li> The number of parameters (parameter_count) is wrong for the method
+ * <li> A constant pool index is out of bounds.
+ * <li> A constant pool index does not refer to a UTF-8 entry
+ * <li> A parameter's name is "", or contains an illegal character
+ * <li> The flags field contains an illegal flag (something other than
+ * FINAL, SYNTHETIC, or MANDATED)
+ * </ul>
+ *
+ * See {@link java.lang.reflect.Executable#getParameters} for more
+ * information.
+ *
+ * @see java.lang.reflect.Executable#getParameters
+ * @since 1.8
+ * @hide Hidden pending tests
+ */
+public class MalformedParametersException extends RuntimeException {
+
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = 20130919L;
+
+ /**
+ * Create a {@code MalformedParametersException} with an empty
+ * reason.
+ */
+ public MalformedParametersException() {}
+
+ /**
+ * Create a {@code MalformedParametersException}.
+ *
+ * @param reason The reason for the exception.
+ */
+ public MalformedParametersException(String reason) {
+ super(reason);
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/reflect/Method.java b/ojluni/src/main/java/java/lang/reflect/Method.java
index a9f2eb7..e3fa1c9 100644
--- a/ojluni/src/main/java/java/lang/reflect/Method.java
+++ b/ojluni/src/main/java/java/lang/reflect/Method.java
@@ -50,7 +50,7 @@
* @author Kenneth Russell
* @author Nakul Saraiya
*/
-public final class Method extends AbstractMethod {
+public final class Method extends Executable {
/**
* Orders methods by their name, parameters and return type.
*
@@ -82,13 +82,19 @@
private Method() {
}
+ @Override
+ boolean hasGenericInformation() {
+ // Android-changed: Signature retrieval is handled in Executable.
+ return super.hasGenericInformationInternal();
+ }
+
/**
* {@inheritDoc}
- */
+ */
@Override
public Class<?> getDeclaringClass() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getDeclaringClass();
+ // Android-changed: This is handled by Executable.
+ return super.getDeclaringClassInternal();
}
/**
@@ -97,7 +103,7 @@
*/
@Override
public String getName() {
- // Android-changed: This is handled by AbstractMethod.
+ // Android-changed: This is handled by Executable.
return getMethodNameInternal();
}
@@ -106,8 +112,8 @@
*/
@Override
public int getModifiers() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getModifiers();
+ // Android-changed: This is handled by Executable.
+ return super.getModifiersInternal();
}
/**
@@ -118,7 +124,7 @@
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public TypeVariable<Method>[] getTypeParameters() {
- // Android-changed: This is mostly handled by AbstractMethod.
+ // Android-changed: This is mostly handled by Executable.
GenericInfo info = getMethodOrConstructorGenericInfoInternal();
return (TypeVariable<Method>[]) info.formalTypeParameters.clone();
}
@@ -130,7 +136,7 @@
* @return the return type for the method this object represents
*/
public Class<?> getReturnType() {
- // Android-changed: This is handled by AbstractMethod.
+ // Android-changed: This is handled by Executable.
return getMethodReturnTypeInternal();
}
@@ -159,6 +165,7 @@
* @since 1.5
*/
public Type getGenericReturnType() {
+ // Android-changed: Modified implementation to use Executable.
return Types.getType(getMethodOrConstructorGenericInfoInternal().genericReturnType);
}
@@ -167,16 +174,16 @@
*/
@Override
public Class<?>[] getParameterTypes() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterTypes();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterTypesInternal();
}
/**
* {@inheritDoc}
*/
public int getParameterCount() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterCount();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterCountInternal();
}
/**
@@ -238,7 +245,6 @@
return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
}
-
/**
* Returns a string describing this {@code Method}. The string is
* formatted as the method access modifiers, if any, followed by
@@ -332,7 +338,6 @@
sb.append(getName());
}
-
/**
* Invokes the underlying method represented by this {@code Method}
* object, on the specified object with the specified parameters.
@@ -402,7 +407,7 @@
* @since 1.5
*/
public boolean isBridge() {
- // Android-changed: This is handled by AbstractMethod.
+ // Android-changed: This is handled by Executable.
return super.isBridgeMethodInternal();
}
@@ -425,7 +430,6 @@
return super.isSynthetic();
}
-
/**
* Returns {@code true} if this method is a default
* method; returns {@code false} otherwise.
@@ -439,7 +443,7 @@
* @since 1.8
*/
public boolean isDefault() {
- // Android-changed: This is handled by AbstractMethod.
+ // Android-changed: This is handled by Executable.
return super.isDefaultMethodInternal();
}
@@ -482,8 +486,8 @@
*/
@Override
public Annotation[][] getParameterAnnotations() {
- // Android-changed: This is handled by AbstractMethod.
- return super.getParameterAnnotations();
+ // Android-changed: This is handled by Executable.
+ return super.getParameterAnnotationsInternal();
}
/**
diff --git a/ojluni/src/main/java/java/lang/reflect/Parameter.java b/ojluni/src/main/java/java/lang/reflect/Parameter.java
new file mode 100644
index 0000000..2d96307
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/reflect/Parameter.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.reflect;
+
+import java.lang.annotation.*;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import libcore.reflect.AnnotatedElements;
+
+/**
+ * Information about method parameters.
+ *
+ * A {@code Parameter} provides information about method parameters,
+ * including its name and modifiers. It also provides an alternate
+ * means of obtaining attributes for the parameter.
+ *
+ * @since 1.8
+ */
+public final class Parameter implements AnnotatedElement {
+
+ private final String name;
+ private final int modifiers;
+ private final Executable executable;
+ private final int index;
+
+ /**
+ * Package-private constructor for {@code Parameter}.
+ *
+ * If method parameter data is present in the classfile, then the
+ * JVM creates {@code Parameter} objects directly. If it is
+ * absent, however, then {@code Executable} uses this constructor
+ * to synthesize them.
+ *
+ * @param name The name of the parameter.
+ * @param modifiers The modifier flags for the parameter.
+ * @param executable The executable which defines this parameter.
+ * @param index The index of the parameter.
+ */
+ Parameter(String name,
+ int modifiers,
+ Executable executable,
+ int index) {
+ this.name = name;
+ this.modifiers = modifiers;
+ this.executable = executable;
+ this.index = index;
+ }
+
+ /**
+ * Compares based on the executable and the index.
+ *
+ * @param obj The object to compare.
+ * @return Whether or not this is equal to the argument.
+ */
+ public boolean equals(Object obj) {
+ if(obj instanceof Parameter) {
+ Parameter other = (Parameter)obj;
+ return (other.executable.equals(executable) &&
+ other.index == index);
+ }
+ return false;
+ }
+
+ /**
+ * Returns a hash code based on the executable's hash code and the
+ * index.
+ *
+ * @return A hash code based on the executable's hash code.
+ */
+ public int hashCode() {
+ return executable.hashCode() ^ index;
+ }
+
+ // Android-changed: Removed references to the class file format.
+ /**
+ * Returns true if the parameter has a name; returns false otherwise.
+ * Whether a parameter has a name is determined by compiler options
+ * and whether the parameter is synthesized.
+ *
+ * @return true if and only if the parameter has a name
+ */
+ public boolean isNamePresent() {
+ return executable.hasRealParameterData() && name != null;
+ }
+
+ /**
+ * Returns a string describing this parameter. The format is the
+ * modifiers for the parameter, if any, in canonical order as
+ * recommended by <cite>The Java™ Language
+ * Specification</cite>, followed by the fully- qualified type of
+ * the parameter (excluding the last [] if the parameter is
+ * variable arity), followed by "..." if the parameter is variable
+ * arity, followed by a space, followed by the name of the
+ * parameter.
+ *
+ * @return A string representation of the parameter and associated
+ * information.
+ */
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ final Type type = getParameterizedType();
+ final String typename = type.getTypeName();
+
+ sb.append(Modifier.toString(getModifiers()));
+
+ if(0 != modifiers)
+ sb.append(' ');
+
+ if(isVarArgs())
+ sb.append(typename.replaceFirst("\\[\\]$", "..."));
+ else
+ sb.append(typename);
+
+ sb.append(' ');
+ sb.append(getName());
+
+ return sb.toString();
+ }
+
+ /**
+ * Return the {@code Executable} which declares this parameter.
+ *
+ * @return The {@code Executable} declaring this parameter.
+ */
+ public Executable getDeclaringExecutable() {
+ return executable;
+ }
+
+ /**
+ * Get the modifier flags for this the parameter represented by
+ * this {@code Parameter} object.
+ *
+ * @return The modifier flags for this parameter.
+ */
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ /**
+ * Returns the name of the parameter. If the parameter's name is
+ * {@linkplain #isNamePresent() present}, then this method returns
+ * the name provided by the class file. Otherwise, this method
+ * synthesizes a name of the form argN, where N is the index of
+ * the parameter in the descriptor of the method which declares
+ * the parameter.
+ *
+ * @return The name of the parameter, either provided by the class
+ * file or synthesized if the class file does not provide
+ * a name.
+ */
+ public String getName() {
+ // Note: empty strings as paramete names are now outlawed.
+ // The .equals("") is for compatibility with current JVM
+ // behavior. It may be removed at some point.
+ if(name == null || name.equals(""))
+ return "arg" + index;
+ else
+ return name;
+ }
+
+ // Package-private accessor to the real name field.
+ String getRealName() {
+ return name;
+ }
+
+ /**
+ * Returns a {@code Type} object that identifies the parameterized
+ * type for the parameter represented by this {@code Parameter}
+ * object.
+ *
+ * @return a {@code Type} object identifying the parameterized
+ * type of the parameter represented by this object
+ */
+ public Type getParameterizedType() {
+ Type tmp = parameterTypeCache;
+ if (null == tmp) {
+ tmp = executable.getAllGenericParameterTypes()[index];
+ parameterTypeCache = tmp;
+ }
+
+ return tmp;
+ }
+
+ private transient volatile Type parameterTypeCache = null;
+
+ /**
+ * Returns a {@code Class} object that identifies the
+ * declared type for the parameter represented by this
+ * {@code Parameter} object.
+ *
+ * @return a {@code Class} object identifying the declared
+ * type of the parameter represented by this object
+ */
+ public Class<?> getType() {
+ Class<?> tmp = parameterClassCache;
+ if (null == tmp) {
+ tmp = executable.getParameterTypes()[index];
+ parameterClassCache = tmp;
+ }
+ return tmp;
+ }
+
+ private transient volatile Class<?> parameterClassCache = null;
+
+ /**
+ * Returns {@code true} if this parameter is implicitly declared
+ * in source code; returns {@code false} otherwise.
+ *
+ * @return true if and only if this parameter is implicitly
+ * declared as defined by <cite>The Java™ Language
+ * Specification</cite>.
+ */
+ public boolean isImplicit() {
+ return Modifier.isMandated(getModifiers());
+ }
+
+ /**
+ * Returns {@code true} if this parameter is neither implicitly
+ * nor explicitly declared in source code; returns {@code false}
+ * otherwise.
+ *
+ * @jls 13.1 The Form of a Binary
+ * @return true if and only if this parameter is a synthetic
+ * construct as defined by
+ * <cite>The Java™ Language Specification</cite>.
+ */
+ public boolean isSynthetic() {
+ return Modifier.isSynthetic(getModifiers());
+ }
+
+ /**
+ * Returns {@code true} if this parameter represents a variable
+ * argument list; returns {@code false} otherwise.
+ *
+ * @return {@code true} if an only if this parameter represents a
+ * variable argument list.
+ */
+ public boolean isVarArgs() {
+ return executable.isVarArgs() &&
+ index == executable.getParameterCount() - 1;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
+ Objects.requireNonNull(annotationClass);
+ // Android-changed: Uses native code to obtain annotation information.
+ return getAnnotationNative(executable, index, annotationClass);
+ }
+ private static native <A extends Annotation> A getAnnotationNative(
+ Executable executable, int parameterIndex, Class<A> annotationType);
+
+ /**
+ * {@inheritDoc}
+ * @throws NullPointerException {@inheritDoc}
+ */
+ @Override
+ public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+ // Android-changed: Uses AnnotatedElements instead.
+ return AnnotatedElements.getDirectOrIndirectAnnotationsByType(this, annotationClass);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Annotation[] getDeclaredAnnotations() {
+ return executable.getParameterAnnotations()[index];
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
+ // Only annotations on classes are inherited, for all other
+ // objects getDeclaredAnnotation is the same as
+ // getAnnotation.
+ return getAnnotation(annotationClass);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ */
+ @Override
+ public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
+ // Only annotations on classes are inherited, for all other
+ // objects getDeclaredAnnotations is the same as
+ // getAnnotations.
+ return getAnnotationsByType(annotationClass);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Annotation[] getAnnotations() {
+ return getDeclaredAnnotations();
+ }
+}
diff --git a/ojluni/src/main/java/java/net/DatagramSocket.java b/ojluni/src/main/java/java/net/DatagramSocket.java
index 6f2c95c..f9dbaff 100755
--- a/ojluni/src/main/java/java/net/DatagramSocket.java
+++ b/ojluni/src/main/java/java/net/DatagramSocket.java
@@ -152,46 +152,44 @@
if (!isBound())
bind(new InetSocketAddress(0));
- // ----- BEGIN android -----
- connectedAddress = address;
- connectedPort = port;
- // ----- END android -----
-
- // old impls do not support connect/disconnect
- if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&
- ((AbstractPlainDatagramSocketImpl)impl).nativeConnectDisabled())) {
- connectState = ST_CONNECTED_NO_IMPL;
- } else {
- /* ----- BEGIN android -----
- try {
- getImpl().connect(address, port);
-
- // socket is now connected by the impl
- connectState = ST_CONNECTED;
- } catch (SocketException se) {
- // connection will be emulated by DatagramSocket
+ // Android-changed: This section now throws any SocketException generated by connect()
+ // to enable it to be recorded as the pendingConnectException. It has been enclosed in a
+ // try-finally to ensure connectedAddress and connectedPort are set when the exception
+ // is thrown.
+ try {
+ // old impls do not support connect/disconnect
+ // Android-changed: Added special handling for AbstractPlainDatagramSocketImpl in
+ // the condition below.
+ if (oldImpl || (impl instanceof AbstractPlainDatagramSocketImpl &&
+ ((AbstractPlainDatagramSocketImpl)impl).nativeConnectDisabled())) {
connectState = ST_CONNECTED_NO_IMPL;
- }*/
- getImpl().connect(address, port);
+ } else {
+ try {
+ getImpl().connect(address, port);
- // socket is now connected by the impl
- connectState = ST_CONNECTED;
- // Do we need to filter some packets?
- int avail = getImpl().dataAvailable();
- if (avail == -1) {
- throw new SocketException();
- }
- explicitFilter = avail > 0;
- if (explicitFilter) {
- bytesLeftToFilter = getReceiveBufferSize();
- }
- // ----- END android -----
+ // socket is now connected by the impl
+ connectState = ST_CONNECTED;
+
+ // Do we need to filter some packets?
+ int avail = getImpl().dataAvailable();
+ if (avail == -1) {
+ throw new SocketException();
+ }
+ explicitFilter = avail > 0;
+ if (explicitFilter) {
+ bytesLeftToFilter = getReceiveBufferSize();
+ }
+ } catch (SocketException se) {
+ // connection will be emulated by DatagramSocket
+ connectState = ST_CONNECTED_NO_IMPL;
+ // Android-changed: Propagate the SocketException so connect() can store it.
+ throw se;
+ }
+ }
+ } finally {
+ connectedAddress = address;
+ connectedPort = port;
}
-
- /* ----- BEGIN android -----
- connectedAddress = address;
- connectedPort = port;
- ----- END android ----- */
}
diff --git a/ojluni/src/main/java/java/security/DigestOutputStream.java b/ojluni/src/main/java/java/security/DigestOutputStream.java
index 1307bdf..d7f777b 100644
--- a/ojluni/src/main/java/java/security/DigestOutputStream.java
+++ b/ojluni/src/main/java/java/security/DigestOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,13 +37,13 @@
* the bits going through the stream.
*
* <p>To complete the message digest computation, call one of the
- * <code>digest</code> methods on the associated message
- * digest after your calls to one of this digest ouput stream's
+ * {@code digest} methods on the associated message
+ * digest after your calls to one of this digest output stream's
* {@link #write(int) write} methods.
*
* <p>It is possible to turn this stream on or off (see
* {@link #on(boolean) on}). When it is on, a call to one of the
- * <code>write</code> methods results in
+ * {@code write} methods results in
* an update on the message digest. But when it is off, the message
* digest is not updated. The default is for the stream to be on.
*
@@ -99,8 +99,8 @@
* the specified byte, and in any case writes the byte
* to the output stream. That is, if the digest function is on
* (see {@link #on(boolean) on}), this method calls
- * <code>update</code> on the message digest associated with this
- * stream, passing it the byte <code>b</code>. This method then
+ * {@code update} on the message digest associated with this
+ * stream, passing it the byte {@code b}. This method then
* writes the byte to the output stream, blocking until the byte
* is actually written.
*
@@ -112,17 +112,17 @@
* @see MessageDigest#update(byte)
*/
public void write(int b) throws IOException {
+ out.write(b);
if (on) {
digest.update((byte)b);
}
- out.write(b);
}
/**
* Updates the message digest (if the digest function is on) using
* the specified subarray, and in any case writes the subarray to
* the output stream. That is, if the digest function is on (see
- * {@link #on(boolean) on}), this method calls <code>update</code>
+ * {@link #on(boolean) on}), this method calls {@code update}
* on the message digest associated with this stream, passing it
* the subarray specifications. This method then writes the subarray
* bytes to the output stream, blocking until the bytes are actually
@@ -131,26 +131,35 @@
* @param b the array containing the subarray to be used for updating
* and writing to the output stream.
*
- * @param off the offset into <code>b</code> of the first byte to
+ * @param off the offset into {@code b} of the first byte to
* be updated and written.
*
* @param len the number of bytes of data to be updated and written
- * from <code>b</code>, starting at offset <code>off</code>.
+ * from {@code b}, starting at offset {@code off}.
*
* @exception IOException if an I/O error occurs.
*
* @see MessageDigest#update(byte[], int, int)
*/
public void write(byte[] b, int off, int len) throws IOException {
+ // BEGIN ANDROID-ADDED: perform checks for parameters first.
+ // See org.apache.harmony.security.tests.j.s.DigestOutputStreamTest#test_write$BII_6
+ if (b == null || off + len > b.length) {
+ throw new IllegalArgumentException("wrong parameters for write");
+ }
+ if (off < 0 || len < 0) {
+ throw new IndexOutOfBoundsException("wrong index for write");
+ }
+ // END ANDROID-ADDED
+ out.write(b, off, len);
if (on) {
digest.update(b, off, len);
}
- out.write(b, off, len);
}
/**
* Turns the digest function on or off. The default is on. When
- * it is on, a call to one of the <code>write</code> methods results in an
+ * it is on, a call to one of the {@code write} methods results in an
* update on the message digest. But when it is off, the message
* digest is not updated.
*
diff --git a/ojluni/src/main/java/java/security/Signature.java b/ojluni/src/main/java/java/security/Signature.java
index 8923ecd..a8a42a1 100644
--- a/ojluni/src/main/java/java/security/Signature.java
+++ b/ojluni/src/main/java/java/security/Signature.java
@@ -1,6 +1,6 @@
/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,8 +42,9 @@
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
-
+/* BEGIN ANDROID-REMOVED: this debugging mechanism is not available in Android.
import sun.security.util.Debug;
+ * END ANDROID-REMOVED */
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
@@ -54,10 +55,10 @@
*
* <p> The signature algorithm can be, among others, the NIST standard
* DSA, using DSA and SHA-1. The DSA algorithm using the
- * SHA-1 message digest algorithm can be specified as <tt>SHA1withDSA</tt>.
+ * SHA-1 message digest algorithm can be specified as {@code SHA1withDSA}.
* In the case of RSA, there are multiple choices for the message digest
* algorithm, so the signing algorithm could be specified as, for example,
- * <tt>MD2withRSA</tt>, <tt>MD5withRSA</tt>, or <tt>SHA1withRSA</tt>.
+ * {@code MD2withRSA}, {@code MD5withRSA}, or {@code SHA1withRSA}.
* The algorithm name must be specified, as there is no default.
*
* <p> A Signature object can be used to generate and verify digital
@@ -78,13 +79,13 @@
* (see {@link #initSign(PrivateKey)}
* and {@link #initSign(PrivateKey, SecureRandom)}).
*
- * </ul><p>
+ * </ul>
*
- * <li>Updating<p>
+ * <li>Updating
*
* <p>Depending on the type of initialization, this will update the
* bytes to be signed or verified. See the
- * {@link #update(byte) update} methods.<p>
+ * {@link #update(byte) update} methods.
*
* <li>Signing or Verifying a signature on all updated bytes. See the
* {@link #sign() sign} methods and the {@link #verify(byte[]) verify}
@@ -93,13 +94,13 @@
* </ol>
*
* <p>Note that this class is abstract and extends from
- * <code>SignatureSpi</code> for historical reasons.
+ * {@code SignatureSpi} for historical reasons.
* Application developers should only take notice of the methods defined in
- * this <code>Signature</code> class; all the methods in
+ * this {@code Signature} class; all the methods in
* the superclass are intended for cryptographic service providers who wish to
* supply their own implementations of digital signature algorithms.
*
- * <p> Android provides the following <code>Signature</code> algorithms:
+ * <p> Android provides the following {@code Signature} algorithms:
* <table>
* <thead>
* <tr>
@@ -214,9 +215,16 @@
public abstract class Signature extends SignatureSpi {
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism not available in Android
private static final Debug debug =
Debug.getInstance("jca", "Signature");
+ private static final Debug pdebug =
+ Debug.getInstance("provider", "Provider");
+ private static final boolean skipDebug =
+ Debug.isOn("engine=") && !Debug.isOn("signature");
+ * END ANDROID-REMOVED */
+
/*
* The algorithm for this signature object.
* This value is used to map an OID to the particular algorithm.
@@ -344,6 +352,7 @@
Signature sig;
if (instance.impl instanceof Signature) {
sig = (Signature)instance.impl;
+ sig.algorithm = algorithm;
} else {
SignatureSpi spi = (SignatureSpi)instance.impl;
sig = new Delegate(spi, algorithm);
@@ -385,11 +394,13 @@
// instance of SignatureSpi but not Signature
boolean r = (instance instanceof SignatureSpi)
&& (instance instanceof Signature == false);
+ /* BEGIN ANDROID-REMOVED: this mechanism not available in Android
if ((debug != null) && (r == false)) {
debug.println("Not a SignatureSpi " + className);
debug.println("Delayed provider selection may not be "
+ "available for algorithm " + s.getAlgorithm());
}
+ * END ANDROID-REMOVED */
result = Boolean.valueOf(r);
signatureInfo.put(className, result);
} catch (Exception e) {
@@ -546,6 +557,13 @@
throws InvalidKeyException {
engineInitVerify(publicKey);
state = VERIFY;
+
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism not supported in Android.
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + this.provider.getName());
+ }
+ * END ANDROID-REMOVED */
}
/**
@@ -556,7 +574,7 @@
* extension field implies that the public key in
* the certificate and its corresponding private key are not
* supposed to be used for digital signatures, an
- * <code>InvalidKeyException</code> is thrown.
+ * {@code InvalidKeyException} is thrown.
*
* @param certificate the certificate of the identity whose signature is
* going to be verified.
@@ -590,6 +608,13 @@
PublicKey publicKey = certificate.getPublicKey();
engineInitVerify(publicKey);
state = VERIFY;
+
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " verification algorithm from: " + this.provider.getName());
+ }
+ * END ANDROID-REMOVED */
}
/**
@@ -606,6 +631,13 @@
throws InvalidKeyException {
engineInitSign(privateKey);
state = SIGN;
+
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " signing algorithm from: " + this.provider.getName());
+ }
+ * END ANDROID-REMOVED */
}
/**
@@ -624,6 +656,13 @@
throws InvalidKeyException {
engineInitSign(privateKey, random);
state = SIGN;
+
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
+ if (!skipDebug && pdebug != null) {
+ pdebug.println("Signature." + algorithm +
+ " signing algorithm from: " + this.provider.getName());
+ }
+ * END ANDROID-REMOVED */
}
/**
@@ -633,10 +672,10 @@
*
* <p>A call to this method resets this signature object to the state
* it was in when previously initialized for signing via a
- * call to <code>initSign(PrivateKey)</code>. That is, the object is
+ * call to {@code initSign(PrivateKey)}. That is, the object is
* reset and available to generate another signature from the same
- * signer, if desired, via new calls to <code>update</code> and
- * <code>sign</code>.
+ * signer, if desired, via new calls to {@code update} and
+ * {@code sign}.
*
* @return the signature bytes of the signing operation's result.
*
@@ -654,28 +693,28 @@
/**
* Finishes the signature operation and stores the resulting signature
- * bytes in the provided buffer <code>outbuf</code>, starting at
- * <code>offset</code>.
+ * bytes in the provided buffer {@code outbuf}, starting at
+ * {@code offset}.
* The format of the signature depends on the underlying
* signature scheme.
*
* <p>This signature object is reset to its initial state (the state it
- * was in after a call to one of the <code>initSign</code> methods) and
+ * was in after a call to one of the {@code initSign} methods) and
* can be reused to generate further signatures with the same private key.
*
* @param outbuf buffer for the signature result.
*
- * @param offset offset into <code>outbuf</code> where the signature is
+ * @param offset offset into {@code outbuf} where the signature is
* stored.
*
- * @param len number of bytes within <code>outbuf</code> allotted for the
+ * @param len number of bytes within {@code outbuf} allotted for the
* signature.
*
- * @return the number of bytes placed into <code>outbuf</code>.
+ * @return the number of bytes placed into {@code outbuf}.
*
* @exception SignatureException if this signature object is not
* initialized properly, if this signature algorithm is unable to
- * process the input data provided, or if <code>len</code> is less
+ * process the input data provided, or if {@code len} is less
* than the actual signature length.
*
* @since 1.2
@@ -685,6 +724,9 @@
if (outbuf == null) {
throw new IllegalArgumentException("No output buffer given");
}
+ if (offset < 0 || len < 0) {
+ throw new IllegalArgumentException("offset or len is less than 0");
+ }
if (outbuf.length - offset < len) {
throw new IllegalArgumentException
("Output buffer too small for specified offset and length");
@@ -701,9 +743,9 @@
*
* <p>A call to this method resets this signature object to the state
* it was in when previously initialized for verification via a
- * call to <code>initVerify(PublicKey)</code>. That is, the object is
+ * call to {@code initVerify(PublicKey)}. That is, the object is
* reset and available to verify another signature from the identity
- * whose public key was specified in the call to <code>initVerify</code>.
+ * whose public key was specified in the call to {@code initVerify}.
*
* @param signature the signature bytes to be verified.
*
@@ -728,9 +770,9 @@
*
* <p>A call to this method resets this signature object to the state
* it was in when previously initialized for verification via a
- * call to <code>initVerify(PublicKey)</code>. That is, the object is
+ * call to {@code initVerify(PublicKey)}. That is, the object is
* reset and available to verify another signature from the identity
- * whose public key was specified in the call to <code>initVerify</code>.
+ * whose public key was specified in the call to {@code initVerify}.
*
*
* @param signature the signature bytes to be verified.
@@ -743,19 +785,26 @@
* initialized properly, the passed-in signature is improperly
* encoded or of the wrong type, if this signature algorithm is unable to
* process the input data provided, etc.
- * @exception IllegalArgumentException if the <code>signature</code>
- * byte array is null, or the <code>offset</code> or <code>length</code>
- * is less than 0, or the sum of the <code>offset</code> and
- * <code>length</code> is greater than the length of the
- * <code>signature</code> byte array.
+ * @exception IllegalArgumentException if the {@code signature}
+ * byte array is null, or the {@code offset} or {@code length}
+ * is less than 0, or the sum of the {@code offset} and
+ * {@code length} is greater than the length of the
+ * {@code signature} byte array.
* @since 1.4
*/
public final boolean verify(byte[] signature, int offset, int length)
throws SignatureException {
if (state == VERIFY) {
- if ((signature == null) || (offset < 0) || (length < 0) ||
- (length > signature.length - offset)) {
- throw new IllegalArgumentException("Bad arguments");
+ if (signature == null) {
+ throw new IllegalArgumentException("signature is null");
+ }
+ if (offset < 0 || length < 0) {
+ throw new IllegalArgumentException
+ ("offset or length is less than 0");
+ }
+ if (signature.length - offset < length) {
+ throw new IllegalArgumentException
+ ("signature too small for specified offset and length");
}
return engineVerify(signature, offset, length);
@@ -807,17 +856,17 @@
*/
public final void update(byte[] data, int off, int len)
throws SignatureException {
- // Android-changed: Check data, off & len early and throw an exception
- // as soon as possible.
- if (data == null) {
- throw new IllegalArgumentException("data == null");
- }
-
- if (off < 0 || len < 0 || off + len > data.length) {
- throw new IllegalArgumentException();
- }
-
if (state == SIGN || state == VERIFY) {
+ if (data == null) {
+ throw new IllegalArgumentException("data is null");
+ }
+ if (off < 0 || len < 0) {
+ throw new IllegalArgumentException("off or len is less than 0");
+ }
+ if (data.length - off < len) {
+ throw new IllegalArgumentException
+ ("data too small for specified offset and length");
+ }
engineUpdate(data, off, len);
} else {
throw new SignatureException("object not initialized for "
@@ -827,8 +876,8 @@
/**
* Updates the data to be signed or verified using the specified
- * ByteBuffer. Processes the <code>data.remaining()</code> bytes
- * starting at at <code>data.position()</code>.
+ * ByteBuffer. Processes the {@code data.remaining()} bytes
+ * starting at at {@code data.position()}.
* Upon return, the buffer's position will be equal to its limit;
* its limit will not have changed.
*
@@ -895,7 +944,7 @@
* @param param the string identifier of the parameter.
* @param value the parameter value.
*
- * @exception InvalidParameterException if <code>param</code> is an
+ * @exception InvalidParameterException if {@code param} is an
* invalid parameter for this signature algorithm engine,
* the parameter is already set
* and cannot be set again, a security exception occurs, and so on.
@@ -961,7 +1010,7 @@
* @return the object that represents the parameter value, or null if
* there is none.
*
- * @exception InvalidParameterException if <code>param</code> is an invalid
+ * @exception InvalidParameterException if {@code param} is an invalid
* parameter for this engine, or another exception occurs while
* trying to get this parameter.
*
@@ -982,7 +1031,7 @@
* @return a clone if the implementation is cloneable.
*
* @exception CloneNotSupportedException if this is called
- * on an implementation that does not support <code>Cloneable</code>.
+ * on an implementation that does not support {@code Cloneable}.
*/
public Object clone() throws CloneNotSupportedException {
if (this instanceof Cloneable) {
@@ -1015,6 +1064,7 @@
* and its original parent (Object).
*/
+ @SuppressWarnings("deprecation")
private static class Delegate extends Signature {
// The provider implementation (delegate)
@@ -1043,7 +1093,7 @@
* @return a clone if the delegate is cloneable.
*
* @exception CloneNotSupportedException if this is called on a
- * delegate that does not support <code>Cloneable</code>.
+ * delegate that does not support {@code Cloneable}.
*/
public Object clone() throws CloneNotSupportedException {
chooseFirstProvider();
@@ -1097,6 +1147,7 @@
if (sigSpi != null) {
return;
}
+ /* BEGIN ANDROID-REMOVED: this debugging mechanism is not supported in Android.
if (debug != null) {
int w = --warnCount;
if (w >= 0) {
@@ -1109,6 +1160,7 @@
new Exception("Call trace").printStackTrace();
}
}
+ * END ANDROID-REMOVED */
Exception lastException = null;
List<Service> list;
if (((Signature)this).algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {
@@ -1313,6 +1365,7 @@
}
// adapter for RSA/ECB/PKCS1Padding ciphers
+ @SuppressWarnings("deprecation")
private static class CipherAdapter extends SignatureSpi {
private final Cipher cipher;
@@ -1378,7 +1431,7 @@
byte[] out = cipher.doFinal(sigBytes);
byte[] dataBytes = data.toByteArray();
data.reset();
- return Arrays.equals(out, dataBytes);
+ return MessageDigest.isEqual(out, dataBytes);
} catch (BadPaddingException e) {
// e.g. wrong public key used
// return false rather than throwing exception
diff --git a/ojluni/src/main/java/java/text/SimpleDateFormat.java b/ojluni/src/main/java/java/text/SimpleDateFormat.java
index c1301b3..b17245f 100644
--- a/ojluni/src/main/java/java/text/SimpleDateFormat.java
+++ b/ojluni/src/main/java/java/text/SimpleDateFormat.java
@@ -39,25 +39,35 @@
package java.text;
+import android.icu.text.TimeZoneFormat;
+import android.icu.text.TimeZoneNames;
+import android.icu.util.ULocale;
+
import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
+import java.util.Arrays;
import java.util.Calendar;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
+import java.util.EnumSet;
import java.util.GregorianCalendar;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
+import java.util.Set;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import libcore.icu.LocaleData;
-import libcore.icu.TimeZoneNames;
import sun.util.calendar.CalendarUtils;
import static java.text.DateFormatSymbols.*;
+// Android-changed: Added supported API level, removed unnecessary <br>
/**
* <code>SimpleDateFormat</code> is a concrete class for formatting and
* parsing dates in a locale-sensitive manner. It allows for formatting
@@ -100,116 +110,139 @@
* <th align=left>Date or Time Component
* <th align=left>Presentation
* <th align=left>Examples
+ * <th align=left>Supported (API Levels)
* <tr>
* <td><code>G</code>
* <td>Era designator
* <td><a href="#text">Text</a>
* <td><code>AD</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>y</code>
* <td>Year
* <td><a href="#year">Year</a>
* <td><code>1996</code>; <code>96</code>
+ * <td>1+</td>
* <tr>
* <td><code>Y</code>
* <td>Week year
* <td><a href="#year">Year</a>
* <td><code>2009</code>; <code>09</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>M</code>
* <td>Month in year (context sensitive)
* <td><a href="#month">Month</a>
* <td><code>July</code>; <code>Jul</code>; <code>07</code>
+ * <td>1+</td>
* <tr>
* <td><code>w</code>
* <td>Week in year
* <td><a href="#number">Number</a>
* <td><code>27</code>
+ * <td>1+</td>
* <tr>
* <td><code>W</code>
* <td>Week in month
* <td><a href="#number">Number</a>
* <td><code>2</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>D</code>
* <td>Day in year
* <td><a href="#number">Number</a>
* <td><code>189</code>
+ * <td>1+</td>
* <tr>
* <td><code>d</code>
* <td>Day in month
* <td><a href="#number">Number</a>
* <td><code>10</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>F</code>
* <td>Day of week in month
* <td><a href="#number">Number</a>
* <td><code>2</code>
+ * <td>1+</td>
* <tr>
* <td><code>E</code>
* <td>Day name in week
* <td><a href="#text">Text</a>
* <td><code>Tuesday</code>; <code>Tue</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>u</code>
* <td>Day number of week (1 = Monday, ..., 7 = Sunday)
* <td><a href="#number">Number</a>
* <td><code>1</code>
+ * <td>24+</td>
* <tr>
* <td><code>a</code>
* <td>Am/pm marker
* <td><a href="#text">Text</a>
* <td><code>PM</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>H</code>
* <td>Hour in day (0-23)
* <td><a href="#number">Number</a>
* <td><code>0</code>
+ * <td>1+</td>
* <tr>
* <td><code>k</code>
* <td>Hour in day (1-24)
* <td><a href="#number">Number</a>
* <td><code>24</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>K</code>
* <td>Hour in am/pm (0-11)
* <td><a href="#number">Number</a>
* <td><code>0</code>
+ * <td>1+</td>
* <tr>
* <td><code>h</code>
* <td>Hour in am/pm (1-12)
* <td><a href="#number">Number</a>
* <td><code>12</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>m</code>
* <td>Minute in hour
* <td><a href="#number">Number</a>
* <td><code>30</code>
+ * <td>1+</td>
* <tr>
* <td><code>s</code>
* <td>Second in minute
* <td><a href="#number">Number</a>
* <td><code>55</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>S</code>
* <td>Millisecond
* <td><a href="#number">Number</a>
* <td><code>978</code>
+ * <td>1+</td>
* <tr>
* <td><code>z</code>
* <td>Time zone
* <td><a href="#timezone">General time zone</a>
* <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
+ * <td>1+</td>
* <tr style="background-color: rgb(238, 238, 255);">
* <td><code>Z</code>
* <td>Time zone
* <td><a href="#rfc822timezone">RFC 822 time zone</a>
* <td><code>-0800</code>
+ * <td>1+</td>
* <tr>
* <td><code>X</code>
* <td>Time zone
* <td><a href="#iso8601timezone">ISO 8601 time zone</a>
* <td><code>-08</code>; <code>-0800</code>; <code>-08:00</code>
+ * <td>1+</td>
* </table>
* </blockquote>
* Pattern letters are usually repeated, as their number determines the
@@ -220,15 +253,15 @@
* the full form is used; otherwise a short or abbreviated form
* is used if available.
* For parsing, both forms are accepted, independent of the number
- * of pattern letters.<br><br></li>
+ * of pattern letters.</li>
* <li><strong><a name="number">Number:</a></strong>
* For formatting, the number of pattern letters is the minimum
* number of digits, and shorter numbers are zero-padded to this amount.
* For parsing, the number of pattern letters is ignored unless
- * it's needed to separate two adjacent fields.<br><br></li>
+ * it's needed to separate two adjacent fields.</li>
* <li><strong><a name="year">Year:</a></strong>
* If the formatter's {@link #getCalendar() Calendar} is the Gregorian
- * calendar, the following rules are applied.<br>
+ * calendar, the following rules are applied.
* <ul>
* <li>For formatting, if the number of pattern letters is 2, the year
* is truncated to 2 digits; otherwise it is interpreted as a
@@ -257,7 +290,7 @@
* letters is 4 or more, a calendar specific {@linkplain
* Calendar#LONG long form} is used. Otherwise, a calendar
* specific {@linkplain Calendar#SHORT short or abbreviated form}
- * is used.<br>
+ * is used.
* <br>
* If week year {@code 'Y'} is specified and the {@linkplain
* #getCalendar() calendar} doesn't support any <a
@@ -266,11 +299,11 @@
* support of week years can be tested with a call to {@link
* DateFormat#getCalendar() getCalendar()}.{@link
* java.util.Calendar#isWeekDateSupported()
- * isWeekDateSupported()}.<br><br></li>
+ * isWeekDateSupported()}.</li>
* <li><strong><a name="month">Month:</a></strong>
* If the number of pattern letters is 3 or more, the month is
* interpreted as <a href="#text">text</a>; otherwise,
- * it is interpreted as a <a href="#number">number</a>.<br><br></li>
+ * it is interpreted as a <a href="#number">number</a>.</li>
* <li><strong><a name="timezone">General time zone:</a></strong>
* Time zones are interpreted as <a href="#text">text</a> if they have
* names. For time zones representing a GMT offset value, the
@@ -291,7 +324,7 @@
* 00 and 59. The format is locale independent and digits must be taken
* from the Basic Latin block of the Unicode standard.
* <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
- * accepted.<br><br></li>
+ * accepted.</li>
* <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
* For formatting, the RFC 822 4-digit time zone format is used:
*
@@ -533,6 +566,11 @@
transient boolean useDateFormatSymbols;
/**
+ * ICU TimeZoneNames used to format and parse time zone names.
+ */
+ private transient TimeZoneNames timeZoneNames;
+
+ /**
* Constructs a <code>SimpleDateFormat</code> using the default pattern and
* date format symbols for the default
* {@link java.util.Locale.Category#FORMAT FORMAT} locale.
@@ -1116,6 +1154,16 @@
Field.DAY_OF_WEEK
};
+ private static final String UTC = "UTC";
+
+ /**
+ * The list of time zone ids formatted as "UTC".
+ * This mirrors isUtc in libcore_icu_TimeZoneNames.cpp
+ */
+ private static final Set<String> UTC_ZONE_IDS = Collections.unmodifiableSet(new HashSet<>(
+ Arrays.asList("Etc/UCT", "Etc/UTC", "Etc/Universal", "Etc/Zulu", "UCT", "UTC",
+ "Universal", "Zulu")));
+
/**
* Private member function that does the real date/time formatting.
*/
@@ -1241,13 +1289,32 @@
if (current == null) {
TimeZone tz = calendar.getTimeZone();
boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
- int tzstyle = count < 4 ? TimeZone.SHORT : TimeZone.LONG;
String zoneString;
if (formatData.isZoneStringsSet) {
- zoneString = TimeZoneNames.getDisplayName(
+ // DateFormatSymbols.setZoneStrings() has be used, use those values instead of
+ // ICU code.
+ int tzstyle = count < 4 ? TimeZone.SHORT : TimeZone.LONG;
+ zoneString = libcore.icu.TimeZoneNames.getDisplayName(
formatData.getZoneStringsWrapper(), tz.getID(), daylight, tzstyle);
} else {
- zoneString = tz.getDisplayName(daylight, tzstyle, formatData.locale);
+ if (UTC_ZONE_IDS.contains(tz.getID())) {
+ // ICU doesn't have name strings for UTC, explicitly print it as "UTC".
+ zoneString = UTC;
+ } else {
+ TimeZoneNames.NameType nameType;
+ if (count < 4) {
+ nameType = daylight
+ ? TimeZoneNames.NameType.SHORT_DAYLIGHT
+ : TimeZoneNames.NameType.SHORT_STANDARD;
+ } else {
+ nameType = daylight
+ ? TimeZoneNames.NameType.LONG_DAYLIGHT
+ : TimeZoneNames.NameType.LONG_STANDARD;
+ }
+ String canonicalID = android.icu.util.TimeZone.getCanonicalID(tz.getID());
+ zoneString = getTimeZoneNames()
+ .getDisplayName(canonicalID, nameType, calendar.getTimeInMillis());
+ }
}
if (zoneString != null) {
buffer.append(zoneString);
@@ -1694,22 +1761,127 @@
return -1;
}
- private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
- String[][] zoneStrings) {
- int index = standardIndex + 2;
- String zoneName = zoneStrings[zoneIndex][index];
- if (text.regionMatches(true, start,
- zoneName, 0, zoneName.length())) {
- return true;
+ /**
+ * Parses the string in {@code text} (starting at {@code start}), interpreting it as a time zone
+ * name. If a time zone is found, the internal calendar is set to that timezone and the index of
+ * the first character after the time zone name is returned. Otherwise, returns {@code 0}.
+ * @return the index of the next character to parse or {@code 0} on error.
+ */
+ private int subParseZoneString(String text, int start, CalendarBuilder calb) {
+ if (formatData.isZoneStringsSet) {
+ // DateFormatSymbols.setZoneStrings() has be used, use those values instead of ICU code.
+ return subParseZoneStringFromSymbols(text, start, calb);
+ } else {
+ return subParseZoneStringFromICU(text, start, calb);
}
- return false;
+ }
+
+ private TimeZoneNames getTimeZoneNames() {
+ if (timeZoneNames == null) {
+ timeZoneNames = TimeZoneNames.getInstance(locale);
+ }
+ return timeZoneNames;
}
/**
- * find time zone 'text' matched zoneStrings and set to internal
- * calendar.
+ * The set of name types accepted when parsing time zone names.
*/
- private int subParseZoneString(String text, int start, CalendarBuilder calb) {
+ private static final EnumSet<TimeZoneNames.NameType> NAME_TYPES =
+ EnumSet.of(TimeZoneNames.NameType.LONG_GENERIC, TimeZoneNames.NameType.LONG_STANDARD,
+ TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_GENERIC,
+ TimeZoneNames.NameType.SHORT_STANDARD, TimeZoneNames.NameType.SHORT_DAYLIGHT);
+
+ /**
+ * Time zone name types that indicate daylight saving time.
+ */
+ private static final Set<TimeZoneNames.NameType> DST_NAME_TYPES =
+ Collections.unmodifiableSet(EnumSet.of(
+ TimeZoneNames.NameType.LONG_DAYLIGHT, TimeZoneNames.NameType.SHORT_DAYLIGHT));
+
+ /**
+ * Parses the time zone string using the ICU4J class {@link TimeZoneNames}.
+ */
+ private int subParseZoneStringFromICU(String text, int start, CalendarBuilder calb) {
+ String currentTimeZoneID = android.icu.util.TimeZone.getCanonicalID(getTimeZone().getID());
+
+ TimeZoneNames tzNames = getTimeZoneNames();
+ TimeZoneNames.MatchInfo bestMatch = null;
+ // The MetaZones associated with the current time zone are needed in two places, both of
+ // which are avoided in some cases, so they are computed lazily.
+ Set<String> currentTzMetaZoneIds = null;
+
+ // ICU doesn't parse the string "UTC", so manually check for it.
+ if (start + UTC.length() <= text.length() &&
+ text.regionMatches(true /* ignoreCase */, start, UTC, 0, UTC.length())) {
+ bestMatch = new TimeZoneNames.MatchInfo(
+ TimeZoneNames.NameType.SHORT_GENERIC, UTC, null, UTC.length());
+ } else {
+ Collection<TimeZoneNames.MatchInfo> matches = tzNames.find(text, start, NAME_TYPES);
+ for (TimeZoneNames.MatchInfo match : matches) {
+ if (bestMatch == null || bestMatch.matchLength() < match.matchLength()) {
+ bestMatch = match;
+ } else if (bestMatch.matchLength() == match.matchLength()) {
+ if (currentTimeZoneID.equals(match.tzID())) {
+ // Prefer the currently set timezone over other matches, even if they are
+ // the same length.
+ bestMatch = match;
+ break;
+ } else if (match.mzID() != null) {
+ if (currentTzMetaZoneIds == null) {
+ currentTzMetaZoneIds =
+ tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
+ }
+ if (currentTzMetaZoneIds.contains(match.mzID())) {
+ bestMatch = match;
+ break;
+ }
+ }
+ }
+ }
+ if (bestMatch == null) {
+ // No match found, return error.
+ return 0;
+ }
+ }
+
+ String tzId = bestMatch.tzID();
+ if (tzId == null) {
+ if (currentTzMetaZoneIds == null) {
+ currentTzMetaZoneIds = tzNames.getAvailableMetaZoneIDs(currentTimeZoneID);
+ }
+ if (currentTzMetaZoneIds.contains(bestMatch.mzID())) {
+ tzId = currentTimeZoneID;
+ } else {
+ // Match was for a meta-zone, find the matching reference zone.
+ ULocale uLocale = ULocale.forLocale(locale);
+ String region = uLocale.getCountry();
+ if (region.length() == 0) {
+ uLocale = ULocale.addLikelySubtags(uLocale);
+ region = uLocale.getCountry();
+ }
+ tzId = tzNames.getReferenceZoneID(bestMatch.mzID(), region);
+ }
+ }
+
+ TimeZone newTimeZone = TimeZone.getTimeZone(tzId);
+ if (!currentTimeZoneID.equals(tzId)) {
+ setTimeZone(newTimeZone);
+ }
+
+ // Same logic as in subParseZoneStringFromSymbols, see below for details.
+ boolean isDst = DST_NAME_TYPES.contains(bestMatch.nameType());
+ int dstAmount = isDst ? newTimeZone.getDSTSavings() : 0;
+ if (!isDst || dstAmount != 0) {
+ calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount);
+ }
+
+ return bestMatch.matchLength() + start;
+ }
+
+ /**
+ * Parses the time zone string using the information in {@link #formatData}.
+ */
+ private int subParseZoneStringFromSymbols(String text, int start, CalendarBuilder calb) {
boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
TimeZone currentTimeZone = getTimeZone();
diff --git a/ojluni/src/main/java/java/util/Currency.java b/ojluni/src/main/java/java/util/Currency.java
index da6df1b..9856f50 100644
--- a/ojluni/src/main/java/java/util/Currency.java
+++ b/ojluni/src/main/java/java/util/Currency.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,49 +27,45 @@
package java.util;
import java.io.Serializable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import libcore.icu.ICU;
/**
* Represents a currency. Currencies are identified by their ISO 4217 currency
- * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
- * ISO web site</a> for more information, including a table of
- * currency codes.
+ * codes. Visit the <a href="http://www.iso.org/iso/home/standards/currency_codes.htm">
+ * ISO web site</a> for more information.
* <p>
* The class is designed so that there's never more than one
* <code>Currency</code> instance for any given currency. Therefore, there's
* no public constructor. You obtain a <code>Currency</code> instance using
* the <code>getInstance</code> methods.
- * <p>
- * Users can supersede the Java runtime currency data by creating a properties
- * file named <code><JAVA_HOME>/lib/currency.properties</code>. The contents
- * of the properties file are key/value pairs of the ISO 3166 country codes
- * and the ISO 4217 currency data respectively. The value part consists of
- * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
- * code, and a minor unit. Those three ISO 4217 values are separated by commas.
- * The lines which start with '#'s are considered comment lines. For example,
- * <p>
- * <code>
- * #Sample currency properties<br>
- * JP=JPZ,999,0
- * </code>
- * <p>
- * will supersede the currency data for Japan.
*
* @since 1.4
*/
+// Android-changed: Superseding runtime currency data via a properties file is not
+// supported on Android.
public final class Currency implements Serializable {
private static final long serialVersionUID = -158308464356906721L;
- private static HashMap<String, Currency> instances = new HashMap<>();
+ /**
+ * ISO 4217 currency code for this currency.
+ *
+ * @serial
+ */
+ private final String currencyCode;
+ // class data: instance map
+
+ private static ConcurrentMap<String, Currency> instances = new ConcurrentHashMap<>(7);
private static HashSet<Currency> available;
+ // Android-changed: Implement Currency on top of ICU throughout.
+ // We do not keep track of defaultFractionDigits and numericCode separately here.
private transient final android.icu.util.Currency icuCurrency;
- private final String currencyCode;
-
/**
* Constructs a <code>Currency</code> instance. The constructor is private
* so that we can insure that there's never more than one instance for a
@@ -90,19 +86,20 @@
* a supported ISO 4217 code.
*/
public static Currency getInstance(String currencyCode) {
- synchronized (instances) {
- Currency instance = instances.get(currencyCode);
- if (instance == null) {
- android.icu.util.Currency icuInstance =
- android.icu.util.Currency.getInstance(currencyCode);
- if (icuInstance == null) {
- return null;
- }
- instance = new Currency(icuInstance);
- instances.put(currencyCode, instance);
- }
+ // Android-changed BEGIN: use ICU
+ Currency instance = instances.get(currencyCode);
+ if (instance != null) {
return instance;
}
+ android.icu.util.Currency icuInstance =
+ android.icu.util.Currency.getInstance(currencyCode);
+ if (icuInstance == null) {
+ return null;
+ }
+ Currency currencyVal = new Currency(icuInstance);
+ // ANDROID-changed END
+ instance = instances.putIfAbsent(currencyCode, currencyVal);
+ return (instance != null ? instance : currencyVal);
}
/**
@@ -120,13 +117,14 @@
* @param locale the locale for whose country a <code>Currency</code>
* instance is needed
* @return the <code>Currency</code> instance for the country of the given
- * locale, or null
+ * locale, or {@code null}
* @exception NullPointerException if <code>locale</code> or its country
- * code is null
- * @exception IllegalArgumentException if the country of the given locale
+ * code is {@code null}
+ * @exception IllegalArgumentException if the country of the given {@code locale}
* is not a supported ISO 3166 country code.
*/
public static Currency getInstance(Locale locale) {
+ // Android-changed BEGIN: use ICU
android.icu.util.Currency icuInstance =
android.icu.util.Currency.getInstance(locale);
String variant = locale.getVariant();
@@ -143,6 +141,7 @@
return null;
}
return getInstance(currencyCode);
+ // Android-changed END
}
/**
@@ -156,8 +155,9 @@
* @since 1.7
*/
public static Set<Currency> getAvailableCurrencies() {
- synchronized (Currency.class) {
+ synchronized(Currency.class) {
if (available == null) {
+ // Android-changed BEGIN: use ICU
Set<android.icu.util.Currency> icuAvailableCurrencies
= android.icu.util.Currency.getAvailableCurrencies();
available = new HashSet<>();
@@ -169,9 +169,13 @@
}
available.add(currency);
}
+ // Android-changed END
}
- return (Set<Currency>) available.clone();
}
+
+ @SuppressWarnings("unchecked")
+ Set<Currency> result = (Set<Currency>) available.clone();
+ return result;
}
/**
@@ -184,15 +188,21 @@
}
/**
- * Gets the symbol of this currency for the default locale.
+ * Gets the symbol of this currency for the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale.
* For example, for the US Dollar, the symbol is "$" if the default
* locale is the US, while for other locales it may be "US$". If no
* symbol can be determined, the ISO 4217 currency code is returned.
+ * <p>
+ * This is equivalent to calling
+ * {@link #getSymbol(Locale)
+ * getSymbol(Locale.getDefault(Locale.Category.DISPLAY))}.
*
- * @return the symbol of this currency for the default locale
+ * @return the symbol of this currency for the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale
*/
public String getSymbol() {
- return icuCurrency.getSymbol();
+ return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
}
/**
@@ -207,10 +217,12 @@
* @exception NullPointerException if <code>locale</code> is null
*/
public String getSymbol(Locale locale) {
+ // Android-changed BEGIN: use ICU
if (locale == null) {
throw new NullPointerException("locale == null");
}
return icuCurrency.getSymbol(locale);
+ // Android-changed END
}
/**
@@ -223,10 +235,12 @@
* @return the default number of fraction digits used with this currency
*/
public int getDefaultFractionDigits() {
+ // Android-changed BEGIN: use ICU
if (icuCurrency.getCurrencyCode().equals("XXX")) {
return -1;
}
return icuCurrency.getDefaultFractionDigits();
+ // Android-changed END
}
/**
@@ -236,19 +250,27 @@
* @since 1.7
*/
public int getNumericCode() {
+ // Android-changed: use ICU
+ // was: return numericCode;
return icuCurrency.getNumericCode();
}
/**
* Gets the name that is suitable for displaying this currency for
- * the default locale. If there is no suitable display name found
+ * the default {@link Locale.Category#DISPLAY DISPLAY} locale.
+ * If there is no suitable display name found
* for the default locale, the ISO 4217 currency code is returned.
+ * <p>
+ * This is equivalent to calling
+ * {@link #getDisplayName(Locale)
+ * getDisplayName(Locale.getDefault(Locale.Category.DISPLAY))}.
*
- * @return the display name of this currency for the default locale
+ * @return the display name of this currency for the default
+ * {@link Locale.Category#DISPLAY DISPLAY} locale
* @since 1.7
*/
public String getDisplayName() {
- return icuCurrency.getDisplayName();
+ return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
}
/**
@@ -263,7 +285,8 @@
* @since 1.7
*/
public String getDisplayName(Locale locale) {
- return icuCurrency.getDisplayName(locale);
+ // Android-changed: use ICU
+ return icuCurrency.getDisplayName(Objects.requireNonNull(locale));
}
/**
@@ -271,7 +294,9 @@
*
* @return the ISO 4217 currency code of this currency
*/
+ @Override
public String toString() {
+ // Android-changed: use ICU
return icuCurrency.toString();
}
diff --git a/ojluni/src/main/java/java/util/Formattable.java b/ojluni/src/main/java/java/util/Formattable.java
index 28b788c..f7e1e50 100644
--- a/ojluni/src/main/java/java/util/Formattable.java
+++ b/ojluni/src/main/java/java/util/Formattable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
* For example, the following class prints out different representations of a
* stock's name depending on the flags and length constraints:
*
- * <blockquote><pre>
+ * {@code
* import java.nio.CharBuffer;
* import java.util.Formatter;
* import java.util.Formattable;
@@ -89,12 +89,12 @@
* return String.format("%s - %s", symbol, companyName);
* }
* }
- * </pre></blockquote>
+ * }
*
* <p> When used in conjunction with the {@link java.util.Formatter}, the above
* class produces the following output for various format strings.
*
- * <blockquote><pre>
+ * {@code
* Formatter fmt = new Formatter();
* StockName sn = new StockName("HUGE", "Huge Fruit, Inc.",
* "Fruit Titanesque, Inc.");
@@ -104,7 +104,7 @@
* fmt.format("%-10.8s", sn); // -> "HUGE "
* fmt.format("%.12s", sn); // -> "Huge Fruit,*"
* fmt.format(Locale.FRANCE, "%25s", sn); // -> " Fruit Titanesque, Inc."
- * </pre></blockquote>
+ * }
*
* <p> Formattables are not necessarily safe for multithreaded access. Thread
* safety is optional and may be enforced by classes that extend and implement
diff --git a/ojluni/src/main/java/java/util/IllegalFormatConversionException.java b/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
index 9bdbfc4..a9b006f 100644
--- a/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
+++ b/ojluni/src/main/java/java/util/IllegalFormatConversionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
private static final long serialVersionUID = 17000126L;
private char c;
- private Class arg;
+ private Class<?> arg;
/**
* Constructs an instance of this class with the mismatched conversion and
diff --git a/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java b/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
index 64dde4d..bacab3d 100644
--- a/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
+++ b/ojluni/src/main/java/java/util/InvalidPropertiesFormatException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,9 @@
*/
public class InvalidPropertiesFormatException extends IOException {
+
+ private static final long serialVersionUID = 7763056076009360219L;
+
/**
* Constructs an InvalidPropertiesFormatException with the specified
* cause.
diff --git a/ojluni/src/main/java/java/util/ListResourceBundle.java b/ojluni/src/main/java/java/util/ListResourceBundle.java
index 736016f..99090ca 100644
--- a/ojluni/src/main/java/java/util/ListResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ListResourceBundle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -89,7 +89,7 @@
*
* public class MyResources_fr extends ListResourceBundle {
* protected Object[][] getContents() {
- * return new Object[][] = {
+ * return new Object[][] {
* // LOCALIZE THIS
* {"s1", "Le disque \"{1}\" {0}."}, // MessageFormat pattern
* {"s2", "1"}, // location of {0} in pattern
@@ -105,6 +105,12 @@
* }
* </pre>
* </blockquote>
+ *
+ * <p>
+ * The implementation of a {@code ListResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the methods in this class are thread-safe.
+ *
* @see ResourceBundle
* @see PropertyResourceBundle
* @since JDK1.1
@@ -200,5 +206,8 @@
lookup = temp;
}
- private Map<String,Object> lookup = null;
+ // Android-changed: Fix unsafe publication http://b/31467561
+ // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+ // was: private Map<String,Object> lookup = null;
+ private volatile Map<String,Object> lookup = null;
}
diff --git a/ojluni/src/main/java/java/util/MissingFormatWidthException.java b/ojluni/src/main/java/java/util/MissingFormatWidthException.java
index af76ac5..9650fe2 100644
--- a/ojluni/src/main/java/java/util/MissingFormatWidthException.java
+++ b/ojluni/src/main/java/java/util/MissingFormatWidthException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
/**
* Unchecked exception thrown when the format width is required.
*
- * <p> Unless otherwise specified, passing a <tt>null</tt> argument to anyg
+ * <p> Unless otherwise specified, passing a <tt>null</tt> argument to any
* method or constructor in this class will cause a {@link
* NullPointerException} to be thrown.
*
diff --git a/ojluni/src/main/java/java/util/NoSuchElementException.java b/ojluni/src/main/java/java/util/NoSuchElementException.java
index 88ff2c0..15e1aad 100644
--- a/ojluni/src/main/java/java/util/NoSuchElementException.java
+++ b/ojluni/src/main/java/java/util/NoSuchElementException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,12 @@
package java.util;
/**
- * Thrown by the <code>nextElement</code> method of an
- * <code>Enumeration</code> to indicate that there are no more
- * elements in the enumeration.
+ * Thrown by various accessor methods to indicate that the element being requested
+ * does not exist.
*
* @author unascribed
- * @see java.util.Enumeration
* @see java.util.Enumeration#nextElement()
+ * @see java.util.Iterator#next()
* @since JDK1.0
*/
public
diff --git a/ojluni/src/main/java/java/util/Properties.java b/ojluni/src/main/java/java/util/Properties.java
index 7c3f0bb..fe61f98 100644
--- a/ojluni/src/main/java/java/util/Properties.java
+++ b/ojluni/src/main/java/java/util/Properties.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,8 +37,8 @@
import java.io.BufferedWriter;
/**
- * The <code>Properties</code> class represents a persistent set of
- * properties. The <code>Properties</code> can be saved to a stream
+ * The {@code Properties} class represents a persistent set of
+ * properties. The {@code Properties} can be saved to a stream
* or loaded from a stream. Each key and its corresponding value in
* the property list is a string.
* <p>
@@ -46,17 +46,17 @@
* "defaults"; this second property list is searched if
* the property key is not found in the original property list.
* <p>
- * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
- * <code>put</code> and <code>putAll</code> methods can be applied to a
- * <code>Properties</code> object. Their use is strongly discouraged as they
+ * Because {@code Properties} inherits from {@code Hashtable}, the
+ * {@code put} and {@code putAll} methods can be applied to a
+ * {@code Properties} object. Their use is strongly discouraged as they
* allow the caller to insert entries whose keys or values are not
- * <code>Strings</code>. The <code>setProperty</code> method should be used
- * instead. If the <code>store</code> or <code>save</code> method is called
- * on a "compromised" <code>Properties</code> object that contains a
- * non-<code>String</code> key or value, the call will fail. Similarly,
- * the call to the <code>propertyNames</code> or <code>list</code> method
- * will fail if it is called on a "compromised" <code>Properties</code>
- * object that contains a non-<code>String</code> key.
+ * {@code Strings}. The {@code setProperty} method should be used
+ * instead. If the {@code store} or {@code save} method is called
+ * on a "compromised" {@code Properties} object that contains a
+ * non-{@code String} key or value, the call will fail. Similarly,
+ * the call to the {@code propertyNames} or {@code list} method
+ * will fail if it is called on a "compromised" {@code Properties}
+ * object that contains a non-{@code String} key.
*
* <p>
* The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
@@ -78,8 +78,9 @@
* <p> The {@link #loadFromXML(InputStream)} and {@link
* #storeToXML(OutputStream, String, String)} methods load and store properties
* in a simple XML format. By default the UTF-8 character encoding is used,
- * however a specific encoding may be specified if required. An XML properties
- * document has the following DOCTYPE declaration:
+ * however a specific encoding may be specified if required. Implementations
+ * are required to support UTF-8 and UTF-16 and may support other encodings.
+ * An XML properties document has the following DOCTYPE declaration:
*
* <pre>
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
@@ -146,15 +147,15 @@
}
/**
- * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
+ * Calls the <tt>Hashtable</tt> method {@code put}. Provided for
* parallelism with the <tt>getProperty</tt> method. Enforces use of
* strings for property keys and values. The value returned is the
- * result of the <tt>Hashtable</tt> call to <code>put</code>.
+ * result of the <tt>Hashtable</tt> call to {@code put}.
*
* @param key the key to be placed into this property list.
* @param value the value corresponding to <tt>key</tt>.
* @return the previous value of the specified key in this property
- * list, or <code>null</code> if it did not have one.
+ * list, or {@code null} if it did not have one.
* @see #getProperty
* @since 1.2
*/
@@ -171,13 +172,13 @@
* kinds of line, <i>natural lines</i> and <i>logical lines</i>.
* A natural line is defined as a line of
* characters that is terminated either by a set of line terminator
- * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
+ * characters ({@code \n} or {@code \r} or {@code \r\n})
* or by the end of the stream. A natural line may be either a blank line,
* a comment line, or hold all or some of a key-element pair. A logical
* line holds all the data of a key-element pair, which may be spread
* out across several adjacent natural lines by escaping
* the line terminator sequence with a backslash character
- * <code>\</code>. Note that a comment line cannot be extended
+ * {@code \}. Note that a comment line cannot be extended
* in this manner; every natural line that is a comment must have
* its own comment indicator, as described below. Lines are read from
* input until the end of the stream is reached.
@@ -185,13 +186,13 @@
* <p>
* A natural line that contains only white space characters is
* considered blank and is ignored. A comment line has an ASCII
- * <code>'#'</code> or <code>'!'</code> as its first non-white
+ * {@code '#'} or {@code '!'} as its first non-white
* space character; comment lines are also ignored and do not
* encode key-element information. In addition to line
* terminators, this format considers the characters space
- * (<code>' '</code>, <code>'\u0020'</code>), tab
- * (<code>'\t'</code>, <code>'\u0009'</code>), and form feed
- * (<code>'\f'</code>, <code>'\u000C'</code>) to be white
+ * ({@code ' '}, {@code '\u005Cu0020'}), tab
+ * ({@code '\t'}, {@code '\u005Cu0009'}), and form feed
+ * ({@code '\f'}, {@code '\u005Cu000C'}) to be white
* space.
*
* <p>
@@ -215,32 +216,31 @@
* <p>
* The key contains all of the characters in the line starting
* with the first non-white space character and up to, but not
- * including, the first unescaped <code>'='</code>,
- * <code>':'</code>, or white space character other than a line
+ * including, the first unescaped {@code '='},
+ * {@code ':'}, or white space character other than a line
* terminator. All of these key termination characters may be
* included in the key by escaping them with a preceding backslash
* character; for example,<p>
*
- * <code>\:\=</code><p>
+ * {@code \:\=}<p>
*
- * would be the two-character key <code>":="</code>. Line
- * terminator characters can be included using <code>\r</code> and
- * <code>\n</code> escape sequences. Any white space after the
+ * would be the two-character key {@code ":="}. Line
+ * terminator characters can be included using {@code \r} and
+ * {@code \n} escape sequences. Any white space after the
* key is skipped; if the first non-white space character after
- * the key is <code>'='</code> or <code>':'</code>, then it is
+ * the key is {@code '='} or {@code ':'}, then it is
* ignored and any white space characters after it are also
* skipped. All remaining characters on the line become part of
* the associated element string; if there are no remaining
* characters, the element is the empty string
- * <code>""</code>. Once the raw character sequences
+ * {@code ""}. Once the raw character sequences
* constituting the key and element are identified, escape
* processing is performed as described above.
*
* <p>
* As an example, each of the following three lines specifies the key
- * <code>"Truth"</code> and the associated element value
- * <code>"Beauty"</code>:
- * <p>
+ * {@code "Truth"} and the associated element value
+ * {@code "Beauty"}:
* <pre>
* Truth = Beauty
* Truth:Beauty
@@ -248,29 +248,25 @@
* </pre>
* As another example, the following three lines specify a single
* property:
- * <p>
* <pre>
* fruits apple, banana, pear, \
* cantaloupe, watermelon, \
* kiwi, mango
* </pre>
- * The key is <code>"fruits"</code> and the associated element is:
- * <p>
+ * The key is {@code "fruits"} and the associated element is:
* <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
- * Note that a space appears before each <code>\</code> so that a space
- * will appear after each comma in the final result; the <code>\</code>,
+ * Note that a space appears before each {@code \} so that a space
+ * will appear after each comma in the final result; the {@code \},
* line terminator, and leading white space on the continuation line are
* merely discarded and are <i>not</i> replaced by one or more other
* characters.
* <p>
* As a third example, the line:
- * <p>
* <pre>cheeses
* </pre>
- * specifies that the key is <code>"cheeses"</code> and the associated
- * element is the empty string <code>""</code>.<p>
+ * specifies that the key is {@code "cheeses"} and the associated
+ * element is the empty string {@code ""}.
* <p>
- *
* <a name="unicodeescapes"></a>
* Characters in keys and elements can be represented in escape
* sequences similar to those used for character and string literals
@@ -283,24 +279,24 @@
* <ul>
* <li> Octal escapes are not recognized.
*
- * <li> The character sequence <code>\b</code> does <i>not</i>
+ * <li> The character sequence {@code \b} does <i>not</i>
* represent a backspace character.
*
* <li> The method does not treat a backslash character,
- * <code>\</code>, before a non-valid escape character as an
+ * {@code \}, before a non-valid escape character as an
* error; the backslash is silently dropped. For example, in a
- * Java string the sequence <code>"\z"</code> would cause a
+ * Java string the sequence {@code "\z"} would cause a
* compile time error. In contrast, this method silently drops
* the backslash. Therefore, this method treats the two character
- * sequence <code>"\b"</code> as equivalent to the single
- * character <code>'b'</code>.
+ * sequence {@code "\b"} as equivalent to the single
+ * character {@code 'b'}.
*
* <li> Escapes are not necessary for single and double quotes;
* however, by the rule above, single and double quote characters
* preceded by a backslash still yield single and double quote
* characters, respectively.
*
- * <li> Only a single 'u' character is allowed in a Uniocde escape
+ * <li> Only a single 'u' character is allowed in a Unicode escape
* sequence.
*
* </ul>
@@ -366,7 +362,9 @@
valueStart = keyLen + 1;
hasSep = true;
break;
- } else if (Character.isWhitespace(c) && !precedingBackslash) {
+ }
+ // Android-changed: use of Character.isWhitespace(c) b/25998006
+ else if (Character.isWhitespace(c) && !precedingBackslash) {
valueStart = keyLen + 1;
break;
}
@@ -379,6 +377,7 @@
}
while (valueStart < limit) {
c = lr.lineBuf[valueStart];
+ // Android-changed: use of Character.isWhitespace(c) b/25998006
if (!Character.isWhitespace(c)) {
if (!hasSep && (c == '=' || c == ':')) {
hasSep = true;
@@ -439,6 +438,9 @@
if (len == 0 || isCommentLine) {
return -1;
}
+ if (precedingBackslash) {
+ len--;
+ }
return len;
}
}
@@ -456,6 +458,7 @@
}
}
if (skipWhiteSpace) {
+ // Android-changed: use of Character.isWhitespace(c) b/25998006
if (Character.isWhitespace(c)) {
continue;
}
@@ -506,6 +509,9 @@
:inStream.read(inByteBuf);
inOff = 0;
if (inLimit <= 0) {
+ if (precedingBackslash) {
+ len--;
+ }
return len;
}
}
@@ -689,20 +695,20 @@
}
/**
- * Calls the <code>store(OutputStream out, String comments)</code> method
+ * Calls the {@code store(OutputStream out, String comments)} method
* and suppresses IOExceptions that were thrown.
*
* @deprecated This method does not throw an IOException if an I/O error
* occurs while saving the property list. The preferred way to save a
- * properties list is via the <code>store(OutputStream out,
- * String comments)</code> method or the
- * <code>storeToXML(OutputStream os, String comment)</code> method.
+ * properties list is via the {@code store(OutputStream out,
+ * String comments)} method or the
+ * {@code storeToXML(OutputStream os, String comment)} method.
*
* @param out an output stream.
* @param comments a description of the property list.
- * @exception ClassCastException if this <code>Properties</code> object
+ * @exception ClassCastException if this {@code Properties} object
* contains any keys or values that are not
- * <code>Strings</code>.
+ * {@code Strings}.
*/
@Deprecated
public void save(OutputStream out, String comments) {
@@ -714,37 +720,37 @@
/**
* Writes this property list (key and element pairs) in this
- * <code>Properties</code> table to the output character stream in a
+ * {@code Properties} table to the output character stream in a
* format suitable for using the {@link #load(java.io.Reader) load(Reader)}
* method.
* <p>
- * Properties from the defaults table of this <code>Properties</code>
+ * Properties from the defaults table of this {@code Properties}
* table (if any) are <i>not</i> written out by this method.
* <p>
- * If the comments argument is not null, then an ASCII <code>#</code>
+ * If the comments argument is not null, then an ASCII {@code #}
* character, the comments string, and a line separator are first written
- * to the output stream. Thus, the <code>comments</code> can serve as an
+ * to the output stream. Thus, the {@code comments} can serve as an
* identifying comment. Any one of a line feed ('\n'), a carriage
* return ('\r'), or a carriage return followed immediately by a line feed
- * in comments is replaced by a line separator generated by the <code>Writer</code>
- * and if the next character in comments is not character <code>#</code> or
- * character <code>!</code> then an ASCII <code>#</code> is written out
+ * in comments is replaced by a line separator generated by the {@code Writer}
+ * and if the next character in comments is not character {@code #} or
+ * character {@code !} then an ASCII {@code #} is written out
* after that line separator.
* <p>
* Next, a comment line is always written, consisting of an ASCII
- * <code>#</code> character, the current date and time (as if produced
- * by the <code>toString</code> method of <code>Date</code> for the
- * current time), and a line separator as generated by the <code>Writer</code>.
+ * {@code #} character, the current date and time (as if produced
+ * by the {@code toString} method of {@code Date} for the
+ * current time), and a line separator as generated by the {@code Writer}.
* <p>
- * Then every entry in this <code>Properties</code> table is
+ * Then every entry in this {@code Properties} table is
* written out, one per line. For each entry the key string is
- * written, then an ASCII <code>=</code>, then the associated
+ * written, then an ASCII {@code =}, then the associated
* element string. For the key, all space characters are
- * written with a preceding <code>\</code> character. For the
+ * written with a preceding {@code \} character. For the
* element, leading space characters, but not embedded or trailing
- * space characters, are written with a preceding <code>\</code>
- * character. The key and element characters <code>#</code>,
- * <code>!</code>, <code>=</code>, and <code>:</code> are written
+ * space characters, are written with a preceding {@code \}
+ * character. The key and element characters {@code #},
+ * {@code !}, {@code =}, and {@code :} are written
* with a preceding backslash to ensure that they are properly loaded.
* <p>
* After the entries have been written, the output stream is flushed.
@@ -755,9 +761,9 @@
* @param comments a description of the property list.
* @exception IOException if writing this property list to the specified
* output stream throws an <tt>IOException</tt>.
- * @exception ClassCastException if this <code>Properties</code> object
- * contains any keys or values that are not <code>Strings</code>.
- * @exception NullPointerException if <code>writer</code> is null.
+ * @exception ClassCastException if this {@code Properties} object
+ * contains any keys or values that are not {@code Strings}.
+ * @exception NullPointerException if {@code writer} is null.
* @since 1.6
*/
public void store(Writer writer, String comments)
@@ -771,11 +777,11 @@
/**
* Writes this property list (key and element pairs) in this
- * <code>Properties</code> table to the output stream in a format suitable
- * for loading into a <code>Properties</code> table using the
+ * {@code Properties} table to the output stream in a format suitable
+ * for loading into a {@code Properties} table using the
* {@link #load(InputStream) load(InputStream)} method.
* <p>
- * Properties from the defaults table of this <code>Properties</code>
+ * Properties from the defaults table of this {@code Properties}
* table (if any) are <i>not</i> written out by this method.
* <p>
* This method outputs the comments, properties keys and values in
@@ -786,12 +792,12 @@
* <li>The stream is written using the ISO 8859-1 character encoding.
*
* <li>Characters not in Latin-1 in the comments are written as
- * <code>\u</code><i>xxxx</i> for their appropriate unicode
+ * {@code \u005Cu}<i>xxxx</i> for their appropriate unicode
* hexadecimal value <i>xxxx</i>.
*
- * <li>Characters less than <code>\u0020</code> and characters greater
- * than <code>\u007E</code> in property keys or values are written
- * as <code>\u</code><i>xxxx</i> for the appropriate hexadecimal
+ * <li>Characters less than {@code \u005Cu0020} and characters greater
+ * than {@code \u005Cu007E} in property keys or values are written
+ * as {@code \u005Cu}<i>xxxx</i> for the appropriate hexadecimal
* value <i>xxxx</i>.
* </ul>
* <p>
@@ -802,9 +808,9 @@
* @param comments a description of the property list.
* @exception IOException if writing this property list to the specified
* output stream throws an <tt>IOException</tt>.
- * @exception ClassCastException if this <code>Properties</code> object
- * contains any keys or values that are not <code>Strings</code>.
- * @exception NullPointerException if <code>out</code> is null.
+ * @exception ClassCastException if this {@code Properties} object
+ * contains any keys or values that are not {@code Strings}.
+ * @exception NullPointerException if {@code out} is null.
* @since 1.2
*/
public void store(OutputStream out, String comments)
@@ -824,7 +830,7 @@
bw.write("#" + new Date().toString());
bw.newLine();
synchronized (this) {
- for (Enumeration e = keys(); e.hasMoreElements();) {
+ for (Enumeration<?> e = keys(); e.hasMoreElements();) {
String key = (String)e.nextElement();
String val = (String)get(key);
key = saveConvert(key, true, escUnicode);
@@ -850,23 +856,36 @@
* Furthermore, the document must satisfy the properties DTD described
* above.
*
+ * <p> An implementation is required to read XML documents that use the
+ * "{@code UTF-8}" or "{@code UTF-16}" encoding. An implementation may
+ * support additional encodings.
+ *
* <p>The specified stream is closed after this method returns.
*
* @param in the input stream from which to read the XML document.
* @throws IOException if reading from the specified input stream
* results in an <tt>IOException</tt>.
+ * @throws java.io.UnsupportedEncodingException if the document's encoding
+ * declaration can be read and it specifies an encoding that is not
+ * supported
* @throws InvalidPropertiesFormatException Data on input stream does not
* constitute a valid XML document with the mandated document type.
- * @throws NullPointerException if <code>in</code> is null.
+ * @throws NullPointerException if {@code in} is null.
* @see #storeToXML(OutputStream, String, String)
+ * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+ * Encoding in Entities</a>
* @since 1.5
*/
public synchronized void loadFromXML(InputStream in)
throws IOException, InvalidPropertiesFormatException
{
- if (in == null)
- throw new NullPointerException();
- XMLUtils.load(this, in);
+ // Android-changed: Keep OpenJDK7u40's XmlUtils.
+ // XmlSupport's system property based XmlPropertiesProvider
+ // selection does not make sense on Android and has too many
+ // dependencies on classes that are not available on Android.
+ //
+ // XmlSupport.load(this, Objects.requireNonNull(in));
+ XMLUtils.load(this, Objects.requireNonNull(in));
in.close();
}
@@ -879,22 +898,20 @@
* <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
*
* @param os the output stream on which to emit the XML document.
- * @param comment a description of the property list, or <code>null</code>
+ * @param comment a description of the property list, or {@code null}
* if no comment is desired.
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
- * @throws NullPointerException if <code>os</code> is null.
- * @throws ClassCastException if this <code>Properties</code> object
+ * @throws NullPointerException if {@code os} is null.
+ * @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
- * <code>Strings</code>.
+ * {@code Strings}.
* @see #loadFromXML(InputStream)
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment)
throws IOException
{
- if (os == null)
- throw new NullPointerException();
storeToXML(os, comment, "UTF-8");
}
@@ -907,13 +924,17 @@
* <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
* </pre>
*
- *<p>If the specified comment is <code>null</code> then no comment
+ * <p>If the specified comment is {@code null} then no comment
* will be stored in the document.
*
+ * <p> An implementation is required to support writing of XML documents
+ * that use the "{@code UTF-8}" or "{@code UTF-16}" encoding. An
+ * implementation may support additional encodings.
+ *
* <p>The specified stream remains open after this method returns.
*
* @param os the output stream on which to emit the XML document.
- * @param comment a description of the property list, or <code>null</code>
+ * @param comment a description of the property list, or {@code null}
* if no comment is desired.
* @param encoding the name of a supported
* <a href="../lang/package-summary.html#charenc">
@@ -921,27 +942,37 @@
*
* @throws IOException if writing to the specified output stream
* results in an <tt>IOException</tt>.
- * @throws NullPointerException if <code>os</code> is <code>null</code>,
- * or if <code>encoding</code> is <code>null</code>.
- * @throws ClassCastException if this <code>Properties</code> object
+ * @throws java.io.UnsupportedEncodingException if the encoding is not
+ * supported by the implementation.
+ * @throws NullPointerException if {@code os} is {@code null},
+ * or if {@code encoding} is {@code null}.
+ * @throws ClassCastException if this {@code Properties} object
* contains any keys or values that are not
- * <code>Strings</code>.
+ * {@code Strings}.
* @see #loadFromXML(InputStream)
+ * @see <a href="http://www.w3.org/TR/REC-xml/#charencoding">Character
+ * Encoding in Entities</a>
* @since 1.5
*/
public void storeToXML(OutputStream os, String comment, String encoding)
throws IOException
{
- if (os == null)
- throw new NullPointerException();
- XMLUtils.save(this, os, comment, encoding);
+ // Android-changed: Keep OpenJDK7u40's XmlUtils.
+ // XmlSupport's system property based XmlPropertiesProvider
+ // selection does not make sense on Android and has too many
+ // dependencies on classes that are not available on Android.
+ //
+ // XmlSupport.save(this, Objects.requireNonNull(os), comment,
+ // Objects.requireNonNull(encoding));
+ XMLUtils.save(this, Objects.requireNonNull(os), comment,
+ Objects.requireNonNull(encoding));
}
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns
- * <code>null</code> if the property is not found.
+ * {@code null} if the property is not found.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
@@ -987,7 +1018,7 @@
* @see #stringPropertyNames
*/
public Enumeration<?> propertyNames() {
- Hashtable h = new Hashtable();
+ Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
return h.keys();
}
@@ -1026,10 +1057,10 @@
*/
public void list(PrintStream out) {
out.println("-- listing properties --");
- Hashtable h = new Hashtable();
+ Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
- for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
- String key = (String)e.nextElement();
+ for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+ String key = e.nextElement();
String val = (String)h.get(key);
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
@@ -1054,10 +1085,10 @@
*/
public void list(PrintWriter out) {
out.println("-- listing properties --");
- Hashtable h = new Hashtable();
+ Hashtable<String,Object> h = new Hashtable<>();
enumerate(h);
- for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
- String key = (String)e.nextElement();
+ for (Enumeration<String> e = h.keys() ; e.hasMoreElements() ;) {
+ String key = e.nextElement();
String val = (String)h.get(key);
if (val.length() > 40) {
val = val.substring(0, 37) + "...";
@@ -1072,11 +1103,11 @@
* @throws ClassCastException if any of the property keys
* is not of String type.
*/
- private synchronized void enumerate(Hashtable h) {
+ private synchronized void enumerate(Hashtable<String,Object> h) {
if (defaults != null) {
defaults.enumerate(h);
}
- for (Enumeration e = keys() ; e.hasMoreElements() ;) {
+ for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
String key = (String)e.nextElement();
h.put(key, get(key));
}
@@ -1091,7 +1122,7 @@
if (defaults != null) {
defaults.enumerateStringProperties(h);
}
- for (Enumeration e = keys() ; e.hasMoreElements() ;) {
+ for (Enumeration<?> e = keys() ; e.hasMoreElements() ;) {
Object k = e.nextElement();
Object v = get(k);
if (k instanceof String && v instanceof String) {
diff --git a/ojluni/src/main/java/java/util/PropertyResourceBundle.java b/ojluni/src/main/java/java/util/PropertyResourceBundle.java
index c7fe3b4..23c3ffe 100644
--- a/ojluni/src/main/java/java/util/PropertyResourceBundle.java
+++ b/ojluni/src/main/java/java/util/PropertyResourceBundle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -100,6 +100,11 @@
* </blockquote>
*
* <p>
+ * The implementation of a {@code PropertyResourceBundle} subclass must be
+ * thread-safe if it's simultaneously used by multiple threads. The default
+ * implementations of the non-abstract methods in this class are thread-safe.
+ *
+ * <p>
* <strong>Note:</strong> PropertyResourceBundle can be constructed either
* from an InputStream or a Reader, which represents a property file.
* Constructing a PropertyResourceBundle instance from an InputStream requires
@@ -124,7 +129,10 @@
* to read from.
* @throws IOException if an I/O error occurs
* @throws NullPointerException if <code>stream</code> is null
+ * @throws IllegalArgumentException if {@code stream} contains a
+ * malformed Unicode escape sequence.
*/
+ @SuppressWarnings({"unchecked", "rawtypes"})
public PropertyResourceBundle (InputStream stream) throws IOException {
Properties properties = new Properties();
properties.load(stream);
@@ -141,8 +149,11 @@
* read from.
* @throws IOException if an I/O error occurs
* @throws NullPointerException if <code>reader</code> is null
+ * @throws IllegalArgumentException if a malformed Unicode escape sequence appears
+ * from {@code reader}.
* @since 1.6
*/
+ @SuppressWarnings({"unchecked", "rawtypes"})
public PropertyResourceBundle (Reader reader) throws IOException {
Properties properties = new Properties();
properties.load(reader);
@@ -186,5 +197,8 @@
// ==================privates====================
- private Map<String,Object> lookup;
+ // Android-changed: Fix unsafe publication http://b/31467561
+ // Fixed in OpenJDK 9: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/29ecac30ecae
+ // was: private Map<String,Object> lookup;
+ private final Map<String,Object> lookup;
}
diff --git a/ojluni/src/main/java/java/util/Random.java b/ojluni/src/main/java/java/util/Random.java
index fb4ecfd..1061b59 100644
--- a/ojluni/src/main/java/java/util/Random.java
+++ b/ojluni/src/main/java/java/util/Random.java
@@ -312,9 +312,8 @@
* Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general
* contract of {@code nextInt} is that one {@code int} value is
- * pseudorandomly generated and returned. All 2<font size="-1"><sup>32
- * </sup></font> possible {@code int} values are produced with
- * (approximately) equal probability.
+ * pseudorandomly generated and returned. All 2<sup>32</sup> possible
+ * {@code int} values are produced with (approximately) equal probability.
*
* <p>The method {@code nextInt} is implemented by class {@code Random}
* as if by:
@@ -335,23 +334,23 @@
* between 0 (inclusive) and the specified value (exclusive), drawn from
* this random number generator's sequence. The general contract of
* {@code nextInt} is that one {@code int} value in the specified range
- * is pseudorandomly generated and returned. All {@code n} possible
+ * is pseudorandomly generated and returned. All {@code bound} possible
* {@code int} values are produced with (approximately) equal
- * probability. The method {@code nextInt(int n)} is implemented by
+ * probability. The method {@code nextInt(int bound)} is implemented by
* class {@code Random} as if by:
* <pre> {@code
- * public int nextInt(int n) {
- * if (n <= 0)
- * throw new IllegalArgumentException("n must be positive");
+ * public int nextInt(int bound) {
+ * if (bound <= 0)
+ * throw new IllegalArgumentException("bound must be positive");
*
- * if ((n & -n) == n) // i.e., n is a power of 2
- * return (int)((n * (long)next(31)) >> 31);
+ * if ((bound & -bound) == bound) // i.e., bound is a power of 2
+ * return (int)((bound * (long)next(31)) >> 31);
*
* int bits, val;
* do {
* bits = next(31);
- * val = bits % n;
- * } while (bits - val + (n-1) < 0);
+ * val = bits % bound;
+ * } while (bits - val + (bound-1) < 0);
* return val;
* }}</pre>
*
@@ -377,28 +376,28 @@
* greatly increases the length of the sequence of values returned by
* successive calls to this method if n is a small power of two.
*
- * @param n the bound on the random number to be returned. Must be
- * positive.
+ * @param bound the upper bound (exclusive). Must be positive.
* @return the next pseudorandom, uniformly distributed {@code int}
- * value between {@code 0} (inclusive) and {@code n} (exclusive)
+ * value between zero (inclusive) and {@code bound} (exclusive)
* from this random number generator's sequence
- * @throws IllegalArgumentException if n is not positive
+ * @throws IllegalArgumentException if bound is not positive
* @since 1.2
*/
+ public int nextInt(int bound) {
+ if (bound <= 0)
+ throw new IllegalArgumentException(BadBound);
- public int nextInt(int n) {
- if (n <= 0)
- throw new IllegalArgumentException("n must be positive");
-
- if ((n & -n) == n) // i.e., n is a power of 2
- return (int)((n * (long)next(31)) >> 31);
-
- int bits, val;
- do {
- bits = next(31);
- val = bits % n;
- } while (bits - val + (n-1) < 0);
- return val;
+ int r = next(31);
+ int m = bound - 1;
+ if ((bound & m) == 0) // i.e., bound is a power of 2
+ r = (int)((bound * (long)r) >> 31);
+ else {
+ for (int u = r;
+ u - (r = u % bound) + m < 0;
+ u = next(31))
+ ;
+ }
+ return r;
}
/**
@@ -457,11 +456,9 @@
* <p>The general contract of {@code nextFloat} is that one
* {@code float} value, chosen (approximately) uniformly from the
* range {@code 0.0f} (inclusive) to {@code 1.0f} (exclusive), is
- * pseudorandomly generated and returned. All 2<font
- * size="-1"><sup>24</sup></font> possible {@code float} values
- * of the form <i>m x </i>2<font
- * size="-1"><sup>-24</sup></font>, where <i>m</i> is a positive
- * integer less than 2<font size="-1"><sup>24</sup> </font>, are
+ * pseudorandomly generated and returned. All 2<sup>24</sup> possible
+ * {@code float} values of the form <i>m x </i>2<sup>-24</sup>,
+ * where <i>m</i> is a positive integer less than 2<sup>24</sup>, are
* produced with (approximately) equal probability.
*
* <p>The method {@code nextFloat} is implemented by class {@code Random}
@@ -532,8 +529,7 @@
* @see Math#random
*/
public double nextDouble() {
- return (((long)(next(26)) << 27) + next(27))
- / (double)(1L << 53);
+ return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}
private double nextNextGaussian;
diff --git a/ojluni/src/main/java/java/util/ResourceBundle.java b/ojluni/src/main/java/java/util/ResourceBundle.java
index f604089..bf73b03 100644
--- a/ojluni/src/main/java/java/util/ResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ResourceBundle.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,6 @@
package java.util;
-import dalvik.system.VMStack;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -59,7 +58,9 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.jar.JarEntry;
+import java.util.spi.ResourceBundleControlProvider;
+import dalvik.system.VMStack;
import sun.reflect.CallerSensitive;
import sun.util.locale.BaseLocale;
import sun.util.locale.LocaleObjectCache;
@@ -76,7 +77,7 @@
*
* <p>
* This allows you to write programs that can:
- * <UL type=SQUARE>
+ * <UL>
* <LI> be easily localized, or translated, into different languages
* <LI> handle multiple locales at once
* <LI> be easily modified later to support even more locales
@@ -186,7 +187,14 @@
* subclass. Your subclasses must override two methods: <code>handleGetObject</code>
* and <code>getKeys()</code>.
*
- * <h4>ResourceBundle.Control</h4>
+ * <p>
+ * The implementation of a {@code ResourceBundle} subclass must be thread-safe
+ * if it's simultaneously used by multiple threads. The default implementations
+ * of the non-abstract methods in this class, and the methods in the direct
+ * known concrete subclasses {@code ListResourceBundle} and
+ * {@code PropertyResourceBundle} are thread-safe.
+ *
+ * <h3>ResourceBundle.Control</h3>
*
* The {@link ResourceBundle.Control} class provides information necessary
* to perform the bundle loading process by the <code>getBundle</code>
@@ -197,7 +205,18 @@
* {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
* factory method for details.
*
- * <h4>Cache Management</h4>
+ * <p><a name="modify_default_behavior">For the {@code getBundle} factory</a>
+ * methods that take no {@link Control} instance, their <a
+ * href="#default_behavior"> default behavior</a> of resource bundle loading
+ * can be modified with <em>installed</em> {@link
+ * ResourceBundleControlProvider} implementations. Any installed providers are
+ * detected at the {@code ResourceBundle} class loading time. If any of the
+ * providers provides a {@link Control} for the given base name, that {@link
+ * Control} will be used instead of the default {@link Control}. If there is
+ * more than one service provider installed for supporting the same base name,
+ * the first one returned from {@link ServiceLoader} will be used.
+ *
+ * <h3>Cache Management</h3>
*
* Resource bundle instances created by the <code>getBundle</code> factory
* methods are cached by default, and the factory methods return the same
@@ -213,7 +232,7 @@
* Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
* long) ResourceBundle.Control.needsReload} for details.
*
- * <h4>Example</h4>
+ * <h3>Example</h3>
*
* The following is a very simple example of a <code>ResourceBundle</code>
* subclass, <code>MyResources</code>, that manages two resources (for a larger number of
@@ -299,7 +318,25 @@
/**
* Queue for reference objects referring to class loaders or bundles.
*/
- private static final ReferenceQueue referenceQueue = new ReferenceQueue();
+ private static final ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
+
+ /**
+ * Returns the base name of this bundle, if known, or {@code null} if unknown.
+ *
+ * If not null, then this is the value of the {@code baseName} parameter
+ * that was passed to the {@code ResourceBundle.getBundle(...)} method
+ * when the resource bundle was loaded.
+ *
+ * @return The base name of the resource bundle, as provided to and expected
+ * by the {@code ResourceBundle.getBundle(...)} methods.
+ *
+ * @see #getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader)
+ *
+ * @since 1.8
+ */
+ public String getBaseBundleName() {
+ return name;
+ }
/**
* The parent bundle of this bundle.
@@ -334,6 +371,21 @@
*/
private volatile Set<String> keySet;
+ private static final List<ResourceBundleControlProvider> providers;
+
+ static {
+ List<ResourceBundleControlProvider> list = null;
+ ServiceLoader<ResourceBundleControlProvider> serviceLoaders
+ = ServiceLoader.loadInstalled(ResourceBundleControlProvider.class);
+ for (ResourceBundleControlProvider provider : serviceLoaders) {
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ list.add(provider);
+ }
+ providers = list;
+ }
+
/**
* Sole constructor. (For invocation by subclass constructors, typically
* implicit.)
@@ -394,12 +446,13 @@
if (parent != null) {
obj = parent.getObject(key);
}
- if (obj == null)
+ if (obj == null) {
throw new MissingResourceException("Can't find resource for bundle "
+this.getClass().getName()
+", key "+key,
this.getClass().getName(),
key);
+ }
}
return obj;
}
@@ -420,6 +473,10 @@
* resources on behalf of the client.
*/
private static ClassLoader getLoader(ClassLoader cl) {
+ // Android-changed: On Android, this method takes a ClassLoader argument:
+ // Callers call {@code getLoader(VMStack.getCallingClassLoader())}
+ // instead of {@code getLoader(Reflection.getCallerClass())}.
+ // ClassLoader cl = caller == null ? null : caller.getClassLoader();
if (cl == null) {
// When the caller's loader is the boot class loader, cl is null
// here. In that case, ClassLoader.getSystemClassLoader() may
@@ -486,7 +543,7 @@
* null, but the base name and the locale must have a non-null
* value.
*/
- private static final class CacheKey implements Cloneable {
+ private static class CacheKey implements Cloneable {
// These three are the actual keys for lookup in Map.
private String name;
private Locale locale;
@@ -581,8 +638,7 @@
// treat it as unequal
&& (loader != null)
&& (loader == otherEntry.loaderRef.get());
- } catch (NullPointerException e) {
- } catch (ClassCastException e) {
+ } catch ( NullPointerException | ClassCastException e) {
}
return false;
}
@@ -612,7 +668,7 @@
return clone;
} catch (CloneNotSupportedException e) {
//this should never happen
- throw new InternalError();
+ throw new InternalError(e);
}
}
@@ -667,11 +723,11 @@
* garbage collected when nobody else is using them. The ResourceBundle
* class has no reason to keep class loaders alive.
*/
- private static final class LoaderReference extends WeakReference<ClassLoader>
- implements CacheKeyReference {
+ private static class LoaderReference extends WeakReference<ClassLoader>
+ implements CacheKeyReference {
private CacheKey cacheKey;
- LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) {
+ LoaderReference(ClassLoader referent, ReferenceQueue<Object> q, CacheKey key) {
super(referent, q);
cacheKey = key;
}
@@ -685,11 +741,11 @@
* References to bundles are soft references so that they can be garbage
* collected when they have no hard references.
*/
- private static final class BundleReference extends SoftReference<ResourceBundle>
- implements CacheKeyReference {
+ private static class BundleReference extends SoftReference<ResourceBundle>
+ implements CacheKeyReference {
private CacheKey cacheKey;
- BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
+ BundleReference(ResourceBundle referent, ReferenceQueue<Object> q, CacheKey key) {
super(referent, q);
cacheKey = key;
}
@@ -721,9 +777,10 @@
public static final ResourceBundle getBundle(String baseName)
{
return getBundleImpl(baseName, Locale.getDefault(),
- /* must determine loader here, else we break stack invariant */
+ // Android-changed: use of VMStack.getCallingClassLoader()
getLoader(VMStack.getCallingClassLoader()),
- Control.INSTANCE);
+ // getLoader(Reflection.getCallerClass()),
+ getDefaultControl(baseName));
}
/**
@@ -764,8 +821,9 @@
public static final ResourceBundle getBundle(String baseName,
Control control) {
return getBundleImpl(baseName, Locale.getDefault(),
- /* must determine loader here, else we break stack invariant */
+ // Android-changed: use of VMStack.getCallingClassLoader()
getLoader(VMStack.getCallingClassLoader()),
+ // getLoader(Reflection.getCallerClass()),
control);
}
@@ -795,9 +853,10 @@
Locale locale)
{
return getBundleImpl(baseName, locale,
- /* must determine loader here, else we break stack invariant */
+ // Android-changed: use of VMStack.getCallingClassLoader()
getLoader(VMStack.getCallingClassLoader()),
- Control.INSTANCE);
+ // getLoader(Reflection.getCallerClass()),
+ getDefaultControl(baseName));
}
/**
@@ -841,8 +900,9 @@
public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
Control control) {
return getBundleImpl(baseName, targetLocale,
- /* must determine loader here, else we break stack invariant */
+ // Android-changed: use of VMStack.getCallingClassLoader()
getLoader(VMStack.getCallingClassLoader()),
+ // getLoader(Reflection.getCallerClass()),
control);
}
@@ -850,9 +910,15 @@
* Gets a resource bundle using the specified base name, locale, and class
* loader.
*
- * <p><a name="default_behavior"></a>This method behaves the same as calling
+ * <p>This method behaves the same as calling
* {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
- * default instance of {@link Control}. The following describes this behavior.
+ * default instance of {@link Control} unless another {@link Control} is
+ * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the
+ * description of <a href="#modify_default_behavior">modifying the default
+ * behavior</a>.
+ *
+ * <p><a name="default_behavior">The following describes the default
+ * behavior</a>.
*
* <p><code>getBundle</code> uses the base name, the specified locale, and
* the default locale (obtained from {@link java.util.Locale#getDefault()
@@ -947,8 +1013,8 @@
* <p>If still no result bundle is found, the base name alone is looked up. If
* this still fails, a <code>MissingResourceException</code> is thrown.
*
- * <p><a name="parent_chain"></a> Once a result resource bundle has been found,
- * its <em>parent chain</em> is instantiated. If the result bundle already
+ * <p><a name="parent_chain"> Once a result resource bundle has been found,
+ * its <em>parent chain</em> is instantiated</a>. If the result bundle already
* has a parent (perhaps because it was returned from a cache) the chain is
* complete.
*
@@ -977,8 +1043,8 @@
* path name (using "/") instead of a fully qualified class name (using
* ".").
*
- * <p><a name="default_behavior_example"></a>
- * <strong>Example:</strong>
+ * <p><a name="default_behavior_example">
+ * <strong>Example:</strong></a>
* <p>
* The following class and property files are provided:
* <pre>
@@ -999,7 +1065,7 @@
* <p>Calling <code>getBundle</code> with the locale arguments below will
* instantiate resource bundles as follows:
*
- * <table>
+ * <table summary="getBundle() locale to resource bundle mapping">
* <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
* <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
* <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
@@ -1027,7 +1093,7 @@
if (loader == null) {
throw new NullPointerException();
}
- return getBundleImpl(baseName, locale, loader, Control.INSTANCE);
+ return getBundleImpl(baseName, locale, loader, getDefaultControl(baseName));
}
/**
@@ -1039,7 +1105,6 @@
* bundles. Conceptually, the bundle loading process with the given
* <code>control</code> is performed in the following steps.
*
- * <p>
* <ol>
* <li>This factory method looks up the resource bundle in the cache for
* the specified <code>baseName</code>, <code>targetLocale</code> and
@@ -1079,45 +1144,45 @@
* <code>control.newBundle</code>.
*
* <table style="width: 50%; text-align: left; margin-left: 40px;"
- * border="0" cellpadding="2" cellspacing="2">
- * <tbody><code>
+ * border="0" cellpadding="2" cellspacing="2" summary="locale-format combinations for newBundle">
+ * <tbody>
* <tr>
* <td
- * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
+ * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>Locale</code><br>
* </td>
* <td
- * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
+ * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;"><code>format</code><br>
* </td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code><br>
* </td>
- * <td style="vertical-align: top; width: 50%;">java.class<br>
+ * <td style="vertical-align: top; width: 50%;"><code>java.class</code><br>
* </td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
- * <td style="vertical-align: top; width: 50%;">java.properties<br>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("de", "DE")</code></td>
+ * <td style="vertical-align: top; width: 50%;"><code>java.properties</code><br>
* </td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
- * <td style="vertical-align: top; width: 50%;">java.class</td>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+ * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
- * <td style="vertical-align: top; width: 50%;">java.properties</td>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("de")</code></td>
+ * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("")<br>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code><br>
* </td>
- * <td style="vertical-align: top; width: 50%;">java.class</td>
+ * <td style="vertical-align: top; width: 50%;"><code>java.class</code></td>
* </tr>
* <tr>
- * <td style="vertical-align: top; width: 50%;">Locale("")</td>
- * <td style="vertical-align: top; width: 50%;">java.properties</td>
+ * <td style="vertical-align: top; width: 50%;"><code>Locale("")</code></td>
+ * <td style="vertical-align: top; width: 50%;"><code>java.properties</code></td>
* </tr>
- * </code></tbody>
+ * </tbody>
* </table>
* </li>
*
@@ -1210,7 +1275,7 @@
* <p><code>getBundle</code> finds
* <code>foo/bar/Messages_fr.properties</code> and creates a
* <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
- * sets up its parent chain from the list of the candiate locales. Only
+ * sets up its parent chain from the list of the candidate locales. Only
* <code>foo/bar/Messages.properties</code> is found in the list and
* <code>getBundle</code> creates a <code>ResourceBundle</code> instance
* that becomes the parent of the instance for
@@ -1248,6 +1313,18 @@
return getBundleImpl(baseName, targetLocale, loader, control);
}
+ private static Control getDefaultControl(String baseName) {
+ if (providers != null) {
+ for (ResourceBundleControlProvider provider : providers) {
+ Control control = provider.getControl(baseName);
+ if (control != null) {
+ return control;
+ }
+ }
+ }
+ return Control.INSTANCE;
+ }
+
private static ResourceBundle getBundleImpl(String baseName, Locale locale,
ClassLoader loader, Control control) {
if (locale == null || control == null) {
@@ -1333,8 +1410,8 @@
* Checks if the given <code>List</code> is not null, not empty,
* not having null in its elements.
*/
- private static final boolean checkList(List a) {
- boolean valid = (a != null && a.size() != 0);
+ private static boolean checkList(List<?> a) {
+ boolean valid = (a != null && !a.isEmpty());
if (valid) {
int size = a.size();
for (int i = 0; valid && i < size; i++) {
@@ -1344,12 +1421,12 @@
return valid;
}
- private static final ResourceBundle findBundle(CacheKey cacheKey,
- List<Locale> candidateLocales,
- List<String> formats,
- int index,
- Control control,
- ResourceBundle baseBundle) {
+ private static ResourceBundle findBundle(CacheKey cacheKey,
+ List<Locale> candidateLocales,
+ List<String> formats,
+ int index,
+ Control control,
+ ResourceBundle baseBundle) {
Locale targetLocale = candidateLocales.get(index);
ResourceBundle parent = null;
if (index != candidateLocales.size() - 1) {
@@ -1421,10 +1498,10 @@
return parent;
}
- private static final ResourceBundle loadBundle(CacheKey cacheKey,
- List<String> formats,
- Control control,
- boolean reload) {
+ private static ResourceBundle loadBundle(CacheKey cacheKey,
+ List<String> formats,
+ Control control,
+ boolean reload) {
// Here we actually load the bundle in the order of formats
// specified by the getFormats() value.
@@ -1461,7 +1538,7 @@
return bundle;
}
- private static final boolean isValidBundle(ResourceBundle bundle) {
+ private static boolean isValidBundle(ResourceBundle bundle) {
return bundle != null && bundle != NONEXISTENT_BUNDLE;
}
@@ -1469,7 +1546,7 @@
* Determines whether any of resource bundles in the parent chain,
* including the leaf, have expired.
*/
- private static final boolean hasValidParentChain(ResourceBundle bundle) {
+ private static boolean hasValidParentChain(ResourceBundle bundle) {
long now = System.currentTimeMillis();
while (bundle != null) {
if (bundle.expired) {
@@ -1490,9 +1567,9 @@
/**
* Throw a MissingResourceException with proper message
*/
- private static final void throwMissingResourceException(String baseName,
- Locale locale,
- Throwable cause) {
+ private static void throwMissingResourceException(String baseName,
+ Locale locale,
+ Throwable cause) {
// If the cause is a MissingResourceException, avoid creating
// a long chain. (6355009)
if (cause instanceof MissingResourceException) {
@@ -1515,8 +1592,8 @@
* cache or its parent has expired. <code>bundle.expire</code> is true
* upon return if the bundle in the cache has expired.
*/
- private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
- Control control) {
+ private static ResourceBundle findBundleInCache(CacheKey cacheKey,
+ Control control) {
BundleReference bundleRef = cacheList.get(cacheKey);
if (bundleRef == null) {
return null;
@@ -1622,9 +1699,9 @@
* the bundle before this call, the one found in the cache is
* returned.
*/
- private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
- ResourceBundle bundle,
- Control control) {
+ private static ResourceBundle putBundleInCache(CacheKey cacheKey,
+ ResourceBundle bundle,
+ Control control) {
setExpirationTime(cacheKey, control);
if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
CacheKey key = (CacheKey) cacheKey.clone();
@@ -1655,7 +1732,7 @@
return bundle;
}
- private static final void setExpirationTime(CacheKey cacheKey, Control control) {
+ private static void setExpirationTime(CacheKey cacheKey, Control control) {
long ttl = control.getTimeToLive(cacheKey.getName(),
cacheKey.getLocale());
if (ttl >= 0) {
@@ -1680,7 +1757,9 @@
*/
@CallerSensitive
public static final void clearCache() {
+ // Android-changed: use of VMStack.getCallingClassLoader()
clearCache(getLoader(VMStack.getCallingClassLoader()));
+ // clearCache(getLoader(Reflection.getCallerClass()));
}
/**
@@ -2160,11 +2239,11 @@
* one by one as below:
*
* <ul>
- * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
- * <li> [<em>L</em>, <em>C</em>]
- * <li> [<em>L</em>]
- * <li> <code>Locale.ROOT</code>
- * </ul>
+ * <li> [<em>L</em>, <em>C</em>, <em>V</em>] </li>
+ * <li> [<em>L</em>, <em>C</em>] </li>
+ * <li> [<em>L</em>] </li>
+ * <li> <code>Locale.ROOT</code> </li>
+ * </ul></li>
*
* <li>For an input <code>Locale</code> with a non-empty script value,
* append candidate <code>Locale</code>s by omitting the final component
@@ -2172,33 +2251,33 @@
* <code>Locale</code> with country and variant restored:
*
* <ul>
- * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
- * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
- * <li> [<em>L</em>, <em>S</em>]
- * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
- * <li> [<em>L</em>, <em>C</em>]
- * <li> [<em>L</em>]
- * <li> <code>Locale.ROOT</code>
- * </ul>
+ * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]</li>
+ * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+ * <li> [<em>L</em>, <em>S</em>]</li>
+ * <li> [<em>L</em>, <em>C</em>, <em>V</em>]</li>
+ * <li> [<em>L</em>, <em>C</em>]</li>
+ * <li> [<em>L</em>]</li>
+ * <li> <code>Locale.ROOT</code></li>
+ * </ul></li>
*
* <li>For an input <code>Locale</code> with a variant value consisting
* of multiple subtags separated by underscore, generate candidate
* <code>Locale</code>s by omitting the variant subtags one by one, then
- * insert them after every occurence of <code> Locale</code>s with the
+ * insert them after every occurrence of <code> Locale</code>s with the
* full variant value in the original list. For example, if the
* the variant consists of two subtags <em>V1</em> and <em>V2</em>:
*
* <ul>
- * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
- * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
- * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
- * <li> [<em>L</em>, <em>S</em>]
- * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
- * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
- * <li> [<em>L</em>, <em>C</em>]
- * <li> [<em>L</em>]
- * <li> <code>Locale.ROOT</code>
- * </ul>
+ * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+ * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]</li>
+ * <li> [<em>L</em>, <em>S</em>, <em>C</em>]</li>
+ * <li> [<em>L</em>, <em>S</em>]</li>
+ * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]</li>
+ * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]</li>
+ * <li> [<em>L</em>, <em>C</em>]</li>
+ * <li> [<em>L</em>]</li>
+ * <li> <code>Locale.ROOT</code></li>
+ * </ul></li>
*
* <li>Special cases for Chinese. When an input <code>Locale</code> has the
* language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
@@ -2209,21 +2288,21 @@
* is empty, no script is supplied. For example, for <code>Locale("zh", "CN")
* </code>, the candidate list will be:
* <ul>
- * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
- * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
- * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
- * <li> [<em>L</em>("zh")]
- * <li> <code>Locale.ROOT</code>
+ * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]</li>
+ * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]</li>
+ * <li> [<em>L</em>("zh"), <em>C</em>("CN")]</li>
+ * <li> [<em>L</em>("zh")]</li>
+ * <li> <code>Locale.ROOT</code></li>
* </ul>
*
* For <code>Locale("zh", "TW")</code>, the candidate list will be:
* <ul>
- * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
- * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
- * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
- * <li> [<em>L</em>("zh")]
- * <li> <code>Locale.ROOT</code>
- * </ul>
+ * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]</li>
+ * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]</li>
+ * <li> [<em>L</em>("zh"), <em>C</em>("TW")]</li>
+ * <li> [<em>L</em>("zh")]</li>
+ * <li> <code>Locale.ROOT</code></li>
+ * </ul></li>
*
* <li>Special cases for Norwegian. Both <code>Locale("no", "NO",
* "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
@@ -2231,10 +2310,10 @@
* list is generated up to [<em>L</em>("nn")], and then the following
* candidates are added:
*
- * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
- * <li> [<em>L</em>("no"), <em>C</em>("NO")]
- * <li> [<em>L</em>("no")]
- * <li> <code>Locale.ROOT</code>
+ * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]</li>
+ * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+ * <li> [<em>L</em>("no")]</li>
+ * <li> <code>Locale.ROOT</code></li>
* </ul>
*
* If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
@@ -2251,20 +2330,18 @@
* candidate list:
*
* <ul>
- * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
- * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
- * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
- * <li> [<em>L</em>("no"), <em>C</em>("NO")]
- * <li> [<em>L</em>("nb")]
- * <li> [<em>L</em>("no")]
- * <li> <code>Locale.ROOT</code>
+ * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+ * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]</li>
+ * <li> [<em>L</em>("nb"), <em>C</em>("NO")]</li>
+ * <li> [<em>L</em>("no"), <em>C</em>("NO")]</li>
+ * <li> [<em>L</em>("nb")]</li>
+ * <li> [<em>L</em>("no")]</li>
+ * <li> <code>Locale.ROOT</code></li>
* </ul>
*
* <code>Locale("no", "NO", "POSIX")</code> would generate the same list
* except that locales with "no" would appear before the corresponding
* locales with "nb".</li>
- *
- * </li>
* </ol>
*
* <p>The default implementation uses an {@link ArrayList} that
@@ -2284,9 +2361,9 @@
* is returned. And if the resource bundles for the "ja" and
* "" <code>Locale</code>s are found, then the runtime resource
* lookup path (parent chain) is:
- * <pre>
+ * <pre>{@code
* Messages_ja -> Messages
- * </pre>
+ * }</pre>
*
* @param baseName
* the base name of the resource bundle, a fully
@@ -2353,18 +2430,27 @@
if (script.length() == 0 && region.length() > 0) {
// Supply script for users who want to use zh_Hans/zh_Hant
// as bundle names (recommended for Java7+)
- if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
+ switch (region) {
+ case "TW":
+ case "HK":
+ case "MO":
script = "Hant";
- } else if (region.equals("CN") || region.equals("SG")) {
+ break;
+ case "CN":
+ case "SG":
script = "Hans";
+ break;
}
} else if (script.length() > 0 && region.length() == 0) {
// Supply region(country) for users who still package Chinese
// bundles using old convension.
- if (script.equals("Hans")) {
+ switch (script) {
+ case "Hans":
region = "CN";
- } else if (script.equals("Hant")) {
+ break;
+ case "Hant":
region = "TW";
+ break;
}
}
}
@@ -2565,6 +2651,7 @@
ResourceBundle bundle = null;
if (format.equals("java.class")) {
try {
+ @SuppressWarnings("unchecked")
Class<? extends ResourceBundle> bundleClass
= (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
@@ -2579,7 +2666,10 @@
} catch (ClassNotFoundException e) {
}
} else if (format.equals("java.properties")) {
- final String resourceName = toResourceName(bundleName, "properties");
+ final String resourceName = toResourceName0(bundleName, "properties");
+ if (resourceName == null) {
+ return bundle;
+ }
final ClassLoader classLoader = loader;
final boolean reloadFlag = reload;
InputStream stream = null;
@@ -2610,8 +2700,10 @@
}
if (stream != null) {
try {
+ // Android-changed: Use UTF-8 for property based resources. b/26879578
bundle = new PropertyResourceBundle(
new InputStreamReader(stream, StandardCharsets.UTF_8));
+ // bundle = new PropertyResourceBundle(stream);
} finally {
stream.close();
}
@@ -2734,7 +2826,10 @@
}
boolean result = false;
try {
- String resourceName = toResourceName(toBundleName(baseName, locale), format);
+ String resourceName = toResourceName0(toBundleName(baseName, locale), format);
+ if (resourceName == null) {
+ return result;
+ }
URL url = loader.getResource(resourceName);
if (url != null) {
long lastModified = 0;
@@ -2780,7 +2875,7 @@
* and <code>variant</code> are the language, script, country, and variant
* values of <code>locale</code>, respectively. Final component values that
* are empty Strings are omitted along with the preceding '_'. When the
- * script is empty, the script value is ommitted along with the preceding '_'.
+ * script is empty, the script value is omitted along with the preceding '_'.
* If all of the values are empty strings, then <code>baseName</code>
* is returned.
*
@@ -2868,6 +2963,15 @@
sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
return sb.toString();
}
+
+ private String toResourceName0(String bundleName, String suffix) {
+ // application protocol check
+ if (bundleName.contains("://")) {
+ return null;
+ } else {
+ return toResourceName(bundleName, suffix);
+ }
+ }
}
private static class SingleFormatControl extends Control {
diff --git a/ojluni/src/main/java/java/util/ServiceLoader.java b/ojluni/src/main/java/java/util/ServiceLoader.java
index 4b3b029..8a0b3a8 100644
--- a/ojluni/src/main/java/java/util/ServiceLoader.java
+++ b/ojluni/src/main/java/java/util/ServiceLoader.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -66,12 +66,13 @@
*
* <p><a name="format"> A service provider is identified by placing a
* <i>provider-configuration file</i> in the resource directory
- * <tt>META-INF/services</tt>. The file's name is the fully-qualified <a
+ * <tt>META-INF/services</tt>.</a> The file's name is the fully-qualified <a
* href="../lang/ClassLoader.html#name">binary name</a> of the service's type.
* The file contains a list of fully-qualified binary names of concrete
* provider classes, one per line. Space and tab characters surrounding each
* name, as well as blank lines, are ignored. The comment character is
- * <tt>'#'</tt> (<tt>'\u0023'</tt>, <font size="-1">NUMBER SIGN</font>); on
+ * <tt>'#'</tt> (<tt>'\u0023'</tt>,
+ * <font style="font-size:smaller;">NUMBER SIGN</font>); on
* each line all characters following the first comment character are ignored.
* The file must be encoded in UTF-8.
*
@@ -186,10 +187,14 @@
private static final String PREFIX = "META-INF/services/";
// The class or interface representing the service being loaded
- private Class<S> service;
+ private final Class<S> service;
// The class loader used to locate, load, and instantiate providers
- private ClassLoader loader;
+ private final ClassLoader loader;
+
+ // The access control context taken when the ServiceLoader is created
+ // Android-changed: do not use legacy security code
+ // private final AccessControlContext acc;
// Cached providers, in instantiation order
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
@@ -214,25 +219,28 @@
}
private ServiceLoader(Class<S> svc, ClassLoader cl) {
- service = svc;
- loader = cl;
+ service = Objects.requireNonNull(svc, "Service interface cannot be null");
+ loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
+ // Android-changed: Do not use legacy security code (System.getSecurtiyManager()
+ // is always null).
+ // acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
reload();
}
- private static void fail(Class service, String msg, Throwable cause)
+ private static void fail(Class<?> service, String msg, Throwable cause)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg,
cause);
}
- private static void fail(Class service, String msg)
+ private static void fail(Class<?> service, String msg)
throws ServiceConfigurationError
{
throw new ServiceConfigurationError(service.getName() + ": " + msg);
}
- private static void fail(Class service, URL u, int line, String msg)
+ private static void fail(Class<?> service, URL u, int line, String msg)
throws ServiceConfigurationError
{
fail(service, u + ":" + line + ": " + msg);
@@ -241,7 +249,7 @@
// Parse a single line from the given configuration file, adding the name
// on the line to the names list.
//
- private int parseLine(Class service, URL u, BufferedReader r, int lc,
+ private int parseLine(Class<?> service, URL u, BufferedReader r, int lc,
List<String> names)
throws IOException, ServiceConfigurationError
{
@@ -287,7 +295,7 @@
// If an I/O error occurs while reading from the given URL, or
// if a configuration-file format error is detected
//
- private Iterator<String> parse(Class service, URL u)
+ private Iterator<String> parse(Class<?> service, URL u)
throws ServiceConfigurationError
{
InputStream in = null;
@@ -328,7 +336,7 @@
this.loader = loader;
}
- public boolean hasNext() {
+ private boolean hasNextService() {
if (nextName != null) {
return true;
}
@@ -353,10 +361,9 @@
return true;
}
- public S next() {
- if (!hasNext()) {
+ private S nextService() {
+ if (!hasNextService())
throw new NoSuchElementException();
- }
String cn = nextName;
nextName = null;
Class<?> c = null;
@@ -364,13 +371,18 @@
c = Class.forName(cn, false, loader);
} catch (ClassNotFoundException x) {
fail(service,
+ // Android-changed: Let the ServiceConfigurationError have a cause.
"Provider " + cn + " not found", x);
+ // "Provider " + cn + " not found");
}
if (!service.isAssignableFrom(c)) {
+ // Android-changed: Let the ServiceConfigurationError have a cause.
ClassCastException cce = new ClassCastException(
service.getCanonicalName() + " is not assignable from " + c.getCanonicalName());
fail(service,
"Provider " + cn + " not a subtype", cce);
+ // fail(service,
+ // "Provider " + cn + " not a subtype");
}
try {
S p = service.cast(c.newInstance());
@@ -378,12 +390,40 @@
return p;
} catch (Throwable x) {
fail(service,
- "Provider " + cn + " could not be instantiated: " + x,
+ "Provider " + cn + " could not be instantiated",
x);
}
throw new Error(); // This cannot happen
}
+ public boolean hasNext() {
+ // Android-changed: do not use legacy security code
+ /* if (acc == null) { */
+ return hasNextService();
+ /*
+ } else {
+ PrivilegedAction<Boolean> action = new PrivilegedAction<Boolean>() {
+ public Boolean run() { return hasNextService(); }
+ };
+ return AccessController.doPrivileged(action, acc);
+ }
+ */
+ }
+
+ public S next() {
+ // Android-changed: do not use legacy security code
+ /* if (acc == null) { */
+ return nextService();
+ /*
+ } else {
+ PrivilegedAction<S> action = new PrivilegedAction<S>() {
+ public S run() { return nextService(); }
+ };
+ return AccessController.doPrivileged(action, acc);
+ }
+ */
+ }
+
public void remove() {
throw new UnsupportedOperationException();
}
@@ -427,6 +467,12 @@
* Invoking its {@link java.util.Iterator#remove() remove} method will
* cause an {@link UnsupportedOperationException} to be thrown.
*
+ * @implNote When adding providers to the cache, the {@link #iterator
+ * Iterator} processes resources in the order that the {@link
+ * java.lang.ClassLoader#getResources(java.lang.String)
+ * ClassLoader.getResources(String)} method finds the service configuration
+ * files.
+ *
* @return An iterator that lazily loads providers for this loader's
* service
*/
@@ -459,6 +505,8 @@
* Creates a new service loader for the given service type and class
* loader.
*
+ * @param <S> the class of the service type
+ *
* @param service
* The interface or abstract class representing the service
*
@@ -492,6 +540,8 @@
* ServiceLoader.load(<i>service</i>,
* Thread.currentThread().getContextClassLoader())</pre></blockquote>
*
+ * @param <S> the class of the service type
+ *
* @param service
* The interface or abstract class representing the service
*
@@ -521,6 +571,8 @@
* have been installed into the current Java virtual machine; providers on
* the application's class path will be ignored.
*
+ * @param <S> the class of the service type
+ *
* @param service
* The interface or abstract class representing the service
*
@@ -536,6 +588,8 @@
return ServiceLoader.load(service, prev);
}
+ // Android-changed BEGIN: Add a method to instantiate a class from a system
+ // property (used in other parts of libcore).
/**
* Internal API to support built-in SPIs that check a system property first.
* Returns an instance specified by a property with the class' binary name, or null if
@@ -554,6 +608,7 @@
throw new Error(e);
}
}
+ // Android-changed END
/**
* Returns a string describing this service.
diff --git a/ojluni/src/main/java/java/util/TimerTask.java b/ojluni/src/main/java/java/util/TimerTask.java
index b8c8340..5750486 100644
--- a/ojluni/src/main/java/java/util/TimerTask.java
+++ b/ojluni/src/main/java/java/util/TimerTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -130,14 +130,14 @@
* <p>This method is typically invoked from within a task's run method, to
* determine whether the current execution of the task is sufficiently
* timely to warrant performing the scheduled activity:
- * <pre>
+ * <pre>{@code
* public void run() {
* if (System.currentTimeMillis() - scheduledExecutionTime() >=
* MAX_TARDINESS)
* return; // Too late; skip this execution.
* // Perform the task
* }
- * </pre>
+ * }</pre>
* This method is typically <i>not</i> used in conjunction with
* <i>fixed-delay execution</i> repeating tasks, as their scheduled
* execution times are allowed to drift over time, and so are not terribly
diff --git a/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java b/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java
new file mode 100644
index 0000000..e731f0f
--- /dev/null
+++ b/ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.util.spi;
+
+import java.util.ResourceBundle;
+
+/**
+ * An interface for service providers that provide implementations of {@link
+ * java.util.ResourceBundle.Control}. The <a
+ * href="../ResourceBundle.html#default_behavior">default resource bundle loading
+ * behavior</a> of the {@code ResourceBundle.getBundle} factory methods that take
+ * no {@link java.util.ResourceBundle.Control} instance can be modified with {@code
+ * ResourceBundleControlProvider} implementations.
+ *
+ * <p>Provider implementations must be packaged using the <a
+ * href="{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/extensions/index.html">Java Extension
+ * Mechanism</a> as installed extensions. Refer to {@link java.util.ServiceLoader}
+ * for the extension packaging. Any installed {@code
+ * ResourceBundleControlProvider} implementations are loaded using {@link
+ * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time.
+ *
+ * @author Masayoshi Okutsu
+ * @since 1.8
+ * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
+ * ResourceBundle.getBundle
+ * @see java.util.ServiceLoader#loadInstalled(Class)
+ */
+public interface ResourceBundleControlProvider {
+ /**
+ * Returns a {@code ResourceBundle.Control} instance that is used
+ * to handle resource bundle loading for the given {@code
+ * baseName}. This method must return {@code null} if the given
+ * {@code baseName} isn't handled by this provider.
+ *
+ * @param baseName the base name of the resource bundle
+ * @return a {@code ResourceBundle.Control} instance,
+ * or {@code null} if the given {@code baseName} is not
+ * applicable to this provider.
+ * @throws NullPointerException if {@code baseName} is {@code null}
+ */
+ public ResourceBundle.Control getControl(String baseName);
+}
diff --git a/ojluni/src/main/java/javax/crypto/CipherOutputStream.java b/ojluni/src/main/java/javax/crypto/CipherOutputStream.java
index 15edd45..6b8d273 100644
--- a/ojluni/src/main/java/javax/crypto/CipherOutputStream.java
+++ b/ojluni/src/main/java/javax/crypto/CipherOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,9 @@
// the buffer holding data ready to be written out
private byte[] obuffer;
+ // stream status
+ private boolean closed = false;
+
/**
*
* Constructs a CipherOutputStream from an OutputStream and a
@@ -198,11 +201,14 @@
* @since JCE1.2
*/
public void close() throws IOException {
+ if (closed) {
+ return;
+ }
+
+ closed = true;
try {
obuffer = cipher.doFinal();
- } catch (IllegalBlockSizeException e) {
- obuffer = null;
- } catch (BadPaddingException e) {
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
obuffer = null;
}
try {
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLContext.java b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
index 7e615b8..fa8a3af 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLContext.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLContext.java
@@ -50,13 +50,13 @@
* <td>Default</td>
* <td>10+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL</td>
- * <td>10+</td>
+ * <td>10–TBD</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSLv3</td>
- * <td>10+</td>
+ * <td>10–TBD</td>
* </tr>
* <tr>
* <td>TLS</td>
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLEngine.java b/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
index f460d5f..c4b3df0 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLEngine.java
@@ -380,9 +380,9 @@
* </tr>
* </thead>
* <tbody>
- * <tr>
+ * <tr class="deprecated">
* <td>SSLv3</td>
- * <td>1+</td>
+ * <td>1–TBD</td>
* <td>1–22</td>
* </tr>
* <tr>
@@ -498,14 +498,14 @@
* <td>9–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
- * <td>9+</td>
+ * <td>9–TBD</td>
* <td>9–19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_RC4_128_SHA</td>
- * <td>9+</td>
+ * <td>9–TBD</td>
* <td>9–23</td>
* </tr>
* <tr class="deprecated">
@@ -718,9 +718,9 @@
* <td>20–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>20–TBD</td>
* <td>20–23</td>
* </tr>
* <tr>
@@ -783,9 +783,9 @@
* <td>20–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_RC4_128_SHA</td>
- * <td>20+</td>
+ * <td>20–TBD</td>
* <td>20–23</td>
* </tr>
* <tr class="deprecated">
@@ -933,9 +933,9 @@
* <td>21+</td>
* <td>21+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_PSK_WITH_RC4_128_SHA</td>
- * <td>21+</td>
+ * <td>21–TBD</td>
* <td></td>
* </tr>
* <tr class="deprecated">
diff --git a/ojluni/src/main/java/javax/net/ssl/SSLSocket.java b/ojluni/src/main/java/javax/net/ssl/SSLSocket.java
index 7203166..093f2d9 100644
--- a/ojluni/src/main/java/javax/net/ssl/SSLSocket.java
+++ b/ojluni/src/main/java/javax/net/ssl/SSLSocket.java
@@ -155,10 +155,10 @@
* </tr>
* </thead>
* <tbody>
- * <tr>
+ * <tr class="deprecated">
* <td>SSLv3</td>
- * <td>1+</td>
- * <td>1+</td>
+ * <td>1–TBD</td>
+ * <td>1–22</td>
* </tr>
* <tr>
* <td>TLSv1</td>
@@ -188,9 +188,9 @@
* </tr>
* </thead>
* <tbody>
- * <tr>
+ * <tr class="deprecated">
* <td>SSLv3</td>
- * <td>1+</td>
+ * <td>1–TBD</td>
* <td>1–22</td>
* </tr>
* <tr>
@@ -313,14 +313,14 @@
* <td>9–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
- * <td>9+</td>
+ * <td>9–TBD</td>
* <td>9–19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>SSL_RSA_WITH_RC4_128_SHA</td>
- * <td>9+</td>
+ * <td>9–TBD</td>
* <td>9–23</td>
* </tr>
* <tr class="deprecated">
@@ -458,9 +458,9 @@
* <td>11–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_ECDSA_WITH_RC4_128_SHA</td>
- * <td>11+</td>
+ * <td>11–TBD</td>
* <td>11–23</td>
* </tr>
* <tr>
@@ -518,9 +518,9 @@
* <td>11–22</td>
* <td></td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_ECDHE_RSA_WITH_RC4_128_SHA</td>
- * <td>11+</td>
+ * <td>11–TBD</td>
* <td>11–23</td>
* </tr>
* <tr class="deprecated">
@@ -663,9 +663,9 @@
* <td>21+</td>
* <td>21+</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>TLS_PSK_WITH_RC4_128_SHA</td>
- * <td>21+</td>
+ * <td>21–TBD</td>
* <td></td>
* </tr>
* <tr>
@@ -848,16 +848,16 @@
* <td>1–8</td>
* <td>1–8</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>RC4-MD5</td>
* <td>SSL_RSA_WITH_RC4_128_MD5</td>
- * <td>1+</td>
+ * <td>1–TBD</td>
* <td>1–19</td>
* </tr>
- * <tr>
+ * <tr class="deprecated">
* <td>RC4-SHA</td>
* <td>SSL_RSA_WITH_RC4_128_SHA</td>
- * <td>1+</td>
+ * <td>1–TBD</td>
* <td>1–23</td>
* </tr>
* </tbody>
diff --git a/ojluni/src/main/java/javax/security/auth/Subject.java b/ojluni/src/main/java/javax/security/auth/Subject.java
index 56e864c..2c9e8b8 100644
--- a/ojluni/src/main/java/javax/security/auth/Subject.java
+++ b/ojluni/src/main/java/javax/security/auth/Subject.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,39 +42,39 @@
import sun.security.util.ResourcesMgr;
/**
- * <p> A <code>Subject</code> represents a grouping of related information
+ * <p> A {@code Subject} represents a grouping of related information
* for a single entity, such as a person.
* Such information includes the Subject's identities as well as
* its security-related attributes
* (passwords and cryptographic keys, for example).
*
* <p> Subjects may potentially have multiple identities.
- * Each identity is represented as a <code>Principal</code>
- * within the <code>Subject</code>. Principals simply bind names to a
- * <code>Subject</code>. For example, a <code>Subject</code> that happens
+ * Each identity is represented as a {@code Principal}
+ * within the {@code Subject}. Principals simply bind names to a
+ * {@code Subject}. For example, a {@code Subject} that happens
* to be a person, Alice, might have two Principals:
* one which binds "Alice Bar", the name on her driver license,
- * to the <code>Subject</code>, and another which binds,
+ * to the {@code Subject}, and another which binds,
* "999-99-9999", the number on her student identification card,
- * to the <code>Subject</code>. Both Principals refer to the same
- * <code>Subject</code> even though each has a different name.
+ * to the {@code Subject}. Both Principals refer to the same
+ * {@code Subject} even though each has a different name.
*
- * <p> A <code>Subject</code> may also own security-related attributes,
+ * <p> A {@code Subject} may also own security-related attributes,
* which are referred to as credentials.
* Sensitive credentials that require special protection, such as
* private cryptographic keys, are stored within a private credential
- * <code>Set</code>. Credentials intended to be shared, such as
+ * {@code Set}. Credentials intended to be shared, such as
* public key certificates or Kerberos server tickets are stored
- * within a public credential <code>Set</code>. Different permissions
+ * within a public credential {@code Set}. Different permissions
* are required to access and modify the different credential Sets.
*
- * <p> To retrieve all the Principals associated with a <code>Subject</code>,
- * invoke the <code>getPrincipals</code> method. To retrieve
- * all the public or private credentials belonging to a <code>Subject</code>,
- * invoke the <code>getPublicCredentials</code> method or
- * <code>getPrivateCredentials</code> method, respectively.
- * To modify the returned <code>Set</code> of Principals and credentials,
- * use the methods defined in the <code>Set</code> class.
+ * <p> To retrieve all the Principals associated with a {@code Subject},
+ * invoke the {@code getPrincipals} method. To retrieve
+ * all the public or private credentials belonging to a {@code Subject},
+ * invoke the {@code getPublicCredentials} method or
+ * {@code getPrivateCredentials} method, respectively.
+ * To modify the returned {@code Set} of Principals and credentials,
+ * use the methods defined in the {@code Set} class.
* For example:
* <pre>
* Subject subject;
@@ -86,13 +86,13 @@
* subject.getPublicCredentials().add(credential);
* </pre>
*
- * <p> This <code>Subject</code> class implements <code>Serializable</code>.
- * While the Principals associated with the <code>Subject</code> are serialized,
- * the credentials associated with the <code>Subject</code> are not.
- * Note that the <code>java.security.Principal</code> class
- * does not implement <code>Serializable</code>. Therefore all concrete
- * <code>Principal</code> implementations associated with Subjects
- * must implement <code>Serializable</code>.
+ * <p> This {@code Subject} class implements {@code Serializable}.
+ * While the Principals associated with the {@code Subject} are serialized,
+ * the credentials associated with the {@code Subject} are not.
+ * Note that the {@code java.security.Principal} class
+ * does not implement {@code Serializable}. Therefore all concrete
+ * {@code Principal} implementations associated with Subjects
+ * must implement {@code Serializable}.
*
* @see java.security.Principal
* @see java.security.DomainCombiner
@@ -102,14 +102,14 @@
private static final long serialVersionUID = -8308522755600156056L;
/**
- * A <code>Set</code> that provides a view of all of this
+ * A {@code Set} that provides a view of all of this
* Subject's Principals
*
* <p>
*
* @serial Each element in this set is a
- * <code>java.security.Principal</code>.
- * The set is a <code>Subject.SecureSet</code>.
+ * {@code java.security.Principal}.
+ * The set is a {@code Subject.SecureSet}.
*/
Set<Principal> principals;
@@ -135,21 +135,21 @@
= new ProtectionDomain[0];
/**
- * Create an instance of a <code>Subject</code>
- * with an empty <code>Set</code> of Principals and empty
+ * Create an instance of a {@code Subject}
+ * with an empty {@code Set} of Principals and empty
* Sets of public and private credentials.
*
- * <p> The newly constructed Sets check whether this <code>Subject</code>
+ * <p> The newly constructed Sets check whether this {@code Subject}
* has been set read-only before permitting subsequent modifications.
* The newly created Sets also prevent illegal modifications
* by ensuring that callers have sufficient permissions.
*
* <p> To modify the Principals Set, the caller must have
- * <code>AuthPermission("modifyPrincipals")</code>.
+ * {@code AuthPermission("modifyPrincipals")}.
* To modify the public credential Set, the caller must have
- * <code>AuthPermission("modifyPublicCredentials")</code>.
+ * {@code AuthPermission("modifyPublicCredentials")}.
* To modify the private credential Set, the caller must have
- * <code>AuthPermission("modifyPrivateCredentials")</code>.
+ * {@code AuthPermission("modifyPrivateCredentials")}.
*/
public Subject() {
@@ -162,39 +162,39 @@
}
/**
- * Create an instance of a <code>Subject</code> with
+ * Create an instance of a {@code Subject} with
* Principals and credentials.
*
* <p> The Principals and credentials from the specified Sets
* are copied into newly constructed Sets.
- * These newly created Sets check whether this <code>Subject</code>
+ * These newly created Sets check whether this {@code Subject}
* has been set read-only before permitting subsequent modifications.
* The newly created Sets also prevent illegal modifications
* by ensuring that callers have sufficient permissions.
*
* <p> To modify the Principals Set, the caller must have
- * <code>AuthPermission("modifyPrincipals")</code>.
+ * {@code AuthPermission("modifyPrincipals")}.
* To modify the public credential Set, the caller must have
- * <code>AuthPermission("modifyPublicCredentials")</code>.
+ * {@code AuthPermission("modifyPublicCredentials")}.
* To modify the private credential Set, the caller must have
- * <code>AuthPermission("modifyPrivateCredentials")</code>.
+ * {@code AuthPermission("modifyPrivateCredentials")}.
* <p>
*
- * @param readOnly true if the <code>Subject</code> is to be read-only,
+ * @param readOnly true if the {@code Subject} is to be read-only,
* and false otherwise. <p>
*
- * @param principals the <code>Set</code> of Principals
- * to be associated with this <code>Subject</code>. <p>
+ * @param principals the {@code Set} of Principals
+ * to be associated with this {@code Subject}. <p>
*
- * @param pubCredentials the <code>Set</code> of public credentials
- * to be associated with this <code>Subject</code>. <p>
+ * @param pubCredentials the {@code Set} of public credentials
+ * to be associated with this {@code Subject}. <p>
*
- * @param privCredentials the <code>Set</code> of private credentials
- * to be associated with this <code>Subject</code>.
+ * @param privCredentials the {@code Set} of private credentials
+ * to be associated with this {@code Subject}.
*
* @exception NullPointerException if the specified
- * <code>principals</code>, <code>pubCredentials</code>,
- * or <code>privCredentials</code> are <code>null</code>.
+ * {@code principals}, {@code pubCredentials},
+ * or {@code privCredentials} are {@code null}.
*/
public Subject(boolean readOnly, Set<? extends Principal> principals,
Set<?> pubCredentials, Set<?> privCredentials)
@@ -216,24 +216,24 @@
}
/**
- * Set this <code>Subject</code> to be read-only.
+ * Set this {@code Subject} to be read-only.
*
* <p> Modifications (additions and removals) to this Subject's
- * <code>Principal</code> <code>Set</code> and
+ * {@code Principal} {@code Set} and
* credential Sets will be disallowed.
- * The <code>destroy</code> operation on this Subject's credentials will
+ * The {@code destroy} operation on this Subject's credentials will
* still be permitted.
*
- * <p> Subsequent attempts to modify the Subject's <code>Principal</code>
+ * <p> Subsequent attempts to modify the Subject's {@code Principal}
* and credential Sets will result in an
- * <code>IllegalStateException</code> being thrown.
- * Also, once a <code>Subject</code> is read-only,
+ * {@code IllegalStateException} being thrown.
+ * Also, once a {@code Subject} is read-only,
* it can not be reset to being writable again.
*
* <p>
*
* @exception SecurityException if the caller does not have permission
- * to set this <code>Subject</code> to be read-only.
+ * to set this {@code Subject} to be read-only.
*/
public void setReadOnly() {
java.lang.SecurityManager sm = System.getSecurityManager();
@@ -245,40 +245,40 @@
}
/**
- * Query whether this <code>Subject</code> is read-only.
+ * Query whether this {@code Subject} is read-only.
*
* <p>
*
- * @return true if this <code>Subject</code> is read-only, false otherwise.
+ * @return true if this {@code Subject} is read-only, false otherwise.
*/
public boolean isReadOnly() {
return this.readOnly;
}
/**
- * Get the <code>Subject</code> associated with the provided
- * <code>AccessControlContext</code>.
+ * Get the {@code Subject} associated with the provided
+ * {@code AccessControlContext}.
*
- * <p> The <code>AccessControlContext</code> may contain many
- * Subjects (from nested <code>doAs</code> calls).
- * In this situation, the most recent <code>Subject</code> associated
- * with the <code>AccessControlContext</code> is returned.
+ * <p> The {@code AccessControlContext} may contain many
+ * Subjects (from nested {@code doAs} calls).
+ * In this situation, the most recent {@code Subject} associated
+ * with the {@code AccessControlContext} is returned.
*
* <p>
*
- * @param acc the <code>AccessControlContext</code> from which to retrieve
- * the <code>Subject</code>.
+ * @param acc the {@code AccessControlContext} from which to retrieve
+ * the {@code Subject}.
*
- * @return the <code>Subject</code> associated with the provided
- * <code>AccessControlContext</code>, or <code>null</code>
- * if no <code>Subject</code> is associated
- * with the provided <code>AccessControlContext</code>.
+ * @return the {@code Subject} associated with the provided
+ * {@code AccessControlContext}, or {@code null}
+ * if no {@code Subject} is associated
+ * with the provided {@code AccessControlContext}.
*
* @exception SecurityException if the caller does not have permission
- * to get the <code>Subject</code>. <p>
+ * to get the {@code Subject}. <p>
*
* @exception NullPointerException if the provided
- * <code>AccessControlContext</code> is <code>null</code>.
+ * {@code AccessControlContext} is {@code null}.
*/
public static Subject getSubject(final AccessControlContext acc) {
@@ -306,33 +306,36 @@
}
/**
- * Perform work as a particular <code>Subject</code>.
+ * Perform work as a particular {@code Subject}.
*
* <p> This method first retrieves the current Thread's
- * <code>AccessControlContext</code> via
- * <code>AccessController.getContext</code>,
- * and then instantiates a new <code>AccessControlContext</code>
+ * {@code AccessControlContext} via
+ * {@code AccessController.getContext},
+ * and then instantiates a new {@code AccessControlContext}
* using the retrieved context along with a new
- * <code>SubjectDomainCombiner</code> (constructed using
- * the provided <code>Subject</code>).
- * Finally, this method invokes <code>AccessController.doPrivileged</code>,
- * passing it the provided <code>PrivilegedAction</code>,
- * as well as the newly constructed <code>AccessControlContext</code>.
+ * {@code SubjectDomainCombiner} (constructed using
+ * the provided {@code Subject}).
+ * Finally, this method invokes {@code AccessController.doPrivileged},
+ * passing it the provided {@code PrivilegedAction},
+ * as well as the newly constructed {@code AccessControlContext}.
*
* <p>
*
- * @param subject the <code>Subject</code> that the specified
- * <code>action</code> will run as. This parameter
- * may be <code>null</code>. <p>
+ * @param subject the {@code Subject} that the specified
+ * {@code action} will run as. This parameter
+ * may be {@code null}. <p>
+ *
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
*
* @param action the code to be run as the specified
- * <code>Subject</code>. <p>
+ * {@code Subject}. <p>
*
* @return the value returned by the PrivilegedAction's
- * <code>run</code> method.
+ * {@code run} method.
*
- * @exception NullPointerException if the <code>PrivilegedAction</code>
- * is <code>null</code>. <p>
+ * @exception NullPointerException if the {@code PrivilegedAction}
+ * is {@code null}. <p>
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
@@ -359,38 +362,41 @@
}
/**
- * Perform work as a particular <code>Subject</code>.
+ * Perform work as a particular {@code Subject}.
*
* <p> This method first retrieves the current Thread's
- * <code>AccessControlContext</code> via
- * <code>AccessController.getContext</code>,
- * and then instantiates a new <code>AccessControlContext</code>
+ * {@code AccessControlContext} via
+ * {@code AccessController.getContext},
+ * and then instantiates a new {@code AccessControlContext}
* using the retrieved context along with a new
- * <code>SubjectDomainCombiner</code> (constructed using
- * the provided <code>Subject</code>).
- * Finally, this method invokes <code>AccessController.doPrivileged</code>,
- * passing it the provided <code>PrivilegedExceptionAction</code>,
- * as well as the newly constructed <code>AccessControlContext</code>.
+ * {@code SubjectDomainCombiner} (constructed using
+ * the provided {@code Subject}).
+ * Finally, this method invokes {@code AccessController.doPrivileged},
+ * passing it the provided {@code PrivilegedExceptionAction},
+ * as well as the newly constructed {@code AccessControlContext}.
*
* <p>
*
- * @param subject the <code>Subject</code> that the specified
- * <code>action</code> will run as. This parameter
- * may be <code>null</code>. <p>
+ * @param subject the {@code Subject} that the specified
+ * {@code action} will run as. This parameter
+ * may be {@code null}. <p>
+ *
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
*
* @param action the code to be run as the specified
- * <code>Subject</code>. <p>
+ * {@code Subject}. <p>
*
* @return the value returned by the
- * PrivilegedExceptionAction's <code>run</code> method.
+ * PrivilegedExceptionAction's {@code run} method.
*
* @exception PrivilegedActionException if the
- * <code>PrivilegedExceptionAction.run</code>
+ * {@code PrivilegedExceptionAction.run}
* method throws a checked exception. <p>
*
* @exception NullPointerException if the specified
- * <code>PrivilegedExceptionAction</code> is
- * <code>null</code>. <p>
+ * {@code PrivilegedExceptionAction} is
+ * {@code null}. <p>
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
@@ -418,33 +424,36 @@
}
/**
- * Perform privileged work as a particular <code>Subject</code>.
+ * Perform privileged work as a particular {@code Subject}.
*
- * <p> This method behaves exactly as <code>Subject.doAs</code>,
+ * <p> This method behaves exactly as {@code Subject.doAs},
* except that instead of retrieving the current Thread's
- * <code>AccessControlContext</code>, it uses the provided
- * <code>AccessControlContext</code>. If the provided
- * <code>AccessControlContext</code> is <code>null</code>,
- * this method instantiates a new <code>AccessControlContext</code>
+ * {@code AccessControlContext}, it uses the provided
+ * {@code AccessControlContext}. If the provided
+ * {@code AccessControlContext} is {@code null},
+ * this method instantiates a new {@code AccessControlContext}
* with an empty collection of ProtectionDomains.
*
* <p>
*
- * @param subject the <code>Subject</code> that the specified
- * <code>action</code> will run as. This parameter
- * may be <code>null</code>. <p>
+ * @param subject the {@code Subject} that the specified
+ * {@code action} will run as. This parameter
+ * may be {@code null}. <p>
+ *
+ * @param <T> the type of the value returned by the PrivilegedAction's
+ * {@code run} method.
*
* @param action the code to be run as the specified
- * <code>Subject</code>. <p>
+ * {@code Subject}. <p>
*
- * @param acc the <code>AccessControlContext</code> to be tied to the
+ * @param acc the {@code AccessControlContext} to be tied to the
* specified <i>subject</i> and <i>action</i>. <p>
*
* @return the value returned by the PrivilegedAction's
- * <code>run</code> method.
+ * {@code run} method.
*
- * @exception NullPointerException if the <code>PrivilegedAction</code>
- * is <code>null</code>. <p>
+ * @exception NullPointerException if the {@code PrivilegedAction}
+ * is {@code null}. <p>
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
@@ -476,38 +485,41 @@
}
/**
- * Perform privileged work as a particular <code>Subject</code>.
+ * Perform privileged work as a particular {@code Subject}.
*
- * <p> This method behaves exactly as <code>Subject.doAs</code>,
+ * <p> This method behaves exactly as {@code Subject.doAs},
* except that instead of retrieving the current Thread's
- * <code>AccessControlContext</code>, it uses the provided
- * <code>AccessControlContext</code>. If the provided
- * <code>AccessControlContext</code> is <code>null</code>,
- * this method instantiates a new <code>AccessControlContext</code>
+ * {@code AccessControlContext}, it uses the provided
+ * {@code AccessControlContext}. If the provided
+ * {@code AccessControlContext} is {@code null},
+ * this method instantiates a new {@code AccessControlContext}
* with an empty collection of ProtectionDomains.
*
* <p>
*
- * @param subject the <code>Subject</code> that the specified
- * <code>action</code> will run as. This parameter
- * may be <code>null</code>. <p>
+ * @param subject the {@code Subject} that the specified
+ * {@code action} will run as. This parameter
+ * may be {@code null}. <p>
+ *
+ * @param <T> the type of the value returned by the
+ * PrivilegedExceptionAction's {@code run} method.
*
* @param action the code to be run as the specified
- * <code>Subject</code>. <p>
+ * {@code Subject}. <p>
*
- * @param acc the <code>AccessControlContext</code> to be tied to the
+ * @param acc the {@code AccessControlContext} to be tied to the
* specified <i>subject</i> and <i>action</i>. <p>
*
* @return the value returned by the
- * PrivilegedExceptionAction's <code>run</code> method.
+ * PrivilegedExceptionAction's {@code run} method.
*
* @exception PrivilegedActionException if the
- * <code>PrivilegedExceptionAction.run</code>
+ * {@code PrivilegedExceptionAction.run}
* method throws a checked exception. <p>
*
* @exception NullPointerException if the specified
- * <code>PrivilegedExceptionAction</code> is
- * <code>null</code>. <p>
+ * {@code PrivilegedExceptionAction} is
+ * {@code null}. <p>
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
@@ -556,19 +568,19 @@
}
/**
- * Return the <code>Set</code> of Principals associated with this
- * <code>Subject</code>. Each <code>Principal</code> represents
- * an identity for this <code>Subject</code>.
+ * Return the {@code Set} of Principals associated with this
+ * {@code Subject}. Each {@code Principal} represents
+ * an identity for this {@code Subject}.
*
- * <p> The returned <code>Set</code> is backed by this Subject's
- * internal <code>Principal</code> <code>Set</code>. Any modification
- * to the returned <code>Set</code> affects the internal
- * <code>Principal</code> <code>Set</code> as well.
+ * <p> The returned {@code Set} is backed by this Subject's
+ * internal {@code Principal} {@code Set}. Any modification
+ * to the returned {@code Set} affects the internal
+ * {@code Principal} {@code Set} as well.
*
* <p>
*
- * @return The <code>Set</code> of Principals associated with this
- * <code>Subject</code>.
+ * @return The {@code Set} of Principals associated with this
+ * {@code Subject}.
*/
public Set<Principal> getPrincipals() {
@@ -578,26 +590,28 @@
}
/**
- * Return a <code>Set</code> of Principals associated with this
- * <code>Subject</code> that are instances or subclasses of the specified
- * <code>Class</code>.
+ * Return a {@code Set} of Principals associated with this
+ * {@code Subject} that are instances or subclasses of the specified
+ * {@code Class}.
*
- * <p> The returned <code>Set</code> is not backed by this Subject's
- * internal <code>Principal</code> <code>Set</code>. A new
- * <code>Set</code> is created and returned for each method invocation.
- * Modifications to the returned <code>Set</code>
- * will not affect the internal <code>Principal</code> <code>Set</code>.
+ * <p> The returned {@code Set} is not backed by this Subject's
+ * internal {@code Principal} {@code Set}. A new
+ * {@code Set} is created and returned for each method invocation.
+ * Modifications to the returned {@code Set}
+ * will not affect the internal {@code Principal} {@code Set}.
*
* <p>
*
- * @param c the returned <code>Set</code> of Principals will all be
+ * @param <T> the type of the class modeled by {@code c}
+ *
+ * @param c the returned {@code Set} of Principals will all be
* instances of this class.
*
- * @return a <code>Set</code> of Principals that are instances of the
- * specified <code>Class</code>.
+ * @return a {@code Set} of Principals that are instances of the
+ * specified {@code Class}.
*
- * @exception NullPointerException if the specified <code>Class</code>
- * is <code>null</code>.
+ * @exception NullPointerException if the specified {@code Class}
+ * is {@code null}.
*/
public <T extends Principal> Set<T> getPrincipals(Class<T> c) {
@@ -611,18 +625,18 @@
}
/**
- * Return the <code>Set</code> of public credentials held by this
- * <code>Subject</code>.
+ * Return the {@code Set} of public credentials held by this
+ * {@code Subject}.
*
- * <p> The returned <code>Set</code> is backed by this Subject's
- * internal public Credential <code>Set</code>. Any modification
- * to the returned <code>Set</code> affects the internal public
- * Credential <code>Set</code> as well.
+ * <p> The returned {@code Set} is backed by this Subject's
+ * internal public Credential {@code Set}. Any modification
+ * to the returned {@code Set} affects the internal public
+ * Credential {@code Set} as well.
*
* <p>
*
- * @return A <code>Set</code> of public credentials held by this
- * <code>Subject</code>.
+ * @return A {@code Set} of public credentials held by this
+ * {@code Subject}.
*/
public Set<Object> getPublicCredentials() {
@@ -632,29 +646,29 @@
}
/**
- * Return the <code>Set</code> of private credentials held by this
- * <code>Subject</code>.
+ * Return the {@code Set} of private credentials held by this
+ * {@code Subject}.
*
- * <p> The returned <code>Set</code> is backed by this Subject's
- * internal private Credential <code>Set</code>. Any modification
- * to the returned <code>Set</code> affects the internal private
- * Credential <code>Set</code> as well.
+ * <p> The returned {@code Set} is backed by this Subject's
+ * internal private Credential {@code Set}. Any modification
+ * to the returned {@code Set} affects the internal private
+ * Credential {@code Set} as well.
*
* <p> A caller requires permissions to access the Credentials
- * in the returned <code>Set</code>, or to modify the
- * <code>Set</code> itself. A <code>SecurityException</code>
+ * in the returned {@code Set}, or to modify the
+ * {@code Set} itself. A {@code SecurityException}
* is thrown if the caller does not have the proper permissions.
*
- * <p> While iterating through the <code>Set</code>,
- * a <code>SecurityException</code> is thrown
+ * <p> While iterating through the {@code Set},
+ * a {@code SecurityException} is thrown
* if the caller does not have permission to access a
- * particular Credential. The <code>Iterator</code>
- * is nevertheless advanced to next element in the <code>Set</code>.
+ * particular Credential. The {@code Iterator}
+ * is nevertheless advanced to next element in the {@code Set}.
*
* <p>
*
- * @return A <code>Set</code> of private credentials held by this
- * <code>Subject</code>.
+ * @return A {@code Set} of private credentials held by this
+ * {@code Subject}.
*/
public Set<Object> getPrivateCredentials() {
@@ -672,26 +686,28 @@
}
/**
- * Return a <code>Set</code> of public credentials associated with this
- * <code>Subject</code> that are instances or subclasses of the specified
- * <code>Class</code>.
+ * Return a {@code Set} of public credentials associated with this
+ * {@code Subject} that are instances or subclasses of the specified
+ * {@code Class}.
*
- * <p> The returned <code>Set</code> is not backed by this Subject's
- * internal public Credential <code>Set</code>. A new
- * <code>Set</code> is created and returned for each method invocation.
- * Modifications to the returned <code>Set</code>
- * will not affect the internal public Credential <code>Set</code>.
+ * <p> The returned {@code Set} is not backed by this Subject's
+ * internal public Credential {@code Set}. A new
+ * {@code Set} is created and returned for each method invocation.
+ * Modifications to the returned {@code Set}
+ * will not affect the internal public Credential {@code Set}.
*
* <p>
*
- * @param c the returned <code>Set</code> of public credentials will all be
+ * @param <T> the type of the class modeled by {@code c}
+ *
+ * @param c the returned {@code Set} of public credentials will all be
* instances of this class.
*
- * @return a <code>Set</code> of public credentials that are instances
- * of the specified <code>Class</code>.
+ * @return a {@code Set} of public credentials that are instances
+ * of the specified {@code Class}.
*
- * @exception NullPointerException if the specified <code>Class</code>
- * is <code>null</code>.
+ * @exception NullPointerException if the specified {@code Class}
+ * is {@code null}.
*/
public <T> Set<T> getPublicCredentials(Class<T> c) {
@@ -705,30 +721,32 @@
}
/**
- * Return a <code>Set</code> of private credentials associated with this
- * <code>Subject</code> that are instances or subclasses of the specified
- * <code>Class</code>.
+ * Return a {@code Set} of private credentials associated with this
+ * {@code Subject} that are instances or subclasses of the specified
+ * {@code Class}.
*
* <p> The caller must have permission to access all of the
- * requested Credentials, or a <code>SecurityException</code>
+ * requested Credentials, or a {@code SecurityException}
* will be thrown.
*
- * <p> The returned <code>Set</code> is not backed by this Subject's
- * internal private Credential <code>Set</code>. A new
- * <code>Set</code> is created and returned for each method invocation.
- * Modifications to the returned <code>Set</code>
- * will not affect the internal private Credential <code>Set</code>.
+ * <p> The returned {@code Set} is not backed by this Subject's
+ * internal private Credential {@code Set}. A new
+ * {@code Set} is created and returned for each method invocation.
+ * Modifications to the returned {@code Set}
+ * will not affect the internal private Credential {@code Set}.
*
* <p>
*
- * @param c the returned <code>Set</code> of private credentials will all be
+ * @param <T> the type of the class modeled by {@code c}
+ *
+ * @param c the returned {@code Set} of private credentials will all be
* instances of this class.
*
- * @return a <code>Set</code> of private credentials that are instances
- * of the specified <code>Class</code>.
+ * @return a {@code Set} of private credentials that are instances
+ * of the specified {@code Class}.
*
- * @exception NullPointerException if the specified <code>Class</code>
- * is <code>null</code>.
+ * @exception NullPointerException if the specified {@code Class}
+ * is {@code null}.
*/
public <T> Set<T> getPrivateCredentials(Class<T> c) {
@@ -750,25 +768,25 @@
}
/**
- * Compares the specified Object with this <code>Subject</code>
+ * Compares the specified Object with this {@code Subject}
* for equality. Returns true if the given object is also a Subject
- * and the two <code>Subject</code> instances are equivalent.
- * More formally, two <code>Subject</code> instances are
- * equal if their <code>Principal</code> and <code>Credential</code>
+ * and the two {@code Subject} instances are equivalent.
+ * More formally, two {@code Subject} instances are
+ * equal if their {@code Principal} and {@code Credential}
* Sets are equal.
*
* <p>
*
* @param o Object to be compared for equality with this
- * <code>Subject</code>.
+ * {@code Subject}.
*
* @return true if the specified Object is equal to this
- * <code>Subject</code>.
+ * {@code Subject}.
*
* @exception SecurityException if the caller does not have permission
- * to access the private credentials for this <code>Subject</code>,
+ * to access the private credentials for this {@code Subject},
* or if the caller does not have permission to access the
- * private credentials for the provided <code>Subject</code>.
+ * private credentials for the provided {@code Subject}.
*/
public boolean equals(Object o) {
@@ -815,11 +833,11 @@
}
/**
- * Return the String representation of this <code>Subject</code>.
+ * Return the String representation of this {@code Subject}.
*
* <p>
*
- * @return the String representation of this <code>Subject</code>.
+ * @return the String representation of this {@code Subject}.
*/
public String toString() {
return toString(true);
@@ -876,11 +894,11 @@
}
/**
- * Returns a hashcode for this <code>Subject</code>.
+ * Returns a hashcode for this {@code Subject}.
*
* <p>
*
- * @return a hashcode for this <code>Subject</code>.
+ * @return a hashcode for this {@code Subject}.
*
* @exception SecurityException if the caller does not have permission
* to access this Subject's private credentials.
@@ -892,10 +910,10 @@
* hashcodes of this Subject's Principals and credentials.
*
* If a particular credential was destroyed
- * (<code>credential.hashCode()</code> throws an
- * <code>IllegalStateException</code>),
+ * ({@code credential.hashCode()} throws an
+ * {@code IllegalStateException}),
* the hashcode for that credential is derived via:
- * <code>credential.getClass().toString().hashCode()</code>.
+ * {@code credential.getClass().toString().hashCode()}.
*/
int hashCode = 0;
@@ -941,12 +959,32 @@
/**
* Reads this object from a stream (i.e., deserializes it)
*/
+ @SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
+ ObjectInputStream.GetField gf = s.readFields();
- // The Credential <code>Set</code> is not serialized, but we do not
+ readOnly = gf.get("readOnly", false);
+
+ Set<Principal> inputPrincs = (Set<Principal>)gf.get("principals", null);
+
+ // Rewrap the principals into a SecureSet
+ if (inputPrincs == null) {
+ throw new NullPointerException
+ (ResourcesMgr.getString("invalid.null.input.s."));
+ }
+ try {
+ principals = Collections.synchronizedSet(new SecureSet<Principal>
+ (this, PRINCIPAL_SET, inputPrincs));
+ } catch (NullPointerException npe) {
+ // Sometimes people deserialize the principals set only.
+ // Subject is not accessible, so just don't fail.
+ principals = Collections.synchronizedSet
+ (new SecureSet<Principal>(this, PRINCIPAL_SET));
+ }
+
+ // The Credential {@code Set} is not serialized, but we do not
// want the default deserialization routine to set it to null.
this.pubCredentials = Collections.synchronizedSet
(new SecureSet<Object>(this, PUB_CREDENTIAL_SET));
@@ -980,13 +1018,13 @@
/**
* @serial An integer identifying the type of objects contained
- * in this set. If <code>which == 1</code>,
+ * in this set. If {@code which == 1},
* this is a Principal set and all the elements are
- * of type <code>java.security.Principal</code>.
- * If <code>which == 2</code>, this is a public credential
- * set and all the elements are of type <code>Object</code>.
- * If <code>which == 3</code>, this is a private credential
- * set and all the elements are of type <code>Object</code>.
+ * of type {@code java.security.Principal}.
+ * If {@code which == 2}, this is a public credential
+ * set and all the elements are of type {@code Object}.
+ * If {@code which == 3}, this is a private credential
+ * set and all the elements are of type {@code Object}.
*/
private int which;
@@ -1168,7 +1206,7 @@
}
public boolean removeAll(Collection<?> c) {
-
+ Objects.requireNonNull(c);
boolean modified = false;
final Iterator<E> e = iterator();
while (e.hasNext()) {
@@ -1204,7 +1242,7 @@
}
public boolean retainAll(Collection<?> c) {
-
+ Objects.requireNonNull(c);
boolean modified = false;
boolean retain = false;
final Iterator<E> e = iterator();
@@ -1291,18 +1329,25 @@
oos.writeFields();
}
+ @SuppressWarnings("unchecked")
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException
{
ObjectInputStream.GetField fields = ois.readFields();
subject = (Subject) fields.get("this$0", null);
- elements = (LinkedList<E>) fields.get("elements", null);
which = fields.get("which", 0);
+
+ LinkedList<E> tmp = (LinkedList<E>) fields.get("elements", null);
+ if (tmp.getClass() != LinkedList.class) {
+ elements = new LinkedList<E>(tmp);
+ } else {
+ elements = tmp;
+ }
}
}
/**
- * This class implements a <code>Set</code> which returns only
+ * This class implements a {@code Set} which returns only
* members that are an instance of a specified Class.
*/
private class ClassSet<T> extends AbstractSet<T> {
@@ -1329,6 +1374,7 @@
}
}
+ @SuppressWarnings("unchecked") /*To suppress warning from line 1374*/
private void populateSet() {
final Iterator<?> iterator;
switch(which) {
diff --git a/ojluni/src/main/java/sun/invoke/util/VerifyAccess.java b/ojluni/src/main/java/sun/invoke/util/VerifyAccess.java
new file mode 100644
index 0000000..d2e5820
--- /dev/null
+++ b/ojluni/src/main/java/sun/invoke/util/VerifyAccess.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.invoke.util;
+
+import java.lang.reflect.Modifier;
+import static java.lang.reflect.Modifier.*;
+import sun.reflect.Reflection;
+
+/**
+ * This class centralizes information about the JVM's linkage access control.
+ * @author jrose
+ */
+public class VerifyAccess {
+
+ private VerifyAccess() { } // cannot instantiate
+
+ private static final int PACKAGE_ONLY = 0;
+ private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
+ private static final int PROTECTED_OR_PACKAGE_ALLOWED = (PACKAGE_ALLOWED|PROTECTED);
+ private static final int ALL_ACCESS_MODES = (PUBLIC|PRIVATE|PROTECTED|PACKAGE_ONLY);
+ private static final boolean ALLOW_NESTMATE_ACCESS = false;
+
+ /**
+ * Evaluate the JVM linkage rules for access to the given method
+ * on behalf of a caller class which proposes to perform the access.
+ * Return true if the caller class has privileges to invoke a method
+ * or access a field with the given properties.
+ * This requires an accessibility check of the referencing class,
+ * plus an accessibility check of the member within the class,
+ * which depends on the member's modifier flags.
+ * <p>
+ * The relevant properties include the defining class ({@code defc})
+ * of the member, and its modifier flags ({@code mods}).
+ * Also relevant is the class used to make the initial symbolic reference
+ * to the member ({@code refc}). If this latter class is not distinguished,
+ * the defining class should be passed for both arguments ({@code defc == refc}).
+ * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
+ * A field or method R is accessible to a class or interface D if
+ * and only if any of the following conditions is true:<ul>
+ * <li>R is public.
+ * <li>R is protected and is declared in a class C, and D is either
+ * a subclass of C or C itself. Furthermore, if R is not
+ * static, then the symbolic reference to R must contain a
+ * symbolic reference to a class T, such that T is either a
+ * subclass of D, a superclass of D or D itself.
+ * <li>R is either protected or has default access (that is,
+ * neither public nor protected nor private), and is declared
+ * by a class in the same runtime package as D.
+ * <li>R is private and is declared in D.
+ * </ul>
+ * This discussion of access control omits a related restriction
+ * on the target of a protected field access or method invocation
+ * (the target must be of class D or a subtype of D). That
+ * requirement is checked as part of the verification process
+ * (5.4.1); it is not part of link-time access control.
+ * @param refc the class used in the symbolic reference to the proposed member
+ * @param defc the class in which the proposed member is actually defined
+ * @param mods modifier flags for the proposed member
+ * @param lookupClass the class for which the access check is being made
+ * @return true iff the the accessing class can access such a member
+ */
+ public static boolean isMemberAccessible(Class<?> refc, // symbolic ref class
+ Class<?> defc, // actual def class
+ int mods, // actual member mods
+ Class<?> lookupClass,
+ int allowedModes) {
+ if (allowedModes == 0) return false;
+ assert((allowedModes & PUBLIC) != 0 &&
+ (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0);
+ // The symbolic reference class (refc) must always be fully verified.
+ if (!isClassAccessible(refc, lookupClass, allowedModes)) {
+ return false;
+ }
+ // Usually refc and defc are the same, but verify defc also in case they differ.
+ if (defc == lookupClass &&
+ (allowedModes & PRIVATE) != 0)
+ return true; // easy check; all self-access is OK
+ switch (mods & ALL_ACCESS_MODES) {
+ case PUBLIC:
+ return true; // already checked above
+ case PROTECTED:
+ assert !defc.isInterface(); // protected members aren't allowed in interfaces
+ if ((allowedModes & PROTECTED_OR_PACKAGE_ALLOWED) != 0 &&
+ isSamePackage(defc, lookupClass))
+ return true;
+ if ((allowedModes & PROTECTED) == 0)
+ return false;
+ // Protected members are accessible by subclasses, which does not include interfaces.
+ // Interfaces are types, not classes. They should not have access to
+ // protected members in j.l.Object, even though it is their superclass.
+ if ((mods & STATIC) != 0 &&
+ !isRelatedClass(refc, lookupClass))
+ return false;
+ if ((allowedModes & PROTECTED) != 0 &&
+ isSubClass(lookupClass, defc))
+ return true;
+ return false;
+ case PACKAGE_ONLY: // That is, zero. Unmarked member is package-only access.
+ assert !defc.isInterface(); // package-private members aren't allowed in interfaces
+ return ((allowedModes & PACKAGE_ALLOWED) != 0 &&
+ isSamePackage(defc, lookupClass));
+ case PRIVATE:
+ // Loosened rules for privates follows access rules for inner classes.
+ return (ALLOW_NESTMATE_ACCESS &&
+ (allowedModes & PRIVATE) != 0 &&
+ isSamePackageMember(defc, lookupClass));
+ default:
+ throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods));
+ }
+ }
+
+ static boolean isRelatedClass(Class<?> refc, Class<?> lookupClass) {
+ return (refc == lookupClass ||
+ isSubClass(refc, lookupClass) ||
+ isSubClass(lookupClass, refc));
+ }
+
+ static boolean isSubClass(Class<?> lookupClass, Class<?> defc) {
+ return defc.isAssignableFrom(lookupClass) &&
+ !lookupClass.isInterface(); // interfaces are types, not classes.
+ }
+
+ /**
+ * Evaluate the JVM linkage rules for access to the given class on behalf of caller.
+ * <h3>JVM Specification, 5.4.4 "Access Control"</h3>
+ * A class or interface C is accessible to a class or interface D
+ * if and only if either of the following conditions are true:<ul>
+ * <li>C is public.
+ * <li>C and D are members of the same runtime package.
+ * </ul>
+ * @param refc the symbolic reference class to which access is being checked (C)
+ * @param lookupClass the class performing the lookup (D)
+ */
+ public static boolean isClassAccessible(Class<?> refc, Class<?> lookupClass,
+ int allowedModes) {
+ if (allowedModes == 0) return false;
+ // Android-changed: Use public APIs to figure out whether a class
+ // is public or not.
+ if (Modifier.isPublic(refc.getModifiers()))
+ return true;
+ if ((allowedModes & PACKAGE_ALLOWED) != 0 &&
+ isSamePackage(lookupClass, refc))
+ return true;
+ return false;
+ }
+
+ /**
+ * Decide if the given method type, attributed to a member or symbolic
+ * reference of a given reference class, is really visible to that class.
+ * @param type the supposed type of a member or symbolic reference of refc
+ * @param refc the class attempting to make the reference
+ */
+ public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
+ if (type == refc) return true; // easy check
+ while (type.isArray()) type = type.getComponentType();
+ if (type.isPrimitive() || type == Object.class) return true;
+ ClassLoader parent = type.getClassLoader();
+ if (parent == null) return true;
+ ClassLoader child = refc.getClassLoader();
+ if (child == null) return false;
+ if (parent == child || loadersAreRelated(parent, child, true))
+ return true;
+ // Do it the hard way: Look up the type name from the refc loader.
+ try {
+ Class<?> res = child.loadClass(type.getName());
+ return (type == res);
+ } catch (ClassNotFoundException ex) {
+ return false;
+ }
+ }
+
+ /**
+ * Decide if the given method type, attributed to a member or symbolic
+ * reference of a given reference class, is really visible to that class.
+ * @param type the supposed type of a member or symbolic reference of refc
+ * @param refc the class attempting to make the reference
+ */
+ public static boolean isTypeVisible(java.lang.invoke.MethodType type, Class<?> refc) {
+ for (int n = -1, max = type.parameterCount(); n < max; n++) {
+ Class<?> ptype = (n < 0 ? type.returnType() : type.parameterType(n));
+ if (!isTypeVisible(ptype, refc))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Test if two classes have the same class loader and package qualifier.
+ * @param class1 a class
+ * @param class2 another class
+ * @return whether they are in the same package
+ */
+ public static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+ // Android-changed: Throw IAE (instead of asserting) if called with array classes.
+ if (class1.isArray() || class2.isArray()) {
+ throw new IllegalArgumentException();
+ }
+
+ if (class1 == class2)
+ return true;
+ if (class1.getClassLoader() != class2.getClassLoader())
+ return false;
+ String name1 = class1.getName(), name2 = class2.getName();
+ int dot = name1.lastIndexOf('.');
+ if (dot != name2.lastIndexOf('.'))
+ return false;
+ for (int i = 0; i < dot; i++) {
+ if (name1.charAt(i) != name2.charAt(i))
+ return false;
+ }
+ return true;
+ }
+
+ /** Return the package name for this class.
+ */
+ public static String getPackageName(Class<?> cls) {
+ assert(!cls.isArray());
+ String name = cls.getName();
+ int dot = name.lastIndexOf('.');
+ if (dot < 0) return "";
+ return name.substring(0, dot);
+ }
+
+ /**
+ * Test if two classes are defined as part of the same package member (top-level class).
+ * If this is true, they can share private access with each other.
+ * @param class1 a class
+ * @param class2 another class
+ * @return whether they are identical or nested together
+ */
+ public static boolean isSamePackageMember(Class<?> class1, Class<?> class2) {
+ if (class1 == class2)
+ return true;
+ if (!isSamePackage(class1, class2))
+ return false;
+ if (getOutermostEnclosingClass(class1) != getOutermostEnclosingClass(class2))
+ return false;
+ return true;
+ }
+
+ private static Class<?> getOutermostEnclosingClass(Class<?> c) {
+ Class<?> pkgmem = c;
+ for (Class<?> enc = c; (enc = enc.getEnclosingClass()) != null; )
+ pkgmem = enc;
+ return pkgmem;
+ }
+
+ private static boolean loadersAreRelated(ClassLoader loader1, ClassLoader loader2,
+ boolean loader1MustBeParent) {
+ if (loader1 == loader2 || loader1 == null
+ || (loader2 == null && !loader1MustBeParent)) {
+ return true;
+ }
+ for (ClassLoader scan2 = loader2;
+ scan2 != null; scan2 = scan2.getParent()) {
+ if (scan2 == loader1) return true;
+ }
+ if (loader1MustBeParent) return false;
+ // see if loader2 is a parent of loader1:
+ for (ClassLoader scan1 = loader1;
+ scan1 != null; scan1 = scan1.getParent()) {
+ if (scan1 == loader2) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Is the class loader of parentClass identical to, or an ancestor of,
+ * the class loader of childClass?
+ * @param parentClass a class
+ * @param childClass another class, which may be a descendent of the first class
+ * @return whether parentClass precedes or equals childClass in class loader order
+ */
+ public static boolean classLoaderIsAncestor(Class<?> parentClass, Class<?> childClass) {
+ return loadersAreRelated(parentClass.getClassLoader(), childClass.getClassLoader(), true);
+ }
+}
diff --git a/ojluni/src/main/java/sun/misc/IoTrace.java b/ojluni/src/main/java/sun/misc/IoTrace.java
deleted file mode 100644
index ab15ed1..0000000
--- a/ojluni/src/main/java/sun/misc/IoTrace.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.misc;
-
-import java.net.InetAddress;
-
-/**
- * Utility class used to identify trace points for I/O calls.
- * <p>
- * To use this class, a diagnostic tool must redefine this class with a version
- * that contains calls to the the diagnostic tool. This implementation will then
- * receive callbacks when file and socket operations are performed. The reason
- * for requiring a redefine of the class is to avoid any overhead caused by the
- * instrumentation.
- * <p>
- * The xxBegin() methods return a "context". This can be any Object. This
- * context will be passed to the corresponding xxEnd() method. This way, an
- * implementation can correlate the beginning of an operation with the end.
- * <p>
- * It is possible for a xxEnd() method to be called with a null handle. This
- * happens if tracing was started between the call to xxBegin() and xxEnd(), in
- * which case xxBegin() would not have been called. It is the implementation's
- * responsibility to not throw an exception in this case.
- * <p>
- * Only blocking I/O operations are identified with this facility.
- * <p>
- * <b>Warning</b>
- * <p>
- * These methods are called from sensitive points in the I/O subsystem. Great
- * care must be taken to not interfere with ongoing operations or cause
- * deadlocks. In particular:
- * <ul>
- * <li>Implementations must not throw exceptions since this will cause
- * disruptions to the I/O operations.
- * <li>Implementations must not do I/O operations since this will lead to an
- * endless loop.
- * <li>Since the hooks may be called while holding low-level locks in the I/O
- * subsystem, implementations must be careful with synchronization or
- * interaction with other threads to avoid deadlocks in the VM.
- * </ul>
- */
-public final class IoTrace {
- private IoTrace() {
- }
-
- /**
- * Called before data is read from a socket.
- *
- * @return a context object
- */
- public static Object socketReadBegin() {
- return null;
- }
-
- /**
- * Called after data is read from the socket.
- *
- * @param context
- * the context returned by the previous call to socketReadBegin()
- * @param address
- * the remote address the socket is bound to
- * @param port
- * the remote port the socket is bound to
- * @param timeout
- * the SO_TIMEOUT value of the socket (in milliseconds) or 0 if
- * there is no timeout set
- * @param bytesRead
- * the number of bytes read from the socket, 0 if there was an
- * error reading from the socket
- */
- public static void socketReadEnd(Object context, InetAddress address, int port,
- int timeout, long bytesRead) {
- }
-
- /**
- * Called before data is written to a socket.
- *
- * @return a context object
- */
- public static Object socketWriteBegin() {
- return null;
- }
-
- /**
- * Called after data is written to a socket.
- *
- * @param context
- * the context returned by the previous call to
- * socketWriteBegin()
- * @param address
- * the remote address the socket is bound to
- * @param port
- * the remote port the socket is bound to
- * @param bytesWritten
- * the number of bytes written to the socket, 0 if there was an
- * error writing to the socket
- */
- public static void socketWriteEnd(Object context, InetAddress address, int port,
- long bytesWritten) {
- }
-
- /**
- * Called before data is read from a file.
- *
- * @param path
- * the path of the file
- * @return a context object
- */
- public static Object fileReadBegin(String path) {
- return null;
- }
-
- /**
- * Called after data is read from a file.
- *
- * @param context
- * the context returned by the previous call to fileReadBegin()
- * @param bytesRead
- * the number of bytes written to the file, 0 if there was an
- * error writing to the file
- */
- public static void fileReadEnd(Object context, long bytesRead) {
- }
-
- /**
- * Called before data is written to a file.
- *
- * @param path
- * the path of the file
- * @return a context object
- */
- public static Object fileWriteBegin(String path) {
- return null;
- }
-
- /**
- * Called after data is written to a file.
- *
- * @param context
- * the context returned by the previous call to fileReadBegin()
- * @param bytesWritten
- * the number of bytes written to the file, 0 if there was an
- * error writing to the file
- */
- public static void fileWriteEnd(Object context, long bytesWritten) {
- }
-}
diff --git a/ojluni/src/main/java/sun/security/util/ManifestEntryVerifier.java b/ojluni/src/main/java/sun/security/util/ManifestEntryVerifier.java
index 3d1b473..8e0169e 100644
--- a/ojluni/src/main/java/sun/security/util/ManifestEntryVerifier.java
+++ b/ojluni/src/main/java/sun/security/util/ManifestEntryVerifier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
import java.util.*;
import java.util.jar.*;
-import sun.misc.BASE64Decoder;
+import java.util.Base64;
import sun.security.jca.Providers;
@@ -63,7 +63,6 @@
/** the manifest hashes for the digests in use */
ArrayList<byte[]> manifestHashes;
- private BASE64Decoder decoder = null;
private String name = null;
private Manifest man;
@@ -81,7 +80,6 @@
createdDigests = new HashMap<String, MessageDigest>(11);
digests = new ArrayList<MessageDigest>();
manifestHashes = new ArrayList<byte[]>();
- decoder = new BASE64Decoder();
this.man = man;
}
@@ -147,7 +145,7 @@
digest.reset();
digests.add(digest);
manifestHashes.add(
- decoder.decodeBuffer((String)se.getValue()));
+ Base64.getMimeDecoder().decode((String)se.getValue()));
}
}
}
diff --git a/ojluni/src/main/java/sun/security/util/Resources.java b/ojluni/src/main/java/sun/security/util/Resources.java
index 299facc..286acc9 100644
--- a/ojluni/src/main/java/sun/security/util/Resources.java
+++ b/ojluni/src/main/java/sun/security/util/Resources.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,509 +34,6 @@
private static final Object[][] contents = {
- // shared (from jarsigner)
- {"SPACE", " "},
- {"2SPACE", " "},
- {"6SPACE", " "},
- {"COMMA", ", "},
- // shared (from keytool)
- {"NEWLINE", "\n"},
- {"STAR",
- "*******************************************"},
- {"STARNN",
- "*******************************************\n\n"},
-
- // keytool: Help part
- {".OPTION.", " [OPTION]..."},
- {"Options.", "Options:"},
- {"Use.keytool.help.for.all.available.commands",
- "Use \"keytool -help\" for all available commands"},
- {"Key.and.Certificate.Management.Tool",
- "Key and Certificate Management Tool"},
- {"Commands.", "Commands:"},
- {"Use.keytool.command.name.help.for.usage.of.command.name",
- "Use \"keytool -command_name -help\" for usage of command_name"},
- // keytool: help: commands
- {"Generates.a.certificate.request",
- "Generates a certificate request"}, //-certreq
- {"Changes.an.entry.s.alias",
- "Changes an entry's alias"}, //-changealias
- {"Deletes.an.entry",
- "Deletes an entry"}, //-delete
- {"Exports.certificate",
- "Exports certificate"}, //-exportcert
- {"Generates.a.key.pair",
- "Generates a key pair"}, //-genkeypair
- {"Generates.a.secret.key",
- "Generates a secret key"}, //-genseckey
- {"Generates.certificate.from.a.certificate.request",
- "Generates certificate from a certificate request"}, //-gencert
- {"Generates.CRL", "Generates CRL"}, //-gencrl
- {"Imports.entries.from.a.JDK.1.1.x.style.identity.database",
- "Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb
- {"Imports.a.certificate.or.a.certificate.chain",
- "Imports a certificate or a certificate chain"}, //-importcert
- {"Imports.one.or.all.entries.from.another.keystore",
- "Imports one or all entries from another keystore"}, //-importkeystore
- {"Clones.a.key.entry",
- "Clones a key entry"}, //-keyclone
- {"Changes.the.key.password.of.an.entry",
- "Changes the key password of an entry"}, //-keypasswd
- {"Lists.entries.in.a.keystore",
- "Lists entries in a keystore"}, //-list
- {"Prints.the.content.of.a.certificate",
- "Prints the content of a certificate"}, //-printcert
- {"Prints.the.content.of.a.certificate.request",
- "Prints the content of a certificate request"}, //-printcertreq
- {"Prints.the.content.of.a.CRL.file",
- "Prints the content of a CRL file"}, //-printcrl
- {"Generates.a.self.signed.certificate",
- "Generates a self-signed certificate"}, //-selfcert
- {"Changes.the.store.password.of.a.keystore",
- "Changes the store password of a keystore"}, //-storepasswd
- // keytool: help: options
- {"alias.name.of.the.entry.to.process",
- "alias name of the entry to process"}, //-alias
- {"destination.alias",
- "destination alias"}, //-destalias
- {"destination.key.password",
- "destination key password"}, //-destkeypass
- {"destination.keystore.name",
- "destination keystore name"}, //-destkeystore
- {"destination.keystore.password.protected",
- "destination keystore password protected"}, //-destprotected
- {"destination.keystore.provider.name",
- "destination keystore provider name"}, //-destprovidername
- {"destination.keystore.password",
- "destination keystore password"}, //-deststorepass
- {"destination.keystore.type",
- "destination keystore type"}, //-deststoretype
- {"distinguished.name",
- "distinguished name"}, //-dname
- {"X.509.extension",
- "X.509 extension"}, //-ext
- {"output.file.name",
- "output file name"}, //-file and -outfile
- {"input.file.name",
- "input file name"}, //-file and -infile
- {"key.algorithm.name",
- "key algorithm name"}, //-keyalg
- {"key.password",
- "key password"}, //-keypass
- {"key.bit.size",
- "key bit size"}, //-keysize
- {"keystore.name",
- "keystore name"}, //-keystore
- {"new.password",
- "new password"}, //-new
- {"do.not.prompt",
- "do not prompt"}, //-noprompt
- {"password.through.protected.mechanism",
- "password through protected mechanism"}, //-protected
- {"provider.argument",
- "provider argument"}, //-providerarg
- {"provider.class.name",
- "provider class name"}, //-providerclass
- {"provider.name",
- "provider name"}, //-providername
- {"provider.classpath",
- "provider classpath"}, //-providerpath
- {"output.in.RFC.style",
- "output in RFC style"}, //-rfc
- {"signature.algorithm.name",
- "signature algorithm name"}, //-sigalg
- {"source.alias",
- "source alias"}, //-srcalias
- {"source.key.password",
- "source key password"}, //-srckeypass
- {"source.keystore.name",
- "source keystore name"}, //-srckeystore
- {"source.keystore.password.protected",
- "source keystore password protected"}, //-srcprotected
- {"source.keystore.provider.name",
- "source keystore provider name"}, //-srcprovidername
- {"source.keystore.password",
- "source keystore password"}, //-srcstorepass
- {"source.keystore.type",
- "source keystore type"}, //-srcstoretype
- {"SSL.server.host.and.port",
- "SSL server host and port"}, //-sslserver
- {"signed.jar.file",
- "signed jar file"}, //=jarfile
- {"certificate.validity.start.date.time",
- "certificate validity start date/time"}, //-startdate
- {"keystore.password",
- "keystore password"}, //-storepass
- {"keystore.type",
- "keystore type"}, //-storetype
- {"trust.certificates.from.cacerts",
- "trust certificates from cacerts"}, //-trustcacerts
- {"verbose.output",
- "verbose output"}, //-v
- {"validity.number.of.days",
- "validity number of days"}, //-validity
- {"Serial.ID.of.cert.to.revoke",
- "Serial ID of cert to revoke"}, //-id
- // keytool: Running part
- {"keytool.error.", "keytool error: "},
- {"Illegal.option.", "Illegal option: "},
- {"Illegal.value.", "Illegal value: "},
- {"Unknown.password.type.", "Unknown password type: "},
- {"Cannot.find.environment.variable.",
- "Cannot find environment variable: "},
- {"Cannot.find.file.", "Cannot find file: "},
- {"Command.option.flag.needs.an.argument.", "Command option {0} needs an argument."},
- {"Warning.Different.store.and.key.passwords.not.supported.for.PKCS12.KeyStores.Ignoring.user.specified.command.value.",
- "Warning: Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified {0} value."},
- {".keystore.must.be.NONE.if.storetype.is.{0}",
- "-keystore must be NONE if -storetype is {0}"},
- {"Too.many.retries.program.terminated",
- "Too many retries, program terminated"},
- {".storepasswd.and.keypasswd.commands.not.supported.if.storetype.is.{0}",
- "-storepasswd and -keypasswd commands not supported if -storetype is {0}"},
- {".keypasswd.commands.not.supported.if.storetype.is.PKCS12",
- "-keypasswd commands not supported if -storetype is PKCS12"},
- {".keypass.and.new.can.not.be.specified.if.storetype.is.{0}",
- "-keypass and -new can not be specified if -storetype is {0}"},
- {"if.protected.is.specified.then.storepass.keypass.and.new.must.not.be.specified",
- "if -protected is specified, then -storepass, -keypass, and -new must not be specified"},
- {"if.srcprotected.is.specified.then.srcstorepass.and.srckeypass.must.not.be.specified",
- "if -srcprotected is specified, then -srcstorepass and -srckeypass must not be specified"},
- {"if.keystore.is.not.password.protected.then.storepass.keypass.and.new.must.not.be.specified",
- "if keystore is not password protected, then -storepass, -keypass, and -new must not be specified"},
- {"if.source.keystore.is.not.password.protected.then.srcstorepass.and.srckeypass.must.not.be.specified",
- "if source keystore is not password protected, then -srcstorepass and -srckeypass must not be specified"},
- {"Illegal.startdate.value", "Illegal startdate value"},
- {"Validity.must.be.greater.than.zero",
- "Validity must be greater than zero"},
- {"provName.not.a.provider", "{0} not a provider"},
- {"Usage.error.no.command.provided", "Usage error: no command provided"},
- {"Source.keystore.file.exists.but.is.empty.", "Source keystore file exists, but is empty: "},
- {"Please.specify.srckeystore", "Please specify -srckeystore"},
- {"Must.not.specify.both.v.and.rfc.with.list.command",
- "Must not specify both -v and -rfc with 'list' command"},
- {"Key.password.must.be.at.least.6.characters",
- "Key password must be at least 6 characters"},
- {"New.password.must.be.at.least.6.characters",
- "New password must be at least 6 characters"},
- {"Keystore.file.exists.but.is.empty.",
- "Keystore file exists, but is empty: "},
- {"Keystore.file.does.not.exist.",
- "Keystore file does not exist: "},
- {"Must.specify.destination.alias", "Must specify destination alias"},
- {"Must.specify.alias", "Must specify alias"},
- {"Keystore.password.must.be.at.least.6.characters",
- "Keystore password must be at least 6 characters"},
- {"Enter.keystore.password.", "Enter keystore password: "},
- {"Enter.source.keystore.password.", "Enter source keystore password: "},
- {"Enter.destination.keystore.password.", "Enter destination keystore password: "},
- {"Keystore.password.is.too.short.must.be.at.least.6.characters",
- "Keystore password is too short - must be at least 6 characters"},
- {"Unknown.Entry.Type", "Unknown Entry Type"},
- {"Too.many.failures.Alias.not.changed", "Too many failures. Alias not changed"},
- {"Entry.for.alias.alias.successfully.imported.",
- "Entry for alias {0} successfully imported."},
- {"Entry.for.alias.alias.not.imported.", "Entry for alias {0} not imported."},
- {"Problem.importing.entry.for.alias.alias.exception.Entry.for.alias.alias.not.imported.",
- "Problem importing entry for alias {0}: {1}.\nEntry for alias {0} not imported."},
- {"Import.command.completed.ok.entries.successfully.imported.fail.entries.failed.or.cancelled",
- "Import command completed: {0} entries successfully imported, {1} entries failed or cancelled"},
- {"Warning.Overwriting.existing.alias.alias.in.destination.keystore",
- "Warning: Overwriting existing alias {0} in destination keystore"},
- {"Existing.entry.alias.alias.exists.overwrite.no.",
- "Existing entry alias {0} exists, overwrite? [no]: "},
- {"Too.many.failures.try.later", "Too many failures - try later"},
- {"Certification.request.stored.in.file.filename.",
- "Certification request stored in file <{0}>"},
- {"Submit.this.to.your.CA", "Submit this to your CA"},
- {"if.alias.not.specified.destalias.srckeypass.and.destkeypass.must.not.be.specified",
- "if alias not specified, destalias, srckeypass, and destkeypass must not be specified"},
- {"Certificate.stored.in.file.filename.",
- "Certificate stored in file <{0}>"},
- {"Certificate.reply.was.installed.in.keystore",
- "Certificate reply was installed in keystore"},
- {"Certificate.reply.was.not.installed.in.keystore",
- "Certificate reply was not installed in keystore"},
- {"Certificate.was.added.to.keystore",
- "Certificate was added to keystore"},
- {"Certificate.was.not.added.to.keystore",
- "Certificate was not added to keystore"},
- {".Storing.ksfname.", "[Storing {0}]"},
- {"alias.has.no.public.key.certificate.",
- "{0} has no public key (certificate)"},
- {"Cannot.derive.signature.algorithm",
- "Cannot derive signature algorithm"},
- {"Alias.alias.does.not.exist",
- "Alias <{0}> does not exist"},
- {"Alias.alias.has.no.certificate",
- "Alias <{0}> has no certificate"},
- {"Key.pair.not.generated.alias.alias.already.exists",
- "Key pair not generated, alias <{0}> already exists"},
- {"Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for",
- "Generating {0} bit {1} key pair and self-signed certificate ({2}) with a validity of {3} days\n\tfor: {4}"},
- {"Enter.key.password.for.alias.", "Enter key password for <{0}>"},
- {".RETURN.if.same.as.keystore.password.",
- "\t(RETURN if same as keystore password): "},
- {"Key.password.is.too.short.must.be.at.least.6.characters",
- "Key password is too short - must be at least 6 characters"},
- {"Too.many.failures.key.not.added.to.keystore",
- "Too many failures - key not added to keystore"},
- {"Destination.alias.dest.already.exists",
- "Destination alias <{0}> already exists"},
- {"Password.is.too.short.must.be.at.least.6.characters",
- "Password is too short - must be at least 6 characters"},
- {"Too.many.failures.Key.entry.not.cloned",
- "Too many failures. Key entry not cloned"},
- {"key.password.for.alias.", "key password for <{0}>"},
- {"Keystore.entry.for.id.getName.already.exists",
- "Keystore entry for <{0}> already exists"},
- {"Creating.keystore.entry.for.id.getName.",
- "Creating keystore entry for <{0}> ..."},
- {"No.entries.from.identity.database.added",
- "No entries from identity database added"},
- {"Alias.name.alias", "Alias name: {0}"},
- {"Creation.date.keyStore.getCreationDate.alias.",
- "Creation date: {0,date}"},
- {"alias.keyStore.getCreationDate.alias.",
- "{0}, {1,date}, "},
- {"alias.", "{0}, "},
- {"Entry.type.type.", "Entry type: {0}"},
- {"Certificate.chain.length.", "Certificate chain length: "},
- {"Certificate.i.1.", "Certificate[{0,number,integer}]:"},
- {"Certificate.fingerprint.SHA1.", "Certificate fingerprint (SHA1): "},
- {"Keystore.type.", "Keystore type: "},
- {"Keystore.provider.", "Keystore provider: "},
- {"Your.keystore.contains.keyStore.size.entry",
- "Your keystore contains {0,number,integer} entry"},
- {"Your.keystore.contains.keyStore.size.entries",
- "Your keystore contains {0,number,integer} entries"},
- {"Failed.to.parse.input", "Failed to parse input"},
- {"Empty.input", "Empty input"},
- {"Not.X.509.certificate", "Not X.509 certificate"},
- {"alias.has.no.public.key", "{0} has no public key"},
- {"alias.has.no.X.509.certificate", "{0} has no X.509 certificate"},
- {"New.certificate.self.signed.", "New certificate (self-signed):"},
- {"Reply.has.no.certificates", "Reply has no certificates"},
- {"Certificate.not.imported.alias.alias.already.exists",
- "Certificate not imported, alias <{0}> already exists"},
- {"Input.not.an.X.509.certificate", "Input not an X.509 certificate"},
- {"Certificate.already.exists.in.keystore.under.alias.trustalias.",
- "Certificate already exists in keystore under alias <{0}>"},
- {"Do.you.still.want.to.add.it.no.",
- "Do you still want to add it? [no]: "},
- {"Certificate.already.exists.in.system.wide.CA.keystore.under.alias.trustalias.",
- "Certificate already exists in system-wide CA keystore under alias <{0}>"},
- {"Do.you.still.want.to.add.it.to.your.own.keystore.no.",
- "Do you still want to add it to your own keystore? [no]: "},
- {"Trust.this.certificate.no.", "Trust this certificate? [no]: "},
- {"YES", "YES"},
- {"New.prompt.", "New {0}: "},
- {"Passwords.must.differ", "Passwords must differ"},
- {"Re.enter.new.prompt.", "Re-enter new {0}: "},
- {"Re.enter.new.password.", "Re-enter new password: "},
- {"They.don.t.match.Try.again", "They don't match. Try again"},
- {"Enter.prompt.alias.name.", "Enter {0} alias name: "},
- {"Enter.new.alias.name.RETURN.to.cancel.import.for.this.entry.",
- "Enter new alias name\t(RETURN to cancel import for this entry): "},
- {"Enter.alias.name.", "Enter alias name: "},
- {".RETURN.if.same.as.for.otherAlias.",
- "\t(RETURN if same as for <{0}>)"},
- {".PATTERN.printX509Cert",
- "Owner: {0}\nIssuer: {1}\nSerial number: {2}\nValid from: {3} until: {4}\nCertificate fingerprints:\n\t MD5: {5}\n\t SHA1: {6}\n\t SHA256: {7}\n\t Signature algorithm name: {8}\n\t Version: {9}"},
- {"What.is.your.first.and.last.name.",
- "What is your first and last name?"},
- {"What.is.the.name.of.your.organizational.unit.",
- "What is the name of your organizational unit?"},
- {"What.is.the.name.of.your.organization.",
- "What is the name of your organization?"},
- {"What.is.the.name.of.your.City.or.Locality.",
- "What is the name of your City or Locality?"},
- {"What.is.the.name.of.your.State.or.Province.",
- "What is the name of your State or Province?"},
- {"What.is.the.two.letter.country.code.for.this.unit.",
- "What is the two-letter country code for this unit?"},
- {"Is.name.correct.", "Is {0} correct?"},
- {"no", "no"},
- {"yes", "yes"},
- {"y", "y"},
- {".defaultValue.", " [{0}]: "},
- {"Alias.alias.has.no.key",
- "Alias <{0}> has no key"},
- {"Alias.alias.references.an.entry.type.that.is.not.a.private.key.entry.The.keyclone.command.only.supports.cloning.of.private.key",
- "Alias <{0}> references an entry type that is not a private key entry. The -keyclone command only supports cloning of private key entries"},
-
- {".WARNING.WARNING.WARNING.",
- "***************** WARNING WARNING WARNING *****************"},
- {"Signer.d.", "Signer #%d:"},
- {"Timestamp.", "Timestamp:"},
- {"Signature.", "Signature:"},
- {"CRLs.", "CRLs:"},
- {"Certificate.owner.", "Certificate owner: "},
- {"Not.a.signed.jar.file", "Not a signed jar file"},
- {"No.certificate.from.the.SSL.server",
- "No certificate from the SSL server"},
-
- {".The.integrity.of.the.information.stored.in.your.keystore.",
- "* The integrity of the information stored in your keystore *\n" +
- "* has NOT been verified! In order to verify its integrity, *\n" +
- "* you must provide your keystore password. *"},
- {".The.integrity.of.the.information.stored.in.the.srckeystore.",
- "* The integrity of the information stored in the srckeystore*\n" +
- "* has NOT been verified! In order to verify its integrity, *\n" +
- "* you must provide the srckeystore password. *"},
-
- {"Certificate.reply.does.not.contain.public.key.for.alias.",
- "Certificate reply does not contain public key for <{0}>"},
- {"Incomplete.certificate.chain.in.reply",
- "Incomplete certificate chain in reply"},
- {"Certificate.chain.in.reply.does.not.verify.",
- "Certificate chain in reply does not verify: "},
- {"Top.level.certificate.in.reply.",
- "Top-level certificate in reply:\n"},
- {".is.not.trusted.", "... is not trusted. "},
- {"Install.reply.anyway.no.", "Install reply anyway? [no]: "},
- {"NO", "NO"},
- {"Public.keys.in.reply.and.keystore.don.t.match",
- "Public keys in reply and keystore don't match"},
- {"Certificate.reply.and.certificate.in.keystore.are.identical",
- "Certificate reply and certificate in keystore are identical"},
- {"Failed.to.establish.chain.from.reply",
- "Failed to establish chain from reply"},
- {"n", "n"},
- {"Wrong.answer.try.again", "Wrong answer, try again"},
- {"Secret.key.not.generated.alias.alias.already.exists",
- "Secret Key not generated, alias <{0}> already exists"},
- {"Please.provide.keysize.for.secret.key.generation",
- "Please provide -keysize for secret key generation"},
-
- {"Extensions.", "Extensions: "},
- {".Empty.value.", "(Empty value)"},
- {"Extension.Request.", "Extension Request:"},
- {"PKCS.10.Certificate.Request.Version.1.0.Subject.s.Public.Key.s.format.s.key.",
- "PKCS #10 Certificate Request (Version 1.0)\n" +
- "Subject: %s\nPublic Key: %s format %s key\n"},
- {"Unknown.keyUsage.type.", "Unknown keyUsage type: "},
- {"Unknown.extendedkeyUsage.type.", "Unknown extendedkeyUsage type: "},
- {"Unknown.AccessDescription.type.", "Unknown AccessDescription type: "},
- {"Unrecognized.GeneralName.type.", "Unrecognized GeneralName type: "},
- {"This.extension.cannot.be.marked.as.critical.",
- "This extension cannot be marked as critical. "},
- {"Odd.number.of.hex.digits.found.", "Odd number of hex digits found: "},
- {"Unknown.extension.type.", "Unknown extension type: "},
- {"command.{0}.is.ambiguous.", "command {0} is ambiguous:"},
-
- // policytool
- {"Warning.A.public.key.for.alias.signers.i.does.not.exist.Make.sure.a.KeyStore.is.properly.configured.",
- "Warning: A public key for alias {0} does not exist. Make sure a KeyStore is properly configured."},
- {"Warning.Class.not.found.class", "Warning: Class not found: {0}"},
- {"Warning.Invalid.argument.s.for.constructor.arg",
- "Warning: Invalid argument(s) for constructor: {0}"},
- {"Illegal.Principal.Type.type", "Illegal Principal Type: {0}"},
- {"Illegal.option.option", "Illegal option: {0}"},
- {"Usage.policytool.options.", "Usage: policytool [options]"},
- {".file.file.policy.file.location",
- " [-file <file>] policy file location"},
- {"New", "New"},
- {"Open", "Open"},
- {"Save", "Save"},
- {"Save.As", "Save As"},
- {"View.Warning.Log", "View Warning Log"},
- {"Exit", "Exit"},
- {"Add.Policy.Entry", "Add Policy Entry"},
- {"Edit.Policy.Entry", "Edit Policy Entry"},
- {"Remove.Policy.Entry", "Remove Policy Entry"},
- {"Edit", "Edit"},
- {"Retain", "Retain"},
-
- {"Warning.File.name.may.include.escaped.backslash.characters.It.is.not.necessary.to.escape.backslash.characters.the.tool.escapes",
- "Warning: File name may include escaped backslash characters. " +
- "It is not necessary to escape backslash characters " +
- "(the tool escapes characters as necessary when writing " +
- "the policy contents to the persistent store).\n\n" +
- "Click on Retain to retain the entered name, or click on " +
- "Edit to edit the name."},
-
- {"Add.Public.Key.Alias", "Add Public Key Alias"},
- {"Remove.Public.Key.Alias", "Remove Public Key Alias"},
- {"File", "File"},
- {"KeyStore", "KeyStore"},
- {"Policy.File.", "Policy File:"},
- {"Could.not.open.policy.file.policyFile.e.toString.",
- "Could not open policy file: {0}: {1}"},
- {"Policy.Tool", "Policy Tool"},
- {"Errors.have.occurred.while.opening.the.policy.configuration.View.the.Warning.Log.for.more.information.",
- "Errors have occurred while opening the policy configuration. View the Warning Log for more information."},
- {"Error", "Error"},
- {"OK", "OK"},
- {"Status", "Status"},
- {"Warning", "Warning"},
- {"Permission.",
- "Permission: "},
- {"Principal.Type.", "Principal Type:"},
- {"Principal.Name.", "Principal Name:"},
- {"Target.Name.",
- "Target Name: "},
- {"Actions.",
- "Actions: "},
- {"OK.to.overwrite.existing.file.filename.",
- "OK to overwrite existing file {0}?"},
- {"Cancel", "Cancel"},
- {"CodeBase.", "CodeBase:"},
- {"SignedBy.", "SignedBy:"},
- {"Add.Principal", "Add Principal"},
- {"Edit.Principal", "Edit Principal"},
- {"Remove.Principal", "Remove Principal"},
- {"Principals.", "Principals:"},
- {".Add.Permission", " Add Permission"},
- {".Edit.Permission", " Edit Permission"},
- {"Remove.Permission", "Remove Permission"},
- {"Done", "Done"},
- {"KeyStore.URL.", "KeyStore URL:"},
- {"KeyStore.Type.", "KeyStore Type:"},
- {"KeyStore.Provider.", "KeyStore Provider:"},
- {"KeyStore.Password.URL.", "KeyStore Password URL:"},
- {"Principals", "Principals"},
- {".Edit.Principal.", " Edit Principal:"},
- {".Add.New.Principal.", " Add New Principal:"},
- {"Permissions", "Permissions"},
- {".Edit.Permission.", " Edit Permission:"},
- {".Add.New.Permission.", " Add New Permission:"},
- {"Signed.By.", "Signed By:"},
- {"Cannot.Specify.Principal.with.a.Wildcard.Class.without.a.Wildcard.Name",
- "Cannot Specify Principal with a Wildcard Class without a Wildcard Name"},
- {"Cannot.Specify.Principal.without.a.Name",
- "Cannot Specify Principal without a Name"},
- {"Permission.and.Target.Name.must.have.a.value",
- "Permission and Target Name must have a value"},
- {"Remove.this.Policy.Entry.", "Remove this Policy Entry?"},
- {"Overwrite.File", "Overwrite File"},
- {"Policy.successfully.written.to.filename",
- "Policy successfully written to {0}"},
- {"null.filename", "null filename"},
- {"Save.changes.", "Save changes?"},
- {"Yes", "Yes"},
- {"No", "No"},
- {"Policy.Entry", "Policy Entry"},
- {"Save.Changes", "Save Changes"},
- {"No.Policy.Entry.selected", "No Policy Entry selected"},
- {"Unable.to.open.KeyStore.ex.toString.",
- "Unable to open KeyStore: {0}"},
- {"No.principal.selected", "No principal selected"},
- {"No.permission.selected", "No permission selected"},
- {"name", "name"},
- {"configuration.type", "configuration type"},
- {"environment.variable.name", "environment variable name"},
- {"library.name", "library name"},
- {"package.name", "package name"},
- {"policy.type", "policy type"},
- {"property.name", "property name"},
- {"Principal.List", "Principal List"},
- {"Permission.List", "Permission List"},
- {"Code.Base", "Code Base"},
- {"KeyStore.U.R.L.", "KeyStore U R L:"},
- {"KeyStore.Password.U.R.L.", "KeyStore Password U R L:"},
-
-
// javax.security.auth.PrivateCredentialPermission
{"invalid.null.input.s.", "invalid null input(s)"},
{"actions.can.only.be.read.", "actions can only be 'read'"},
@@ -561,6 +58,7 @@
{"provided.null.OID.map", "provided null OID map"},
// javax.security.auth.Subject
+ {"NEWLINE", "\n"},
{"invalid.null.AccessControlContext.provided",
"invalid null AccessControlContext provided"},
{"invalid.null.action.provided", "invalid null action provided"},
@@ -629,6 +127,8 @@
{"multiple.Codebase.expressions",
"multiple Codebase expressions"},
{"multiple.SignedBy.expressions","multiple SignedBy expressions"},
+ {"duplicate.keystore.domain.name","duplicate keystore domain name: {0}"},
+ {"duplicate.keystore.name","duplicate keystore name: {0}"},
{"SignedBy.has.empty.alias","SignedBy has empty alias"},
{"can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name",
"can not specify Principal with a wildcard class without a wildcard name"},
@@ -664,6 +164,7 @@
*
* @return the contents of this <code>ResourceBundle</code>.
*/
+ @Override
public Object[][] getContents() {
return contents;
}
diff --git a/ojluni/src/main/java/sun/security/util/SecurityConstants.java b/ojluni/src/main/java/sun/security/util/SecurityConstants.java
index adad3fa..39fabcf 100644
--- a/ojluni/src/main/java/sun/security/util/SecurityConstants.java
+++ b/ojluni/src/main/java/sun/security/util/SecurityConstants.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -71,35 +71,6 @@
public static final AllPermission ALL_PERMISSION = new AllPermission();
/**
- * Permission type used when AWT is not present.
- */
- /* ----- BEGIN android -----
- private static class FakeAWTPermission extends BasicPermission {
- private static final long serialVersionUID = -1L;
- public FakeAWTPermission(String name) {
- super(name);
- }
- public String toString() {
- return "(\"java.awt.AWTPermission\" \"" + getName() + "\")";
- }
- }
- ----- END android ----- */
-
- /**
- * Permission factory used when AWT is not present.
- */
- /* ----- BEGIN android -----
- private static class FakeAWTPermissionFactory
- implements PermissionFactory<FakeAWTPermission>
- {
- @Override
- public FakeAWTPermission newPermission(String name) {
- return new FakeAWTPermission(name);
- }
- }
- ----- END android ----- */
-
- /**
* AWT Permissions used in the JDK.
*/
/* ----- BEGIN android -----
@@ -109,38 +80,28 @@
// The class name of the factory to create java.awt.AWTPermission objects.
private static final String AWTFactory = "sun.awt.AWTPermissionFactory";
- // The PermissionFactory to create AWT permissions (or fake permissions
- // if AWT is not present).
+ // The PermissionFactory to create AWT permissions (or null if AWT is
+ // not present)
private static final PermissionFactory<?> factory = permissionFactory();
private static PermissionFactory<?> permissionFactory() {
- Class<?> c = AccessController
- .doPrivileged(new PrivilegedAction<Class<?>>() {
- public Class<?> run() {
- try {
- return Class.forName(AWTFactory, true, null);
- } catch (ClassNotFoundException e) {
- // not available
- return null;
- }
- }});
- if (c != null) {
- // AWT present
- try {
- return (PermissionFactory<?>)c.newInstance();
- } catch (InstantiationException x) {
- throw new InternalError(x.getMessage());
- } catch (IllegalAccessException x) {
- throw new InternalError(x.getMessage());
- }
- } else {
- // AWT not present
- return new FakeAWTPermissionFactory();
+ Class<?> c;
+ try {
+ c = Class.forName(AWTFactory, false, AWT.class.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // not available
+ return null;
+ }
+ // AWT present
+ try {
+ return (PermissionFactory<?>)c.newInstance();
+ } catch (ReflectiveOperationException x) {
+ throw new InternalError(x);
}
}
private static Permission newAWTPermission(String name) {
- return factory.newPermission(name);
+ return (factory == null) ? null : factory.newPermission(name);
}
// java.lang.SecurityManager
@@ -259,5 +220,5 @@
// java.lang.SecurityManager
public static final SocketPermission LOCAL_LISTEN_PERMISSION =
- new SocketPermission("localhost:1024-", SOCKET_LISTEN_ACTION);
+ new SocketPermission("localhost:0", SOCKET_LISTEN_ACTION);
}
diff --git a/ojluni/src/main/native/FileInputStream.c b/ojluni/src/main/native/FileInputStream.c
index 0501c97..a5a54f5 100644
--- a/ojluni/src/main/native/FileInputStream.c
+++ b/ojluni/src/main/native/FileInputStream.c
@@ -63,7 +63,7 @@
}
JNIEXPORT void JNICALL
-FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
+FileInputStream_open0(JNIEnv *env, jobject this, jstring path) {
fileOpen(env, this, path, fis_fd, O_RDONLY);
}
@@ -133,7 +133,7 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FileInputStream, open, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(FileInputStream, open0, "(Ljava/lang/String;)V"),
NATIVE_METHOD(FileInputStream, skip0, "(J)J"),
NATIVE_METHOD(FileInputStream, available0, "()I"),
};
diff --git a/ojluni/src/main/native/FileOutputStream_md.c b/ojluni/src/main/native/FileOutputStream_md.c
index 642cef6..615627a 100644
--- a/ojluni/src/main/native/FileOutputStream_md.c
+++ b/ojluni/src/main/native/FileOutputStream_md.c
@@ -52,14 +52,14 @@
JNIEXPORT void JNICALL
-FileOutputStream_open(JNIEnv *env, jobject this,
+FileOutputStream_open0(JNIEnv *env, jobject this,
jstring path, jboolean append) {
fileOpen(env, this, path, fos_fd,
O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(FileOutputStream, open, "(Ljava/lang/String;Z)V"),
+ NATIVE_METHOD(FileOutputStream, open0, "(Ljava/lang/String;Z)V"),
};
void register_java_io_FileOutputStream(JNIEnv* env) {
diff --git a/ojluni/src/main/native/Register.cpp b/ojluni/src/main/native/Register.cpp
index 5f67d8d..0d31d02 100644
--- a/ojluni/src/main/native/Register.cpp
+++ b/ojluni/src/main/native/Register.cpp
@@ -37,7 +37,6 @@
extern void register_java_io_FileDescriptor(JNIEnv*);
extern void register_java_io_FileInputStream(JNIEnv*);
extern void register_java_io_FileOutputStream(JNIEnv*);
-extern void register_java_io_FileSystem(JNIEnv*);
extern void register_java_io_ObjectInputStream(JNIEnv*);
extern void register_java_io_ObjectOutputStream(JNIEnv*);
extern void register_java_io_ObjectStreamClass(JNIEnv*);
@@ -100,7 +99,6 @@
register_java_util_zip_Deflater(env);
register_java_util_zip_CRC32(env);
register_java_util_zip_Adler32(env);
- register_java_io_FileSystem(env);
register_sun_nio_ch_IOUtil(env);
register_sun_nio_ch_FileChannelImpl(env);
register_sun_nio_ch_FileDispatcherImpl(env);
diff --git a/ojluni/src/main/native/openjdksub.mk b/ojluni/src/main/native/openjdksub.mk
index f0f199a..3a3fcb0 100644
--- a/ojluni/src/main/native/openjdksub.mk
+++ b/ojluni/src/main/native/openjdksub.mk
@@ -36,7 +36,6 @@
NativeThread.c \
FileKey.c \
UnixFileSystem_md.c \
- FileSystem_md.c \
ObjectStreamClass.c \
ObjectOutputStream.c \
ObjectInputStream.c \
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index a3709e5..646f7ce 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -22,6 +22,7 @@
ojluni/src/main/java/java/io/DataInputStream.java \
ojluni/src/main/java/java/io/DataOutput.java \
ojluni/src/main/java/java/io/DataOutputStream.java \
+ ojluni/src/main/java/java/io/DefaultFileSystem.java \
ojluni/src/main/java/java/io/DeleteOnExitHook.java \
ojluni/src/main/java/java/io/EOFException.java \
ojluni/src/main/java/java/io/ExpiringCache.java \
@@ -186,9 +187,11 @@
ojluni/src/main/java/java/lang/reflect/InvocationTargetException.java \
ojluni/src/main/java/java/lang/ReflectiveOperationException.java \
ojluni/src/main/java/java/lang/reflect/MalformedParameterizedTypeException.java \
+ ojluni/src/main/java/java/lang/reflect/MalformedParametersException.java \
ojluni/src/main/java/java/lang/reflect/Member.java \
ojluni/src/main/java/java/lang/reflect/Method.java \
ojluni/src/main/java/java/lang/reflect/Modifier.java \
+ ojluni/src/main/java/java/lang/reflect/Parameter.java \
ojluni/src/main/java/java/lang/reflect/ParameterizedType.java \
ojluni/src/main/java/java/lang/reflect/Proxy.java \
ojluni/src/main/java/java/lang/reflect/ReflectPermission.java \
@@ -1161,6 +1164,8 @@
ojluni/src/main/java/sun/misc/FloatingDecimal.java \
ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java \
ojluni/src/main/java/java/lang/invoke/MethodHandle.java \
+ ojluni/src/main/java/java/lang/invoke/MethodHandles.java \
+ ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java \
ojluni/src/main/java/java/lang/invoke/MethodHandleInfo.java \
ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java \
ojluni/src/main/java/java/lang/invoke/MethodType.java \
@@ -1176,6 +1181,7 @@
ojluni/src/main/java/java/util/spi/CurrencyNameProvider.java \
ojluni/src/main/java/java/util/spi/LocaleNameProvider.java \
ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java \
+ ojluni/src/main/java/java/util/spi/ResourceBundleControlProvider.java \
ojluni/src/main/java/java/util/spi/TimeZoneNameProvider.java \
ojluni/src/main/java/jdk/net/ExtendedSocketOptions.java \
ojluni/src/main/java/jdk/net/NetworkPermission.java \
@@ -1184,6 +1190,7 @@
ojluni/src/main/java/sun/invoke/empty/Empty.java \
ojluni/src/main/java/sun/invoke/util/BytecodeDescriptor.java \
ojluni/src/main/java/sun/invoke/util/Wrapper.java \
+ ojluni/src/main/java/sun/invoke/util/VerifyAccess.java \
ojluni/src/main/java/sun/misc/ASCIICaseInsensitiveComparator.java \
ojluni/src/main/java/sun/misc/BASE64Decoder.java \
ojluni/src/main/java/sun/misc/BASE64Encoder.java \
@@ -1201,7 +1208,6 @@
ojluni/src/main/java/sun/misc/Hashing.java \
ojluni/src/main/java/sun/misc/HexDumpEncoder.java \
ojluni/src/main/java/sun/misc/InvalidJarIndexException.java \
- ojluni/src/main/java/sun/misc/IoTrace.java \
ojluni/src/main/java/sun/misc/IOUtils.java \
ojluni/src/main/java/sun/misc/JarIndex.java \
ojluni/src/main/java/sun/misc/JavaIOFileDescriptorAccess.java \
@@ -1603,22 +1609,24 @@
ojluni/src/main/java/sun/util/logging/PlatformLogger.java \
ojluni/src/main/java/sun/util/ResourceBundleEnumeration.java \
ojluni/src/main/java/sun/util/resources/OpenListResourceBundle.java \
- $(openjdk_javadoc_files)
+ $(openjdk_javadoc_files) \
+ $(openjdk_lambda_stub_files)
# Stubs needed to satisfy javac's dependencies when compiling lambda code. These are
# not used on Android devices or required by the Jack compiler.
#
-# The stub files in openjdk_lambda_duplicate_stub_files are present in core-oj as
-# well, and need to be included here to support compiling against older SDKs and the
-# like. This additional bit of ugliness if required to avoid a circular dependency
-# between core-all and these stubs. Eventually, all of these stubs will become
-# "duplicates" and then that list can be renamed to "openjdk_lambda_stub_files".
+# On aosp/master:
+# openjdk_lambda_stub_files : These are included in core-oj as stubs
+# openjdk_lambda_duplicate_stub_files : These contain complete implementations in core-oj.
+#
+# On older platforms : Both sets of stub files are used and core-oj does not contain
+# any of these classes.
openjdk_lambda_stub_files := \
ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
- ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
openjdk_lambda_duplicate_stub_files := \
+ ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
ojluni/src/lambda/java/java/lang/invoke/MethodType.java \
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index d2f8b67..1f6756e 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -230,7 +230,10 @@
provide("MessageDigest", "SHA-384");
provide("MessageDigest", "SHA-512");
provide("Policy", "JavaPolicy");
- provide("SSLContext", "SSLv3");
+ // Android does not support SSLv3
+ if (IS_RI) {
+ provide("SSLContext", "SSLv3");
+ }
provide("SSLContext", "TLSv1");
provide("SSLContext", "TLSv1.1");
provide("SSLContext", "TLSv1.2");
@@ -290,7 +293,10 @@
// Not documented as in RI 6 but mentioned in Standard Names
provide("AlgorithmParameters", "PBE");
- provide("SSLContext", "SSL");
+ // Android does not support SSLv3
+ if (IS_RI) {
+ provide("SSLContext", "SSL");
+ }
provide("SSLContext", "TLS");
// Not documented as in RI 6 but that exist in RI 6
@@ -580,8 +586,6 @@
provideSslContextEnabledProtocols("TLSv1.2", TLSVersion.SSLv3, TLSVersion.TLSv12);
provideSslContextEnabledProtocols("Default", TLSVersion.SSLv3, TLSVersion.TLSv1);
} else {
- provideSslContextEnabledProtocols("SSL", TLSVersion.SSLv3, TLSVersion.TLSv12);
- provideSslContextEnabledProtocols("SSLv3", TLSVersion.SSLv3, TLSVersion.TLSv12);
provideSslContextEnabledProtocols("TLS", TLSVersion.TLSv1, TLSVersion.TLSv12);
provideSslContextEnabledProtocols("TLSv1", TLSVersion.TLSv1, TLSVersion.TLSv12);
provideSslContextEnabledProtocols("TLSv1.1", TLSVersion.TLSv1, TLSVersion.TLSv12);
@@ -593,9 +597,6 @@
public static final String SSL_CONTEXT_PROTOCOLS_DEFAULT = "Default";
public static final Set<String> SSL_CONTEXT_PROTOCOLS = new HashSet<String>(Arrays.asList(
SSL_CONTEXT_PROTOCOLS_DEFAULT,
- "SSL",
- // "SSLv2",
- "SSLv3",
"TLS",
"TLSv1",
"TLSv1.1",
@@ -619,8 +620,6 @@
}
public static final Set<String> SSL_SOCKET_PROTOCOLS = new HashSet<String>(Arrays.asList(
- // "SSLv2",
- "SSLv3",
"TLSv1",
"TLSv1.1",
"TLSv1.2"));
@@ -735,11 +734,7 @@
addBoth( "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");
addBoth( "TLS_RSA_WITH_AES_128_CBC_SHA");
addBoth( "TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
- addBoth( "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA");
- addBoth( "TLS_ECDHE_RSA_WITH_RC4_128_SHA");
- addBoth( "SSL_RSA_WITH_RC4_128_SHA");
addBoth( "SSL_RSA_WITH_3DES_EDE_CBC_SHA");
- addBoth( "SSL_RSA_WITH_RC4_128_MD5");
// TLSv1.2 cipher suites
addBoth( "TLS_RSA_WITH_AES_128_CBC_SHA256");
@@ -762,7 +757,6 @@
addOpenSsl("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256");
// Pre-Shared Key (PSK) cipher suites
- addOpenSsl("TLS_PSK_WITH_RC4_128_SHA");
addOpenSsl("TLS_PSK_WITH_AES_128_CBC_SHA");
addOpenSsl("TLS_PSK_WITH_AES_256_CBC_SHA");
addOpenSsl("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA");
@@ -801,6 +795,12 @@
addRi( "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256");
addNeither("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384");
+ // Android does not have RC4 support
+ addRi( "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA");
+ addRi( "TLS_ECDHE_RSA_WITH_RC4_128_SHA");
+ addRi( "SSL_RSA_WITH_RC4_128_SHA");
+ addRi( "SSL_RSA_WITH_RC4_128_MD5");
+
// Dropped
addNeither("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
addNeither("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");