am 1aea503e: Merge "Fix SimpleDateFormatTest when run outside California"

* commit '1aea503e8f568f9c17c14335783a89d41787e657':
  Fix SimpleDateFormatTest when run outside California
diff --git a/Android.mk b/Android.mk
index fd9bcd1..295f2c2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -50,4 +50,26 @@
 $(info ********************************************************************************)
 endif
 
+
+#
+# "m dalvik-host" for quick minimal host build
+#
+
+.PHONY: dalvik-host
+dalvik-host: \
+    dalvik \
+    $(HOST_OUT)/bin/dalvikvm \
+    $(HOST_OUT)/bin/dexopt \
+    $(HOST_OUT)/lib/libjavacore.so \
+    $(HOST_OUT)/lib/libjavacrypto.so \
+    $(HOST_OUT)/lib/libjavacoretests.so \
+    cacerts-host \
+    core-hostdex \
+    conscrypt-hostdex \
+    okhttp-hostdex \
+    bouncycastle-hostdex \
+    apache-xml-hostdex \
+    apache-harmony-tests-hostdex \
+    $(call intermediates-dir-for,JAVA_LIBRARIES,core-tests,,COMMON)/classes.jar
+
 include $(subdir_makefiles)
diff --git a/Docs.mk b/Docs.mk
index a163d1f..612b3d9 100644
--- a/Docs.mk
+++ b/Docs.mk
@@ -17,8 +17,8 @@
    dalvik/src/main/java/dalvik/annotation \
    dalvik/src/main/java/dalvik/bytecode \
    json/src/main/java \
-   libart/src/main/java/dalvik \
-   libart/src/main/java/java \
+   libdvm/src/main/java/dalvik \
+   libdvm/src/main/java/java \
    luni/src/main/java/android \
    luni/src/main/java/java \
    luni/src/main/java/javax \
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index c857390..8935b9a 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -62,6 +62,7 @@
 endif
 endif
 
+libdvm_core_src_files += $(common_core_src_files) $(call all-main-java-files-under,libdvm)
 libart_core_src_files += $(common_core_src_files) $(call all-main-java-files-under,libart)
 
 local_javac_flags=-encoding UTF-8
@@ -75,6 +76,18 @@
 # Definitions to make the core library.
 
 include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libdvm_core_src_files)
+LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVACFLAGS := $(local_javac_flags)
+LOCAL_DX_FLAGS := --core-library
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := core
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
+LOCAL_REQUIRED_MODULES := tzdata
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(libart_core_src_files)
 LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
@@ -95,7 +108,7 @@
 LOCAL_SRC_FILES := $(test_src_files)
 LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-libart okhttp core-junit bouncycastle
+LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit okhttp
 LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support sqlite-jdbc mockwebserver nist-pkix-tests
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_MODULE := core-tests
@@ -109,7 +122,7 @@
 LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
 LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-libart core-junit bouncycastle
+LOCAL_JAVA_LIBRARIES := bouncycastle core core-junit
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_MODULE := core-tests-support
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
@@ -122,7 +135,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-libart core-junit
+LOCAL_JAVA_LIBRARIES := core core-junit
 LOCAL_JAVACFLAGS := $(local_javac_flags)
 LOCAL_MODULE := jsr166-tests
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
@@ -156,6 +169,18 @@
 
 # Definitions to make the core library.
 include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libdvm_core_src_files)
+LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVACFLAGS := $(local_javac_flags)
+LOCAL_DX_FLAGS := --core-library
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := core-hostdex
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
+LOCAL_REQUIRED_MODULES := tzdata-host
+include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(libart_core_src_files)
 LOCAL_JAVA_RESOURCE_DIRS := $(core_resource_dirs)
 LOCAL_NO_STANDARD_LIBRARIES := true
@@ -175,8 +200,7 @@
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES := $(test_src_files)
     LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
-    LOCAL_NO_STANDARD_LIBRARIES := true
-    LOCAL_JAVA_LIBRARIES := core-libart-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex core-tests-support-hostdex
+    LOCAL_JAVA_LIBRARIES := bouncycastle-hostdex core-junit-hostdex core-tests-support-hostdex okhttp-hostdex
     LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-host nist-pkix-tests-host
     LOCAL_JAVACFLAGS := $(local_javac_flags)
     LOCAL_MODULE_TAGS := optional
@@ -190,8 +214,7 @@
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
     LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
-    LOCAL_NO_STANDARD_LIBRARIES := true
-    LOCAL_JAVA_LIBRARIES := core-libart-hostdex core-junit-hostdex bouncycastle-hostdex
+    LOCAL_JAVA_LIBRARIES := bouncycastle-hostdex core-junit-hostdex
     LOCAL_JAVACFLAGS := $(local_javac_flags)
     LOCAL_MODULE_TAGS := optional
     LOCAL_MODULE := core-tests-support-hostdex
diff --git a/NativeCode.mk b/NativeCode.mk
index 12e8114..0ae615e 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -66,7 +66,7 @@
 core_c_includes := libcore/include $(LOCAL_C_INCLUDES)
 core_shared_libraries := $(LOCAL_SHARED_LIBRARIES)
 core_static_libraries := $(LOCAL_STATIC_LIBRARIES)
-core_cflags := -Wall -Wextra -Werror
+core_cflags := $(LOCAL_CFLAGS) -Wall -Wextra -Werror
 core_cppflags += -std=gnu++11
 
 core_test_files := \
diff --git a/benchmarks/Android.mk b/benchmarks/Android.mk
index c0a38a0..b91894f 100644
--- a/benchmarks/Android.mk
+++ b/benchmarks/Android.mk
@@ -1,39 +1,34 @@
-# -*- mode: makefile -*-
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
 LOCAL_PATH:= $(call my-dir)
-
-ifeq ($(LIBCORE_SKIP_TESTS),)
-
 ##################################################
 include $(CLEAR_VARS)
-LOCAL_MODULE := benchmarks
+
+ifeq ($(LIBCORE_SKIP_TESTS),)
+# Only compile source java files in this apk.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := caliper-prebuilt core-tests
-LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-libart conscrypt core-junit bouncycastle framework
+
+LOCAL_MODULE := benchmarks
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+	caliper-prebuilt \
+	core-tests
+
+LOCAL_JAVA_LIBRARIES := \
+	bouncycastle \
+	conscrypt \
+	core
+
 LOCAL_MODULE_TAGS := tests
+
 LOCAL_MODULE_PATH := $(PRODUCT_OUT)/data/caliperperf
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
 include $(BUILD_JAVA_LIBRARY)
 
 ##################################################
 # Prebuilt Java libraries
 include $(CLEAR_VARS)
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := caliper-prebuilt:libs/caliper.jar
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-include $(BUILD_MULTI_PREBUILT)
 
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+	caliper-prebuilt:libs/caliper.jar
+
+include $(BUILD_MULTI_PREBUILT)
 endif
diff --git a/dalvik/src/main/java/dalvik/system/DexClassLoader.java b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
index ac2a70a5..a645f42 100644
--- a/dalvik/src/main/java/dalvik/system/DexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
@@ -24,9 +24,9 @@
  * installed as part of an application.
  *
  * <p>This class loader requires an application-private, writable directory to
- * cache optimized classes. Use {@code Context.getDir(String, int)} to create
+ * cache optimized classes. Use {@code Context.getCodeCacheDir()} to create
  * such a directory: <pre>   {@code
- *   File dexOutputDir = context.getDir("dex", 0);
+ *   File dexOutputDir = context.getCodeCacheDir();
  * }</pre>
  *
  * <p><strong>Do not cache optimized classes on external storage.</strong>
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 01991b0..7968c51 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1382,5 +1382,34 @@
   description: "Known failure in GregorianCalendarTest",
   bug: 12778197,
   name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
+},
+{
+  description: "SpdyConnection issue https://github.com/square/okhttp/issues/644 crashes the test app. Android does not provide SPDY/HTTP_2 connections by default so have been suppressed.",
+  bug: 14462336,
+  names: [
+    "com.squareup.okhttp.internal.spdy.SpdyConnectionTest",
+    "com.squareup.okhttp.internal.http.HttpOverHttp20Draft09Test",
+    "com.squareup.okhttp.internal.http.HttpOverSpdy3Test",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_SPDY_3",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_HTTP_2",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_SPDY_3",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_HTTP_2",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_SPDY_3",
+    "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPut_HTTP_2"
+  ]
+},
+{
+  description: "Okhttp test hardcodes the TLS version expected.",
+  bug: 14462336,
+  names: [
+    "com.squareup.okhttp.internal.http.URLConnectionTest#sslFallbackNotUsedWhenRecycledConnectionFails"
+  ]
+},
+{
+  description: "The test relies on SimpleDateFormat zzz producing GMT not GMT+00:00 as it does on Android. Android issue 66136.",
+  bug: 14462336,
+  names: [
+    "com.squareup.okhttp.internal.http.HttpResponseCacheTest#setIfModifiedSince"
+  ]
 }
 ]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 49e7868..d5d8191 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -23,8 +23,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.security.CodeSigner;
 import java.security.Permission;
 import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.Vector;
 import java.util.jar.Attributes;
@@ -92,6 +95,12 @@
 
     private final String emptyEntry3 = "svgunit.js";
 
+    private static final String VALID_CHAIN_JAR = "hyts_signed_validChain.jar";
+
+    private static final String INVALID_CHAIN_JAR = "hyts_signed_invalidChain.jar";
+
+    private static final String AMBIGUOUS_SIGNERS_JAR = "hyts_signed_ambiguousSignerArray.jar";
+
     private File resources;
 
     // custom security manager
@@ -641,6 +650,73 @@
                         + jarName + "\"", foundCerts);
     }
 
+    private static class Results {
+        public Certificate[] certificates;
+        public CodeSigner[] signers;
+    }
+
+    private Results getSignedJarCerts(String jarName) throws Exception {
+        Support_Resources.copyFile(resources, null, jarName);
+
+        File file = new File(resources, jarName);
+        Results results = new Results();
+
+        JarFile jarFile = new JarFile(file, true, ZipFile.OPEN_READ);
+        try {
+
+            Enumeration<JarEntry> e = jarFile.entries();
+            while (e.hasMoreElements()) {
+                JarEntry entry = e.nextElement();
+                InputStream is = jarFile.getInputStream(entry);
+                // Skip bytes because we have to read the entire file for it to read signatures.
+                is.skip(entry.getSize());
+                is.close();
+                Certificate[] certs = entry.getCertificates();
+                CodeSigner[] signers = entry.getCodeSigners();
+                if (certs != null && certs.length > 0) {
+                    results.certificates = certs;
+                    results.signers = signers;
+                    break;
+                }
+            }
+        } finally {
+            jarFile.close();
+        }
+
+        return results;
+    }
+
+    public void testJarFile_Signed_ValidChain() throws Exception {
+        Results result = getSignedJarCerts(VALID_CHAIN_JAR);
+        assertNotNull(result);
+        assertEquals(Arrays.deepToString(result.certificates), 3, result.certificates.length);
+        assertEquals(Arrays.deepToString(result.signers), 1, result.signers.length);
+        assertEquals(3, result.signers[0].getSignerCertPath().getCertificates().size());
+        assertEquals("CN=fake-chain", ((X509Certificate) result.certificates[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) result.certificates[1]).getSubjectDN().toString());
+        assertEquals("CN=root1", ((X509Certificate) result.certificates[2]).getSubjectDN().toString());
+    }
+
+    public void testJarFile_Signed_InvalidChain() throws Exception {
+        Results result = getSignedJarCerts(INVALID_CHAIN_JAR);
+        assertNotNull(result);
+        assertEquals(Arrays.deepToString(result.certificates), 3, result.certificates.length);
+        assertEquals(Arrays.deepToString(result.signers), 1, result.signers.length);
+        assertEquals(3, result.signers[0].getSignerCertPath().getCertificates().size());
+        assertEquals("CN=fake-chain", ((X509Certificate) result.certificates[0]).getSubjectDN().toString());
+        assertEquals("CN=intermediate1", ((X509Certificate) result.certificates[1]).getSubjectDN().toString());
+        assertEquals("CN=root1", ((X509Certificate) result.certificates[2]).getSubjectDN().toString());
+    }
+
+    public void testJarFile_Signed_AmbiguousSigners() throws Exception {
+        Results result = getSignedJarCerts(AMBIGUOUS_SIGNERS_JAR);
+        assertNotNull(result);
+        assertEquals(Arrays.deepToString(result.certificates), 2, result.certificates.length);
+        assertEquals(Arrays.deepToString(result.signers), 2, result.signers.length);
+        assertEquals(1, result.signers[0].getSignerCertPath().getCertificates().size());
+        assertEquals(1, result.signers[1].getSignerCertPath().getCertificates().size());
+    }
+
     /*
      * The jar created by 1.4 which does not provide a
      * algorithm-Digest-Manifest-Main-Attributes entry in .SF file.
diff --git a/libdvm/src/main/java/dalvik/system/VMRuntime.java b/libdvm/src/main/java/dalvik/system/VMRuntime.java
new file mode 100644
index 0000000..f117b70
--- /dev/null
+++ b/libdvm/src/main/java/dalvik/system/VMRuntime.java
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2007 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.system;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Provides an interface to VM-global, Dalvik-specific features.
+ * An application cannot create its own Runtime instance, and must obtain
+ * one from the getRuntime method.
+ *
+ * @hide
+ */
+public final class VMRuntime {
+
+    /**
+     * Holds the VMRuntime singleton.
+     */
+    private static final VMRuntime THE_ONE = new VMRuntime();
+
+    private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP
+            = new HashMap<String, String>();
+    static {
+        ABI_TO_INSTRUCTION_SET_MAP.put("armeabi", "arm");
+        ABI_TO_INSTRUCTION_SET_MAP.put("armeabi-v7a", "arm");
+        ABI_TO_INSTRUCTION_SET_MAP.put("mips", "mips");
+        ABI_TO_INSTRUCTION_SET_MAP.put("x86", "x86");
+    }
+
+    private int targetSdkVersion;
+
+    /**
+     * Prevents this class from being instantiated.
+     */
+    private VMRuntime() {
+    }
+
+    /**
+     * Returns the object that represents the VM instance's Dalvik-specific
+     * runtime environment.
+     *
+     * @return the runtime object
+     */
+    public static VMRuntime getRuntime() {
+        return THE_ONE;
+    }
+
+    /**
+     * Returns a copy of the VM's command-line property settings.
+     * These are in the form "name=value" rather than "-Dname=value".
+     */
+    public native String[] properties();
+
+    /**
+     * Returns the VM's boot class path.
+     */
+    public native String bootClassPath();
+
+    /**
+     * Returns the VM's class path.
+     */
+    public native String classPath();
+
+    /**
+     * Returns the VM's version.
+     */
+    public native String vmVersion();
+
+    /**
+     * Returns the name of the shared library providing the VM implementation.
+     */
+    public native String vmLibrary();
+
+    /**
+     * Returns the VM's instruction set.
+     */
+    public String vmInstructionSet() {
+        return "";
+    }
+
+    /**
+     * Returns whether the VM is running in 64-bit mode.
+     */
+    public boolean is64Bit() {
+        return false;
+    }
+
+    /**
+     * Returns whether the VM is running with JNI checking enabled.
+     */
+    public native boolean isCheckJniEnabled();
+
+    /**
+     * Gets the current ideal heap utilization, represented as a number
+     * between zero and one.  After a GC happens, the Dalvik heap may
+     * be resized so that (size of live objects) / (size of heap) is
+     * equal to this number.
+     *
+     * @return the current ideal heap utilization
+     */
+    public native float getTargetHeapUtilization();
+
+    /**
+     * Sets the current ideal heap utilization, represented as a number
+     * between zero and one.  After a GC happens, the Dalvik heap may
+     * be resized so that (size of live objects) / (size of heap) is
+     * equal to this number.
+     *
+     * <p>This is only a hint to the garbage collector and may be ignored.
+     *
+     * @param newTarget the new suggested ideal heap utilization.
+     *                  This value may be adjusted internally.
+     * @return the previous ideal heap utilization
+     * @throws IllegalArgumentException if newTarget is &lt;= 0.0 or &gt;= 1.0
+     */
+    public float setTargetHeapUtilization(float newTarget) {
+        if (newTarget <= 0.0f || newTarget >= 1.0f) {
+            throw new IllegalArgumentException(newTarget +
+                    " out of range (0,1)");
+        }
+        /* Synchronize to make sure that only one thread gets
+         * a given "old" value if both update at the same time.
+         * Allows for reliable save-and-restore semantics.
+         */
+        synchronized (this) {
+            float oldTarget = getTargetHeapUtilization();
+            nativeSetTargetHeapUtilization(newTarget);
+            return oldTarget;
+        }
+    }
+
+    /**
+     * Sets the target SDK version. Should only be called before the
+     * app starts to run, because it may change the VM's behavior in
+     * dangerous ways. Use 0 to mean "current" (since callers won't
+     * necessarily know the actual current SDK version, and the
+     * allocated version numbers start at 1), and 10000 to mean
+     * CUR_DEVELOPMENT.
+     */
+    public synchronized void setTargetSdkVersion(int targetSdkVersion) {
+        this.targetSdkVersion = targetSdkVersion;
+        setTargetSdkVersionNative(this.targetSdkVersion);
+    }
+
+    /**
+     * Gets the target SDK version. See {@link #setTargetSdkVersion} for
+     * special values.
+     */
+    public synchronized int getTargetSdkVersion() {
+        return targetSdkVersion;
+    }
+
+    private native void setTargetSdkVersionNative(int targetSdkVersion);
+
+    /**
+     * This method exists for binary compatibility.  It was part of a
+     * heap sizing API which was removed in Android 3.0 (Honeycomb).
+     */
+    @Deprecated
+    public long getMinimumHeapSize() {
+        return 0;
+    }
+
+    /**
+     * This method exists for binary compatibility.  It was part of a
+     * heap sizing API which was removed in Android 3.0 (Honeycomb).
+     */
+    @Deprecated
+    public long setMinimumHeapSize(long size) {
+        return 0;
+    }
+
+    /**
+     * This method exists for binary compatibility.  It used to
+     * perform a garbage collection that cleared SoftReferences.
+     */
+    @Deprecated
+    public void gcSoftReferences() {}
+
+    /**
+     * This method exists for binary compatibility.  It is equivalent
+     * to {@link System#runFinalization}.
+     */
+    @Deprecated
+    public void runFinalizationSync() {
+        System.runFinalization();
+    }
+
+    /**
+     * Implements setTargetHeapUtilization().
+     *
+     * @param newTarget the new suggested ideal heap utilization.
+     *                  This value may be adjusted internally.
+     */
+    private native void nativeSetTargetHeapUtilization(float newTarget);
+
+    /**
+     * This method exists for binary compatibility.  It was part of
+     * the external allocation API which was removed in Android 3.0 (Honeycomb).
+     */
+    @Deprecated
+    public boolean trackExternalAllocation(long size) {
+        return true;
+    }
+
+    /**
+     * This method exists for binary compatibility.  It was part of
+     * the external allocation API which was removed in Android 3.0 (Honeycomb).
+     */
+    @Deprecated
+    public void trackExternalFree(long size) {}
+
+    /**
+     * This method exists for binary compatibility.  It was part of
+     * the external allocation API which was removed in Android 3.0 (Honeycomb).
+     */
+    @Deprecated
+    public long getExternalBytesAllocated() {
+        return 0;
+    }
+
+    /**
+     * Tells the VM to enable the JIT compiler. If the VM does not have a JIT
+     * implementation, calling this method should have no effect.
+     */
+    public native void startJitCompilation();
+
+    /**
+     * Tells the VM to disable the JIT compiler. If the VM does not have a JIT
+     * implementation, calling this method should have no effect.
+     */
+    public native void disableJitCompilation();
+
+    /**
+     * Returns an array allocated in an area of the Java heap where it will never be moved.
+     * This is used to implement native allocations on the Java heap, such as DirectByteBuffers
+     * and Bitmaps.
+     */
+    public native Object newNonMovableArray(Class<?> componentType, int length);
+
+    /**
+     * Returns an array of at least minLength, but potentially larger. The increased size comes from
+     * avoiding any padding after the array. The amount of padding varies depending on the
+     * componentType and the memory allocator implementation.
+     */
+    public Object newUnpaddedArray(Class<?> componentType, int minLength) {
+        // Dalvik has 32bit pointers, the array header is 16bytes plus 4bytes for dlmalloc,
+        // allocations are 8byte aligned so having 4bytes of array data avoids padding.
+        if (!componentType.isPrimitive()) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return java.lang.reflect.Array.newInstance(componentType, size);
+        } else if (componentType == char.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new char[size];
+        } else if (componentType == int.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new int[size];
+        } else if (componentType == byte.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new byte[size];
+        } else if (componentType == boolean.class) {
+            int bytes = 20 + minLength;
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes;
+            return new boolean[size];
+        } else if (componentType == short.class) {
+            int bytes = 20 + (2 * minLength);
+            int alignedUpBytes = (bytes + 7) & -8;
+            int dataBytes = alignedUpBytes - 20;
+            int size = dataBytes / 2;
+            return new short[size];
+        } else if (componentType == float.class) {
+            int size = ((minLength & 1) == 0) ? minLength + 1 : minLength;
+            return new float[size];
+        } else if (componentType == long.class) {
+            return new long[minLength];
+        } else if (componentType == double.class) {
+            return new double[minLength];
+        } else {
+            assert componentType == void.class;
+            throw new IllegalArgumentException("Can't allocate an array of void");
+        }
+    }
+
+    /**
+     * Returns the address of array[0]. This differs from using JNI in that JNI might lie and
+     * give you the address of a copy of the array when in forcecopy mode.
+     */
+    public native long addressOf(Object array);
+
+    /**
+     * Removes any growth limits, allowing the application to allocate
+     * up to the maximum heap size.
+     */
+    public native void clearGrowthLimit();
+
+    /**
+     * Returns true if either a Java debugger or native debugger is active.
+     */
+    public native boolean isDebuggerActive();
+
+    /**
+     * Registers a native allocation so that the heap knows about it and performs GC as required.
+     * If the number of native allocated bytes exceeds the native allocation watermark, the
+     * function requests a concurrent GC. If the native bytes allocated exceeds a second higher
+     * watermark, it is determined that the application is registering native allocations at an
+     * unusually high rate and a GC is performed inside of the function to prevent memory usage
+     * from excessively increasing.
+     */
+    public native void registerNativeAllocation(int bytes);
+
+    /**
+     * Registers a native free by reducing the number of native bytes accounted for.
+     */
+    public native void registerNativeFree(int bytes);
+
+    /**
+     * Let the heap know of the new process state. This can change allocation and garbage collection
+     * behavior regarding trimming and compaction.
+     */
+    public native void updateProcessState(int state);
+
+    /**
+     * Fill in dex caches with classes, fields, and methods that are
+     * already loaded. Typically used after Zygote preloading.
+     */
+    public native void preloadDexCaches();
+
+    /**
+     * Register application info
+     */
+    public static void registerAppInfo(String appDir, String processName, String pkgname) {
+        // Nothing to do in dalvik.
+    }
+
+    /**
+     * Returns the runtime instruction set corresponding to a given ABI. Multiple
+     * compatible ABIs might map to the same instruction set. For example
+     * {@code armeabi-v7a} and {@code armeabi} might map to the instruction set {@code arm}.
+     *
+     * This influences the compilation of the applications classes.
+     */
+    public static String getInstructionSet(String abi) {
+        final String instructionSet = ABI_TO_INSTRUCTION_SET_MAP.get(abi);
+        if (instructionSet == null) {
+            throw new IllegalArgumentException("Unsupported ABI: " + abi);
+        }
+
+        return instructionSet;
+    }
+
+    public static boolean is64BitInstructionSet(String instructionSet) {
+        return false;
+    }
+
+    public static boolean is64BitAbi(String abi) {
+        return false;
+    }
+}
diff --git a/libdvm/src/main/java/dalvik/system/VMStack.java b/libdvm/src/main/java/dalvik/system/VMStack.java
new file mode 100644
index 0000000..bae1829
--- /dev/null
+++ b/libdvm/src/main/java/dalvik/system/VMStack.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 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.system;
+
+/**
+ * Provides a limited interface to the Dalvik VM stack. This class is mostly
+ * used for implementing security checks.
+ *
+ * @hide
+ */
+public final class VMStack {
+    /**
+     * Returns the defining class loader of the caller's caller.
+     *
+     * @return the requested class loader, or {@code null} if this is the
+     *         bootstrap class loader.
+     */
+    native public static ClassLoader getCallingClassLoader();
+
+    /**
+     * Returns the class of the caller's caller's caller.
+     *
+     * @return the requested class, or {@code null}.
+     */
+    native public static Class<?> getStackClass2();
+
+    /**
+     * Creates an array of classes from the methods at the top of the stack.
+     * We continue until we reach the bottom of the stack or exceed the
+     * specified maximum depth.
+     * <p>
+     * The topmost stack frame (this method) and the one above that (the
+     * caller) are excluded from the array.  Frames with java.lang.reflect
+     * classes are skipped over.
+     * <p>
+     * The classes in the array are the defining classes of the methods.
+     * <p>
+     * This is similar to Harmony's VMStack.getClasses, except that this
+     * implementation doesn't have a concept of "privileged" frames.
+     *
+     * @param maxDepth
+     *      maximum number of classes to return, or -1 for all
+     * @return an array with classes for the most-recent methods on the stack
+     */
+    native public static Class<?>[] getClasses(int maxDepth);
+
+    /**
+     * Returns the first ClassLoader on the call stack that isn't either of
+     * the passed-in ClassLoaders.
+     */
+    public static ClassLoader getClosestUserClassLoader(ClassLoader bootstrap,
+                                                        ClassLoader system) {
+        Class<?>[] stackClasses = VMStack.getClasses(-1);
+        for (Class<?> stackClass : stackClasses) {
+            ClassLoader loader = stackClass.getClassLoader();
+            if (loader != null && loader != bootstrap && loader != system) {
+                return loader;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Retrieves the stack trace from the specified thread.
+     *
+     * @param t
+     *      thread of interest
+     * @return an array of stack trace elements, or null if the thread
+     *      doesn't have a stack trace (e.g. because it exited)
+     */
+    native public static StackTraceElement[] getThreadStackTrace(Thread t);
+
+    /**
+     * Retrieves a partial stack trace from the specified thread into
+     * the provided array.
+     *
+     * @param t
+     *      thread of interest
+     * @param stackTraceElements
+     *      preallocated array for use when only the top of stack is
+     *      desired. Unused elements will be filled with null values.
+     * @return the number of elements filled
+     */
+    native public static int fillStackTraceElements(Thread t,
+        StackTraceElement[] stackTraceElements);
+}
diff --git a/libdvm/src/main/java/java/lang/Class.java b/libdvm/src/main/java/java/lang/Class.java
new file mode 100644
index 0000000..af6278d
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/Class.java
@@ -0,0 +1,1354 @@
+/*
+ * 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) 2006-2007 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;
+
+import com.android.dex.Dex;
+import dalvik.system.VMStack;
+import java.io.InputStream;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Inherited;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import org.apache.harmony.kernel.vm.StringUtils;
+import libcore.reflect.AnnotationAccess;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.InternalNames;
+import libcore.reflect.Types;
+import libcore.util.BasicLruCache;
+import libcore.util.CollectionUtils;
+import libcore.util.EmptyArray;
+
+/**
+ * The in-memory representation of a Java class. This representation serves as
+ * the starting point for querying class-related information, a process usually
+ * called "reflection". There are basically three types of {@code Class}
+ * instances: those representing real classes and interfaces, those representing
+ * primitive types, and those representing array classes.
+ *
+ * <h4>Class instances representing object types (classes or interfaces)</h4>
+ * <p>
+ * These represent an ordinary class or interface as found in the class
+ * hierarchy. The name associated with these {@code Class} instances is simply
+ * the fully qualified class name of the class or interface that it represents.
+ * In addition to this human-readable name, each class is also associated by a
+ * so-called <em>signature</em>, which is the letter "L", followed by the
+ * class name and a semicolon (";"). The signature is what the runtime system
+ * uses internally for identifying the class (for example in a DEX file).
+ * </p>
+ * <h4>Classes representing primitive types</h4>
+ * <p>
+ * These represent the standard Java primitive types and hence share their
+ * names (for example "int" for the {@code int} primitive type). Although it is
+ * not possible to create new instances based on these {@code Class} instances,
+ * they are still useful for providing reflection information, and as the
+ * component type of array classes. There is one {@code Class} instance for each
+ * primitive type, and their signatures are:
+ * </p>
+ * <ul>
+ * <li>{@code B} representing the {@code byte} primitive type</li>
+ * <li>{@code S} representing the {@code short} primitive type</li>
+ * <li>{@code I} representing the {@code int} primitive type</li>
+ * <li>{@code J} representing the {@code long} primitive type</li>
+ * <li>{@code F} representing the {@code float} primitive type</li>
+ * <li>{@code D} representing the {@code double} primitive type</li>
+ * <li>{@code C} representing the {@code char} primitive type</li>
+ * <li>{@code Z} representing the {@code boolean} primitive type</li>
+ * <li>{@code V} representing void function return values</li>
+ * </ul>
+ * <p>
+ * <h4>Classes representing array classes</h4>
+ * <p>
+ * These represent the classes of Java arrays. There is one such {@code Class}
+ * instance per combination of array leaf component type and arity (number of
+ * dimensions). In this case, the name associated with the {@code Class}
+ * consists of one or more left square brackets (one per dimension in the array)
+ * followed by the signature of the class representing the leaf component type,
+ * which can be either an object type or a primitive type. The signature of a
+ * {@code Class} representing an array type is the same as its name. Examples
+ * of array class signatures are:
+ * </p>
+ * <ul>
+ * <li>{@code [I} representing the {@code int[]} type</li>
+ * <li>{@code [Ljava/lang/String;} representing the {@code String[]} type</li>
+ * <li>{@code [[[C} representing the {@code char[][][]} type (three dimensions!)</li>
+ * </ul>
+ */
+public final class Class<T> implements Serializable, AnnotatedElement, GenericDeclaration, Type {
+
+    private static final long serialVersionUID = 3206093459760846163L;
+
+    /**
+     * Class def index from dex file. An index of -1 indicates that there is no class definition,
+     * for example for an array type.
+     */
+    private transient int dexClassDefIndex;
+
+    /** The type index of this class within the dex file that defines it. */
+    private transient int dexTypeIndex;
+
+    /**
+     * Have we computed the type and class def indices? Volatile to avoid double check locking bugs.
+     */
+    private transient volatile boolean dexIndicesInitialized;
+
+    /**
+     * Lazily computed name of this class; always prefer calling getName().
+     */
+    private transient String name;
+
+    private Class() {
+        // Prevent this class to be instantiated, instance
+        // should be created by JVM only
+    }
+
+    /**
+     * Returns the dex file from which this class was loaded.
+     * @hide
+     */
+    public native Dex getDex();
+
+    /** Lazily compute indices in to Dex */
+    private synchronized void computeDexIndices() {
+        if (!dexIndicesInitialized) {
+            Dex dex = getDex();
+            dexTypeIndex = dex.findTypeIndex(InternalNames.getInternalName(this));
+            if (dexTypeIndex < 0) {
+                dexTypeIndex = -1;
+                dexClassDefIndex = -1;
+            } else {
+                dexClassDefIndex = dex.findClassDefIndexFromTypeIndex(dexTypeIndex);
+            }
+            dexIndicesInitialized = true;
+        }
+    }
+
+    /**
+     * The class def of this class in its own Dex, or -1 if there is no class def.
+     *
+     * @hide
+     */
+    public int getDexClassDefIndex() {
+        if (!dexIndicesInitialized) {
+            computeDexIndices();
+        }
+        return dexClassDefIndex;
+    }
+
+    /**
+     * The type index of this class in its own Dex, or -1 if it is unknown. If a class is referenced
+     * by multiple Dex files, it will have a different type index in each. Dex files support 65534
+     * type indices, with 65535 representing no index.
+     *
+     * @hide
+     */
+    public int getDexTypeIndex() {
+        if (!dexIndicesInitialized) {
+            computeDexIndices();
+        }
+        return dexTypeIndex;
+    }
+
+    /**
+     * Returns a {@code Class} object which represents the class with the
+     * given name. The name should be the name of a non-primitive class, as described in
+     * the {@link Class class definition}.
+     * Primitive types can not be found using this method; use {@code int.class} or {@code Integer.TYPE} instead.
+     *
+     * <p>If the class has not yet been loaded, it is loaded and initialized
+     * first. This is done through either the class loader of the calling class
+     * or one of its parent class loaders. It is possible that a static initializer is run as
+     * a result of this call.
+     *
+     * @throws ClassNotFoundException
+     *             if the requested class can not be found.
+     * @throws LinkageError
+     *             if an error occurs during linkage
+     * @throws ExceptionInInitializerError
+     *             if an exception occurs during static initialization of a
+     *             class.
+     */
+    public static Class<?> forName(String className) throws ClassNotFoundException {
+        return forName(className, true, VMStack.getCallingClassLoader());
+    }
+
+    /**
+     * Returns a {@code Class} object which represents the class with the
+     * given name. The name should be the name of a non-primitive class, as described in
+     * the {@link Class class definition}.
+     * Primitive types can not be found using this method; use {@code int.class} or {@code Integer.TYPE} instead.
+     *
+     * <p>If the class has not yet been loaded, it is loaded first, using the given class loader.
+     * If the class has not yet been initialized and {@code shouldInitialize} is true,
+     * the class will be initialized.
+     *
+     * @throws ClassNotFoundException
+     *             if the requested class can not be found.
+     * @throws LinkageError
+     *             if an error occurs during linkage
+     * @throws ExceptionInInitializerError
+     *             if an exception occurs during static initialization of a
+     *             class.
+     */
+    public static Class<?> forName(String className, boolean shouldInitialize,
+            ClassLoader classLoader) throws ClassNotFoundException {
+
+        if (classLoader == null) {
+            classLoader = ClassLoader.getSystemClassLoader();
+        }
+        // Catch an Exception thrown by the underlying native code. It wraps
+        // up everything inside a ClassNotFoundException, even if e.g. an
+        // Error occurred during initialization. This as a workaround for
+        // an ExceptionInInitializerError that's also wrapped. It is actually
+        // expected to be thrown. Maybe the same goes for other errors.
+        // Not wrapping up all the errors will break android though.
+        Class<?> result;
+        try {
+            result = classForName(className, shouldInitialize,
+                    classLoader);
+        } catch (ClassNotFoundException e) {
+            Throwable cause = e.getCause();
+            if (cause instanceof ExceptionInInitializerError) {
+                throw (ExceptionInInitializerError) cause;
+            }
+            throw e;
+        }
+        return result;
+    }
+
+    private static native Class<?> classForName(String className, boolean shouldInitialize,
+            ClassLoader classLoader) throws ClassNotFoundException;
+
+    /**
+     * Returns an array containing {@code Class} objects for all public classes
+     * and interfaces that are members of this class. This includes public
+     * members inherited from super classes and interfaces. If there are no such
+     * class members or if this object represents a primitive type then an array
+     * of length 0 is returned.
+     */
+    public Class<?>[] getClasses() {
+        Class<?>[] result = getDeclaredClasses(this, true);
+        // Traverse all superclasses.
+        for (Class<?> c = this.getSuperclass(); c != null; c = c.getSuperclass()) {
+            Class<?>[] temp = getDeclaredClasses(c, true);
+            if (temp.length != 0) {
+                result = arraycopy(new Class[result.length + temp.length], result, temp);
+            }
+        }
+        return result;
+    }
+
+    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+
+        A annotation = getDeclaredAnnotation(annotationType);
+        if (annotation != null) {
+            return annotation;
+        }
+
+        if (annotationType.isAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                annotation = sup.getDeclaredAnnotation(annotationType);
+                if (annotation != null) {
+                    return annotation;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an array containing all the annotations of this class. If there are no annotations
+     * then an empty array is returned.
+     *
+     * @see #getDeclaredAnnotations()
+     */
+    public Annotation[] getAnnotations() {
+        /*
+         * We need to get the annotations declared on this class, plus the
+         * annotations from superclasses that have the "@Inherited" annotation
+         * set.  We create a temporary map to use while we accumulate the
+         * annotations and convert it to an array at the end.
+         *
+         * It's possible to have duplicates when annotations are inherited.
+         * We use a Map to filter those out.
+         *
+         * HashMap might be overkill here.
+         */
+        HashMap<Class, Annotation> map = new HashMap<Class, Annotation>();
+        Annotation[] declaredAnnotations = getDeclaredAnnotations();
+
+        for (int i = declaredAnnotations.length-1; i >= 0; --i) {
+            map.put(declaredAnnotations[i].annotationType(), declaredAnnotations[i]);
+        }
+        for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+            declaredAnnotations = sup.getDeclaredAnnotations();
+            for (int i = declaredAnnotations.length-1; i >= 0; --i) {
+                Class<?> clazz = declaredAnnotations[i].annotationType();
+                if (!map.containsKey(clazz) && clazz.isAnnotationPresent(Inherited.class)) {
+                    map.put(clazz, declaredAnnotations[i]);
+                }
+            }
+        }
+
+        /* convert annotation values from HashMap to array */
+        Collection<Annotation> coll = map.values();
+        return coll.toArray(new Annotation[coll.size()]);
+    }
+
+    /**
+     * Returns the canonical name of this class. If this class does not have a
+     * canonical name as defined in the Java Language Specification, then the
+     * method returns {@code null}.
+     */
+    public String getCanonicalName() {
+        if (isLocalClass() || isAnonymousClass())
+            return null;
+
+        if (isArray()) {
+            /*
+             * The canonical name of an array type depends on the (existence of)
+             * the component type's canonical name.
+             */
+            String name = getComponentType().getCanonicalName();
+            if (name != null) {
+                return name + "[]";
+            }
+        } else if (isMemberClass()) {
+            /*
+             * The canonical name of an inner class depends on the (existence
+             * of) the declaring class' canonical name.
+             */
+            String name = getDeclaringClass().getCanonicalName();
+            if (name != null) {
+                return name + "." + getSimpleName();
+            }
+        } else {
+            /*
+             * The canonical name of a top-level class or primitive type is
+             * equal to the fully qualified name.
+             */
+            return getName();
+        }
+
+        /*
+         * Other classes don't have a canonical name.
+         */
+        return null;
+    }
+
+    /**
+     * Returns the class loader which was used to load the class represented by
+     * this {@code Class}. Implementations are free to return {@code null} for
+     * classes that were loaded by the bootstrap class loader. The Android
+     * reference implementation, though, always returns a reference to an actual
+     * class loader.
+     */
+    public ClassLoader getClassLoader() {
+        if (this.isPrimitive()) {
+            return null;
+        }
+
+        ClassLoader loader = getClassLoaderImpl();
+        if (loader == null) {
+            loader = BootClassLoader.getInstance();
+        }
+        return loader;
+    }
+
+    /**
+     * This must be provided by the VM vendor, as it is used by other provided
+     * class implementations in this package. Outside of this class, it is used
+     * by SecurityManager.classLoaderDepth(),
+     * currentClassLoader() and currentLoadedClass(). Return the ClassLoader for
+     * this Class without doing any security checks. The bootstrap ClassLoader
+     * is returned, unlike getClassLoader() which returns null in place of the
+     * bootstrap ClassLoader.
+     */
+    ClassLoader getClassLoaderImpl() {
+        ClassLoader loader = getClassLoader(this);
+        return loader == null ? BootClassLoader.getInstance() : loader;
+    }
+
+    /*
+     * Returns the defining class loader for the given class.
+     */
+    private static native ClassLoader getClassLoader(Class<?> c);
+
+    /**
+     * Returns a {@code Class} object which represents the component type if
+     * this class represents an array type. Returns {@code null} if this class
+     * does not represent an array type. The component type of an array type is
+     * the type of the elements of the array.
+     */
+    public native Class<?> getComponentType();
+
+    /**
+     * Returns a {@code Constructor} object which represents the public
+     * constructor matching the given parameter types.
+     * {@code (Class[]) null} is equivalent to the empty array.
+     *
+     * <p>See {@link #getMethod} for details of the search order.
+     * Use {@link #getDeclaredConstructor} if you don't want to search superclasses.
+     *
+     * @throws NoSuchMethodException
+     *             if the constructor can not be found.
+     */
+    @SuppressWarnings("unchecked")
+    public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException {
+        return (Constructor) getConstructorOrMethod("<init>", false, true, parameterTypes);
+    }
+
+    /**
+     * Returns a constructor or method with the given name. Use "<init>" to return a constructor.
+     */
+    private Member getConstructorOrMethod(String name, boolean searchSuperTypes,
+            boolean publicOnly, Class<?>[] parameterTypes) throws NoSuchMethodException {
+        if (searchSuperTypes && !publicOnly) {
+            throw new AssertionError(); // can't lookup non-public members recursively
+        }
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        if (parameterTypes == null) {
+            parameterTypes = EmptyArray.CLASS;
+        }
+        for (Class<?> c : parameterTypes) {
+            if (c == null) {
+                throw new NoSuchMethodException("parameter type is null");
+            }
+        }
+        Member result = searchSuperTypes
+                ? getPublicConstructorOrMethodRecursive(name, parameterTypes)
+                : Class.getDeclaredConstructorOrMethod(this, name, parameterTypes);
+        if (result == null || publicOnly && (result.getModifiers() & Modifier.PUBLIC) == 0) {
+            throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
+        }
+        return result;
+    }
+
+    private Member getPublicConstructorOrMethodRecursive(String name, Class<?>[] parameterTypes) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            Member result = Class.getDeclaredConstructorOrMethod(c, name, parameterTypes);
+            if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+                return result;
+            }
+        }
+
+        // search implemented interfaces
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Class<?> ifc : c.getInterfaces()) {
+                Member result = ifc.getPublicConstructorOrMethodRecursive(name, parameterTypes);
+                if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+                    return result;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an array containing {@code Constructor} objects for all public
+     * constructors for this {@code Class}. If there
+     * are no public constructors or if this {@code Class} represents an array
+     * class, a primitive type or void then an empty array is returned.
+     *
+     * @see #getDeclaredConstructors()
+     */
+    public Constructor<?>[] getConstructors() {
+        return getDeclaredConstructors(this, true);
+    }
+
+    /**
+     * Returns the annotations that are directly defined on the class
+     * represented by this {@code Class}. Annotations that are inherited are not
+     * included in the result. If there are no annotations at all, an empty
+     * array is returned.
+     *
+     * @see #getAnnotations()
+     */
+    public native Annotation[] getDeclaredAnnotations();
+
+    /**
+     * Returns the annotation if it exists.
+     */
+    native private <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass);
+
+    /**
+     * Returns true if the annotation exists.
+     */
+    native private boolean isDeclaredAnnotationPresent(Class<? extends Annotation> annotationClass);
+
+    /**
+     * Returns an array containing {@code Class} objects for all classes and
+     * interfaces that are declared as members of the class which this {@code
+     * Class} represents. If there are no classes or interfaces declared or if
+     * this class represents an array class, a primitive type or void, then an
+     * empty array is returned.
+     */
+    public Class<?>[] getDeclaredClasses() {
+        return getDeclaredClasses(this, false);
+    }
+
+    /*
+     * Returns the list of member classes of the given class.
+     * If no members exist, an empty array is returned.
+     */
+    private static native Class<?>[] getDeclaredClasses(Class<?> c, boolean publicOnly);
+
+    /**
+     * Returns a {@code Constructor} object which represents the constructor
+     * matching the given parameter types that is declared by the class
+     * represented by this {@code Class}.
+     * {@code (Class[]) null} is equivalent to the empty array.
+     *
+     * <p>Use {@link #getConstructor} if you want to search superclasses.
+     *
+     * @throws NoSuchMethodException
+     *             if the requested constructor can not be found.
+     */
+    @SuppressWarnings("unchecked")
+    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
+            throws NoSuchMethodException {
+        return (Constructor) getConstructorOrMethod("<init>", false, false, parameterTypes);
+    }
+
+    /**
+     * Returns an array containing {@code Constructor} objects for all
+     * constructors declared in the class represented by this {@code Class}. If
+     * there are no constructors or if this {@code Class} represents an array
+     * class, a primitive type, or void then an empty array is returned.
+     *
+     * @see #getConstructors()
+     */
+    public Constructor<?>[] getDeclaredConstructors() {
+        return getDeclaredConstructors(this, false);
+    }
+
+    /*
+     * Returns the list of constructors. If no constructors exist, an empty array is returned.
+     */
+    private static native <T> Constructor<T>[] getDeclaredConstructors(Class<T> c,
+                                                                       boolean publicOnly);
+
+    /**
+     * Returns a {@code Field} object for the field with the given name
+     * which is declared in the class represented by this {@code Class}.
+     *
+     * @throws NoSuchFieldException if the requested field can not be found.
+     * @see #getField(String)
+     */
+    public Field getDeclaredField(String name) throws NoSuchFieldException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        Field result = getDeclaredField(this, name);
+        if (result == null) {
+            throw new NoSuchFieldException(name);
+        }
+        return result;
+    }
+
+    /**
+     * Returns an array containing {@code Field} objects for all fields declared
+     * in the class represented by this {@code Class}. If there are no fields or
+     * if this {@code Class} represents an array class, a primitive type or void
+     * then an empty array is returned.
+     *
+     * @see #getFields()
+     */
+    public Field[] getDeclaredFields() {
+        return getDeclaredFields(this, false);
+    }
+
+    /*
+     * Returns the list of fields without performing any security checks
+     * first. If no fields exist at all, an empty array is returned.
+     */
+    static native Field[] getDeclaredFields(Class<?> c, boolean publicOnly);
+
+    /**
+     * Returns the field if it is defined by {@code c}; null otherwise. This
+     * may return a non-public member.
+     */
+    static native Field getDeclaredField(Class<?> c, String name);
+
+    /**
+     * Returns a {@code Method} object which represents the method matching the
+     * given name and parameter types that is declared by the class
+     * represented by this {@code Class}.
+     * {@code (Class[]) null} is equivalent to the empty array.
+     *
+     * <p>See {@link #getMethod} if you want to search superclasses.
+     *
+     * @throws NoSuchMethodException
+     *             if the requested method can not be found.
+     * @throws NullPointerException
+     *             if {@code name} is {@code null}.
+     */
+    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
+            throws NoSuchMethodException {
+        Member member = getConstructorOrMethod(name, false, false, parameterTypes);
+        if (member instanceof Constructor) {
+            throw new NoSuchMethodException(name);
+        }
+        return (Method) member;
+    }
+
+    /**
+     * Returns an array containing {@code Method} objects for all methods
+     * declared in the class represented by this {@code Class}. If there are no
+     * methods or if this {@code Class} represents an array class, a primitive
+     * type or void then an empty array is returned.
+     *
+     * @see #getMethods()
+     */
+    public Method[] getDeclaredMethods() {
+        return getDeclaredMethods(this, false);
+    }
+
+    /**
+     * Returns the list of methods. If no methods exist, an empty array is returned.
+     */
+    static native Method[] getDeclaredMethods(Class<?> c, boolean publicOnly);
+
+    /**
+     * Returns the constructor or method if it is defined by {@code c}; null
+     * otherwise. This may return a non-public member. Use "<init>" to get a constructor.
+     */
+    static native Member getDeclaredConstructorOrMethod(Class c, String name, Class[] args);
+
+    /**
+     * Returns the declaring {@code Class} of this {@code Class}. Returns
+     * {@code null} if the class is not a member of another class or if this
+     * {@code Class} represents an array class, a primitive type, or void.
+     */
+    public native Class<?> getDeclaringClass();
+
+    /**
+     * Returns the enclosing {@code Class} of this {@code Class}. If there is no
+     * enclosing class the method returns {@code null}.
+     */
+    public native Class<?> getEnclosingClass();
+
+    /**
+     * Returns the enclosing {@code Constructor} of this {@code Class}, if it is an
+     * anonymous or local/automatic class; otherwise {@code null}.
+     */
+    public native Constructor<?> getEnclosingConstructor();
+
+    /**
+     * Returns the enclosing {@code Method} of this {@code Class}, if it is an
+     * anonymous or local/automatic class; otherwise {@code null}.
+     */
+    public native Method getEnclosingMethod();
+
+    /**
+     * Returns the {@code enum} constants associated with this {@code Class}.
+     * Returns {@code null} if this {@code Class} does not represent an {@code
+     * enum} type.
+     */
+    @SuppressWarnings("unchecked") // we only cast after confirming that this class is an enum
+    public T[] getEnumConstants() {
+        if (!isEnum()) {
+            return null;
+        }
+        return (T[]) Enum.getSharedConstants((Class) this).clone();
+    }
+
+    /**
+     * Returns a {@code Field} object which represents the public field with the
+     * given name. This method first searches the class C represented by
+     * this {@code Class}, then the interfaces implemented by C and finally the
+     * superclasses of C.
+     *
+     * @throws NoSuchFieldException
+     *             if the field can not be found.
+     * @see #getDeclaredField(String)
+     */
+    public Field getField(String name) throws NoSuchFieldException {
+        if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        Field result = getPublicFieldRecursive(name);
+        if (result == null) {
+            throw new NoSuchFieldException(name);
+        }
+        return result;
+    }
+
+    private Field getPublicFieldRecursive(String name) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            Field result = Class.getDeclaredField(c, name);
+            if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+                return result;
+            }
+        }
+
+        // search implemented interfaces
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Class<?> ifc : c.getInterfaces()) {
+                Field result = ifc.getPublicFieldRecursive(name);
+                if (result != null && (result.getModifiers() & Modifier.PUBLIC) != 0) {
+                    return result;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns an array containing {@code Field} objects for all public fields
+     * for the class C represented by this {@code Class}. Fields may be declared
+     * in C, the interfaces it implements or in the superclasses of C. The
+     * elements in the returned array are in no particular order.
+     *
+     * <p>If there are no public fields or if this class represents an array class,
+     * a primitive type or {@code void} then an empty array is returned.
+     *
+     * @see #getDeclaredFields()
+     */
+    public Field[] getFields() {
+        List<Field> fields = new ArrayList<Field>();
+        getPublicFieldsRecursive(fields);
+
+        /*
+         * The result may include duplicates when this class implements an interface
+         * through multiple paths. Remove those duplicates.
+         */
+        CollectionUtils.removeDuplicates(fields, Field.ORDER_BY_NAME_AND_DECLARING_CLASS);
+        return fields.toArray(new Field[fields.size()]);
+    }
+
+    /**
+     * Populates {@code result} with public fields defined by this class, its
+     * superclasses, and all implemented interfaces.
+     */
+    private void getPublicFieldsRecursive(List<Field> result) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Field field : Class.getDeclaredFields(c, true)) {
+                result.add(field);
+            }
+        }
+
+        // search implemented interfaces
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Class<?> ifc : c.getInterfaces()) {
+                ifc.getPublicFieldsRecursive(result);
+            }
+        }
+    }
+
+    /**
+     * Returns the {@link Type}s of the interfaces that this {@code Class} directly
+     * implements. If the {@code Class} represents a primitive type or {@code
+     * void} then an empty array is returned.
+     */
+    public Type[] getGenericInterfaces() {
+        Type[] result;
+        synchronized (Caches.genericInterfaces) {
+            result = Caches.genericInterfaces.get(this);
+            if (result == null) {
+                String annotationSignature = AnnotationAccess.getSignature(this);
+                if (annotationSignature == null) {
+                    result = getInterfaces();
+                } else {
+                    GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+                    parser.parseForClass(this, annotationSignature);
+                    result = Types.getTypeArray(parser.interfaceTypes, false);
+                }
+                Caches.genericInterfaces.put(this, result);
+            }
+        }
+        return (result.length == 0) ? result : result.clone();
+    }
+
+    /**
+     * Returns the {@code Type} that represents the superclass of this {@code
+     * class}.
+     */
+    public Type getGenericSuperclass() {
+        Type genericSuperclass = getSuperclass();
+        // This method is specified to return null for all cases where getSuperclass
+        // returns null, i.e, for primitives, interfaces, void and java.lang.Object.
+
+        if (genericSuperclass == null) {
+            return null;
+        }
+        String annotationSignature = AnnotationAccess.getSignature(this);
+        if (annotationSignature != null) {
+            GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+            parser.parseForClass(this, annotationSignature);
+            genericSuperclass = parser.superclassType;
+        }
+        return Types.getType(genericSuperclass);
+    }
+
+    /**
+     * Returns an array of {@code Class} objects that match the interfaces
+     * in the {@code implements} declaration of the class represented
+     * by this {@code Class}. The order of the elements in the array is
+     * identical to the order in the original class declaration. If the class
+     * does not implement any interfaces, an empty array is returned.
+     */
+    public native Class<?>[] getInterfaces();
+
+    /**
+     * Returns a {@code Method} object which represents the public method with
+     * the given name and parameter types.
+     * {@code (Class[]) null} is equivalent to the empty array.
+     *
+     * <p>This method first searches the class C represented by this {@code Class},
+     * then the superclasses of C,
+     * and finally the interfaces implemented by C and its superclasses.
+     *
+     * <p>Use {@link #getDeclaredMethod} if you don't want to search superclasses.
+     *
+     * @throws NoSuchMethodException
+     *             if the method can not be found.
+     */
+    public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException {
+        Member member = getConstructorOrMethod(name, true, true, parameterTypes);
+        if (member instanceof Constructor) {
+            throw new NoSuchMethodException(name);
+        }
+        return (Method) member;
+    }
+
+    /**
+     * Returns an array containing {@code Method} objects for all public methods
+     * for the class C represented by this {@code Class}. Methods may be
+     * declared in C, the interfaces it implements or in the superclasses of C.
+     * The elements in the returned array are in no particular order.
+     *
+     * <p>If there are no public methods or if this {@code Class} represents a
+     * primitive type or {@code void} then an empty array is returned.
+     *
+     * @see #getDeclaredMethods()
+     */
+    public Method[] getMethods() {
+        List<Method> methods = new ArrayList<Method>();
+        getPublicMethodsRecursive(methods);
+
+        /*
+         * Remove methods defined by multiple types, preferring to keep methods
+         * declared by derived types.
+         */
+        CollectionUtils.removeDuplicates(methods, Method.ORDER_BY_SIGNATURE);
+        return methods.toArray(new Method[methods.size()]);
+    }
+
+    /**
+     * Populates {@code result} with public methods defined by this class, its
+     * superclasses, and all implemented interfaces, including overridden methods.
+     */
+    private void getPublicMethodsRecursive(List<Method> result) {
+        // search superclasses
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Method method : Class.getDeclaredMethods(c, true)) {
+                result.add(method);
+            }
+        }
+
+        // search implemented interfaces
+        for (Class<?> c = this; c != null; c = c.getSuperclass()) {
+            for (Class<?> ifc : c.getInterfaces()) {
+                ifc.getPublicMethodsRecursive(result);
+            }
+        }
+    }
+
+    /**
+     * Returns an integer that represents the modifiers of the class represented
+     * by this {@code Class}. The returned value is a combination of bits
+     * defined by constants in the {@link Modifier} class.
+     */
+    public int getModifiers() {
+        return getModifiers(this, false);
+    }
+
+    /*
+     * Returns the modifiers for the given class.
+     *
+     * {@code ignoreInnerClassesAttrib} determines whether we look for and use the
+     *     flags from an "inner class" attribute
+     */
+    private static native int getModifiers(Class<?> clazz, boolean ignoreInnerClassesAttrib);
+
+    /**
+     * Returns the name of the class represented by this {@code Class}. For a
+     * description of the format which is used, see the class definition of
+     * {@link Class}.
+     */
+    public String getName() {
+        String result = name;
+        return (result == null) ? (name = getNameNative()) : result;
+    }
+
+    private native String getNameNative();
+
+    /**
+     * Returns the simple name of the class represented by this {@code Class} as
+     * defined in the source code. If there is no name (that is, the class is
+     * anonymous) then an empty string is returned. If the receiver is an array
+     * then the name of the underlying type with square braces appended (for
+     * example {@code "Integer[]"}) is returned.
+     *
+     * @return the simple name of the class represented by this {@code Class}.
+     */
+    public String getSimpleName() {
+        if (isArray()) {
+            return getComponentType().getSimpleName() + "[]";
+        }
+
+        String name = getName();
+
+        if (isAnonymousClass()) {
+            return "";
+        }
+
+        if (isMemberClass() || isLocalClass()) {
+            return getInnerClassName();
+        }
+
+        int dot = name.lastIndexOf('.');
+        if (dot != -1) {
+            return name.substring(dot + 1);
+        }
+
+        return name;
+    }
+
+    /*
+     * Returns the simple name of a member or local class, or null otherwise.
+     */
+    private native String getInnerClassName();
+
+    /**
+     * Returns null.
+     */
+    public ProtectionDomain getProtectionDomain() {
+        return null;
+    }
+
+    /**
+     * Returns the URL of the given resource, or null if the resource is not found.
+     * The mapping between the resource name and the URL is managed by the class' class loader.
+     *
+     * @see ClassLoader
+     */
+    public URL getResource(String resourceName) {
+        // Get absolute resource name, but without the leading slash
+        if (resourceName.startsWith("/")) {
+            resourceName = resourceName.substring(1);
+        } else {
+            String pkg = getName();
+            int dot = pkg.lastIndexOf('.');
+            if (dot != -1) {
+                pkg = pkg.substring(0, dot).replace('.', '/');
+            } else {
+                pkg = "";
+            }
+
+            resourceName = pkg + "/" + resourceName;
+        }
+
+        // Delegate to proper class loader
+        ClassLoader loader = getClassLoader();
+        if (loader != null) {
+            return loader.getResource(resourceName);
+        } else {
+            return ClassLoader.getSystemResource(resourceName);
+        }
+    }
+
+    /**
+     * Returns a read-only stream for the contents of the given resource, or null if the resource
+     * is not found.
+     * The mapping between the resource name and the stream is managed by the class' class loader.
+     *
+     * @see ClassLoader
+     */
+    public InputStream getResourceAsStream(String resourceName) {
+        // Get absolute resource name, but without the leading slash
+        if (resourceName.startsWith("/")) {
+            resourceName = resourceName.substring(1);
+        } else {
+            String pkg = getName();
+            int dot = pkg.lastIndexOf('.');
+            if (dot != -1) {
+                pkg = pkg.substring(0, dot).replace('.', '/');
+            } else {
+                pkg = "";
+            }
+
+            resourceName = pkg + "/" + resourceName;
+        }
+
+        // Delegate to proper class loader
+        ClassLoader loader = getClassLoader();
+        if (loader != null) {
+            return loader.getResourceAsStream(resourceName);
+        } else {
+            return ClassLoader.getSystemResourceAsStream(resourceName);
+        }
+    }
+
+    /**
+     * Returns null. (On Android, a {@code ClassLoader} can load classes from multiple dex files.
+     * All classes from any given dex file will have the same signers, but different dex
+     * files may have different signers. This does not fit well with the original
+     * {@code ClassLoader}-based model of {@code getSigners}.)
+     */
+    public Object[] getSigners() {
+        // See http://code.google.com/p/android/issues/detail?id=1766.
+        return null;
+    }
+
+    /**
+     * Returns the {@code Class} object which represents the superclass of the
+     * class represented by this {@code Class}. If this {@code Class} represents
+     * the {@code Object} class, a primitive type, an interface or void then the
+     * method returns {@code null}. If this {@code Class} represents an array
+     * class then the {@code Object} class is returned.
+     */
+    public native Class<? super T> getSuperclass();
+
+    /**
+     * Returns an array containing {@code TypeVariable} objects for type
+     * variables declared by the generic class represented by this {@code
+     * Class}. Returns an empty array if the class is not generic.
+     */
+    @SuppressWarnings("unchecked")
+    public synchronized TypeVariable<Class<T>>[] getTypeParameters() {
+        String annotationSignature = AnnotationAccess.getSignature(this);
+        if (annotationSignature == null) {
+            return EmptyArray.TYPE_VARIABLE;
+        }
+        GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
+        parser.parseForClass(this, annotationSignature);
+        return parser.formalTypeParameters;
+    }
+
+    /**
+     * Tests whether this {@code Class} represents an annotation class.
+     */
+    public boolean isAnnotation() {
+        final int ACC_ANNOTATION = 0x2000;  // not public in reflect.Modifiers
+        int mod = getModifiers(this, true);
+        return (mod & ACC_ANNOTATION) != 0;
+    }
+
+    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+
+        if (isDeclaredAnnotationPresent(annotationType)) {
+            return true;
+        }
+
+        if (annotationType.isDeclaredAnnotationPresent(Inherited.class)) {
+            for (Class<?> sup = getSuperclass(); sup != null; sup = sup.getSuperclass()) {
+                if (sup.isDeclaredAnnotationPresent(annotationType)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Tests whether the class represented by this {@code Class} is
+     * anonymous.
+     */
+    native public boolean isAnonymousClass();
+
+    /**
+     * Tests whether the class represented by this {@code Class} is an array class.
+     */
+    public boolean isArray() {
+        return getComponentType() != null;
+    }
+
+    /**
+     * Tests whether the given class type can be converted to the class
+     * represented by this {@code Class}. Conversion may be done via an identity
+     * conversion or a widening reference conversion (if either the receiver or
+     * the argument represent primitive types, only the identity conversion
+     * applies).
+     *
+     * @throws NullPointerException
+     *             if {@code c} is {@code null}.
+     */
+    public native boolean isAssignableFrom(Class<?> c);
+
+    /**
+     * Tests whether the class represented by this {@code Class} is an
+     * {@code enum}.
+     */
+    public boolean isEnum() {
+        if (getSuperclass() != Enum.class) {
+            return false;
+        }
+        int mod = getModifiers(this, true);
+        return (mod & 0x4000) != 0;
+    }
+
+    /**
+     * Tests whether the given object can be cast to the class
+     * represented by this {@code Class}. This is the runtime version of the
+     * {@code instanceof} operator.
+     *
+     * @return {@code true} if {@code object} can be cast to the type
+     *         represented by this {@code Class}; {@code false} if {@code
+     *         object} is {@code null} or cannot be cast.
+     */
+    public native boolean isInstance(Object object);
+
+    /**
+     * Tests whether this {@code Class} represents an interface.
+     */
+    public native boolean isInterface();
+
+    /**
+     * Tests whether the class represented by this {@code Class} is defined
+     * locally.
+     */
+    public boolean isLocalClass() {
+        boolean enclosed = (getEnclosingMethod() != null ||
+                         getEnclosingConstructor() != null);
+        return enclosed && !isAnonymousClass();
+    }
+
+    /**
+     * Tests whether the class represented by this {@code Class} is a member
+     * class.
+     */
+    public boolean isMemberClass() {
+        return getDeclaringClass() != null;
+    }
+
+    /**
+     * Tests whether this {@code Class} represents a primitive type.
+     */
+    public native boolean isPrimitive();
+
+    /**
+     * Tests whether this {@code Class} represents a synthetic type.
+     */
+    public boolean isSynthetic() {
+        final int ACC_SYNTHETIC = 0x1000;   // not public in reflect.Modifiers
+        int mod = getModifiers(this, true);
+        return (mod & ACC_SYNTHETIC) != 0;
+    }
+
+    /**
+     * Returns a new instance of the class represented by this {@code Class},
+     * created by invoking the default (that is, zero-argument) constructor. If
+     * there is no such constructor, or if the creation fails (either because of
+     * a lack of available memory or because an exception is thrown by the
+     * constructor), an {@code InstantiationException} is thrown. If the default
+     * constructor exists but is not accessible from the context where this
+     * method is invoked, an {@code IllegalAccessException} is thrown.
+     *
+     * @throws IllegalAccessException
+     *             if the default constructor is not visible.
+     * @throws InstantiationException
+     *             if the instance can not be created.
+     */
+    public T newInstance() throws InstantiationException, IllegalAccessException {
+        return newInstanceImpl();
+    }
+
+    private native T newInstanceImpl() throws IllegalAccessException, InstantiationException;
+
+    @Override
+    public String toString() {
+        if (isPrimitive()) {
+            return getSimpleName();
+        }
+        return (isInterface() ? "interface " : "class ") + getName();
+    }
+
+    /**
+     * Returns the {@code Package} of which the class represented by this
+     * {@code Class} is a member. Returns {@code null} if no {@code Package}
+     * object was created by the class loader of the class.
+     */
+    public Package getPackage() {
+        // TODO This might be a hack, but the VM doesn't have the necessary info.
+        ClassLoader loader = getClassLoader();
+        if (loader != null) {
+            String name = getName();
+            int dot = name.lastIndexOf('.');
+            return (dot != -1 ? loader.getPackage(name.substring(0, dot)) : null);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the assertion status for the class represented by this {@code
+     * Class}. Assertion is enabled / disabled based on the class loader,
+     * package or class default at runtime.
+     */
+    public native boolean desiredAssertionStatus();
+
+    /**
+     * Casts this {@code Class} to represent a subclass of the given class.
+     * If successful, this {@code Class} is returned; otherwise a {@code
+     * ClassCastException} is thrown.
+     *
+     * @throws ClassCastException
+     *             if this {@code Class} cannot be cast to the given type.
+     */
+    @SuppressWarnings("unchecked")
+    public <U> Class<? extends U> asSubclass(Class<U> c) {
+        if (c.isAssignableFrom(this)) {
+            return (Class<? extends U>)this;
+        }
+        String actualClassName = this.getName();
+        String desiredClassName = c.getName();
+        throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
+    }
+
+    /**
+     * Casts the given object to the type represented by this {@code Class}.
+     * If the object is {@code null} then the result is also {@code null}.
+     *
+     * @throws ClassCastException
+     *             if the object cannot be cast to the given type.
+     */
+    @SuppressWarnings("unchecked")
+    public T cast(Object obj) {
+        if (obj == null) {
+            return null;
+        } else if (this.isInstance(obj)) {
+            return (T)obj;
+        }
+        String actualClassName = obj.getClass().getName();
+        String desiredClassName = this.getName();
+        throw new ClassCastException(actualClassName + " cannot be cast to " + desiredClassName);
+    }
+
+    /**
+     * Copies two arrays into one. Assumes that the destination array is large
+     * enough.
+     *
+     * @param result the destination array
+     * @param head the first source array
+     * @param tail the second source array
+     * @return the destination array, that is, result
+     */
+    private static <T extends Object> T[] arraycopy(T[] result, T[] head, T[] tail) {
+        System.arraycopy(head, 0, result, 0, head.length);
+        System.arraycopy(tail, 0, result, head.length, tail.length);
+        return result;
+    }
+
+    /**
+     * The annotation directory offset of this class in its own Dex, or 0 if it
+     * is unknown.
+     *
+     * TODO: 0 is a sentinel that means 'no annotations directory'; this should be -1 if unknown
+     *
+     * @hide
+     */
+    public int getDexAnnotationDirectoryOffset() {
+        Dex dex = getDex();
+        if (dex == null) {
+            return 0;
+        }
+        int classDefIndex = getDexClassDefIndex();
+        if (classDefIndex < 0) {
+            return 0;
+        }
+        return dex.annotationDirectoryOffsetFromClassDefIndex(classDefIndex);
+    }
+
+
+    /**
+     * Returns a resolved type from the dex cache, computing the type from the dex file if
+     * necessary.
+     * TODO: use Dalvik's dex cache.
+     * @hide
+     */
+    public Class<?> getDexCacheType(Dex dex, int typeIndex) {
+        String internalName = dex.typeNames().get(typeIndex);
+        return InternalNames.getClass(getClassLoader(), internalName);
+    }
+
+    /**
+     * Returns a string from the dex cache, computing the string from the dex file if necessary.
+     *
+     * @hide
+     */
+    public String getDexCacheString(Dex dex, int dexStringIndex) {
+        return dex.strings().get(dexStringIndex);
+    }
+
+
+    private static class Caches {
+        /**
+         * Cache to avoid frequent recalculation of generic interfaces, which is generally uncommon.
+         * Sized sufficient to allow ConcurrentHashMapTest to run without recalculating its generic
+         * interfaces (required to avoid time outs). Validated by running reflection heavy code
+         * such as applications using Guice-like frameworks.
+         */
+        private static final BasicLruCache<Class, Type[]> genericInterfaces
+            = new BasicLruCache<Class, Type[]>(8);
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/ClassLoader.java b/libdvm/src/main/java/java/lang/ClassLoader.java
new file mode 100644
index 0000000..c6a80913
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/ClassLoader.java
@@ -0,0 +1,836 @@
+/*
+ * 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) 2008 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;
+
+import dalvik.system.PathClassLoader;
+import dalvik.system.VMStack;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.security.ProtectionDomain;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Loads classes and resources from a repository. One or more class loaders are
+ * installed at runtime. These are consulted whenever the runtime system needs a
+ * specific class that is not yet available in-memory. Typically, class loaders
+ * are grouped into a tree where child class loaders delegate all requests to
+ * parent class loaders. Only if the parent class loader cannot satisfy the
+ * request, the child class loader itself tries to handle it.
+ * <p>
+ * {@code ClassLoader} is an abstract class that implements the common
+ * infrastructure required by all class loaders. Android provides several
+ * concrete implementations of the class, with
+ * {@link dalvik.system.PathClassLoader} being the one typically used. Other
+ * applications may implement subclasses of {@code ClassLoader} to provide
+ * special ways for loading classes.
+ * </p>
+ * @see Class
+ */
+public abstract class ClassLoader {
+
+    /**
+     * The 'System' ClassLoader - the one that is responsible for loading
+     * classes from the classpath. It is not equal to the bootstrap class loader -
+     * that one handles the built-in classes.
+     *
+     * Because of a potential class initialization race between ClassLoader and
+     * java.lang.System, reproducible when using JDWP with "suspend=y", we defer
+     * creation of the system class loader until first use. We use a static
+     * inner class to get synchronization at init time without having to sync on
+     * every access.
+     *
+     * @see #getSystemClassLoader()
+     */
+    static private class SystemClassLoader {
+        public static ClassLoader loader = ClassLoader.createSystemClassLoader();
+    }
+
+    /**
+     * The parent ClassLoader.
+     */
+    private ClassLoader parent;
+
+    /**
+     * The packages known to the class loader.
+     */
+    private Map<String, Package> packages = new HashMap<String, Package>();
+
+    /**
+     * Create the system class loader. Note this is NOT the bootstrap class
+     * loader (which is managed by the VM). We use a null value for the parent
+     * to indicate that the bootstrap loader is our parent.
+     */
+    private static ClassLoader createSystemClassLoader() {
+        String classPath = System.getProperty("java.class.path", ".");
+
+        // String[] paths = classPath.split(":");
+        // URL[] urls = new URL[paths.length];
+        // for (int i = 0; i < paths.length; i++) {
+        // try {
+        // urls[i] = new URL("file://" + paths[i]);
+        // }
+        // catch (Exception ex) {
+        // ex.printStackTrace();
+        // }
+        // }
+        //
+        // return new java.net.URLClassLoader(urls, null);
+
+        // TODO Make this a java.net.URLClassLoader once we have those?
+        return new PathClassLoader(classPath, BootClassLoader.getInstance());
+    }
+
+    /**
+     * Returns the system class loader. This is the parent for new
+     * {@code ClassLoader} instances and is typically the class loader used to
+     * start the application.
+     */
+    public static ClassLoader getSystemClassLoader() {
+        return SystemClassLoader.loader;
+    }
+
+    /**
+     * Finds the URL of the resource with the specified name. The system class
+     * loader's resource lookup algorithm is used to find the resource.
+     *
+     * @return the {@code URL} object for the requested resource or {@code null}
+     *         if the resource can not be found.
+     * @param resName
+     *            the name of the resource to find.
+     * @see Class#getResource
+     */
+    public static URL getSystemResource(String resName) {
+        return SystemClassLoader.loader.getResource(resName);
+    }
+
+    /**
+     * Returns an enumeration of URLs for the resource with the specified name.
+     * The system class loader's resource lookup algorithm is used to find the
+     * resource.
+     *
+     * @return an enumeration of {@code URL} objects containing the requested
+     *         resources.
+     * @param resName
+     *            the name of the resource to find.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    public static Enumeration<URL> getSystemResources(String resName) throws IOException {
+        return SystemClassLoader.loader.getResources(resName);
+    }
+
+    /**
+     * Returns a stream for the resource with the specified name. The system
+     * class loader's resource lookup algorithm is used to find the resource.
+     * Basically, the contents of the java.class.path are searched in order,
+     * looking for a path which matches the specified resource.
+     *
+     * @return a stream for the resource or {@code null}.
+     * @param resName
+     *            the name of the resource to find.
+     * @see Class#getResourceAsStream
+     */
+    public static InputStream getSystemResourceAsStream(String resName) {
+        return SystemClassLoader.loader.getResourceAsStream(resName);
+    }
+
+    /**
+     * Constructs a new instance of this class with the system class loader as
+     * its parent.
+     */
+    protected ClassLoader() {
+        this(getSystemClassLoader(), false);
+    }
+
+    /**
+     * Constructs a new instance of this class with the specified class loader
+     * as its parent.
+     *
+     * @param parentLoader
+     *            The {@code ClassLoader} to use as the new class loader's
+     *            parent.
+     */
+    protected ClassLoader(ClassLoader parentLoader) {
+        this(parentLoader, false);
+    }
+
+    /*
+     * constructor for the BootClassLoader which needs parent to be null.
+     */
+    ClassLoader(ClassLoader parentLoader, boolean nullAllowed) {
+        if (parentLoader == null && !nullAllowed) {
+            throw new NullPointerException("parentLoader == null && !nullAllowed");
+        }
+        parent = parentLoader;
+    }
+
+    /**
+     * Constructs a new class from an array of bytes containing a class
+     * definition in class file format.
+     *
+     * @param classRep
+     *            the memory image of a class file.
+     * @param offset
+     *            the offset into {@code classRep}.
+     * @param length
+     *            the length of the class file.
+     * @return the {@code Class} object created from the specified subset of
+     *         data in {@code classRep}.
+     * @throws ClassFormatError
+     *             if {@code classRep} does not contain a valid class.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0}, {@code length < 0} or if
+     *             {@code offset + length} is greater than the length of
+     *             {@code classRep}.
+     * @deprecated Use {@link #defineClass(String, byte[], int, int)} instead.
+     */
+    @Deprecated
+    protected final Class<?> defineClass(byte[] classRep, int offset, int length)
+            throws ClassFormatError {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Constructs a new class from an array of bytes containing a class
+     * definition in class file format.
+     *
+     * @param className
+     *            the expected name of the new class, may be {@code null} if not
+     *            known.
+     * @param classRep
+     *            the memory image of a class file.
+     * @param offset
+     *            the offset into {@code classRep}.
+     * @param length
+     *            the length of the class file.
+     * @return the {@code Class} object created from the specified subset of
+     *         data in {@code classRep}.
+     * @throws ClassFormatError
+     *             if {@code classRep} does not contain a valid class.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0}, {@code length < 0} or if
+     *             {@code offset + length} is greater than the length of
+     *             {@code classRep}.
+     */
+    protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length)
+            throws ClassFormatError {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Constructs a new class from an array of bytes containing a class
+     * definition in class file format and assigns the specified protection
+     * domain to the new class. If the provided protection domain is
+     * {@code null} then a default protection domain is assigned to the class.
+     *
+     * @param className
+     *            the expected name of the new class, may be {@code null} if not
+     *            known.
+     * @param classRep
+     *            the memory image of a class file.
+     * @param offset
+     *            the offset into {@code classRep}.
+     * @param length
+     *            the length of the class file.
+     * @param protectionDomain
+     *            the protection domain to assign to the loaded class, may be
+     *            {@code null}.
+     * @return the {@code Class} object created from the specified subset of
+     *         data in {@code classRep}.
+     * @throws ClassFormatError
+     *             if {@code classRep} does not contain a valid class.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset < 0}, {@code length < 0} or if
+     *             {@code offset + length} is greater than the length of
+     *             {@code classRep}.
+     * @throws NoClassDefFoundError
+     *             if {@code className} is not equal to the name of the class
+     *             contained in {@code classRep}.
+     */
+    protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length,
+            ProtectionDomain protectionDomain) throws java.lang.ClassFormatError {
+        throw new UnsupportedOperationException("can't load this type of class file");
+    }
+
+    /**
+     * Defines a new class with the specified name, byte code from the byte
+     * buffer and the optional protection domain. If the provided protection
+     * domain is {@code null} then a default protection domain is assigned to
+     * the class.
+     *
+     * @param name
+     *            the expected name of the new class, may be {@code null} if not
+     *            known.
+     * @param b
+     *            the byte buffer containing the byte code of the new class.
+     * @param protectionDomain
+     *            the protection domain to assign to the loaded class, may be
+     *            {@code null}.
+     * @return the {@code Class} object created from the data in {@code b}.
+     * @throws ClassFormatError
+     *             if {@code b} does not contain a valid class.
+     * @throws NoClassDefFoundError
+     *             if {@code className} is not equal to the name of the class
+     *             contained in {@code b}.
+     */
+    protected final Class<?> defineClass(String name, ByteBuffer b,
+            ProtectionDomain protectionDomain) throws ClassFormatError {
+
+        byte[] temp = new byte[b.remaining()];
+        b.get(temp);
+        return defineClass(name, temp, 0, temp.length, protectionDomain);
+    }
+
+    /**
+     * Overridden by subclasses, throws a {@code ClassNotFoundException} by
+     * default. This method is called by {@code loadClass} after the parent
+     * {@code ClassLoader} has failed to find a loaded class of the same name.
+     *
+     * @param className
+     *            the name of the class to look for.
+     * @return the {@code Class} object that is found.
+     * @throws ClassNotFoundException
+     *             if the class cannot be found.
+     */
+    protected Class<?> findClass(String className) throws ClassNotFoundException {
+        throw new ClassNotFoundException(className);
+    }
+
+    /**
+     * Returns the class with the specified name if it has already been loaded
+     * by the VM or {@code null} if it has not yet been loaded.
+     *
+     * @param className
+     *            the name of the class to look for.
+     * @return the {@code Class} object or {@code null} if the requested class
+     *         has not been loaded.
+     */
+    protected final Class<?> findLoadedClass(String className) {
+        ClassLoader loader;
+        if (this == BootClassLoader.getInstance())
+            loader = null;
+        else
+            loader = this;
+        return VMClassLoader.findLoadedClass(loader, className);
+    }
+
+    /**
+     * Finds the class with the specified name, loading it using the system
+     * class loader if necessary.
+     *
+     * @param className
+     *            the name of the class to look for.
+     * @return the {@code Class} object with the requested {@code className}.
+     * @throws ClassNotFoundException
+     *             if the class can not be found.
+     */
+    protected final Class<?> findSystemClass(String className) throws ClassNotFoundException {
+        return Class.forName(className, false, getSystemClassLoader());
+    }
+
+    /**
+     * Returns this class loader's parent.
+     *
+     * @return this class loader's parent or {@code null}.
+     */
+    public final ClassLoader getParent() {
+        return parent;
+    }
+
+    /**
+     * Returns the URL of the resource with the specified name. This
+     * implementation first tries to use the parent class loader to find the
+     * resource; if this fails then {@link #findResource(String)} is called to
+     * find the requested resource.
+     *
+     * @param resName
+     *            the name of the resource to find.
+     * @return the {@code URL} object for the requested resource or {@code null}
+     *         if the resource can not be found
+     * @see Class#getResource
+     */
+    public URL getResource(String resName) {
+        URL resource = parent.getResource(resName);
+        if (resource == null) {
+            resource = findResource(resName);
+        }
+        return resource;
+    }
+
+    /**
+     * Returns an enumeration of URLs for the resource with the specified name.
+     * This implementation first uses this class loader's parent to find the
+     * resource, then it calls {@link #findResources(String)} to get additional
+     * URLs. The returned enumeration contains the {@code URL} objects of both
+     * find operations.
+     *
+     * @return an enumeration of {@code URL} objects for the requested resource.
+     * @param resName
+     *            the name of the resource to find.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    @SuppressWarnings("unchecked")
+    public Enumeration<URL> getResources(String resName) throws IOException {
+
+        Enumeration first = parent.getResources(resName);
+        Enumeration second = findResources(resName);
+
+        return new TwoEnumerationsInOne(first, second);
+    }
+
+    /**
+     * Returns a stream for the resource with the specified name. See
+     * {@link #getResource(String)} for a description of the lookup algorithm
+     * used to find the resource.
+     *
+     * @return a stream for the resource or {@code null} if the resource can not be found
+     * @param resName
+     *            the name of the resource to find.
+     * @see Class#getResourceAsStream
+     */
+    public InputStream getResourceAsStream(String resName) {
+        try {
+            URL url = getResource(resName);
+            if (url != null) {
+                return url.openStream();
+            }
+        } catch (IOException ex) {
+            // Don't want to see the exception.
+        }
+
+        return null;
+    }
+
+    /**
+     * Loads the class with the specified name. Invoking this method is
+     * equivalent to calling {@code loadClass(className, false)}.
+     * <p>
+     * <strong>Note:</strong> In the Android reference implementation, the
+     * second parameter of {@link #loadClass(String, boolean)} is ignored
+     * anyway.
+     * </p>
+     *
+     * @return the {@code Class} object.
+     * @param className
+     *            the name of the class to look for.
+     * @throws ClassNotFoundException
+     *             if the class can not be found.
+     */
+    public Class<?> loadClass(String className) throws ClassNotFoundException {
+        return loadClass(className, false);
+    }
+
+    /**
+     * Loads the class with the specified name, optionally linking it after
+     * loading. The following steps are performed:
+     * <ol>
+     * <li> Call {@link #findLoadedClass(String)} to determine if the requested
+     * class has already been loaded.</li>
+     * <li>If the class has not yet been loaded: Invoke this method on the
+     * parent class loader.</li>
+     * <li>If the class has still not been loaded: Call
+     * {@link #findClass(String)} to find the class.</li>
+     * </ol>
+     * <p>
+     * <strong>Note:</strong> In the Android reference implementation, the
+     * {@code resolve} parameter is ignored; classes are never linked.
+     * </p>
+     *
+     * @return the {@code Class} object.
+     * @param className
+     *            the name of the class to look for.
+     * @param resolve
+     *            Indicates if the class should be resolved after loading. This
+     *            parameter is ignored on the Android reference implementation;
+     *            classes are not resolved.
+     * @throws ClassNotFoundException
+     *             if the class can not be found.
+     */
+    protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
+        Class<?> clazz = findLoadedClass(className);
+
+        if (clazz == null) {
+            try {
+                clazz = parent.loadClass(className, false);
+            } catch (ClassNotFoundException e) {
+                // Don't want to see this.
+            }
+
+            if (clazz == null) {
+                clazz = findClass(className);
+            }
+        }
+
+        return clazz;
+    }
+
+    /**
+     * Forces a class to be linked (initialized). If the class has already been
+     * linked this operation has no effect.
+     * <p>
+     * <strong>Note:</strong> In the Android reference implementation, this
+     * method has no effect.
+     * </p>
+     *
+     * @param clazz
+     *            the class to link.
+     */
+    protected final void resolveClass(Class<?> clazz) {
+        // no-op, doesn't make sense on android.
+    }
+
+    /**
+     * Finds the URL of the resource with the specified name. This
+     * implementation just returns {@code null}; it should be overridden in
+     * subclasses.
+     *
+     * @param resName
+     *            the name of the resource to find.
+     * @return the {@code URL} object for the requested resource.
+     */
+    protected URL findResource(String resName) {
+        return null;
+    }
+
+    /**
+     * Finds an enumeration of URLs for the resource with the specified name.
+     * This implementation just returns an empty {@code Enumeration}; it should
+     * be overridden in subclasses.
+     *
+     * @param resName
+     *            the name of the resource to find.
+     * @return an enumeration of {@code URL} objects for the requested resource.
+     * @throws IOException
+     *             if an I/O error occurs.
+     */
+    @SuppressWarnings( {
+            "unchecked", "unused"
+    })
+    protected Enumeration<URL> findResources(String resName) throws IOException {
+        return Collections.emptyEnumeration();
+    }
+
+    /**
+     * Returns the absolute path of the native library with the specified name,
+     * or {@code null}. If this method returns {@code null} then the virtual
+     * machine searches the directories specified by the system property
+     * "java.library.path".
+     * <p>
+     * This implementation always returns {@code null}.
+     * </p>
+     *
+     * @param libName
+     *            the name of the library to find.
+     * @return the absolute path of the library.
+     */
+    protected String findLibrary(String libName) {
+        return null;
+    }
+
+    /**
+     * Returns the package with the specified name. Package information is
+     * searched in this class loader.
+     *
+     * @param name
+     *            the name of the package to find.
+     * @return the package with the requested name; {@code null} if the package
+     *         can not be found.
+     */
+    protected Package getPackage(String name) {
+        synchronized (packages) {
+            return packages.get(name);
+        }
+    }
+
+    /**
+     * Returns all the packages known to this class loader.
+     *
+     * @return an array with all packages known to this class loader.
+     */
+    protected Package[] getPackages() {
+        synchronized (packages) {
+            Collection<Package> col = packages.values();
+            Package[] result = new Package[col.size()];
+            col.toArray(result);
+            return result;
+        }
+    }
+
+    /**
+     * Defines and returns a new {@code Package} using the specified
+     * information. If {@code sealBase} is {@code null}, the package is left
+     * unsealed. Otherwise, the package is sealed using this URL.
+     *
+     * @param name
+     *            the name of the package.
+     * @param specTitle
+     *            the title of the specification.
+     * @param specVersion
+     *            the version of the specification.
+     * @param specVendor
+     *            the vendor of the specification.
+     * @param implTitle
+     *            the implementation title.
+     * @param implVersion
+     *            the implementation version.
+     * @param implVendor
+     *            the specification vendor.
+     * @param sealBase
+     *            the URL used to seal this package or {@code null} to leave the
+     *            package unsealed.
+     * @return the {@code Package} object that has been created.
+     * @throws IllegalArgumentException
+     *             if a package with the specified name already exists.
+     */
+    protected Package definePackage(String name, String specTitle, String specVersion,
+            String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)
+            throws IllegalArgumentException {
+
+        synchronized (packages) {
+            if (packages.containsKey(name)) {
+                throw new IllegalArgumentException("Package " + name + " already defined");
+            }
+
+            Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle,
+                    implVersion, implVendor, sealBase);
+
+            packages.put(name, newPackage);
+
+            return newPackage;
+        }
+    }
+
+    /**
+     * Sets the signers of the specified class. This implementation does
+     * nothing.
+     *
+     * @param c
+     *            the {@code Class} object for which to set the signers.
+     * @param signers
+     *            the signers for {@code c}.
+     */
+    protected final void setSigners(Class<?> c, Object[] signers) {
+    }
+
+    /**
+     * Sets the assertion status of the class with the specified name.
+     * <p>
+     * <strong>Note: </strong>This method does nothing in the Android reference
+     * implementation.
+     * </p>
+     *
+     * @param cname
+     *            the name of the class for which to set the assertion status.
+     * @param enable
+     *            the new assertion status.
+     */
+    public void setClassAssertionStatus(String cname, boolean enable) {
+    }
+
+    /**
+     * Sets the assertion status of the package with the specified name.
+     * <p>
+     * <strong>Note: </strong>This method does nothing in the Android reference
+     * implementation.
+     * </p>
+     *
+     * @param pname
+     *            the name of the package for which to set the assertion status.
+     * @param enable
+     *            the new assertion status.
+     */
+    public void setPackageAssertionStatus(String pname, boolean enable) {
+    }
+
+    /**
+     * Sets the default assertion status for this class loader.
+     * <p>
+     * <strong>Note: </strong>This method does nothing in the Android reference
+     * implementation.
+     * </p>
+     *
+     * @param enable
+     *            the new assertion status.
+     */
+    public void setDefaultAssertionStatus(boolean enable) {
+    }
+
+    /**
+     * Sets the default assertion status for this class loader to {@code false}
+     * and removes any package default and class assertion status settings.
+     * <p>
+     * <strong>Note:</strong> This method does nothing in the Android reference
+     * implementation.
+     * </p>
+     */
+    public void clearAssertionStatus() {
+    }
+}
+
+/*
+ * Provides a helper class that combines two existing URL enumerations into one.
+ * It is required for the getResources() methods. Items are fetched from the
+ * first enumeration until it's empty, then from the second one.
+ */
+class TwoEnumerationsInOne implements Enumeration<URL> {
+
+    private Enumeration<URL> first;
+
+    private Enumeration<URL> second;
+
+    public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) {
+        this.first = first;
+        this.second = second;
+    }
+
+    public boolean hasMoreElements() {
+        return first.hasMoreElements() || second.hasMoreElements();
+    }
+
+    public URL nextElement() {
+        if (first.hasMoreElements()) {
+            return first.nextElement();
+        } else {
+            return second.nextElement();
+        }
+    }
+
+}
+
+/**
+ * Provides an explicit representation of the boot class loader. It sits at the
+ * head of the class loader chain and delegates requests to the VM's internal
+ * class loading mechanism.
+ */
+class BootClassLoader extends ClassLoader {
+
+    private static BootClassLoader instance;
+
+    @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
+    public static synchronized BootClassLoader getInstance() {
+        if (instance == null) {
+            instance = new BootClassLoader();
+        }
+
+        return instance;
+    }
+
+    public BootClassLoader() {
+        super(null, true);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        return VMClassLoader.loadClass(name, false);
+    }
+
+    @Override
+    protected URL findResource(String name) {
+        return VMClassLoader.getResource(name);
+    }
+
+    @SuppressWarnings("unused")
+    @Override
+    protected Enumeration<URL> findResources(String resName) throws IOException {
+        return Collections.enumeration(VMClassLoader.getResources(resName));
+    }
+
+    /**
+     * Returns package information for the given package. Unfortunately, the
+     * Android BootClassLoader doesn't really have this information, and as a
+     * non-secure ClassLoader, it isn't even required to, according to the spec.
+     * Yet, we want to provide it, in order to make all those hopeful callers of
+     * {@code myClass.getPackage().getName()} happy. Thus we construct a Package
+     * object the first time it is being requested and fill most of the fields
+     * with dummy values. The Package object is then put into the ClassLoader's
+     * Package cache, so we see the same one next time. We don't create Package
+     * objects for null arguments or for the default package.
+     * <p>
+     * There a limited chance that we end up with multiple Package objects
+     * representing the same package: It can happen when when a package is
+     * scattered across different JAR files being loaded by different
+     * ClassLoaders. Rather unlikely, and given that this whole thing is more or
+     * less a workaround, probably not worth the effort.
+     */
+    @Override
+    protected Package getPackage(String name) {
+        if (name != null && !name.isEmpty()) {
+            synchronized (this) {
+                Package pack = super.getPackage(name);
+
+                if (pack == null) {
+                    pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0",
+                            "Unknown", null);
+                }
+
+                return pack;
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public URL getResource(String resName) {
+        return findResource(resName);
+    }
+
+    @Override
+    protected Class<?> loadClass(String className, boolean resolve)
+           throws ClassNotFoundException {
+        Class<?> clazz = findLoadedClass(className);
+
+        if (clazz == null) {
+            clazz = findClass(className);
+        }
+
+        return clazz;
+    }
+
+    @Override
+    public Enumeration<URL> getResources(String resName) throws IOException {
+        return findResources(resName);
+    }
+}
+
+/**
+ * TODO Open issues - Missing / empty methods - Signer stuff - Protection
+ * domains - Assertions
+ */
diff --git a/libdvm/src/main/java/java/lang/Daemons.java b/libdvm/src/main/java/java/lang/Daemons.java
new file mode 100644
index 0000000..78a4152
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/Daemons.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2011 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;
+
+import dalvik.system.VMRuntime;
+import java.lang.ref.FinalizerReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.TimeoutException;
+import libcore.util.EmptyArray;
+
+/**
+ * Calls Object.finalize() on objects in the finalizer reference queue. The VM
+ * will abort if any finalize() call takes more than the maximum finalize time
+ * to complete.
+ *
+ * @hide
+ */
+public final class Daemons {
+    private static final int NANOS_PER_MILLI = 1000 * 1000;
+    private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000;
+    private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND;
+
+    public static void start() {
+        ReferenceQueueDaemon.INSTANCE.start();
+        FinalizerDaemon.INSTANCE.start();
+        FinalizerWatchdogDaemon.INSTANCE.start();
+    }
+
+    public static void stop() {
+        ReferenceQueueDaemon.INSTANCE.stop();
+        FinalizerDaemon.INSTANCE.stop();
+        FinalizerWatchdogDaemon.INSTANCE.stop();
+    }
+
+    /**
+     * A background task that provides runtime support to the application.
+     * Daemons can be stopped and started, but only so that the zygote can be a
+     * single-threaded process when it forks.
+     */
+    private static abstract class Daemon implements Runnable {
+        private Thread thread;
+
+        public synchronized void start() {
+            if (thread != null) {
+                throw new IllegalStateException("already running");
+            }
+            thread = new Thread(ThreadGroup.mSystem, this,
+                getClass().getSimpleName());
+            thread.setDaemon(true);
+            thread.start();
+        }
+
+        public abstract void run();
+
+        /**
+         * Returns true while the current thread should continue to run; false
+         * when it should return.
+         */
+        protected synchronized boolean isRunning() {
+            return thread != null;
+        }
+
+        public synchronized void interrupt() {
+            if (thread == null) {
+                throw new IllegalStateException("not running");
+            }
+            thread.interrupt();
+        }
+
+        /**
+         * Waits for the runtime thread to stop. This interrupts the thread
+         * currently running the runnable and then waits for it to exit.
+         */
+        public void stop() {
+            Thread threadToStop;
+            synchronized (this) {
+                threadToStop = thread;
+                thread = null;
+            }
+            if (threadToStop == null) {
+                throw new IllegalStateException("not running");
+            }
+            threadToStop.interrupt();
+            while (true) {
+                try {
+                    threadToStop.join();
+                    return;
+                } catch (InterruptedException ignored) {
+                }
+            }
+        }
+
+        /**
+         * Returns the current stack trace of the thread, or an empty stack trace
+         * if the thread is not currently running.
+         */
+        public synchronized StackTraceElement[] getStackTrace() {
+            return thread != null ? thread.getStackTrace() : EmptyArray.STACK_TRACE_ELEMENT;
+        }
+    }
+
+    /**
+     * This heap management thread moves elements from the garbage collector's
+     * pending list to the managed reference queue.
+     */
+    private static class ReferenceQueueDaemon extends Daemon {
+        private static final ReferenceQueueDaemon INSTANCE = new ReferenceQueueDaemon();
+
+        @Override public void run() {
+            while (isRunning()) {
+                Reference<?> list;
+                try {
+                    synchronized (ReferenceQueue.class) {
+                        while (ReferenceQueue.unenqueued == null) {
+                            ReferenceQueue.class.wait();
+                        }
+                        list = ReferenceQueue.unenqueued;
+                        ReferenceQueue.unenqueued = null;
+                    }
+                } catch (InterruptedException e) {
+                    continue;
+                }
+                enqueue(list);
+            }
+        }
+
+        private void enqueue(Reference<?> list) {
+            while (list != null) {
+                Reference<?> reference;
+                // pendingNext is owned by the GC so no synchronization is required
+                if (list == list.pendingNext) {
+                    reference = list;
+                    reference.pendingNext = null;
+                    list = null;
+                } else {
+                    reference = list.pendingNext;
+                    list.pendingNext = reference.pendingNext;
+                    reference.pendingNext = null;
+                }
+                reference.enqueueInternal();
+            }
+        }
+    }
+
+    private static class FinalizerDaemon extends Daemon {
+        private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
+        private final ReferenceQueue<Object> queue = FinalizerReference.queue;
+        private volatile Object finalizingObject;
+        private volatile long finalizingStartedNanos;
+
+        @Override public void run() {
+            while (isRunning()) {
+                // Take a reference, blocking until one is ready or the thread should stop
+                try {
+                    doFinalize((FinalizerReference<?>) queue.remove());
+                } catch (InterruptedException ignored) {
+                }
+            }
+        }
+
+        @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
+        private void doFinalize(FinalizerReference<?> reference) {
+            FinalizerReference.remove(reference);
+            Object object = reference.get();
+            reference.clear();
+            try {
+                finalizingStartedNanos = System.nanoTime();
+                finalizingObject = object;
+                synchronized (FinalizerWatchdogDaemon.INSTANCE) {
+                    FinalizerWatchdogDaemon.INSTANCE.notify();
+                }
+                object.finalize();
+            } catch (Throwable ex) {
+                // The RI silently swallows these, but Android has always logged.
+                System.logE("Uncaught exception thrown by finalizer", ex);
+            } finally {
+                finalizingObject = null;
+            }
+        }
+    }
+
+    /**
+     * The watchdog exits the VM if the finalizer ever gets stuck. We consider
+     * the finalizer to be stuck if it spends more than MAX_FINALIZATION_MILLIS
+     * on one instance.
+     */
+    private static class FinalizerWatchdogDaemon extends Daemon {
+        private static final FinalizerWatchdogDaemon INSTANCE = new FinalizerWatchdogDaemon();
+
+        @Override public void run() {
+            while (isRunning()) {
+                Object object = waitForObject();
+                if (object == null) {
+                    // We have been interrupted, need to see if this daemon has been stopped.
+                    continue;
+                }
+                boolean finalized = waitForFinalization(object);
+                if (!finalized && !VMRuntime.getRuntime().isDebuggerActive()) {
+                    finalizerTimedOut(object);
+                    break;
+                }
+            }
+        }
+
+        private Object waitForObject() {
+            while (true) {
+                Object object = FinalizerDaemon.INSTANCE.finalizingObject;
+                if (object != null) {
+                    return object;
+                }
+                synchronized (this) {
+                    // wait until something is ready to be finalized
+                    // http://code.google.com/p/android/issues/detail?id=22778
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        // Daemon.stop may have interrupted us.
+                        return null;
+                    }
+                }
+            }
+        }
+
+        private void sleepFor(long startNanos, long durationNanos) {
+            while (true) {
+                long elapsedNanos = System.nanoTime() - startNanos;
+                long sleepNanos = durationNanos - elapsedNanos;
+                long sleepMills = sleepNanos / NANOS_PER_MILLI;
+                if (sleepMills <= 0) {
+                    return;
+                }
+                try {
+                    Thread.sleep(sleepMills);
+                } catch (InterruptedException e) {
+                    if (!isRunning()) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        private boolean waitForFinalization(Object object) {
+            sleepFor(FinalizerDaemon.INSTANCE.finalizingStartedNanos, MAX_FINALIZE_NANOS);
+            return object != FinalizerDaemon.INSTANCE.finalizingObject;
+        }
+
+        private static void finalizerTimedOut(Object object) {
+            // The current object has exceeded the finalization deadline; abort!
+            String message = object.getClass().getName() + ".finalize() timed out after "
+                    + (MAX_FINALIZE_NANOS / NANOS_PER_SECOND) + " seconds";
+            Exception syntheticException = new TimeoutException(message);
+            // We use the stack from where finalize() was running to show where it was stuck.
+            syntheticException.setStackTrace(FinalizerDaemon.INSTANCE.getStackTrace());
+            Thread.UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler();
+            if (h == null) {
+                // If we have no handler, log and exit.
+                System.logE(message, syntheticException);
+                System.exit(2);
+            }
+            // Otherwise call the handler to do crash reporting.
+            // We don't just throw because we're not the thread that
+            // timed out; we're the thread that detected it.
+            h.uncaughtException(Thread.currentThread(), syntheticException);
+        }
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/Enum.java b/libdvm/src/main/java/java/lang/Enum.java
new file mode 100644
index 0000000..4b897aa
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/Enum.java
@@ -0,0 +1,221 @@
+/* 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 java.lang;
+
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import libcore.util.BasicLruCache;
+import libcore.util.EmptyArray;
+
+/**
+ * The superclass of all enumerated types. Actual enumeration types inherit from
+ * this class, but extending this class does not make a class an enumeration
+ * type, since the compiler needs to generate special information for it.
+ */
+public abstract class Enum<E extends Enum<E>> implements Serializable, Comparable<E> {
+
+    private static final long serialVersionUID = -4300926546619394005L;
+
+    private static final BasicLruCache<Class<? extends Enum>, Object[]> sharedConstantsCache
+            = new BasicLruCache<Class<? extends Enum>, Object[]>(64) {
+        @Override protected Object[] create(Class<? extends Enum> enumType) {
+            if (!enumType.isEnum()) {
+                return null;
+            }
+            Method method = (Method) Class.getDeclaredConstructorOrMethod(
+                    enumType, "values", EmptyArray.CLASS);
+            try {
+                return (Object[]) method.invoke((Object[]) null);
+            } catch (IllegalAccessException impossible) {
+                throw new AssertionError();
+            } catch (InvocationTargetException impossible) {
+                throw new AssertionError();
+            }
+        }
+    };
+
+    private final String name;
+
+    private final int ordinal;
+
+    /**
+     * Constructor for constants of enum subtypes.
+     *
+     * @param name
+     *            the enum constant's declared name.
+     * @param ordinal
+     *            the enum constant's ordinal, which corresponds to its position
+     *            in the enum declaration, starting at zero.
+     */
+    protected Enum(String name, int ordinal) {
+        this.name = name;
+        this.ordinal = ordinal;
+    }
+
+    /**
+     * Returns the name of this enum constant. The name is the field as it
+     * appears in the {@code enum} declaration.
+     *
+     * @return the name of this enum constant.
+     * @see #toString()
+     */
+    public final String name() {
+        return name;
+    }
+
+    /**
+     * Returns the position of the enum constant in the declaration. The first
+     * constant has an ordinal value of zero.
+     *
+     * @return the ordinal value of this enum constant.
+     */
+    public final int ordinal() {
+        return ordinal;
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of this
+     * object. In this case, the enum constant's name is returned.
+     *
+     * @return a printable representation of this object.
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    /**
+     * Compares this object with the specified object and indicates if they are
+     * equal. In order to be equal, {@code object} must be identical to this
+     * enum constant.
+     *
+     * @param other
+     *            the object to compare this enum constant with.
+     * @return {@code true} if the specified object is equal to this
+     *         {@code Enum}; {@code false} otherwise.
+     */
+    @Override
+    public final boolean equals(Object other) {
+        return this == other;
+    }
+
+    @Override
+    public final int hashCode() {
+        return ordinal + (name == null ? 0 : name.hashCode());
+    }
+
+    /**
+     * {@code Enum} objects are singletons, they may not be cloned. This method
+     * always throws a {@code CloneNotSupportedException}.
+     *
+     * @return does not return.
+     * @throws CloneNotSupportedException
+     *             is always thrown.
+     */
+    @Override
+    protected final Object clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException("Enums may not be cloned");
+    }
+
+    /**
+     * Compares this object to the specified enum object to determine their
+     * relative order. This method compares the object's ordinal values, that
+     * is, their position in the enum declaration.
+     *
+     * @param o
+     *            the enum object to compare this object to.
+     * @return a negative value if the ordinal value of this enum constant is
+     *         less than the ordinal value of {@code o}; 0 if the ordinal
+     *         values of this enum constant and {@code o} are equal; a positive
+     *         value if the ordinal value of this enum constant is greater than
+     *         the ordinal value of {@code o}.
+     * @see java.lang.Comparable
+     */
+    public final int compareTo(E o) {
+        return ordinal - o.ordinal();
+    }
+
+    /**
+     * Returns the enum constant's declaring class.
+     *
+     * @return the class object representing the constant's enum type.
+     */
+    @SuppressWarnings("unchecked")
+    public final Class<E> getDeclaringClass() {
+        Class<?> myClass = getClass();
+        Class<?> mySuperClass = myClass.getSuperclass();
+        if (Enum.class == mySuperClass) {
+            return (Class<E>)myClass;
+        }
+        return (Class<E>)mySuperClass;
+    }
+
+    /**
+     * Returns the constant with the specified name of the specified enum type.
+     *
+     * @param enumType
+     *            the class of the enumerated type to search for the constant
+     *            value.
+     * @param name
+     *            the name of the constant value to find.
+     * @return the enum constant.
+     * @throws NullPointerException
+     *             if either {@code enumType} or {@code name} are {@code null}.
+     * @throws IllegalArgumentException
+     *             if {@code enumType} is not an enumerated type or does not
+     *             have a constant value called {@code name}.
+     */
+    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
+        if (enumType == null) {
+            throw new NullPointerException("enumType == null");
+        } else if (name == null) {
+            throw new NullPointerException("name == null");
+        }
+        T[] values = getSharedConstants(enumType);
+        if (values == null) {
+            throw new IllegalArgumentException(enumType + " is not an enum type");
+        }
+        for (T value : values) {
+            if (name.equals(value.name())) {
+                return value;
+            }
+        }
+        throw new IllegalArgumentException(name + " is not a constant in " + enumType.getName());
+    }
+
+    /**
+     * Returns a shared, mutable array containing the constants of this enum. It
+     * is an error to modify the returned array.
+     *
+     * @hide
+     */
+    @SuppressWarnings("unchecked") // the cache always returns the type matching enumType
+    public static <T extends Enum<T>> T[] getSharedConstants(Class<T> enumType) {
+        return (T[]) sharedConstantsCache.get(enumType);
+    }
+
+    /**
+     * Enum types may not have finalizers.
+     *
+     * @since 1.6
+     */
+    @Override
+    @SuppressWarnings("FinalizeDoesntCallSuperFinalize")
+    protected final void finalize() {
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/Object.java b/libdvm/src/main/java/java/lang/Object.java
new file mode 100644
index 0000000..d2cd2f1
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/Object.java
@@ -0,0 +1,443 @@
+/*
+ * 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) 2008 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;
+
+/**
+ * The root class of the Java class hierarchy. All non-primitive types
+ * (including arrays) inherit either directly or indirectly from this class.
+ *
+ * <a name="writing_equals"><h4>Writing a correct {@code equals} method</h4></a>
+ * <p>Follow this style to write a canonical {@code equals} method:
+ * <pre>
+ *   // Use @Override to avoid accidental overloading.
+ *   &#x0040;Override public boolean equals(Object o) {
+ *     // Return true if the objects are identical.
+ *     // (This is just an optimization, not required for correctness.)
+ *     if (this == o) {
+ *       return true;
+ *     }
+ *
+ *     // Return false if the other object has the wrong type.
+ *     // This type may be an interface depending on the interface's specification.
+ *     if (!(o instanceof MyType)) {
+ *       return false;
+ *     }
+ *
+ *     // Cast to the appropriate type.
+ *     // This will succeed because of the instanceof, and lets us access private fields.
+ *     MyType lhs = (MyType) o;
+ *
+ *     // Check each field. Primitive fields, reference fields, and nullable reference
+ *     // fields are all treated differently.
+ *     return primitiveField == lhs.primitiveField &amp;&amp;
+ *             referenceField.equals(lhs.referenceField) &amp;&amp;
+ *             (nullableField == null ? lhs.nullableField == null
+ *                                    : nullableField.equals(lhs.nullableField));
+ *   }
+ * </pre>
+ * <p>If you override {@code equals}, you should also override {@code hashCode}: equal
+ * instances must have equal hash codes.
+ *
+ * <p>See <i>Effective Java</i> item 8 for much more detail and clarification.
+ *
+ * <a name="writing_hashCode"><h4>Writing a correct {@code hashCode} method</h4></a>
+ * <p>Follow this style to write a canonical {@code hashCode} method:
+ * <pre>
+ *   &#x0040;Override public int hashCode() {
+ *     // Start with a non-zero constant.
+ *     int result = 17;
+ *
+ *     // Include a hash for each field.
+ *     result = 31 * result + (booleanField ? 1 : 0);
+ *
+ *     result = 31 * result + byteField;
+ *     result = 31 * result + charField;
+ *     result = 31 * result + shortField;
+ *     result = 31 * result + intField;
+ *
+ *     result = 31 * result + (int) (longField ^ (longField >>> 32));
+ *
+ *     result = 31 * result + Float.floatToIntBits(floatField);
+ *
+ *     long doubleFieldBits = Double.doubleToLongBits(doubleField);
+ *     result = 31 * result + (int) (doubleFieldBits ^ (doubleFieldBits >>> 32));
+ *
+ *     result = 31 * result + Arrays.hashCode(arrayField);
+ *
+ *     result = 31 * result + referenceField.hashCode();
+ *     result = 31 * result +
+ *         (nullableReferenceField == null ? 0
+ *                                         : nullableReferenceField.hashCode());
+ *
+ *     return result;
+ *   }
+ * </pre>
+ *
+ * <p>If you don't intend your type to be used as a hash key, don't simply rely on the default
+ * {@code hashCode} implementation, because that silently and non-obviously breaks any future
+ * code that does use your type as a hash key. You should throw instead:
+ * <pre>
+ *   &#x0040;Override public int hashCode() {
+ *     throw new UnsupportedOperationException();
+ *   }
+ * </pre>
+ *
+ * <p>See <i>Effective Java</i> item 9 for much more detail and clarification.
+ *
+ * <a name="writing_toString"><h4>Writing a useful {@code toString} method</h4></a>
+ * <p>For debugging convenience, it's common to override {@code toString} in this style:
+ * <pre>
+ *   &#x0040;Override public String toString() {
+ *     return getClass().getName() + "[" +
+ *         "primitiveField=" + primitiveField + ", " +
+ *         "referenceField=" + referenceField + ", " +
+ *         "arrayField=" + Arrays.toString(arrayField) + "]";
+ *   }
+ * </pre>
+ * <p>The set of fields to include is generally the same as those that would be tested
+ * in your {@code equals} implementation.
+ * <p>See <i>Effective Java</i> item 10 for much more detail and clarification.
+ */
+public class Object {
+    /**
+     * Constructs a new instance of {@code Object}.
+     */
+    public Object() {
+    }
+
+    /**
+     * Creates and returns a copy of this {@code Object}. The default
+     * implementation returns a so-called "shallow" copy: It creates a new
+     * instance of the same class and then copies the field values (including
+     * object references) from this instance to the new instance. A "deep" copy,
+     * in contrast, would also recursively clone nested objects. A subclass that
+     * needs to implement this kind of cloning should call {@code super.clone()}
+     * to create the new instance and then create deep copies of the nested,
+     * mutable objects.
+     *
+     * @return a copy of this object.
+     * @throws CloneNotSupportedException
+     *             if this object's class does not implement the {@code
+     *             Cloneable} interface.
+     */
+    protected Object clone() throws CloneNotSupportedException {
+        if (!(this instanceof Cloneable)) {
+            throw new CloneNotSupportedException("Class doesn't implement Cloneable");
+        }
+
+        return internalClone((Cloneable) this);
+    }
+
+    /*
+     * Native helper method for cloning.
+     */
+    private native Object internalClone(Cloneable o);
+
+    /**
+     * Compares this instance with the specified object and indicates if they
+     * are equal. In order to be equal, {@code o} must represent the same object
+     * as this instance using a class-specific comparison. The general contract
+     * is that this comparison should be reflexive, symmetric, and transitive.
+     * Also, no object reference other than null is equal to null.
+     *
+     * <p>The default implementation returns {@code true} only if {@code this ==
+     * o}. See <a href="{@docRoot}reference/java/lang/Object.html#writing_equals">Writing a correct
+     * {@code equals} method</a>
+     * if you intend implementing your own {@code equals} method.
+     *
+     * <p>The general contract for the {@code equals} and {@link
+     * #hashCode()} methods is that if {@code equals} returns {@code true} for
+     * any two objects, then {@code hashCode()} must return the same value for
+     * these objects. This means that subclasses of {@code Object} usually
+     * override either both methods or neither of them.
+     *
+     * @param o
+     *            the object to compare this instance with.
+     * @return {@code true} if the specified object is equal to this {@code
+     *         Object}; {@code false} otherwise.
+     * @see #hashCode
+     */
+    public boolean equals(Object o) {
+        return this == o;
+    }
+
+    /**
+     * Invoked when the garbage collector has detected that this instance is no longer reachable.
+     * The default implementation does nothing, but this method can be overridden to free resources.
+     *
+     * <p>Note that objects that override {@code finalize} are significantly more expensive than
+     * objects that don't. Finalizers may be run a long time after the object is no longer
+     * reachable, depending on memory pressure, so it's a bad idea to rely on them for cleanup.
+     * Note also that finalizers are run on a single VM-wide finalizer thread,
+     * so doing blocking work in a finalizer is a bad idea. A finalizer is usually only necessary
+     * for a class that has a native peer and needs to call a native method to destroy that peer.
+     * Even then, it's better to provide an explicit {@code close} method (and implement
+     * {@link java.io.Closeable}), and insist that callers manually dispose of instances. This
+     * works well for something like files, but less well for something like a {@code BigInteger}
+     * where typical calling code would have to deal with lots of temporaries. Unfortunately,
+     * code that creates lots of temporaries is the worst kind of code from the point of view of
+     * the single finalizer thread.
+     *
+     * <p>If you <i>must</i> use finalizers, consider at least providing your own
+     * {@link java.lang.ref.ReferenceQueue} and having your own thread process that queue.
+     *
+     * <p>Unlike constructors, finalizers are not automatically chained. You are responsible for
+     * calling {@code super.finalize()} yourself.
+     *
+     * <p>Uncaught exceptions thrown by finalizers are ignored and do not terminate the finalizer
+     * thread.
+     *
+     * See <i>Effective Java</i> Item 7, "Avoid finalizers" for more.
+     */
+    @FindBugsSuppressWarnings("FI_EMPTY")
+    protected void finalize() throws Throwable {
+    }
+
+    /**
+     * Returns the unique instance of {@link Class} that represents this
+     * object's class. Note that {@code getClass()} is a special case in that it
+     * actually returns {@code Class<? extends Foo>} where {@code Foo} is the
+     * erasure of the type of the expression {@code getClass()} was called upon.
+     * <p>
+     * As an example, the following code actually compiles, although one might
+     * think it shouldn't:
+     * <p>
+     * <pre>{@code
+     *   List<Integer> l = new ArrayList<Integer>();
+     *   Class<? extends List> c = l.getClass();}</pre>
+     *
+     * @return this object's {@code Class} instance.
+     */
+    public final native Class<?> getClass();
+
+    /**
+     * Returns an integer hash code for this object. By contract, any two
+     * objects for which {@link #equals} returns {@code true} must return
+     * the same hash code value. This means that subclasses of {@code Object}
+     * usually override both methods or neither method.
+     *
+     * <p>Note that hash values must not change over time unless information used in equals
+     * comparisons also changes.
+     *
+     * <p>See <a href="{@docRoot}reference/java/lang/Object.html#writing_hashCode">Writing a correct
+     * {@code hashCode} method</a>
+     * if you intend implementing your own {@code hashCode} method.
+     *
+     * @return this object's hash code.
+     * @see #equals
+     */
+    public native int hashCode();
+
+    /**
+     * Causes a thread which is waiting on this object's monitor (by means of
+     * calling one of the {@code wait()} methods) to be woken up. If more than
+     * one thread is waiting, one of them is chosen at the discretion of the
+     * VM. The chosen thread will not run immediately. The thread
+     * that called {@code notify()} has to release the object's monitor first.
+     * Also, the chosen thread still has to compete against other threads that
+     * try to synchronize on the same object.
+     *
+     * <p>This method can only be invoked by a thread which owns this object's
+     * monitor. A thread becomes owner of an object's monitor
+     * <ul>
+     * <li>by executing a synchronized method of that object;</li>
+     * <li>by executing the body of a {@code synchronized} statement that
+     * synchronizes on the object;</li>
+     * <li>by executing a synchronized static method if the object is of type
+     * {@code Class}.</li>
+     * </ul>
+     *
+     * @see #notifyAll
+     * @see #wait()
+     * @see #wait(long)
+     * @see #wait(long,int)
+     * @see java.lang.Thread
+     */
+    public final native void notify();
+
+    /**
+     * Causes all threads which are waiting on this object's monitor (by means
+     * of calling one of the {@code wait()} methods) to be woken up. The threads
+     * will not run immediately. The thread that called {@code notify()} has to
+     * release the object's monitor first. Also, the threads still have to
+     * compete against other threads that try to synchronize on the same object.
+     *
+     * <p>This method can only be invoked by a thread which owns this object's
+     * monitor. A thread becomes owner of an object's monitor
+     * <ul>
+     * <li>by executing a synchronized method of that object;</li>
+     * <li>by executing the body of a {@code synchronized} statement that
+     * synchronizes on the object;</li>
+     * <li>by executing a synchronized static method if the object is of type
+     * {@code Class}.</li>
+     * </ul>
+     *
+     * @throws IllegalMonitorStateException
+     *             if the thread calling this method is not the owner of this
+     *             object's monitor.
+     * @see #notify
+     * @see #wait()
+     * @see #wait(long)
+     * @see #wait(long,int)
+     * @see java.lang.Thread
+     */
+    public final native void notifyAll();
+
+    /**
+     * Returns a string containing a concise, human-readable description of this
+     * object. Subclasses are encouraged to override this method and provide an
+     * implementation that takes into account the object's type and data. The
+     * default implementation is equivalent to the following expression:
+     * <pre>
+     *   getClass().getName() + '@' + Integer.toHexString(hashCode())</pre>
+     * <p>See <a href="{@docRoot}reference/java/lang/Object.html#writing_toString">Writing a useful
+     * {@code toString} method</a>
+     * if you intend implementing your own {@code toString} method.
+     *
+     * @return a printable representation of this object.
+     */
+    public String toString() {
+        return getClass().getName() + '@' + Integer.toHexString(hashCode());
+    }
+
+    /**
+     * Causes the calling thread to wait until another thread calls the {@code
+     * notify()} or {@code notifyAll()} method of this object. This method can
+     * only be invoked by a thread which owns this object's monitor; see
+     * {@link #notify()} on how a thread can become the owner of a monitor.
+     *
+     * <p>A waiting thread can be sent {@code interrupt()} to cause it to
+     * prematurely stop waiting, so {@code wait} should be called in a loop to
+     * check that the condition that has been waited for has been met before
+     * continuing.
+     *
+     * <p>While the thread waits, it gives up ownership of this object's
+     * monitor. When it is notified (or interrupted), it re-acquires the monitor
+     * before it starts running.
+     *
+     * @throws IllegalMonitorStateException
+     *             if the thread calling this method is not the owner of this
+     *             object's monitor.
+     * @throws InterruptedException if the current thread has been interrupted.
+     *             The interrupted status of the current thread will be cleared before the exception
+     *             is thrown.
+     * @see #notify
+     * @see #notifyAll
+     * @see #wait(long)
+     * @see #wait(long,int)
+     * @see java.lang.Thread
+     */
+    public final void wait() throws InterruptedException {
+        wait(0, 0);
+    }
+
+    /**
+     * Causes the calling thread to wait until another thread calls the {@code
+     * notify()} or {@code notifyAll()} method of this object or until the
+     * specified timeout expires. This method can only be invoked by a thread
+     * which owns this object's monitor; see {@link #notify()} on how a thread
+     * can become the owner of a monitor.
+     *
+     * <p>A waiting thread can be sent {@code interrupt()} to cause it to
+     * prematurely stop waiting, so {@code wait} should be called in a loop to
+     * check that the condition that has been waited for has been met before
+     * continuing.
+     *
+     * <p>While the thread waits, it gives up ownership of this object's
+     * monitor. When it is notified (or interrupted), it re-acquires the monitor
+     * before it starts running.
+     *
+     * <p>A timeout of zero means the calling thread should wait forever unless interrupted or
+     * notified.
+     *
+     * @param millis
+     *            the maximum time to wait in milliseconds.
+     * @throws IllegalArgumentException
+     *             if {@code millis < 0}.
+     * @throws IllegalMonitorStateException
+     *             if the thread calling this method is not the owner of this
+     *             object's monitor.
+     * @throws InterruptedException if the current thread has been interrupted.
+     *             The interrupted status of the current thread will be cleared before the exception
+     *             is thrown.
+     * @see #notify
+     * @see #notifyAll
+     * @see #wait()
+     * @see #wait(long,int)
+     * @see java.lang.Thread
+     */
+    public final void wait(long millis) throws InterruptedException {
+        wait(millis, 0);
+    }
+
+    /**
+     * Causes the calling thread to wait until another thread calls the {@code
+     * notify()} or {@code notifyAll()} method of this object or until the
+     * specified timeout expires. This method can only be invoked by a thread
+     * that owns this object's monitor; see {@link #notify()} on how a thread
+     * can become the owner of a monitor.
+     *
+     * <p>A waiting thread can be sent {@code interrupt()} to cause it to
+     * prematurely stop waiting, so {@code wait} should be called in a loop to
+     * check that the condition that has been waited for has been met before
+     * continuing.
+     *
+     * <p>While the thread waits, it gives up ownership of this object's
+     * monitor. When it is notified (or interrupted), it re-acquires the monitor
+     * before it starts running.
+     *
+     * <p>A timeout of zero means the calling thread should wait forever unless interrupted or
+     * notified.
+     *
+     * @param millis
+     *            the maximum time to wait in milliseconds.
+     * @param nanos
+     *            the fraction of a millisecond to wait, specified in
+     *            nanoseconds.
+     * @throws IllegalArgumentException
+     *             if {@code millis < 0}, {@code nanos < 0} or {@code nanos >
+     *             999999}.
+     * @throws IllegalMonitorStateException
+     *             if the thread calling this method is not the owner of this
+     *             object's monitor.
+     * @throws InterruptedException if the current thread has been interrupted.
+     *             The interrupted status of the current thread will be cleared before the exception
+     *             is thrown.
+     * @see #notify
+     * @see #notifyAll
+     * @see #wait()
+     * @see #wait(long,int)
+     * @see java.lang.Thread
+     */
+    public final native void wait(long millis, int nanos) throws InterruptedException;
+}
diff --git a/libdvm/src/main/java/java/lang/String.java b/libdvm/src/main/java/java/lang/String.java
new file mode 100644
index 0000000..10a6301
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/String.java
@@ -0,0 +1,2075 @@
+/*
+ *  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 java.lang;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.Charsets;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Formatter;
+import java.util.Locale;
+import java.util.regex.Pattern;
+import libcore.util.EmptyArray;
+
+/**
+ * An immutable sequence of characters/code units ({@code char}s). A
+ * {@code String} is represented by array of UTF-16 values, such that
+ * Unicode supplementary characters (code points) are stored/encoded as
+ * surrogate pairs via Unicode code units ({@code char}).
+ *
+ * <a name="backing_array"><h3>Backing Arrays</h3></a>
+ * This class is implemented using a char[]. The length of the array may exceed
+ * the length of the string. For example, the string "Hello" may be backed by
+ * the array {@code ['H', 'e', 'l', 'l', 'o', 'W'. 'o', 'r', 'l', 'd']} with
+ * offset 0 and length 5.
+ *
+ * <p>Multiple strings can share the same char[] because strings are immutable.
+ * The {@link #substring} method <strong>always</strong> returns a string that
+ * shares the backing array of its source string. Generally this is an
+ * optimization: fewer character arrays need to be allocated, and less copying
+ * is necessary. But this can also lead to unwanted heap retention. Taking a
+ * short substring of long string means that the long shared char[] won't be
+ * garbage until both strings are garbage. This typically happens when parsing
+ * small substrings out of a large input. To avoid this where necessary, call
+ * {@code new String(longString.subString(...))}. The string copy constructor
+ * always ensures that the backing array is no larger than necessary.
+ *
+ * @see StringBuffer
+ * @see StringBuilder
+ * @see Charset
+ * @since 1.0
+ */
+public final class String implements Serializable, Comparable<String>, CharSequence {
+
+    private static final long serialVersionUID = -6849794470754667710L;
+
+    private static final char REPLACEMENT_CHAR = (char) 0xfffd;
+
+    /**
+     * CaseInsensitiveComparator compares Strings ignoring the case of the
+     * characters.
+     */
+    private static final class CaseInsensitiveComparator implements
+            Comparator<String>, Serializable {
+        private static final long serialVersionUID = 8575799808933029326L;
+
+        /**
+         * Compare the two objects to determine the relative ordering.
+         *
+         * @param o1
+         *            an Object to compare
+         * @param o2
+         *            an Object to compare
+         * @return an int < 0 if object1 is less than object2, 0 if they are
+         *         equal, and > 0 if object1 is greater
+         *
+         * @throws ClassCastException
+         *                if objects are not the correct type
+         */
+        public int compare(String o1, String o2) {
+            return o1.compareToIgnoreCase(o2);
+        }
+    }
+
+    /**
+     * A comparator ignoring the case of the characters.
+     */
+    public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
+
+    private static final char[] ASCII;
+    static {
+        ASCII = new char[128];
+        for (int i = 0; i < ASCII.length; ++i) {
+            ASCII[i] = (char) i;
+        }
+    }
+
+    private final char[] value;
+
+    private final int offset;
+
+    private final int count;
+
+    private int hashCode;
+
+    /**
+     * Creates an empty string.
+     */
+    public String() {
+        value = EmptyArray.CHAR;
+        offset = 0;
+        count = 0;
+    }
+
+    /*
+     * Private constructor used for JIT optimization.
+     */
+    @SuppressWarnings("unused")
+    private String(String s, char c) {
+        offset = 0;
+        value = new char[s.count + 1];
+        count = s.count + 1;
+        System.arraycopy(s.value, s.offset, value, 0, s.count);
+        value[s.count] = c;
+    }
+
+    /**
+     * Converts the byte array to a string using the system's
+     * {@link java.nio.charset.Charset#defaultCharset default charset}.
+     */
+    @FindBugsSuppressWarnings("DM_DEFAULT_ENCODING")
+    public String(byte[] data) {
+        this(data, 0, data.length);
+    }
+
+    /**
+     * Converts the byte array to a string, setting the high byte of every
+     * character to the specified value.
+     *
+     * @param data
+     *            the byte array to convert to a string.
+     * @param high
+     *            the high byte to use.
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @deprecated Use {@link #String(byte[])} or {@link #String(byte[], String)} instead.
+     */
+    @Deprecated
+    public String(byte[] data, int high) {
+        this(data, high, 0, data.length);
+    }
+
+    /**
+     * Converts a subsequence of the byte array to a string using the system's
+     * {@link java.nio.charset.Charset#defaultCharset default charset}.
+     *
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}.
+     */
+    public String(byte[] data, int offset, int byteCount) {
+        this(data, offset, byteCount, Charset.defaultCharset());
+    }
+
+    /**
+     * Converts the byte array to a string, setting the high byte of every
+     * character to {@code high}.
+     *
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}
+     *
+     * @deprecated Use {@link #String(byte[], int, int)} instead.
+     */
+    @Deprecated
+    public String(byte[] data, int high, int offset, int byteCount) {
+        if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
+            throw failedBoundsCheck(data.length, offset, byteCount);
+        }
+        this.offset = 0;
+        this.value = new char[byteCount];
+        this.count = byteCount;
+        high <<= 8;
+        for (int i = 0; i < count; i++) {
+            value[i] = (char) (high + (data[offset++] & 0xff));
+        }
+    }
+
+    /**
+     * Converts the byte array to a string using the named charset.
+     *
+     * <p>The behavior when the bytes cannot be decoded by the named charset
+     * is unspecified. Use {@link java.nio.charset.CharsetDecoder} for more control.
+     *
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}.
+     * @throws UnsupportedEncodingException
+     *             if the named charset is not supported.
+     */
+    public String(byte[] data, int offset, int byteCount, String charsetName) throws UnsupportedEncodingException {
+        this(data, offset, byteCount, Charset.forNameUEE(charsetName));
+    }
+
+    /**
+     * Converts the byte array to a string using the named charset.
+     *
+     * <p>The behavior when the bytes cannot be decoded by the named charset
+     * is unspecified. Use {@link java.nio.charset.CharsetDecoder} for more control.
+     *
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @throws UnsupportedEncodingException
+     *             if {@code charsetName} is not supported.
+     */
+    public String(byte[] data, String charsetName) throws UnsupportedEncodingException {
+        this(data, 0, data.length, Charset.forNameUEE(charsetName));
+    }
+
+    /**
+     * Converts the byte array to a string using the given charset.
+     *
+     * <p>The behavior when the bytes cannot be decoded by the given charset
+     * is to replace malformed input and unmappable characters with the charset's default
+     * replacement string. Use {@link java.nio.charset.CharsetDecoder} for more control.
+     *
+     * @throws IndexOutOfBoundsException
+     *             if {@code byteCount < 0 || offset < 0 || offset + byteCount > data.length}
+     * @throws NullPointerException
+     *             if {@code data == null}
+     *
+     * @since 1.6
+     */
+    public String(byte[] data, int offset, int byteCount, Charset charset) {
+        if ((offset | byteCount) < 0 || byteCount > data.length - offset) {
+            throw failedBoundsCheck(data.length, offset, byteCount);
+        }
+
+        // We inline UTF-8, ISO-8859-1, and US-ASCII decoders for speed and because 'count' and
+        // 'value' are final.
+        String canonicalCharsetName = charset.name();
+        if (canonicalCharsetName.equals("UTF-8")) {
+            byte[] d = data;
+            char[] v = new char[byteCount];
+
+            int idx = offset;
+            int last = offset + byteCount;
+            int s = 0;
+outer:
+            while (idx < last) {
+                byte b0 = d[idx++];
+                if ((b0 & 0x80) == 0) {
+                    // 0xxxxxxx
+                    // Range:  U-00000000 - U-0000007F
+                    int val = b0 & 0xff;
+                    v[s++] = (char) val;
+                } else if (((b0 & 0xe0) == 0xc0) || ((b0 & 0xf0) == 0xe0) ||
+                        ((b0 & 0xf8) == 0xf0) || ((b0 & 0xfc) == 0xf8) || ((b0 & 0xfe) == 0xfc)) {
+                    int utfCount = 1;
+                    if ((b0 & 0xf0) == 0xe0) utfCount = 2;
+                    else if ((b0 & 0xf8) == 0xf0) utfCount = 3;
+                    else if ((b0 & 0xfc) == 0xf8) utfCount = 4;
+                    else if ((b0 & 0xfe) == 0xfc) utfCount = 5;
+
+                    // 110xxxxx (10xxxxxx)+
+                    // Range:  U-00000080 - U-000007FF (count == 1)
+                    // Range:  U-00000800 - U-0000FFFF (count == 2)
+                    // Range:  U-00010000 - U-001FFFFF (count == 3)
+                    // Range:  U-00200000 - U-03FFFFFF (count == 4)
+                    // Range:  U-04000000 - U-7FFFFFFF (count == 5)
+
+                    if (idx + utfCount > last) {
+                        v[s++] = REPLACEMENT_CHAR;
+                        continue;
+                    }
+
+                    // Extract usable bits from b0
+                    int val = b0 & (0x1f >> (utfCount - 1));
+                    for (int i = 0; i < utfCount; ++i) {
+                        byte b = d[idx++];
+                        if ((b & 0xc0) != 0x80) {
+                            v[s++] = REPLACEMENT_CHAR;
+                            idx--; // Put the input char back
+                            continue outer;
+                        }
+                        // Push new bits in from the right side
+                        val <<= 6;
+                        val |= b & 0x3f;
+                    }
+
+                    // Note: Java allows overlong char
+                    // specifications To disallow, check that val
+                    // is greater than or equal to the minimum
+                    // value for each count:
+                    //
+                    // count    min value
+                    // -----   ----------
+                    //   1           0x80
+                    //   2          0x800
+                    //   3        0x10000
+                    //   4       0x200000
+                    //   5      0x4000000
+
+                    // Allow surrogate values (0xD800 - 0xDFFF) to
+                    // be specified using 3-byte UTF values only
+                    if ((utfCount != 2) && (val >= 0xD800) && (val <= 0xDFFF)) {
+                        v[s++] = REPLACEMENT_CHAR;
+                        continue;
+                    }
+
+                    // Reject chars greater than the Unicode maximum of U+10FFFF.
+                    if (val > 0x10FFFF) {
+                        v[s++] = REPLACEMENT_CHAR;
+                        continue;
+                    }
+
+                    // Encode chars from U+10000 up as surrogate pairs
+                    if (val < 0x10000) {
+                        v[s++] = (char) val;
+                    } else {
+                        int x = val & 0xffff;
+                        int u = (val >> 16) & 0x1f;
+                        int w = (u - 1) & 0xffff;
+                        int hi = 0xd800 | (w << 6) | (x >> 10);
+                        int lo = 0xdc00 | (x & 0x3ff);
+                        v[s++] = (char) hi;
+                        v[s++] = (char) lo;
+                    }
+                } else {
+                    // Illegal values 0x8*, 0x9*, 0xa*, 0xb*, 0xfd-0xff
+                    v[s++] = REPLACEMENT_CHAR;
+                }
+            }
+
+            if (s == byteCount) {
+                // We guessed right, so we can use our temporary array as-is.
+                this.offset = 0;
+                this.value = v;
+                this.count = s;
+            } else {
+                // Our temporary array was too big, so reallocate and copy.
+                this.offset = 0;
+                this.value = new char[s];
+                this.count = s;
+                System.arraycopy(v, 0, value, 0, s);
+            }
+        } else if (canonicalCharsetName.equals("ISO-8859-1")) {
+            this.offset = 0;
+            this.value = new char[byteCount];
+            this.count = byteCount;
+            Charsets.isoLatin1BytesToChars(data, offset, byteCount, value);
+        } else if (canonicalCharsetName.equals("US-ASCII")) {
+            this.offset = 0;
+            this.value = new char[byteCount];
+            this.count = byteCount;
+            Charsets.asciiBytesToChars(data, offset, byteCount, value);
+        } else {
+            CharBuffer cb = charset.decode(ByteBuffer.wrap(data, offset, byteCount));
+            this.offset = 0;
+            this.count = cb.length();
+            if (count > 0) {
+                // We could use cb.array() directly, but that would mean we'd have to trust
+                // the CharsetDecoder doesn't hang on to the CharBuffer and mutate it later,
+                // which would break String's immutability guarantee. It would also tend to
+                // mean that we'd be wasting memory because CharsetDecoder doesn't trim the
+                // array. So we copy.
+                this.value = new char[count];
+                System.arraycopy(cb.array(), 0, value, 0, count);
+            } else {
+                this.value = EmptyArray.CHAR;
+            }
+        }
+    }
+
+    /**
+     * Converts the byte array to a String using the given charset.
+     *
+     * @throws NullPointerException if {@code data == null}
+     * @since 1.6
+     */
+    public String(byte[] data, Charset charset) {
+        this(data, 0, data.length, charset);
+    }
+
+    /**
+     * Initializes this string to contain the characters in the specified
+     * character array. Modifying the character array after creating the string
+     * has no effect on the string.
+     *
+     * @throws NullPointerException if {@code data == null}
+     */
+    public String(char[] data) {
+        this(data, 0, data.length);
+    }
+
+    /**
+     * Initializes this string to contain the specified characters in the
+     * character array. Modifying the character array after creating the string
+     * has no effect on the string.
+     *
+     * @throws NullPointerException
+     *             if {@code data == null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code charCount < 0 || offset < 0 || offset + charCount > data.length}
+     */
+    public String(char[] data, int offset, int charCount) {
+        if ((offset | charCount) < 0 || charCount > data.length - offset) {
+            throw failedBoundsCheck(data.length, offset, charCount);
+        }
+        this.offset = 0;
+        this.value = new char[charCount];
+        this.count = charCount;
+        System.arraycopy(data, offset, value, 0, count);
+    }
+
+    /*
+     * Internal version of the String(char[], int, int) constructor.
+     * Does not range check, null check, or copy the character array.
+     */
+    String(int offset, int charCount, char[] chars) {
+        this.value = chars;
+        this.offset = offset;
+        this.count = charCount;
+    }
+
+    /**
+     * Constructs a new string with the same sequence of characters as {@code
+     * toCopy}. The returned string's <a href="#backing_array">backing array</a>
+     * is no larger than necessary.
+     */
+    public String(String toCopy) {
+        value = (toCopy.value.length == toCopy.count)
+                ? toCopy.value
+                : Arrays.copyOfRange(toCopy.value, toCopy.offset, toCopy.offset + toCopy.length());
+        offset = 0;
+        count = value.length;
+    }
+
+    /*
+     * Private constructor useful for JIT optimization.
+     */
+    @SuppressWarnings( { "unused", "nls" })
+    private String(String s1, String s2) {
+        if (s1 == null) {
+            s1 = "null";
+        }
+        if (s2 == null) {
+            s2 = "null";
+        }
+        count = s1.count + s2.count;
+        value = new char[count];
+        offset = 0;
+        System.arraycopy(s1.value, s1.offset, value, 0, s1.count);
+        System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count);
+    }
+
+    /*
+     * Private constructor useful for JIT optimization.
+     */
+    @SuppressWarnings( { "unused", "nls" })
+    private String(String s1, String s2, String s3) {
+        if (s1 == null) {
+            s1 = "null";
+        }
+        if (s2 == null) {
+            s2 = "null";
+        }
+        if (s3 == null) {
+            s3 = "null";
+        }
+        count = s1.count + s2.count + s3.count;
+        value = new char[count];
+        offset = 0;
+        System.arraycopy(s1.value, s1.offset, value, 0, s1.count);
+        System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count);
+        System.arraycopy(s3.value, s3.offset, value, s1.count + s2.count, s3.count);
+    }
+
+    /**
+     * Creates a {@code String} from the contents of the specified
+     * {@code StringBuffer}.
+     */
+    public String(StringBuffer stringBuffer) {
+        offset = 0;
+        synchronized (stringBuffer) {
+            value = stringBuffer.shareValue();
+            count = stringBuffer.length();
+        }
+    }
+
+    /**
+     * Creates a {@code String} from the sub-array of Unicode code points.
+     *
+     * @throws NullPointerException
+     *             if {@code codePoints == null}.
+     * @throws IllegalArgumentException
+     *             if any of the elements of {@code codePoints} are not valid
+     *             Unicode code points.
+     * @throws IndexOutOfBoundsException
+     *             if {@code offset} or {@code count} are not within the bounds
+     *             of {@code codePoints}.
+     * @since 1.5
+     */
+    public String(int[] codePoints, int offset, int count) {
+        if (codePoints == null) {
+            throw new NullPointerException("codePoints == null");
+        }
+        if ((offset | count) < 0 || count > codePoints.length - offset) {
+            throw failedBoundsCheck(codePoints.length, offset, count);
+        }
+        this.offset = 0;
+        this.value = new char[count * 2];
+        int end = offset + count;
+        int c = 0;
+        for (int i = offset; i < end; i++) {
+            c += Character.toChars(codePoints[i], this.value, c);
+        }
+        this.count = c;
+    }
+
+    /**
+     * Creates a {@code String} from the contents of the specified {@code
+     * StringBuilder}.
+     *
+     * @throws NullPointerException
+     *             if {@code stringBuilder == null}.
+     * @since 1.5
+     */
+    public String(StringBuilder stringBuilder) {
+        if (stringBuilder == null) {
+            throw new NullPointerException("stringBuilder == null");
+        }
+        this.offset = 0;
+        this.count = stringBuilder.length();
+        this.value = new char[this.count];
+        stringBuilder.getChars(0, this.count, this.value, 0);
+    }
+
+    /*
+     * Creates a {@code String} that is s1 + v1. May be used by JIT code.
+     */
+    @SuppressWarnings("unused")
+    private String(String s1, int v1) {
+        if (s1 == null) {
+            s1 = "null";
+        }
+        String s2 = String.valueOf(v1);
+        int len = s1.count + s2.count;
+        value = new char[len];
+        offset = 0;
+        System.arraycopy(s1.value, s1.offset, value, 0, s1.count);
+        System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count);
+        count = len;
+    }
+
+    /**
+     * Returns the character at {@code index}.
+     * @throws IndexOutOfBoundsException if {@code index < 0} or {@code index >= length()}.
+     */
+    public char charAt(int index) {
+        if (index < 0 || index >= count) {
+            throw indexAndLength(index);
+        }
+        return value[offset + index];
+    }
+
+    private StringIndexOutOfBoundsException indexAndLength(int index) {
+        throw new StringIndexOutOfBoundsException(this, index);
+    }
+
+    private StringIndexOutOfBoundsException startEndAndLength(int start, int end) {
+        throw new StringIndexOutOfBoundsException(this, start, end - start);
+    }
+
+    private StringIndexOutOfBoundsException failedBoundsCheck(int arrayLength, int offset, int count) {
+        throw new StringIndexOutOfBoundsException(arrayLength, offset, count);
+    }
+
+    /**
+     * This isn't equivalent to either of ICU's u_foldCase case folds, and thus any of the Unicode
+     * case folds, but it's what the RI uses.
+     */
+    private char foldCase(char ch) {
+        if (ch < 128) {
+            if ('A' <= ch && ch <= 'Z') {
+                return (char) (ch + ('a' - 'A'));
+            }
+            return ch;
+        }
+        return Character.toLowerCase(Character.toUpperCase(ch));
+    }
+
+    /**
+     * Compares the specified string to this string using the Unicode values of
+     * the characters. Returns 0 if the strings contain the same characters in
+     * the same order. Returns a negative integer if the first non-equal
+     * character in this string has a Unicode value which is less than the
+     * Unicode value of the character at the same position in the specified
+     * string, or if this string is a prefix of the specified string. Returns a
+     * positive integer if the first non-equal character in this string has a
+     * Unicode value which is greater than the Unicode value of the character at
+     * the same position in the specified string, or if the specified string is
+     * a prefix of this string.
+     *
+     * @param string
+     *            the string to compare.
+     * @return 0 if the strings are equal, a negative integer if this string is
+     *         before the specified string, or a positive integer if this string
+     *         is after the specified string.
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public native int compareTo(String string);
+
+    /**
+     * Compares the specified string to this string using the Unicode values of
+     * the characters, ignoring case differences. Returns 0 if the strings
+     * contain the same characters in the same order. Returns a negative integer
+     * if the first non-equal character in this string has a Unicode value which
+     * is less than the Unicode value of the character at the same position in
+     * the specified string, or if this string is a prefix of the specified
+     * string. Returns a positive integer if the first non-equal character in
+     * this string has a Unicode value which is greater than the Unicode value
+     * of the character at the same position in the specified string, or if the
+     * specified string is a prefix of this string.
+     *
+     * @param string
+     *            the string to compare.
+     * @return 0 if the strings are equal, a negative integer if this string is
+     *         before the specified string, or a positive integer if this string
+     *         is after the specified string.
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public int compareToIgnoreCase(String string) {
+        int o1 = offset, o2 = string.offset, result;
+        int end = offset + (count < string.count ? count : string.count);
+        char c1, c2;
+        char[] target = string.value;
+        while (o1 < end) {
+            if ((c1 = value[o1++]) == (c2 = target[o2++])) {
+                continue;
+            }
+            c1 = foldCase(c1);
+            c2 = foldCase(c2);
+            if ((result = c1 - c2) != 0) {
+                return result;
+            }
+        }
+        return count - string.count;
+    }
+
+    /**
+     * Concatenates this string and the specified string.
+     *
+     * @param string
+     *            the string to concatenate
+     * @return a new string which is the concatenation of this string and the
+     *         specified string.
+     */
+    public String concat(String string) {
+        if (string.count > 0 && count > 0) {
+            char[] buffer = new char[count + string.count];
+            System.arraycopy(value, offset, buffer, 0, count);
+            System.arraycopy(string.value, string.offset, buffer, count, string.count);
+            return new String(0, buffer.length, buffer);
+        }
+        return count == 0 ? string : this;
+    }
+
+    /**
+     * Creates a new string containing the characters in the specified character
+     * array. Modifying the character array after creating the string has no
+     * effect on the string.
+     *
+     * @param data
+     *            the array of characters.
+     * @return the new string.
+     * @throws NullPointerException
+     *             if {@code data} is {@code null}.
+     */
+    public static String copyValueOf(char[] data) {
+        return new String(data, 0, data.length);
+    }
+
+    /**
+     * Creates a new string containing the specified characters in the character
+     * array. Modifying the character array after creating the string has no
+     * effect on the string.
+     *
+     * @param data
+     *            the array of characters.
+     * @param start
+     *            the starting offset in the character array.
+     * @param length
+     *            the number of characters to use.
+     * @return the new string.
+     * @throws NullPointerException
+     *             if {@code data} is {@code null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code length < 0, start < 0} or {@code start + length >
+     *             data.length}.
+     */
+    public static String copyValueOf(char[] data, int start, int length) {
+        return new String(data, start, length);
+    }
+
+    /**
+     * Compares the specified string to this string to determine if the
+     * specified string is a suffix.
+     *
+     * @param suffix
+     *            the suffix to look for.
+     * @return {@code true} if the specified string is a suffix of this string,
+     *         {@code false} otherwise.
+     * @throws NullPointerException
+     *             if {@code suffix} is {@code null}.
+     */
+    public boolean endsWith(String suffix) {
+        return regionMatches(count - suffix.count, suffix, 0, suffix.count);
+    }
+
+    /**
+     * Compares the specified object to this string and returns true if they are
+     * equal. The object must be an instance of string with the same characters
+     * in the same order.
+     *
+     * @param other
+     *            the object to compare.
+     * @return {@code true} if the specified object is equal to this string,
+     *         {@code false} otherwise.
+     * @see #hashCode
+     */
+    @Override public boolean equals(Object other) {
+        if (other == this) {
+          return true;
+        }
+        if (other instanceof String) {
+            String s = (String)other;
+            int count = this.count;
+            if (s.count != count) {
+                return false;
+            }
+            // TODO: we want to avoid many boundchecks in the loop below
+            // for long Strings until we have array equality intrinsic.
+            // Bad benchmarks just push .equals without first getting a
+            // hashCode hit (unlike real world use in a Hashtable). Filter
+            // out these long strings here. When we get the array equality
+            // intrinsic then remove this use of hashCode.
+            if (hashCode() != s.hashCode()) {
+                return false;
+            }
+            char[] value1 = value;
+            int offset1 = offset;
+            char[] value2 = s.value;
+            int offset2 = s.offset;
+            for (int end = offset1 + count; offset1 < end; ) {
+                if (value1[offset1] != value2[offset2]) {
+                    return false;
+                }
+                offset1++;
+                offset2++;
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Compares the specified string to this string ignoring the case of the
+     * characters and returns true if they are equal.
+     *
+     * @param string
+     *            the string to compare.
+     * @return {@code true} if the specified string is equal to this string,
+     *         {@code false} otherwise.
+     */
+    @FindBugsSuppressWarnings("ES_COMPARING_PARAMETER_STRING_WITH_EQ")
+    public boolean equalsIgnoreCase(String string) {
+        if (string == this) {
+            return true;
+        }
+        if (string == null || count != string.count) {
+            return false;
+        }
+        int o1 = offset, o2 = string.offset;
+        int end = offset + count;
+        char[] target = string.value;
+        while (o1 < end) {
+            char c1 = value[o1++];
+            char c2 = target[o2++];
+            if (c1 != c2 && foldCase(c1) != foldCase(c2)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Mangles this string into a byte array by stripping the high order bits from
+     * each character. Use {@link #getBytes()} or {@link #getBytes(String)} instead.
+     *
+     * @param start
+     *            the starting offset of characters to copy.
+     * @param end
+     *            the ending offset of characters to copy.
+     * @param data
+     *            the destination byte array.
+     * @param index
+     *            the starting offset in the destination byte array.
+     * @throws NullPointerException
+     *             if {@code data} is {@code null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code start < 0}, {@code end > length()}, {@code index <
+     *             0} or {@code end - start > data.length - index}.
+     * @deprecated Use {@link #getBytes()} or {@link #getBytes(String)} instead.
+     */
+    @Deprecated
+    public void getBytes(int start, int end, byte[] data, int index) {
+        // Note: last character not copied!
+        if (start >= 0 && start <= end && end <= count) {
+            end += offset;
+            try {
+                for (int i = offset + start; i < end; i++) {
+                    data[index++] = (byte) value[i];
+                }
+            } catch (ArrayIndexOutOfBoundsException ignored) {
+                throw failedBoundsCheck(data.length, index, end - start);
+            }
+        } else {
+            throw startEndAndLength(start, end);
+        }
+    }
+
+    /**
+     * Returns a new byte array containing the characters of this string encoded using the
+     * system's {@link java.nio.charset.Charset#defaultCharset default charset}.
+     *
+     * <p>The behavior when this string cannot be represented in the system's default charset
+     * is unspecified. In practice, when the default charset is UTF-8 (as it is on Android),
+     * all strings can be encoded.
+     */
+    public byte[] getBytes() {
+        return getBytes(Charset.defaultCharset());
+    }
+
+    /**
+     * Returns a new byte array containing the characters of this string encoded using the
+     * named charset.
+     *
+     * <p>The behavior when this string cannot be represented in the named charset
+     * is unspecified. Use {@link java.nio.charset.CharsetEncoder} for more control.
+     *
+     * @throws UnsupportedEncodingException if the charset is not supported
+     */
+    public byte[] getBytes(String charsetName) throws UnsupportedEncodingException {
+        return getBytes(Charset.forNameUEE(charsetName));
+    }
+
+    /**
+     * Returns a new byte array containing the characters of this string encoded using the
+     * given charset.
+     *
+     * <p>The behavior when this string cannot be represented in the given charset
+     * is to replace malformed input and unmappable characters with the charset's default
+     * replacement byte array. Use {@link java.nio.charset.CharsetEncoder} for more control.
+     *
+     * @since 1.6
+     */
+    public byte[] getBytes(Charset charset) {
+        String canonicalCharsetName = charset.name();
+        if (canonicalCharsetName.equals("UTF-8")) {
+            return Charsets.toUtf8Bytes(value, offset, count);
+        } else if (canonicalCharsetName.equals("ISO-8859-1")) {
+            return Charsets.toIsoLatin1Bytes(value, offset, count);
+        } else if (canonicalCharsetName.equals("US-ASCII")) {
+            return Charsets.toAsciiBytes(value, offset, count);
+        } else if (canonicalCharsetName.equals("UTF-16BE")) {
+            return Charsets.toBigEndianUtf16Bytes(value, offset, count);
+        } else {
+            CharBuffer chars = CharBuffer.wrap(this.value, this.offset, this.count);
+            ByteBuffer buffer = charset.encode(chars.asReadOnlyBuffer());
+            byte[] bytes = new byte[buffer.limit()];
+            buffer.get(bytes);
+            return bytes;
+        }
+    }
+
+    /**
+     * Copies the specified characters in this string to the character array
+     * starting at the specified offset in the character array.
+     *
+     * @param start
+     *            the starting offset of characters to copy.
+     * @param end
+     *            the ending offset of characters to copy.
+     * @param buffer
+     *            the destination character array.
+     * @param index
+     *            the starting offset in the character array.
+     * @throws NullPointerException
+     *             if {@code buffer} is {@code null}.
+     * @throws IndexOutOfBoundsException
+     *             if {@code start < 0}, {@code end > length()}, {@code start >
+     *             end}, {@code index < 0}, {@code end - start > buffer.length -
+     *             index}
+     */
+    public void getChars(int start, int end, char[] buffer, int index) {
+        // Note: last character not copied!
+        if (start >= 0 && start <= end && end <= count) {
+            System.arraycopy(value, start + offset, buffer, index, end - start);
+        } else {
+            // We throw StringIndexOutOfBoundsException rather than System.arraycopy's AIOOBE.
+            throw startEndAndLength(start, end);
+        }
+    }
+
+    /**
+     * Version of getChars without bounds checks, for use by other classes
+     * within the java.lang package only.  The caller is responsible for
+     * ensuring that start >= 0 && start <= end && end <= count.
+     */
+    void _getChars(int start, int end, char[] buffer, int index) {
+        // NOTE last character not copied!
+        System.arraycopy(value, start + offset, buffer, index, end - start);
+    }
+
+    @Override public int hashCode() {
+        int hash = hashCode;
+        if (hash == 0) {
+            if (count == 0) {
+                return 0;
+            }
+            final int end = count + offset;
+            final char[] chars = value;
+            for (int i = offset; i < end; ++i) {
+                hash = 31*hash + chars[i];
+            }
+            hashCode = hash;
+        }
+        return hash;
+    }
+
+    /**
+     * Searches in this string for the first index of the specified character.
+     * The search for the character starts at the beginning and moves towards
+     * the end of this string.
+     *
+     * @param c
+     *            the character to find.
+     * @return the index in this string of the specified character, -1 if the
+     *         character isn't found.
+     */
+    public int indexOf(int c) {
+        // TODO: just "return indexOf(c, 0);" when the JIT can inline that deep.
+        if (c > 0xffff) {
+            return indexOfSupplementary(c, 0);
+        }
+        return fastIndexOf(c, 0);
+    }
+
+    /**
+     * Searches in this string for the index of the specified character. The
+     * search for the character starts at the specified offset and moves towards
+     * the end of this string.
+     *
+     * @param c
+     *            the character to find.
+     * @param start
+     *            the starting offset.
+     * @return the index in this string of the specified character, -1 if the
+     *         character isn't found.
+     */
+    public int indexOf(int c, int start) {
+        if (c > 0xffff) {
+            return indexOfSupplementary(c, start);
+        }
+        return fastIndexOf(c, start);
+    }
+
+    private native int fastIndexOf(int c, int start);
+
+    private int indexOfSupplementary(int c, int start) {
+        if (!Character.isSupplementaryCodePoint(c)) {
+            return -1;
+        }
+        char[] chars = Character.toChars(c);
+        String needle = new String(0, chars.length, chars);
+        return indexOf(needle, start);
+    }
+
+    /**
+     * Searches in this string for the first index of the specified string. The
+     * search for the string starts at the beginning and moves towards the end
+     * of this string.
+     *
+     * @param string
+     *            the string to find.
+     * @return the index of the first character of the specified string in this
+     *         string, -1 if the specified string is not a substring.
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public int indexOf(String string) {
+        int start = 0;
+        int subCount = string.count;
+        int _count = count;
+        if (subCount > 0) {
+            if (subCount > _count) {
+                return -1;
+            }
+            char[] target = string.value;
+            int subOffset = string.offset;
+            char firstChar = target[subOffset];
+            int end = subOffset + subCount;
+            while (true) {
+                int i = indexOf(firstChar, start);
+                if (i == -1 || subCount + i > _count) {
+                    return -1; // handles subCount > count || start >= count
+                }
+                int o1 = offset + i, o2 = subOffset;
+                char[] _value = value;
+                while (++o2 < end && _value[++o1] == target[o2]) {
+                    // Intentionally empty
+                }
+                if (o2 == end) {
+                    return i;
+                }
+                start = i + 1;
+            }
+        }
+        return start < _count ? start : _count;
+    }
+
+    /**
+     * Searches in this string for the index of the specified string. The search
+     * for the string starts at the specified offset and moves towards the end
+     * of this string.
+     *
+     * @param subString
+     *            the string to find.
+     * @param start
+     *            the starting offset.
+     * @return the index of the first character of the specified string in this
+     *         string, -1 if the specified string is not a substring.
+     * @throws NullPointerException
+     *             if {@code subString} is {@code null}.
+     */
+    public int indexOf(String subString, int start) {
+        if (start < 0) {
+            start = 0;
+        }
+        int subCount = subString.count;
+        int _count = count;
+        if (subCount > 0) {
+            if (subCount + start > _count) {
+                return -1;
+            }
+            char[] target = subString.value;
+            int subOffset = subString.offset;
+            char firstChar = target[subOffset];
+            int end = subOffset + subCount;
+            while (true) {
+                int i = indexOf(firstChar, start);
+                if (i == -1 || subCount + i > _count) {
+                    return -1; // handles subCount > count || start >= count
+                }
+                int o1 = offset + i, o2 = subOffset;
+                char[] _value = value;
+                while (++o2 < end && _value[++o1] == target[o2]) {
+                    // Intentionally empty
+                }
+                if (o2 == end) {
+                    return i;
+                }
+                start = i + 1;
+            }
+        }
+        return start < _count ? start : _count;
+    }
+
+    /**
+     * Returns an interned string equal to this string. The VM maintains an internal set of
+     * unique strings. All string literals found in loaded classes'
+     * constant pools are automatically interned. Manually-interned strings are only weakly
+     * referenced, so calling {@code intern} won't lead to unwanted retention.
+     *
+     * <p>Interning is typically used because it guarantees that for interned strings
+     * {@code a} and {@code b}, {@code a.equals(b)} can be simplified to
+     * {@code a == b}. (This is not true of non-interned strings.)
+     *
+     * <p>Many applications find it simpler and more convenient to use an explicit
+     * {@link java.util.HashMap} to implement their own pools.
+     */
+    public native String intern();
+
+    /**
+     * Returns true if the length of this string is 0.
+     *
+     * @since 1.6
+     */
+    public boolean isEmpty() {
+        return count == 0;
+    }
+
+    /**
+     * Returns the last index of the code point {@code c}, or -1.
+     * The search for the character starts at the end and moves towards the
+     * beginning of this string.
+     */
+    public int lastIndexOf(int c) {
+        if (c > 0xffff) {
+            return lastIndexOfSupplementary(c, Integer.MAX_VALUE);
+        }
+        int _count = count;
+        int _offset = offset;
+        char[] _value = value;
+        for (int i = _offset + _count - 1; i >= _offset; --i) {
+            if (_value[i] == c) {
+                return i - _offset;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the last index of the code point {@code c}, or -1.
+     * The search for the character starts at offset {@code start} and moves towards
+     * the beginning of this string.
+     */
+    public int lastIndexOf(int c, int start) {
+        if (c > 0xffff) {
+            return lastIndexOfSupplementary(c, start);
+        }
+        int _count = count;
+        int _offset = offset;
+        char[] _value = value;
+        if (start >= 0) {
+            if (start >= _count) {
+                start = _count - 1;
+            }
+            for (int i = _offset + start; i >= _offset; --i) {
+                if (_value[i] == c) {
+                    return i - _offset;
+                }
+            }
+        }
+        return -1;
+    }
+
+    private int lastIndexOfSupplementary(int c, int start) {
+        if (!Character.isSupplementaryCodePoint(c)) {
+            return -1;
+        }
+        char[] chars = Character.toChars(c);
+        String needle = new String(0, chars.length, chars);
+        return lastIndexOf(needle, start);
+    }
+
+    /**
+     * Searches in this string for the last index of the specified string. The
+     * search for the string starts at the end and moves towards the beginning
+     * of this string.
+     *
+     * @param string
+     *            the string to find.
+     * @return the index of the first character of the specified string in this
+     *         string, -1 if the specified string is not a substring.
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public int lastIndexOf(String string) {
+        // Use count instead of count - 1 so lastIndexOf("") returns count
+        return lastIndexOf(string, count);
+    }
+
+    /**
+     * Searches in this string for the index of the specified string. The search
+     * for the string starts at the specified offset and moves towards the
+     * beginning of this string.
+     *
+     * @param subString
+     *            the string to find.
+     * @param start
+     *            the starting offset.
+     * @return the index of the first character of the specified string in this
+     *         string , -1 if the specified string is not a substring.
+     * @throws NullPointerException
+     *             if {@code subString} is {@code null}.
+     */
+    public int lastIndexOf(String subString, int start) {
+        int subCount = subString.count;
+        if (subCount <= count && start >= 0) {
+            if (subCount > 0) {
+                if (start > count - subCount) {
+                    start = count - subCount;
+                }
+                // count and subCount are both >= 1
+                char[] target = subString.value;
+                int subOffset = subString.offset;
+                char firstChar = target[subOffset];
+                int end = subOffset + subCount;
+                while (true) {
+                    int i = lastIndexOf(firstChar, start);
+                    if (i == -1) {
+                        return -1;
+                    }
+                    int o1 = offset + i, o2 = subOffset;
+                    while (++o2 < end && value[++o1] == target[o2]) {
+                        // Intentionally empty
+                    }
+                    if (o2 == end) {
+                        return i;
+                    }
+                    start = i - 1;
+                }
+            }
+            return start < count ? start : count;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the number of characters in this string.
+     */
+    public int length() {
+        return count;
+    }
+
+    /**
+     * Compares the specified string to this string and compares the specified
+     * range of characters to determine if they are the same.
+     *
+     * @param thisStart
+     *            the starting offset in this string.
+     * @param string
+     *            the string to compare.
+     * @param start
+     *            the starting offset in the specified string.
+     * @param length
+     *            the number of characters to compare.
+     * @return {@code true} if the ranges of characters are equal, {@code false}
+     *         otherwise
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public boolean regionMatches(int thisStart, String string, int start, int length) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+        if (start < 0 || string.count - start < length) {
+            return false;
+        }
+        if (thisStart < 0 || count - thisStart < length) {
+            return false;
+        }
+        if (length <= 0) {
+            return true;
+        }
+        int o1 = offset + thisStart, o2 = string.offset + start;
+        char[] value1 = value;
+        char[] value2 = string.value;
+        for (int i = 0; i < length; ++i) {
+            if (value1[o1 + i] != value2[o2 + i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Compares the specified string to this string and compares the specified
+     * range of characters to determine if they are the same. When ignoreCase is
+     * true, the case of the characters is ignored during the comparison.
+     *
+     * @param ignoreCase
+     *            specifies if case should be ignored.
+     * @param thisStart
+     *            the starting offset in this string.
+     * @param string
+     *            the string to compare.
+     * @param start
+     *            the starting offset in the specified string.
+     * @param length
+     *            the number of characters to compare.
+     * @return {@code true} if the ranges of characters are equal, {@code false}
+     *         otherwise.
+     * @throws NullPointerException
+     *             if {@code string} is {@code null}.
+     */
+    public boolean regionMatches(boolean ignoreCase, int thisStart, String string, int start, int length) {
+        if (!ignoreCase) {
+            return regionMatches(thisStart, string, start, length);
+        }
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+        if (thisStart < 0 || length > count - thisStart) {
+            return false;
+        }
+        if (start < 0 || length > string.count - start) {
+            return false;
+        }
+        thisStart += offset;
+        start += string.offset;
+        int end = thisStart + length;
+        char[] target = string.value;
+        while (thisStart < end) {
+            char c1 = value[thisStart++];
+            char c2 = target[start++];
+            if (c1 != c2 && foldCase(c1) != foldCase(c2)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Copies this string replacing occurrences of the specified character with
+     * another character.
+     *
+     * @param oldChar
+     *            the character to replace.
+     * @param newChar
+     *            the replacement character.
+     * @return a new string with occurrences of oldChar replaced by newChar.
+     */
+    public String replace(char oldChar, char newChar) {
+        char[] buffer = value;
+        int _offset = offset;
+        int _count = count;
+
+        int idx = _offset;
+        int last = _offset + _count;
+        boolean copied = false;
+        while (idx < last) {
+            if (buffer[idx] == oldChar) {
+                if (!copied) {
+                    char[] newBuffer = new char[_count];
+                    System.arraycopy(buffer, _offset, newBuffer, 0, _count);
+                    buffer = newBuffer;
+                    idx -= _offset;
+                    last -= _offset;
+                    copied = true;
+                }
+                buffer[idx] = newChar;
+            }
+            idx++;
+        }
+
+        return copied ? new String(0, count, buffer) : this;
+    }
+
+    /**
+     * Copies this string replacing occurrences of the specified target sequence
+     * with another sequence. The string is processed from the beginning to the
+     * end.
+     *
+     * @param target
+     *            the sequence to replace.
+     * @param replacement
+     *            the replacement sequence.
+     * @return the resulting string.
+     * @throws NullPointerException
+     *             if {@code target} or {@code replacement} is {@code null}.
+     */
+    public String replace(CharSequence target, CharSequence replacement) {
+        if (target == null) {
+            throw new NullPointerException("target == null");
+        }
+        if (replacement == null) {
+            throw new NullPointerException("replacement == null");
+        }
+
+        String targetString = target.toString();
+        int matchStart = indexOf(targetString, 0);
+        if (matchStart == -1) {
+            // If there's nothing to replace, return the original string untouched.
+            return this;
+        }
+
+        String replacementString = replacement.toString();
+
+        // The empty target matches at the start and end and between each character.
+        int targetLength = targetString.length();
+        if (targetLength == 0) {
+            // The result contains the original 'count' characters, a copy of the
+            // replacement string before every one of those characters, and a final
+            // copy of the replacement string at the end.
+            int resultLength = count + (count + 1) * replacementString.length();
+            StringBuilder result = new StringBuilder(resultLength);
+            result.append(replacementString);
+            int end = offset + count;
+            for (int i = offset; i != end; ++i) {
+                result.append(value[i]);
+                result.append(replacementString);
+            }
+            return result.toString();
+        }
+
+        StringBuilder result = new StringBuilder(count);
+        int searchStart = 0;
+        do {
+            // Copy characters before the match...
+            result.append(value, offset + searchStart, matchStart - searchStart);
+            // Insert the replacement...
+            result.append(replacementString);
+            // And skip over the match...
+            searchStart = matchStart + targetLength;
+        } while ((matchStart = indexOf(targetString, searchStart)) != -1);
+        // Copy any trailing chars...
+        result.append(value, offset + searchStart, count - searchStart);
+        return result.toString();
+    }
+
+    /**
+     * Compares the specified string to this string to determine if the
+     * specified string is a prefix.
+     *
+     * @param prefix
+     *            the string to look for.
+     * @return {@code true} if the specified string is a prefix of this string,
+     *         {@code false} otherwise
+     * @throws NullPointerException
+     *             if {@code prefix} is {@code null}.
+     */
+    public boolean startsWith(String prefix) {
+        return startsWith(prefix, 0);
+    }
+
+    /**
+     * Compares the specified string to this string, starting at the specified
+     * offset, to determine if the specified string is a prefix.
+     *
+     * @param prefix
+     *            the string to look for.
+     * @param start
+     *            the starting offset.
+     * @return {@code true} if the specified string occurs in this string at the
+     *         specified offset, {@code false} otherwise.
+     * @throws NullPointerException
+     *             if {@code prefix} is {@code null}.
+     */
+    public boolean startsWith(String prefix, int start) {
+        return regionMatches(start, prefix, 0, prefix.count);
+    }
+
+    /**
+     * Returns a string containing a suffix of this string. The returned string
+     * shares this string's <a href="#backing_array">backing array</a>.
+     *
+     * @param start
+     *            the offset of the first character.
+     * @return a new string containing the characters from start to the end of
+     *         the string.
+     * @throws IndexOutOfBoundsException
+     *             if {@code start < 0} or {@code start > length()}.
+     */
+    public String substring(int start) {
+        if (start == 0) {
+            return this;
+        }
+        if (start >= 0 && start <= count) {
+            return new String(offset + start, count - start, value);
+        }
+        throw indexAndLength(start);
+    }
+
+    /**
+     * Returns a string containing a subsequence of characters from this string.
+     * The returned string shares this string's <a href="#backing_array">backing
+     * array</a>.
+     *
+     * @param start
+     *            the offset of the first character.
+     * @param end
+     *            the offset one past the last character.
+     * @return a new string containing the characters from start to end - 1
+     * @throws IndexOutOfBoundsException
+     *             if {@code start < 0}, {@code start > end} or {@code end >
+     *             length()}.
+     */
+    public String substring(int start, int end) {
+        if (start == 0 && end == count) {
+            return this;
+        }
+        // NOTE last character not copied!
+        // Fast range check.
+        if (start >= 0 && start <= end && end <= count) {
+            return new String(offset + start, end - start, value);
+        }
+        throw startEndAndLength(start, end);
+    }
+
+    /**
+     * Returns a new {@code char} array containing a copy of the characters in this string.
+     * This is expensive and rarely useful. If you just want to iterate over the characters in
+     * the string, use {@link #charAt} instead.
+     */
+    public char[] toCharArray() {
+        char[] buffer = new char[count];
+        System.arraycopy(value, offset, buffer, 0, count);
+        return buffer;
+    }
+
+    /**
+     * Converts this string to lower case, using the rules of the user's default locale.
+     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
+     *
+     * @return a new lower case string, or {@code this} if it's already all lower case.
+     */
+    public String toLowerCase() {
+        return CaseMapper.toLowerCase(Locale.getDefault(), this, value, offset, count);
+    }
+
+    /**
+     * Converts this string to lower case, using the rules of {@code locale}.
+     *
+     * <p>Most case mappings are unaffected by the language of a {@code Locale}. Exceptions include
+     * dotted and dotless I in Azeri and Turkish locales, and dotted and dotless I and J in
+     * Lithuanian locales. On the other hand, it isn't necessary to provide a Greek locale to get
+     * correct case mapping of Greek characters: any locale will do.
+     *
+     * <p>See <a href="http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt">http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt</a>
+     * for full details of context- and language-specific special cases.
+     *
+     * @return a new lower case string, or {@code this} if it's already all lower case.
+     */
+    public String toLowerCase(Locale locale) {
+        return CaseMapper.toLowerCase(locale, this, value, offset, count);
+    }
+
+    /**
+     * Returns this string.
+     */
+    @Override
+    public String toString() {
+        return this;
+    }
+
+    /**
+     * Converts this this string to upper case, using the rules of the user's default locale.
+     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
+     *
+     * @return a new upper case string, or {@code this} if it's already all upper case.
+     */
+    public String toUpperCase() {
+        return CaseMapper.toUpperCase(Locale.getDefault(), this, value, offset, count);
+    }
+
+    /**
+     * Converts this this string to upper case, using the rules of {@code locale}.
+     *
+     * <p>Most case mappings are unaffected by the language of a {@code Locale}. Exceptions include
+     * dotted and dotless I in Azeri and Turkish locales, and dotted and dotless I and J in
+     * Lithuanian locales. On the other hand, it isn't necessary to provide a Greek locale to get
+     * correct case mapping of Greek characters: any locale will do.
+     *
+     * <p>See <a href="http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt">http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt</a>
+     * for full details of context- and language-specific special cases.
+     *
+     * @return a new upper case string, or {@code this} if it's already all upper case.
+     */
+    public String toUpperCase(Locale locale) {
+        return CaseMapper.toUpperCase(locale, this, value, offset, count);
+    }
+
+    /**
+     * Copies this string removing white space characters from the beginning and
+     * end of the string.
+     *
+     * @return a new string with characters <code><= \\u0020</code> removed from
+     *         the beginning and the end.
+     */
+    public String trim() {
+        int start = offset, last = offset + count - 1;
+        int end = last;
+        while ((start <= end) && (value[start] <= ' ')) {
+            start++;
+        }
+        while ((end >= start) && (value[end] <= ' ')) {
+            end--;
+        }
+        if (start == offset && end == last) {
+            return this;
+        }
+        return new String(start, end - start + 1, value);
+    }
+
+    /**
+     * Creates a new string containing the characters in the specified character
+     * array. Modifying the character array after creating the string has no
+     * effect on the string.
+     *
+     * @param data
+     *            the array of characters.
+     * @return the new string.
+     * @throws NullPointerException
+     *             if {@code data} is {@code null}.
+     */
+    public static String valueOf(char[] data) {
+        return new String(data, 0, data.length);
+    }
+
+    /**
+     * Creates a new string containing the specified characters in the character
+     * array. Modifying the character array after creating the string has no
+     * effect on the string.
+     *
+     * @param data
+     *            the array of characters.
+     * @param start
+     *            the starting offset in the character array.
+     * @param length
+     *            the number of characters to use.
+     * @return the new string.
+     * @throws IndexOutOfBoundsException
+     *             if {@code length < 0}, {@code start < 0} or {@code start +
+     *             length > data.length}
+     * @throws NullPointerException
+     *             if {@code data} is {@code null}.
+     */
+    public static String valueOf(char[] data, int start, int length) {
+        return new String(data, start, length);
+    }
+
+    /**
+     * Converts the specified character to its string representation.
+     *
+     * @param value
+     *            the character.
+     * @return the character converted to a string.
+     */
+    public static String valueOf(char value) {
+        String s;
+        if (value < 128) {
+            s = new String(value, 1, ASCII);
+        } else {
+            s = new String(0, 1, new char[] { value });
+        }
+        s.hashCode = value;
+        return s;
+    }
+
+    /**
+     * Converts the specified double to its string representation.
+     *
+     * @param value
+     *            the double.
+     * @return the double converted to a string.
+     */
+    public static String valueOf(double value) {
+        return Double.toString(value);
+    }
+
+    /**
+     * Converts the specified float to its string representation.
+     *
+     * @param value
+     *            the float.
+     * @return the float converted to a string.
+     */
+    public static String valueOf(float value) {
+        return Float.toString(value);
+    }
+
+    /**
+     * Converts the specified integer to its string representation.
+     *
+     * @param value
+     *            the integer.
+     * @return the integer converted to a string.
+     */
+    public static String valueOf(int value) {
+        return Integer.toString(value);
+    }
+
+    /**
+     * Converts the specified long to its string representation.
+     *
+     * @param value
+     *            the long.
+     * @return the long converted to a string.
+     */
+    public static String valueOf(long value) {
+        return Long.toString(value);
+    }
+
+    /**
+     * Converts the specified object to its string representation. If the object
+     * is null return the string {@code "null"}, otherwise use {@code
+     * toString()} to get the string representation.
+     *
+     * @param value
+     *            the object.
+     * @return the object converted to a string, or the string {@code "null"}.
+     */
+    public static String valueOf(Object value) {
+        return value != null ? value.toString() : "null";
+    }
+
+    /**
+     * Converts the specified boolean to its string representation. When the
+     * boolean is {@code true} return {@code "true"}, otherwise return {@code
+     * "false"}.
+     *
+     * @param value
+     *            the boolean.
+     * @return the boolean converted to a string.
+     */
+    public static String valueOf(boolean value) {
+        return value ? "true" : "false";
+    }
+
+    /**
+     * Returns whether the characters in the StringBuffer {@code strbuf} are the
+     * same as those in this string.
+     *
+     * @param strbuf
+     *            the StringBuffer to compare this string to.
+     * @return {@code true} if the characters in {@code strbuf} are identical to
+     *         those in this string. If they are not, {@code false} will be
+     *         returned.
+     * @throws NullPointerException
+     *             if {@code strbuf} is {@code null}.
+     * @since 1.4
+     */
+    public boolean contentEquals(StringBuffer strbuf) {
+        synchronized (strbuf) {
+            int size = strbuf.length();
+            if (count != size) {
+                return false;
+            }
+            return regionMatches(0, new String(0, size, strbuf.getValue()), 0,
+                    size);
+        }
+    }
+
+    /**
+     * Compares a {@code CharSequence} to this {@code String} to determine if
+     * their contents are equal.
+     *
+     * @param cs
+     *            the character sequence to compare to.
+     * @return {@code true} if equal, otherwise {@code false}
+     * @since 1.5
+     */
+    public boolean contentEquals(CharSequence cs) {
+        if (cs == null) {
+            throw new NullPointerException("cs == null");
+        }
+
+        int len = cs.length();
+
+        if (len != count) {
+            return false;
+        }
+
+        if (len == 0 && count == 0) {
+            return true; // since both are empty strings
+        }
+
+        return regionMatches(0, cs.toString(), 0, len);
+    }
+
+    /**
+     * Tests whether this string matches the given {@code regularExpression}. This method returns
+     * true only if the regular expression matches the <i>entire</i> input string. A common mistake is
+     * to assume that this method behaves like {@link #contains}; if you want to match anywhere
+     * within the input string, you need to add {@code .*} to the beginning and end of your
+     * regular expression. See {@link Pattern#matches}.
+     *
+     * <p>If the same regular expression is to be used for multiple operations, it may be more
+     * efficient to reuse a compiled {@code Pattern}.
+     *
+     * @throws PatternSyntaxException
+     *             if the syntax of the supplied regular expression is not
+     *             valid.
+     * @throws NullPointerException if {@code regularExpression == null}
+     * @since 1.4
+     */
+    public boolean matches(String regularExpression) {
+        return Pattern.matches(regularExpression, this);
+    }
+
+    /**
+     * Replaces all matches for {@code regularExpression} within this string with the given
+     * {@code replacement}.
+     * See {@link Pattern} for regular expression syntax.
+     *
+     * <p>If the same regular expression is to be used for multiple operations, it may be more
+     * efficient to reuse a compiled {@code Pattern}.
+     *
+     * @throws PatternSyntaxException
+     *             if the syntax of the supplied regular expression is not
+     *             valid.
+     * @throws NullPointerException if {@code regularExpression == null}
+     * @see Pattern
+     * @since 1.4
+     */
+    public String replaceAll(String regularExpression, String replacement) {
+        return Pattern.compile(regularExpression).matcher(this).replaceAll(replacement);
+    }
+
+    /**
+     * Replaces the first match for {@code regularExpression} within this string with the given
+     * {@code replacement}.
+     * See {@link Pattern} for regular expression syntax.
+     *
+     * <p>If the same regular expression is to be used for multiple operations, it may be more
+     * efficient to reuse a compiled {@code Pattern}.
+     *
+     * @throws PatternSyntaxException
+     *             if the syntax of the supplied regular expression is not
+     *             valid.
+     * @throws NullPointerException if {@code regularExpression == null}
+     * @see Pattern
+     * @since 1.4
+     */
+    public String replaceFirst(String regularExpression, String replacement) {
+        return Pattern.compile(regularExpression).matcher(this).replaceFirst(replacement);
+    }
+
+    /**
+     * Splits this string using the supplied {@code regularExpression}.
+     * Equivalent to {@code split(regularExpression, 0)}.
+     * See {@link Pattern#split(CharSequence, int)} for an explanation of {@code limit}.
+     * See {@link Pattern} for regular expression syntax.
+     *
+     * <p>If the same regular expression is to be used for multiple operations, it may be more
+     * efficient to reuse a compiled {@code Pattern}.
+     *
+     * @throws NullPointerException if {@code regularExpression ==  null}
+     * @throws PatternSyntaxException
+     *             if the syntax of the supplied regular expression is not
+     *             valid.
+     * @see Pattern
+     * @since 1.4
+     */
+    public String[] split(String regularExpression) {
+        return split(regularExpression, 0);
+    }
+
+    /**
+     * Splits this string using the supplied {@code regularExpression}.
+     * See {@link Pattern#split(CharSequence, int)} for an explanation of {@code limit}.
+     * See {@link Pattern} for regular expression syntax.
+     *
+     * <p>If the same regular expression is to be used for multiple operations, it may be more
+     * efficient to reuse a compiled {@code Pattern}.
+     *
+     * @throws NullPointerException if {@code regularExpression ==  null}
+     * @throws PatternSyntaxException
+     *             if the syntax of the supplied regular expression is not
+     *             valid.
+     * @since 1.4
+     */
+    public String[] split(String regularExpression, int limit) {
+        String[] result = java.util.regex.Splitter.fastSplit(regularExpression, this, limit);
+        return result != null ? result : Pattern.compile(regularExpression).split(this, limit);
+    }
+
+    /**
+     * Has the same result as the substring function, but is present so that
+     * string may implement the CharSequence interface.
+     *
+     * @param start
+     *            the offset the first character.
+     * @param end
+     *            the offset of one past the last character to include.
+     * @return the subsequence requested.
+     * @throws IndexOutOfBoundsException
+     *             if {@code start < 0}, {@code end < 0}, {@code start > end} or
+     *             {@code end > length()}.
+     * @see java.lang.CharSequence#subSequence(int, int)
+     * @since 1.4
+     */
+    public CharSequence subSequence(int start, int end) {
+        return substring(start, end);
+    }
+
+    /**
+     * Returns the Unicode code point at the given {@code index}.
+     *
+     * @throws IndexOutOfBoundsException if {@code index < 0 || index >= length()}
+     * @see Character#codePointAt(char[], int, int)
+     * @since 1.5
+     */
+    public int codePointAt(int index) {
+        if (index < 0 || index >= count) {
+            throw indexAndLength(index);
+        }
+        return Character.codePointAt(value, offset + index, offset + count);
+    }
+
+    /**
+     * Returns the Unicode code point that precedes the given {@code index}.
+     *
+     * @throws IndexOutOfBoundsException if {@code index < 1 || index > length()}
+     * @see Character#codePointBefore(char[], int, int)
+     * @since 1.5
+     */
+    public int codePointBefore(int index) {
+        if (index < 1 || index > count) {
+            throw indexAndLength(index);
+        }
+        return Character.codePointBefore(value, offset + index, offset);
+    }
+
+    /**
+     * Calculates the number of Unicode code points between {@code start}
+     * and {@code end}.
+     *
+     * @param start
+     *            the inclusive beginning index of the subsequence.
+     * @param end
+     *            the exclusive end index of the subsequence.
+     * @return the number of Unicode code points in the subsequence.
+     * @throws IndexOutOfBoundsException
+     *         if {@code start < 0 || end > length() || start > end}
+     * @see Character#codePointCount(CharSequence, int, int)
+     * @since 1.5
+     */
+    public int codePointCount(int start, int end) {
+        if (start < 0 || end > count || start > end) {
+            throw startEndAndLength(start, end);
+        }
+        return Character.codePointCount(value, offset + start, end - start);
+    }
+
+    /**
+     * Determines if this {@code String} contains the sequence of characters in
+     * the {@code CharSequence} passed.
+     *
+     * @param cs
+     *            the character sequence to search for.
+     * @return {@code true} if the sequence of characters are contained in this
+     *         string, otherwise {@code false}.
+     * @since 1.5
+     */
+    public boolean contains(CharSequence cs) {
+        if (cs == null) {
+            throw new NullPointerException("cs == null");
+        }
+        return indexOf(cs.toString()) >= 0;
+    }
+
+    /**
+     * Returns the index within this object that is offset from {@code index} by
+     * {@code codePointOffset} code points.
+     *
+     * @param index
+     *            the index within this object to calculate the offset from.
+     * @param codePointOffset
+     *            the number of code points to count.
+     * @return the index within this object that is the offset.
+     * @throws IndexOutOfBoundsException
+     *             if {@code index} is negative or greater than {@code length()}
+     *             or if there aren't enough code points before or after {@code
+     *             index} to match {@code codePointOffset}.
+     * @since 1.5
+     */
+    public int offsetByCodePoints(int index, int codePointOffset) {
+        int s = index + offset;
+        int r = Character.offsetByCodePoints(value, offset, count, s, codePointOffset);
+        return r - offset;
+    }
+
+    /**
+     * Returns a localized formatted string, using the supplied format and arguments,
+     * using the user's default locale.
+     *
+     * <p>If you're formatting a string other than for human
+     * consumption, you should use the {@code format(Locale, String, Object...)}
+     * overload and supply {@code Locale.US}. See
+     * "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
+     *
+     * @param format the format string (see {@link java.util.Formatter#format})
+     * @param args
+     *            the list of arguments passed to the formatter. If there are
+     *            more arguments than required by {@code format},
+     *            additional arguments are ignored.
+     * @return the formatted string.
+     * @throws NullPointerException if {@code format == null}
+     * @throws java.util.IllegalFormatException
+     *             if the format is invalid.
+     * @since 1.5
+     */
+    public static String format(String format, Object... args) {
+        return format(Locale.getDefault(), format, args);
+    }
+
+    /**
+     * Returns a formatted string, using the supplied format and arguments,
+     * localized to the given locale.
+     *
+     * @param locale
+     *            the locale to apply; {@code null} value means no localization.
+     * @param format the format string (see {@link java.util.Formatter#format})
+     * @param args
+     *            the list of arguments passed to the formatter. If there are
+     *            more arguments than required by {@code format},
+     *            additional arguments are ignored.
+     * @return the formatted string.
+     * @throws NullPointerException if {@code format == null}
+     * @throws java.util.IllegalFormatException
+     *             if the format is invalid.
+     * @since 1.5
+     */
+    public static String format(Locale locale, String format, Object... args) {
+        if (format == null) {
+            throw new NullPointerException("format == null");
+        }
+        int bufferSize = format.length() + (args == null ? 0 : args.length * 10);
+        Formatter f = new Formatter(new StringBuilder(bufferSize), locale);
+        return f.format(format, args).toString();
+    }
+
+    /*
+     * An implementation of a String.indexOf that is supposed to perform
+     * substantially better than the default algorithm if the "needle" (the
+     * subString being searched for) is a constant string.
+     *
+     * For example, a JIT, upon encountering a call to String.indexOf(String),
+     * where the needle is a constant string, may compute the values cache, md2
+     * and lastChar, and change the call to the following method.
+     */
+    @FindBugsSuppressWarnings("UPM_UNCALLED_PRIVATE_METHOD")
+    @SuppressWarnings("unused")
+    private static int indexOf(String haystackString, String needleString,
+            int cache, int md2, char lastChar) {
+        char[] haystack = haystackString.value;
+        int haystackOffset = haystackString.offset;
+        int haystackLength = haystackString.count;
+        char[] needle = needleString.value;
+        int needleOffset = needleString.offset;
+        int needleLength = needleString.count;
+        int needleLengthMinus1 = needleLength - 1;
+        int haystackEnd = haystackOffset + haystackLength;
+        outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) {
+            if (lastChar == haystack[i]) {
+                for (int j = 0; j < needleLengthMinus1; ++j) {
+                    if (needle[j + needleOffset] != haystack[i + j
+                            - needleLengthMinus1]) {
+                        int skip = 1;
+                        if ((cache & (1 << haystack[i])) == 0) {
+                            skip += j;
+                        }
+                        i += Math.max(md2, skip);
+                        continue outer_loop;
+                    }
+                }
+                return i - needleLengthMinus1 - haystackOffset;
+            }
+
+            if ((cache & (1 << haystack[i])) == 0) {
+                i += needleLengthMinus1;
+            }
+            i++;
+        }
+        return -1;
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/Thread.java b/libdvm/src/main/java/java/lang/Thread.java
new file mode 100644
index 0000000..a40dde1
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/Thread.java
@@ -0,0 +1,1288 @@
+/*
+ * 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) 2008 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;
+
+import dalvik.system.VMStack;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import libcore.util.EmptyArray;
+
+/**
+ * A {@code Thread} is a concurrent unit of execution. It has its own call stack
+ * for methods being invoked, their arguments and local variables. Each application
+ * has at least one thread running when it is started, the main thread, in the main
+ * {@link ThreadGroup}. The runtime keeps its own threads in the system thread
+ * group.
+ *
+ * <p>There are two ways to execute code in a new thread.
+ * You can either subclass {@code Thread} and overriding its {@link #run()} method,
+ * or construct a new {@code Thread} and pass a {@link Runnable} to the constructor.
+ * In either case, the {@link #start()} method must be called to actually execute
+ * the new {@code Thread}.
+ *
+ * <p>Each {@code Thread} has an integer priority that affect how the thread is
+ * scheduled by the OS. A new thread inherits the priority of its parent.
+ * A thread's priority can be set using the {@link #setPriority(int)} method.
+ */
+public class Thread implements Runnable {
+    private static final int NANOS_PER_MILLI = 1000000;
+
+    /** Park states */
+    private static class ParkState {
+        /** park state indicating unparked */
+        private static final int UNPARKED = 1;
+
+        /** park state indicating preemptively unparked */
+        private static final int PREEMPTIVELY_UNPARKED = 2;
+
+        /** park state indicating parked */
+        private static final int PARKED = 3;
+    }
+
+    /**
+     * A representation of a thread's state. A given thread may only be in one
+     * state at a time.
+     */
+    public enum State {
+        /**
+         * The thread has been created, but has never been started.
+         */
+        NEW,
+        /**
+         * The thread may be run.
+         */
+        RUNNABLE,
+        /**
+         * The thread is blocked and waiting for a lock.
+         */
+        BLOCKED,
+        /**
+         * The thread is waiting.
+         */
+        WAITING,
+        /**
+         * The thread is waiting for a specified amount of time.
+         */
+        TIMED_WAITING,
+        /**
+         * The thread has been terminated.
+         */
+        TERMINATED
+    }
+
+    /**
+     * The maximum priority value allowed for a thread.
+     * This corresponds to (but does not have the same value as)
+     * {@code android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY}.
+     */
+    public static final int MAX_PRIORITY = 10;
+
+    /**
+     * The minimum priority value allowed for a thread.
+     * This corresponds to (but does not have the same value as)
+     * {@code android.os.Process.THREAD_PRIORITY_LOWEST}.
+     */
+    public static final int MIN_PRIORITY = 1;
+
+    /**
+     * The normal (default) priority value assigned to the main thread.
+     * This corresponds to (but does not have the same value as)
+     * {@code android.os.Process.THREAD_PRIORITY_DEFAULT}.
+
+     */
+    public static final int NORM_PRIORITY = 5;
+
+    /* some of these are accessed directly by the VM; do not rename them */
+    volatile VMThread vmThread;
+    volatile ThreadGroup group;
+    volatile boolean daemon;
+    volatile String name;
+    volatile int priority;
+    volatile long stackSize;
+    Runnable target;
+    private static int count = 0;
+
+    /**
+     * Holds the thread's ID. We simply count upwards, so
+     * each Thread has a unique ID.
+     */
+    private long id;
+
+    /**
+     * Normal thread local values.
+     */
+    ThreadLocal.Values localValues;
+
+    /**
+     * Inheritable thread local values.
+     */
+    ThreadLocal.Values inheritableValues;
+
+    /** Callbacks to run on interruption. */
+    private final List<Runnable> interruptActions = new ArrayList<Runnable>();
+
+    /**
+     * Holds the class loader for this Thread, in case there is one.
+     */
+    private ClassLoader contextClassLoader;
+
+    /**
+     * Holds the handler for uncaught exceptions in this Thread,
+     * in case there is one.
+     */
+    private UncaughtExceptionHandler uncaughtHandler;
+
+    /**
+     * Holds the default handler for uncaught exceptions, in case there is one.
+     */
+    private static UncaughtExceptionHandler defaultUncaughtHandler;
+
+    /**
+     * Reflects whether this Thread has already been started. A Thread
+     * can only be started once (no recycling). Also, we need it to deduce
+     * the proper Thread status.
+     */
+    boolean hasBeenStarted = false;
+
+    /** the park state of the thread */
+    private int parkState = ParkState.UNPARKED;
+
+    /** The synchronization object responsible for this thread parking. */
+    private Object parkBlocker;
+
+    /**
+     * Constructs a new {@code Thread} with no {@code Runnable} object and a
+     * newly generated name. The new {@code Thread} will belong to the same
+     * {@code ThreadGroup} as the {@code Thread} calling this constructor.
+     *
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread() {
+        create(null, null, null, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with a {@code Runnable} object and a
+     * newly generated name. The new {@code Thread} will belong to the same
+     * {@code ThreadGroup} as the {@code Thread} calling this constructor.
+     *
+     * @param runnable
+     *            a {@code Runnable} whose method <code>run</code> will be
+     *            executed by the new {@code Thread}
+     *
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(Runnable runnable) {
+        create(null, runnable, null, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with a {@code Runnable} object and name
+     * provided. The new {@code Thread} will belong to the same {@code
+     * ThreadGroup} as the {@code Thread} calling this constructor.
+     *
+     * @param runnable
+     *            a {@code Runnable} whose method <code>run</code> will be
+     *            executed by the new {@code Thread}
+     * @param threadName
+     *            the name for the {@code Thread} being created
+     *
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(Runnable runnable, String threadName) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+
+        create(null, runnable, threadName, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with no {@code Runnable} object and the
+     * name provided. The new {@code Thread} will belong to the same {@code
+     * ThreadGroup} as the {@code Thread} calling this constructor.
+     *
+     * @param threadName
+     *            the name for the {@code Thread} being created
+     *
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     *
+     */
+    public Thread(String threadName) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+
+        create(null, null, threadName, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with a {@code Runnable} object and a
+     * newly generated name. The new {@code Thread} will belong to the {@code
+     * ThreadGroup} passed as parameter.
+     *
+     * @param group
+     *            {@code ThreadGroup} to which the new {@code Thread} will
+     *            belong
+     * @param runnable
+     *            a {@code Runnable} whose method <code>run</code> will be
+     *            executed by the new {@code Thread}
+     * @throws IllegalThreadStateException
+     *             if <code>group.destroy()</code> has already been done
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(ThreadGroup group, Runnable runnable) {
+        create(group, runnable, null, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with a {@code Runnable} object, the given
+     * name and belonging to the {@code ThreadGroup} passed as parameter.
+     *
+     * @param group
+     *            ThreadGroup to which the new {@code Thread} will belong
+     * @param runnable
+     *            a {@code Runnable} whose method <code>run</code> will be
+     *            executed by the new {@code Thread}
+     * @param threadName
+     *            the name for the {@code Thread} being created
+     * @throws IllegalThreadStateException
+     *             if <code>group.destroy()</code> has already been done
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(ThreadGroup group, Runnable runnable, String threadName) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+
+        create(group, runnable, threadName, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with no {@code Runnable} object, the
+     * given name and belonging to the {@code ThreadGroup} passed as parameter.
+     *
+     * @param group
+     *            {@code ThreadGroup} to which the new {@code Thread} will belong
+     * @param threadName
+     *            the name for the {@code Thread} being created
+     * @throws IllegalThreadStateException
+     *             if <code>group.destroy()</code> has already been done
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(ThreadGroup group, String threadName) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+
+        create(group, null, threadName, 0);
+    }
+
+    /**
+     * Constructs a new {@code Thread} with a {@code Runnable} object, the given
+     * name and belonging to the {@code ThreadGroup} passed as parameter.
+     *
+     * @param group
+     *            {@code ThreadGroup} to which the new {@code Thread} will
+     *            belong
+     * @param runnable
+     *            a {@code Runnable} whose method <code>run</code> will be
+     *            executed by the new {@code Thread}
+     * @param threadName
+     *            the name for the {@code Thread} being created
+     * @param stackSize
+     *            a stack size for the new {@code Thread}. This has a highly
+     *            platform-dependent interpretation. It may even be ignored
+     *            completely.
+     * @throws IllegalThreadStateException
+     *             if <code>group.destroy()</code> has already been done
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    public Thread(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+        create(group, runnable, threadName, stackSize);
+    }
+
+    /**
+     * Package-scope method invoked by Dalvik VM to create "internal"
+     * threads or attach threads created externally.
+     *
+     * Don't call Thread.currentThread(), since there may not be such
+     * a thing (e.g. for Main).
+     */
+    Thread(ThreadGroup group, String name, int priority, boolean daemon) {
+        synchronized (Thread.class) {
+            id = ++Thread.count;
+        }
+
+        if (name == null) {
+            this.name = "Thread-" + id;
+        } else {
+            this.name = name;
+        }
+
+        if (group == null) {
+            throw new InternalError("group not specified");
+        }
+
+        this.group = group;
+
+        this.target = null;
+        this.stackSize = 0;
+        this.priority = priority;
+        this.daemon = daemon;
+
+        /* add ourselves to our ThreadGroup of choice */
+        this.group.addThread(this);
+    }
+
+    /**
+     * Initializes a new, existing Thread object with a runnable object,
+     * the given name and belonging to the ThreadGroup passed as parameter.
+     * This is the method that the several public constructors delegate their
+     * work to.
+     *
+     * @param group ThreadGroup to which the new Thread will belong
+     * @param runnable a java.lang.Runnable whose method <code>run</code> will
+     *        be executed by the new Thread
+     * @param threadName Name for the Thread being created
+     * @param stackSize Platform dependent stack size
+     * @throws IllegalThreadStateException if <code>group.destroy()</code> has
+     *         already been done
+     * @see java.lang.ThreadGroup
+     * @see java.lang.Runnable
+     */
+    private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {
+        Thread currentThread = Thread.currentThread();
+        if (group == null) {
+            group = currentThread.getThreadGroup();
+        }
+
+        if (group.isDestroyed()) {
+            throw new IllegalThreadStateException("Group already destroyed");
+        }
+
+        this.group = group;
+
+        synchronized (Thread.class) {
+            id = ++Thread.count;
+        }
+
+        if (threadName == null) {
+            this.name = "Thread-" + id;
+        } else {
+            this.name = threadName;
+        }
+
+        this.target = runnable;
+        this.stackSize = stackSize;
+
+        this.priority = currentThread.getPriority();
+
+        this.contextClassLoader = currentThread.contextClassLoader;
+
+        // Transfer over InheritableThreadLocals.
+        if (currentThread.inheritableValues != null) {
+            inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);
+        }
+
+        // add ourselves to our ThreadGroup of choice
+        this.group.addThread(this);
+    }
+
+    /**
+     * Returns the number of active {@code Thread}s in the running {@code
+     * Thread}'s group and its subgroups.
+     *
+     * @return the number of {@code Thread}s
+     */
+    public static int activeCount() {
+        return currentThread().getThreadGroup().activeCount();
+    }
+
+    /**
+     * Does nothing.
+     */
+    public final void checkAccess() {
+    }
+
+    /**
+     * Returns the number of stack frames in this thread.
+     *
+     * @return Number of stack frames
+     * @deprecated The results of this call were never well defined. To make
+     *             things worse, it would depend on whether the Thread was
+     *             suspended or not, and suspend was deprecated too.
+     */
+    @Deprecated
+    public int countStackFrames() {
+        return getStackTrace().length;
+    }
+
+    /**
+     * Returns the Thread of the caller, that is, the current Thread.
+     *
+     * @return the current Thread.
+     */
+    public static Thread currentThread() {
+        return VMThread.currentThread();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     * @deprecated Not implemented.
+     */
+    @Deprecated
+    public void destroy() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Prints to the standard error stream a text representation of the current
+     * stack for this Thread.
+     *
+     * @see Throwable#printStackTrace()
+     */
+    public static void dumpStack() {
+        new Throwable("stack dump").printStackTrace();
+    }
+
+    /**
+     * Copies an array with all Threads which are in the same ThreadGroup as the
+     * receiver - and subgroups - into the array <code>threads</code> passed as
+     * parameter. If the array passed as parameter is too small no exception is
+     * thrown - the extra elements are simply not copied.
+     *
+     * @param threads
+     *            array into which the Threads will be copied
+     * @return How many Threads were copied over
+     */
+    public static int enumerate(Thread[] threads) {
+        Thread thread = Thread.currentThread();
+        return thread.getThreadGroup().enumerate(threads);
+    }
+
+    /**
+     * Returns a map of all the currently live threads to their stack traces.
+     */
+    public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
+        Map<Thread, StackTraceElement[]> map = new HashMap<Thread, StackTraceElement[]>();
+
+        // Find out how many live threads we have. Allocate a bit more
+        // space than needed, in case new ones are just being created.
+        int count = ThreadGroup.mSystem.activeCount();
+        Thread[] threads = new Thread[count + count / 2];
+
+        // Enumerate the threads and collect the stacktraces.
+        count = ThreadGroup.mSystem.enumerate(threads);
+        for (int i = 0; i < count; i++) {
+            map.put(threads[i], threads[i].getStackTrace());
+        }
+
+        return map;
+    }
+
+    /**
+     * Returns the context ClassLoader for this Thread.
+     *
+     * @return ClassLoader The context ClassLoader
+     * @see java.lang.ClassLoader
+     * @see #getContextClassLoader()
+     */
+    public ClassLoader getContextClassLoader() {
+        return contextClassLoader;
+    }
+
+    /**
+     * Returns the default exception handler that's executed when uncaught
+     * exception terminates a thread.
+     *
+     * @return an {@link UncaughtExceptionHandler} or <code>null</code> if
+     *         none exists.
+     */
+    public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() {
+        return defaultUncaughtHandler;
+    }
+
+    /**
+     * Returns the thread's identifier. The ID is a positive <code>long</code>
+     * generated on thread creation, is unique to the thread, and doesn't change
+     * during the lifetime of the thread; the ID may be reused after the thread
+     * has been terminated.
+     *
+     * @return the thread's ID.
+     */
+    public long getId() {
+        return id;
+    }
+
+    /**
+     * Returns the name of the Thread.
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the priority of the Thread.
+     */
+    public final int getPriority() {
+        return priority;
+    }
+
+    /**
+     * Returns an array of {@link StackTraceElement} representing the current thread's stack.
+     */
+    public StackTraceElement[] getStackTrace() {
+        StackTraceElement ste[] = VMStack.getThreadStackTrace(this);
+        return ste != null ? ste : EmptyArray.STACK_TRACE_ELEMENT;
+    }
+
+    /**
+     * Returns the current state of the Thread. This method is useful for
+     * monitoring purposes.
+     *
+     * @return a {@link State} value.
+     */
+    public State getState() {
+        // TODO This is ugly and should be implemented better.
+        VMThread vmt = this.vmThread;
+
+        // Make sure we have a valid reference to an object. If native code
+        // deletes the reference we won't run into a null reference later.
+        VMThread thread = vmThread;
+        if (thread != null) {
+            // If the Thread Object became invalid or was not yet started,
+            // getStatus() will return -1.
+            int state = thread.getStatus();
+            if(state != -1) {
+                return VMThread.STATE_MAP[state];
+            }
+        }
+        return hasBeenStarted ? Thread.State.TERMINATED : Thread.State.NEW;
+    }
+
+    /**
+     * Returns the ThreadGroup to which this Thread belongs.
+     *
+     * @return the Thread's ThreadGroup
+     */
+    public final ThreadGroup getThreadGroup() {
+        // TODO This should actually be done at native termination.
+        if (getState() == Thread.State.TERMINATED) {
+            return null;
+        } else {
+            return group;
+        }
+    }
+
+    /**
+     * Returns the thread's uncaught exception handler. If not explicitly set,
+     * then the ThreadGroup's handler is returned. If the thread is terminated,
+     * then <code>null</code> is returned.
+     *
+     * @return an {@link UncaughtExceptionHandler} instance or {@code null}.
+     */
+    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
+        if (uncaughtHandler != null)
+            return uncaughtHandler;
+        else
+            return group;           // ThreadGroup is instance of UEH
+    }
+
+    /**
+     * Posts an interrupt request to this {@code Thread}. The behavior depends on
+     * the state of this {@code Thread}:
+     * <ul>
+     * <li>
+     * {@code Thread}s blocked in one of {@code Object}'s {@code wait()} methods
+     * or one of {@code Thread}'s {@code join()} or {@code sleep()} methods will
+     * be woken up, their interrupt status will be cleared, and they receive an
+     * {@link InterruptedException}.
+     * <li>
+     * {@code Thread}s blocked in an I/O operation of an
+     * {@link java.nio.channels.InterruptibleChannel} will have their interrupt
+     * status set and receive an
+     * {@link java.nio.channels.ClosedByInterruptException}. Also, the channel
+     * will be closed.
+     * <li>
+     * {@code Thread}s blocked in a {@link java.nio.channels.Selector} will have
+     * their interrupt status set and return immediately. They don't receive an
+     * exception in this case.
+     * <ul>
+     *
+     * @see Thread#interrupted
+     * @see Thread#isInterrupted
+     */
+    public void interrupt() {
+        // Interrupt this thread before running actions so that other
+        // threads that observe the interrupt as a result of an action
+        // will see that this thread is in the interrupted state.
+        VMThread vmt = this.vmThread;
+        if (vmt != null) {
+            vmt.interrupt();
+        }
+
+        synchronized (interruptActions) {
+            for (int i = interruptActions.size() - 1; i >= 0; i--) {
+                interruptActions.get(i).run();
+            }
+        }
+    }
+
+    /**
+     * Returns a <code>boolean</code> indicating whether the current Thread (
+     * <code>currentThread()</code>) has a pending interrupt request (<code>
+     * true</code>) or not (<code>false</code>). It also has the side-effect of
+     * clearing the flag.
+     *
+     * @return a <code>boolean</code> indicating the interrupt status
+     * @see Thread#currentThread
+     * @see Thread#interrupt
+     * @see Thread#isInterrupted
+     */
+    public static boolean interrupted() {
+        return VMThread.interrupted();
+    }
+
+    /**
+     * Returns <code>true</code> if the receiver has already been started and
+     * still runs code (hasn't died yet). Returns <code>false</code> either if
+     * the receiver hasn't been started yet or if it has already started and run
+     * to completion and died.
+     *
+     * @return a <code>boolean</code> indicating the liveness of the Thread
+     * @see Thread#start
+     */
+    public final boolean isAlive() {
+        return (vmThread != null);
+    }
+
+    /**
+     * Tests whether this is a daemon thread.
+     * A daemon thread only runs as long as there are non-daemon threads running.
+     * When the last non-daemon thread ends, the runtime will exit. This is not
+     * normally relevant to applications with a UI.
+     */
+    public final boolean isDaemon() {
+        return daemon;
+    }
+
+    /**
+     * Returns a <code>boolean</code> indicating whether the receiver has a
+     * pending interrupt request (<code>true</code>) or not (
+     * <code>false</code>)
+     *
+     * @return a <code>boolean</code> indicating the interrupt status
+     * @see Thread#interrupt
+     * @see Thread#interrupted
+     */
+    public boolean isInterrupted() {
+        VMThread vmt = this.vmThread;
+        if (vmt != null) {
+            return vmt.isInterrupted();
+        }
+
+        return false;
+    }
+
+    /**
+     * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+     * the receiver finishes its execution and dies.
+     *
+     * @throws InterruptedException if the current thread has been interrupted.
+     *         The interrupted status of the current thread will be cleared before the exception is
+     *         thrown.
+     * @see Object#notifyAll
+     * @see java.lang.ThreadDeath
+     */
+    public final void join() throws InterruptedException {
+        VMThread t = vmThread;
+        if (t == null) {
+            return;
+        }
+
+        synchronized (t) {
+            while (isAlive()) {
+                t.wait();
+            }
+        }
+    }
+
+    /**
+     * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+     * the receiver finishes its execution and dies or the specified timeout
+     * expires, whatever happens first.
+     *
+     * <p>A timeout of zero means the calling thread should wait forever unless interrupted.
+     *
+     * @param millis The maximum time to wait (in milliseconds).
+     * @throws InterruptedException if the current thread has been interrupted.
+     *         The interrupted status of the current thread will be cleared before the exception is
+     *         thrown.
+     * @see Object#notifyAll
+     * @see java.lang.ThreadDeath
+     */
+    public final void join(long millis) throws InterruptedException {
+        join(millis, 0);
+    }
+
+    /**
+     * Blocks the current Thread (<code>Thread.currentThread()</code>) until
+     * the receiver finishes its execution and dies or the specified timeout
+     * expires, whatever happens first.
+     *
+     * <p>A timeout of zero means the calling thread should wait forever unless interrupted.
+     *
+     * @param millis The maximum time to wait (in milliseconds).
+     * @param nanos Extra nanosecond precision
+     * @throws InterruptedException if the current thread has been interrupted.
+     *         The interrupted status of the current thread will be cleared before the exception is
+     *         thrown.
+     * @see Object#notifyAll
+     * @see java.lang.ThreadDeath
+     */
+    public final void join(long millis, int nanos) throws InterruptedException {
+        if (millis < 0 || nanos < 0 || nanos >= NANOS_PER_MILLI) {
+            throw new IllegalArgumentException("bad timeout: millis=" + millis + ",nanos=" + nanos);
+        }
+
+        // avoid overflow: if total > 292,277 years, just wait forever
+        boolean overflow = millis >= (Long.MAX_VALUE - nanos) / NANOS_PER_MILLI;
+        boolean forever = (millis | nanos) == 0;
+        if (forever | overflow) {
+            join();
+            return;
+        }
+
+        VMThread t = vmThread;
+        if (t == null) {
+            return;
+        }
+
+        synchronized (t) {
+            if (!isAlive()) {
+                return;
+            }
+
+            // guaranteed not to overflow
+            long nanosToWait = millis * NANOS_PER_MILLI + nanos;
+
+            // wait until this thread completes or the timeout has elapsed
+            long start = System.nanoTime();
+            while (true) {
+                t.wait(millis, nanos);
+                if (!isAlive()) {
+                    break;
+                }
+                long nanosElapsed = System.nanoTime() - start;
+                long nanosRemaining = nanosToWait - nanosElapsed;
+                if (nanosRemaining <= 0) {
+                    break;
+                }
+                millis = nanosRemaining / NANOS_PER_MILLI;
+                nanos = (int) (nanosRemaining - millis * NANOS_PER_MILLI);
+            }
+        }
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     * @deprecated Only useful in conjunction with deprecated method {@link Thread#suspend}.
+     */
+    @Deprecated
+    public final void resume() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Calls the <code>run()</code> method of the Runnable object the receiver
+     * holds. If no Runnable is set, does nothing.
+     *
+     * @see Thread#start
+     */
+    public void run() {
+        if (target != null) {
+            target.run();
+        }
+    }
+
+    /**
+     * Set the context ClassLoader for the receiver.
+     *
+     * @param cl The context ClassLoader
+     * @see #getContextClassLoader()
+     */
+    public void setContextClassLoader(ClassLoader cl) {
+        contextClassLoader = cl;
+    }
+
+    /**
+     * Marks this thread as a daemon thread.
+     * A daemon thread only runs as long as there are non-daemon threads running.
+     * When the last non-daemon thread ends, the runtime will exit. This is not
+     * normally relevant to applications with a UI.
+     * @throws IllegalThreadStateException - if this thread has already started.
+     */
+    public final void setDaemon(boolean isDaemon) {
+        checkNotStarted();
+        if (vmThread == null) {
+            daemon = isDaemon;
+        }
+    }
+
+    private void checkNotStarted() {
+        if (hasBeenStarted) {
+            throw new IllegalThreadStateException("Thread already started");
+        }
+    }
+
+    /**
+     * Sets the default uncaught exception handler. This handler is invoked in
+     * case any Thread dies due to an unhandled exception.
+     *
+     * @param handler
+     *            The handler to set or null.
+     */
+    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
+        Thread.defaultUncaughtHandler = handler;
+    }
+
+    /**
+     * Adds a runnable to be invoked upon interruption. If this thread has
+     * already been interrupted, the runnable will be invoked immediately. The
+     * action should be idempotent as it may be invoked multiple times for a
+     * single interruption.
+     *
+     * <p>Each call to this method must be matched with a corresponding call to
+     * {@link #popInterruptAction$}.
+     *
+     * @hide used by NIO
+     */
+    public final void pushInterruptAction$(Runnable interruptAction) {
+        synchronized (interruptActions) {
+            interruptActions.add(interruptAction);
+        }
+
+        if (interruptAction != null && isInterrupted()) {
+            interruptAction.run();
+        }
+    }
+
+    /**
+     * Removes {@code interruptAction} so it is not invoked upon interruption.
+     *
+     * @param interruptAction the pushed action, used to check that the call
+     *     stack is correctly nested.
+     *
+     * @hide used by NIO
+     */
+    public final void popInterruptAction$(Runnable interruptAction) {
+        synchronized (interruptActions) {
+            Runnable removed = interruptActions.remove(interruptActions.size() - 1);
+            if (interruptAction != removed) {
+                throw new IllegalArgumentException(
+                        "Expected " + interruptAction + " but was " + removed);
+            }
+        }
+    }
+
+    /**
+     * Sets the name of the Thread.
+     *
+     * @param threadName the new name for the Thread
+     * @see Thread#getName
+     */
+    public final void setName(String threadName) {
+        if (threadName == null) {
+            throw new NullPointerException("threadName == null");
+        }
+
+        name = threadName;
+        VMThread vmt = this.vmThread;
+        if (vmt != null) {
+            /* notify the VM that the thread name has changed */
+            vmt.nameChanged(threadName);
+        }
+    }
+
+    /**
+     * Sets the priority of this thread. If the requested priority is greater than the
+     * parent thread group's {@link java.lang.ThreadGroup#getMaxPriority}, the group's maximum
+     * priority will be used instead.
+     *
+     * @throws IllegalArgumentException - if the new priority is greater than {@link #MAX_PRIORITY}
+     *     or less than {@link #MIN_PRIORITY}
+     */
+    public final void setPriority(int priority) {
+        if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
+            throw new IllegalArgumentException("Priority out of range: " + priority);
+        }
+
+        if (priority > group.getMaxPriority()) {
+            priority = group.getMaxPriority();
+        }
+
+        this.priority = priority;
+
+        VMThread vmt = this.vmThread;
+        if (vmt != null) {
+            vmt.setPriority(priority);
+        }
+    }
+
+    /**
+     * <p>
+     * Sets the uncaught exception handler. This handler is invoked in case this
+     * Thread dies due to an unhandled exception.
+     * </p>
+     *
+     * @param handler
+     *            The handler to set or <code>null</code>.
+     */
+    public void setUncaughtExceptionHandler(UncaughtExceptionHandler handler) {
+        uncaughtHandler = handler;
+    }
+
+    /**
+     * Causes the thread which sent this message to sleep for the given interval
+     * of time (given in milliseconds). The precision is not guaranteed - the
+     * Thread may sleep more or less than requested.
+     *
+     * @param time
+     *            The time to sleep in milliseconds.
+     * @throws InterruptedException if the current thread has been interrupted.
+     *            The interrupted status of the current thread will be cleared before the exception
+     *            is thrown.
+     * @see Thread#interrupt()
+     */
+    public static void sleep(long time) throws InterruptedException {
+        Thread.sleep(time, 0);
+    }
+
+    /**
+     * Causes the thread which sent this message to sleep for the given interval
+     * of time (given in milliseconds and nanoseconds). The precision is not
+     * guaranteed - the Thread may sleep more or less than requested.
+     *
+     * @param millis
+     *            The time to sleep in milliseconds.
+     * @param nanos
+     *            Extra nanosecond precision
+     * @throws InterruptedException if the current thread has been interrupted.
+     *            The interrupted status of the current thread will be cleared before the exception
+     *            is thrown.
+     * @see Thread#interrupt()
+     */
+    public static void sleep(long millis, int nanos) throws InterruptedException {
+        VMThread.sleep(millis, nanos);
+    }
+
+    /**
+     * Starts the new Thread of execution. The <code>run()</code> method of
+     * the receiver will be called by the receiver Thread itself (and not the
+     * Thread calling <code>start()</code>).
+     *
+     * @throws IllegalThreadStateException - if this thread has already started.
+     * @see Thread#run
+     */
+    public synchronized void start() {
+        checkNotStarted();
+
+        hasBeenStarted = true;
+
+        VMThread.create(this, stackSize);
+    }
+
+    /**
+     * Requests the receiver Thread to stop and throw ThreadDeath. The Thread is
+     * resumed if it was suspended and awakened if it was sleeping, so that it
+     * can proceed to throw ThreadDeath.
+     *
+     * @deprecated Stopping a thread in this manner is unsafe and can
+     * leave your application and the VM in an unpredictable state.
+     */
+    @Deprecated
+    public final void stop() {
+        stop(new ThreadDeath());
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     * @deprecated Stopping a thread in this manner is unsafe and can
+     * leave your application and the VM in an unpredictable state.
+     */
+    @Deprecated
+    public final synchronized void stop(Throwable throwable) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Throws {@code UnsupportedOperationException}.
+     * @deprecated May cause deadlocks.
+     */
+    @Deprecated
+    public final void suspend() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of the
+     * Thread. It includes the Thread's name, priority, and group name.
+     *
+     * @return a printable representation for the receiver.
+     */
+    @Override
+    public String toString() {
+        return "Thread[" + name + "," + priority + "," + group.getName() + "]";
+    }
+
+    /**
+     * Causes the calling Thread to yield execution time to another Thread that
+     * is ready to run. The actual scheduling is implementation-dependent.
+     */
+    public static void yield() {
+        VMThread.yield();
+    }
+
+    /**
+     * Indicates whether the current Thread has a monitor lock on the specified
+     * object.
+     *
+     * @param object the object to test for the monitor lock
+     * @return true if the current thread has a monitor lock on the specified
+     *         object; false otherwise
+     */
+    public static boolean holdsLock(Object object) {
+        return currentThread().vmThread.holdsLock(object);
+    }
+
+    /**
+     * Implemented by objects that want to handle cases where a thread is being
+     * terminated by an uncaught exception. Upon such termination, the handler
+     * is notified of the terminating thread and causal exception. If there is
+     * no explicit handler set then the thread's group is the default handler.
+     */
+    public static interface UncaughtExceptionHandler {
+        /**
+         * The thread is being terminated by an uncaught exception. Further
+         * exceptions thrown in this method are prevent the remainder of the
+         * method from executing, but are otherwise ignored.
+         *
+         * @param thread the thread that has an uncaught exception
+         * @param ex the exception that was thrown
+         */
+        void uncaughtException(Thread thread, Throwable ex);
+    }
+
+    /**
+     * Unparks this thread. This unblocks the thread it if it was
+     * previously parked, or indicates that the thread is "preemptively
+     * unparked" if it wasn't already parked. The latter means that the
+     * next time the thread is told to park, it will merely clear its
+     * latent park bit and carry on without blocking.
+     *
+     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
+     * in-depth information of the behavior of this method.</p>
+     *
+     * @hide for Unsafe
+     */
+    public void unpark() {
+        VMThread vmt = vmThread;
+
+        if (vmt == null) {
+            /*
+             * vmThread is null before the thread is start()ed. In
+             * this case, we just go ahead and set the state to
+             * PREEMPTIVELY_UNPARKED. Since this happens before the
+             * thread is started, we don't have to worry about
+             * synchronizing with it.
+             */
+            parkState = ParkState.PREEMPTIVELY_UNPARKED;
+            return;
+        }
+
+        synchronized (vmt) {
+            switch (parkState) {
+                case ParkState.PREEMPTIVELY_UNPARKED: {
+                    /*
+                     * Nothing to do in this case: By definition, a
+                     * preemptively unparked thread is to remain in
+                     * the preemptively unparked state if it is told
+                     * to unpark.
+                     */
+                    break;
+                }
+                case ParkState.UNPARKED: {
+                    parkState = ParkState.PREEMPTIVELY_UNPARKED;
+                    break;
+                }
+                default /*parked*/: {
+                    parkState = ParkState.UNPARKED;
+                    vmt.notifyAll();
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Parks the current thread for a particular number of nanoseconds, or
+     * indefinitely. If not indefinitely, this method unparks the thread
+     * after the given number of nanoseconds if no other thread unparks it
+     * first. If the thread has been "preemptively unparked," this method
+     * cancels that unparking and returns immediately. This method may
+     * also return spuriously (that is, without the thread being told to
+     * unpark and without the indicated amount of time elapsing).
+     *
+     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
+     * in-depth information of the behavior of this method.</p>
+     *
+     * <p>This method must only be called when <code>this</code> is the current
+     * thread.
+     *
+     * @param nanos number of nanoseconds to park for or <code>0</code>
+     * to park indefinitely
+     * @throws IllegalArgumentException thrown if <code>nanos &lt; 0</code>
+     *
+     * @hide for Unsafe
+     */
+    public void parkFor(long nanos) {
+        VMThread vmt = vmThread;
+
+        if (vmt == null) {
+            // Running threads should always have an associated vmThread.
+            throw new AssertionError();
+        }
+
+        synchronized (vmt) {
+            switch (parkState) {
+                case ParkState.PREEMPTIVELY_UNPARKED: {
+                    parkState = ParkState.UNPARKED;
+                    break;
+                }
+                case ParkState.UNPARKED: {
+                    long millis = nanos / NANOS_PER_MILLI;
+                    nanos %= NANOS_PER_MILLI;
+
+                    parkState = ParkState.PARKED;
+                    try {
+                        vmt.wait(millis, (int) nanos);
+                    } catch (InterruptedException ex) {
+                        interrupt();
+                    } finally {
+                        /*
+                         * Note: If parkState manages to become
+                         * PREEMPTIVELY_UNPARKED before hitting this
+                         * code, it should left in that state.
+                         */
+                        if (parkState == ParkState.PARKED) {
+                            parkState = ParkState.UNPARKED;
+                        }
+                    }
+                    break;
+                }
+                default /*parked*/: {
+                    throw new AssertionError(
+                            "shouldn't happen: attempt to repark");
+                }
+            }
+        }
+    }
+
+    /**
+     * Parks the current thread until the specified system time. This
+     * method attempts to unpark the current thread immediately after
+     * <code>System.currentTimeMillis()</code> reaches the specified
+     * value, if no other thread unparks it first. If the thread has
+     * been "preemptively unparked," this method cancels that
+     * unparking and returns immediately. This method may also return
+     * spuriously (that is, without the thread being told to unpark
+     * and without the indicated amount of time elapsing).
+     *
+     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
+     * in-depth information of the behavior of this method.</p>
+     *
+     * <p>This method must only be called when <code>this</code> is the
+     * current thread.
+     *
+     * @param time the time after which the thread should be unparked,
+     * in absolute milliseconds-since-the-epoch
+     *
+     * @hide for Unsafe
+     */
+    public void parkUntil(long time) {
+        VMThread vmt = vmThread;
+
+        if (vmt == null) {
+            // Running threads should always have an associated vmThread.
+            throw new AssertionError();
+        }
+
+        synchronized (vmt) {
+            /*
+             * Note: This conflates the two time bases of "wall clock"
+             * time and "monotonic uptime" time. However, given that
+             * the underlying system can only wait on monotonic time,
+             * it is unclear if there is any way to avoid the
+             * conflation. The downside here is that if, having
+             * calculated the delay, the wall clock gets moved ahead,
+             * this method may not return until well after the wall
+             * clock has reached the originally designated time. The
+             * reverse problem (the wall clock being turned back)
+             * isn't a big deal, since this method is allowed to
+             * spuriously return for any reason, and this situation
+             * can safely be construed as just such a spurious return.
+             */
+            long delayMillis = time - System.currentTimeMillis();
+
+            if (delayMillis <= 0) {
+                parkState = ParkState.UNPARKED;
+            } else {
+                parkFor(delayMillis * NANOS_PER_MILLI);
+            }
+        }
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/ThreadGroup.java b/libdvm/src/main/java/java/lang/ThreadGroup.java
new file mode 100644
index 0000000..7fc6b72
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/ThreadGroup.java
@@ -0,0 +1,726 @@
+/*
+ * 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 java.lang;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import libcore.util.CollectionUtils;
+
+/**
+ * {@code ThreadGroup} is a means of organizing threads into a hierarchical structure.
+ * This class is obsolete. See <i>Effective Java</i> Item 73, "Avoid thread groups" for details.
+ * @see Thread
+ */
+public class ThreadGroup implements Thread.UncaughtExceptionHandler {
+
+    // Name of this ThreadGroup
+    // VM needs this field name for debugging.
+    private String name;
+
+    // Maximum priority for Threads inside this ThreadGroup
+    private int maxPriority = Thread.MAX_PRIORITY;
+
+    // The ThreadGroup to which this ThreadGroup belongs
+    // VM needs this field name for debugging.
+    final ThreadGroup parent;
+
+    /**
+     * Weak references to the threads in this group.
+     * Access is guarded by synchronizing on this field.
+     */
+    private final List<WeakReference<Thread>> threadRefs = new ArrayList<WeakReference<Thread>>(5);
+
+    /**
+     * View of the threads.
+     * Access is guarded by synchronizing on threadRefs.
+     */
+    private final Iterable<Thread> threads = CollectionUtils.dereferenceIterable(threadRefs, true);
+
+    /**
+     * Thread groups. Access is guarded by synchronizing on this field.
+     */
+    private final List<ThreadGroup> groups = new ArrayList<ThreadGroup>(3);
+
+    // Whether this ThreadGroup is a daemon ThreadGroup or not
+    private boolean isDaemon;
+
+    // Whether this ThreadGroup has already been destroyed or not
+    private boolean isDestroyed;
+
+    /* the VM uses these directly; do not rename */
+    static final ThreadGroup mSystem = new ThreadGroup();
+    static final ThreadGroup mMain = new ThreadGroup(mSystem, "main");
+
+    /**
+     * Constructs a new {@code ThreadGroup} with the given name. The new {@code ThreadGroup}
+     * will be child of the {@code ThreadGroup} to which the calling thread belongs.
+     *
+     * @param name the name
+     * @see Thread#currentThread
+     */
+    public ThreadGroup(String name) {
+        this(Thread.currentThread().getThreadGroup(), name);
+    }
+
+    /**
+     * Constructs a new {@code ThreadGroup} with the given name, as a child of the
+     * given {@code ThreadGroup}.
+     *
+     * @param parent the parent
+     * @param name the name
+     * @throws NullPointerException if {@code parent == null}
+     * @throws IllegalThreadStateException if {@code parent} has been
+     *         destroyed already
+     */
+    public ThreadGroup(ThreadGroup parent, String name) {
+        if (parent == null) {
+            throw new NullPointerException("parent == null");
+        }
+        this.name = name;
+        this.parent = parent;
+        if (parent != null) {
+            parent.add(this);
+            this.setMaxPriority(parent.getMaxPriority());
+            if (parent.isDaemon()) {
+                this.setDaemon(true);
+            }
+        }
+    }
+
+    /**
+     * Initialize the special "system" ThreadGroup. Was "main" in Harmony,
+     * but we have an additional group above that in Android.
+     */
+    private ThreadGroup() {
+        this.name = "system";
+        this.parent = null;
+    }
+
+    /**
+     * Returns the number of running {@code Thread}s which are children of this thread group,
+     * directly or indirectly.
+     *
+     * @return the number of children
+     */
+    public int activeCount() {
+        int count = 0;
+        synchronized (threadRefs) {
+            for (Thread thread : threads) {
+                if (thread.isAlive()) {
+                    count++;
+                }
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                count += group.activeCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns the number of {@code ThreadGroup}s which are children of this group,
+     * directly or indirectly.
+     *
+     * @return the number of children
+     */
+    public int activeGroupCount() {
+        int count = 0;
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                // One for this group & the subgroups
+                count += 1 + group.activeGroupCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Adds a {@code ThreadGroup} to this thread group.
+     *
+     * @param g ThreadGroup to add
+     * @throws IllegalThreadStateException if this group has been destroyed already
+     */
+    private void add(ThreadGroup g) throws IllegalThreadStateException {
+        synchronized (groups) {
+            if (isDestroyed) {
+                throw new IllegalThreadStateException();
+            }
+            groups.add(g);
+        }
+    }
+
+    /**
+     * Does nothing. The definition of this method depends on the deprecated
+     * method {@link #suspend()}. The exact behavior of this call was never
+     * specified.
+     *
+     * @param b Used to control low memory implicit suspension
+     * @return {@code true} (always)
+     *
+     * @deprecated Required deprecated method {@link #suspend()}.
+     */
+    @Deprecated
+    public boolean allowThreadSuspension(boolean b) {
+        // Does not apply to this VM, no-op
+        return true;
+    }
+
+    /**
+     * Does nothing.
+     */
+    public final void checkAccess() {
+    }
+
+    /**
+     * Destroys this thread group and recursively all its subgroups. It is only legal
+     * to destroy a {@code ThreadGroup} that has no threads in it. Any daemon
+     * {@code ThreadGroup} is destroyed automatically when it becomes empty (no threads
+     * or thread groups in it).
+     *
+     * @throws IllegalThreadStateException if this thread group or any of its
+     *         subgroups has been destroyed already or if it still contains
+     *         threads.
+     */
+    public final void destroy() {
+        synchronized (threadRefs) {
+            synchronized (groups) {
+                if (isDestroyed) {
+                    throw new IllegalThreadStateException(
+                            "Thread group was already destroyed: "
+                            + (this.name != null ? this.name : "n/a"));
+                }
+                if (threads.iterator().hasNext()) {
+                    throw new IllegalThreadStateException(
+                            "Thread group still contains threads: "
+                            + (this.name != null ? this.name : "n/a"));
+                }
+                // Call recursively for subgroups
+                while (!groups.isEmpty()) {
+                    // We always get the first element - remember, when the
+                    // child dies it removes itself from our collection. See
+                    // below.
+                    groups.get(0).destroy();
+                }
+
+                if (parent != null) {
+                    parent.remove(this);
+                }
+
+                // Now that the ThreadGroup is really destroyed it can be tagged as so
+                this.isDestroyed = true;
+            }
+        }
+    }
+
+    /*
+     * Auxiliary method that destroys this thread group and recursively all its
+     * subgroups if this is a daemon ThreadGroup.
+     *
+     * @see #destroy
+     * @see #setDaemon
+     * @see #isDaemon
+     */
+    private void destroyIfEmptyDaemon() {
+        // Has to be non-destroyed daemon to make sense
+        synchronized (threadRefs) {
+            if (isDaemon && !isDestroyed && !threads.iterator().hasNext()) {
+                synchronized (groups) {
+                    if (groups.isEmpty()) {
+                        destroy();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterates over all active threads in this group (and its sub-groups) and
+     * stores the threads in the given array. Returns when the array is full or
+     * no more threads remain, whichever happens first.
+     *
+     * <p>Note that this method will silently ignore any threads that don't fit in the
+     * supplied array.
+     *
+     * @param threads the array into which the {@code Thread}s will be copied
+     * @return the number of {@code Thread}s that were copied
+     */
+    public int enumerate(Thread[] threads) {
+        return enumerate(threads, true);
+    }
+
+    /**
+     * Iterates over all active threads in this group (and, optionally, its
+     * sub-groups) and stores the threads in the given array. Returns when the
+     * array is full or no more threads remain, whichever happens first.
+     *
+     * <p>Note that this method will silently ignore any threads that don't fit in the
+     * supplied array.
+     *
+     * @param threads the array into which the {@code Thread}s will be copied
+     * @param recurse indicates whether {@code Thread}s in subgroups should be
+     *        recursively copied as well
+     * @return the number of {@code Thread}s that were copied
+     */
+    public int enumerate(Thread[] threads, boolean recurse) {
+        return enumerateGeneric(threads, recurse, 0, true);
+    }
+
+    /**
+     * Iterates over all thread groups in this group (and its sub-groups) and
+     * and stores the groups in the given array. Returns when the array is full
+     * or no more groups remain, whichever happens first.
+     *
+     * <p>Note that this method will silently ignore any thread groups that don't fit in the
+     * supplied array.
+     *
+     * @param groups the array into which the {@code ThreadGroup}s will be copied
+     * @return the number of {@code ThreadGroup}s that were copied
+     */
+    public int enumerate(ThreadGroup[] groups) {
+        return enumerate(groups, true);
+    }
+
+    /**
+     * Iterates over all thread groups in this group (and, optionally, its
+     * sub-groups) and stores the groups in the given array. Returns when
+     * the array is full or no more groups remain, whichever happens first.
+     *
+     * <p>Note that this method will silently ignore any thread groups that don't fit in the
+     * supplied array.
+     *
+     * @param groups the array into which the {@code ThreadGroup}s will be copied
+     * @param recurse indicates whether {@code ThreadGroup}s in subgroups should be
+     *        recursively copied as well or not
+     * @return the number of {@code ThreadGroup}s that were copied
+     */
+    public int enumerate(ThreadGroup[] groups, boolean recurse) {
+        return enumerateGeneric(groups, recurse, 0, false);
+    }
+
+    /**
+     * Copies into <param>enumeration</param> starting at
+     * <param>enumerationIndex</param> all Threads or ThreadGroups in the
+     * receiver. If <param>recurse</param> is true, recursively enumerate the
+     * elements in subgroups.
+     *
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     *
+     * @param enumeration array into which the elements will be copied
+     * @param recurse Indicates whether subgroups should be enumerated or not
+     * @param enumerationIndex Indicates in which position of the enumeration
+     *        array we are
+     * @param enumeratingThreads Indicates whether we are enumerating Threads or
+     *        ThreadGroups
+     * @return How many elements were enumerated/copied over
+     */
+    private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
+            boolean enumeratingThreads) {
+        if (enumeratingThreads) {
+            synchronized (threadRefs) {
+                // walk the references directly so we can iterate in reverse order
+                for (int i = threadRefs.size() - 1; i >= 0; --i) {
+                    Thread thread = threadRefs.get(i).get();
+                    if (thread != null && thread.isAlive()) {
+                        if (enumerationIndex >= enumeration.length) {
+                            return enumerationIndex;
+                        }
+                        enumeration[enumerationIndex++] = thread;
+                    }
+                }
+            }
+        } else {
+            synchronized (groups) {
+                for (int i = groups.size() - 1; i >= 0; --i) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumeration[enumerationIndex++] = groups.get(i);
+                }
+            }
+        }
+
+        if (recurse) {
+            synchronized (groups) {
+                for (ThreadGroup group : groups) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumerationIndex = group.enumerateGeneric(enumeration, recurse,
+                            enumerationIndex, enumeratingThreads);
+                }
+            }
+        }
+        return enumerationIndex;
+    }
+
+    /**
+     * Returns the maximum allowed priority for a {@code Thread} in this thread group.
+     *
+     * @return the maximum priority
+     *
+     * @see #setMaxPriority
+     */
+    public final int getMaxPriority() {
+        return maxPriority;
+    }
+
+    /**
+     * Returns the name of this thread group.
+     *
+     * @return the group's name
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Returns this thread group's parent {@code ThreadGroup}. It can be null if this
+     * is the the root ThreadGroup.
+     *
+     * @return the parent
+     */
+    public final ThreadGroup getParent() {
+        return parent;
+    }
+
+    /**
+     * Interrupts every {@code Thread} in this group and recursively in all its
+     * subgroups.
+     *
+     * @see Thread#interrupt
+     */
+    public final void interrupt() {
+        synchronized (threadRefs) {
+            for (Thread thread : threads) {
+                thread.interrupt();
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                group.interrupt();
+            }
+        }
+    }
+
+    /**
+     * Checks whether this thread group is a daemon {@code ThreadGroup}.
+     *
+     * @return true if this thread group is a daemon {@code ThreadGroup}
+     *
+     * @see #setDaemon
+     * @see #destroy
+     */
+    public final boolean isDaemon() {
+        return isDaemon;
+    }
+
+    /**
+     * Checks whether this thread group has already been destroyed.
+     *
+     * @return true if this thread group has already been destroyed
+     * @see #destroy
+     */
+    public synchronized boolean isDestroyed() {
+        return isDestroyed;
+    }
+
+    /**
+     * Outputs to {@code System.out} a text representation of the
+     * hierarchy of {@code Thread}s and {@code ThreadGroup}s in this thread group (and recursively).
+     * Proper indentation is used to show the nesting of groups inside groups
+     * and threads inside groups.
+     */
+    public void list() {
+        // We start in a fresh line
+        System.out.println();
+        list(0);
+    }
+
+    /*
+     * Outputs to {@code System.out}a text representation of the
+     * hierarchy of Threads and ThreadGroups in this thread group (and recursively).
+     * The indentation will be four spaces per level of nesting.
+     *
+     * @param levels How many levels of nesting, so that proper indentation can
+     * be output.
+     */
+    private void list(int levels) {
+        indent(levels);
+        System.out.println(this.toString());
+
+        ++levels;
+        synchronized (threadRefs) {
+            for (Thread thread : threads) {
+                indent(levels);
+                System.out.println(thread);
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                group.list(levels);
+            }
+        }
+    }
+
+    private void indent(int levels) {
+        for (int i = 0; i < levels; i++) {
+            System.out.print("    "); // 4 spaces for each level
+        }
+    }
+
+    /**
+     * Checks whether this thread group is a direct or indirect parent group of a
+     * given {@code ThreadGroup}.
+     *
+     * @param g the potential child {@code ThreadGroup}
+     * @return true if this thread group is parent of {@code g}
+     */
+    public final boolean parentOf(ThreadGroup g) {
+        while (g != null) {
+            if (this == g) {
+                return true;
+            }
+            g = g.parent;
+        }
+        return false;
+    }
+
+    /**
+     * Removes an immediate subgroup.
+     *
+     * @param g ThreadGroup to remove
+     *
+     * @see #add(Thread)
+     * @see #add(ThreadGroup)
+     */
+    private void remove(ThreadGroup g) {
+        synchronized (groups) {
+            for (Iterator<ThreadGroup> i = groups.iterator(); i.hasNext(); ) {
+                ThreadGroup threadGroup = i.next();
+                if (threadGroup.equals(g)) {
+                    i.remove();
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+
+    /**
+     * Resumes every thread in this group and recursively in all its
+     * subgroups.
+     *
+     * @see Thread#resume
+     * @see #suspend
+     *
+     * @deprecated Requires deprecated method {@link Thread#resume()}.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void resume() {
+        synchronized (threadRefs) {
+            for (Thread thread : threads) {
+                thread.resume();
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                group.resume();
+            }
+        }
+    }
+
+    /**
+     * Sets whether this is a daemon {@code ThreadGroup} or not. Daemon
+     * thread groups are automatically destroyed when they become empty.
+     *
+     * @param isDaemon the new value
+     * @see #isDaemon
+     * @see #destroy
+     */
+    public final void setDaemon(boolean isDaemon) {
+        this.isDaemon = isDaemon;
+    }
+
+    /**
+     * Configures the maximum allowed priority for a {@code Thread} in this group and
+     * recursively in all its subgroups.
+     *
+     * <p>A caller can never increase the maximum priority of a thread group.
+     * Such an attempt will not result in an exception, it will
+     * simply leave the thread group with its current maximum priority.
+     *
+     * @param newMax the new maximum priority to be set
+     *
+     * @throws IllegalArgumentException if the new priority is greater than
+     *         Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
+     *
+     * @see #getMaxPriority
+     */
+    public final void setMaxPriority(int newMax) {
+        if (newMax <= this.maxPriority) {
+            if (newMax < Thread.MIN_PRIORITY) {
+                newMax = Thread.MIN_PRIORITY;
+            }
+
+            int parentPriority = parent == null ? newMax : parent.getMaxPriority();
+            this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
+            synchronized (groups) {
+                for (ThreadGroup group : groups) {
+                    group.setMaxPriority(newMax);
+                }
+            }
+        }
+    }
+
+    /**
+     * Stops every thread in this group and recursively in all its subgroups.
+     *
+     * @see Thread#stop()
+     * @see Thread#stop(Throwable)
+     * @see ThreadDeath
+     *
+     * @deprecated Requires deprecated method {@link Thread#stop()}.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void stop() {
+        if (stopHelper()) {
+            Thread.currentThread().stop();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private boolean stopHelper() {
+        boolean stopCurrent = false;
+        synchronized (threadRefs) {
+            Thread current = Thread.currentThread();
+            for (Thread thread : threads) {
+                if (thread == current) {
+                    stopCurrent = true;
+                } else {
+                    thread.stop();
+                }
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                stopCurrent |= group.stopHelper();
+            }
+        }
+        return stopCurrent;
+    }
+
+    /**
+     * Suspends every thread in this group and recursively in all its
+     * subgroups.
+     *
+     * @see Thread#suspend
+     * @see #resume
+     *
+     * @deprecated Requires deprecated method {@link Thread#suspend()}.
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void suspend() {
+        if (suspendHelper()) {
+            Thread.currentThread().suspend();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private boolean suspendHelper() {
+        boolean suspendCurrent = false;
+        synchronized (threadRefs) {
+            Thread current = Thread.currentThread();
+            for (Thread thread : threads) {
+                if (thread == current) {
+                    suspendCurrent = true;
+                } else {
+                    thread.suspend();
+                }
+            }
+        }
+        synchronized (groups) {
+            for (ThreadGroup group : groups) {
+                suspendCurrent |= group.suspendHelper();
+            }
+        }
+        return suspendCurrent;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getName() + "[name=" + getName()
+                + ",maxPriority=" + getMaxPriority() + "]";
+    }
+
+    /**
+     * Handles uncaught exceptions. Any uncaught exception in any {@code Thread}
+     * is forwarded to the thread's {@code ThreadGroup} by invoking this
+     * method.
+     *
+     * <p>New code should use {@link Thread#setUncaughtExceptionHandler} instead of thread groups.
+     *
+     * @param t the Thread that terminated with an uncaught exception
+     * @param e the uncaught exception itself
+     */
+    public void uncaughtException(Thread t, Throwable e) {
+        if (parent != null) {
+            parent.uncaughtException(t, e);
+        } else if (Thread.getDefaultUncaughtExceptionHandler() != null) {
+            // TODO The spec is unclear regarding this. What do we do?
+            Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, e);
+        } else if (!(e instanceof ThreadDeath)) {
+            // No parent group, has to be 'system' Thread Group
+            e.printStackTrace(System.err);
+        }
+    }
+
+    /**
+     * Called by the Thread constructor.
+     */
+    final void addThread(Thread thread) throws IllegalThreadStateException {
+        synchronized (threadRefs) {
+            if (isDestroyed) {
+                throw new IllegalThreadStateException();
+            }
+            threadRefs.add(new WeakReference<Thread>(thread));
+        }
+    }
+
+    /**
+     * Called by the VM when a Thread dies.
+     */
+    final void removeThread(Thread thread) throws IllegalThreadStateException {
+        synchronized (threadRefs) {
+            for (Iterator<Thread> i = threads.iterator(); i.hasNext(); ) {
+                if (i.next().equals(thread)) {
+                    i.remove();
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/VMClassLoader.java b/libdvm/src/main/java/java/lang/VMClassLoader.java
new file mode 100644
index 0000000..d7162c6
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/VMClassLoader.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 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;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+class VMClassLoader {
+
+    /**
+     * Get a resource from a file in the bootstrap class path.
+     *
+     * It would be simpler to just walk through the class path elements
+     * ourselves, but that would require reopening Jar files.
+     *
+     * We assume that the bootclasspath can't change once the VM has
+     * started.  This assumption seems to be supported by the spec.
+     */
+    static URL getResource(String name) {
+        int numEntries = getBootClassPathSize();
+        for (int i = 0; i < numEntries; i++) {
+            String urlStr = getBootClassPathResource(name, i);
+            if (urlStr != null) {
+                try {
+                    return new URL(urlStr);
+                } catch (MalformedURLException mue) {
+                    mue.printStackTrace();
+                    // unexpected; keep going
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Get an enumeration with all matching resources.
+     */
+    static List<URL> getResources(String name) {
+        ArrayList<URL> list = new ArrayList<URL>();
+        int numEntries = getBootClassPathSize();
+        for (int i = 0; i < numEntries; i++) {
+            String urlStr = getBootClassPathResource(name, i);
+            if (urlStr != null) {
+                try {
+                    list.add(new URL(urlStr));
+                } catch (MalformedURLException mue) {
+                    mue.printStackTrace();
+                    // unexpected; keep going
+                }
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Load class with bootstrap class loader.
+     */
+    native static Class loadClass(String name, boolean resolve) throws ClassNotFoundException;
+
+    native static Class getPrimitiveClass(char type);
+
+    native static Class findLoadedClass(ClassLoader cl, String name);
+
+    /**
+     * Boot class path manipulation, for getResources().
+     */
+    native private static int getBootClassPathSize();
+    native private static String getBootClassPathResource(String name, int index);
+}
diff --git a/libdvm/src/main/java/java/lang/VMThread.java b/libdvm/src/main/java/java/lang/VMThread.java
new file mode 100644
index 0000000..01f6ee3
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/VMThread.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 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;
+
+class VMThread {
+    Thread thread;
+    int vmData;
+
+    VMThread(Thread t) {
+        thread = t;
+    }
+
+    native static void create(Thread t, long stackSize);
+
+    static native Thread currentThread();
+    static native boolean interrupted();
+    static native void sleep (long msec, int nsec) throws InterruptedException;
+    static native void yield();
+
+    native void interrupt();
+
+    native boolean isInterrupted();
+
+    /**
+     *  Starts the VMThread (and thus the Java Thread) with the given
+     *  stack size.
+     */
+    void start(long stackSize) {
+        VMThread.create(thread, stackSize);
+    }
+
+    /**
+     * Queries whether this Thread holds a monitor lock on the
+     * given object.
+     */
+    native boolean holdsLock(Object object);
+
+    native void setPriority(int newPriority);
+    native int getStatus();
+
+    /**
+     * Holds a mapping from native Thread statuses to Java one. Required for
+     * translating back the result of getStatus().
+     */
+    static final Thread.State[] STATE_MAP = new Thread.State[] {
+        Thread.State.TERMINATED,     // ZOMBIE
+        Thread.State.RUNNABLE,       // RUNNING
+        Thread.State.TIMED_WAITING,  // TIMED_WAIT
+        Thread.State.BLOCKED,        // MONITOR
+        Thread.State.WAITING,        // WAIT
+        Thread.State.NEW,            // INITIALIZING
+        Thread.State.NEW,            // STARTING
+        Thread.State.RUNNABLE,       // NATIVE
+        Thread.State.WAITING,        // VMWAIT
+        Thread.State.RUNNABLE        // SUSPENDED
+    };
+
+    /**
+     * Tell the VM that the thread's name has changed.  This is useful for
+     * DDMS, which would otherwise be oblivious to Thread.setName calls.
+     */
+    native void nameChanged(String newName);
+}
diff --git a/libdvm/src/main/java/java/lang/ref/Reference.java b/libdvm/src/main/java/java/lang/ref/Reference.java
new file mode 100644
index 0000000..bd63535
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/ref/Reference.java
@@ -0,0 +1,200 @@
+/*
+ * 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) 2008 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.ref;
+
+/**
+ * Provides an abstract class which describes behavior common to all reference
+ * objects. It is not possible to create immediate subclasses of
+ * {@code Reference} in addition to the ones provided by this package. It is
+ * also not desirable to do so, since references require very close cooperation
+ * with the system's garbage collector. The existing, specialized reference
+ * classes should be used instead.
+ *
+ * <p>Three different type of references exist, each being weaker than the preceding one:
+ * {@link java.lang.ref.SoftReference}, {@link java.lang.ref.WeakReference}, and
+ * {@link java.lang.ref.PhantomReference}. "Weakness" here means that less restrictions are
+ * being imposed on the garbage collector as to when it is allowed to
+ * actually garbage-collect the referenced object.
+ *
+ * <p>In order to use reference objects properly it is important to understand
+ * the different types of reachability that trigger their clearing and
+ * enqueueing. The following table lists these, from strongest to weakest.
+ * For each row, an object is said to have the reachability on the left side
+ * if (and only if) it fulfills all of the requirements on the right side. In
+ * all rows, consider the <em>root set</em> to be a set of references that
+ * are "resistant" to garbage collection (that is, running threads, method
+ * parameters, local variables, static fields and the like).
+ *
+ * <p><table>
+ * <tr>
+ * <td>Strongly reachable</td>
+ * <td> <ul>
+ * <li>There exists at least one path from the root set to the object that does not traverse any
+ * instance of a {@code java.lang.ref.Reference} subclass.
+ * </li>
+ * </ul> </td>
+ * </tr>
+ *
+ * <tr>
+ * <td>Softly reachable</td>
+ * <td> <ul>
+ * <li>The object is not strongly reachable.</li>
+ * <li>There exists at least one path from the root set to the object that does traverse
+ * a {@code java.lang.ref.SoftReference} instance, but no {@code java.lang.ref.WeakReference}
+ * or {@code java.lang.ref.PhantomReference} instances.</li>
+ * </ul> </td>
+ * </tr>
+ *
+ * <tr>
+ * <td>Weakly reachable</td>
+ * <td> <ul>
+ * <li>The object is neither strongly nor softly reachable.</li>
+ * <li>There exists at least one path from the root set to the object that does traverse a
+ * {@code java.lang.ref.WeakReference} instance, but no {@code java.lang.ref.PhantomReference}
+ * instances.</li>
+ * </ul> </td>
+ * </tr>
+ *
+ * <tr>
+ * <td>Phantom-reachable</td>
+ * <td> <ul>
+ * <li>The object is neither strongly, softly, nor weakly reachable.</li>
+ * <li>The object is referenced by a {@code java.lang.ref.PhantomReference} instance.</li>
+ * <li>The object has already been finalized.</li>
+ * </ul> </td>
+ * </tr>
+ * </table>
+ */
+public abstract class Reference<T> {
+
+    /**
+     * The object to which this reference refers.
+     * VM requirement: this field <em>must</em> be called "referent"
+     * and be an object.
+     */
+    volatile T referent;
+
+    /**
+     * If non-null, the queue on which this reference will be enqueued
+     * when the referent is appropriately reachable.
+     * VM requirement: this field <em>must</em> be called "queue"
+     * and be a java.lang.ref.ReferenceQueue.
+     */
+    volatile ReferenceQueue<? super T> queue;
+
+    /**
+     * Used internally by java.lang.ref.ReferenceQueue.
+     * VM requirement: this field <em>must</em> be called "queueNext"
+     * and be a java.lang.ref.Reference.
+     */
+    @SuppressWarnings("unchecked")
+    volatile Reference queueNext;
+
+    /**
+     * Used internally by the VM.  This field forms a circular and
+     * singly linked list of reference objects discovered by the
+     * garbage collector and awaiting processing by the reference
+     * queue thread.
+     *
+     * @hide
+     */
+    public volatile Reference<?> pendingNext;
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    Reference() {
+    }
+
+    Reference(T r, ReferenceQueue<? super T> q) {
+        referent = r;
+        queue = q;
+    }
+
+    /**
+     * Makes the referent {@code null}. This does not force the reference
+     * object to be enqueued.
+     */
+    public void clear() {
+        referent = null;
+    }
+
+    /**
+     * Adds an object to its reference queue.
+     *
+     * @return {@code true} if this call has caused the {@code Reference} to
+     * become enqueued, or {@code false} otherwise
+     *
+     * @hide
+     */
+    public final synchronized boolean enqueueInternal() {
+        if (queue != null && queueNext == null) {
+            queue.enqueue(this);
+            queue = null;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Forces the reference object to be enqueued if it has been associated with
+     * a queue.
+     *
+     * @return {@code true} if this call has caused the {@code Reference} to
+     * become enqueued, or {@code false} otherwise
+     */
+    public boolean enqueue() {
+        return enqueueInternal();
+    }
+
+    /**
+     * Returns the referent of the reference object.
+     *
+     * @return the referent to which reference refers, or {@code null} if the
+     *         object has been cleared.
+     */
+    public T get() {
+        return referent;
+    }
+
+    /**
+     * Checks whether the reference object has been enqueued.
+     *
+     * @return {@code true} if the {@code Reference} has been enqueued, {@code
+     *         false} otherwise
+     */
+    public boolean isEnqueued() {
+        return queueNext != null;
+    }
+
+}
diff --git a/libdvm/src/main/java/java/lang/reflect/AccessibleObject.java b/libdvm/src/main/java/java/lang/reflect/AccessibleObject.java
new file mode 100644
index 0000000..f3d96af
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -0,0 +1,320 @@
+/*
+ * 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) 2008 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 java.lang.annotation.Annotation;
+import java.util.Hashtable;
+import org.apache.harmony.kernel.vm.StringUtils;
+
+/**
+ * {@code AccessibleObject} is the superclass of all member reflection classes
+ * (Field, Constructor, Method). AccessibleObject provides the ability to toggle
+ * a flag controlling access checks for these objects. By default, accessing a
+ * member (for example, setting a field or invoking a method) checks the
+ * validity of the access (for example, invoking a private method from outside
+ * the defining class is prohibited) and throws IllegalAccessException if the
+ * operation is not permitted. If the accessible flag is set to true, these
+ * checks are omitted. This allows privileged code, such as Java object
+ * serialization, object inspectors, and debuggers to have complete access to
+ * objects.
+ *
+ * @see Field
+ * @see Constructor
+ * @see Method
+ */
+public class AccessibleObject implements AnnotatedElement {
+
+    /**
+     * If true, object is accessible, bypassing normal access checks
+     */
+    boolean flag = false;
+
+    // Holds a mapping from Java type names to native type codes.
+    static Hashtable<String, String> trans;
+
+    static {
+        trans = new Hashtable<String, String>(9);
+        trans.put("byte", "B");
+        trans.put("char", "C");
+        trans.put("short", "S");
+        trans.put("int", "I");
+        trans.put("long", "J");
+        trans.put("float", "F");
+        trans.put("double", "D");
+        trans.put("void", "V");
+        trans.put("boolean", "Z");
+    }
+
+    /**
+     * Attempts to set the value of the accessible flag for all the objects in
+     * the array provided. Setting this
+     * flag to {@code false} will enable access checks, setting to {@code true}
+     * will disable them.
+     *
+     * @param objects
+     *            the accessible objects
+     * @param flag
+     *            the new value for the accessible flag
+     *
+     * @see #setAccessible(boolean)
+     */
+    public static void setAccessible(AccessibleObject[] objects, boolean flag) {
+        for (AccessibleObject object : objects) {
+            object.flag = flag;
+        }
+    }
+
+    /**
+     * Constructs a new {@code AccessibleObject} instance. {@code
+     * AccessibleObject} instances can only be constructed by the virtual
+     * machine.
+     */
+    protected AccessibleObject() {
+    }
+
+    /**
+     * Indicates whether this object is accessible without access checks being
+     * performed. Returns the accessible flag.
+     *
+     * @return {@code true} if this object is accessible without access
+     *         checks, {@code false} otherwise
+     */
+    public boolean isAccessible() {
+        return flag;
+    }
+
+    /**
+     * Attempts to set the value of the accessible flag. Setting this flag to
+     * {@code false} will enable access checks, setting to {@code true} will
+     * disable them.
+     *
+     * @param flag
+     *            the new value for the accessible flag
+     */
+    public void setAccessible(boolean flag) {
+        this.flag = flag;
+    }
+
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        throw new UnsupportedOperationException();
+    }
+
+    public Annotation[] getDeclaredAnnotations() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Annotation[] getAnnotations() {
+        // for all but Class, getAnnotations == getDeclaredAnnotations
+        return getDeclaredAnnotations();
+    }
+
+    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns the signature for a class. This is the kind of signature used
+     * internally by the JVM, with one-character codes representing the basic
+     * types. It is not suitable for printing.
+     *
+     * @param clazz
+     *            the class for which a signature is required
+     *
+     * @return The signature as a string
+     */
+    String getSignature(Class<?> clazz) {
+        String result = "";
+        String nextType = clazz.getName();
+
+        if(trans.containsKey(nextType)) {
+            result = trans.get(nextType);
+        } else {
+            if(clazz.isArray()) {
+                result = "[" + getSignature(clazz.getComponentType());
+            } else {
+                result = "L" + nextType + ";";
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns a printable String consisting of the canonical names of the
+     * classes contained in an array. The form is that used in parameter and
+     * exception lists, that is, the class or type names are separated by
+     * commas.
+     *
+     * @param types
+     *            the array of classes
+     *
+     * @return The String of names
+     */
+    String toString(Class<?>[] types) {
+        StringBuilder result = new StringBuilder();
+
+        if (types.length != 0) {
+            appendTypeName(result, types[0]);
+            for (int i = 1; i < types.length; i++) {
+                result.append(',');
+                appendTypeName(result, types[i]);
+            }
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Gets the Signature attribute for this instance. Returns {@code null}
+     * if not found.
+     */
+    /*package*/ String getSignatureAttribute() {
+        /*
+         * Note: This method would have been declared abstract, but the
+         * standard API lists this class as concrete.
+         */
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Retrieve the signature attribute from an arbitrary class.  This is
+     * the same as Class.getSignatureAttribute(), but it can be used from
+     * the java.lang.reflect package.
+     */
+    /*package*/ static String getClassSignatureAttribute(Class clazz) {
+        Object[] annotation = getClassSignatureAnnotation(clazz);
+
+        if (annotation == null) {
+            return null;
+        }
+
+        return StringUtils.combineStrings(annotation);
+    }
+
+    /**
+     * Retrieve the signature annotation from an arbitrary class.  This is
+     * the same as Class.getSignatureAttribute(), but it can be used from
+     * the java.lang.reflect package.
+     */
+    private static native Object[] getClassSignatureAnnotation(Class clazz);
+
+    /**
+     * Appends the best {@link #toString} name for {@code c} to {@code out}.
+     * This works around the fact that {@link Class#getName} is lousy for
+     * primitive arrays (it writes "[C" instead of "char[]") and {@link
+     * Class#getCanonicalName()} is lousy for nested classes (it uses a "."
+     * separator rather than a "$" separator).
+     */
+    void appendTypeName(StringBuilder out, Class<?> c) {
+        int dimensions = 0;
+        while (c.isArray()) {
+            c = c.getComponentType();
+            dimensions++;
+        }
+        out.append(c.getName());
+        for (int d = 0; d < dimensions; d++) {
+            out.append("[]");
+        }
+    }
+
+    /**
+     * Appends names of the specified array classes to the buffer. The array
+     * elements may represent a simple type, a reference type or an array type.
+     * Output format: java.lang.Object[], java.io.File, void
+     *
+     * @param types array of classes to print the names
+     * @throws NullPointerException if any of the arguments is null
+     */
+    void appendArrayGenericType(StringBuilder sb, Type[] types) {
+        if (types.length > 0) {
+            appendGenericType(sb, types[0]);
+            for (int i = 1; i < types.length; i++) {
+                sb.append(',');
+                appendGenericType(sb, types[i]);
+            }
+        }
+    }
+
+    /**
+     * Appends the generic type representation to the buffer.
+     *
+     * @param sb buffer
+     * @param obj the generic type which representation should be appended to the buffer
+     *
+     * @throws NullPointerException if any of the arguments is null
+     */
+    void appendGenericType(StringBuilder sb, Type obj) {
+        if (obj instanceof TypeVariable) {
+            sb.append(((TypeVariable)obj).getName());
+        } else if (obj instanceof ParameterizedType) {
+            sb.append(obj.toString());
+        } else if (obj instanceof GenericArrayType) { //XXX: is it a working branch?
+            Type simplified = ((GenericArrayType)obj).getGenericComponentType();
+            appendGenericType(sb, simplified);
+            sb.append("[]");
+        } else if (obj instanceof Class) {
+            Class c = ((Class<?>)obj);
+            if (c.isArray()){
+                String as[] = c.getName().split("\\[");
+                int len = as.length-1;
+                if (as[len].length() > 1){
+                    sb.append(as[len].substring(1, as[len].length()-1));
+                } else {
+                    char ch = as[len].charAt(0);
+                    if (ch == 'I')
+                        sb.append("int");
+                    else if (ch == 'B')
+                        sb.append("byte");
+                    else if (ch == 'J')
+                        sb.append("long");
+                    else if (ch == 'F')
+                        sb.append("float");
+                    else if (ch == 'D')
+                        sb.append("double");
+                    else if (ch == 'S')
+                        sb.append("short");
+                    else if (ch == 'C')
+                        sb.append("char");
+                    else if (ch == 'Z')
+                        sb.append("boolean");
+                    else if (ch == 'V') //XXX: is it a working branch?
+                        sb.append("void");
+                }
+                for (int i = 0; i < len; i++){
+                    sb.append("[]");
+                }
+            } else {
+                sb.append(c.getName());
+            }
+        }
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/reflect/Constructor.java b/libdvm/src/main/java/java/lang/reflect/Constructor.java
new file mode 100644
index 0000000..acce44f
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/reflect/Constructor.java
@@ -0,0 +1,466 @@
+/*
+ * 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) 2008 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 java.lang.annotation.Annotation;
+import libcore.util.EmptyArray;
+import org.apache.harmony.kernel.vm.StringUtils;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.ListOfTypes;
+import libcore.reflect.Types;
+
+/**
+ * This class represents a constructor. Information about the constructor can be
+ * accessed, and the constructor can be invoked dynamically.
+ *
+ * @param <T> the class that declares this constructor
+ */
+public final class Constructor<T> extends AccessibleObject implements GenericDeclaration,
+        Member {
+
+    Class<T> declaringClass;
+
+    Class<?>[] parameterTypes;
+
+    Class<?>[] exceptionTypes;
+
+    ListOfTypes genericExceptionTypes;
+    ListOfTypes genericParameterTypes;
+    TypeVariable<Constructor<T>>[] formalTypeParameters;
+    private volatile boolean genericTypesAreInitialized = false;
+
+    private synchronized void initGenericTypes() {
+        if (!genericTypesAreInitialized) {
+            String signatureAttribute = getSignatureAttribute();
+            GenericSignatureParser parser = new GenericSignatureParser(
+                    declaringClass.getClassLoader());
+            parser.parseForConstructor(this, signatureAttribute, exceptionTypes);
+            formalTypeParameters = parser.formalTypeParameters;
+            genericParameterTypes = parser.parameterTypes;
+            genericExceptionTypes = parser.exceptionTypes;
+            genericTypesAreInitialized = true;
+        }
+    }
+
+    int slot;
+
+    private int methodDexIndex;
+
+    /**
+     * Prevent this class from being instantiated.
+     */
+    private Constructor(){
+        //do nothing
+    }
+
+    /**
+     * Creates an instance of the class. Only called from native code, thus
+     * private.
+     *
+     * @param declaringClass
+     *            the class this constructor object belongs to
+     * @param ptypes
+     *            the parameter types of the constructor
+     * @param extypes
+     *            the exception types of the constructor
+     * @param slot
+     *            the slot of the constructor inside the VM class structure
+     */
+    private Constructor(Class<T> declaringClass, Class<?>[] ptypes, Class<?>[] extypes, int slot, int methodDexIndex) {
+        this.declaringClass = declaringClass;
+        this.parameterTypes = ptypes;
+        this.exceptionTypes = extypes;          // may be null
+        this.slot = slot;
+        this.methodDexIndex = methodDexIndex;
+    }
+
+    /** @hide */
+    public int getDexMethodIndex() {
+        return methodDexIndex;
+    }
+
+    @Override /*package*/ String getSignatureAttribute() {
+        Object[] annotation = Method.getSignatureAnnotation(declaringClass, slot);
+
+        if (annotation == null) {
+            return null;
+        }
+
+        return StringUtils.combineStrings(annotation);
+    }
+
+    public TypeVariable<Constructor<T>>[] getTypeParameters() {
+        initGenericTypes();
+        return formalTypeParameters.clone();
+    }
+
+    /**
+     * Returns the string representation of the constructor's declaration,
+     * including the type parameters.
+     *
+     * @return the string representation of the constructor's declaration
+     */
+    public String toGenericString() {
+        StringBuilder sb = new StringBuilder(80);
+        initGenericTypes();
+        // append modifiers if any
+        int modifier = getModifiers();
+        if (modifier != 0) {
+            sb.append(Modifier.toString(modifier & ~Modifier.VARARGS)).append(' ');
+        }
+        // append type parameters
+        if (formalTypeParameters != null && formalTypeParameters.length > 0) {
+            sb.append('<');
+            for (int i = 0; i < formalTypeParameters.length; i++) {
+                appendGenericType(sb, formalTypeParameters[i]);
+                if (i < formalTypeParameters.length - 1) {
+                    sb.append(",");
+                }
+            }
+            sb.append("> ");
+        }
+        // append constructor name
+        appendTypeName(sb, getDeclaringClass());
+        // append parameters
+        sb.append('(');
+        appendArrayGenericType(sb, Types.getTypeArray(genericParameterTypes, false));
+        sb.append(')');
+        // append exceptions if any
+        Type[] genericExceptionTypeArray = Types.getTypeArray(genericExceptionTypes, false);
+        if (genericExceptionTypeArray.length > 0) {
+            sb.append(" throws ");
+            appendArrayGenericType(sb, genericExceptionTypeArray);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the generic parameter types as an array of {@code Type}
+     * instances, in declaration order. If this constructor has no generic
+     * parameters, an empty array is returned.
+     *
+     * @return the parameter types
+     *
+     * @throws GenericSignatureFormatError
+     *             if the generic constructor signature is invalid
+     * @throws TypeNotPresentException
+     *             if any parameter type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if any parameter type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type[] getGenericParameterTypes() {
+        initGenericTypes();
+        return Types.getTypeArray(genericParameterTypes, true);
+    }
+
+    /**
+     * Returns the exception types as an array of {@code Type} instances. If
+     * this constructor has no declared exceptions, an empty array will be
+     * returned.
+     *
+     * @return an array of generic exception types
+     *
+     * @throws GenericSignatureFormatError
+     *             if the generic constructor signature is invalid
+     * @throws TypeNotPresentException
+     *             if any exception type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if any exception type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type[] getGenericExceptionTypes() {
+        initGenericTypes();
+        return Types.getTypeArray(genericExceptionTypes, true);
+    }
+
+    @Override
+    public Annotation[] getDeclaredAnnotations() {
+        return Method.getDeclaredAnnotations(declaringClass, slot);
+    }
+
+    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return Method.getAnnotation(declaringClass, slot, annotationType);
+    }
+
+    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return Method.isAnnotationPresent(declaringClass, slot, annotationType);
+    }
+
+    /**
+     * Returns an array of arrays that represent the annotations of the formal
+     * parameters of this constructor. If there are no parameters on this
+     * constructor, then an empty array is returned. If there are no annotations
+     * set, then an array of empty arrays is returned.
+     *
+     * @return an array of arrays of {@code Annotation} instances
+     */
+    public Annotation[][] getParameterAnnotations() {
+        Annotation[][] parameterAnnotations
+                = Method.getParameterAnnotations(declaringClass, slot);
+        if (parameterAnnotations.length == 0) {
+            return Method.noAnnotations(parameterTypes.length);
+        }
+        return parameterAnnotations;
+    }
+
+    /**
+     * Indicates whether or not this constructor takes a variable number of
+     * arguments.
+     *
+     * @return {@code true} if a vararg is declare, otherwise
+     *         {@code false}
+     */
+    public boolean isVarArgs() {
+        int mods = Method.getMethodModifiers(declaringClass, slot);
+        return (mods & Modifier.VARARGS) != 0;
+    }
+
+    /**
+     * Indicates whether or not this constructor is synthetic (artificially
+     * introduced by the compiler).
+     *
+     * @return {@code true} if this constructor is synthetic, {@code false}
+     *         otherwise
+     */
+    public boolean isSynthetic() {
+        int mods = Method.getMethodModifiers(declaringClass, slot);
+        return (mods & Modifier.SYNTHETIC) != 0;
+    }
+
+    /**
+     * Indicates whether or not the specified {@code object} is equal to this
+     * constructor. To be equal, the specified object must be an instance
+     * of {@code Constructor} with the same declaring class and parameter types
+     * as this constructor.
+     *
+     * @param object
+     *            the object to compare
+     *
+     * @return {@code true} if the specified object is equal to this
+     *         constructor, {@code false} otherwise
+     *
+     * @see #hashCode
+     */
+    @Override
+    public boolean equals(Object object) {
+        return object instanceof Constructor && toString().equals(object.toString());
+    }
+
+    /**
+     * Returns the class that declares this constructor.
+     *
+     * @return the declaring class
+     */
+    public Class<T> getDeclaringClass() {
+        return declaringClass;
+    }
+
+    /**
+     * Returns the exception types as an array of {@code Class} instances. If
+     * this constructor has no declared exceptions, an empty array will be
+     * returned.
+     *
+     * @return the declared exception classes
+     */
+    public Class<?>[] getExceptionTypes() {
+        if (exceptionTypes == null) {
+            return EmptyArray.CLASS;
+        }
+        return exceptionTypes.clone();
+    }
+
+    /**
+     * Returns the modifiers for this constructor. The {@link Modifier} class
+     * should be used to decode the result.
+     *
+     * @return the modifiers for this constructor
+     *
+     * @see Modifier
+     */
+    public int getModifiers() {
+        return Method.getMethodModifiers(declaringClass, slot);
+    }
+
+    /**
+     * Returns the name of this constructor.
+     *
+     * @return the name of this constructor
+     */
+    public String getName() {
+        return declaringClass.getName();
+    }
+
+    /**
+     * Returns an array of the {@code Class} objects associated with the
+     * parameter types of this constructor. If the constructor was declared with
+     * no parameters, an empty array will be returned.
+     *
+     * @return the parameter types
+     */
+    public Class<?>[] getParameterTypes() {
+        return parameterTypes.clone();
+    }
+
+    /**
+     * Returns the constructor's signature in non-printable form. This is called
+     * (only) from IO native code and needed for deriving the serialVersionUID
+     * of the class
+     *
+     * @return the constructor's signature
+     */
+    @SuppressWarnings("unused")
+    private String getSignature() {
+        StringBuilder result = new StringBuilder();
+
+        result.append('(');
+        for (int i = 0; i < parameterTypes.length; i++) {
+            result.append(getSignature(parameterTypes[i]));
+        }
+        result.append(")V");
+
+        return result.toString();
+    }
+
+    /**
+     * Returns an integer hash code for this constructor. Constructors which are
+     * equal return the same value for this method. The hash code for a
+     * Constructor is the hash code of the name of the declaring class.
+     *
+     * @return the hash code
+     *
+     * @see #equals
+     */
+    @Override
+    public int hashCode() {
+        return declaringClass.getName().hashCode();
+    }
+
+    /**
+     * Returns a new instance of the declaring class, initialized by dynamically
+     * invoking the constructor represented by this {@code Constructor} object.
+     * This reproduces the effect of {@code new declaringClass(arg1, arg2, ... ,
+     * argN)} This method performs the following:
+     * <ul>
+     * <li>A new instance of the declaring class is created. If the declaring
+     * class cannot be instantiated (i.e. abstract class, an interface, an array
+     * type, or a primitive type) then an InstantiationException is thrown.</li>
+     * <li>If this Constructor object is enforcing access control (see
+     * {@link AccessibleObject}) and this constructor is not accessible from the
+     * current context, an IllegalAccessException is thrown.</li>
+     * <li>If the number of arguments passed and the number of parameters do not
+     * match, an IllegalArgumentException is thrown.</li>
+     * <li>For each argument passed:
+     * <ul>
+     * <li>If the corresponding parameter type is a primitive type, the argument
+     * is unboxed. If the unboxing fails, an IllegalArgumentException is
+     * thrown.</li>
+     * <li>If the resulting argument cannot be converted to the parameter type
+     * via a widening conversion, an IllegalArgumentException is thrown.</li>
+     * </ul>
+     * <li>The constructor represented by this {@code Constructor} object is
+     * then invoked. If an exception is thrown during the invocation, it is
+     * caught and wrapped in an InvocationTargetException. This exception is
+     * then thrown. If the invocation completes normally, the newly initialized
+     * object is returned.
+     * </ul>
+     *
+     * @param args
+     *            the arguments to the constructor
+     *
+     * @return the new, initialized, object
+     *
+     * @throws InstantiationException
+     *                if the class cannot be instantiated
+     * @throws IllegalAccessException
+     *                if this constructor is not accessible
+     * @throws IllegalArgumentException
+     *                if an incorrect number of arguments are passed, or an
+     *                argument could not be converted by a widening conversion
+     * @throws InvocationTargetException
+     *                if an exception was thrown by the invoked constructor
+     *
+     * @see AccessibleObject
+     */
+    public T newInstance(Object... args) throws InstantiationException, IllegalAccessException,
+            IllegalArgumentException, InvocationTargetException {
+        return constructNative (args, declaringClass, parameterTypes, slot, flag);
+    }
+
+    private native T constructNative(Object[] args, Class<T> declaringClass,
+            Class<?>[] parameterTypes, int slot,
+            boolean noAccessCheck) throws InstantiationException, IllegalAccessException,
+            InvocationTargetException;
+
+    /**
+     * Returns a string containing a concise, human-readable description of this
+     * constructor. The format of the string is:
+     *
+     * <ol>
+     *   <li>modifiers (if any)
+     *   <li>declaring class name
+     *   <li>'('
+     *   <li>parameter types, separated by ',' (if any)
+     *   <li>')'
+     *   <li>'throws' plus exception types, separated by ',' (if any)
+     * </ol>
+     *
+     * For example:
+     * {@code public String(byte[],String) throws UnsupportedEncodingException}
+     *
+     * @return a printable representation for this constructor
+     */
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
+
+        if (result.length() != 0)
+            result.append(' ');
+        result.append(declaringClass.getName());
+        result.append("(");
+        result.append(toString(parameterTypes));
+        result.append(")");
+        if (exceptionTypes != null && exceptionTypes.length != 0) {
+            result.append(" throws ");
+            result.append(toString(exceptionTypes));
+        }
+
+        return result.toString();
+    }
+}
diff --git a/libdvm/src/main/java/java/lang/reflect/Field.java b/libdvm/src/main/java/java/lang/reflect/Field.java
new file mode 100644
index 0000000..fa8e5e7
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/reflect/Field.java
@@ -0,0 +1,931 @@
+/*
+ * 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) 2008 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 java.lang.annotation.Annotation;
+import java.util.Comparator;
+import org.apache.harmony.kernel.vm.StringUtils;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.Types;
+
+/**
+ * This class represents a field. Information about the field can be accessed,
+ * and the field's value can be accessed dynamically.
+ */
+public final class Field extends AccessibleObject implements Member {
+
+    /**
+     * Orders fields by their name and declaring class.
+     *
+     * @hide
+     */
+    public static final Comparator<Field> ORDER_BY_NAME_AND_DECLARING_CLASS
+            = new Comparator<Field>() {
+        @Override public int compare(Field a, Field b) {
+            int comparison = a.name.compareTo(b.name);
+            if (comparison != 0) {
+                return comparison;
+            }
+
+            return a.getDeclaringClass().getName().compareTo(b.getDeclaringClass().getName());
+        }
+    };
+
+    private Class<?> declaringClass;
+
+    private Class<?> type;
+
+    private Type genericType;
+
+    private volatile boolean genericTypesAreInitialized = false;
+
+    private String name;
+
+    private int slot;
+
+    private final int fieldDexIndex;
+
+    private static final char TYPE_BOOLEAN = 'Z';
+
+    private static final char TYPE_BYTE = 'B';
+
+    private static final char TYPE_CHAR = 'C';
+
+    private static final char TYPE_SHORT = 'S';
+
+    private static final char TYPE_INTEGER = 'I';
+
+    private static final char TYPE_FLOAT = 'F';
+
+    private static final char TYPE_LONG = 'J';
+
+    private static final char TYPE_DOUBLE = 'D';
+
+    private Field(Class<?> declaringClass, Class<?> type, String name, int slot, int fieldDexIndex) {
+        this.declaringClass = declaringClass;
+        this.type = type;
+        this.name = name;
+        this.slot = slot;
+        this.fieldDexIndex = fieldDexIndex;
+    }
+
+    /**
+     * Returns the index of this field's ID in its dex file.
+     * @hide
+     */
+    public int getDexFieldIndex() {
+        return fieldDexIndex;
+    }
+
+    private synchronized void initGenericType() {
+        if (!genericTypesAreInitialized) {
+            String signatureAttribute = getSignatureAttribute();
+            GenericSignatureParser parser = new GenericSignatureParser(
+                    declaringClass.getClassLoader());
+            parser.parseForField(this.declaringClass, signatureAttribute);
+            genericType = parser.fieldType;
+            if (genericType == null) {
+                genericType = getType();
+            }
+            genericTypesAreInitialized = true;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    /* package */String getSignatureAttribute() {
+        Object[] annotation = getSignatureAnnotation(declaringClass, slot);
+
+        if (annotation == null) {
+            return null;
+        }
+
+        return StringUtils.combineStrings(annotation);
+    }
+
+    /**
+     * Get the Signature annotation for this field. Returns null if not found.
+     */
+    native private Object[] getSignatureAnnotation(Class declaringClass, int slot);
+
+    /**
+     * Indicates whether or not this field is synthetic.
+     *
+     * @return {@code true} if this field is synthetic, {@code false} otherwise
+     */
+    public boolean isSynthetic() {
+        int flags = getFieldModifiers(declaringClass, slot);
+        return (flags & Modifier.SYNTHETIC) != 0;
+    }
+
+    /**
+     * Returns the string representation of this field, including the field's
+     * generic type.
+     *
+     * @return the string representation of this field
+     */
+    public String toGenericString() {
+        StringBuilder sb = new StringBuilder(80);
+        // append modifiers if any
+        int modifier = getModifiers();
+        if (modifier != 0) {
+            sb.append(Modifier.toString(modifier)).append(' ');
+        }
+        // append generic type
+        appendGenericType(sb, getGenericType());
+        sb.append(' ');
+        // append full field name
+        sb.append(getDeclaringClass().getName()).append('.').append(getName());
+        return sb.toString();
+    }
+
+    /**
+     * Indicates whether or not this field is an enumeration constant.
+     *
+     * @return {@code true} if this field is an enumeration constant, {@code
+     *         false} otherwise
+     */
+    public boolean isEnumConstant() {
+        int flags = getFieldModifiers(declaringClass, slot);
+        return (flags & Modifier.ENUM) != 0;
+    }
+
+    /**
+     * Returns the generic type of this field.
+     *
+     * @return the generic type
+     * @throws GenericSignatureFormatError
+     *             if the generic field signature is invalid
+     * @throws TypeNotPresentException
+     *             if the generic type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if the generic type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type getGenericType() {
+        initGenericType();
+        return Types.getType(genericType);
+    }
+
+    @Override public Annotation[] getDeclaredAnnotations() {
+        return getDeclaredAnnotations(declaringClass, slot);
+    }
+    private static native Annotation[] getDeclaredAnnotations(Class declaringClass, int slot);
+
+    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return getAnnotation(declaringClass, slot, annotationType);
+    }
+    private static native <A extends Annotation> A getAnnotation(
+            Class<?> declaringClass, int slot, Class<A> annotationType);
+
+    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return isAnnotationPresent(declaringClass, slot, annotationType);
+    }
+    private static native boolean isAnnotationPresent(
+            Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType);
+
+    /**
+     * Indicates whether or not the specified {@code object} is equal to this
+     * field. To be equal, the specified object must be an instance of
+     * {@code Field} with the same declaring class, type and name as this field.
+     *
+     * @param object
+     *            the object to compare
+     * @return {@code true} if the specified object is equal to this method,
+     *         {@code false} otherwise
+     * @see #hashCode
+     */
+    @Override
+    public boolean equals(Object object) {
+        return object instanceof Field && toString().equals(object.toString());
+    }
+
+    /**
+     * Returns the value of the field in the specified object. This reproduces
+     * the effect of {@code object.fieldName}
+     *
+     * <p>If the type of this field is a primitive type, the field value is
+     * automatically boxed.
+     *
+     * <p>If this field is static, the object argument is ignored.
+     * Otherwise, if the object is null, a NullPointerException is thrown. If
+     * the object is not an instance of the declaring class of the method, an
+     * IllegalArgumentException is thrown.
+     *
+     * <p>If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value, possibly boxed
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public Object get(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getField(object, declaringClass, type, slot, flag);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code
+     * boolean}. This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public boolean getBoolean(Object object) throws IllegalAccessException,
+            IllegalArgumentException {
+        return getZField(object, declaringClass, type, slot, flag, TYPE_BOOLEAN);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code byte}.
+     * This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public byte getByte(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getBField(object, declaringClass, type, slot, flag, TYPE_BYTE);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code char}.
+     * This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public char getChar(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getCField(object, declaringClass, type, slot, flag, TYPE_CHAR);
+    }
+
+    /**
+     * Returns the class that declares this field.
+     *
+     * @return the declaring class
+     */
+    public Class<?> getDeclaringClass() {
+        return declaringClass;
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code
+     * double}. This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public double getDouble(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getDField(object, declaringClass, type, slot, flag, TYPE_DOUBLE);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code float}
+     * . This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public float getFloat(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getFField(object, declaringClass, type, slot, flag, TYPE_FLOAT);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as an {@code int}.
+     * This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public int getInt(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getIField(object, declaringClass, type, slot, flag, TYPE_INTEGER);
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code long}.
+     * This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public long getLong(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getJField(object, declaringClass, type, slot, flag, TYPE_LONG);
+    }
+
+    /**
+     * Returns the modifiers for this field. The {@link Modifier} class should
+     * be used to decode the result.
+     *
+     * @return the modifiers for this field
+     * @see Modifier
+     */
+    public int getModifiers() {
+        return getFieldModifiers(declaringClass, slot);
+    }
+
+    private native int getFieldModifiers(Class<?> declaringClass, int slot);
+
+    /**
+     * Returns the name of this field.
+     *
+     * @return the name of this field
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the value of the field in the specified object as a {@code short}
+     * . This reproduces the effect of {@code object.fieldName}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @return the field value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public short getShort(Object object) throws IllegalAccessException, IllegalArgumentException {
+        return getSField(object, declaringClass, type, slot, flag, TYPE_SHORT);
+    }
+
+    /**
+     * Returns the constructor's signature in non-printable form. This is called
+     * (only) from IO native code and needed for deriving the serialVersionUID
+     * of the class
+     *
+     * @return the constructor's signature.
+     */
+    @SuppressWarnings("unused")
+    private String getSignature() {
+        return getSignature(type);
+    }
+
+    /**
+     * Return the {@link Class} associated with the type of this field.
+     *
+     * @return the type of this field
+     */
+    public Class<?> getType() {
+        return type;
+    }
+
+    /**
+     * Returns an integer hash code for this field. Objects which are equal
+     * return the same value for this method.
+     * <p>
+     * The hash code for a Field is the exclusive-or combination of the hash
+     * code of the field's name and the hash code of the name of its declaring
+     * class.
+     *
+     * @return the hash code for this field
+     * @see #equals
+     */
+    @Override
+    public int hashCode() {
+        return name.hashCode() ^ getDeclaringClass().getName().hashCode();
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the value. This
+     * reproduces the effect of {@code object.fieldName = value}
+     *
+     * <p>If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     *
+     * <p>If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     *
+     * <p>If the field type is a primitive type, the value is automatically
+     * unboxed. If the unboxing fails, an IllegalArgumentException is thrown. If
+     * the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void set(Object object, Object value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setField(object, declaringClass, type, slot, flag, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code
+     * boolean} value. This reproduces the effect of {@code object.fieldName =
+     * value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setBoolean(Object object, boolean value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setZField(object, declaringClass, type, slot, flag, TYPE_BOOLEAN, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code byte}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setByte(Object object, byte value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setBField(object, declaringClass, type, slot, flag, TYPE_BYTE, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code char}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setChar(Object object, char value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setCField(object, declaringClass, type, slot, flag, TYPE_CHAR, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code double}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setDouble(Object object, double value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setDField(object, declaringClass, type, slot, flag, TYPE_DOUBLE, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code float}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setFloat(Object object, float value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setFField(object, declaringClass, type, slot, flag, TYPE_FLOAT, value);
+    }
+
+    /**
+     * Set the value of the field in the specified object to the {@code int}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setInt(Object object, int value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setIField(object, declaringClass, type, slot, flag, TYPE_INTEGER, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code long}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setLong(Object object, long value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setJField(object, declaringClass, type, slot, flag, TYPE_LONG, value);
+    }
+
+    /**
+     * Sets the value of the field in the specified object to the {@code short}
+     * value. This reproduces the effect of {@code object.fieldName = value}
+     * <p>
+     * If this field is static, the object argument is ignored.
+     * Otherwise, if the object is {@code null}, a NullPointerException is
+     * thrown. If the object is not an instance of the declaring class of the
+     * method, an IllegalArgumentException is thrown.
+     * <p>
+     * If this Field object is enforcing access control (see AccessibleObject)
+     * and this field is not accessible from the current context, an
+     * IllegalAccessException is thrown.
+     * <p>
+     * If the value cannot be converted to the field type via a widening
+     * conversion, an IllegalArgumentException is thrown.
+     *
+     * @param object
+     *            the object to access
+     * @param value
+     *            the new value
+     * @throws NullPointerException
+     *             if the object is {@code null} and the field is non-static
+     * @throws IllegalArgumentException
+     *             if the object is not compatible with the declaring class
+     * @throws IllegalAccessException
+     *             if this field is not accessible
+     */
+    public void setShort(Object object, short value) throws IllegalAccessException,
+            IllegalArgumentException {
+        setSField(object, declaringClass, type, slot, flag, TYPE_SHORT, value);
+    }
+
+    /**
+     * Returns a string containing a concise, human-readable description of this
+     * field.
+     * <p>
+     * The format of the string is:
+     * <ol>
+     *   <li>modifiers (if any)
+     *   <li>type
+     *   <li>declaring class name
+     *   <li>'.'
+     *   <li>field name
+     * </ol>
+     * <p>
+     * For example: {@code public static java.io.InputStream
+     * java.lang.System.in}
+     *
+     * @return a printable representation for this field
+     */
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
+        if (result.length() != 0) {
+            result.append(' ');
+        }
+        appendTypeName(result, type);
+        result.append(' ');
+        appendTypeName(result, declaringClass);
+        result.append('.');
+        result.append(name);
+        return result.toString();
+    }
+
+    private native Object getField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck) throws IllegalAccessException;
+
+    private native double getDField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native int getIField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native long getJField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native boolean getZField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native float getFField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native char getCField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native short getSField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native byte getBField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor) throws IllegalAccessException;
+
+    private native void setField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, Object value) throws IllegalAccessException;
+
+    private native void setDField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, double v) throws IllegalAccessException;
+
+    private native void setIField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, int i) throws IllegalAccessException;
+
+    private native void setJField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, long j) throws IllegalAccessException;
+
+    private native void setZField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, boolean z) throws IllegalAccessException;
+
+    private native void setFField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, float f) throws IllegalAccessException;
+
+    private native void setCField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, char c) throws IllegalAccessException;
+
+    private native void setSField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, short s) throws IllegalAccessException;
+
+    private native void setBField(Object o, Class<?> declaringClass, Class<?> type, int slot,
+            boolean noAccessCheck, char descriptor, byte b) throws IllegalAccessException;
+
+}
diff --git a/libdvm/src/main/java/java/lang/reflect/Method.java b/libdvm/src/main/java/java/lang/reflect/Method.java
new file mode 100644
index 0000000..f8efbf4
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/reflect/Method.java
@@ -0,0 +1,587 @@
+/*
+ * 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) 2008 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 java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Comparator;
+import libcore.util.EmptyArray;
+import org.apache.harmony.kernel.vm.StringUtils;
+import libcore.reflect.GenericSignatureParser;
+import libcore.reflect.ListOfTypes;
+import libcore.reflect.Types;
+
+/**
+ * This class represents a method. Information about the method can be accessed,
+ * and the method can be invoked dynamically.
+ */
+public final class Method extends AccessibleObject implements GenericDeclaration, Member {
+
+    /**
+     * Orders methods by their name, parameters and return type.
+     *
+     * @hide
+     */
+    public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
+        public int compare(Method a, Method b) {
+            int comparison = a.name.compareTo(b.name);
+            if (comparison != 0) {
+                return comparison;
+            }
+
+            Class<?>[] aParameters = a.parameterTypes;
+            Class<?>[] bParameters = b.parameterTypes;
+            int length = Math.min(aParameters.length, bParameters.length);
+            for (int i = 0; i < length; i++) {
+                comparison = aParameters[i].getName().compareTo(bParameters[i].getName());
+                if (comparison != 0) {
+                    return comparison;
+                }
+            }
+
+            if (aParameters.length != bParameters.length) {
+                return aParameters.length - bParameters.length;
+            }
+
+            // this is necessary for methods that have covariant return types.
+            return a.getReturnType().getName().compareTo(b.getReturnType().getName());
+        }
+    };
+
+    private int slot;
+
+    private final int methodDexIndex;
+
+    private Class<?> declaringClass;
+
+    private String name;
+
+    private Class<?>[] parameterTypes;
+
+    private Class<?>[] exceptionTypes;
+
+    private Class<?> returnType;
+
+    private ListOfTypes genericExceptionTypes;
+    private ListOfTypes genericParameterTypes;
+    private Type genericReturnType;
+    private TypeVariable<Method>[] formalTypeParameters;
+    private volatile boolean genericTypesAreInitialized = false;
+
+    private synchronized void initGenericTypes() {
+        if (!genericTypesAreInitialized) {
+            String signatureAttribute = getSignatureAttribute();
+            GenericSignatureParser parser = new GenericSignatureParser(
+                    declaringClass.getClassLoader());
+            parser.parseForMethod(this, signatureAttribute, exceptionTypes);
+            formalTypeParameters = parser.formalTypeParameters;
+            genericParameterTypes = parser.parameterTypes;
+            genericExceptionTypes = parser.exceptionTypes;
+            genericReturnType = parser.returnType;
+            genericTypesAreInitialized = true;
+        }
+    }
+
+    private Method(Class<?> declaring, Class<?>[] paramTypes, Class<?>[] exceptTypes, Class<?> returnType, String name, int slot, int methodDexIndex) {
+        this.declaringClass = declaring;
+        this.name = name;
+        this.slot = slot;
+        this.parameterTypes = paramTypes;
+        this.exceptionTypes = exceptTypes;      // may be null
+        this.returnType = returnType;
+        this.methodDexIndex = methodDexIndex;
+    }
+
+    /** @hide */
+    public int getDexMethodIndex() {
+        return methodDexIndex;
+    }
+
+    public TypeVariable<Method>[] getTypeParameters() {
+        initGenericTypes();
+        return formalTypeParameters.clone();
+    }
+
+    /** {@inheritDoc} */
+    @Override /*package*/ String getSignatureAttribute() {
+        Object[] annotation = getSignatureAnnotation(declaringClass, slot);
+
+        if (annotation == null) {
+            return null;
+        }
+
+        return StringUtils.combineStrings(annotation);
+    }
+
+    /**
+     * Returns the Signature annotation for this method. Returns {@code null} if
+     * not found.
+     */
+    static native Object[] getSignatureAnnotation(Class declaringClass, int slot);
+
+    /**
+     * Returns the string representation of the method's declaration, including
+     * the type parameters.
+     *
+     * @return the string representation of this method
+     */
+    public String toGenericString() {
+        StringBuilder sb = new StringBuilder(80);
+
+        initGenericTypes();
+
+        // append modifiers if any
+        int modifier = getModifiers();
+        if (modifier != 0) {
+            sb.append(Modifier.toString(modifier & ~(Modifier.BRIDGE +
+                    Modifier.VARARGS))).append(' ');
+        }
+        // append type parameters
+        if (formalTypeParameters != null && formalTypeParameters.length > 0) {
+            sb.append('<');
+            for (int i = 0; i < formalTypeParameters.length; i++) {
+                appendGenericType(sb, formalTypeParameters[i]);
+                if (i < formalTypeParameters.length - 1) {
+                    sb.append(",");
+                }
+            }
+            sb.append("> ");
+        }
+        // append return type
+        appendGenericType(sb, Types.getType(genericReturnType));
+        sb.append(' ');
+        // append method name
+        appendTypeName(sb, getDeclaringClass());
+        sb.append(".").append(getName());
+        // append parameters
+        sb.append('(');
+        appendArrayGenericType(sb, Types.getTypeArray(genericParameterTypes, false));
+        sb.append(')');
+        // append exceptions if any
+        Type[] genericExceptionTypeArray = Types.getTypeArray(genericExceptionTypes, false);
+        if (genericExceptionTypeArray.length > 0) {
+            sb.append(" throws ");
+            appendArrayGenericType(sb, genericExceptionTypeArray);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns the parameter types as an array of {@code Type} instances, in
+     * declaration order. If this method has no parameters, an empty array is
+     * returned.
+     *
+     * @return the parameter types
+     *
+     * @throws GenericSignatureFormatError
+     *             if the generic method signature is invalid
+     * @throws TypeNotPresentException
+     *             if any parameter type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if any parameter type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type[] getGenericParameterTypes() {
+        initGenericTypes();
+        return Types.getTypeArray(genericParameterTypes, true);
+    }
+
+    /**
+     * Returns the exception types as an array of {@code Type} instances. If
+     * this method has no declared exceptions, an empty array will be returned.
+     *
+     * @return an array of generic exception types
+     *
+     * @throws GenericSignatureFormatError
+     *             if the generic method signature is invalid
+     * @throws TypeNotPresentException
+     *             if any exception type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if any exception type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type[] getGenericExceptionTypes() {
+        initGenericTypes();
+        return Types.getTypeArray(genericExceptionTypes, true);
+    }
+
+    /**
+     * Returns the return type of this method as a {@code Type} instance.
+     *
+     * @return the return type of this method
+     *
+     * @throws GenericSignatureFormatError
+     *             if the generic method signature is invalid
+     * @throws TypeNotPresentException
+     *             if the return type points to a missing type
+     * @throws MalformedParameterizedTypeException
+     *             if the return type points to a type that cannot be
+     *             instantiated for some reason
+     */
+    public Type getGenericReturnType() {
+        initGenericTypes();
+        return Types.getType(genericReturnType);
+    }
+
+    @Override
+    public Annotation[] getDeclaredAnnotations() {
+        return getDeclaredAnnotations(declaringClass, slot);
+    }
+    static native Annotation[] getDeclaredAnnotations(Class<?> declaringClass, int slot);
+
+    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return getAnnotation(declaringClass, slot, annotationType);
+    }
+    static native <A extends Annotation> A getAnnotation(
+            Class<?> declaringClass, int slot, Class<A> annotationType);
+
+    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
+        if (annotationType == null) {
+            throw new NullPointerException("annotationType == null");
+        }
+        return isAnnotationPresent(declaringClass, slot, annotationType);
+    }
+    static native boolean isAnnotationPresent(
+            Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType);
+
+    private static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
+
+    /**
+     * Creates an array of empty Annotation arrays.
+     */
+    /*package*/ static Annotation[][] noAnnotations(int size) {
+        Annotation[][] annotations = new Annotation[size][];
+        for (int i = 0; i < size; i++) {
+            annotations[i] = NO_ANNOTATIONS;
+        }
+        return annotations;
+    }
+
+    /**
+     * Returns an array of arrays that represent the annotations of the formal
+     * parameters of this method. If there are no parameters on this method,
+     * then an empty array is returned. If there are no annotations set, then
+     * and array of empty arrays is returned.
+     *
+     * @return an array of arrays of {@code Annotation} instances
+     */
+    public Annotation[][] getParameterAnnotations() {
+        Annotation[][] parameterAnnotations
+                = getParameterAnnotations(declaringClass, slot);
+        if (parameterAnnotations.length == 0) {
+            return noAnnotations(parameterTypes.length);
+        }
+        return parameterAnnotations;
+    }
+
+    static native Annotation[][] getParameterAnnotations(Class declaringClass, int slot);
+
+    /**
+     * Indicates whether or not this method takes a variable number argument.
+     *
+     * @return {@code true} if a vararg is declared, {@code false} otherwise
+     */
+    public boolean isVarArgs() {
+        int modifiers = getMethodModifiers(declaringClass, slot);
+        return (modifiers & Modifier.VARARGS) != 0;
+    }
+
+    /**
+     * Indicates whether or not this method is a bridge.
+     *
+     * @return {@code true} if this method is a bridge, {@code false} otherwise
+     */
+    public boolean isBridge() {
+        int modifiers = getMethodModifiers(declaringClass, slot);
+        return (modifiers & Modifier.BRIDGE) != 0;
+    }
+
+    /**
+     * Indicates whether or not this method is synthetic.
+     *
+     * @return {@code true} if this method is synthetic, {@code false} otherwise
+     */
+    public boolean isSynthetic() {
+        int modifiers = getMethodModifiers(declaringClass, slot);
+        return (modifiers & Modifier.SYNTHETIC) != 0;
+    }
+
+    /**
+     * Returns the default value for the annotation member represented by this
+     * method.
+     *
+     * @return the default value, or {@code null} if none
+     *
+     * @throws TypeNotPresentException
+     *             if this annotation member is of type {@code Class} and no
+     *             definition can be found
+     */
+    public Object getDefaultValue() {
+        return getDefaultValue(declaringClass, slot);
+    }
+    native private Object getDefaultValue(Class declaringClass, int slot);
+
+    /**
+     * Indicates whether or not the specified {@code object} is equal to this
+     * method. To be equal, the specified object must be an instance
+     * of {@code Method} with the same declaring class and parameter types
+     * as this method.
+     *
+     * @param object
+     *            the object to compare
+     *
+     * @return {@code true} if the specified object is equal to this
+     *         method, {@code false} otherwise
+     *
+     * @see #hashCode
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (!(object instanceof Method)) {
+            return false;
+        }
+        Method rhs = (Method) object;
+        // We don't compare exceptionTypes because two methods
+        // can't differ only by their declared exceptions.
+        return declaringClass.equals(rhs.declaringClass) &&
+            name.equals(rhs.name) &&
+            getModifiers() == rhs.getModifiers() &&
+            returnType.equals(rhs.returnType) &&
+            Arrays.equals(parameterTypes, rhs.parameterTypes);
+    }
+
+    /**
+     * Returns the class that declares this method.
+     *
+     * @return the declaring class
+     */
+    public Class<?> getDeclaringClass() {
+        return declaringClass;
+    }
+
+    /**
+     * Returns the exception types as an array of {@code Class} instances. If
+     * this method has no declared exceptions, an empty array is returned.
+     *
+     * @return the declared exception classes
+     */
+    public Class<?>[] getExceptionTypes() {
+        if (exceptionTypes == null) {
+            return EmptyArray.CLASS;
+        }
+        return exceptionTypes.clone();
+    }
+
+    /**
+     * Returns the modifiers for this method. The {@link Modifier} class should
+     * be used to decode the result.
+     *
+     * @return the modifiers for this method
+     *
+     * @see Modifier
+     */
+    public int getModifiers() {
+        return getMethodModifiers(declaringClass, slot);
+    }
+
+    static native int getMethodModifiers(Class<?> declaringClass, int slot);
+
+    /**
+     * Returns the name of the method represented by this {@code Method}
+     * instance.
+     *
+     * @return the name of this method
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns an array of {@code Class} objects associated with the parameter
+     * types of this method. If the method was declared with no parameters, an
+     * empty array will be returned.
+     *
+     * @return the parameter types
+     */
+    public Class<?>[] getParameterTypes() {
+        return parameterTypes.clone();
+    }
+
+    /**
+     * Returns the {@code Class} associated with the return type of this
+     * method.
+     *
+     * @return the return type
+     */
+    public Class<?> getReturnType() {
+        return returnType;
+    }
+
+    /**
+     * Returns an integer hash code for this method. Objects which are equal
+     * return the same value for this method. The hash code for this Method is
+     * the hash code of the name of this method.
+     *
+     * @return hash code for this method
+     *
+     * @see #equals
+     */
+    @Override
+    public int hashCode() {
+        return name.hashCode();
+    }
+
+    /**
+     * Returns the result of dynamically invoking this method. Equivalent to
+     * {@code receiver.methodName(arg1, arg2, ... , argN)}.
+     *
+     * <p>If the method is static, the receiver argument is ignored (and may be null).
+     *
+     * <p>If the method takes no arguments, you can pass {@code (Object[]) null} instead of
+     * allocating an empty array.
+     *
+     * <p>If you're calling a varargs method, you need to pass an {@code Object[]} for the
+     * varargs parameter: that conversion is usually done in {@code javac}, not the VM, and
+     * the reflection machinery does not do this for you. (It couldn't, because it would be
+     * ambiguous.)
+     *
+     * <p>Reflective method invocation follows the usual process for method lookup.
+     *
+     * <p>If an exception is thrown during the invocation it is caught and
+     * wrapped in an InvocationTargetException. This exception is then thrown.
+     *
+     * <p>If the invocation completes normally, the return value itself is
+     * returned. If the method is declared to return a primitive type, the
+     * return value is boxed. If the return type is void, null is returned.
+     *
+     * @param receiver
+     *            the object on which to call this method (or null for static methods)
+     * @param args
+     *            the arguments to the method
+     * @return the result
+     *
+     * @throws NullPointerException
+     *             if {@code receiver == null} for a non-static method
+     * @throws IllegalAccessException
+     *             if this method is not accessible (see {@link AccessibleObject})
+     * @throws IllegalArgumentException
+     *             if the number of arguments doesn't match the number of parameters, the receiver
+     *             is incompatible with the declaring class, or an argument could not be unboxed
+     *             or converted by a widening conversion to the corresponding parameter type
+     * @throws InvocationTargetException
+     *             if an exception was thrown by the invoked method
+     */
+    public Object invoke(Object receiver, Object... args)
+            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        if (args == null) {
+            args = EmptyArray.OBJECT;
+        }
+        return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
+    }
+
+    private native Object invokeNative(Object obj, Object[] args, Class<?> declaringClass,
+            Class<?>[] parameterTypes, Class<?> returnType, int slot, boolean noAccessCheck)
+                    throws IllegalAccessException, IllegalArgumentException,
+                            InvocationTargetException;
+
+    /**
+     * Returns a string containing a concise, human-readable description of this
+     * method. The format of the string is:
+     *
+     * <ol>
+     *   <li>modifiers (if any)
+     *   <li>return type or 'void'
+     *   <li>declaring class name
+     *   <li>'('
+     *   <li>parameter types, separated by ',' (if any)
+     *   <li>')'
+     *   <li>'throws' plus exception types, separated by ',' (if any)
+     * </ol>
+     *
+     * For example: {@code public native Object
+     * java.lang.Method.invoke(Object,Object) throws
+     * IllegalAccessException,IllegalArgumentException
+     * ,InvocationTargetException}
+     *
+     * @return a printable representation for this method
+     */
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
+
+        if (result.length() != 0)
+            result.append(' ');
+        result.append(returnType.getName());
+        result.append(' ');
+        result.append(declaringClass.getName());
+        result.append('.');
+        result.append(name);
+        result.append("(");
+        result.append(toString(parameterTypes));
+        result.append(")");
+        if (exceptionTypes != null && exceptionTypes.length != 0) {
+            result.append(" throws ");
+            result.append(toString(exceptionTypes));
+        }
+
+        return result.toString();
+    }
+
+    /**
+     * Returns the constructor's signature in non-printable form. This is called
+     * (only) from IO native code and needed for deriving the serialVersionUID
+     * of the class
+     *
+     * @return The constructor's signature.
+     */
+    @SuppressWarnings("unused")
+    private String getSignature() {
+        StringBuilder result = new StringBuilder();
+
+        result.append('(');
+        for (int i = 0; i < parameterTypes.length; i++) {
+            result.append(getSignature(parameterTypes[i]));
+        }
+        result.append(')');
+        result.append(getSignature(returnType));
+
+        return result.toString();
+    }
+
+}
diff --git a/libdvm/src/main/java/java/lang/reflect/Proxy.java b/libdvm/src/main/java/java/lang/reflect/Proxy.java
new file mode 100644
index 0000000..3b10887
--- /dev/null
+++ b/libdvm/src/main/java/java/lang/reflect/Proxy.java
@@ -0,0 +1,278 @@
+/*
+ *  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 java.lang.reflect;
+
+import java.io.Serializable;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * {@code Proxy} defines methods for creating dynamic proxy classes and instances.
+ * A proxy class implements a declared set of interfaces and delegates method
+ * invocations to an {@code InvocationHandler}.
+ *
+ * @see InvocationHandler
+ * @since 1.3
+ */
+public class Proxy implements Serializable {
+
+    private static final long serialVersionUID = -2222568056686623797L;
+
+    // maps class loaders to created classes by interface names
+    private static final Map<ClassLoader, Map<String, WeakReference<Class<?>>>> loaderCache = new WeakHashMap<ClassLoader, Map<String, WeakReference<Class<?>>>>();
+
+    // to find previously created types
+    private static final Map<Class<?>, String> proxyCache = new WeakHashMap<Class<?>, String>();
+
+    private static int NextClassNameIndex = 0;
+
+    /**
+     * The invocation handler on which the method calls are dispatched.
+     */
+    protected InvocationHandler h;
+
+    @SuppressWarnings("unused")
+    private Proxy() {
+    }
+
+    /**
+     * Constructs a new {@code Proxy} instance with the specified invocation
+     * handler.
+     *
+     * @param h
+     *            the invocation handler for the newly created proxy
+     */
+    protected Proxy(InvocationHandler h) {
+        this.h = h;
+    }
+
+    /**
+     * Returns the dynamically built {@code Class} for the specified interfaces.
+     * Creates a new {@code Class} when necessary. The order of the interfaces
+     * is relevant. Invocations of this method with the same interfaces but
+     * different order result in different generated classes. The interfaces
+     * must be visible from the supplied class loader; no duplicates are
+     * permitted. All non-public interfaces must be defined in the same package.
+     *
+     * @param loader
+     *            the class loader that will define the proxy class
+     * @param interfaces
+     *            an array of {@code Class} objects, each one identifying an
+     *            interface that will be implemented by the returned proxy
+     *            class
+     * @return a proxy class that implements all of the interfaces referred to
+     *         in the contents of {@code interfaces}
+     * @throws IllegalArgumentException
+     *                if any of the interface restrictions are violated
+     * @throws NullPointerException
+     *                if either {@code interfaces} or any of its elements are
+     *                {@code null}
+     */
+    public static Class<?> getProxyClass(ClassLoader loader,
+            Class<?>... interfaces) throws IllegalArgumentException {
+        // check that interfaces are a valid array of visible interfaces
+        if (interfaces == null) {
+            throw new NullPointerException("interfaces == null");
+        }
+        String commonPackageName = null;
+        for (int i = 0, length = interfaces.length; i < length; i++) {
+            Class<?> next = interfaces[i];
+            if (next == null) {
+                throw new NullPointerException("interfaces[" + i + "] == null");
+            }
+            String name = next.getName();
+            if (!next.isInterface()) {
+                throw new IllegalArgumentException(name + " is not an interface");
+            }
+            if (loader != next.getClassLoader()) {
+                try {
+                    if (next != Class.forName(name, false, loader)) {
+                        throw new IllegalArgumentException(name +
+                                " is not visible from class loader");
+                    }
+                } catch (ClassNotFoundException ex) {
+                    throw new IllegalArgumentException(name + " is not visible from class loader");
+                }
+            }
+            for (int j = i + 1; j < length; j++) {
+                if (next == interfaces[j]) {
+                    throw new IllegalArgumentException(name + " appears more than once");
+                }
+            }
+            if (!Modifier.isPublic(next.getModifiers())) {
+                int last = name.lastIndexOf('.');
+                String p = last == -1 ? "" : name.substring(0, last);
+                if (commonPackageName == null) {
+                    commonPackageName = p;
+                } else if (!commonPackageName.equals(p)) {
+                    throw new IllegalArgumentException("non-public interfaces must be " +
+                            "in the same package");
+                }
+            }
+        }
+
+        // search cache for matching proxy class using the class loader
+        synchronized (loaderCache) {
+            Map<String, WeakReference<Class<?>>> interfaceCache = loaderCache
+                    .get(loader);
+            if (interfaceCache == null) {
+                loaderCache
+                        .put(
+                                loader,
+                                (interfaceCache = new HashMap<String, WeakReference<Class<?>>>()));
+            }
+
+            String interfaceKey = "";
+            if (interfaces.length == 1) {
+                interfaceKey = interfaces[0].getName();
+            } else {
+                StringBuilder names = new StringBuilder();
+                for (int i = 0, length = interfaces.length; i < length; i++) {
+                    names.append(interfaces[i].getName());
+                    names.append(' ');
+                }
+                interfaceKey = names.toString();
+            }
+
+            Class<?> newClass;
+            WeakReference<Class<?>> ref = interfaceCache.get(interfaceKey);
+            if (ref == null) {
+                String nextClassName = "$Proxy" + NextClassNameIndex++;
+                if (commonPackageName != null && commonPackageName.length() > 0) {
+                    nextClassName = commonPackageName + "." + nextClassName;
+                }
+                if (loader == null) {
+                    loader = ClassLoader.getSystemClassLoader();
+                }
+                newClass = generateProxy(nextClassName.replace('.', '/'), interfaces, loader);
+                // Need a weak reference to the class so it can
+                // be unloaded if the class loader is discarded
+                interfaceCache.put(interfaceKey, new WeakReference<Class<?>>(newClass));
+                synchronized (proxyCache) {
+                    // the value is unused
+                    proxyCache.put(newClass, "");
+                }
+            } else {
+                newClass = ref.get();
+                assert newClass != null : "\ninterfaceKey=\"" + interfaceKey + "\""
+                                        + "\nloaderCache=\"" + loaderCache + "\""
+                                        + "\nintfCache=\"" + interfaceCache + "\""
+                                        + "\nproxyCache=\"" + proxyCache + "\"";
+            }
+            return newClass;
+        }
+    }
+
+    /**
+     * Returns an instance of the dynamically built class for the specified
+     * interfaces. Method invocations on the returned instance are forwarded to
+     * the specified invocation handler. The interfaces must be visible from the
+     * supplied class loader; no duplicates are permitted. All non-public
+     * interfaces must be defined in the same package.
+     *
+     * @param loader
+     *            the class loader that will define the proxy class
+     * @param interfaces
+     *            an array of {@code Class} objects, each one identifying an
+     *            interface that will be implemented by the returned proxy
+     *            object
+     * @param h
+     *            the invocation handler that handles the dispatched method
+     *            invocations
+     * @return a new proxy object that delegates to the handler {@code h}
+     * @throws IllegalArgumentException
+     *                if any of the interface restrictions are violated
+     * @throws NullPointerException
+     *                if the interfaces or any of its elements are null
+     */
+    public static Object newProxyInstance(ClassLoader loader,
+            Class<?>[] interfaces, InvocationHandler h)
+            throws IllegalArgumentException {
+        if (h == null) {
+            throw new NullPointerException("h == null");
+        }
+        try {
+            return getProxyClass(loader, interfaces).getConstructor(
+                    new Class<?>[] { InvocationHandler.class }).newInstance(
+                    new Object[] { h });
+        } catch (NoSuchMethodException ex) {
+            throw (InternalError) (new InternalError(ex.toString())
+                    .initCause(ex));
+        } catch (IllegalAccessException ex) {
+            throw (InternalError) (new InternalError(ex.toString())
+                    .initCause(ex));
+        } catch (InstantiationException ex) {
+            throw (InternalError) (new InternalError(ex.toString())
+                    .initCause(ex));
+        } catch (InvocationTargetException ex) {
+            Throwable target = ex.getTargetException();
+            throw (InternalError) (new InternalError(target.toString())
+                    .initCause(target));
+        }
+    }
+
+    /**
+     * Indicates whether or not the specified class is a dynamically generated
+     * proxy class.
+     *
+     * @param cl
+     *            the class
+     * @return {@code true} if the class is a proxy class, {@code false}
+     *         otherwise
+     * @throws NullPointerException
+     *                if the class is {@code null}
+     */
+    public static boolean isProxyClass(Class<?> cl) {
+        if (cl == null) {
+            throw new NullPointerException("cl == null");
+        }
+        synchronized (proxyCache) {
+            return proxyCache.containsKey(cl);
+        }
+    }
+
+    /**
+     * Returns the invocation handler of the specified proxy instance.
+     *
+     * @param proxy
+     *            the proxy instance
+     * @return the invocation handler of the specified proxy instance
+     * @throws IllegalArgumentException
+     *                if the supplied {@code proxy} is not a proxy object
+     */
+    public static InvocationHandler getInvocationHandler(Object proxy)
+            throws IllegalArgumentException {
+
+        if (isProxyClass(proxy.getClass())) {
+            return ((Proxy) proxy).h;
+        }
+
+        throw new IllegalArgumentException("not a proxy instance");
+    }
+
+    native private static Class generateProxy(String name, Class[] interfaces,
+        ClassLoader loader);
+
+    /*
+     * The VM clones this method's descriptor when generating a proxy class.
+     * There is no implementation.
+     */
+    native private static void constructorPrototype(InvocationHandler h);
+}
diff --git a/libdvm/src/main/java/org/apache/harmony/kernel/vm/StringUtils.java b/libdvm/src/main/java/org/apache/harmony/kernel/vm/StringUtils.java
new file mode 100644
index 0000000..01d0e30
--- /dev/null
+++ b/libdvm/src/main/java/org/apache/harmony/kernel/vm/StringUtils.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 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 org.apache.harmony.kernel.vm;
+
+/**
+ * String utility functions.
+ */
+public final class StringUtils {
+    /**
+     * This class is uninstantiable.
+     */
+    private StringUtils() {
+        // This space intentionally left blank.
+    }
+
+    /**
+     * Combine a list of strings in an <code>Object[]</code> into a single
+     * string.
+     *
+     * @param list non-null; the strings to combine
+     * @return non-null; the combined form
+     */
+    public static String combineStrings(Object[] list) {
+        int listLength = list.length;
+
+        switch (listLength) {
+            case 0: {
+                return "";
+            }
+            case 1: {
+                return (String) list[0];
+            }
+        }
+
+        int strLength = 0;
+
+        for (int i = 0; i < listLength; i++) {
+            strLength += ((String) list[i]).length();
+        }
+
+        StringBuilder sb = new StringBuilder(strLength);
+
+        for (int i = 0; i < listLength; i++) {
+            sb.append(list[i]);
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/libdvm/src/main/java/sun/misc/Unsafe.java b/libdvm/src/main/java/sun/misc/Unsafe.java
new file mode 100644
index 0000000..884340b
--- /dev/null
+++ b/libdvm/src/main/java/sun/misc/Unsafe.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2007 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 sun.misc;
+
+import dalvik.system.VMStack;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * The package name notwithstanding, this class is the quasi-standard
+ * way for Java code to gain access to and use functionality which,
+ * when unsupervised, would allow one to break the pointer/type safety
+ * of Java.
+ */
+public final class Unsafe {
+    /** Traditional dalvik name. */
+    private static final Unsafe THE_ONE = new Unsafe();
+    /** Traditional RI name. */
+    private static final Unsafe theUnsafe = THE_ONE;
+
+    /**
+     * This class is only privately instantiable.
+     */
+    private Unsafe() {}
+
+    /**
+     * Gets the unique instance of this class. This is only allowed in
+     * very limited situations.
+     */
+    public static Unsafe getUnsafe() {
+        /*
+         * Only code on the bootclasspath is allowed to get at the
+         * Unsafe instance.
+         */
+        ClassLoader calling = VMStack.getCallingClassLoader();
+        if ((calling != null) && (calling != Unsafe.class.getClassLoader())) {
+            throw new SecurityException("Unsafe access denied");
+        }
+
+        return THE_ONE;
+    }
+
+    /**
+     * Gets the raw byte offset from the start of an object's memory to
+     * the memory used to store the indicated instance field.
+     *
+     * @param field non-null; the field in question, which must be an
+     * instance field
+     * @return the offset to the field
+     */
+    public long objectFieldOffset(Field field) {
+        if (Modifier.isStatic(field.getModifiers())) {
+            throw new IllegalArgumentException(
+                    "valid for instance fields only");
+        }
+
+        return objectFieldOffset0(field);
+    }
+
+    /**
+     * Helper for {@link #objectFieldOffset}, which does all the work,
+     * assuming the parameter is deemed valid.
+     *
+     * @param field non-null; the instance field
+     * @return the offset to the field
+     */
+    private static native long objectFieldOffset0(Field field);
+
+    /**
+     * Gets the offset from the start of an array object's memory to
+     * the memory used to store its initial (zeroeth) element.
+     *
+     * @param clazz non-null; class in question; must be an array class
+     * @return the offset to the initial element
+     */
+    public int arrayBaseOffset(Class clazz) {
+        if (! clazz.isArray()) {
+            throw new IllegalArgumentException(
+                    "valid for array classes only");
+        }
+
+        return arrayBaseOffset0(clazz);
+    }
+
+    /**
+     * Helper for {@link #arrayBaseOffset}, which does all the work,
+     * assuming the parameter is deemed valid.
+     *
+     * @return the offset to the field
+     */
+    private static native int arrayBaseOffset0(Class clazz);
+
+    /**
+     * Gets the size of each element of the given array class.
+     *
+     * @param clazz non-null; class in question; must be an array class
+     * @return &gt; 0; the size of each element of the array
+     */
+    public int arrayIndexScale(Class clazz) {
+        if (! clazz.isArray()) {
+            throw new IllegalArgumentException(
+                    "valid for array classes only");
+        }
+
+        return arrayIndexScale0(clazz);
+    }
+
+    /**
+     * Helper for {@link #arrayIndexScale}, which does all the work,
+     * assuming the parameter is deemed valid.
+     *
+     * @return the offset to the field
+     */
+    private static native int arrayIndexScale0(Class clazz);
+
+    /**
+     * Performs a compare-and-set operation on an <code>int</code>
+     * field within the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param expectedValue expected value of the field
+     * @param newValue new value to store in the field if the contents are
+     * as expected
+     * @return <code>true</code> if the new value was in fact stored, and
+     * <code>false</code> if not
+     */
+    public native boolean compareAndSwapInt(Object obj, long offset,
+            int expectedValue, int newValue);
+
+    /**
+     * Performs a compare-and-set operation on a <code>long</code>
+     * field within the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param expectedValue expected value of the field
+     * @param newValue new value to store in the field if the contents are
+     * as expected
+     * @return <code>true</code> if the new value was in fact stored, and
+     * <code>false</code> if not
+     */
+    public native boolean compareAndSwapLong(Object obj, long offset,
+            long expectedValue, long newValue);
+
+    /**
+     * Performs a compare-and-set operation on an <code>Object</code>
+     * field (that is, a reference field) within the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param expectedValue expected value of the field
+     * @param newValue new value to store in the field if the contents are
+     * as expected
+     * @return <code>true</code> if the new value was in fact stored, and
+     * <code>false</code> if not
+     */
+    public native boolean compareAndSwapObject(Object obj, long offset,
+            Object expectedValue, Object newValue);
+
+    /**
+     * Gets an <code>int</code> field from the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native int getIntVolatile(Object obj, long offset);
+
+    /**
+     * Stores an <code>int</code> field into the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putIntVolatile(Object obj, long offset, int newValue);
+
+    /**
+     * Gets a <code>long</code> field from the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native long getLongVolatile(Object obj, long offset);
+
+    /**
+     * Stores a <code>long</code> field into the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putLongVolatile(Object obj, long offset, long newValue);
+
+    /**
+     * Gets an <code>Object</code> field from the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native Object getObjectVolatile(Object obj, long offset);
+
+    /**
+     * Stores an <code>Object</code> field into the given object,
+     * using <code>volatile</code> semantics.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putObjectVolatile(Object obj, long offset,
+            Object newValue);
+
+    /**
+     * Gets an <code>int</code> field from the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native int getInt(Object obj, long offset);
+
+    /**
+     * Stores an <code>int</code> field into the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putInt(Object obj, long offset, int newValue);
+
+    /**
+     * Lazy set an int field.
+     */
+    public native void putOrderedInt(Object obj, long offset, int newValue);
+
+    /**
+     * Gets a <code>long</code> field from the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native long getLong(Object obj, long offset);
+
+    /**
+     * Stores a <code>long</code> field into the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putLong(Object obj, long offset, long newValue);
+
+    /**
+     * Lazy set a long field.
+     */
+    public native void putOrderedLong(Object obj, long offset, long newValue);
+
+    /**
+     * Gets an <code>Object</code> field from the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @return the retrieved value
+     */
+    public native Object getObject(Object obj, long offset);
+
+    /**
+     * Stores an <code>Object</code> field into the given object.
+     *
+     * @param obj non-null; object containing the field
+     * @param offset offset to the field within <code>obj</code>
+     * @param newValue the value to store
+     */
+    public native void putObject(Object obj, long offset, Object newValue);
+
+    /**
+     * Lazy set an object field.
+     */
+    public native void putOrderedObject(Object obj, long offset,
+            Object newValue);
+
+    /**
+     * Parks the calling thread for the specified amount of time,
+     * unless the "permit" for the thread is already available (due to
+     * a previous call to {@link #unpark}. This method may also return
+     * spuriously (that is, without the thread being told to unpark
+     * and without the indicated amount of time elapsing).
+     *
+     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
+     * in-depth information of the behavior of this method.</p>
+     *
+     * @param absolute whether the given time value is absolute
+     * milliseconds-since-the-epoch (<code>true</code>) or relative
+     * nanoseconds-from-now (<code>false</code>)
+     * @param time the (absolute millis or relative nanos) time value
+     */
+    public void park(boolean absolute, long time) {
+        if (absolute) {
+            Thread.currentThread().parkUntil(time);
+        } else {
+            Thread.currentThread().parkFor(time);
+        }
+    }
+
+    /**
+     * Unparks the given object, which must be a {@link Thread}.
+     *
+     * <p>See {@link java.util.concurrent.locks.LockSupport} for more
+     * in-depth information of the behavior of this method.</p>
+     *
+     * @param obj non-null; the object to unpark
+     */
+    public void unpark(Object obj) {
+        if (obj instanceof Thread) {
+            ((Thread) obj).unpark();
+        } else {
+            throw new IllegalArgumentException("valid for Threads only");
+        }
+    }
+
+    /**
+     * Allocates an instance of the given class without running the constructor.
+     * The class' <clinit> will be run, if necessary.
+     */
+    public native Object allocateInstance(Class<?> c);
+}
diff --git a/luni/src/main/java/android/system/ErrnoException.java b/luni/src/main/java/android/system/ErrnoException.java
index 134d6a0..90155c8 100644
--- a/luni/src/main/java/android/system/ErrnoException.java
+++ b/luni/src/main/java/android/system/ErrnoException.java
@@ -24,8 +24,6 @@
  * A checked exception thrown when {@link Os} methods fail. This exception contains the native
  * errno value, for comparison against the constants in {@link OsConstants}, should sophisticated
  * callers need to adjust their behavior based on the exact failure.
- *
- * @hide
  */
 public final class ErrnoException extends Exception {
   private final String functionName;
diff --git a/luni/src/main/java/android/system/Os.java b/luni/src/main/java/android/system/Os.java
index e7613df..0b80b52 100644
--- a/luni/src/main/java/android/system/Os.java
+++ b/luni/src/main/java/android/system/Os.java
@@ -47,8 +47,6 @@
  * primitives used to implement the higher-level APIs.
  *
  * <p>The corresponding constants can be found in {@link OsConstants}.
- *
- * @hide
  */
 public final class Os {
   private Os() {}
@@ -63,6 +61,8 @@
    */
   public static boolean access(String path, int mode) throws ErrnoException { return Libcore.os.access(path, mode); }
 
+  /** @hide */ public static InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return Libcore.os.android_getaddrinfo(node, hints, netId); }
+
   /**
    * See <a href="http://man7.org/linux/man-pages/man2/bind.2.html">bind(2)</a>.
    */
@@ -157,8 +157,6 @@
    */
   public static String gai_strerror(int error) { return Libcore.os.gai_strerror(error); }
 
-  /** @hide */ public static InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException { return Libcore.os.getaddrinfo(node, hints); }
-
   /**
    * See <a href="http://man7.org/linux/man-pages/man2/getegid.2.html">getegid(2)</a>.
    */
diff --git a/luni/src/main/java/android/system/OsConstants.java b/luni/src/main/java/android/system/OsConstants.java
index 0a49311..c758eb7 100644
--- a/luni/src/main/java/android/system/OsConstants.java
+++ b/luni/src/main/java/android/system/OsConstants.java
@@ -18,7 +18,6 @@
 
 /**
  * Constants and helper functions for use with {@link Os}.
- * @hide
  */
 public final class OsConstants {
     private OsConstants() {
diff --git a/luni/src/main/java/android/system/StructPollfd.java b/luni/src/main/java/android/system/StructPollfd.java
index 8bdecb2..b812612 100644
--- a/luni/src/main/java/android/system/StructPollfd.java
+++ b/luni/src/main/java/android/system/StructPollfd.java
@@ -22,8 +22,6 @@
 /**
  * Used as an in/out parameter to {@link Os#poll}.
  * Corresponds to C's {@code struct pollfd} from {@code &lt;poll.h&gt;}.
- *
- * @hide
  */
 public final class StructPollfd {
   /** The file descriptor to poll. */
diff --git a/luni/src/main/java/android/system/StructStat.java b/luni/src/main/java/android/system/StructStat.java
index 87bd50c..a6958c1 100644
--- a/luni/src/main/java/android/system/StructStat.java
+++ b/luni/src/main/java/android/system/StructStat.java
@@ -21,8 +21,6 @@
 /**
  * File information returned by {@link Os#fstat}, {@link Os#lstat}, and {@link Os#stat}.
  * Corresponds to C's {@code struct stat} from {@code &lt;stat.h&gt;}.
- *
- * @hide
  */
 public final class StructStat {
   /** Device ID of device containing file. */
diff --git a/luni/src/main/java/android/system/StructStatVfs.java b/luni/src/main/java/android/system/StructStatVfs.java
index b0b7802..942a39a 100644
--- a/luni/src/main/java/android/system/StructStatVfs.java
+++ b/luni/src/main/java/android/system/StructStatVfs.java
@@ -20,8 +20,6 @@
 
 /**
  * File information returned by {@link Os#fstatvfs} and {@link Os#statvfs}.
- *
- * @hide
  */
 public final class StructStatVfs {
   /** File system block size (used for block counts). */
diff --git a/luni/src/main/java/android/system/StructUtsname.java b/luni/src/main/java/android/system/StructUtsname.java
index c62dbfa..5d9127b 100644
--- a/luni/src/main/java/android/system/StructUtsname.java
+++ b/luni/src/main/java/android/system/StructUtsname.java
@@ -21,8 +21,6 @@
 /**
  * Information returned by {@link Os#uname}.
  * Corresponds to C's {@code struct utsname} from {@code &lt;sys/utsname.h&gt;}.
- *
- * @hide
  */
 public final class StructUtsname {
   /** The OS name, such as "Linux". */
diff --git a/luni/src/main/java/android/util/MutableBoolean.java b/luni/src/main/java/android/util/MutableBoolean.java
index 90bf68c..5a8a200 100644
--- a/luni/src/main/java/android/util/MutableBoolean.java
+++ b/luni/src/main/java/android/util/MutableBoolean.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableBoolean {
   public boolean value;
diff --git a/luni/src/main/java/android/util/MutableByte.java b/luni/src/main/java/android/util/MutableByte.java
index 65738b9..7397ba4 100644
--- a/luni/src/main/java/android/util/MutableByte.java
+++ b/luni/src/main/java/android/util/MutableByte.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableByte {
   public byte value;
diff --git a/luni/src/main/java/android/util/MutableChar.java b/luni/src/main/java/android/util/MutableChar.java
index b59bab3..f435331 100644
--- a/luni/src/main/java/android/util/MutableChar.java
+++ b/luni/src/main/java/android/util/MutableChar.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableChar {
   public char value;
diff --git a/luni/src/main/java/android/util/MutableDouble.java b/luni/src/main/java/android/util/MutableDouble.java
index 3e2cc3a..f62f47e 100644
--- a/luni/src/main/java/android/util/MutableDouble.java
+++ b/luni/src/main/java/android/util/MutableDouble.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableDouble {
   public double value;
diff --git a/luni/src/main/java/android/util/MutableFloat.java b/luni/src/main/java/android/util/MutableFloat.java
index 6e30501..6b5441c 100644
--- a/luni/src/main/java/android/util/MutableFloat.java
+++ b/luni/src/main/java/android/util/MutableFloat.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableFloat {
   public float value;
diff --git a/luni/src/main/java/android/util/MutableInt.java b/luni/src/main/java/android/util/MutableInt.java
index 8220c44..2f93030 100644
--- a/luni/src/main/java/android/util/MutableInt.java
+++ b/luni/src/main/java/android/util/MutableInt.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableInt {
   public int value;
diff --git a/luni/src/main/java/android/util/MutableLong.java b/luni/src/main/java/android/util/MutableLong.java
index 5df6a0d..94beab5 100644
--- a/luni/src/main/java/android/util/MutableLong.java
+++ b/luni/src/main/java/android/util/MutableLong.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableLong {
   public long value;
diff --git a/luni/src/main/java/android/util/MutableShort.java b/luni/src/main/java/android/util/MutableShort.java
index 3880fef..cdd9923 100644
--- a/luni/src/main/java/android/util/MutableShort.java
+++ b/luni/src/main/java/android/util/MutableShort.java
@@ -17,7 +17,6 @@
 package android.util;
 
 /**
- * @hide
  */
 public final class MutableShort {
   public short value;
diff --git a/luni/src/main/java/java/io/ObjectInputStream.java b/luni/src/main/java/java/io/ObjectInputStream.java
index d07075f..cd7f736 100644
--- a/luni/src/main/java/java/io/ObjectInputStream.java
+++ b/luni/src/main/java/java/io/ObjectInputStream.java
@@ -1053,7 +1053,8 @@
      * @see #readFields
      * @see #readObject()
      */
-    private void readFieldValues(Object obj, ObjectStreamClass classDesc) throws OptionalDataException, ClassNotFoundException, IOException {
+    private void readFieldValues(Object obj, ObjectStreamClass classDesc)
+            throws OptionalDataException, ClassNotFoundException, IOException {
         // Now we must read all fields and assign them to the receiver
         ObjectStreamField[] fields = classDesc.getLoadFields();
         fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields;
@@ -1577,6 +1578,9 @@
             ClassNotFoundException, IOException {
         // read classdesc for Enum first
         ObjectStreamClass classDesc = readEnumDesc();
+
+        Class enumType = classDesc.checkAndGetTcEnumClass();
+
         int newHandle = nextHandle();
         // read name after class desc
         String name;
@@ -1598,9 +1602,11 @@
 
         Enum<?> result;
         try {
-            result = Enum.valueOf((Class) classDesc.forClass(), name);
+            result = Enum.valueOf(enumType, name);
         } catch (IllegalArgumentException e) {
-            throw new InvalidObjectException(e.getMessage());
+            InvalidObjectException ioe = new InvalidObjectException(e.getMessage());
+            ioe.initCause(e);
+            throw ioe;
         }
         registerObjectRead(result, newHandle, unshared);
         return result;
@@ -1782,9 +1788,10 @@
             throw missingClassDescriptor();
         }
 
+        Class<?> objectClass = classDesc.checkAndGetTcObjectClass();
+
         int newHandle = nextHandle();
-        Class<?> objectClass = classDesc.forClass();
-        Object result = null;
+        Object result;
         Object registeredResult = null;
         if (objectClass != null) {
             // Now we know which class to instantiate and which constructor to
@@ -2056,8 +2063,7 @@
      *             if the source stream does not contain readable serialized
      *             objects.
      */
-    protected void readStreamHeader() throws IOException,
-            StreamCorruptedException {
+    protected void readStreamHeader() throws IOException, StreamCorruptedException {
         if (input.readShort() == STREAM_MAGIC
                 && input.readShort() == STREAM_VERSION) {
             return;
@@ -2257,7 +2263,7 @@
                 // not primitive class
                 // Use the first non-null ClassLoader on the stack. If null, use
                 // the system class loader
-                cls = Class.forName(className, true, callerClassLoader);
+                cls = Class.forName(className, false, callerClassLoader);
             }
         }
         return cls;
@@ -2331,8 +2337,7 @@
             throws InvalidClassException {
 
         Class<?> localClass = loadedStreamClass.forClass();
-        ObjectStreamClass localStreamClass = ObjectStreamClass
-                .lookupStreamClass(localClass);
+        ObjectStreamClass localStreamClass = ObjectStreamClass.lookupStreamClass(localClass);
 
         if (loadedStreamClass.getSerialVersionUID() != localStreamClass
                 .getSerialVersionUID()) {
diff --git a/luni/src/main/java/java/io/ObjectStreamClass.java b/luni/src/main/java/java/io/ObjectStreamClass.java
index 1bde314..9b7f2c9 100644
--- a/luni/src/main/java/java/io/ObjectStreamClass.java
+++ b/luni/src/main/java/java/io/ObjectStreamClass.java
@@ -1068,7 +1068,6 @@
             tlc.put(cl, cachedValue);
         }
         return cachedValue;
-
     }
 
     /**
@@ -1298,4 +1297,72 @@
     public String toString() {
         return getName() + ": static final long serialVersionUID =" + getSerialVersionUID() + "L;";
     }
+
+    /**
+     * Checks the local class to make sure it is valid for {@link ObjectStreamConstants#TC_OBJECT}
+     * deserialization. Also performs some sanity checks of the stream data. This method is used
+     * during deserialization to confirm the local class is likely to be compatible with the coming
+     * stream data, but before an instance is instantiated.
+     *
+     * @hide used internally during deserialization
+     */
+    public Class<?> checkAndGetTcObjectClass() throws InvalidClassException {
+        // We check some error possibilities that might cause problems later.
+        boolean wasSerializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
+        boolean wasExternalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
+        if (wasSerializable == wasExternalizable) {
+            throw new InvalidClassException(
+                    getName() + " stream data is corrupt: SC_SERIALIZABLE=" + wasSerializable
+                            + " SC_EXTERNALIZABLE=" + wasExternalizable
+                            + ", classDescFlags must have one or the other");
+        }
+
+        // TC_ENUM is handled elsewhere. See checkAndGetTcEnumClass().
+        if (isEnum()) {
+            throw new InvalidClassException(
+                    getName() + " local class is incompatible: Local class is an enum, streamed"
+                            + " data is tagged with TC_OBJECT");
+        }
+
+        // isSerializable() is true if the local class implements Serializable. Externalizable
+        // classes are also Serializable via inheritance.
+        if (!isSerializable()) {
+            throw new InvalidClassException(getName() + " local class is incompatible: Not"
+                    + " Serializable");
+        }
+
+        // The stream class was externalizable, but is only serializable locally.
+        if (wasExternalizable != isExternalizable()) {
+            throw new InvalidClassException(
+                    getName() + " local class is incompatible: Local class is Serializable, stream"
+                            + " data requires Externalizable");
+        }
+
+        // The following are left unchecked and thus are treated leniently at this point.
+        // SC_BLOCK_DATA may be set iff SC_EXTERNALIZABLE is set AND version 2 of the protocol is in
+        // use.
+        // SC_ENUM should not be set.
+
+        return forClass();
+    }
+
+    /**
+     * Checks the local class to make sure it is valid for {@link ObjectStreamConstants#TC_ENUM}
+     * deserialization. This method is used during deserialization to confirm the local class is
+     * likely to be compatible with the coming stream data, but before an instance is instantiated.
+     *
+     * @hide used internally during deserialization
+     */
+    public Class<?> checkAndGetTcEnumClass() throws InvalidClassException {
+        if (!isEnum()) {
+            throw new InvalidClassException(
+                    getName() + " local class is incompatible: Local class is not an enum,"
+                            + " streamed data is tagged with TC_ENUM");
+        }
+
+        // The stream flags are expected to be SC_SERIALIZABLE | SC_ENUM but these and the
+        // other flags are not used when reading enum data so they are treated leniently.
+
+        return forClass();
+    }
 }
diff --git a/luni/src/main/java/java/io/ObjectStreamConstants.java b/luni/src/main/java/java/io/ObjectStreamConstants.java
index 8228b33..95f8b03 100644
--- a/luni/src/main/java/java/io/ObjectStreamConstants.java
+++ b/luni/src/main/java/java/io/ObjectStreamConstants.java
@@ -149,25 +149,25 @@
     // Flags that indicate if the object was serializable, externalizable
     // and had a writeObject method when dumped.
     /**
-     * Bit mask for the {@code flag} field in ObjectStreamClass. Indicates
-     * that a serializable class has its own {@code writeObject} method.
+     * Bit mask for the {@code flag} field in {@link ObjectStreamClass}. Indicates
+     * that a {@link Serializable} class has its own {@code writeObject} method.
      */
     public static final byte SC_WRITE_METHOD = 0x01; // If SC_SERIALIZABLE
 
     /**
-     * Bit mask for the {@code flag} field in ObjectStreamClass. Indicates
-     * that a class is serializable.
+     * Bit mask for the {@code flag} field in {@link ObjectStreamClass}. Indicates
+     * that a class implements {@link Serializable} but not {@link Externalizable}.
      */
     public static final byte SC_SERIALIZABLE = 0x02;
 
     /**
-     * Bit mask for the {@code flag} field in ObjectStreamClass. Indicates
-     * that a class is externalizable.
+     * Bit mask for the {@code flag} field in {@link ObjectStreamClass}. Indicates
+     * that a class implements {@link Externalizable}.
      */
     public static final byte SC_EXTERNALIZABLE = 0x04;
 
     /**
-     * Bit mask for the {@code flag} field in ObjectStreamClass. Indicates
+     * Bit mask for the {@code flag} field in {@link ObjectStreamClass}. Indicates
      * that an externalizable class is written in block data mode.
      */
     public static final byte SC_BLOCK_DATA = 0x08; // If SC_EXTERNALIZABLE
@@ -178,7 +178,7 @@
     public static final byte TC_ENUM = 0x7E;
 
     /**
-     * Bit mask for the {@code flag} field in ObjectStreamClass. Indicates
+     * Bit mask for the {@code flag} field in {@link ObjectStreamClass}. Indicates
      * that a class is an enum type.
      */
     public static final byte SC_ENUM = 0x10;
diff --git a/luni/src/main/java/java/net/AddressCache.java b/luni/src/main/java/java/net/AddressCache.java
index 194761a..2aba78b 100644
--- a/luni/src/main/java/java/net/AddressCache.java
+++ b/luni/src/main/java/java/net/AddressCache.java
@@ -37,8 +37,36 @@
     private static final long TTL_NANOS = 2 * 1000000000L;
 
     // The actual cache.
-    private final BasicLruCache<String, AddressCacheEntry> cache
-            = new BasicLruCache<String, AddressCacheEntry>(MAX_ENTRIES);
+    private final BasicLruCache<AddressCacheKey, AddressCacheEntry> cache
+            = new BasicLruCache<AddressCacheKey, AddressCacheEntry>(MAX_ENTRIES);
+
+    static class AddressCacheKey {
+        private final String mHostname;
+        private final int mNetId;
+
+        AddressCacheKey(String hostname, int netId) {
+            mHostname = hostname;
+            mNetId = netId;
+        }
+
+        @Override public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof AddressCacheKey)) {
+                return false;
+            }
+            AddressCacheKey lhs = (AddressCacheKey) o;
+            return mHostname.equals(lhs.mHostname) && mNetId == lhs.mNetId;
+        }
+
+        @Override public int hashCode() {
+            int result = 17;
+            result = 31 * result + mNetId;
+            result = 31 * result + mHostname.hashCode();
+            return result;
+        }
+    }
 
     static class AddressCacheEntry {
         // Either an InetAddress[] for a positive entry,
@@ -67,12 +95,12 @@
     }
 
     /**
-     * Returns the cached InetAddress[] associated with 'hostname'. Returns null if nothing is known
-     * about 'hostname'. Returns a String suitable for use as an UnknownHostException detail
-     * message if 'hostname' is known not to exist.
+     * Returns the cached InetAddress[] for 'hostname' on network 'netId'. Returns null
+     * if nothing is known about 'hostname'. Returns a String suitable for use as an
+     * UnknownHostException detail message if 'hostname' is known not to exist.
      */
-    public Object get(String hostname) {
-        AddressCacheEntry entry = cache.get(hostname);
+    public Object get(String hostname, int netId) {
+        AddressCacheEntry entry = cache.get(new AddressCacheKey(hostname, netId));
         // Do we have a valid cache entry?
         if (entry != null && entry.expiryNanos >= System.nanoTime()) {
             return entry.value;
@@ -86,15 +114,15 @@
      * Associates the given 'addresses' with 'hostname'. The association will expire after a
      * certain length of time.
      */
-    public void put(String hostname, InetAddress[] addresses) {
-        cache.put(hostname, new AddressCacheEntry(addresses));
+    public void put(String hostname, int netId, InetAddress[] addresses) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(addresses));
     }
 
     /**
      * Records that 'hostname' is known not to have any associated addresses. (I.e. insert a
      * negative cache entry.)
      */
-    public void putUnknownHost(String hostname, String detailMessage) {
-        cache.put(hostname, new AddressCacheEntry(detailMessage));
+    public void putUnknownHost(String hostname, int netId, String detailMessage) {
+        cache.put(new AddressCacheKey(hostname, netId), new AddressCacheEntry(detailMessage));
     }
 }
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java
index e31b4c3..5cfa15a 100644
--- a/luni/src/main/java/java/net/InetAddress.java
+++ b/luni/src/main/java/java/net/InetAddress.java
@@ -127,6 +127,9 @@
 
     private static final long serialVersionUID = 3286316764910316507L;
 
+    /** Using NetID of NETID_UNSET indicates resolution should be done on default network. */
+    private static final int NETID_UNSET = 0;
+
     private int family;
 
     byte[] ipaddress;
@@ -209,14 +212,29 @@
      * @throws UnknownHostException if the address lookup fails.
      */
     public static InetAddress[] getAllByName(String host) throws UnknownHostException {
-        return getAllByNameImpl(host).clone();
+        return getAllByNameImpl(host, NETID_UNSET).clone();
     }
 
     /**
-     * Returns the InetAddresses for {@code host}. The returned array is shared
-     * and must be cloned before it is returned to application code.
+     * Operates identically to {@code getAllByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host the hostname or literal IP string to be resolved.
+     * @param netId the network to use for host resolution.
+     * @return the array of addresses associated with the specified host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
      */
-    private static InetAddress[] getAllByNameImpl(String host) throws UnknownHostException {
+    public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException {
+        return getAllByNameImpl(host, netId).clone();
+    }
+
+    /**
+     * Returns the InetAddresses for {@code host} on network {@code netId}. The
+     * returned array is shared and must be cloned before it is returned to
+     * application code.
+     */
+    private static InetAddress[] getAllByNameImpl(String host, int netId) throws UnknownHostException {
         if (host == null || host.isEmpty()) {
             return loopbackAddresses();
         }
@@ -231,7 +249,7 @@
             return new InetAddress[] { result };
         }
 
-        return lookupHostByName(host).clone();
+        return lookupHostByName(host, netId).clone();
     }
 
     private static InetAddress makeInetAddress(byte[] bytes, String hostName) throws UnknownHostException {
@@ -264,7 +282,7 @@
         hints.ai_flags = AI_NUMERICHOST;
         InetAddress[] addresses = null;
         try {
-            addresses = Libcore.os.getaddrinfo(address, hints);
+            addresses = Libcore.os.android_getaddrinfo(address, hints, NETID_UNSET);
         } catch (GaiException ignored) {
         }
         return (addresses != null) ? addresses[0] : null;
@@ -284,7 +302,22 @@
      *             if the address lookup fails.
      */
     public static InetAddress getByName(String host) throws UnknownHostException {
-        return getAllByNameImpl(host)[0];
+        return getAllByNameImpl(host, NETID_UNSET)[0];
+    }
+
+    /**
+     * Operates identically to {@code getByName} except host resolution is
+     * performed on the network designated by {@code netId}.
+     *
+     * @param host
+     *            the hostName to be resolved to an address or {@code null}.
+     * @param netId the network to use for host resolution.
+     * @return the {@code InetAddress} instance representing the host.
+     * @throws UnknownHostException if the address lookup fails.
+     * @hide internal use only
+     */
+    public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException {
+        return getAllByNameImpl(host, netId)[0];
     }
 
     /**
@@ -360,7 +393,7 @@
      */
     public static InetAddress getLocalHost() throws UnknownHostException {
         String host = Libcore.os.uname().nodename;
-        return lookupHostByName(host)[0];
+        return lookupHostByName(host, NETID_UNSET)[0];
     }
 
     /**
@@ -377,12 +410,14 @@
      * Resolves a hostname to its IP addresses using a cache.
      *
      * @param host the hostname to resolve.
+     * @param netId the network to perform resolution upon.
      * @return the IP addresses of the host.
      */
-    private static InetAddress[] lookupHostByName(String host) throws UnknownHostException {
+    private static InetAddress[] lookupHostByName(String host, int netId)
+            throws UnknownHostException {
         BlockGuard.getThreadPolicy().onNetwork();
         // Do we have a result cached?
-        Object cachedResult = addressCache.get(host);
+        Object cachedResult = addressCache.get(host, netId);
         if (cachedResult != null) {
             if (cachedResult instanceof InetAddress[]) {
                 // A cached positive result.
@@ -400,12 +435,12 @@
             // for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
             // anyway, just pick one.
             hints.ai_socktype = SOCK_STREAM;
-            InetAddress[] addresses = Libcore.os.getaddrinfo(host, hints);
+            InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
             // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
             for (InetAddress address : addresses) {
                 address.hostName = host;
             }
-            addressCache.put(host, addresses);
+            addressCache.put(host, netId, addresses);
             return addresses;
         } catch (GaiException gaiException) {
             // If the failure appears to have been a lack of INTERNET permission, throw a clear
@@ -418,7 +453,7 @@
             }
             // Otherwise, throw an UnknownHostException.
             String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
-            addressCache.putUnknownHost(host, detailMessage);
+            addressCache.putUnknownHost(host, netId, detailMessage);
             throw gaiException.rethrowAsUnknownHostException(detailMessage);
         }
     }
diff --git a/luni/src/main/java/java/nio/DatagramChannelImpl.java b/luni/src/main/java/java/nio/DatagramChannelImpl.java
index e736c40..9008637 100644
--- a/luni/src/main/java/java/nio/DatagramChannelImpl.java
+++ b/luni/src/main/java/java/nio/DatagramChannelImpl.java
@@ -130,7 +130,6 @@
         }
     }
 
-    /** @hide Until ready for a public API change */
     @Override
     synchronized public boolean isConnected() {
         return connected;
diff --git a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
index 7185c32..ae33672 100644
--- a/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/ServerSocketChannelImpl.java
@@ -55,7 +55,6 @@
         return socket;
     }
 
-    /** @hide Until ready for a public API change */
     @Override
     public SocketChannel accept() throws IOException {
         if (!isOpen()) {
diff --git a/luni/src/main/java/java/util/IllformedLocaleException.java b/luni/src/main/java/java/util/IllformedLocaleException.java
index db1754e..3dec1cd 100644
--- a/luni/src/main/java/java/util/IllformedLocaleException.java
+++ b/luni/src/main/java/java/util/IllformedLocaleException.java
@@ -21,7 +21,6 @@
  *
  * See {@link Locale} and {@link Locale.Builder}.
  *
- * @hide
  * @since 1.7
  */
 public class IllformedLocaleException extends RuntimeException {
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index e0582dc..a8ff15d 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -253,7 +253,6 @@
      *
      * See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
      *
-     * @hide
      * @since 1.7
      */
     public static final char PRIVATE_USE_EXTENSION = 'x';
@@ -264,7 +263,6 @@
      *
      * See {@link #getExtension(char)} and {@link Builder#setExtension(char, String)}.
      *
-     * @hide
      * @since 1.7
      */
     public static final char UNICODE_LOCALE_EXTENSION = 'u';
@@ -302,7 +300,6 @@
      * the structured state (keywords and attributes) specified therein.
      *
      * @since 1.7
-     * @hide
      */
     public static final class Builder {
         private String language;
@@ -812,7 +809,6 @@
      *
      * @throws NullPointerException if {@code languageTag} is {@code null}.
      *
-     * @hide
      * @since 1.7
      */
     public static Locale forLanguageTag(String languageTag) {
@@ -1150,6 +1146,8 @@
      * Returns the full variant name in the default {@code Locale} for the variant code of
      * this {@code Locale}. If there is no matching variant name, the variant code is
      * returned.
+     *
+     * @since 1.7
      */
     public final String getDisplayVariant() {
         return getDisplayVariant(getDefault());
@@ -1159,6 +1157,8 @@
      * Returns the full variant name in the specified {@code Locale} for the variant code
      * of this {@code Locale}. If there is no matching variant name, the variant code is
      * returned.
+     *
+     * @since 1.7
      */
     public String getDisplayVariant(Locale locale) {
         if (variantCode.isEmpty()) {
@@ -1263,7 +1263,6 @@
      * If set, the script code will be a title cased string of length 4, as per the ISO 15924
      * specification.
      *
-     * @hide
      * @since 1.7
      */
     public String getScript() {
@@ -1273,7 +1272,6 @@
     /**
      * Equivalent to {@code getDisplayScript(Locale.getDefault()))}
      *
-     * @hide
      * @since 1.7
      */
     public String getDisplayScript() {
@@ -1285,7 +1283,6 @@
      * script code is unknown, the return value of this method is the same as that of
      * {@link #getScript()}.
      *
-     * @hide
      * @since 1.7
      */
     public String getDisplayScript(Locale locale) {
@@ -1321,7 +1318,6 @@
      * For example, we do not require scripts to be a registered ISO 15924 scripts or
      * languages to appear in the ISO-639-2 code list.
      *
-     * @hide
      * @since 1.7
      */
     public String toLanguageTag() {
@@ -1528,7 +1524,6 @@
      * See <a href="https://tools.ietf.org/html/bcp47#section-2.1">
      *     the IETF BCP-47 specification</a> (Section 2.2.6) for details.
      *
-     * @hide
      * @since 1.7
      */
     public Set<Character> getExtensionKeys() {
@@ -1543,7 +1538,6 @@
      * locale extension can be fetched using {@link #getUnicodeLocaleAttributes()},
      * {@link #getUnicodeLocaleKeys()}  and {@link #getUnicodeLocaleType}.
      *
-     * @hide
      * @since 1.7
      */
     public String getExtension(char extensionKey) {
@@ -1556,7 +1550,6 @@
      * For more information about types and keywords, see {@link Builder#setUnicodeLocaleKeyword}
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
-     * @hide
      * @since 1.7
      */
     public String getUnicodeLocaleType(String keyWord) {
@@ -1569,7 +1562,6 @@
      * For more information about attributes, see {@link Builder#addUnicodeLocaleAttribute}
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
-     * @hide
      * @since 1.7
      */
     public Set<String> getUnicodeLocaleAttributes() {
@@ -1582,7 +1574,6 @@
      * For more information about types and keywords, see {@link Builder#setUnicodeLocaleKeyword}
      * and <a href="http://www.unicode.org/reports/tr35/#BCP47">Unicode Technical Standard #35</a>
      *
-     * @hide
      * @since 1.7
      */
     public Set<String> getUnicodeLocaleKeys() {
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
index 54b53ae..b38d6a5 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentLinkedDeque.java
@@ -56,8 +56,6 @@
  * actions subsequent to the access or removal of that element from
  * the {@code ConcurrentLinkedDeque} in another thread.
  *
- * @hide
- *
  * @since 1.7
  * @author Doug Lea
  * @author Martin Buchholz
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
index 5ac01c8..9448616 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinPool.java
@@ -39,7 +39,7 @@
  * ForkJoinPool}s may also be appropriate for use with event-style
  * tasks that are never joined.
  *
- * <p>A static {@link #commonPool()} is available and appropriate for
+ * <p>A static {@code commonPool()} is available and appropriate for
  * most applications. The common pool is used by any ForkJoinTask that
  * is not explicitly submitted to a specified pool. Using the common
  * pool normally reduces resource usage (its threads are slowly
@@ -127,7 +127,6 @@
  * or internal resources have been exhausted.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public class ForkJoinPool extends AbstractExecutorService {
@@ -213,8 +212,7 @@
      * choosing existing queues, and may be randomly repositioned upon
      * contention with other submitters.  In essence, submitters act
      * like workers except that they are restricted to executing local
-     * tasks that they submitted (or in the case of CountedCompleters,
-     * others with the same root task).  However, because most
+     * tasks that they submitted. However, because most
      * shared/external queue operations are more expensive than
      * internal, and because, at steady state, external submitters
      * will compete for CPU with workers, ForkJoinTask.join and
@@ -419,12 +417,6 @@
      * to find work (see MAX_HELP) and fall back to suspending the
      * worker and if necessary replacing it with another.
      *
-     * Helping actions for CountedCompleters are much simpler: Method
-     * helpComplete can take and execute any task with the same root
-     * as the task being waited on. However, this still entails some
-     * traversal of completer chains, so is less efficient than using
-     * CountedCompleters without explicit joins.
-     *
      * It is impossible to keep exactly the target parallelism number
      * of threads running at any given time.  Determining the
      * existence of conservatively safe helping targets, the
@@ -2907,7 +2899,7 @@
      * Possibly initiates an orderly shutdown in which previously
      * submitted tasks are executed, but no new tasks will be
      * accepted. Invocation has no effect on execution state if this
-     * is the {@link #commonPool()}, and no additional effect if
+     * is the {@code commonPool()}, and no additional effect if
      * already shut down.  Tasks that are in the process of being
      * submitted concurrently during the course of this method may or
      * may not be rejected.
@@ -2920,7 +2912,7 @@
     /**
      * Possibly attempts to cancel and/or stop all tasks, and reject
      * all subsequently submitted tasks.  Invocation has no effect on
-     * execution state if this is the {@link #commonPool()}, and no
+     * execution state if this is the {@code commonPool()}, and no
      * additional effect if already shut down. Otherwise, tasks that
      * are in the process of being submitted or executed concurrently
      * during the course of this method may or may not be
@@ -2979,8 +2971,8 @@
     /**
      * Blocks until all tasks have completed execution after a
      * shutdown request, or the timeout occurs, or the current thread
-     * is interrupted, whichever happens first. Because the {@link
-     * #commonPool()} never terminates until program shutdown, when
+     * is interrupted, whichever happens first. Because the {@code
+     * commonPool()} never terminates until program shutdown, when
      * applied to the common pool, this method is equivalent to {@link
      * #awaitQuiescence(long, TimeUnit)} but always returns {@code false}.
      *
@@ -3064,7 +3056,7 @@
 
     /**
      * Waits and/or attempts to assist performing tasks indefinitely
-     * until the {@link #commonPool()} {@link #isQuiescent}.
+     * until the {@code commonPool()} {@link #isQuiescent}.
      */
     static void quiesceCommonPool() {
         common.awaitQuiescence(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
index 6d25775..c6bc6de 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinTask.java
@@ -32,8 +32,8 @@
  *
  * <p>A "main" {@code ForkJoinTask} begins execution when it is
  * explicitly submitted to a {@link ForkJoinPool}, or, if not already
- * engaged in a ForkJoin computation, commenced in the {@link
- * ForkJoinPool#commonPool()} via {@link #fork}, {@link #invoke}, or
+ * engaged in a ForkJoin computation, commenced in the {@code
+ * ForkJoinPool.commonPool()} via {@link #fork}, {@link #invoke}, or
  * related methods.  Once started, it will usually in turn start other
  * subtasks.  As indicated by the name of this class, many programs
  * using {@code ForkJoinTask} employ only methods {@link #fork} and
@@ -74,10 +74,9 @@
  * but doing do requires three further considerations: (1) Completion
  * of few if any <em>other</em> tasks should be dependent on a task
  * that blocks on external synchronization or I/O. Event-style async
- * tasks that are never joined (for example, those subclassing {@link
- * CountedCompleter}) often fall into this category.  (2) To minimize
- * resource impact, tasks should be small; ideally performing only the
- * (possibly) blocking action. (3) Unless the {@link
+ * tasks that are never joined often fall into this category.
+ * (2) To minimize resource impact, tasks should be small; ideally
+ * performing only the (possibly) blocking action. (3) Unless the {@link
  * ForkJoinPool.ManagedBlocker} API is used, or the number of possibly
  * blocked tasks is known to be less than the pool's {@link
  * ForkJoinPool#getParallelism} level, the pool cannot guarantee that
@@ -120,13 +119,11 @@
  * <p>The ForkJoinTask class is not usually directly subclassed.
  * Instead, you subclass one of the abstract classes that support a
  * particular style of fork/join processing, typically {@link
- * RecursiveAction} for most computations that do not return results,
- * {@link RecursiveTask} for those that do, and {@link
- * CountedCompleter} for those in which completed actions trigger
- * other actions.  Normally, a concrete ForkJoinTask subclass declares
- * fields comprising its parameters, established in a constructor, and
- * then defines a {@code compute} method that somehow uses the control
- * methods supplied by this base class.
+ * RecursiveAction} for most computations that do not return results
+ * and {@link RecursiveTask} for those that do. Normally, a concrete
+ * ForkJoinTask subclass declares fields comprising its parameters,
+ * established in a constructor, and then defines a {@code compute}
+ * method that somehow uses the control methods supplied by this base class.
  *
  * <p>Method {@link #join} and its variants are appropriate for use
  * only when completion dependencies are acyclic; that is, the
@@ -138,9 +135,9 @@
  * may be of use in constructing custom subclasses for problems that
  * are not statically structured as DAGs. To support such usages, a
  * ForkJoinTask may be atomically <em>tagged</em> with a {@code short}
- * value using {@link #setForkJoinTaskTag} or {@link
- * #compareAndSetForkJoinTaskTag} and checked using {@link
- * #getForkJoinTaskTag}. The ForkJoinTask implementation does not use
+ * value using {@code setForkJoinTaskTag} or {@code
+ * compareAndSetForkJoinTaskTag} and checked using {@code
+ * getForkJoinTaskTag}. The ForkJoinTask implementation does not use
  * these {@code protected} methods or tags for any purpose, but they
  * may be of use in the construction of specialized subclasses.  For
  * example, parallel graph traversals can use the supplied methods to
@@ -178,7 +175,6 @@
  * execution. Serialization is not relied on during execution itself.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
@@ -645,8 +641,8 @@
 
     /**
      * Arranges to asynchronously execute this task in the pool the
-     * current task is running in, if applicable, or using the {@link
-     * ForkJoinPool#commonPool()} if not {@link #inForkJoinPool}.  While
+     * current task is running in, if applicable, or using the {@code
+     * ForkJoinPool.commonPool()} if not {@link #inForkJoinPool}.  While
      * it is not necessarily enforced, it is a usage error to fork a
      * task more than once unless it has completed and been
      * reinitialized.  Subsequent modifications to the state of this
diff --git a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
index 5f2799b..ae28700 100644
--- a/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
+++ b/luni/src/main/java/java/util/concurrent/ForkJoinWorkerThread.java
@@ -18,7 +18,6 @@
  * {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public class ForkJoinWorkerThread extends Thread {
diff --git a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
index cff5dbf..a041fb1 100644
--- a/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/LinkedTransferQueue.java
@@ -50,7 +50,6 @@
  * the {@code LinkedTransferQueue} in another thread.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  * @param <E> the type of elements held in this collection
  */
diff --git a/luni/src/main/java/java/util/concurrent/Phaser.java b/luni/src/main/java/java/util/concurrent/Phaser.java
index a9adbe5..a97d187 100644
--- a/luni/src/main/java/java/util/concurrent/Phaser.java
+++ b/luni/src/main/java/java/util/concurrent/Phaser.java
@@ -227,7 +227,6 @@
  * of participants.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public class Phaser {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveAction.java b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
index 8d666f6..e3a6340 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveAction.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveAction.java
@@ -131,7 +131,6 @@
  * }}</pre>
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public abstract class RecursiveAction extends ForkJoinTask<Void> {
diff --git a/luni/src/main/java/java/util/concurrent/RecursiveTask.java b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
index 421c9d3..80baa52 100644
--- a/luni/src/main/java/java/util/concurrent/RecursiveTask.java
+++ b/luni/src/main/java/java/util/concurrent/RecursiveTask.java
@@ -34,7 +34,6 @@
  * sequentially solve rather than subdividing.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public abstract class RecursiveTask<V> extends ForkJoinTask<V> {
diff --git a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
index a52351b..483981d 100644
--- a/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
+++ b/luni/src/main/java/java/util/concurrent/ScheduledThreadPoolExecutor.java
@@ -690,7 +690,6 @@
      * @param value if {@code true}, remove on cancellation, else don't
      * @see #getRemoveOnCancelPolicy
      * @since 1.7
-     * @hide
      */
     public void setRemoveOnCancelPolicy(boolean value) {
         removeOnCancel = value;
@@ -705,7 +704,6 @@
      *         from the queue
      * @see #setRemoveOnCancelPolicy
      * @since 1.7
-     * @hide
      */
     public boolean getRemoveOnCancelPolicy() {
         return removeOnCancel;
diff --git a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
index a559321..5baf75f 100644
--- a/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
+++ b/luni/src/main/java/java/util/concurrent/ThreadLocalRandom.java
@@ -30,7 +30,6 @@
  * generation methods.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  */
 public class ThreadLocalRandom extends Random {
diff --git a/luni/src/main/java/java/util/concurrent/TransferQueue.java b/luni/src/main/java/java/util/concurrent/TransferQueue.java
index 9cd5773..4c2be6f 100644
--- a/luni/src/main/java/java/util/concurrent/TransferQueue.java
+++ b/luni/src/main/java/java/util/concurrent/TransferQueue.java
@@ -33,7 +33,6 @@
  * and {@code transfer} are effectively synonymous.
  *
  * @since 1.7
- * @hide
  * @author Doug Lea
  * @param <E> the type of elements held in this collection
  */
diff --git a/luni/src/main/java/java/util/concurrent/atomic/Fences.java b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
index 7ecf45a..5714ba0 100644
--- a/luni/src/main/java/java/util/concurrent/atomic/Fences.java
+++ b/luni/src/main/java/java/util/concurrent/atomic/Fences.java
@@ -453,7 +453,6 @@
  *
  * </dl>
  *
- * @since 1.7
  * @hide
  * @author Doug Lea
  */
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
index 4c5e280..37aa9d0 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java
@@ -1255,7 +1255,6 @@
      *         current thread, and {@code false} if the current thread
      *         is at the head of the queue or the queue is empty
      * @since 1.7
-     * @hide
      */
     public final boolean hasQueuedPredecessors() {
         // The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
index 0350060..e711da5 100644
--- a/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+++ b/luni/src/main/java/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
@@ -1485,7 +1485,6 @@
      *         current thread, and {@code false} if the current thread
      *         is at the head of the queue or the queue is empty
      * @since 1.7
-     * @hide
      */
     public final boolean hasQueuedPredecessors() {
         // The correctness of this depends on head being initialized
diff --git a/luni/src/main/java/java/util/jar/JarEntry.java b/luni/src/main/java/java/util/jar/JarEntry.java
index 85c8678..bceef63 100644
--- a/luni/src/main/java/java/util/jar/JarEntry.java
+++ b/luni/src/main/java/java/util/jar/JarEntry.java
@@ -17,16 +17,16 @@
 
 package java.util.jar;
 
-import javax.security.auth.x500.X500Principal;
 import java.io.IOException;
 import java.security.CodeSigner;
 import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
 import java.util.zip.ZipEntry;
 
 /**
@@ -114,8 +114,12 @@
      * entry or {@code null} if none exists. Make sure that the everything is
      * read from the input stream before calling this method, or else the method
      * returns {@code null}.
+     * <p>
+     * This method returns all the signers' unverified chains concatenated
+     * together in one array. To know which certificates were tied to the
+     * private keys that made the signatures on this entry, see
+     * {@link #getCodeSigners()} instead.
      *
-     * @return the certificate for this entry.
      * @see java.security.cert.Certificate
      */
     public Certificate[] getCertificates() {
@@ -126,7 +130,27 @@
         if (jarVerifier == null) {
             return null;
         }
-        return jarVerifier.getCertificates(getName());
+
+        Certificate[][] certChains = jarVerifier.getCertificateChains(getName());
+        if (certChains == null) {
+            return null;
+        }
+
+        // Measure number of certs.
+        int count = 0;
+        for (Certificate[] chain : certChains) {
+            count += chain.length;
+        }
+
+        // Create new array and copy all the certs into it.
+        Certificate[] certs = new Certificate[count];
+        int i = 0;
+        for (Certificate[] chain : certChains) {
+            System.arraycopy(chain, 0, certs, i, chain.length);
+            i += chain.length;
+        }
+
+        return certs;
     }
 
     void setAttributes(Attributes attrib) {
@@ -138,68 +162,60 @@
      * JAR file. If there is no such code signer, it returns {@code null}. Make
      * sure that the everything is read from the input stream before calling
      * this method, or else the method returns {@code null}.
+     * <p>
+     * Only the digital signature on the entry is cryptographically verified.
+     * None of the certificates in the the {@link CertPath} returned from
+     * {@link CodeSigner#getSignerCertPath()} are verified and must be verified
+     * by the caller if needed. See {@link CertPathValidator} for more
+     * information.
      *
-     * @return the code signers for the JAR entry.
+     * @return an array of CodeSigner for this JAR entry.
      * @see CodeSigner
      */
     public CodeSigner[] getCodeSigners() {
+        if (parentJar == null) {
+            return null;
+        }
+
+        JarVerifier jarVerifier = parentJar.verifier;
+        if (jarVerifier == null) {
+            return null;
+        }
+
         if (signers == null) {
-            signers = getCodeSigners(getCertificates());
+            signers = getCodeSigners(jarVerifier.getCertificateChains(getName()));
         }
         if (signers == null) {
             return null;
         }
 
-        CodeSigner[] tmp = new CodeSigner[signers.length];
-        System.arraycopy(signers, 0, tmp, 0, tmp.length);
-        return tmp;
+        return signers.clone();
     }
 
-    private CodeSigner[] getCodeSigners(Certificate[] certs) {
-        if (certs == null) {
+    private CodeSigner[] getCodeSigners(Certificate[][] certChains) {
+        if (certChains == null) {
             return null;
         }
 
-        X500Principal prevIssuer = null;
-        ArrayList<Certificate> list = new ArrayList<Certificate>(certs.length);
-        ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>();
+        ArrayList<CodeSigner> asigners = new ArrayList<CodeSigner>(certChains.length);
 
-        for (Certificate element : certs) {
-            if (!(element instanceof X509Certificate)) {
-                // Only X509Certificate-s are taken into account - see API spec.
-                continue;
-            }
-            X509Certificate x509 = (X509Certificate) element;
-            if (prevIssuer != null) {
-                X500Principal subj = x509.getSubjectX500Principal();
-                if (!prevIssuer.equals(subj)) {
-                    // Ok, this ends the previous chain,
-                    // so transform this one into CertPath ...
-                    addCodeSigner(asigners, list);
-                    // ... and start a new one
-                    list.clear();
-                }// else { it's still the same chain }
-
-            }
-            prevIssuer = x509.getIssuerX500Principal();
-            list.add(x509);
-        }
-        if (!list.isEmpty()) {
-            addCodeSigner(asigners, list);
-        }
-        if (asigners.isEmpty()) {
-            // 'signers' is 'null' already
-            return null;
+        for (Certificate[] chain : certChains) {
+            addCodeSigner(asigners, chain);
         }
 
         CodeSigner[] tmp = new CodeSigner[asigners.size()];
         asigners.toArray(tmp);
         return tmp;
-
     }
 
-    private void addCodeSigner(ArrayList<CodeSigner> asigners,
-            List<Certificate> list) {
+    private void addCodeSigner(ArrayList<CodeSigner> asigners, Certificate[] certs) {
+        for (Certificate cert : certs) {
+            // Only X509Certificate instances are counted. See API spec.
+            if (!(cert instanceof X509Certificate)) {
+                return;
+            }
+        }
+
         CertPath certPath = null;
         if (!isFactoryChecked) {
             try {
@@ -214,7 +230,7 @@
             return;
         }
         try {
-            certPath = factory.generateCertPath(list);
+            certPath = factory.generateCertPath(Arrays.asList(certs));
         } catch (CertificateException ex) {
             // do nothing
         }
diff --git a/luni/src/main/java/java/util/jar/JarVerifier.java b/luni/src/main/java/java/util/jar/JarVerifier.java
index c545a02..467e298 100644
--- a/luni/src/main/java/java/util/jar/JarVerifier.java
+++ b/luni/src/main/java/java/util/jar/JarVerifier.java
@@ -27,7 +27,6 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
@@ -72,8 +71,8 @@
     private final Hashtable<String, Certificate[]> certificates =
             new Hashtable<String, Certificate[]>(5);
 
-    private final Hashtable<String, Certificate[]> verifiedEntries =
-            new Hashtable<String, Certificate[]>();
+    private final Hashtable<String, Certificate[][]> verifiedEntries =
+            new Hashtable<String, Certificate[][]>();
 
     /**
      * Stores and a hash and a message digest and verifies that massage digest
@@ -87,16 +86,16 @@
 
         private final byte[] hash;
 
-        private final Certificate[] certificates;
+        private final Certificate[][] certChains;
 
-        private final Hashtable<String, Certificate[]> verifiedEntries;
+        private final Hashtable<String, Certificate[][]> verifiedEntries;
 
         VerifierEntry(String name, MessageDigest digest, byte[] hash,
-                Certificate[] certificates, Hashtable<String, Certificate[]> verifedEntries) {
+                Certificate[][] certChains, Hashtable<String, Certificate[][]> verifedEntries) {
             this.name = name;
             this.digest = digest;
             this.hash = hash;
-            this.certificates = certificates;
+            this.certChains = certChains;
             this.verifiedEntries = verifedEntries;
         }
 
@@ -132,7 +131,7 @@
             if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
                 throw invalidDigest(JarFile.MANIFEST_NAME, name, name);
             }
-            verifiedEntries.put(name, certificates);
+            verifiedEntries.put(name, certChains);
         }
     }
 
@@ -185,7 +184,7 @@
             return null;
         }
 
-        ArrayList<Certificate> certs = new ArrayList<Certificate>();
+        ArrayList<Certificate[]> certChains = new ArrayList<Certificate[]>();
         Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator();
         while (it.hasNext()) {
             Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
@@ -195,16 +194,16 @@
                 String signatureFile = entry.getKey();
                 Certificate[] certChain = certificates.get(signatureFile);
                 if (certChain != null) {
-                    Collections.addAll(certs, certChain);
+                    certChains.add(certChain);
                 }
             }
         }
 
         // entry is not signed
-        if (certs.isEmpty()) {
+        if (certChains.isEmpty()) {
             return null;
         }
-        Certificate[] certificatesArray = certs.toArray(new Certificate[certs.size()]);
+        Certificate[][] certChainsArray = certChains.toArray(new Certificate[certChains.size()][]);
 
         for (int i = 0; i < DIGEST_ALGORITHMS.length; i++) {
             final String algorithm = DIGEST_ALGORITHMS[i];
@@ -216,9 +215,8 @@
 
             try {
                 return new VerifierEntry(name, MessageDigest.getInstance(algorithm), hashBytes,
-                        certificatesArray, verifiedEntries);
-            } catch (NoSuchAlgorithmException e) {
-                // ignored
+                        certChainsArray, verifiedEntries);
+            } catch (NoSuchAlgorithmException ignored) {
             }
         }
         return null;
@@ -396,20 +394,16 @@
     }
 
     /**
-     * Returns all of the {@link java.security.cert.Certificate} instances that
+     * Returns all of the {@link java.security.cert.Certificate} chains that
      * were used to verify the signature on the JAR entry called
-     * {@code name}.
+     * {@code name}. Callers must not modify the returned arrays.
      *
      * @param name
      *            the name of a JAR entry.
-     * @return an array of {@link java.security.cert.Certificate}.
+     * @return an array of {@link java.security.cert.Certificate} chains.
      */
-    Certificate[] getCertificates(String name) {
-        Certificate[] verifiedCerts = verifiedEntries.get(name);
-        if (verifiedCerts == null) {
-            return null;
-        }
-        return verifiedCerts.clone();
+    Certificate[][] getCertificateChains(String name) {
+        return verifiedEntries.get(name);
     }
 
     /**
diff --git a/luni/src/main/java/java/util/jar/StrictJarFile.java b/luni/src/main/java/java/util/jar/StrictJarFile.java
index fa175d8..4a8af5f 100644
--- a/luni/src/main/java/java/util/jar/StrictJarFile.java
+++ b/luni/src/main/java/java/util/jar/StrictJarFile.java
@@ -87,16 +87,51 @@
     }
 
     /**
-     * Return all certificates for a given {@link ZipEntry} belonging to this jar.
+     * Return all certificate chains for a given {@link ZipEntry} belonging to this jar.
      * This method MUST be called only after fully exhausting the InputStream belonging
      * to this entry.
      *
      * Returns {@code null} if this jar file isn't signed or if this method is
      * called before the stream is processed.
      */
+    public Certificate[][] getCertificateChains(ZipEntry ze) {
+        if (isSigned) {
+            return verifier.getCertificateChains(ze.getName());
+        }
+
+        return null;
+    }
+
+    /**
+     * Return all certificates for a given {@link ZipEntry} belonging to this jar.
+     * This method MUST be called only after fully exhausting the InputStream belonging
+     * to this entry.
+     *
+     * Returns {@code null} if this jar file isn't signed or if this method is
+     * called before the stream is processed.
+     *
+     * @deprecated Switch callers to use getCertificateChains instead
+     */
+    @Deprecated
     public Certificate[] getCertificates(ZipEntry ze) {
         if (isSigned) {
-            return verifier.getCertificates(ze.getName());
+            Certificate[][] certChains = verifier.getCertificateChains(ze.getName());
+
+            // Measure number of certs.
+            int count = 0;
+            for (Certificate[] chain : certChains) {
+                count += chain.length;
+            }
+
+            // Create new array and copy all the certs into it.
+            Certificate[] certs = new Certificate[count];
+            int i = 0;
+            for (Certificate[] chain : certChains) {
+                System.arraycopy(chain, 0, certs, i, chain.length);
+                i += chain.length;
+            }
+
+            return certs;
         }
 
         return null;
diff --git a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
index 65c8b03..fa11371 100644
--- a/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
+++ b/luni/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java
@@ -154,7 +154,10 @@
         int suffixLength = cn.length() - (asterisk + 1);
         int suffixStart = hostName.length() - suffixLength;
         if (hostName.indexOf('.', asterisk) < suffixStart) {
-            return false; // wildcard '*' can't match a '.'
+            // TODO: remove workaround for *.clients.google.com http://b/5426333
+            if (!hostName.endsWith(".clients.google.com")) {
+                return false; // wildcard '*' can't match a '.'
+            }
         }
 
         if (!hostName.regionMatches(suffixStart, cn, asterisk + 1, suffixLength)) {
diff --git a/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java b/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java
index c3c1606..25ab76f 100644
--- a/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java
+++ b/luni/src/main/java/javax/net/ssl/DistinguishedNameParser.java
@@ -17,6 +17,9 @@
 
 package javax.net.ssl;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import javax.security.auth.x500.X500Principal;
 
 /**
@@ -406,4 +409,71 @@
             }
         }
     }
+
+    /**
+     * Parses the DN and returns all values for an attribute type, in
+     * the order of decreasing significance (most significant first).
+     *
+     * @param attributeType attribute type to look for (e.g. "ca")
+     */
+    public List<String> getAllMostSpecificFirst(String attributeType) {
+        // Initialize internal state.
+        pos = 0;
+        beg = 0;
+        end = 0;
+        cur = 0;
+        chars = dn.toCharArray();
+        List<String> result = Collections.emptyList();
+
+        String attType = nextAT();
+        if (attType == null) {
+            return result;
+        }
+        while (pos < length) {
+            String attValue = "";
+
+            switch (chars[pos]) {
+            case '"':
+                attValue = quotedAV();
+                break;
+            case '#':
+                attValue = hexAV();
+                break;
+            case '+':
+            case ',':
+            case ';': // compatibility with RFC 1779: semicolon can separate RDNs
+                //empty attribute value
+                break;
+            default:
+                attValue = escapedAV();
+            }
+
+            // Values are ordered from most specific to least specific
+            // due to the RFC2253 formatting. So take the first match
+            // we see.
+            if (attributeType.equalsIgnoreCase(attType)) {
+                if (result.isEmpty()) {
+                    result = new ArrayList<String>();
+                }
+                result.add(attValue);
+            }
+
+            if (pos >= length) {
+                break;
+            }
+
+            if (chars[pos] == ',' || chars[pos] == ';') {
+            } else if (chars[pos] != '+') {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+
+            pos++;
+            attType = nextAT();
+            if (attType == null) {
+                throw new IllegalStateException("Malformed DN: " + dn);
+            }
+        }
+
+        return result;
+    }
 }
diff --git a/luni/src/main/java/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index d09e442..bf4b448 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -52,6 +52,7 @@
 
     public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException { return os.accept(fd, peerAddress); }
     public boolean access(String path, int mode) throws ErrnoException { return os.access(path, mode); }
+    public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException { return os.android_getaddrinfo(node, hints, netId); }
     public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException { os.bind(fd, address, port); }
     public void chmod(String path, int mode) throws ErrnoException { os.chmod(path, mode); }
     public void chown(String path, int uid, int gid) throws ErrnoException { os.chown(path, uid, gid); }
@@ -73,7 +74,6 @@
     public void fsync(FileDescriptor fd) throws ErrnoException { os.fsync(fd); }
     public void ftruncate(FileDescriptor fd, long length) throws ErrnoException { os.ftruncate(fd, length); }
     public String gai_strerror(int error) { return os.gai_strerror(error); }
-    public InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException { return os.getaddrinfo(node, hints); }
     public int getegid() { return os.getegid(); }
     public int geteuid() { return os.geteuid(); }
     public int getgid() { return os.getgid(); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index a537aeb..511bb27 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -43,6 +43,7 @@
 public interface Os {
     public FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
     public boolean access(String path, int mode) throws ErrnoException;
+    public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
     public void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public void chmod(String path, int mode) throws ErrnoException;
     public void chown(String path, int uid, int gid) throws ErrnoException;
@@ -64,7 +65,6 @@
     public void fsync(FileDescriptor fd) throws ErrnoException;
     public void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
     public String gai_strerror(int error);
-    public InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException;
     public int getegid();
     public int geteuid();
     public int getgid();
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index 7551190..f5eaaa3 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -46,6 +46,7 @@
 
     public native FileDescriptor accept(FileDescriptor fd, InetSocketAddress peerAddress) throws ErrnoException, SocketException;
     public native boolean access(String path, int mode) throws ErrnoException;
+    public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;
     public native void bind(FileDescriptor fd, InetAddress address, int port) throws ErrnoException, SocketException;
     public native void chmod(String path, int mode) throws ErrnoException;
     public native void chown(String path, int uid, int gid) throws ErrnoException;
@@ -67,7 +68,6 @@
     public native void fsync(FileDescriptor fd) throws ErrnoException;
     public native void ftruncate(FileDescriptor fd, long length) throws ErrnoException;
     public native String gai_strerror(int error);
-    public native InetAddress[] getaddrinfo(String node, StructAddrinfo hints) throws GaiException;
     public native int getegid();
     public native int geteuid();
     public native int getgid();
diff --git a/luni/src/main/native/Portability.h b/luni/src/main/native/Portability.h
index fb60ed4..1520311 100644
--- a/luni/src/main/native/Portability.h
+++ b/luni/src/main/native/Portability.h
@@ -65,7 +65,7 @@
 #include <sys/param.h>
 #include <sys/mount.h>
 
-#else
+#else  // defined(__APPLE__)
 
 // Bionic or glibc.
 
@@ -73,6 +73,15 @@
 #include <sys/sendfile.h>
 #include <sys/statvfs.h>
 
-#endif
+#endif  // defined(__APPLE__)
+
+#if !defined(__BIONIC__)
+#include <netdb.h>
+#include "../../bionic/libc/dns/include/resolv_netid.h"
+inline int android_getaddrinfofornet(const char *hostname, const char *servname,
+    const struct addrinfo *hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo **res) {
+  return getaddrinfo(hostname, servname, hints, res);
+}
+#endif  // !defined(__BIONIC__)
 
 #endif  // PORTABILITY_H_included
diff --git a/luni/src/main/native/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index 51dd8a1..e8e8efb 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -25,6 +25,7 @@
 #include "NetworkUtilities.h"
 #include "Portability.h"
 #include "readlink.h"
+#include "../../bionic/libc/dns/include/resolv_netid.h"  // For android_getaddrinfofornet.
 #include "ScopedBytes.h"
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
@@ -661,7 +662,8 @@
     return env->NewStringUTF(gai_strerror(error));
 }
 
-static jobjectArray Posix_getaddrinfo(JNIEnv* env, jobject, jstring javaNode, jobject javaHints) {
+static jobjectArray Posix_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
+        jobject javaHints, jint netId) {
     ScopedUtfChars node(env, javaNode);
     if (node.c_str() == NULL) {
         return NULL;
@@ -681,10 +683,10 @@
 
     addrinfo* addressList = NULL;
     errno = 0;
-    int rc = getaddrinfo(node.c_str(), NULL, &hints, &addressList);
+    int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
     UniquePtr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
     if (rc != 0) {
-        throwGaiException(env, "getaddrinfo", rc);
+        throwGaiException(env, "android_getaddrinfo", rc);
         return NULL;
     }
 
@@ -694,7 +696,7 @@
         if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
             ++addressCount;
         } else {
-            ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
         }
     }
     if (addressCount == 0) {
@@ -712,7 +714,7 @@
     for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
         if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
             // Unknown address family. Skip this address.
-            ALOGE("getaddrinfo unexpected ai_family %i", ai->ai_family);
+            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
             continue;
         }
 
@@ -1537,6 +1539,7 @@
 static JNINativeMethod gMethods[] = {
     NATIVE_METHOD(Posix, accept, "(Ljava/io/FileDescriptor;Ljava/net/InetSocketAddress;)Ljava/io/FileDescriptor;"),
     NATIVE_METHOD(Posix, access, "(Ljava/lang/String;I)Z"),
+    NATIVE_METHOD(Posix, android_getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;I)[Ljava/net/InetAddress;"),
     NATIVE_METHOD(Posix, bind, "(Ljava/io/FileDescriptor;Ljava/net/InetAddress;I)V"),
     NATIVE_METHOD(Posix, chmod, "(Ljava/lang/String;I)V"),
     NATIVE_METHOD(Posix, chown, "(Ljava/lang/String;II)V"),
@@ -1558,7 +1561,6 @@
     NATIVE_METHOD(Posix, fsync, "(Ljava/io/FileDescriptor;)V"),
     NATIVE_METHOD(Posix, ftruncate, "(Ljava/io/FileDescriptor;J)V"),
     NATIVE_METHOD(Posix, gai_strerror, "(I)Ljava/lang/String;"),
-    NATIVE_METHOD(Posix, getaddrinfo, "(Ljava/lang/String;Landroid/system/StructAddrinfo;)[Ljava/net/InetAddress;"),
     NATIVE_METHOD(Posix, getegid, "()I"),
     NATIVE_METHOD(Posix, geteuid, "()I"),
     NATIVE_METHOD(Posix, getgid, "()I"),
diff --git a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
index 6d033d3..1475a63 100644
--- a/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
+++ b/luni/src/test/java/com/android/org/bouncycastle/jce/provider/CertBlacklistTest.java
@@ -109,6 +109,24 @@
                     "3xQAyMuOHm72exJljYFqIsiNvGE0KufCqCuH1PD97IXMrLlwGmKKg5jP349lySBpJjm6RDqCTT+6" +
                     "dUl2jkVbeNmco99Y7AOdtLsOdXBMCo5x8lK8zwQWFrzEms0joHXCpWfGWA==";
 
+    public static final String ANSSI = "" +
+                    "MIIDbDCCAlSgAwIBAgIDAx2nMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNVBAYTAkZSMQ4wDAYDVQQK" +
+                    "EwVER1RQRTEsMCoGA1UEAxMjQUMgREdUUEUgU2lnbmF0dXJlIEF1dGhlbnRpZmljYXRpb24wHhcN" +
+                    "MTMwNzE4MTAwNTI4WhcNMTQwNzE4MTAwNTI4WjA+MQswCQYDVQQGEwJGUjETMBEGA1UECgwKREcg" +
+                    "VHLDqXNvcjEaMBgGA1UEAwwRQUMgREcgVHLDqXNvciBTU0wwggEiMA0GCSqGSIb3DQEBAQUAA4IB" +
+                    "DwAwggEKAoIBAQDI0WFSUyY+MmtFkqFjTefoFyDgh9b1C/2YvSIvT8oCH62JWT5rpeTCZwaXbqWc" +
+                    "jaNfzggqaFsokqfhBif43HNHNtNJmvKE32VcuLB0SpsLR/1VeTd9F99C1JeHVa+nelumOHEfouX8" +
+                    "rRFrxNXNIYTVeiENT8Y2YqRb/XAril9g7i674uFzLiNR/t/N/F8Exujv9U8m8rmgud/+tG9WDRaD" +
+                    "Jwoj3ZFCOnL5qLnSUEcS6TzWpozLmC2JVO5GZKGGd7qC9FjdBkVilkbVIEGSrYvz2Uz2v5IGqMBI" +
+                    "QaFL/kSYWxGTaedTOk2drFEApp9AEPTfv1NwCWBfegsGQrHUROM3AgMBAAGjZjBkMBIGA1UdEwEB" +
+                    "/wQIMAYBAf8CAQQwHQYDVR0OBBYEFAAMW8lJqJW0DtAv5p3Mjogxvh9lMB8GA1UdIwQYMBaAFOnb" +
+                    "kI/9W5nkFTvwYlyn5A1Y6IeZMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAtDfG" +
+                    "HkHOLW2d9fiMtwtkEwDauISJLJyCjoRmawzmQbIZXq7HaLliVfE0sdfKUm0iQ0im1/CpnJLPoTeK" +
+                    "yBHvNu1ubLc2m+9dabAYhF3pVdKC+gNaAzBXZ9Gt0p1CLk1lf8Hg+R10HN2IPCv7V/crz2Ga+c23" +
+                    "4P3pfwYW8+Nd7alGCuvqot6UYXOlheF7zWUkHn6z6tvY+9oMDHKSUAthhA/FB50JgJU89zyTv1eg" +
+                    "Y3ldKwvYBW3W3yNZdTHbPyNsPJdhqA55mDNsteE5YTp1PyySDb1MSVrbxDEruoH6ZE99Hob4Ih8A" +
+                    "mn7MHZatGClECgjXWFZ2Gxa7OUCaQpcH8g==";
+
     public CertBlacklistTest() throws IOException {
         tmpFile = File.createTempFile("test", "");
         DEFAULT_PUBKEYS = getDefaultPubkeys();
@@ -415,6 +433,20 @@
         assertEquals(bl.isPublicKeyBlackListed(pk), true);
     }
 
+    public void testANSSISerialBlacklist() throws Exception {
+        CertBlacklist bl = new CertBlacklist();
+        assertEquals(bl.isSerialNumberBlackListed(createSerialNumber(ANSSI)), true);
+    }
+
+    public void testANSSIIntermediatePubkeyBlacklist() throws Exception {
+        // build the public key
+        PublicKey pk = createPublicKey(ANSSI);
+        // set our blacklist path
+        CertBlacklist bl = new CertBlacklist();
+        // check to make sure it isn't blacklisted
+        assertEquals(bl.isPublicKeyBlackListed(pk), true);
+    }
+
     private static void printHash(String cert) throws Exception {
         System.out.println("CERTIFICATE PUBLIC KEY HASH: " + getHash(createPublicKey(cert)));
     }
diff --git a/luni/src/test/java/libcore/java/io/SerializationTest.java b/luni/src/test/java/libcore/java/io/SerializationTest.java
index d452c11..1002cf1 100644
--- a/luni/src/test/java/libcore/java/io/SerializationTest.java
+++ b/luni/src/test/java/libcore/java/io/SerializationTest.java
@@ -16,12 +16,15 @@
 
 package libcore.java.io;
 
-import java.io.IOException;
+import junit.framework.TestCase;
+
 import java.io.InvalidClassException;
+import java.io.InvalidObjectException;
 import java.io.ObjectStreamClass;
 import java.io.ObjectStreamField;
 import java.io.Serializable;
-import junit.framework.TestCase;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
 import libcore.util.SerializationTester;
 
 public final class SerializationTest extends TestCase {
@@ -61,6 +64,7 @@
         }
     }
 
+    @SuppressWarnings("unused") // Required for deserialization test
     static class SerialVersionUidChanged implements Serializable {
         private static final long serialVersionUID = 1L; // was 0L
         private int a;
@@ -77,7 +81,259 @@
         }
     }
 
+    @SuppressWarnings("unused") // Required for deserialization test
     static class FieldsChanged implements Serializable {
         private int b; // was 'a'
     }
+
+    public static boolean wasSerializableInitializedFlag = false;
+
+    @SuppressWarnings("unused")  // Required for deserialization test.
+    public static class WasSerializable /* implements java.io.Serializable */ {
+        static final long serialVersionUID = 0L;
+        static {
+            SerializationTest.wasSerializableInitializedFlag = true;
+        }
+        private int i;
+    }
+
+    public void testDeserializeWasSerializableClass() throws Exception {
+        // This was created by serializing a WasSerializable when it was serializable.
+        // String s = SerializationTester.serializeHex(new WasSerializable());
+        final String s = "aced0005737200316c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e546573742457617353657269616c697a61626c65000000000000000002000149000169787000000"
+                + "000";
+
+        wasSerializableInitializedFlag = false;
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidClassException expected) {
+        }
+        assertFalse(wasSerializableInitializedFlag);
+    }
+
+    // The WasExternalizable class before it was modified.
+    /*
+    public static class WasExternalizable implements Externalizable {
+        static final long serialVersionUID = 0L;
+
+        @Override
+        public void readExternal(ObjectInput input) throws IOException, ClassNotFoundException {
+
+        }
+
+        @Override
+        public void writeExternal(ObjectOutput output) throws IOException {
+
+        }
+    }
+    */
+
+    public static boolean wasExternalizableInitializedFlag = false;
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public static class WasExternalizable implements Serializable {
+        static final long serialVersionUID = 0L;
+        static {
+            SerializationTest.wasExternalizableInitializedFlag = true;
+        }
+
+    }
+
+    public void testDeserializeWasExternalizableClass() throws Exception {
+        // This was created by serializing a WasExternalizable when it was externalizable.
+        // String s = SerializationTester.serializeHex(new WasExternalizable());
+        final String s = "aced0005737200336c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e546573742457617345787465726e616c697a61626c6500000000000000000c0000787078";
+
+        wasExternalizableInitializedFlag = false;
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidClassException expected) {
+        }
+        // Unlike other similar tests static initialization will take place if the local class is
+        // Serializable or Externalizable because serialVersionUID field is accessed.
+        // The RI appears to do the same.
+        assertTrue(wasExternalizableInitializedFlag);
+    }
+
+    // The WasEnum class before it was modified.
+    /*
+    public enum WasEnum {
+        VALUE
+    }
+    */
+
+    public static boolean wasEnumInitializedFlag = false;
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public static class WasEnum {
+        static final long serialVersionUID = 0L;
+        static {
+            SerializationTest.wasEnumInitializedFlag = true;
+        }
+    }
+
+    public void testDeserializeWasEnum() throws Exception {
+        // This was created by serializing a WasEnum when it was an enum.
+        // String s = SerializationTester.serializeHex(WasEnum.VALUE);
+        final String s = "aced00057e7200296c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e5465737424576173456e756d00000000000000001200007872000e6a6176612e6c616e672e456e7"
+                + "56d0000000000000000120000787074000556414c5545";
+
+        wasEnumInitializedFlag = false;
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidClassException expected) {
+        }
+        assertFalse(wasEnumInitializedFlag);
+    }
+
+    // The WasObject class before it was modified.
+    /*
+    public static class WasObject implements java.io.Serializable {
+        static final long serialVersionUID = 0L;
+        private int i;
+    }
+    */
+
+    public static boolean wasObjectInitializedFlag;
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public enum WasObject {
+        VALUE;
+
+        static {
+            SerializationTest.wasObjectInitializedFlag = true;
+        }
+    }
+
+    public void testDeserializeWasObject() throws Exception {
+        // This was created by serializing a WasObject when it wasn't yet an enum.
+        // String s = SerializationTester.serializeHex(new WasObject());
+        final String s = "aced00057372002b6c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e54657374245761734f626a656374000000000000000002000149000169787000000000";
+
+        wasObjectInitializedFlag = false;
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidClassException expected) {
+        }
+        assertFalse(wasObjectInitializedFlag);
+    }
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public enum EnumMissingValue {
+        /*MISSING_VALUE*/
+    }
+
+    public void testDeserializeEnumMissingValue() throws Exception {
+        // This was created by serializing a EnumMissingValue when it had MISSING_VALUE.
+        // String s = SerializationTester.serializeHex(EnumMissingValue.MISSING_VALUE);
+        final String s = "aced00057e7200326c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e5465737424456e756d4d697373696e6756616c756500000000000000001200007872000e6a61766"
+                + "12e6c616e672e456e756d0000000000000000120000787074000d4d495353494e475f56414c5545";
+
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidObjectException expected) {
+        }
+    }
+
+
+    public static Object hasStaticInitializerObject;
+
+    public static class HasStaticInitializer implements Serializable {
+        static {
+            SerializationTest.hasStaticInitializerObject = new Object();
+        }
+    }
+
+    public void testDeserializeStaticInitializerIsRunEventually() throws Exception {
+        // This was created by serializing a HasStaticInitializer
+        // String s = SerializationTester.serializeHex(new HasStaticInitializer());
+        final String s = "aced0005737200366c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6"
+                + "e5465737424486173537461746963496e697469616c697a6572138aa8ed9e9b660a0200007870";
+
+        // Confirm the ClassLoader behaves as it should.
+        Class.forName(
+                HasStaticInitializer.class.getName(),
+                false /* shouldInitialize */,
+                Thread.currentThread().getContextClassLoader());
+        assertNull(hasStaticInitializerObject);
+
+        SerializationTester.deserializeHex(s);
+
+        assertNotNull(hasStaticInitializerObject);
+    }
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public static /*interface*/ class WasInterface {
+    }
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public static class SerializableInvocationHandler implements InvocationHandler, Serializable {
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) {
+            return null;
+        }
+    }
+
+    public void testDeserializeProxyWasInterface() throws Exception {
+        // This was created by serializing a proxy referencing WasInterface when it was an
+        // interface.
+        // Object o = Proxy.newProxyInstance(
+        //        Thread.currentThread().getContextClassLoader(),
+        //        new Class[] { WasInterface.class },
+        //        new SerializableInvocationHandler());
+        // String s = SerializationTester.serializeHex(o);
+        final String s = "aced0005737d00000001002e6c6962636f72652e6a6176612e696f2e53657269616c697a6"
+                + "174696f6e5465737424576173496e74657266616365787200176a6176612e6c616e672e7265666c6"
+                + "563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f72656"
+                + "66c6563742f496e766f636174696f6e48616e646c65723b78707372003f6c6962636f72652e6a617"
+                + "6612e696f2e53657269616c697a6174696f6e546573742453657269616c697a61626c65496e766f6"
+                + "36174696f6e48616e646c6572e6ceffa2941ee3210200007870";
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (ClassNotFoundException expected) {
+        }
+    }
+
+    @SuppressWarnings("unused") // Required for deserialization test
+    public static class WasSerializableInvocationHandler
+            implements InvocationHandler /*, Serializable*/ {
+        static final long serialVersionUID = 0L;
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) {
+            return null;
+        }
+    }
+
+    public void testDeserializeProxyInvocationHandlerWasSerializable() throws Exception {
+        // This was created by serializing a proxy referencing WasSerializableInvocationHandler when
+        // it was Serializable.
+        // Object o = Proxy.newProxyInstance(
+        //        Thread.currentThread().getContextClassLoader(),
+        //        new Class[] { Comparable.class },
+        //        new WasSerializableInvocationHandler());
+        // String s = SerializationTester.serializeHex(o);
+        final String s = "aced0005737d0000000100146a6176612e6c616e672e436f6d70617261626c65787200176"
+                + "a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c00016874002"
+                + "54c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707"
+                + "37200426c6962636f72652e6a6176612e696f2e53657269616c697a6174696f6e546573742457617"
+                + "353657269616c697a61626c65496e766f636174696f6e48616e646c6572000000000000000002000"
+                + "07870";
+        try {
+            SerializationTester.deserializeHex(s);
+            fail();
+        } catch (InvalidClassException expected) {
+        }
+    }
 }
diff --git a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
index e7fdb1f..eb0e3d0 100644
--- a/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyPairGeneratorTest.java
@@ -56,63 +56,28 @@
 public class KeyPairGeneratorTest extends TestCase {
 
     public void test_providerCount() {
-        Provider[] providers = Security.getProviders();
-        // We expect there to be at least one provider.
-        assertTrue(providers.length > 0);
-        // If this fails remember to add _provider methods below. This test is sharded because it
-        // takes a long time to execute.
-        assertTrue(providers.length < 10);
+        // If this fails remember to add/remove _provider methods below. This test is sharded
+        // because it takes so long.
+        assertEquals(4, Security.getProviders().length);
     }
 
     public void test_getInstance_provider0() throws Exception {
-        test_getInstance(0);
+        test_getInstance(Security.getProviders()[0]);
     }
 
     public void test_getInstance_provider1() throws Exception {
-        test_getInstance(1);
+        test_getInstance(Security.getProviders()[1]);
     }
 
     public void test_getInstance_provider2() throws Exception {
-        test_getInstance(2);
+        test_getInstance(Security.getProviders()[2]);
     }
 
     public void test_getInstance_provider3() throws Exception {
-        test_getInstance(3);
+        test_getInstance(Security.getProviders()[3]);
     }
 
-    public void test_getInstance_provider4() throws Exception {
-        test_getInstance(4);
-    }
-
-    public void test_getInstance_provider5() throws Exception {
-        test_getInstance(5);
-    }
-
-    public void test_getInstance_provider6() throws Exception {
-        test_getInstance(6);
-    }
-
-    public void test_getInstance_provider7() throws Exception {
-        test_getInstance(7);
-    }
-
-    public void test_getInstance_provider8() throws Exception {
-        test_getInstance(8);
-    }
-
-    public void test_getInstance_provider9() throws Exception {
-        test_getInstance(9);
-    }
-
-    private void test_getInstance(int providerIndex) throws Exception {
-        Provider[] providers = Security.getProviders();
-        if (providerIndex >= providers.length) {
-            // Providers can be added by vendors and other tests. We do not
-            // specify a fixed number and silenty pass if the provider at the
-            // specified index does not exist.
-            return;
-        }
-        Provider provider = providers[providerIndex];
+    private void test_getInstance(Provider provider) throws Exception {
         Set<Provider.Service> services = provider.getServices();
         for (Provider.Service service : services) {
             String type = service.getType();
diff --git a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
index 0b194f5..e5a6cd8 100644
--- a/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/StrictJarFileTest.java
@@ -122,6 +122,7 @@
             jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
             if ("Test.class".equals(zipEntry.getName())) {
                 assertNotNull(jarFile.getCertificates(zipEntry));
+                assertNotNull(jarFile.getCertificateChains(zipEntry));
             }
         }
     }
diff --git a/luni/src/test/java/libcore/javax/net/ssl/DistinguishedNameParserTest.java b/luni/src/test/java/libcore/javax/net/ssl/DistinguishedNameParserTest.java
index 723c697..91c596f 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/DistinguishedNameParserTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/DistinguishedNameParserTest.java
@@ -19,38 +19,50 @@
 import javax.net.ssl.DistinguishedNameParser;
 import javax.security.auth.x500.X500Principal;
 import junit.framework.TestCase;
+import java.util.Arrays;
 
 public final class DistinguishedNameParserTest extends TestCase {
-    public void testGetFirstCn() {
-        assertFirstCn("", null);
-        assertFirstCn("ou=xxx", null);
-        assertFirstCn("ou=xxx,cn=xxx", "xxx");
-        assertFirstCn("ou=xxx+cn=yyy,cn=zzz+cn=abc", "yyy");
-        assertFirstCn("cn=a,cn=b", "a");
-        assertFirstCn("cn=Cc,cn=Bb,cn=Aa", "Cc");
-        assertFirstCn("cn=imap.gmail.com", "imap.gmail.com");
+    public void testGetCns() {
+        assertCns("");
+        assertCns("ou=xxx");
+        assertCns("ou=xxx,cn=xxx", "xxx");
+        assertCns("ou=xxx+cn=yyy,cn=zzz+cn=abc", "yyy", "zzz", "abc");
+        assertCns("cn=a,cn=b", "a", "b");
+        assertCns("cn=Cc,cn=Bb,cn=Aa", "Cc", "Bb", "Aa");
+        assertCns("cn=imap.gmail.com", "imap.gmail.com");
+        assertCns("l=\"abcn=a,b\", cn=c", "c");
     }
 
-    public void testGetFirstCnWithOid() {
-        assertFirstCn("2.5.4.3=a,ou=xxx", "a");
+    public void testGetCnsWithOid() {
+        assertCns("2.5.4.3=a,ou=xxx", "a");
     }
 
-    public void testGetFirstCnWithQuotedStrings() {
-        assertFirstCn("cn=\"\\\" a ,=<>#;\"", "\" a ,=<>#;");
-        assertFirstCn("cn=abc\\,def", "abc,def");
+    public void testGetCnsWithQuotedStrings() {
+        assertCns("cn=\"\\\" a ,=<>#;\"", "\" a ,=<>#;");
+        assertCns("cn=abc\\,def", "abc,def");
     }
 
-    public void testGetFirstCnWithUtf8() {
-        assertFirstCn("cn=Lu\\C4\\8Di\\C4\\87", "\u004c\u0075\u010d\u0069\u0107");
+    public void testGetCnsWithUtf8() {
+        assertCns("cn=Lu\\C4\\8Di\\C4\\87", "\u004c\u0075\u010d\u0069\u0107");
     }
 
-    public void testGetFirstCnWithWhitespace() {
-        assertFirstCn("ou=a, cn=  a  b  ,o=x", "a  b");
-        assertFirstCn("cn=\"  a  b  \" ,o=x", "  a  b  ");
+    public void testGetCnsWithWhitespace() {
+        assertCns("ou=a, cn=  a  b  ,o=x", "a  b");
+        assertCns("cn=\"  a  b  \" ,o=x", "  a  b  ");
     }
 
-    private void assertFirstCn(String dn, String expected) {
+    private void assertCns(String dn, String... expected) {
         X500Principal principal = new X500Principal(dn);
-        assertEquals(dn, expected, new DistinguishedNameParser(principal).findMostSpecific("cn"));
+        DistinguishedNameParser parser = new DistinguishedNameParser(principal);
+
+        // Test getAllMostSpecificFirst
+        assertEquals(dn, Arrays.asList(expected), parser.getAllMostSpecificFirst("cn"));
+
+        // Test findMostSpecific
+        if (expected.length > 0) {
+            assertEquals(dn, expected[0], parser.findMostSpecific("cn"));
+        } else {
+            assertNull(dn, parser.findMostSpecific("cn"));
+        }
     }
 }
diff --git a/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar b/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar
new file mode 100644
index 0000000..7da4b59
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_ambiguousSignerArray.jar
Binary files differ
diff --git a/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar b/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar
new file mode 100644
index 0000000..23d7ae8
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_invalidChain.jar
Binary files differ
diff --git a/support/src/test/java/tests/resources/hyts_signed_validChain.jar b/support/src/test/java/tests/resources/hyts_signed_validChain.jar
new file mode 100644
index 0000000..d1f4c56
--- /dev/null
+++ b/support/src/test/java/tests/resources/hyts_signed_validChain.jar
Binary files differ