Merge "Fix a long standing bug within dvmHeapSourceGetObjectBitmaps.  All callers of this function assign the return value to an unsigned value even though this function returns -1 in the error case.  This causes the error checks to succeed in cases where it should otherwise fail. Rather than return -1 on error, I have elected to return 0 instead which just happens to be compatible with all current uses."
diff --git a/docs/embedded-vm-control.html b/docs/embedded-vm-control.html
index 0b279e8..1e54453 100644
--- a/docs/embedded-vm-control.html
+++ b/docs/embedded-vm-control.html
@@ -8,7 +8,7 @@
 <h1>Controlling the Embedded VM</h1>
 
 <ul>
-    <li><a href="#overview">Overview</a>
+    <li><a href="#introduction">Introduction</a> (read this first!)
     <li><a href="#checkjni">Extended JNI Checks</a>
     <li><a href="#assertions">Assertions</a>
     <li><a href="#verifier">Bytecode Verification and Optimization</a>
@@ -18,7 +18,7 @@
     <li><a href="#dexcheck">DEX File Checksums</a>
 </ul>
 
-<h2><a name="overview">Overview</a></h2>
+<h2><a name="introduction">Introduction (read this first!)</a></h2>
 
 <p>The Dalvik VM supports a variety of command-line arguments
 (use <code>adb shell dalvikvm -help</code> to get a summary), but
@@ -31,12 +31,13 @@
 issuing a shell command on the device like this:
 <pre>adb shell setprop &lt;name&gt; &lt;value&gt;</pre>
 
-<p>The Android runtime must be restarted before the changes will take
-effect (<code>adb shell stop; adb shell start</code>).  This is because the
+<p><strong>The Android runtime must be restarted before the changes will take
+effect</strong> (<code>adb shell stop; adb shell start</code>).  This is because the
 settings are processed in the "zygote" process, which starts early and stays
 around "forever".
 
-<p>You may not be able to set this as an unprivileged user.  You can use
+<p>You may not be able to set <code>dalvik.*</code> properties or restart
+the system as an unprivileged user.  You can use
 <code>adb root</code> or run the <code>su</code> command from the device
 shell on "userdebug" builds to become root first.  When in doubt,
 <pre>adb shell getprop &lt;name&gt;</pre>
@@ -48,7 +49,7 @@
 
 <p>Such changes will survive reboots, but will be lost if the data
 partition is wiped.  (Hint: create a <code>local.prop</code>
-on your workstation, then <code>adb push local.prop /data</code> .  Or,
+on your workstation, then <code>adb push local.prop /data</code>.  Or,
 use one-liners like
 <code>adb shell "echo name = value &gt;&gt; /data/local.prop"</code> -- note
 the quotes are important.)
diff --git a/docs/heap-profiling.html b/docs/heap-profiling.html
index 3c80b4a..a9c949e 100644
--- a/docs/heap-profiling.html
+++ b/docs/heap-profiling.html
@@ -11,6 +11,10 @@
 of the virtual heap.  This is very useful for debugging memory usage
 and looking for memory leaks.  Getting at the information can be tricky,
 but has become easier in recent releases.
+</p><p>
+In what follows, the version number refers to the software release
+running on the phone.  To take advantage of the DDMS integration, you will
+also need a sufficiently recent version of DDMS.
 
 
 <h2>Getting the data</h2>
@@ -148,6 +152,7 @@
 permission, which is required to write data to the SD card.  If you're
 accustomed to writing profile data to <code>/sdcard</code>, you will
 need to enable the permission in your application's manifest.
+</p>
 
 
 <h3>Android 2.0 ("Eclair")</h3>
@@ -157,8 +162,15 @@
 and click the "dump HPROF file" button in the top left.  This always
 writes files to the SD card, so
 you must have a card inserted and the permission enabled in your application.
+</p>
 
 
+<h3>Android 2.x ("Froyo")</h3>
+<p>
+DDMS heap dump requests are now streamed directly out of the VM, removing
+the external storage requirement.
+</p>
+
 <h2>Examining the data</h2>
 <p>
 The data file format was augmented slightly from the common hprof format,
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
index cfae706..ce3e95c 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -311,6 +311,16 @@
     public static native void dumpHprofData(String fileName) throws IOException;
 
     /**
+     * Collect "hprof" and send it to DDMS.  This will cause a GC.
+     *
+     * @throws UnsupportedOperationException if the VM was built without
+     *         HPROF support.
+     *
+     * @hide
+     */
+    public static native void dumpHprofDataDdms();
+
+    /**
      * Primes the register map cache.
      *
      * @hide
diff --git a/libcore/dom/src/test/java/org/w3c/domts/DOMTest.java b/libcore/dom/src/test/java/org/w3c/domts/DOMTest.java
index b39ea67..7dd8f26 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/DOMTest.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/DOMTest.java
@@ -165,8 +165,8 @@
           //
           //   if available use JDK 1.4's File.toURI().toString()
           //
-          Method method = File.class.getMethod("toURI", null);
-          Object uri = method.invoke(tempFile, null);
+          Method method = File.class.getMethod("toURI", (Class<?>) null);
+          Object uri = method.invoke(tempFile, (Class<?>) null);
           return uri.toString();
         }
         catch (NoSuchMethodException ex) {
diff --git a/libcore/dom/src/test/java/org/w3c/domts/LSDocumentBuilderFactory.java b/libcore/dom/src/test/java/org/w3c/domts/LSDocumentBuilderFactory.java
index 7ed0f54..b769602 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/LSDocumentBuilderFactory.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/LSDocumentBuilderFactory.java
@@ -272,8 +272,8 @@
     try {
       Class domImplRegistryClass = Class.forName(
           "org.w3c.dom.bootstrap.DOMImplementationRegistry");
-      Method newInstanceMethod = domImplRegistryClass.getMethod("newInstance", null);
-      Object domRegistry = newInstanceMethod.invoke(null, null);
+      Method newInstanceMethod = domImplRegistryClass.getMethod("newInstance", (Class<?>) null);
+      Object domRegistry = newInstanceMethod.invoke(null, (Class<?>) null);
       Method getDOMImplementationMethod = domImplRegistryClass.getMethod(
           "getDOMImplementation", new Class[] {String.class});
       impl = (DOMImplementation) getDOMImplementationMethod.invoke(domRegistry,
diff --git a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
index d2e38ca..f3484da 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue1.java
@@ -69,7 +69,7 @@
       attributes = testNode.getAttributes();
       titleAttr = (Attr) attributes.getNamedItem("class");
       value = titleAttr.getValue();
-      assertEquals("attrValue1", "Yα", value);
+      assertEquals("attrValue1", "Y\u03b1", value); // android-changed: GREEK LOWER CASE ALPHA
       }
    /**
     *  Gets URI that identifies the test.
diff --git a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
index fd5b211..814b693 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrgetvalue2.java
@@ -89,7 +89,7 @@
       firstChild = titleAttr.getFirstChild();
       retval = titleAttr.insertBefore(alphaRef, firstChild);
       value = titleAttr.getValue();
-      assertEquals("attrValue1", "αYα", value);
+      assertEquals("attrValue1", "\u03b1Y\u03b1", value); // android-changed: GREEK LOWER CASE ALPHA
       }
         
     }
diff --git a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
index c9a2e62..8ba4c57 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_attrspecifiedvaluechanged.java
@@ -71,7 +71,7 @@
       doc = (Document) load("hc_staff", true);
       addressList = doc.getElementsByTagName("acronym");
       testNode = addressList.item(2);
-      ((Element) /*Node */testNode).setAttribute("class", "Yα");
+      ((Element) /*Node */testNode).setAttribute("class", "Y\u03b1"); // android-changed: GREEK LOWER CASE ALPHA
       attributes = testNode.getAttributes();
       streetAttr = (Attr) attributes.getNamedItem("class");
       state = streetAttr.getSpecified();
diff --git a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
index e8d3268..36dc3f8 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_namednodemapinuseattributeerr.java
@@ -75,7 +75,7 @@
       elementList = doc.getElementsByTagName("acronym");
       firstNode = (Element) elementList.item(0);
       domesticAttr = doc.createAttribute("title");
-      domesticAttr.setValue("Yα");
+      domesticAttr.setValue("Y\u03b1"); // android-changed: GREEK LOWER CASE ALPHA
       setAttr = firstNode.setAttributeNode(domesticAttr);
       elementList = doc.getElementsByTagName("acronym");
       testNode = elementList.item(2);
diff --git a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
index 5694a4a..2a10501 100644
--- a/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
+++ b/libcore/dom/src/test/java/org/w3c/domts/level1/core/hc_textparseintolistofelements.java
@@ -72,13 +72,13 @@
       java.util.List result = new java.util.ArrayList();
       
       java.util.List expectedNormal = new java.util.ArrayList();
-      expectedNormal.add("β");
+      expectedNormal.add("\u03b2"); // android-changed: GREEK LOWER CASE BETA
       expectedNormal.add(" Dallas, ");
-      expectedNormal.add("γ");
+      expectedNormal.add("\u03b3"); // android-changed: GREEK LOWER CASE GAMMA
       expectedNormal.add("\n 98554");
       
       java.util.List expectedExpanded = new java.util.ArrayList();
-      expectedExpanded.add("β Dallas, γ\n 98554");
+      expectedExpanded.add("\u03b2 Dallas, \u03b3\n 98554"); // android-changed: GREEK LOWER CASE BETA, GREEK LOWER CASE GAMMA
       
       doc = (Document) load("hc_staff", false);
       elementList = doc.getElementsByTagName("acronym");
diff --git a/libcore/luni/src/main/java/java/io/EmulatedFields.java b/libcore/luni/src/main/java/java/io/EmulatedFields.java
index a947a52..f6dbdfc 100644
--- a/libcore/luni/src/main/java/java/io/EmulatedFields.java
+++ b/libcore/luni/src/main/java/java/io/EmulatedFields.java
@@ -119,7 +119,7 @@
     public boolean defaulted(String name) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, null);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no field '" + name + "'");
         }
         return slot.defaulted;
     }
@@ -207,7 +207,7 @@
         ObjectSlot slot = findSlot(name, Byte.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no byte field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Byte) slot.fieldValue)
                 .byteValue();
@@ -233,7 +233,7 @@
         ObjectSlot slot = findSlot(name, Character.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no char field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Character) slot.fieldValue)
                 .charValue();
@@ -259,7 +259,7 @@
         ObjectSlot slot = findSlot(name, Double.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no double field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Double) slot.fieldValue)
                 .doubleValue();
@@ -285,7 +285,7 @@
         ObjectSlot slot = findSlot(name, Float.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no float field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Float) slot.fieldValue)
                 .floatValue();
@@ -311,7 +311,7 @@
         ObjectSlot slot = findSlot(name, Integer.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no int field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Integer) slot.fieldValue)
                 .intValue();
@@ -337,7 +337,7 @@
         ObjectSlot slot = findSlot(name, Long.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no long field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Long) slot.fieldValue)
                 .longValue();
@@ -363,7 +363,7 @@
         ObjectSlot slot = findSlot(name, null);
         // if not initialized yet, we give the default value
         if (slot == null || slot.field.getType().isPrimitive()) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no Object field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : slot.fieldValue;
     }
@@ -388,7 +388,7 @@
         ObjectSlot slot = findSlot(name, Short.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no short field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Short) slot.fieldValue)
                 .shortValue();
@@ -414,7 +414,7 @@
         ObjectSlot slot = findSlot(name, Boolean.TYPE);
         // if not initialized yet, we give the default value
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no boolean field '" + name + "'");
         }
         return slot.defaulted ? defaultValue : ((Boolean) slot.fieldValue)
                 .booleanValue();
@@ -435,7 +435,7 @@
     public void put(String name, byte value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Byte.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no byte field '" + name + "'");
         }
         slot.fieldValue = Byte.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -456,7 +456,7 @@
     public void put(String name, char value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Character.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no char field '" + name + "'");
         }
         slot.fieldValue = Character.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -477,7 +477,7 @@
     public void put(String name, double value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Double.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no double field '" + name + "'");
         }
         slot.fieldValue = Double.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -498,7 +498,7 @@
     public void put(String name, float value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Float.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no float field '" + name + "'");
         }
         slot.fieldValue = Float.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -519,7 +519,7 @@
     public void put(String name, int value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Integer.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no integer field '" + name + "'");
         }
         slot.fieldValue = Integer.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -540,7 +540,7 @@
     public void put(String name, long value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Long.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no long field '" + name + "'");
         }
         slot.fieldValue = Long.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -565,7 +565,7 @@
         }
         ObjectSlot slot = findSlot(name, valueClass);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no Object field '" + name + "'");
         }
         slot.fieldValue = value;
         slot.defaulted = false; // No longer default value
@@ -586,7 +586,7 @@
     public void put(String name, short value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Short.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no short field '" + name + "'");
         }
         slot.fieldValue = Short.valueOf(value);
         slot.defaulted = false; // No longer default value
@@ -607,7 +607,7 @@
     public void put(String name, boolean value) throws IllegalArgumentException {
         ObjectSlot slot = findSlot(name, Boolean.TYPE);
         if (slot == null) {
-            throw new IllegalArgumentException();
+            throw new IllegalArgumentException("no boolean field '" + name + "'");
         }
         slot.fieldValue = Boolean.valueOf(value);
         slot.defaulted = false; // No longer default value
diff --git a/libcore/luni/src/main/java/java/net/AddressCache.java b/libcore/luni/src/main/java/java/net/AddressCache.java
index 8388b48..c0d8d97 100644
--- a/libcore/luni/src/main/java/java/net/AddressCache.java
+++ b/libcore/luni/src/main/java/java/net/AddressCache.java
@@ -47,7 +47,7 @@
     // The actual cache.
     private final Map<String, AddressCacheEntry> map;
     
-    class AddressCacheEntry {
+    static class AddressCacheEntry {
         // The addresses. May be the empty array for a negative cache entry.
         InetAddress[] addresses;
         
diff --git a/libcore/luni/src/main/java/java/util/Currency.java b/libcore/luni/src/main/java/java/util/Currency.java
index ed9868f..6aa295a 100644
--- a/libcore/luni/src/main/java/java/util/Currency.java
+++ b/libcore/luni/src/main/java/java/util/Currency.java
@@ -174,7 +174,9 @@
             return localeData.currencySymbol;
         }
 
-        return Resources.getCurrencySymbolNative(locale.toString(), currencyCode);
+        // Try ICU, and fall back to the currency code if ICU has nothing.
+        String symbol = Resources.getCurrencySymbolNative(locale.toString(), currencyCode);
+        return symbol != null ? symbol : currencyCode;
         // END android-changed
     }
 
diff --git a/libcore/luni/src/test/java/java/util/AllTests.java b/libcore/luni/src/test/java/java/util/AllTests.java
index fdeb03a..774d48b 100644
--- a/libcore/luni/src/test/java/java/util/AllTests.java
+++ b/libcore/luni/src/test/java/java/util/AllTests.java
@@ -22,8 +22,10 @@
 public class AllTests {
     public static final Test suite() {
         TestSuite suite = tests.TestSuiteFactory.createTestSuite();
+        suite.addTestSuite(java.util.CurrencyTest.class);
         suite.addTestSuite(java.util.DateTest.class);
         suite.addTestSuite(java.util.FormatterTest.class);
+        suite.addTestSuite(java.util.TimeZoneTest.class);
         return suite;
     }
 }
diff --git a/libcore/luni/src/test/java/java/util/CurrencyTest.java b/libcore/luni/src/test/java/java/util/CurrencyTest.java
new file mode 100644
index 0000000..16111d5
--- /dev/null
+++ b/libcore/luni/src/test/java/java/util/CurrencyTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 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.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CurrencyTest extends junit.framework.TestCase {
+    // Regression test to ensure that Currency.getSymbol(Locale) returns the
+    // currency code if ICU doesn't have a localization of the symbol. The
+    // harmony Currency tests don't test this, and their DecimalFormat tests
+    // only test it as a side-effect, and in a way that only detected my
+    // specific mistake of returning null (returning "stinky" would have
+    // passed).
+    public void test_getSymbol_fallback() throws Exception {
+        // This assumes that AED never becomes a currency important enough to
+        // Canada that Canadians give it a localized (to Canada) symbol.
+        assertEquals("AED", Currency.getInstance("AED").getSymbol(Locale.CANADA));
+    }
+}
diff --git a/libcore/luni/src/test/java/java/util/FormatterTest.java b/libcore/luni/src/test/java/java/util/FormatterTest.java
index 11d82fb..1722e67 100644
--- a/libcore/luni/src/test/java/java/util/FormatterTest.java
+++ b/libcore/luni/src/test/java/java/util/FormatterTest.java
@@ -37,8 +37,8 @@
     public void test_formatNull() throws Exception {
         // We fast-path %s and %d (with no configuration) but need to make sure we handle the
         // special case of the null argument...
-        assertEquals("null", String.format(Locale.US, "%s", null));
-        assertEquals("null", String.format(Locale.US, "%d", null));
+        assertEquals("null", String.format(Locale.US, "%s", (String) null));
+        assertEquals("null", String.format(Locale.US, "%d", (Integer) null));
         // ...without screwing up conversions that don't take an argument.
         assertEquals("%", String.format(Locale.US, "%%"));
     }
diff --git a/libcore/luni/src/test/java/java/util/TimeZoneTest.java b/libcore/luni/src/test/java/java/util/TimeZoneTest.java
new file mode 100644
index 0000000..ec4879f
--- /dev/null
+++ b/libcore/luni/src/test/java/java/util/TimeZoneTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2010 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.util;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class TimeZoneTest extends junit.framework.TestCase {
+    // http://code.google.com/p/android/issues/detail?id=877
+    public void test_useDaylightTime() {
+        TimeZone asiaTaipei = TimeZone.getTimeZone("Asia/Taipei");
+        assertFalse("Taiwan doesn't use DST", asiaTaipei.useDaylightTime());
+    }
+}
diff --git a/libcore/luni/src/test/java/tests/api/java/util/CalendarTest.java b/libcore/luni/src/test/java/tests/api/java/util/CalendarTest.java
index cc0f91a..4ffe2c6 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/CalendarTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/CalendarTest.java
@@ -983,11 +983,12 @@
             // locale dependent test, bug 1943269
             return;
         }
+        Locale.setDefault(Locale.US);
         Calendar cal = Calendar.getInstance();
-        assertTrue(cal.getMinimalDaysInFirstWeek()==1);
+        assertEquals(1, cal.getMinimalDaysInFirstWeek());
         Locale.setDefault(Locale.FRANCE);
         cal = Calendar.getInstance();
-        assertTrue(cal.getMinimalDaysInFirstWeek()==4);
+        assertEquals(4, cal.getMinimalDaysInFirstWeek());
         Locale.setDefault(Locale.US);
     }
 
diff --git a/libcore/luni/src/test/java/tests/api/java/util/FormatterTest.java b/libcore/luni/src/test/java/tests/api/java/util/FormatterTest.java
index fb03a34..7709b88 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/FormatterTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/FormatterTest.java
@@ -2101,25 +2101,25 @@
         china.set(Calendar.MILLISECOND, 609);
 
         final Object[][] lowerCaseGermanTriple = {
-                {0L,                        'a', "Do"},  //$NON-NLS-2$
-                {Long.MAX_VALUE,            'a', "So"},  //$NON-NLS-2$
-                {-1000L,                    'a', "Do"},  //$NON-NLS-2$
-                {new Date(1147327147578L),  'a', "Do"},  //$NON-NLS-2$
-                {paris,                     'a', "Mo"},  //$NON-NLS-2$
-                {china,                     'a', "Mo"},  //$NON-NLS-2$
+                {0L,                        'a', "Do."},  //$NON-NLS-2$
+                {Long.MAX_VALUE,            'a', "So."},  //$NON-NLS-2$
+                {-1000L,                    'a', "Do."},  //$NON-NLS-2$
+                {new Date(1147327147578L),  'a', "Do."},  //$NON-NLS-2$
+                {paris,                     'a', "Mo."},  //$NON-NLS-2$
+                {china,                     'a', "Mo."},  //$NON-NLS-2$
                 {0L,                        'b', "Jan"},  //$NON-NLS-2$
                 {Long.MAX_VALUE,            'b', "Aug"},  //$NON-NLS-2$
                 {-1000L,                    'b', "Jan"},  //$NON-NLS-2$
                 {new Date(1147327147578L),  'b', "Mai"},  //$NON-NLS-2$
                 {paris,                     'b', "Mai"},  //$NON-NLS-2$
                 {china,                     'b', "Mai"},  //$NON-NLS-2$
-                {0L,                        'c', "Do Jan 01 08:00:00 GMT+08:00 1970"},  //$NON-NLS-2$
-                // {Long.MAX_VALUE,            'c', "So Aug 17 15:12:55 GMT+08:00 292278994"},  //$NON-NLS-2$
-                {Long.MAX_VALUE,            'c', "So Aug 17 15:18:47 GMT+08:00 292278994"},  //$NON-NLS-2$
-                {-1000L,                    'c', "Do Jan 01 07:59:59 GMT+08:00 1970"},  //$NON-NLS-2$
-                {new Date(1147327147578L),  'c', "Do Mai 11 13:59:07 GMT+08:00 2006"},  //$NON-NLS-2$
-                {paris,                     'c', "Mo Mai 08 12:00:00 MESZ 2006"},  //$NON-NLS-2$
-                {china,                     'c', "Mo Mai 08 12:00:00 GMT-08:00 2006"},  //$NON-NLS-2$
+                {0L,                        'c', "Do. Jan 01 08:00:00 GMT+08:00 1970"},  //$NON-NLS-2$
+                // {Long.MAX_VALUE,            'c', "So. Aug 17 15:12:55 GMT+08:00 292278994"},  //$NON-NLS-2$
+                {Long.MAX_VALUE,            'c', "So. Aug 17 15:18:47 GMT+08:00 292278994"},  //$NON-NLS-2$
+                {-1000L,                    'c', "Do. Jan 01 07:59:59 GMT+08:00 1970"},  //$NON-NLS-2$
+                {new Date(1147327147578L),  'c', "Do. Mai 11 13:59:07 GMT+08:00 2006"},  //$NON-NLS-2$
+                {paris,                     'c', "Mo. Mai 08 12:00:00 MESZ 2006"},  //$NON-NLS-2$
+                {china,                     'c', "Mo. Mai 08 12:00:00 GMT-08:00 2006"},  //$NON-NLS-2$
                 {0L,                        'd', "01"},  //$NON-NLS-2$
                 {Long.MAX_VALUE,            'd', "17"},  //$NON-NLS-2$
                 {-1000L,                    'd', "01"},  //$NON-NLS-2$
@@ -2209,13 +2209,13 @@
                 {new Date(1147327147578L),  'b', "mai"}, //$NON-NLS-2$
                 {paris,                     'b', "mai"}, //$NON-NLS-2$
                 {china,                     'b', "mai"}, //$NON-NLS-2$
-                {0L,                        'c', "jeu. janv. 01 08:00:00 HMG+08:00 1970"}, //$NON-NLS-2$
-                // {Long.MAX_VALUE,            'c', "dim. ao\u00fbt 17 15:12:55 HMG+08:00 292278994"}, //$NON-NLS-2$
-                {Long.MAX_VALUE,            'c', "dim. ao\u00fbt 17 15:18:47 HMG+08:00 292278994"}, //$NON-NLS-2$
-                {-1000L,                    'c', "jeu. janv. 01 07:59:59 HMG+08:00 1970"}, //$NON-NLS-2$
-                {new Date(1147327147578L),  'c', "jeu. mai 11 13:59:07 HMG+08:00 2006"}, //$NON-NLS-2$
+                {0L,                        'c', "jeu. janv. 01 08:00:00 UTC+08:00 1970"}, //$NON-NLS-2$
+                // {Long.MAX_VALUE,            'c', "dim. ao\u00fbt 17 15:12:55 UTC+08:00 292278994"}, //$NON-NLS-2$
+                {Long.MAX_VALUE,            'c', "dim. ao\u00fbt 17 15:18:47 UTC+08:00 292278994"}, //$NON-NLS-2$
+                {-1000L,                    'c', "jeu. janv. 01 07:59:59 UTC+08:00 1970"}, //$NON-NLS-2$
+                {new Date(1147327147578L),  'c', "jeu. mai 11 13:59:07 UTC+08:00 2006"}, //$NON-NLS-2$
                 {paris,                     'c', "lun. mai 08 12:00:00 HAEC 2006"}, //$NON-NLS-2$
-                {china,                     'c', "lun. mai 08 12:00:00 HMG-08:00 2006"}, //$NON-NLS-2$
+                {china,                     'c', "lun. mai 08 12:00:00 UTC-08:00 2006"}, //$NON-NLS-2$
                 {0L,                        'd', "01"}, //$NON-NLS-2$
                 {Long.MAX_VALUE,            'd', "17"}, //$NON-NLS-2$
                 {-1000L,                    'd', "01"}, //$NON-NLS-2$
@@ -2401,7 +2401,7 @@
             f = new Formatter(Locale.GERMAN);
             f.format(formatSpecifier, lowerCaseGermanTriple[i][input]);
             assertEquals("Format pattern: " + formatSpecifier //$NON-NLS-2$
-                            + " Argument: " + lowerCaseGermanTriple[i][pattern], //$NON-NLS-2$
+                            + " Argument: " + lowerCaseGermanTriple[i][input], //$NON-NLS-2$
                             lowerCaseGermanTriple[i][output], f.toString());
 
             f = new Formatter(Locale.GERMAN);
@@ -2638,12 +2638,12 @@
                 {new Date(1147327147578L),  'Y', "2006"}, //$NON-NLS-2$
                 {paris,                     'Y', "2006"}, //$NON-NLS-2$
                 {china,                     'Y', "2006"}, //$NON-NLS-2$
-                {0L,                        'Z', "HMG+08:00"}, //$NON-NLS-2$
-                {Long.MAX_VALUE,            'Z', "HMG+08:00"}, //$NON-NLS-2$
-                {-1000L,                    'Z', "HMG+08:00"}, //$NON-NLS-2$
-                {new Date(1147327147578L),  'Z', "HMG+08:00"}, //$NON-NLS-2$
+                {0L,                        'Z', "UTC+08:00"}, //$NON-NLS-2$
+                {Long.MAX_VALUE,            'Z', "UTC+08:00"}, //$NON-NLS-2$
+                {-1000L,                    'Z', "UTC+08:00"}, //$NON-NLS-2$
+                {new Date(1147327147578L),  'Z', "UTC+08:00"}, //$NON-NLS-2$
                 {paris,                     'Z', "HAEC"}, //$NON-NLS-2$
-                {china,                     'Z', "HMG-08:00"}, //$NON-NLS-2$
+                {china,                     'Z', "UTC-08:00"}, //$NON-NLS-2$
                 
         };
 
diff --git a/libcore/luni/src/test/java/tests/api/java/util/TimeZoneTest.java b/libcore/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
index 9b1d395..aacf6ce 100644
--- a/libcore/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/util/TimeZoneTest.java
@@ -315,7 +315,8 @@
         }
         TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
         assertEquals("Pacific Standard Time", tz.getDisplayName(new Locale("US")));
-        assertEquals("Heure normale du Pacifique", tz.getDisplayName(Locale.FRANCE));
+        // BEGIN android-note: RI has "Heure", CLDR/ICU has "heure".
+        assertEquals("heure normale du Pacifique", tz.getDisplayName(Locale.FRANCE));
     }
     
     @TestTargetNew(
@@ -349,9 +350,10 @@
         assertEquals("Pacific Daylight Time", tz.getDisplayName(true,  1, Locale.US));
         assertEquals("Pacific Standard Time", tz.getDisplayName(false, 1, Locale.UK));
         //RI fails on following line. RI always returns short time zone name as "PST" 
-        assertEquals("HMG-08:00",             tz.getDisplayName(false, 0, Locale.FRANCE));
-        assertEquals("Heure avanc\u00e9e du Pacifique", tz.getDisplayName(true,  1, Locale.FRANCE));
-        assertEquals("Heure normale du Pacifique", tz.getDisplayName(false, 1, Locale.FRANCE));
+        assertEquals("UTC-08:00",             tz.getDisplayName(false, 0, Locale.FRANCE));
+        // BEGIN android-note: RI has "Heure", CLDR/ICU has "heure".
+        assertEquals("heure avanc\u00e9e du Pacifique", tz.getDisplayName(true,  1, Locale.FRANCE));
+        assertEquals("heure normale du Pacifique", tz.getDisplayName(false, 1, Locale.FRANCE));
     }
     
     @TestTargetNew(
@@ -392,19 +394,6 @@
     @TestTargetNew(
         level = TestLevel.COMPLETE,
         notes = "",
-        method = "useDaylightTime",
-        args = {}
-    )
-    public void test_useDaylightTime() {
-        // http://code.google.com/p/android/issues/detail?id=877
-        
-        TimeZone asiaTaipei = TimeZone.getTimeZone("Asia/Taipei");
-        assertFalse("Taiwan doesn't use DST", asiaTaipei.useDaylightTime());
-    }
-    
-    @TestTargetNew(
-        level = TestLevel.COMPLETE,
-        notes = "",
         method = "setID",
         args = {java.lang.String.class}
     )
diff --git a/libcore/math/src/main/java/java/math/BigDecimal.java b/libcore/math/src/main/java/java/math/BigDecimal.java
index 33042ba..4e4875b 100644
--- a/libcore/math/src/main/java/java/math/BigDecimal.java
+++ b/libcore/math/src/main/java/java/math/BigDecimal.java
@@ -2148,7 +2148,10 @@
         long newScale = scale;
 
         if (isZero()) {
+            // BEGIN android-changed: preserve RI compatibility, so BigDecimal.equals (which checks
+            // value *and* scale) continues to work.
             return this;
+            // END android-changed
         }
         BigInteger strippedBI = getUnscaledValue();
         BigInteger[] quotAndRem;
diff --git a/libcore/math/src/test/java/tests/api/java/math/BigDecimalTest.java b/libcore/math/src/test/java/tests/api/java/math/BigDecimalTest.java
index 572f2c1..29d68a2 100644
--- a/libcore/math/src/test/java/tests/api/java/math/BigDecimalTest.java
+++ b/libcore/math/src/test/java/tests/api/java/math/BigDecimalTest.java
@@ -1293,7 +1293,6 @@
         method = "stripTrailingZeros",
         args = {}
     )
-    @AndroidOnly("Stripping trailing zeroes from 0.000 value doesn't work on RI. See below")
     public void test_stripTrailingZero() {
         BigDecimal sixhundredtest = new BigDecimal("600.0");
         assertTrue("stripTrailingZero failed for 600.0",
@@ -1306,11 +1305,13 @@
                 ((notrailingzerotest.stripTrailingZeros()).scale() == 0)
                 );
         
+        // BEGIN android-changed: preserve RI compatibility, so BigDecimal.equals (which checks
+        // value *and* scale) continues to work. https://issues.apache.org/jira/browse/HARMONY-4623
         /* Zero */
-        //regression for HARMONY-4623, NON-BUG DIFF with RI
         BigDecimal zerotest = new BigDecimal("0.0000");
         assertEquals("stripTrailingZero failed for 0.0000",
-                0, (zerotest.stripTrailingZeros()).scale() );        
+                4, (zerotest.stripTrailingZeros()).scale() );
+        // END android-changed
     }
 
     @TestTargetNew(
diff --git a/libcore/support/src/test/java/tests/util/TestEnvironment.java b/libcore/support/src/test/java/tests/util/TestEnvironment.java
index 69a87c2..088e624 100644
--- a/libcore/support/src/test/java/tests/util/TestEnvironment.java
+++ b/libcore/support/src/test/java/tests/util/TestEnvironment.java
@@ -73,12 +73,21 @@
         TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
     }
 
-    private static void resetSystemProperties() {
-        String tmpDir = System.getProperty("java.io.tmpdir");
-        if (tmpDir == null) {
-            throw new IllegalStateException("Test execution requires the"
-                    + " system property java.io.tmpdir to be set.");
+    private static String getExistingSystemProperty(String name) {
+        String result = System.getProperty(name);
+        if (result == null) {
+            throw new AssertionError("Tests require the '" + name + "' system property");
         }
+        return result;
+    }
+
+    private static void resetSystemProperties() {
+        // There are two system properties we can't live without.
+        // 1. We need somewhere writable to stash our stuff.
+        String tmpDir = getExistingSystemProperty("java.io.tmpdir");
+        // 2. We need to know who we are, specifically "am I root?" because that affects what
+        // the OS lets us do, and that affects test expectations.
+        String userName = getExistingSystemProperty("user.name");
 
         Properties p = new Properties();
 
@@ -129,7 +138,7 @@
         p.put("line.separator", "\n");
         p.put("path.separator", ":");
         p.put("user.language", "en");
-        p.put("user.name", "");
+        p.put("user.name", userName);
         p.put("user.region", "US");
 
         System.setProperties(p);
diff --git a/libcore/text/src/main/java/java/text/DecimalFormat.java b/libcore/text/src/main/java/java/text/DecimalFormat.java
index 765bdae..65d4d48 100644
--- a/libcore/text/src/main/java/java/text/DecimalFormat.java
+++ b/libcore/text/src/main/java/java/text/DecimalFormat.java
@@ -946,7 +946,7 @@
         // END android-added
 
         if (this.isParseIntegerOnly() && number.equals(NEGATIVE_ZERO_DOUBLE)) {
-            return new Long(0);
+            return Long.valueOf(0); // android-changed
         }
         return number;
 
@@ -1208,18 +1208,10 @@
         fields.put("positiveSuffix", dform.getPositiveSuffix());
         fields.put("negativePrefix", dform.getNegativePrefix());
         fields.put("negativeSuffix", dform.getNegativeSuffix());
-        String posPrefixPattern = (String) Format.getInternalField(
-                "posPrefixPattern", dform);
-        fields.put("posPrefixPattern", posPrefixPattern);
-        String posSuffixPattern = (String) Format.getInternalField(
-                "posSuffixPattern", dform);
-        fields.put("posSuffixPattern", posSuffixPattern);
-        String negPrefixPattern = (String) Format.getInternalField(
-                "negPrefixPattern", dform);
-        fields.put("negPrefixPattern", negPrefixPattern);
-        String negSuffixPattern = (String) Format.getInternalField(
-                "negSuffixPattern", dform);
-        fields.put("negSuffixPattern", negSuffixPattern);
+        fields.put("posPrefixPattern", (String) null);
+        fields.put("posSuffixPattern", (String) null);
+        fields.put("negPrefixPattern", (String) null);
+        fields.put("negSuffixPattern", (String) null);
         fields.put("multiplier", dform.getMultiplier());
         fields.put("groupingSize", (byte) dform.getGroupingSize());
         // BEGIN android-added
@@ -1230,7 +1222,7 @@
         fields.put("parseBigDecimal", parseBigDecimal);
         fields.put("symbols", symbols);
         fields.put("useExponentialNotation", false);
-        fields.put("minExponentDigits", 0);
+        fields.put("minExponentDigits", (byte) 0);
         fields.put("maximumIntegerDigits", dform.getMaximumIntegerDigits());
         fields.put("minimumIntegerDigits", dform.getMinimumIntegerDigits());
         fields.put("maximumFractionDigits", dform.getMaximumFractionDigits());
@@ -1254,52 +1246,24 @@
     private void readObject(ObjectInputStream stream) throws IOException,
             ClassNotFoundException {
 
-        ObjectInputStream.GetField fields = stream.readFields();
-        String positivePrefix = (String) fields.get("positivePrefix", "");
-        String positiveSuffix = (String) fields.get("positiveSuffix", "");
-        String negativePrefix = (String) fields.get("negativePrefix", "-");
-        String negativeSuffix = (String) fields.get("negativeSuffix", "");
-
-        String posPrefixPattern = (String) fields.get("posPrefixPattern", "");
-        String posSuffixPattern = (String) fields.get("posSuffixPattern", "");
-        String negPrefixPattern = (String) fields.get("negPrefixPattern", "-");
-        String negSuffixPattern = (String) fields.get("negSuffixPattern", "");
-
-        int multiplier = fields.get("multiplier", 1);
-        byte groupingSize = fields.get("groupingSize", (byte) 3);
-        // BEGIN android-added
-        boolean groupingUsed = fields.get("groupingUsed", true);
-        // END android-added
-        boolean decimalSeparatorAlwaysShown = fields.get(
-                "decimalSeparatorAlwaysShown", false);
-        boolean parseBigDecimal = fields.get("parseBigDecimal", false);
-        symbols = (DecimalFormatSymbols) fields.get("symbols", null);
-
-        int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
-        int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
-        int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
-        int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
-        int serialVersionOnStream = fields.get("serialVersionOnStream", 0);
-
-        Locale locale = (Locale) Format.getInternalField("locale", symbols);
         // BEGIN android-changed
+        ObjectInputStream.GetField fields = stream.readFields();
+        this.symbols = (DecimalFormatSymbols) fields.get("symbols", null);
+
         initNative("");
-        // END android-changed
-        dform.setPositivePrefix(positivePrefix);
-        dform.setPositiveSuffix(positiveSuffix);
-        dform.setNegativePrefix(negativePrefix);
-        dform.setNegativeSuffix(negativeSuffix);
-        setInternalField("posPrefixPattern", dform, posPrefixPattern);
-        setInternalField("posSuffixPattern", dform, posSuffixPattern);
-        setInternalField("negPrefixPattern", dform, negPrefixPattern);
-        setInternalField("negSuffixPattern", dform, negSuffixPattern);
-        dform.setMultiplier(multiplier);
-        dform.setGroupingSize(groupingSize);
-        // BEGIN android-added
-        dform.setGroupingUsed(groupingUsed);
-        // END android-added
-        dform.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
-        setMinimumIntegerDigits(minimumIntegerDigits);
+        dform.setPositivePrefix((String) fields.get("positivePrefix", ""));
+        dform.setPositiveSuffix((String) fields.get("positiveSuffix", ""));
+        dform.setNegativePrefix((String) fields.get("negativePrefix", "-"));
+        dform.setNegativeSuffix((String) fields.get("negativeSuffix", ""));
+        dform.setMultiplier(fields.get("multiplier", 1));
+        dform.setGroupingSize(fields.get("groupingSize", (byte) 3));
+        dform.setGroupingUsed(fields.get("groupingUsed", true));
+        dform.setDecimalSeparatorAlwaysShown(fields.get("decimalSeparatorAlwaysShown", false));
+
+        final int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
+        final int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
+        final int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
+        final int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
         // BEGIN android-changed: tell ICU what we want, then ask it what we can have, and then
         // set that in our Java object. This isn't RI-compatible, but then very little of our
         // behavior in this area is, and it's not obvious how we can second-guess ICU (or tell
@@ -1307,41 +1271,18 @@
         // because ICU doesn't seem to have its own ideas about the other options.
         dform.setMaximumIntegerDigits(maximumIntegerDigits);
         super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
-        // END android-changed
+
+        setMinimumIntegerDigits(minimumIntegerDigits);
         setMinimumFractionDigits(minimumFractionDigits);
         setMaximumFractionDigits(maximumFractionDigits);
-        setParseBigDecimal(parseBigDecimal);
+        setParseBigDecimal(fields.get("parseBigDecimal", false));
 
-        if (serialVersionOnStream < 3) {
+        if (fields.get("serialVersionOnStream", 0) < 3) {
             setMaximumIntegerDigits(super.getMaximumIntegerDigits());
             setMinimumIntegerDigits(super.getMinimumIntegerDigits());
             setMaximumFractionDigits(super.getMaximumFractionDigits());
             setMinimumFractionDigits(super.getMinimumFractionDigits());
         }
-    }
-
-    /*
-     * Sets private field value by reflection.
-     * 
-     * @param fieldName the field name to be set @param target the object which
-     * field to be set @param value the value to be set
-     */
-    private void setInternalField(final String fieldName, final Object target,
-            final Object value) {
-        AccessController
-                .doPrivileged(new PrivilegedAction<java.lang.reflect.Field>() {
-                    public java.lang.reflect.Field run() {
-                        java.lang.reflect.Field field = null;
-                        try {
-                            field = target.getClass().getDeclaredField(
-                                    fieldName);
-                            field.setAccessible(true);
-                            field.set(target, value);
-                        } catch (Exception e) {
-                            return null;
-                        }
-                        return field;
-                    }
-                });
+        // END android-changed
     }
 }
diff --git a/libcore/text/src/main/java/java/text/Format.java b/libcore/text/src/main/java/java/text/Format.java
index 567b0f6..18b0490 100644
--- a/libcore/text/src/main/java/java/text/Format.java
+++ b/libcore/text/src/main/java/java/text/Format.java
@@ -216,32 +216,6 @@
      */
     public abstract Object parseObject(String string, ParsePosition position);
 
-    /*
-     * Gets private field value by reflection.
-     * 
-     * @param fieldName the field name to be set @param target the object which
-     * field to be gotten
-     */
-    static Object getInternalField(final String fieldName, final Object target) {
-        Object value = AccessController
-                .doPrivileged(new PrivilegedAction<Object>() {
-                    public Object run() {
-                        Object result = null;
-                        java.lang.reflect.Field field = null;
-                        try {
-                            field = target.getClass().getDeclaredField(
-                                    fieldName);
-                            field.setAccessible(true);
-                            result = field.get(target);
-                        } catch (Exception e1) {
-                            return null;
-                        }
-                        return result;
-                    }
-                });
-        return value;
-    }
-
     static boolean upTo(String string, ParsePosition position,
             StringBuffer buffer, char stop) {
         int index = position.getIndex(), length = string.length();
diff --git a/libcore/text/src/main/java/java/text/SimpleDateFormat.java b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
index a67c7e6..20fff63 100644
--- a/libcore/text/src/main/java/java/text/SimpleDateFormat.java
+++ b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
@@ -509,11 +509,6 @@
 
     // BEGIN android-removed
     // SimpleDateFormat(Locale locale, com.ibm.icu.text.SimpleDateFormat icuFormat){
-    //     this(locale);
-    //     this.icuFormat = icuFormat;
-    //     this.icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
-    //     pattern = (String)Format.getInternalField("pattern", icuFormat); //$NON-NLS-1$
-    //     formatData = new DateFormatSymbols(locale);
     // }
     // END android-removed
     
diff --git a/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java b/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java
index b92e37b..7a615d5 100644
--- a/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java
+++ b/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatSymbolsTest.java
@@ -776,17 +776,17 @@
         // Values based on Java 1.5 RI DecimalFormatSymbols for Locale.FRANCE
         /*
          * currency = [EUR]
-         * currencySymbol = [€][U+20ac]
+         * currencySymbol = [U+20ac] // EURO SIGN
          * decimalSeparator = [,][U+002c]
          * digit = [#][U+0023]
-         * groupingSeparator = [ ][U+00a0]
-         * infinity = [∞][U+221e]
+         * groupingSeparator = [U+00a0] // NON-BREAKING SPACE
+         * infinity = [U+221e] // INFINITY
          * internationalCurrencySymbol = [EUR]
          * minusSign = [-][U+002d]
          * monetaryDecimalSeparator = [,][U+002c]
-         * naN = [�][U+fffd]
+         * naN = [U+fffd] // REPLACEMENT CHARACTER
          * patternSeparator = [;][U+003b]
-         * perMill = [‰][U+2030]
+         * perMill = [U+2030] // PER MILLE
          * percent = [%][U+0025]
          * zeroDigit = [0][U+0030]
          */
@@ -800,6 +800,8 @@
         assertEquals('-', dfs.getMinusSign());
         assertEquals(',', dfs.getMonetaryDecimalSeparator());
         // RI's default NaN is U+FFFD, Harmony's is based on ICU
+        // This suggests an RI bug, assuming that non-UTF8 bytes are UTF8 and
+        // getting a conversion failure.
         assertEquals("\uFFFD", dfs.getNaN());
         assertEquals('\u003b', dfs.getPatternSeparator());
         assertEquals('\u2030', dfs.getPerMill());
diff --git a/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java b/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java
index 7c4a319..e949f1d 100644
--- a/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java
+++ b/libcore/text/src/test/java/org/apache/harmony/text/tests/java/text/NumberFormatTest.java
@@ -148,11 +148,10 @@
         // Test for method java.text.NumberFormat
         // getIntegerInstance(java.util.Locale)
         Locale usLocale = Locale.US;
-        // BEGIN android-changed
-        // use de_CH instead
-        // Locale arLocale = new Locale("ar", "AE");
+        Locale arLocale = new Locale("ar", "AE");
+        // BEGIN android-added: use de_CH too.
         Locale chLocale = new Locale("de", "CH");
-        // END android-changed
+        // END android-added
 
         Locale[] requiredLocales = {usLocale, chLocale};
         if (!Support_Locale.areLocalesAvailable(requiredLocales)) {
@@ -182,9 +181,7 @@
                 format.isParseIntegerOnly());
 
         // try with a locale that has a different integer pattern
-        // BEGIN android-changed
-        // use de_CH instead
-        // format = (DecimalFormat) NumberFormat.getIntegerInstance(arLocale);
+        // BEGIN android-added: try de_CH too
         format = (DecimalFormat) NumberFormat.getIntegerInstance(chLocale);
         assertEquals(
                 "Test7: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).toPattern() returned wrong pattern",
@@ -205,8 +202,9 @@
         assertTrue(
                 "Test12: NumberFormat.getIntegerInstance(new Locale(\"de\", \"CH\")).isParseIntegerOnly() returned wrong value",
                 format.isParseIntegerOnly());
-        // use de_CH instead
-        /*assertEquals(
+        // END android-added
+        format = (DecimalFormat) NumberFormat.getIntegerInstance(arLocale);
+        assertEquals(
                 "Test7: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).toPattern() returned wrong pattern",
                 "#,##0;#,##0-", format.toPattern());
         assertEquals(
@@ -224,8 +222,7 @@
                 0, format.getMaximumFractionDigits());
         assertTrue(
                 "Test12: NumberFormat.getIntegerInstance(new Locale(\"ar\", \"AE\")).isParseIntegerOnly() returned wrong value",
-                format.isParseIntegerOnly());*/
-        // END android-changed
+        format.isParseIntegerOnly());
     }
 
     /**
@@ -645,19 +642,20 @@
         // use de_AT instead
         // format = NumberFormat.getCurrencyInstance(mkLocale);
         format = NumberFormat.getCurrencyInstance(atLocale);
-
+        // BEGIN android-changed: ICU uses non-breaking space after the euro sign; the RI uses ' '.
         assertEquals(
                 "Test5: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(35.76) returned wrong value",
-                "\u20ac 35,76", format.format(35.76));
+                "\u20ac\u00a035,76", format.format(35.76));
         assertEquals(
                 "Test6: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(123456.789) returned wrong value",
-                "\u20ac 123.456,79", format.format(123456.789));
+                "\u20ac\u00a0123.456,79", format.format(123456.789));
         assertEquals(
                 "Test7: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(0.1) returned wrong value",
-                "\u20ac 0,10", format.format(0.1));
+                "\u20ac\u00a00,10", format.format(0.1));
         assertEquals(
                 "Test8: NumberFormat.getCurrencyInstance(new Locale(\"de\", \"AT\")).format(0.999) returned wrong value",
-                "\u20ac 1,00", format.format(0.999));
+                "\u20ac\u00a01,00", format.format(0.999));
+        // END android-changed
         // use de_AT instead
         /*assertEquals(
                 "Test5: NumberFormat.getCurrencyInstance(new Locale(\"mk\", \"MK\")).format(35.76) returned wrong value",
diff --git a/libcore/tools/runner/Android.mk b/libcore/tools/runner/Android.mk
index ee5c4f1..851214b 100644
--- a/libcore/tools/runner/Android.mk
+++ b/libcore/tools/runner/Android.mk
@@ -32,6 +32,8 @@
         java/dalvik/runner/MainFinder.java \
         java/dalvik/runner/MainRunner.java \
         java/dalvik/runner/NamingPatternCodeFinder.java \
+        java/dalvik/runner/Option.java \
+        java/dalvik/runner/OptionParser.java \
         java/dalvik/runner/Result.java \
         java/dalvik/runner/Strings.java \
         java/dalvik/runner/TestRun.java \
diff --git a/libcore/tools/runner/java/dalvik/runner/DalvikRunner.java b/libcore/tools/runner/java/dalvik/runner/DalvikRunner.java
index 84d54ef..20e722c 100644
--- a/libcore/tools/runner/java/dalvik/runner/DalvikRunner.java
+++ b/libcore/tools/runner/java/dalvik/runner/DalvikRunner.java
@@ -17,6 +17,7 @@
 package dalvik.runner;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashSet;
@@ -34,25 +35,203 @@
  */
 public final class DalvikRunner {
 
-    private final File localTemp;
-    private File sdkJar;
-    private Integer debugPort;
-    private long timeoutSeconds;
-    private Set<File> expectationFiles = new LinkedHashSet<File>();
-    private File xmlReportsDirectory;
-    private String javaHome;
-    private List<String> vmArgs = new ArrayList<String>();
-    private boolean clean = true;
-    private String deviceRunnerDir = "/sdcard/dalvikrunner";
-    private List<File> testFiles = new ArrayList<File>();
+    private static class Options {
 
-    private DalvikRunner() {
-        localTemp = new File("/tmp/" + UUID.randomUUID());
-        timeoutSeconds = 10 * 60; // default is ten minutes
-        sdkJar = new File("/home/dalvik-prebuild/android-sdk-linux/platforms/android-2.0/android.jar");
-        expectationFiles.add(new File("dalvik/libcore/tools/runner/expectations.txt"));
+        private final List<File> testFiles = new ArrayList<File>();
+
+        @Option(names = { "--expectations" })
+        private Set<File> expectationFiles = new LinkedHashSet<File>();
+        {
+            expectationFiles.add(new File("dalvik/libcore/tools/runner/expectations.txt"));
+        }
+
+        private static String MODE_DEVICE = "device";
+        private static String MODE_HOST = "host";
+        private static String MODE_ACTIVITY = "activity";
+        @Option(names = { "--mode" })
+        private String mode = MODE_DEVICE;
+
+        @Option(names = { "--timeout" })
+        private long timeoutSeconds = 10 * 60; // default is ten minutes;
+
+        @Option(names = { "--clean" })
+        private boolean clean = true;
+
+        @Option(names = { "--xml-reports-directory" })
+        private File xmlReportsDirectory;
+
+        @Option(names = { "--verbose" })
+        private boolean verbose;
+
+        @Option(names = { "--debug" })
+        private Integer debugPort;
+
+        @Option(names = { "--device-runner-dir" })
+        private File deviceRunnerDir = new File("/sdcard/dalvikrunner");
+
+        @Option(names = { "--vm-arg" })
+        private List<String> vmArgs = new ArrayList<String>();
+
+        @Option(names = { "--java-home" })
+        private File javaHome;
+
+        @Option(names = { "--sdk" })
+        private File sdkJar = new File("/home/dalvik-prebuild/android-sdk-linux/platforms/android-2.0/android.jar");
+
+        private void printUsage() {
+            System.out.println("Usage: DalvikRunner [options]... <tests>...");
+            System.out.println();
+            System.out.println("  <tests>: a .java file containing a jtreg test, JUnit test,");
+            System.out.println("      Caliper benchmark, or a directory of such tests.");
+            System.out.println();
+            System.out.println("GENERAL OPTIONS");
+            System.out.println();
+            System.out.println("  --expectations <file>: include the specified file when looking for");
+            System.out.println("      test expectations. The file should include qualified test names");
+            System.out.println("      and the corresponding expected output.");
+            System.out.println("      Default is: " + expectationFiles);
+            System.out.println();
+            System.out.println("  --mode <device|host|activity>: specify which environment to run the");
+            System.out.println("      tests in. Options are on the device VM, on the host VM, and on");
+            System.out.println("      device within an android.app.Activity.");
+            System.out.println("      Default is: " + mode);
+            System.out.println();
+            System.out.println("  --clean: remove temporary files (default). Disable with --no-clean");
+            System.out.println("      and use with --verbose if you'd like to manually re-run");
+            System.out.println("      commands afterwards.");
+            System.out.println();
+            System.out.println("  --timeout-seconds <seconds>: maximum execution time of each");
+            System.out.println("      test before the runner aborts it.");
+            System.out.println("      Default is: " + timeoutSeconds);
+            System.out.println();
+            System.out.println("  --xml-reports-directory <path>: directory to emit JUnit-style");
+            System.out.println("      XML test results.");
+            System.out.println();
+            System.out.println("  --verbose: turn on verbose output");
+            System.out.println();
+            System.out.println("DEVICE OPTIONS");
+            System.out.println();
+            System.out.println("  --debug <port>: enable Java debugging on the specified port.");
+            System.out.println("      This port must be free both on the device and on the local");
+            System.out.println("      system.");
+            System.out.println();
+            System.out.println("  --device-runner-dir <directory>: use the specified directory for");
+            System.out.println("      on-device temporary files and code.");
+            System.out.println("      Default is: " + deviceRunnerDir);
+            System.out.println();
+            System.out.println("GENERAL VM OPTIONS");
+            System.out.println();
+            System.out.println("  --vm-arg <argument>: include the specified argument when spawning a");
+            System.out.println("      virtual machine. Examples: -Xint:fast, -ea, -Xmx16M");
+            System.out.println();
+            System.out.println("HOST VM OPTIONS");
+            System.out.println();
+            System.out.println("  --java-home <java_home>: execute the tests on the local workstation");
+            System.out.println("      using the specified java home directory. This does not impact");
+            System.out.println("      which javac gets used. When unset, java is used from the PATH.");
+            System.out.println();
+            System.out.println("COMPILE OPTIONS");
+            System.out.println();
+            System.out.println("  --sdk <android jar>: the API jar file to compile against.");
+            System.out.println("      Usually this is <SDK>/platforms/android-<X.X>/android.jar");
+            System.out.println("      where <SDK> is the path to an Android SDK path and <X.X> is");
+            System.out.println("      a release version like 1.5.");
+            System.out.println("      Default is: " + sdkJar);
+            System.out.println();
+        }
+
+        private boolean parseArgs(String[] args) {
+            final List<String> testFilenames;
+            try {
+                testFilenames = new OptionParser(this).parse(args);
+            } catch (RuntimeException e) {
+                System.out.println(e.getMessage());
+                return false;
+            }
+
+            //
+            // Semantic error validation
+            //
+
+            boolean device;
+            boolean vm;
+            if (mode.equals(MODE_DEVICE)) {
+                device = true;
+                vm = true;
+            } else if (mode.equals(MODE_HOST)) {
+                device = false;
+                vm = true;
+            } else if (mode.equals(MODE_ACTIVITY)) {
+                device = true;
+                vm = false;
+            } else {
+                System.out.println("Unknown mode: " + mode);
+                return false;
+            }
+
+
+            if (device) { // check device option consistency
+                if (javaHome != null) {
+                    System.out.println("java home " + javaHome + " should not be specified for mode " + mode);
+                    return false;
+                }
+
+            } else { // check host (!device) option consistency
+                if (javaHome != null && !new File(javaHome, "/bin/java").exists()) {
+                    System.out.println("Invalid java home: " + javaHome);
+                    return false;
+                }
+                if (debugPort != null) {
+                    System.out.println("debug port " + debugPort + " should not be specified for mode " + mode);
+                    return false;
+                }
+            }
+
+            // check vm option consistency
+            if (!vm) {
+                if (!vmArgs.isEmpty()) {
+                    System.out.println("vm args " + vmArgs + " should not be specified for mode " + mode);
+                    return false;
+                }
+            }
+
+            if (!sdkJar.exists()) {
+                System.out.println("Could not find SDK jar: " + sdkJar);
+                return false;
+            }
+
+            if (xmlReportsDirectory != null && !xmlReportsDirectory.isDirectory()) {
+                System.out.println("Invalid XML reports directory: " + xmlReportsDirectory);
+                return false;
+            }
+
+            if (testFilenames.isEmpty()) {
+                System.out.println("No tests provided.");
+                return false;
+            }
+
+            //
+            // Post-processing arguments
+            //
+
+            for (String testFilename : testFilenames) {
+                testFiles.add(new File(testFilename));
+            }
+
+            if (verbose) {
+                Logger.getLogger("dalvik.runner").setLevel(Level.FINE);
+            }
+
+            return true;
+        }
+
     }
 
+    private final Options options = new Options();
+    private final File localTemp = new File("/tmp/" + UUID.randomUUID());
+
+    private DalvikRunner() {}
+
     private void prepareLogging() {
         ConsoleHandler handler = new ConsoleHandler();
         handler.setLevel(Level.ALL);
@@ -66,139 +245,61 @@
         logger.setUseParentHandlers(false);
     }
 
-    private boolean parseArgs(String[] args) throws Exception {
-        for (int i = 0; i < args.length; i++) {
-            if ("--debug".equals(args[i])) {
-                debugPort = Integer.valueOf(args[++i]);
-
-            } else if ("--device-runner-dir".equals(args[i])) {
-                deviceRunnerDir = args[++i];
-
-            } else if ("--expectations".equals(args[i])) {
-                expectationFiles.add(new File(args[++i]));
-
-            } else if ("--java-home".equals(args[i])) {
-                javaHome = args[++i];
-                if (!new File(javaHome, "/bin/java").exists()) {
-                    System.out.println("Invalid java home: " + javaHome);
-                    return false;
-                }
-
-            } else if ("--timeout-seconds".equals(args[i])) {
-                timeoutSeconds = Long.valueOf(args[++i]);
-
-            } else if ("--sdk".equals(args[i])) {
-                sdkJar = new File(args[++i]);
-                if (!sdkJar.exists()) {
-                    System.out.println("Could not find SDK jar: " + sdkJar);
-                    return false;
-                }
-
-            } else if ("--skip-clean".equals(args[i])) {
-                clean = false;
-
-            } else if ("--verbose".equals(args[i])) {
-                Logger.getLogger("dalvik.runner").setLevel(Level.FINE);
-
-            } else if ("--vm-arg".equals(args[i])) {
-                vmArgs.add(args[++i]);
-
-            } else if ("--xml-reports-directory".equals(args[i])) {
-                xmlReportsDirectory = new File(args[++i]);
-                if (!xmlReportsDirectory.isDirectory()) {
-                    System.out.println("Invalid XML reports directory: " + xmlReportsDirectory);
-                    return false;
-                }
-
-            } else if (args[i].startsWith("-")) {
-                System.out.println("Unrecognized option: " + args[i]);
-                return false;
-
-            } else {
-                testFiles.add(new File(args[i]));
-            }
+    private void run() {
+        Vm vm;
+        if (options.mode.equals(Options.MODE_DEVICE)) {
+            vm = new DeviceDalvikVm(
+                    options.debugPort,
+                    options.timeoutSeconds,
+                    options.sdkJar,
+                    localTemp,
+                    options.vmArgs,
+                    options.clean,
+                    options.deviceRunnerDir);
+        } else if (options.mode.equals(Options.MODE_HOST)) {
+            vm = new JavaVm(
+                    options.debugPort,
+                    options.timeoutSeconds,
+                    options.sdkJar,
+                    localTemp,
+                    options.javaHome,
+                    options.vmArgs,
+                    options.clean);
+        } else if (options.mode.equals(Options.MODE_ACTIVITY)) {
+            vm = null;
+            System.out.println("Mode " + options.mode + " not currently supported.");
+            return;
+        } else {
+            System.out.println("Unknown mode mode " + options.mode + ".");
+            return;
         }
 
-        if (testFiles.isEmpty()) {
-            System.out.println("No tests provided.");
-            return false;
-        }
-
-        return true;
-    }
-
-    private void printUsage() {
-        System.out.println("Usage: DalvikRunner [options]... <tests>...");
-        System.out.println();
-        System.out.println("  <tests>: a .java file containing a jtreg test, JUnit test,");
-        System.out.println("      Caliper benchmark, or a directory of such tests.");
-        System.out.println();
-        System.out.println("OPTIONS");
-        System.out.println();
-        System.out.println("  --debug <port>: enable Java debugging on the specified port.");
-        System.out.println("      This port must be free both on the device and on the local");
-        System.out.println("      system.");
-        System.out.println();
-        System.out.println("  ----device-runner-dir <directory>: use the specified directory for");
-        System.out.println("      on-device temporary files and code.");
-        System.out.println("      Default is: " + deviceRunnerDir);
-        System.out.println();
-        System.out.println("  --expectations <file>: include the specified file when looking for");
-        System.out.println("      test expectations. The file should include qualified test names");
-        System.out.println("      and the corresponding expected output.");
-        System.out.println("      Default is: " + expectationFiles);
-        System.out.println();
-        System.out.println("  --java-home <java_home>: execute the tests on the local workstation");
-        System.out.println("      using the specified java home directory. This does not impact");
-        System.out.println("      which javac gets used. When unset, tests are run on a device");
-        System.out.println("      using adb.");
-        System.out.println();
-        System.out.println("  --sdk <android jar>: the API jar file to compile against.");
-        System.out.println("      Usually this is <SDK>/platforms/android-<X.X>/android.jar");
-        System.out.println("      where <SDK> is the path to an Android SDK path and <X.X> is");
-        System.out.println("      a release version like 1.5.");
-        System.out.println("      Default is: " + sdkJar);
-        System.out.println();
-        System.out.println("  --skip-clean: leave temporary files in their place. Useful when");
-        System.out.println("      coupled with --verbose if you'd like to manually re-run");
-        System.out.println("      commands afterwards.");
-        System.out.println();
-        System.out.println("  --timeout-seconds <seconds>: maximum execution time of each");
-        System.out.println("      test before the runner aborts it.");
-        System.out.println("      Default is: " + timeoutSeconds);
-        System.out.println();
-        System.out.println("  --vm-arg <argument>: include the specified argument when spawning a");
-        System.out.println("      virtual machine. Examples: -Xint:fast, -ea, -Xmx16M");
-        System.out.println();
-        System.out.println("  --xml-reports-directory <path>: directory to emit JUnit-style");
-        System.out.println("      XML test results.");
-        System.out.println();
-        System.out.println("  --verbose: turn on verbose output");
-        System.out.println();
-    }
-
-    private void run() throws Exception {
-        Vm vm = javaHome != null
-                ? new JavaVm(debugPort, timeoutSeconds, sdkJar, localTemp,
-                        javaHome, vmArgs, clean)
-                : new DeviceDalvikVm(debugPort, timeoutSeconds, sdkJar,
-                        localTemp, vmArgs, clean, deviceRunnerDir);
         List<CodeFinder> codeFinders = Arrays.asList(
                 new JtregFinder(localTemp),
                 new JUnitFinder(),
                 new CaliperFinder(),
                 new MainFinder());
-        Driver driver = new Driver(localTemp,
-                vm, expectationFiles, xmlReportsDirectory, codeFinders);
-        driver.loadExpectations();
-        driver.buildAndRunAllTests(testFiles);
+        Driver driver = new Driver(
+                localTemp,
+                vm,
+                options.expectationFiles,
+                options.xmlReportsDirectory,
+                codeFinders);
+        try {
+            driver.loadExpectations();
+        } catch (IOException e) {
+            System.out.println("Problem loading expectations: " + e);
+            return;
+        }
+
+        driver.buildAndRunAllTests(options.testFiles);
         vm.shutdown();
     }
 
-    public static void main(String[] args) throws Exception {
+    public static void main(String[] args) {
         DalvikRunner dalvikRunner = new DalvikRunner();
-        if (!dalvikRunner.parseArgs(args)) {
-            dalvikRunner.printUsage();
+        if (!dalvikRunner.options.parseArgs(args)) {
+            dalvikRunner.options.printUsage();
             return;
         }
         dalvikRunner.prepareLogging();
diff --git a/libcore/tools/runner/java/dalvik/runner/DeviceDalvikVm.java b/libcore/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
index 47db11f..4388565 100644
--- a/libcore/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
+++ b/libcore/tools/runner/java/dalvik/runner/DeviceDalvikVm.java
@@ -38,10 +38,10 @@
     private final Adb adb = new Adb();
 
     DeviceDalvikVm(Integer debugPort, long timeoutSeconds, File sdkJar,
-            File localTemp, List<String> additionalVmArgs, boolean clean, String runnerDir) {
+            File localTemp, List<String> additionalVmArgs, boolean clean, File runnerDir) {
         super(debugPort, timeoutSeconds, sdkJar, localTemp, additionalVmArgs, clean);
 
-        this.runnerDir = new File(runnerDir);
+        this.runnerDir = runnerDir;
         this.testTemp = new File(this.runnerDir, "/tests.tmp");
     }
 
diff --git a/libcore/tools/runner/java/dalvik/runner/Driver.java b/libcore/tools/runner/java/dalvik/runner/Driver.java
index 7a30ab7..81c7d6b 100644
--- a/libcore/tools/runner/java/dalvik/runner/Driver.java
+++ b/libcore/tools/runner/java/dalvik/runner/Driver.java
@@ -72,7 +72,7 @@
     /**
      * Builds and executes all tests in the test directory.
      */
-    public void buildAndRunAllTests(Collection<File> testFiles) throws Exception {
+    public void buildAndRunAllTests(Collection<File> testFiles) {
         localTemp.mkdirs();
 
         final BlockingQueue<TestRun> readyToRun = new ArrayBlockingQueue<TestRun>(4);
@@ -136,10 +136,15 @@
                     + readyToRun.size() + " are ready to run");
 
             // if it takes 5 minutes for build and install, something is broken
-            TestRun testRun = readyToRun.poll(300, TimeUnit.SECONDS);
+            TestRun testRun;
+            try {
+                testRun = readyToRun.poll(5 * 60, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Unexpected interruption waiting for build and install", e);
+            }
+
             if (testRun == null) {
-                throw new IllegalStateException(
-                        "Expected " + tests.size() + " tests but found only " + i);
+                throw new IllegalStateException("Expected " + tests.size() + " tests but found only " + i);
             }
 
             runs.add(testRun);
diff --git a/libcore/tools/runner/java/dalvik/runner/JavaVm.java b/libcore/tools/runner/java/dalvik/runner/JavaVm.java
index 8b53477..e29b36b 100644
--- a/libcore/tools/runner/java/dalvik/runner/JavaVm.java
+++ b/libcore/tools/runner/java/dalvik/runner/JavaVm.java
@@ -24,18 +24,19 @@
  */
 final class JavaVm extends Vm {
 
-    private final String javaHome;
+    private final File javaHome;
 
     JavaVm(Integer debugPort, long timeoutSeconds, File sdkJar, File localTemp,
-            String javaHome, List<String> additionalVmArgs, boolean clean) {
+            File javaHome, List<String> additionalVmArgs, boolean clean) {
         super(debugPort, timeoutSeconds, sdkJar, localTemp, additionalVmArgs, clean);
         this.javaHome = javaHome;
     }
 
     @Override protected VmCommandBuilder newVmCommandBuilder(
             File workingDirectory) {
+        String java = javaHome == null ? "java" : new File(javaHome, "bin/java").getPath();
         return new VmCommandBuilder()
-                .vmCommand(javaHome + "/bin/java")
+                .vmCommand(java)
                 .workingDir(workingDirectory);
     }
 }
diff --git a/libcore/tools/runner/java/dalvik/runner/Option.java b/libcore/tools/runner/java/dalvik/runner/Option.java
new file mode 100644
index 0000000..779aa63
--- /dev/null
+++ b/libcore/tools/runner/java/dalvik/runner/Option.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates a field as representing a command-line option for OptionParser.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Option {
+    /**
+     * The names for this option, such as { "-h", "--help" }.
+     * Names must start with one or two '-'s.
+     * An option must have at least one name.
+     */
+    String[] names();
+}
diff --git a/libcore/tools/runner/java/dalvik/runner/OptionParser.java b/libcore/tools/runner/java/dalvik/runner/OptionParser.java
new file mode 100644
index 0000000..64af51c
--- /dev/null
+++ b/libcore/tools/runner/java/dalvik/runner/OptionParser.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2010 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.runner;
+
+import java.io.File;
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Parses command line options.
+ *
+ * Strings in the passed-in String[] are parsed left-to-right. Each
+ * String is classified as a short option (such as "-v"), a long
+ * option (such as "--verbose"), an argument to an option (such as
+ * "out.txt" in "-f out.txt"), or a non-option positional argument.
+ *
+ * A simple short option is a "-" followed by a short option
+ * character. If the option requires an argument (which is true of any
+ * non-boolean option), it may be written as a separate parameter, but
+ * need not be. That is, "-f out.txt" and "-fout.txt" are both
+ * acceptable.
+ *
+ * It is possible to specify multiple short options after a single "-"
+ * as long as all (except possibly the last) do not require arguments.
+ *
+ * A long option begins with "--" followed by several characters. If
+ * the option requires an argument, it may be written directly after
+ * the option name, separated by "=", or as the next argument. (That
+ * is, "--file=out.txt" or "--file out.txt".)
+ *
+ * A boolean long option '--name' automatically gets a '--no-name'
+ * companion. Given an option "--flag", then, "--flag", "--no-flag",
+ * "--flag=true" and "--flag=false" are all valid, though neither
+ * "--flag true" nor "--flag false" are allowed (since "--flag" by
+ * itself is sufficient, the following "true" or "false" is
+ * interpreted separately). You can use "yes" and "no" as synonyms for
+ * "true" and "false".
+ *
+ * Each String not starting with a "-" and not a required argument of
+ * a previous option is a non-option positional argument, as are all
+ * successive Strings. Each String after a "--" is a non-option
+ * positional argument.
+ *
+ * Parsing of numeric fields such byte, short, int, long, float, and
+ * double fields is supported. This includes both unboxed and boxed
+ * versions (e.g. int vs Integer). If there is a problem parsing the
+ * argument to match the desired type, a runtime exception is thrown.
+ *
+ * File option fields are supported by simply wrapping the string
+ * argument in a File object without testing for the existance of the
+ * file.
+ *
+ * Parameterized Collection fields such as List<File> and Set<String>
+ * are supported as long as the parameter type is otherwise supported
+ * by the option parser. The collection field should be initialized
+ * with an appropriate collection instance.
+ *
+ * The fields corresponding to options are updated as their options
+ * are processed. Any remaining positional arguments are returned as a
+ * List<String>.
+ *
+ * Here's a simple example:
+ *
+ * // This doesn't need to be a separate class, if your application doesn't warrant it.
+ * // Non-@Option fields will be ignored.
+ * class Options {
+ *     @Option(names = { "-q", "--quiet" })
+ *     boolean quiet = false;
+ *
+ *     // Boolean options require a long name if it's to be possible to explicitly turn them off.
+ *     // Here the user can use --no-color.
+ *     @Option(names = { "--color" })
+ *     boolean color = true;
+ *
+ *     @Option(names = { "-m", "--mode" })
+ *     String mode = "standard; // Supply a default just by setting the field.
+ *
+ *     @Option(names = { "-p", "--port" })
+ *     int portNumber = 8888;
+ *
+ *     // There's no need to offer a short name for rarely-used options.
+ *     @Option(names = { "--timeout" })
+ *     double timeout = 1.0;
+ *
+ *     @Option(names = { "-o", "--output-file" })
+ *     File output;
+ *
+ *     // Multiple options are added to the collection.
+ *     // The collection field itself must be non-null.
+ *     @Option(names = { "-i", "--input-file" })
+ *     List<File> inputs = new ArrayList<File>();
+ *
+ * }
+ *
+ * class Main {
+ *     public static void main(String[] args) {
+ *         Options options = new Options();
+ *         List<String> inputFilenames = new OptionParser(options).parse(args);
+ *         for (String inputFilename : inputFilenames) {
+ *             if (!options.quiet) {
+ *                 ...
+ *             }
+ *             ...
+ *         }
+ *     }
+ * }
+ *
+ * See also:
+ *
+ *  the getopt(1) man page
+ *  Python's "optparse" module (http://docs.python.org/library/optparse.html)
+ *  the POSIX "Utility Syntax Guidelines" (http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap12.html#tag_12_02)
+ *  the GNU "Standards for Command Line Interfaces" (http://www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces)
+ */
+public class OptionParser {
+    private static final HashMap<Class<?>, Handler> handlers = new HashMap<Class<?>, Handler>();
+    static {
+        handlers.put(boolean.class, new BooleanHandler());
+        handlers.put(Boolean.class, new BooleanHandler());
+
+        handlers.put(byte.class, new ByteHandler());
+        handlers.put(Byte.class, new ByteHandler());
+        handlers.put(short.class, new ShortHandler());
+        handlers.put(Short.class, new ShortHandler());
+        handlers.put(int.class, new IntegerHandler());
+        handlers.put(Integer.class, new IntegerHandler());
+        handlers.put(long.class, new LongHandler());
+        handlers.put(Long.class, new LongHandler());
+
+        handlers.put(float.class, new FloatHandler());
+        handlers.put(Float.class, new FloatHandler());
+        handlers.put(double.class, new DoubleHandler());
+        handlers.put(Double.class, new DoubleHandler());
+
+        handlers.put(String.class, new StringHandler());
+        handlers.put(File.class, new FileHandler());
+    }
+    Handler getHandler(Type type) {
+        if (type instanceof ParameterizedType) {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            Class rawClass = (Class<?>) parameterizedType.getRawType();
+            if (!Collection.class.isAssignableFrom(rawClass)) {
+                throw new RuntimeException("cannot handle non-collection parameterized type " + type);
+            }
+            Type actualType = parameterizedType.getActualTypeArguments()[0];
+            if (!(actualType instanceof Class)) {
+                throw new RuntimeException("cannot handle nested parameterized type " + type);
+            }
+            return getHandler(actualType);
+        }
+        if (type instanceof Class) {
+            if (Collection.class.isAssignableFrom((Class) type)) {
+                // could handle by just having a default of treating
+                // contents as String but consciously decided this
+                // should be an error
+                throw new RuntimeException(
+                        "cannot handle non-parameterized collection " + type + ". " +
+                        "use a generic Collection to specify a desired element type");
+            }
+            return handlers.get((Class<?>) type);
+        }
+        throw new RuntimeException("cannot handle unknown field type " + type);
+    }
+
+    private final Object optionSource;
+    private final HashMap<String, Field> optionMap;
+
+    /**
+     * Constructs a new OptionParser for setting the @Option fields of 'optionSource'.
+     */
+    public OptionParser(Object optionSource) {
+        this.optionSource = optionSource;
+        this.optionMap = makeOptionMap();
+    }
+
+    /**
+     * Parses the command-line arguments 'args', setting the @Option fields of the 'optionSource' provided to the constructor.
+     * Returns a list of the positional arguments left over after processing all options.
+     */
+    public List<String> parse(String[] args) {
+        return parseOptions(Arrays.asList(args).iterator());
+    }
+
+    private List<String> parseOptions(Iterator<String> args) {
+        final List<String> leftovers = new ArrayList<String>();
+
+        // Scan 'args'.
+        while (args.hasNext()) {
+            final String arg = args.next();
+            if (arg.equals("--")) {
+                // "--" marks the end of options and the beginning of positional arguments.
+                break;
+            } else if (arg.startsWith("--")) {
+                // A long option.
+                parseLongOption(arg, args);
+            } else if (arg.startsWith("-")) {
+                // A short option.
+                parseGroupedShortOptions(arg, args);
+            } else {
+                // The first non-option marks the end of options.
+                leftovers.add(arg);
+                break;
+            }
+        }
+
+        // Package up the leftovers.
+        while (args.hasNext()) {
+            leftovers.add(args.next());
+        }
+        return leftovers;
+    }
+
+    private Field fieldForArg(String name) {
+        final Field field = optionMap.get(name);
+        if (field == null) {
+            throw new RuntimeException("unrecognized option '" + name + "'");
+        }
+        return field;
+    }
+
+    private void parseLongOption(String arg, Iterator<String> args) {
+        String name = arg.replaceFirst("^--no-", "--");
+        String value = null;
+
+        // Support "--name=value" as well as "--name value".
+        final int equalsIndex = name.indexOf('=');
+        if (equalsIndex != -1) {
+            value = name.substring(equalsIndex + 1);
+            name = name.substring(0, equalsIndex);
+        }
+
+        final Field field = fieldForArg(name);
+        final Handler handler = getHandler(field.getGenericType());
+        if (value == null) {
+            if (handler.isBoolean()) {
+                value = arg.startsWith("--no-") ? "false" : "true";
+            } else {
+                value = grabNextValue(args, name, field);
+            }
+        }
+        setValue(optionSource, field, arg, handler, value);
+    }
+
+    // Given boolean options a and b, and non-boolean option f, we want to allow:
+    // -ab
+    // -abf out.txt
+    // -abfout.txt
+    // (But not -abf=out.txt --- POSIX doesn't mention that either way, but GNU expressly forbids it.)
+    private void parseGroupedShortOptions(String arg, Iterator<String> args) {
+        for (int i = 1; i < arg.length(); ++i) {
+            final String name = "-" + arg.charAt(i);
+            final Field field = fieldForArg(name);
+            final Handler handler = getHandler(field.getGenericType());
+            String value;
+            if (handler.isBoolean()) {
+                value = "true";
+            } else {
+                // We need a value. If there's anything left, we take the rest of this "short option".
+                if (i + 1 < arg.length()) {
+                    value = arg.substring(i + 1);
+                    i = arg.length() - 1;
+                } else {
+                    value = grabNextValue(args, name, field);
+                }
+            }
+            setValue(optionSource, field, arg, handler, value);
+        }
+    }
+
+    private static void setValue(Object object, Field field, String arg, Handler handler, String valueText) {
+
+        Object value = handler.translate(valueText);
+        if (value == null) {
+            final String type = field.getType().getSimpleName().toLowerCase();
+            throw new RuntimeException("couldn't convert '" + valueText + "' to a " + type + " for option '" + arg + "'");
+        }
+        try {
+            field.setAccessible(true);
+            if (Collection.class.isAssignableFrom(field.getType())) {
+                Collection collection = (Collection)field.get(object);
+                collection.add(value);
+            } else {
+                field.set(object, value);
+            }
+        } catch (IllegalAccessException ex) {
+            throw new RuntimeException("internal error", ex);
+        }
+    }
+
+    // Returns the next element of 'args' if there is one. Uses 'name' and 'field' to construct a helpful error message.
+    private String grabNextValue(Iterator<String> args, String name, Field field) {
+        if (!args.hasNext()) {
+            final String type = field.getType().getSimpleName().toLowerCase();
+            throw new RuntimeException("option '" + name + "' requires a " + type + " argument");
+        }
+        return args.next();
+    }
+
+    // Cache the available options and report any problems with the options themselves right away.
+    private HashMap<String, Field> makeOptionMap() {
+        final HashMap<String, Field> optionMap = new HashMap<String, Field>();
+        final Class<?> optionClass = optionSource.getClass();
+        for (Field field : optionClass.getDeclaredFields()) {
+            if (field.isAnnotationPresent(Option.class)) {
+                final Option option = field.getAnnotation(Option.class);
+                final String[] names = option.names();
+                if (names.length == 0) {
+                    throw new RuntimeException("found an @Option with no name!");
+                }
+                for (String name : names) {
+                    if (optionMap.put(name, field) != null) {
+                        throw new RuntimeException("found multiple @Options sharing the name '" + name + "'");
+                    }
+                }
+                if (getHandler(field.getGenericType()) == null) {
+                    throw new RuntimeException("unsupported @Option field type '" + field.getType() + "'");
+                }
+            }
+        }
+        return optionMap;
+    }
+
+    static abstract class Handler {
+        // Only BooleanHandler should ever override this.
+        boolean isBoolean() {
+            return false;
+        }
+
+        /**
+         * Returns an object of appropriate type for the given Handle, corresponding to 'valueText'.
+         * Returns null on failure.
+         */
+        abstract Object translate(String valueText);
+    }
+
+    static class BooleanHandler extends Handler {
+        @Override boolean isBoolean() {
+            return true;
+        }
+
+        Object translate(String valueText) {
+            if (valueText.equalsIgnoreCase("true") || valueText.equalsIgnoreCase("yes")) {
+                return Boolean.TRUE;
+            } else if (valueText.equalsIgnoreCase("false") || valueText.equalsIgnoreCase("no")) {
+                return Boolean.FALSE;
+            }
+            return null;
+        }
+    }
+
+    static class ByteHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Byte.parseByte(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class ShortHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Short.parseShort(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class IntegerHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Integer.parseInt(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class LongHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Long.parseLong(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class FloatHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Float.parseFloat(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class DoubleHandler extends Handler {
+        Object translate(String valueText) {
+            try {
+                return Double.parseDouble(valueText);
+            } catch (NumberFormatException ex) {
+                return null;
+            }
+        }
+    }
+
+    static class StringHandler extends Handler {
+        Object translate(String valueText) {
+            return valueText;
+        }
+    }
+
+    static class FileHandler extends Handler {
+        Object translate(String valueText) {
+            return new File(valueText);
+        }
+    }
+}
diff --git a/libcore/tools/runner/java/dalvik/runner/Vm.java b/libcore/tools/runner/java/dalvik/runner/Vm.java
index 3d66fce..3afd7ae 100644
--- a/libcore/tools/runner/java/dalvik/runner/Vm.java
+++ b/libcore/tools/runner/java/dalvik/runner/Vm.java
@@ -51,11 +51,11 @@
 
     private final Pattern JAVA_TEST_PATTERN = Pattern.compile("\\/(\\w)+\\.java$");
     static final Classpath COMPILATION_CLASSPATH = Classpath.of(
-            new File("out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar"),
-            new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar"),
-            new File("out/target/common/obj/JAVA_LIBRARIES/jsr305_intermediates/classes.jar"),
-            new File("out/target/common/obj/JAVA_LIBRARIES/guava_intermediates/classes.jar"),
-            new File("out/target/common/obj/JAVA_LIBRARIES/caliper_intermediates/classes.jar"));
+            new File("out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar").getAbsoluteFile(),
+            new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar").getAbsoluteFile(),
+            new File("out/target/common/obj/JAVA_LIBRARIES/jsr305_intermediates/classes.jar").getAbsoluteFile(),
+            new File("out/target/common/obj/JAVA_LIBRARIES/guava_intermediates/classes.jar").getAbsoluteFile(),
+            new File("out/target/common/obj/JAVA_LIBRARIES/caliper_intermediates/classes.jar").getAbsoluteFile());
 
     private static final Logger logger = Logger.getLogger(Vm.class.getName());
 
diff --git a/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
index eacf0a0..5a3c48c 100644
--- a/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
+++ b/libcore/xml/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -17,6 +17,8 @@
 package org.apache.harmony.xml.parsers;
 
 import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
 import java.util.StringTokenizer;
 
 import javax.xml.parsers.DocumentBuilder;
@@ -122,10 +124,16 @@
                 parser.setInput(source.getByteStream(), source.getEncoding());
             } else if (source.getCharacterStream() != null) {
                 parser.setInput(source.getCharacterStream());
+            } else if (source.getSystemId() != null) {
+                URL url = new URL(source.getSystemId());
+                URLConnection urlConnection = url.openConnection();
+                urlConnection.connect();
+                String encoding = source.getEncoding();
+                // TODO: if null, extract the encoding from the Content-Type header?
+                parser.setInput(urlConnection.getInputStream(), encoding);
             } else {
-                // TODO Accept other sources as well?
                 throw new SAXParseException(
-                        "InputSource needs either stream or reader", null);
+                        "InputSource needs a stream, reader or URI", null);
             }
 
             if(parser.nextToken() == XmlPullParser.END_DOCUMENT) {
diff --git a/libcore/xml/src/main/java/org/apache/xml/dtm/DTMException.java b/libcore/xml/src/main/java/org/apache/xml/dtm/DTMException.java
index ebb3024..030dc1f 100644
--- a/libcore/xml/src/main/java/org/apache/xml/dtm/DTMException.java
+++ b/libcore/xml/src/main/java/org/apache/xml/dtm/DTMException.java
@@ -323,7 +323,7 @@
 
         boolean isJdk14OrHigher = false;
         try {
-            Throwable.class.getMethod("getCause",null);
+            Throwable.class.getMethod("getCause", (Class<?>) null);
             isJdk14OrHigher = true;
         } catch (NoSuchMethodException nsme) {
             // do nothing
@@ -357,12 +357,12 @@
                 try {
                     Method meth =
                         ((Object) exception).getClass().getMethod("getException",
-                            null);
+                            (Class<?>) null);
     
                     if (null != meth) {
                         Throwable prev = exception;
     
-                        exception = (Throwable) meth.invoke(exception, null);
+                        exception = (Throwable) meth.invoke(exception, (Class<?>) null);
     
                         if (prev == exception) {
                             break;
diff --git a/libcore/xml/src/main/java/org/apache/xpath/XPathException.java b/libcore/xml/src/main/java/org/apache/xpath/XPathException.java
index b5e682a..315a5d6 100644
--- a/libcore/xml/src/main/java/org/apache/xpath/XPathException.java
+++ b/libcore/xml/src/main/java/org/apache/xpath/XPathException.java
@@ -267,7 +267,7 @@
     
     boolean isJdk14OrHigher = false;
     try {
-        Throwable.class.getMethod("getCause",null);
+        Throwable.class.getMethod("getCause", (Class<?>) null);
         isJdk14OrHigher = true;
     } catch (NoSuchMethodException nsme) {
         // do nothing
diff --git a/libcore/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp b/libcore/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
index 1944bdc..4721800 100644
--- a/libcore/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
+++ b/libcore/xml/src/main/native/org_apache_harmony_xml_ExpatParser.cpp
@@ -471,7 +471,9 @@
     }
 
     /**
-     * Returns the element or attribute local name, like "h1". Never empty.
+     * Returns the element or attribute local name, like "h1". Never empty. When
+     * namespace processing is disabled, this may contain a prefix, yielding a
+     * local name like "html:h1". In such cases, the qName will always be empty.
      */
     jstring localName() {
         return internString(mEnv, mParsingContext, mLocalName);
@@ -504,13 +506,17 @@
     bool matchesQName(const char* qName) {
         char* lastColon = strrchr(qName, ':');
 
-        // if the input doesn't have a colon, there's no namespace prefix. Our
-        // prefix must be empty and the qName must equal our localName
-        if (lastColon == NULL) {
-            return strlen(mPrefix) == 0 && strcmp(qName, mLocalName) == 0;
+        // Compare local names only if either:
+        //  - the input qualified name doesn't have a colon (like "h1")
+        //  - this element doesn't have a prefix. Such is the case when it
+        //    doesn't belong to a namespace, or when this parser's namespace
+        //    processing is disabled. In the latter case, this element's local
+        //    name may still contain a colon (like "html:h1").
+        if (lastColon == NULL || *mPrefix == 0) {
+            return strcmp(qName, mLocalName) == 0;
         }
 
-        // otherwise the prefixes must be equal and our localName must equal qName
+        // Otherwise compare both prefix and local name
         size_t prefixLength = lastColon - qName;
         return strlen(mPrefix) == prefixLength
             && strncmp(qName, mPrefix, prefixLength) == 0
@@ -1004,7 +1010,7 @@
 }
 
 /**
- * Creates a new Expat parser. Called from the Java ExpatParser contructor.
+ * Creates a new Expat parser. Called from the Java ExpatParser constructor.
  *
  * @param object the Java ExpatParser instance
  * @param javaEncoding the character encoding name
@@ -1208,11 +1214,6 @@
         jint attributePointer, jint index) {
     XML_Parser parser = (XML_Parser) pointer;
     ParsingContext* context = (ParsingContext*) XML_GetUserData(parser);
-
-    if (!context->processNamespaces) {
-        return emptyString;
-    }
-
     return ExpatElementName(env, context, attributePointer, index).uri();
 }
 
@@ -1229,11 +1230,6 @@
         jint attributePointer, jint index) {
     XML_Parser parser = (XML_Parser) pointer;
     ParsingContext* context = (ParsingContext*) XML_GetUserData(parser);
-
-    if (!context->processNamespaces) {
-        return emptyString;
-    }
-
     return ExpatElementName(env, context, attributePointer, index).localName();
 }
 
@@ -1250,11 +1246,6 @@
         jint attributePointer, jint index) {
     XML_Parser parser = (XML_Parser) pointer;
     ParsingContext* context = (ParsingContext*) XML_GetUserData(parser);
-
-    if (context->processNamespaces) {
-        return emptyString;
-    }
-
     return ExpatElementName(env, context, attributePointer, index).qName();
 }
 
diff --git a/libcore/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java b/libcore/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java
new file mode 100644
index 0000000..4f58262
--- /dev/null
+++ b/libcore/xml/src/test/java/org/apache/harmony/xml/NamespacedAttributesLookupTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 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.xml;
+
+import junit.framework.TestCase;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParserFactory;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests that we both report and retrieve attributes using the appropriate
+ * names for different combinations of namespaces and namespace prefixes.
+ */
+public class NamespacedAttributesLookupTest extends TestCase {
+
+    private static final String SAX_PROPERTY_NS =
+            "http://xml.org/sax/features/namespaces";
+    private static final String SAX_PROPERTY_NS_PREFIXES =
+            "http://xml.org/sax/features/namespace-prefixes";
+
+    private static String xml = "<?xml version='1.0' encoding='UTF-8'?>" +
+            "<test xmlns='http://foo' xmlns:bar='http://bar' xmlns:baz='http://baz' baz:c='a'>" +
+            "<b c='w' bar:c='x'/>" +
+            "<bar:e baz:c='y' bar:c='z'/>" +
+            "</test>";
+
+    public void testNamespace() throws Exception {
+        List<String> expected = Arrays.asList(
+                "http://foo,test\n" +
+                "  http://baz,c\n" +
+                "  http://bar+c=null,\n" +
+                "  bar:c=null\n",
+
+                "http://foo,b\n" +
+                "  ,c\n" +
+                "  http://bar,c\n" +
+                "  http://bar+c=x,\n" +
+                "  bar:c=x\n",
+
+                "http://bar,e\n" +
+                "  http://baz,c\n" +
+                "  http://bar,c\n" +
+                "  http://bar+c=z,\n" +
+                "  bar:c=z\n");
+
+        boolean namespace = true;
+        boolean namespacePrefixes = false;
+        assertEquals(expected, getStartElements(xml, namespace, namespacePrefixes));
+    }
+
+    public void testNamespacePrefixes() throws Exception {
+        List<String> expected = Arrays.asList(
+                "test\n" +
+                "  xmlns\n" +
+                "  xmlns:bar\n" +
+                "  xmlns:baz\n" +
+                "  baz:c\n" +
+                "  http://bar+c=null,\n" +
+                "  bar:c=null\n",
+
+                "b\n" +
+                "  c\n" +
+                "  bar:c\n" +
+                "  http://bar+c=null,\n" +
+                "  bar:c=x\n",
+
+                "bar:e\n" +
+                "  baz:c\n" +
+                "  bar:c\n" +
+                "  http://bar+c=null,\n" +
+                "  bar:c=z\n");
+
+        boolean namespace = false;
+        boolean namespacePrefixes = true;
+        assertEquals(expected, getStartElements(xml, namespace, namespacePrefixes));
+    }
+
+    public List<String> getStartElements(String xml, final boolean namespace, boolean namespacePrefixes)
+            throws Exception {
+        final List<String> result = new ArrayList<String>();
+        XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+        reader.setFeature(SAX_PROPERTY_NS, namespace);
+        reader.setFeature(SAX_PROPERTY_NS_PREFIXES, namespacePrefixes);
+        reader.setContentHandler(new DefaultHandler() {
+            @Override public final void startElement(
+                    String uri, String localName, String qName, Attributes attributes) {
+                StringBuilder serialized = new StringBuilder();
+                /*
+                 * Only supply the uri+localName or qname depending on whether namespaces are
+                 * enabled. It's an optional parameter and the RI only supplies one or the other.
+                 */
+                if (namespace) {
+                    serialized.append(uri).append(",");
+                    serialized.append(localName);
+                } else {
+                    serialized.append(qName);
+                }
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    serialized.append("\n  ");
+                    if (namespace) {
+                        serialized.append(attributes.getURI(i)).append(",");
+                        serialized.append(attributes.getLocalName(i));
+                    } else {
+                        serialized.append(attributes.getQName(i));
+                    }
+                }
+                serialized.append("\n  http://bar+c=")
+                        .append(attributes.getValue("http://bar", "c")).append(",")
+                        .append("\n  bar:c=")
+                        .append(attributes.getValue("bar:c"))
+                        .append("\n");
+                result.add(serialized.toString());
+            }
+        });
+        reader.parse(new InputSource(new StringReader(xml)));
+        return result;
+    }
+}
diff --git a/libcore/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java b/libcore/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
new file mode 100644
index 0000000..7773814
--- /dev/null
+++ b/libcore/xml/src/test/java/org/apache/harmony/xml/XsltXPathConformanceTestSuite.java
@@ -0,0 +1,484 @@
+/*
+ * Copyright (C) 2010 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.xml;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import junit.textui.TestRunner;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Comment;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Text;
+import org.xml.sax.SAXException;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The <a href="http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xslt">OASIS
+ * XSLT conformance test suite</a>, adapted for use by JUnit. To run these tests
+ * on a device:
+ * <ul>
+ *    <li>Obtain the <a href="http://www.oasis-open.org/committees/download.php/12171/XSLT-testsuite-04.ZIP">test
+ *        suite zip file from the OASIS project site.</li>
+ *    <li>Unzip.
+ *    <li>Copy the files to a device: <code>adb shell mkdir /data/oasis ;
+ *        adb push ./XSLT-Conformance-TC /data/oasis</code>.
+ *    <li>Invoke this class' main method, passing the on-device path to the test
+ *        suite's <code>catalog.xml</code> file as an argument.
+ * </ul>
+ */
+public class XsltXPathConformanceTestSuite {
+
+    private static final String defaultCatalogFile
+            = "/home/dalvik-prebuild/OASIS/XSLT-Conformance-TC/TESTS/catalog.xml";
+
+    /** Orders element attributes by optional URI and name. */
+    private static final Comparator<Attr> orderByName = new Comparator<Attr>() {
+        public int compare(Attr a, Attr b) {
+            int result = compareNullsFirst(a.getBaseURI(), b.getBaseURI());
+            return result == 0 ? result
+                    : compareNullsFirst(a.getName(), b.getName());
+        }
+
+        <T extends Comparable<T>> int compareNullsFirst(T a, T b) {
+            return (a == b) ? 0
+                    : (a == null) ? -1
+                    : (b == null) ? 1
+                    : a.compareTo(b);
+        }
+    };
+
+    private final DocumentBuilder documentBuilder;
+    private final TransformerFactory transformerFactory;
+    private final XmlPullParserFactory xmlPullParserFactory;
+
+    public XsltXPathConformanceTestSuite()
+            throws ParserConfigurationException, XmlPullParserException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        factory.setCoalescing(true);
+        documentBuilder = factory.newDocumentBuilder();
+
+        transformerFactory = TransformerFactory.newInstance();
+        xmlPullParserFactory = XmlPullParserFactory.newInstance();
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length != 1) {
+            System.out.println("Usage: XsltXPathConformanceTestSuite <catalog-xml>");
+            System.out.println();
+            System.out.println("  catalog-xml: an XML file describing an OASIS test suite");
+            System.out.println("               such as: " + defaultCatalogFile);
+            return;
+        }
+
+        File catalogXml = new File(args[0]);
+        TestRunner.run(suite(catalogXml));
+    }
+
+    public static Test suite() throws Exception {
+        return suite(new File(defaultCatalogFile));
+    }
+
+    /**
+     * Returns a JUnit test suite for the tests described by the given document.
+     */
+    public static Test suite(File catalogXml) throws Exception {
+        XsltXPathConformanceTestSuite suite = new XsltXPathConformanceTestSuite();
+
+        /*
+         * Extract the tests from an XML document with the following structure:
+         *
+         *  <test-suite>
+         *    <test-catalog submitter="Lotus">
+         *      <creator>Lotus/IBM</creator>
+         *      <major-path>Xalan_Conformance_Tests</major-path>
+         *      <date>2001-11-16</date>
+         *      <test-case ...> ... </test-case>
+         *      <test-case ...> ... </test-case>
+         *      <test-case ...> ... </test-case>
+         *    </test-catalog>
+         *  </test-suite>
+         */
+
+        Document document = DocumentBuilderFactory.newInstance()
+                .newDocumentBuilder().parse(catalogXml);
+        Element testSuiteElement = document.getDocumentElement();
+        TestSuite result = new TestSuite();
+        for (Element testCatalog : elementsOf(testSuiteElement.getElementsByTagName("test-catalog"))) {
+            Element majorPathElement = (Element) testCatalog.getElementsByTagName("major-path").item(0);
+            String majorPath = majorPathElement.getTextContent();
+            File base = new File(catalogXml.getParentFile(), majorPath);
+
+            for (Element testCaseElement : elementsOf(testCatalog.getElementsByTagName("test-case"))) {
+                result.addTest(suite.create(base, testCaseElement));
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a JUnit test for the test described by the given element.
+     */
+    private Test create(File base, Element testCaseElement) {
+
+        /*
+         * Extract the XSLT test from a DOM entity with the following structure:
+         *
+         *   <test-case category="XSLT-Result-Tree" id="attribset_attribset01">
+         *       <file-path>attribset</file-path>
+         *       <creator>Paul Dick</creator>
+         *       <date>2001-11-08</date>
+         *       <purpose>Set attribute of a LRE from single attribute set.</purpose>
+         *       <spec-citation place="7.1.4" type="section" version="1.0" spec="xslt"/>
+         *        <scenario operation="standard">
+         *           <input-file role="principal-data">attribset01.xml</input-file>
+         *           <input-file role="principal-stylesheet">attribset01.xsl</input-file>
+         *           <output-file role="principal" compare="XML">attribset01.out</output-file>
+         *       </scenario>
+         *   </test-case>
+         */
+
+        Element filePathElement = (Element) testCaseElement.getElementsByTagName("file-path").item(0);
+        Element purposeElement = (Element) testCaseElement.getElementsByTagName("purpose").item(0);
+        Element specCitationElement = (Element) testCaseElement.getElementsByTagName("spec-citation").item(0);
+        Element scenarioElement = (Element) testCaseElement.getElementsByTagName("scenario").item(0);
+
+        String category = testCaseElement.getAttribute("category");
+        String id = testCaseElement.getAttribute("id");
+        String name = category + "." + id;
+        String purpose = purposeElement != null ? purposeElement.getTextContent() : "";
+        String spec = "place=" + specCitationElement.getAttribute("place")
+                + " type" + specCitationElement.getAttribute("type")
+                + " version=" + specCitationElement.getAttribute("version")
+                + " spec=" + specCitationElement.getAttribute("spec");
+        String operation = scenarioElement.getAttribute("operation");
+
+        Element principalDataElement = null;
+        Element principalStylesheetElement = null;
+        Element principalElement = null;
+
+        for (Element element : elementsOf(scenarioElement.getChildNodes())) {
+            String role = element.getAttribute("role");
+            if (role.equals("principal-data")) {
+                principalDataElement = element;
+            } else if (role.equals("principal-stylesheet")) {
+                principalStylesheetElement = element;
+            } else if (role.equals("principal")) {
+                principalElement = element;
+            } else if (!role.equals("supplemental-stylesheet")
+                    && !role.equals("supplemental-data")) {
+                return new MisspecifiedTest("Unexpected element at " + name);
+            }
+        }
+
+        String testDirectory = filePathElement.getTextContent();
+        File inBase = new File(base, testDirectory);
+        File outBase = new File(new File(base, "REF_OUT"), testDirectory);
+
+        if (principalDataElement == null || principalStylesheetElement == null) {
+            return new MisspecifiedTest("Expected <scenario> to have "
+                    + "principal=data and principal-stylesheet elements at " + name);
+        }
+
+        try {
+            File principalData = findFile(inBase, principalDataElement.getTextContent());
+            File principalStylesheet = findFile(inBase, principalStylesheetElement.getTextContent());
+
+            final File principal;
+            final String compareAs;
+            if (!operation.equals("execution-error")) {
+                if (principalElement == null) {
+                    return new MisspecifiedTest("Expected <scenario> to have principal element at " + name);
+                }
+
+                principal = findFile(outBase, principalElement.getTextContent());
+                compareAs = principalElement.getAttribute("compare");
+            } else {
+                principal = null;
+                compareAs = null;
+            }
+
+            return new XsltTest(category, id, purpose, spec, principalData,
+                    principalStylesheet, principal, operation, compareAs);
+        } catch (FileNotFoundException e) {
+            return new MisspecifiedTest(e.getMessage() + " at " + name);
+        }
+    }
+
+    /**
+     * Finds the named file in the named directory. This tries extra hard to
+     * avoid case-insensitive-naming problems, where the requested file is
+     * available in a different casing.
+     */
+    private File findFile(File directory, String name) throws FileNotFoundException {
+        File file = new File(directory, name);
+        if (file.exists()) {
+            return file;
+        }
+
+        for (String child : directory.list()) {
+            if (child.equalsIgnoreCase(name)) {
+                return new File(directory, child);
+            }
+        }
+
+        throw new FileNotFoundException("Missing file: " + file);
+    }
+
+    /**
+     * Placeholder for a test that couldn't be configured to run properly.
+     */
+    public class MisspecifiedTest extends TestCase {
+        private final String message;
+
+        MisspecifiedTest(String message) {
+            super("test");
+            this.message = message;
+        }
+
+        public void test() {
+            fail(message);
+        }
+    }
+
+    /**
+     * Processes an input XML file with an input XSLT stylesheet and compares
+     * the result to an expected output file.
+     */
+    public class XsltTest extends TestCase {
+        // TODO: include these in toString
+        private final String category;
+        private final String id;
+        private final String purpose;
+        private final String spec;
+
+        private final File principalData;
+        private final File principalStylesheet;
+        private final File principal;
+
+        /** either "standard" or "execution-error" */
+        private final String operation;
+
+        /** the syntax to compare the output file using, such as "XML" or "HTML" */
+        private final String compareAs;
+
+        XsltTest(String category, String id, String purpose, String spec,
+                File principalData, File principalStylesheet, File principal,
+                String operation, String compareAs) {
+            super("test");
+            this.category = category;
+            this.id = id;
+            this.purpose = purpose;
+            this.spec = spec;
+            this.principalData = principalData;
+            this.principalStylesheet = principalStylesheet;
+            this.principal = principal;
+            this.operation = operation;
+            this.compareAs = compareAs;
+        }
+
+        public void test() throws Exception {
+            if (purpose != null) {
+                System.out.println("Purpose: " + purpose);
+            }
+            if (spec != null) {
+                System.out.println("Spec: " + spec);
+            }
+
+            Source xslt = new StreamSource(principalStylesheet);
+            Source in = new StreamSource(principalData);
+
+            Transformer transformer;
+            try {
+                transformer = transformerFactory.newTransformer(xslt);
+                assertEquals("Expected transformer creation to fail",
+                        "standard", operation);
+            } catch (TransformerConfigurationException e) {
+                if (operation.equals("execution-error")) {
+                    return; // expected, such as in XSLT-Result-Tree.Attributes__78369
+                }
+                AssertionFailedError failure = new AssertionFailedError();
+                failure.initCause(e);
+                throw failure;
+            }
+
+            Result result;
+            if (compareAs.equals("XML")) {
+                result = new DOMResult();
+            } else {
+                // TODO: implement support for comparing HTML etc.
+                throw new UnsupportedOperationException("Cannot compare as " + compareAs);
+            }
+
+            transformer.transform(in, result);
+
+            if (compareAs.equals("XML")) {
+                DOMResult domResult = (DOMResult) result;
+                assertNodesAreEquivalent(principal, domResult.getNode());
+            }
+        }
+
+        @Override public String getName() {
+            return category + "." + id;
+        }
+    }
+
+    /**
+     * Ensures both XML documents represent the same semantic data. Non-semantic
+     * data such as namespace prefixes, comments, and whitespace is ignored.
+     */
+    private void assertNodesAreEquivalent(File expected, Node actual)
+            throws ParserConfigurationException, IOException, SAXException,
+            XmlPullParserException {
+
+        Document expectedDocument = documentBuilder.parse(new FileInputStream(expected));
+        String expectedString = nodeToNormalizedString(expectedDocument);
+        String actualString = nodeToNormalizedString(actual);
+
+        Assert.assertEquals("Expected XML to match file " + expected,
+                expectedString, actualString);
+    }
+
+    private String nodeToNormalizedString(Node node)
+            throws XmlPullParserException, IOException {
+        StringWriter writer = new StringWriter();
+        XmlSerializer xmlSerializer = xmlPullParserFactory.newSerializer();
+        xmlSerializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+        xmlSerializer.setOutput(writer);
+        emitNode(xmlSerializer, node);
+        xmlSerializer.flush();
+        return writer.toString();
+    }
+
+    private void emitNode(XmlSerializer serializer, Node node) throws IOException {
+        if (node instanceof Element) {
+            Element element = (Element) node;
+            serializer.startTag(element.getBaseURI(), element.getLocalName());
+            emitAttributes(serializer, element);
+            emitChildren(serializer, element);
+            serializer.endTag(element.getBaseURI(), element.getLocalName());
+
+        } else if (node instanceof Text) {
+            // TODO: is it okay to trim whitespace in general? This may cause
+            //     false positives for elements like HTML's <pre> tag
+            String trimmed = node.getTextContent().trim();
+            if (trimmed.length() > 0) {
+                serializer.text(trimmed);
+            }
+
+        } else if (node instanceof Document) {
+            Document document = (Document) node;
+            serializer.startDocument("UTF-8", true);
+            emitNode(serializer, document.getDocumentElement());
+            serializer.endDocument();
+
+        } else if (node instanceof ProcessingInstruction) {
+            ProcessingInstruction processingInstruction = (ProcessingInstruction) node;
+            String data = processingInstruction.getData();
+            String target = processingInstruction.getTarget();
+            serializer.processingInstruction(target + " " + data);
+
+        } else if (node instanceof Comment) {
+            // ignore!
+
+        } else {
+            Object nodeClass = node != null ? node.getClass() : null;
+            throw new UnsupportedOperationException(
+                    "Cannot serialize nodes of type " + nodeClass);
+        }
+    }
+
+    private void emitAttributes(XmlSerializer serializer, Node node)
+            throws IOException {
+        NamedNodeMap map = node.getAttributes();
+        if (map == null) {
+            return;
+        }
+
+        List<Attr> attributes = new ArrayList<Attr>();
+        for (int i = 0; i < map.getLength(); i++) {
+            attributes.add((Attr) map.item(i));
+        }
+        Collections.sort(attributes, orderByName);
+
+        for (Attr attr : attributes) {
+            if ("xmlns".equals(attr.getPrefix()) || "xmlns".equals(attr.getLocalName())) {
+                /*
+                 * Omit namespace declarations because they aren't considered
+                 * data. Ie. <foo:a xmlns:bar="http://google.com"> is semantically
+                 * equal to <bar:a xmlns:bar="http://google.com"> since the
+                 * prefix doesn't matter, only the URI it points to.
+                 *
+                 * When we omit the prefix, our XML serializer will still
+                 * generate one for us, using a predictable pattern.
+                 */
+            } else {
+                serializer.attribute(attr.getBaseURI(), attr.getLocalName(), attr.getValue());
+            }
+        }
+    }
+
+    private void emitChildren(XmlSerializer serializer, Node node)
+            throws IOException {
+        NodeList childNodes = node.getChildNodes();
+        for (int i = 0; i < childNodes.getLength(); i++) {
+            emitNode(serializer, childNodes.item(i));
+        }
+    }
+
+    private static List<Element> elementsOf(NodeList nodeList) {
+        List<Element> result = new ArrayList<Element>();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            if (node instanceof Element) {
+                result.add((Element) node);
+            }
+        }
+        return result;
+    }
+}
diff --git a/libcore/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java b/libcore/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
index 292c2f1..02b6d80 100644
--- a/libcore/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
+++ b/libcore/xml/src/test/java/tests/api/javax/xml/parsers/DocumentBuilderTest.java
@@ -16,6 +16,28 @@
 
 package tests.api.javax.xml.parsers;
 
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import junit.framework.TestCase;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.EntityReference;
+import org.w3c.dom.Text;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import tests.api.org.xml.sax.support.MethodLogger;
+import tests.api.org.xml.sax.support.MockHandler;
+import tests.api.org.xml.sax.support.MockResolver;
+import tests.util.TestEnvironment;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -23,33 +45,6 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.logging.Logger;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-import junit.framework.TestCase;
-
-import org.w3c.dom.DOMImplementation;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.EntityReference;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.w3c.dom.Text;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-import tests.api.org.xml.sax.support.MethodLogger;
-import tests.api.org.xml.sax.support.MockHandler;
-import tests.api.org.xml.sax.support.MockResolver;
-import dalvik.annotation.KnownFailure;
-import dalvik.annotation.TestLevel;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargetNew;
 
 @TestTargetClass(DocumentBuilder.class) 
 public class DocumentBuilderTest extends TestCase {
@@ -133,6 +128,8 @@
     DocumentBuilder db;
 
     protected void setUp() throws Exception {
+        TestEnvironment.reset();
+
         dbf = DocumentBuilderFactory.newInstance();
         
         dbf.setIgnoringElementContentWhitespace(true);
@@ -266,6 +263,21 @@
     }
 
     /**
+     * Tests that the Base URI for the document is populated with the file URI.
+     */
+    @TestTargetNew(
+        level = TestLevel.COMPLETE,
+        notes = "",
+        method = "parse",
+        args = {java.io.File.class}
+    )
+    public void testGetBaseURI() throws IOException, SAXException {
+        File f = resourceToTmpFile("/simple.xml");
+        Document d = db.parse(f);
+        assertTrue(d.getDocumentElement().getBaseURI().startsWith("file://"));
+    }
+
+    /**
      * @tests javax.xml.parsers.DocumentBuilder#parse(java.io.File)
      * Case 1: Try to parse correct xml document.
      * Case 2: Try to call parse() with null argument.
@@ -567,7 +579,6 @@
         method = "parse",
         args = {java.lang.String.class}
     )
-    @KnownFailure("Android DocumentBuilder should support File sources")
     public void test_parseLjava_lang_String() {
         // case 1: Trivial use.
         File f = new File(getClass().getResource("/simple.xml").getFile());
diff --git a/libcore/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTest.java b/libcore/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTest.java
index 2b8bb5c..ca7cf71 100644
--- a/libcore/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTest.java
+++ b/libcore/xml/src/test/java/tests/api/javax/xml/parsers/SAXParserTest.java
@@ -347,8 +347,6 @@
         method = "parse",
         args = {java.io.File.class, org.xml.sax.helpers.DefaultHandler.class}
     )
-    @KnownFailure("The default handler doesn't get the qName value supplied. " +
-            "We either need to change the test, or fix the parser.")
     public void test_parseLjava_io_FileLorg_xml_sax_helpers_DefaultHandler()
     throws Exception {
 
@@ -456,8 +454,6 @@
         method = "parse",
         args = {org.xml.sax.InputSource.class, org.xml.sax.helpers.DefaultHandler.class}
     )
-    @KnownFailure("The default handler doesn't get the qName value supplied. " +
-            "We either need to change the test, or fix the parser.")
     public void test_parseLorg_xml_sax_InputSourceLorg_xml_sax_helpers_DefaultHandler()
     throws Exception {
 
@@ -623,8 +619,6 @@
         method = "parse",
         args = {java.io.InputStream.class, org.xml.sax.helpers.DefaultHandler.class}
     )
-    @KnownFailure("The default handler doesn't get the qName value supplied. " +
-            "We either need to change the test, or fix the parser.")
     public void test_parseLjava_io_InputStreamLorg_xml_sax_helpers_DefaultHandler()
     throws Exception {
 
@@ -675,8 +669,6 @@
         method = "parse",
         args = {java.io.InputStream.class, org.xml.sax.helpers.DefaultHandler.class, java.lang.String.class}
     )
-    @KnownFailure("The default handler doesn't get the qName value supplied. " +
-            "We either need to change the test, or fix the parser.")
     public void test_parseLjava_io_InputStreamLorg_xml_sax_helpers_DefaultHandlerLjava_lang_String() {
         for(int i = 0; i < list_wf.length; i++) {
             try {
@@ -952,8 +944,6 @@
         method = "parse",
         args = {java.lang.String.class, org.xml.sax.helpers.DefaultHandler.class}
     )
-    @KnownFailure("The default handler doesn't get the qName value supplied. " +
-            "We either need to change the test, or fix the parser.")
     public void test_parseLjava_lang_StringLorg_xml_sax_helpers_DefaultHandler()
     throws Exception {
 
@@ -1174,4 +1164,3 @@
     }
     
 }
-
diff --git a/vm/AllocTracker.c b/vm/AllocTracker.c
index 9649e68..9fb1c4d 100644
--- a/vm/AllocTracker.c
+++ b/vm/AllocTracker.c
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * Allocation tracking and reporting.  We maintain a circular buffer with
  * the most recent allocations.  The data can be viewed through DDMS.
@@ -37,10 +38,12 @@
  *
  * TODO: consider making the parameters configurable, so DDMS can decide
  * how many allocations it wants to see and what the stack depth should be.
+ * Changing the window size is easy, changing the max stack depth is harder
+ * because we go from an array of fixed-size structs to variable-sized data.
  */
 #include "Dalvik.h"
 
-#define kMaxAllocRecordStackDepth   8       /* max 255 */
+#define kMaxAllocRecordStackDepth   16      /* max 255 */
 #define kNumAllocRecords            512     /* MUST be power of 2 */
 
 /*
@@ -108,8 +111,9 @@
     dvmLockMutex(&gDvm.allocTrackerLock);
 
     if (gDvm.allocRecords == NULL) {
-        LOGI("Enabling alloc tracker (%d entries / %d bytes)\n",
-            kNumAllocRecords, sizeof(AllocRecord) * kNumAllocRecords);
+        LOGI("Enabling alloc tracker (%d entries, %d frames --> %d bytes)\n",
+            kNumAllocRecords, kMaxAllocRecordStackDepth,
+            sizeof(AllocRecord) * kNumAllocRecords);
         gDvm.allocRecordHead = gDvm.allocRecordCount = 0;
         gDvm.allocRecords =
             (AllocRecord*) malloc(sizeof(AllocRecord) * kNumAllocRecords);
diff --git a/vm/Debugger.c b/vm/Debugger.c
index be6fa66..2f57046 100644
--- a/vm/Debugger.c
+++ b/vm/Debugger.c
@@ -418,6 +418,9 @@
     LOGI("Debugger is active\n");
     dvmInitBreakpoints();
     gDvm.debuggerActive = true;
+#if defined(WITH_JIT)
+    dvmCompilerStateRefresh();
+#endif
 }
 
 /*
@@ -445,6 +448,9 @@
 
     dvmHashTableClear(gDvm.dbgRegistry);
     dvmHashTableUnlock(gDvm.dbgRegistry);
+#if defined(WITH_JIT)
+    dvmCompilerStateRefresh();
+#endif
 }
 
 /*
@@ -3045,4 +3051,3 @@
 
     dvmJdwpDdmSendChunkV(gDvm.jdwpState, type, iov, iovcnt);
 }
-
diff --git a/vm/Globals.h b/vm/Globals.h
index bac28f6..f2dd86a 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -80,6 +80,7 @@
     bool        verboseGc;
     bool        verboseJni;
     bool        verboseClass;
+    bool        verboseShutdown;
 
     bool        jdwpAllowed;        // debugging allowed for this process?
     bool        jdwpConfigured;     // has debugging info been provided?
@@ -685,6 +686,9 @@
     /* Array of profile threshold counters */
     unsigned char *pProfTable;
 
+    /* Copy of pProfTable used for temporarily disabling the Jit */
+    unsigned char *pProfTableCopy;
+
     /* Size of JIT hash table in entries.  Must be a power of 2 */
     unsigned int jitTableSize;
 
diff --git a/vm/Init.c b/vm/Init.c
index c65ce65..5d49986 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -795,6 +795,8 @@
             gDvm.verboseJni = true;
         } else if (strcmp(argv[i], "-verbose:gc") == 0) {
             gDvm.verboseGc = true;
+        } else if (strcmp(argv[i], "-verbose:shutdown") == 0) {
+            gDvm.verboseShutdown = true;
 
         } else if (strncmp(argv[i], "-enableassertions", 17) == 0) {
             enableAssertions(argv[i] + 17, true);
@@ -954,7 +956,7 @@
                 dvmFprintf(stderr, "Bad value for -Xgc");
                 return -1;
             }
-            LOGD("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF");
+            LOGV("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF");
 
         } else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
             gDvm.verifyDexChecksum = true;
@@ -1577,7 +1579,8 @@
      */
     dvmSlayDaemons();
 
-    LOGD("VM cleaning up\n");
+    if (gDvm.verboseShutdown)
+        LOGD("VM cleaning up\n");
 
     dvmDebuggerShutdown();
     dvmReflectShutdown();
diff --git a/vm/Jni.c b/vm/Jni.c
index 7b68195..6692f3b 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -3874,7 +3874,8 @@
     if (ext == NULL)
         return JNI_ERR;
 
-    LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
+    if (gDvm.verboseShutdown)
+        LOGD("DestroyJavaVM waiting for non-daemon threads to exit\n");
 
     /*
      * Sleep on a condition variable until it's okay to exit.
@@ -3906,7 +3907,8 @@
     // TODO: call System.exit() to run any registered shutdown hooks
     // (this may not return -- figure out how this should work)
 
-    LOGD("DestroyJavaVM shutting VM down\n");
+    if (gDvm.verboseShutdown)
+        LOGD("DestroyJavaVM shutting VM down\n");
     dvmShutdown();
 
     // TODO - free resources associated with JNI-attached daemon threads
diff --git a/vm/LinearAlloc.c b/vm/LinearAlloc.c
index a8ed3ab..bf89d50 100644
--- a/vm/LinearAlloc.c
+++ b/vm/LinearAlloc.c
@@ -236,10 +236,12 @@
 
     //dvmLinearAllocDump(classLoader);
 
-    LOGV("Unmapping linear allocator base=%p\n", pHdr->mapAddr);
-    LOGD("LinearAlloc %p used %d of %d (%d%%)\n",
-        classLoader, pHdr->curOffset, pHdr->mapLength,
-        (pHdr->curOffset * 100) / pHdr->mapLength);
+    if (gDvm.verboseShutdown) {
+        LOGV("Unmapping linear allocator base=%p\n", pHdr->mapAddr);
+        LOGD("LinearAlloc %p used %d of %d (%d%%)\n",
+            classLoader, pHdr->curOffset, pHdr->mapLength,
+            (pHdr->curOffset * 100) / pHdr->mapLength);
+    }
 
     if (munmap(pHdr->mapAddr, pHdr->mapLength) != 0) {
         LOGW("LinearAlloc munmap(%p, %d) failed: %s\n",
diff --git a/vm/Profile.c b/vm/Profile.c
index dcfad71..b079988 100644
--- a/vm/Profile.c
+++ b/vm/Profile.c
@@ -230,6 +230,9 @@
     } while (!ATOMIC_CMP_SWAP(&gDvm.activeProfilers, oldValue, newValue));
 
     LOGD("+++ active profiler count now %d\n", newValue);
+#if defined(WITH_JIT)
+    dvmCompilerStateRefresh();
+#endif
 }
 
 
diff --git a/vm/SignalCatcher.c b/vm/SignalCatcher.c
index 90211fd..7edbf38 100644
--- a/vm/SignalCatcher.c
+++ b/vm/SignalCatcher.c
@@ -255,7 +255,7 @@
         } else if (rcvd == SIGUSR1) {
 #if WITH_HPROF
             LOGI("SIGUSR1 forcing GC and HPROF dump\n");
-            hprofDumpHeap(NULL);
+            hprofDumpHeap(NULL, false);
 #else
             LOGI("SIGUSR1 forcing GC (no HPROF)\n");
             dvmCollectGarbage(false);
diff --git a/vm/Sync.c b/vm/Sync.c
index acd916c..5340d86 100644
--- a/vm/Sync.c
+++ b/vm/Sync.c
@@ -504,7 +504,7 @@
 /*
  * Converts the given relative waiting time into an absolute time.
  */
-static void absoluteTime(s8 msec, s4 nsec, struct timespec *ts)
+void dvmAbsoluteTime(s8 msec, s4 nsec, struct timespec *ts)
 {
     s8 endSec;
 
@@ -589,7 +589,7 @@
     if (msec == 0 && nsec == 0) {
         timed = false;
     } else {
-        absoluteTime(msec, nsec, &ts);
+        dvmAbsoluteTime(msec, nsec, &ts);
         timed = true;
     }
 
@@ -1987,4 +1987,3 @@
 }
 
 #endif /*WITH_DEADLOCK_PREDICTION*/
-
diff --git a/vm/Sync.h b/vm/Sync.h
index 0ce3ebc..0832608 100644
--- a/vm/Sync.h
+++ b/vm/Sync.h
@@ -146,6 +146,11 @@
 bool dvmHoldsLock(struct Thread* thread, struct Object* obj);
 
 /*
+ * Converts the given relative time into an absolute time
+ */
+void dvmAbsoluteTime(s8 msec, s4 nsec, struct timespec *ts);
+
+/*
  * Debug.
  */
 void dvmDumpMonitorInfo(const char* msg);
diff --git a/vm/Thread.c b/vm/Thread.c
index 7505ec5..9e95d88 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -1285,8 +1285,6 @@
     ClassObject* nativeStart;
     Method* runMeth;
 
-    assert(thread->threadId != 1);      // not for main thread
-
     nativeStart =
         dvmFindSystemClassNoInit("Ldalvik/system/NativeStart;");
     if (nativeStart == NULL) {
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index bec30f3..4774819 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -856,7 +856,8 @@
                 (int) time(NULL), (int) getpid());
             gcHeap->hprofFileName = nameBuf;
         }
-        gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName);
+        gcHeap->hprofContext = hprofStartup(gcHeap->hprofFileName,
+                gcHeap->hprofDirectToDdms);
         if (gcHeap->hprofContext != NULL) {
             hprofStartHeapDump(gcHeap->hprofContext);
         }
@@ -1071,7 +1072,7 @@
  *
  * Returns 0 on success, or an error code on failure.
  */
-int hprofDumpHeap(const char* fileName)
+int hprofDumpHeap(const char* fileName, bool directToDdms)
 {
     int result;
 
@@ -1079,6 +1080,7 @@
 
     gDvm.gcHeap->hprofDumpOnGc = true;
     gDvm.gcHeap->hprofFileName = fileName;
+    gDvm.gcHeap->hprofDirectToDdms = directToDdms;
     dvmCollectGarbageInternal(false, GC_HPROF_DUMP_HEAP);
     result = gDvm.gcHeap->hprofResult;
 
diff --git a/vm/alloc/HeapInternal.h b/vm/alloc/HeapInternal.h
index a2d31fe..9a5071f 100644
--- a/vm/alloc/HeapInternal.h
+++ b/vm/alloc/HeapInternal.h
@@ -170,6 +170,7 @@
     const char*     hprofFileName;
     hprof_context_t *hprofContext;
     int             hprofResult;
+    bool            hprofDirectToDdms;
 #endif
 };
 
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index 3e0f669..228be5a 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -104,7 +104,7 @@
          */
         if (pthread_join(gDvm.heapWorkerHandle, &threadReturn) != 0)
             LOGW("HeapWorker thread join failed\n");
-        else
+        else if (gDvm.verboseShutdown)
             LOGD("HeapWorker thread has shut down\n");
 
         gDvm.heapWorkerReady = false;
@@ -373,7 +373,8 @@
     }
     dvmUnlockMutex(&gDvm.heapWorkerLock);
 
-    LOGD("HeapWorker thread shutting down\n");
+    if (gDvm.verboseShutdown)
+        LOGD("HeapWorker thread shutting down\n");
     return NULL;
 }
 
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index ceb1da1..9ed3a05 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -295,20 +295,8 @@
         goto fail;
     }
 
-    dvmInitMutex(&gDvmJit.compilerLock);
-    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
-    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
-
     dvmLockMutex(&gDvmJit.compilerLock);
 
-    gDvmJit.haltCompilerThread = false;
-
-    /* Reset the work queue */
-    memset(gDvmJit.compilerWorkQueue, 0,
-           sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
-    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
-    gDvmJit.compilerQueueLength = 0;
-
     /* Track method-level compilation statistics */
     gDvmJit.methodStatsTable =  dvmHashTableCreate(32, NULL);
 
@@ -356,6 +344,7 @@
     gDvmJit.compilerHighWater =
         COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
     gDvmJit.pProfTable = pJitProfTable;
+    gDvmJit.pProfTableCopy = pJitProfTable;
     dvmUnlockMutex(&gDvmJit.tableLock);
 
     /* Signal running threads to refresh their cached pJitTable pointers */
@@ -370,13 +359,39 @@
 
 static void *compilerThreadStart(void *arg)
 {
+    int ret;
+    struct timespec ts;
+
     dvmChangeStatus(NULL, THREAD_VMWAIT);
 
     /*
      * Wait a little before recieving translation requests on the assumption
      * that process start-up code isn't worth compiling.
      */
-    usleep(1 * 1000 * 1000);
+
+    dvmLockMutex(&gDvmJit.compilerLock);
+    /*
+     * TUNING: once framework is calling VMRuntime.startJitCompilation,
+     * experiment with the delay time (and perhaps have target-dependent
+     * values?
+     */
+    dvmAbsoluteTime(1000, 0, &ts);
+#if defined(HAVE_TIMEDWAIT_MONOTONIC)
+    ret = pthread_cond_timedwait_monotonic(&gDvmJit.compilerQueueActivity,
+                                           &gDvmJit.compilerLock, &ts);
+#else
+    ret = pthread_cond_timedwait(&gDvmJit.compilerQueueActivity,
+                                 &gDvmJit.compilerLock, &ts);
+#endif
+    assert(ret == 0 || ret == ETIMEDOUT);
+
+    if (gDvmJit.haltCompilerThread) {
+        dvmUnlockMutex(&gDvmJit.compilerLock);
+        return NULL;
+    }
+
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
     compilerThreadStartup();
 
     dvmLockMutex(&gDvmJit.compilerLock);
@@ -453,14 +468,26 @@
      */
     dvmChangeStatus(NULL, THREAD_RUNNING);
 
-    LOGD("Compiler thread shutting down\n");
+    if (gDvm.verboseShutdown)
+        LOGD("Compiler thread shutting down\n");
     return NULL;
 }
 
 bool dvmCompilerStartup(void)
 {
+
+    dvmInitMutex(&gDvmJit.compilerLock);
+    dvmLockMutex(&gDvmJit.compilerLock);
+    pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
+    pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
+
+    /* Reset the work queue */
+    gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
+    gDvmJit.compilerQueueLength = 0;
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+
     /*
-     * Defer initialization until we're sure JIT'ng makes sense.  Launch
+     * Defer rest of initialization until we're sure JIT'ng makes sense. Launch
      * the compiler thread, which will do the real initialization if and
      * when it is signalled to do so.
      */
@@ -482,7 +509,27 @@
 
         if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
             LOGW("Compiler thread join failed\n");
-        else
+        else if (gDvm.verboseShutdown)
             LOGD("Compiler thread has shut down\n");
     }
 }
+
+
+void dvmCompilerStateRefresh()
+{
+    bool jitActive;
+    bool jitActivate;
+
+    dvmLockMutex(&gDvmJit.tableLock);
+    jitActive = gDvmJit.pProfTable != NULL;
+    jitActivate = !(gDvm.debuggerActive || (gDvm.activeProfilers > 0));
+
+    if (jitActivate && !jitActive) {
+        gDvmJit.pProfTable = gDvmJit.pProfTableCopy;
+        dvmUnlockMutex(&gDvmJit.tableLock);
+    } else if (!jitActivate && jitActive) {
+        gDvmJit.pProfTable = NULL;
+        dvmUnlockMutex(&gDvmJit.tableLock);
+        dvmJitUnchainAll();
+    }
+}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index 71eed5d..6b4d414 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -165,6 +165,7 @@
                               struct SSARepresentation *ssaRep);
 void dvmCompilerDataFlowAnalysisDispatcher(struct CompilationUnit *cUnit,
                 void (*func)(struct CompilationUnit *, struct BasicBlock *));
+void dvmCompilerStateRefresh(void);
 JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc);
 
 #endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 6a59c7e..998c955 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -1328,7 +1328,7 @@
     u4 newInst;
     bool thumbTarget;
 
-    if (gDvm.sumThreadSuspendCount == 0) {
+    if ((gDvmJit.pProfTable != NULL) && gDvm.sumThreadSuspendCount == 0) {
         assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2)));
 
         gDvmJit.translationChains++;
diff --git a/vm/hprof/Hprof.c b/vm/hprof/Hprof.c
index 2e6f7c9..8380fd8 100644
--- a/vm/hprof/Hprof.c
+++ b/vm/hprof/Hprof.c
@@ -33,15 +33,13 @@
 #define kHeadSuffix "-hptemp"
 
 hprof_context_t *
-hprofStartup(const char *outputFileName)
+hprofStartup(const char *outputFileName, bool directToDdms)
 {
-    hprof_context_t *ctx;
+    FILE* fp = NULL;
 
-    ctx = malloc(sizeof(*ctx));
-    if (ctx != NULL) {
+    if (!directToDdms) {
         int len = strlen(outputFileName);
         char fileName[len + sizeof(kHeadSuffix)];
-        FILE *fp;
 
         /* Construct the temp file name.  This wasn't handed to us by the
          * application, so we need to be careful about stomping on it.
@@ -49,14 +47,12 @@
         sprintf(fileName, "%s" kHeadSuffix, outputFileName);
         if (access(fileName, F_OK) == 0) {
             LOGE("hprof: temp file %s exists, bailing\n", fileName);
-            free(ctx);
             return NULL;
         }
 
         fp = fopen(fileName, "w+");
         if (fp == NULL) {
             LOGE("hprof: can't open %s: %s.\n", fileName, strerror(errno));
-            free(ctx);
             return NULL;
         }
         if (unlink(fileName) != 0) {
@@ -64,20 +60,28 @@
             /* keep going */
         }
         LOGI("hprof: dumping VM heap to \"%s\".\n", fileName);
+    }
 
-        hprofStartup_String();
-        hprofStartup_Class();
+    hprofStartup_String();
+    hprofStartup_Class();
 #if WITH_HPROF_STACK
-        hprofStartup_StackFrame();
-        hprofStartup_Stack();
+    hprofStartup_StackFrame();
+    hprofStartup_Stack();
 #endif
 
-        /* pass in "fp" for the temp file, and the name of the output file */
-        hprofContextInit(ctx, strdup(outputFileName), fp, false);
-    } else {
+    hprof_context_t *ctx = malloc(sizeof(*ctx));
+    if (ctx == NULL) {
         LOGE("hprof: can't allocate context.\n");
+        if (fp != NULL)
+            fclose(fp);
+        return NULL;
     }
 
+    /* pass in "fp" for the temp file, and the name of the output file */
+    hprofContextInit(ctx, strdup(outputFileName), fp, false, directToDdms);
+
+    assert(ctx->fp != NULL);
+
     return ctx;
 }
 
@@ -115,46 +119,55 @@
  * Finish up the hprof dump.  Returns true on success.
  */
 bool
-hprofShutdown(hprof_context_t *ctx)
+hprofShutdown(hprof_context_t *tailCtx)
 {
-    FILE *tempFp = ctx->fp;
-    FILE *fp;
+    FILE *fp = NULL;
 
     /* flush output to the temp file, then prepare the output file */
-    hprofFlushCurrentRecord(ctx);
-    free(ctx->curRec.body);
-    ctx->curRec.body = NULL;
-    ctx->curRec.allocLen = 0;
-    ctx->fp = NULL;
+    hprofFlushCurrentRecord(tailCtx);
 
-    LOGI("hprof: dumping heap strings to \"%s\".\n", ctx->fileName);
-    fp = fopen(ctx->fileName, "w");
-    if (fp == NULL) {
-        LOGE("can't open %s: %s\n", ctx->fileName, strerror(errno));
-        fclose(tempFp);
-        free(ctx->fileName);
-        free(ctx);
-        return false;
+    LOGI("hprof: dumping heap strings to \"%s\".\n", tailCtx->fileName);
+    if (!tailCtx->directToDdms) {
+        fp = fopen(tailCtx->fileName, "w");
+        if (fp == NULL) {
+            LOGE("can't open %s: %s\n", tailCtx->fileName, strerror(errno));
+            hprofFreeContext(tailCtx);
+            return false;
+        }
     }
-    hprofContextInit(ctx, ctx->fileName, fp, true);
 
-    hprofDumpStrings(ctx);
-    hprofDumpClasses(ctx);
+    /*
+     * Create a new context struct for the start of the file.  We
+     * heap-allocate it so we can share the "free" function.
+     */
+    hprof_context_t *headCtx = malloc(sizeof(*headCtx));
+    if (headCtx == NULL) {
+        LOGE("hprof: can't allocate context.\n");
+        if (fp != NULL)
+            fclose(fp);
+        hprofFreeContext(tailCtx);
+        return NULL;
+    }
+    hprofContextInit(headCtx, strdup(tailCtx->fileName), fp, true,
+        tailCtx->directToDdms);
+
+    hprofDumpStrings(headCtx);
+    hprofDumpClasses(headCtx);
 
     /* Write a dummy stack trace record so the analysis
      * tools don't freak out.
      */
-    hprofStartNewRecord(ctx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
-    hprofAddU4ToRecord(&ctx->curRec, HPROF_NULL_STACK_TRACE);
-    hprofAddU4ToRecord(&ctx->curRec, HPROF_NULL_THREAD);
-    hprofAddU4ToRecord(&ctx->curRec, 0);    // no frames
+    hprofStartNewRecord(headCtx, HPROF_TAG_STACK_TRACE, HPROF_TIME);
+    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_STACK_TRACE);
+    hprofAddU4ToRecord(&headCtx->curRec, HPROF_NULL_THREAD);
+    hprofAddU4ToRecord(&headCtx->curRec, 0);    // no frames
 
 #if WITH_HPROF_STACK
-    hprofDumpStackFrames(ctx);
-    hprofDumpStacks(ctx);
+    hprofDumpStackFrames(headCtx);
+    hprofDumpStacks(headCtx);
 #endif
 
-    hprofFlushCurrentRecord(ctx);
+    hprofFlushCurrentRecord(headCtx);
 
     hprofShutdown_Class();
     hprofShutdown_String();
@@ -163,24 +176,52 @@
     hprofShutdown_StackFrame();
 #endif
 
-    /*
-     * Append the contents of the temp file to the output file.  The temp
-     * file was removed immediately after being opened, so it will vanish
-     * when we close it.
-     */
-    rewind(tempFp);
-    if (!copyFileToFile(ctx->fp, tempFp)) {
-        LOGW("hprof: file copy failed, hprof data may be incomplete\n");
-        /* finish up anyway */
+    if (tailCtx->directToDdms) {
+        /* flush to ensure memstream pointer and size are updated */
+        fflush(headCtx->fp);
+        fflush(tailCtx->fp);
+
+        /* send the data off to DDMS */
+        struct iovec iov[2];
+        iov[0].iov_base = headCtx->fileDataPtr;
+        iov[0].iov_len = headCtx->fileDataSize;
+        iov[1].iov_base = tailCtx->fileDataPtr;
+        iov[1].iov_len = tailCtx->fileDataSize;
+        dvmDbgDdmSendChunkV(CHUNK_TYPE("HPDS"), iov, 2);
+    } else {
+        /*
+         * Append the contents of the temp file to the output file.  The temp
+         * file was removed immediately after being opened, so it will vanish
+         * when we close it.
+         */
+        rewind(tailCtx->fp);
+        if (!copyFileToFile(headCtx->fp, tailCtx->fp)) {
+            LOGW("hprof: file copy failed, hprof data may be incomplete\n");
+            /* finish up anyway */
+        }
     }
 
-    fclose(tempFp);
-    fclose(ctx->fp);
-    free(ctx->fileName);
-    free(ctx->curRec.body);
-    free(ctx);
+    hprofFreeContext(headCtx);
+    hprofFreeContext(tailCtx);
 
     /* throw out a log message for the benefit of "runhat" */
     LOGI("hprof: heap dump completed, temp file removed\n");
     return true;
 }
+
+/*
+ * Free any heap-allocated items in "ctx", and then free "ctx" itself.
+ */
+void
+hprofFreeContext(hprof_context_t *ctx)
+{
+    assert(ctx != NULL);
+
+    if (ctx->fp != NULL)
+        fclose(ctx->fp);
+    free(ctx->curRec.body);
+    free(ctx->fileName);
+    free(ctx->fileDataPtr);
+    free(ctx);
+}
+
diff --git a/vm/hprof/Hprof.h b/vm/hprof/Hprof.h
index 696b0a7..db5049f 100644
--- a/vm/hprof/Hprof.h
+++ b/vm/hprof/Hprof.h
@@ -125,13 +125,23 @@
      * can cast from a context to a record.
      */
     hprof_record_t curRec;
-    char *fileName;
-    FILE *fp;
+
     u4 gcThreadSerialNumber;
     u1 gcScanState;
     HprofHeapId currentHeap;    // which heap we're currently emitting
     u4 stackTraceSerialNumber;
     size_t objectsInSegment;
+
+    /*
+     * If "directToDdms" is not set, "fileName" is valid, and "fileDataPtr"
+     * and "fileDataSize" are not used.  If "directToDdms" is not set,
+     * it's the other way around.
+     */
+    bool directToDdms;
+    char *fileName;
+    char *fileDataPtr;          // for open_memstream
+    size_t fileDataSize;        // for open_memstream
+    FILE *fp;
 } hprof_context_t;
 
 
@@ -178,7 +188,7 @@
  */
 
 void hprofContextInit(hprof_context_t *ctx, char *fileName, FILE *fp,
-                      bool writeHeader);
+                      bool writeHeader, bool directToDdms);
 
 int hprofFlushRecord(hprof_record_t *rec, FILE *fp);
 int hprofFlushCurrentRecord(hprof_context_t *ctx);
@@ -234,8 +244,9 @@
  * Hprof.c functions
  */
 
-hprof_context_t *hprofStartup(const char *outputFileName);
+hprof_context_t* hprofStartup(const char *outputFileName, bool directToDdms);
 bool hprofShutdown(hprof_context_t *ctx);
+void hprofFreeContext(hprof_context_t *ctx);
 
 /*
  * Heap.c functions
@@ -244,7 +255,7 @@
  * the heap implementation; these functions require heap knowledge,
  * so they are implemented in Heap.c.
  */
-int hprofDumpHeap(const char* fileName);
+int hprofDumpHeap(const char* fileName, bool directToDdms);
 void dvmHeapSetHprofGcScanState(hprof_heap_tag_t state, u4 threadSerialNumber);
 
 #endif  // _DALVIK_HPROF_HPROF
diff --git a/vm/hprof/HprofOutput.c b/vm/hprof/HprofOutput.c
index c6d1cbc..0677c85 100644
--- a/vm/hprof/HprofOutput.c
+++ b/vm/hprof/HprofOutput.c
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 #include <sys/time.h>
+#include <cutils/open_memstream.h>
 #include <time.h>
+#include <errno.h>
 #include "Hprof.h"
 
 #define HPROF_MAGIC_STRING  "JAVA PROFILE 1.0.3"
@@ -54,11 +56,33 @@
         buf_[offset_ + 7] = (unsigned char)(value_      ); \
     } while (0)
 
+/*
+ * Initialize an hprof context struct.
+ *
+ * This will take ownership of "fileName" and "fp".
+ */
 void
 hprofContextInit(hprof_context_t *ctx, char *fileName, FILE *fp,
-    bool writeHeader)
+    bool writeHeader, bool directToDdms)
 {
     memset(ctx, 0, sizeof (*ctx));
+
+    if (directToDdms) {
+        /*
+         * Have to do this here, because it must happen after we
+         * memset the struct (want to treat fileDataPtr/fileDataSize
+         * as read-only while the file is open).
+         */
+        assert(fp == NULL);
+        fp = open_memstream(&ctx->fileDataPtr, &ctx->fileDataSize);
+        if (fp == NULL) {
+            /* not expected */
+            LOGE("hprof: open_memstream failed: %s\n", strerror(errno));
+            dvmAbort();
+        }
+    }
+
+    ctx->directToDdms = directToDdms;
     ctx->fileName = fileName;
     ctx->fp = fp;
 
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
index 34a7736..d536070 100644
--- a/vm/interp/Jit.c
+++ b/vm/interp/Jit.c
@@ -457,7 +457,8 @@
 
     dvmCompilerShutdown();
 
-    dvmCompilerDumpStats();
+    if (gDvm.verboseShutdown)
+        dvmCompilerDumpStats();
 
     dvmDestroyMutex(&gDvmJit.tableLock);
 
@@ -776,6 +777,7 @@
             interpState->entryPoint = kInterpEntryResume;
             switchInterp = !debugOrProfile;
             break;
+        case kJitTSelectRequest:
         case kJitTSelectAbort:
 #if defined(SHOW_TRACE)
             LOGD("TraceGen:  trace abort");
@@ -833,7 +835,8 @@
 void* dvmJitGetCodeAddr(const u2* dPC)
 {
     int idx = dvmJitHash(dPC);
-    const u2* npc = gDvmJit.pJitEntryTable[idx].dPC;
+    const u2* npc = (gDvmJit.pProfTable == NULL) ? NULL :
+                     gDvmJit.pJitEntryTable[idx].dPC;
 
     if (npc != NULL) {
         if (npc == dPC) {
@@ -1130,5 +1133,4 @@
         return (s8)f;
 }
 
-
 #endif /* WITH_JIT */
diff --git a/vm/jdwp/JdwpAdb.c b/vm/jdwp/JdwpAdb.c
index 6ec9f10..dfc7bd7 100644
--- a/vm/jdwp/JdwpAdb.c
+++ b/vm/jdwp/JdwpAdb.c
@@ -174,7 +174,7 @@
             LOGW("receiving file descriptor from ADB failed (socket %d): %s\n",
                  netState->controlSock, strerror(errno));
         } else {
-            LOGI("adbd disconnected\n");
+            LOGD("adbd disconnected\n");
         }
         close(netState->controlSock);
         netState->controlSock = -1;
diff --git a/vm/jdwp/JdwpMain.c b/vm/jdwp/JdwpMain.c
index 4166c67..540259d 100644
--- a/vm/jdwp/JdwpMain.c
+++ b/vm/jdwp/JdwpMain.c
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 /*
  * JDWP initialization.
  */
@@ -185,7 +186,8 @@
         /*
          * Close down the network to inspire the thread to halt.
          */
-        LOGD("JDWP shutting down net...\n");
+        if (gDvm.verboseShutdown)
+            LOGD("JDWP shutting down net...\n");
         dvmJdwpNetShutdown(state);
 
         if (state->debugThreadStarted) {
@@ -195,7 +197,8 @@
             }
         }
 
-        LOGV("JDWP freeing netstate...\n");
+        if (gDvm.verboseShutdown)
+            LOGD("JDWP freeing netstate...\n");
         dvmJdwpNetFree(state);
         state->netState = NULL;
     }
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index 5b984e3..5abdff5 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -1477,25 +1477,21 @@
          interpState->pc,
          interpState->method->name);
 #endif
-
 #if INTERP_TYPE == INTERP_DBG
-    /* Check to see if we've got a trace selection request.  If we do,
-     * but something is amiss, revert to the fast interpreter.
-     */
-#if !defined(WITH_SELF_VERIFICATION)
-    if (dvmJitCheckTraceRequest(self,interpState)) {
+    /* Check to see if we've got a trace selection request. */
+    if (
+#if defined(WITH_SELF_VERIFICATION)
+         (interpState->jitState != kJitSelfVerification) &&
+#endif
+         !gDvm.debuggerActive &&
+#if defined(WITH_PROFILER)
+         (gDvm.activeProfilers == 0) &&
+#endif
+         dvmJitCheckTraceRequest(self, interpState)) {
         interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
+        //LOGD("Invalid trace request, exiting\n");
         return true;
     }
-#else
-    if (interpState->jitState != kJitSelfVerification &&
-        dvmJitCheckTraceRequest(self,interpState)) {
-        interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
-        return true;
-    }
-#endif /* WITH_SELF_VERIFICATION */
 #endif /* INTERP_TYPE == INTERP_DBG */
 #endif /* WITH_JIT */
 
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index bfda671..8b30bd6 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -1217,25 +1217,21 @@
          interpState->pc,
          interpState->method->name);
 #endif
-
 #if INTERP_TYPE == INTERP_DBG
-    /* Check to see if we've got a trace selection request.  If we do,
-     * but something is amiss, revert to the fast interpreter.
-     */
-#if !defined(WITH_SELF_VERIFICATION)
-    if (dvmJitCheckTraceRequest(self,interpState)) {
+    /* Check to see if we've got a trace selection request. */
+    if (
+#if defined(WITH_SELF_VERIFICATION)
+         (interpState->jitState != kJitSelfVerification) &&
+#endif
+         !gDvm.debuggerActive &&
+#if defined(WITH_PROFILER)
+         (gDvm.activeProfilers == 0) &&
+#endif
+         dvmJitCheckTraceRequest(self, interpState)) {
         interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
+        //LOGD("Invalid trace request, exiting\n");
         return true;
     }
-#else
-    if (interpState->jitState != kJitSelfVerification &&
-        dvmJitCheckTraceRequest(self,interpState)) {
-        interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
-        return true;
-    }
-#endif /* WITH_SELF_VERIFICATION */
 #endif /* INTERP_TYPE == INTERP_DBG */
 #endif /* WITH_JIT */
 
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index 4a6ed4e..8ea4bdc 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -42,25 +42,21 @@
          interpState->pc,
          interpState->method->name);
 #endif
-
 #if INTERP_TYPE == INTERP_DBG
-    /* Check to see if we've got a trace selection request.  If we do,
-     * but something is amiss, revert to the fast interpreter.
-     */
-#if !defined(WITH_SELF_VERIFICATION)
-    if (dvmJitCheckTraceRequest(self,interpState)) {
+    /* Check to see if we've got a trace selection request. */
+    if (
+#if defined(WITH_SELF_VERIFICATION)
+         (interpState->jitState != kJitSelfVerification) &&
+#endif
+         !gDvm.debuggerActive &&
+#if defined(WITH_PROFILER)
+         (gDvm.activeProfilers == 0) &&
+#endif
+         dvmJitCheckTraceRequest(self, interpState)) {
         interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
+        //LOGD("Invalid trace request, exiting\n");
         return true;
     }
-#else
-    if (interpState->jitState != kJitSelfVerification &&
-        dvmJitCheckTraceRequest(self,interpState)) {
-        interpState->nextMode = INTERP_STD;
-        //LOGD("** something wrong, exiting\n");
-        return true;
-    }
-#endif /* WITH_SELF_VERIFICATION */
 #endif /* INTERP_TYPE == INTERP_DBG */
 #endif /* WITH_JIT */
 
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index 3f0b5fc..1d2f024 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -93,6 +93,7 @@
 #ifdef WITH_HPROF
     /* VM responds to DDMS heap dump requests */
     features[idx++] = "hprof-heap-dump";
+    features[idx++] = "hprof-heap-dump-streaming";
 #endif
 
     assert(idx <= MAX_FEATURE_COUNT);
@@ -664,7 +665,7 @@
         RETURN_VOID();
     }
 
-    result = hprofDumpHeap(fileName);
+    result = hprofDumpHeap(fileName, false);
     free(fileName);
 
     if (result != 0) {
@@ -681,6 +682,32 @@
 }
 
 /*
+ * static void dumpHprofDataDdms()
+ *
+ * Cause "hprof" data to be computed and sent directly to DDMS.
+ */
+static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
+    JValue* pResult)
+{
+#ifdef WITH_HPROF
+    int result;
+
+    result = hprofDumpHeap("[DDMS]", true);
+
+    if (result != 0) {
+        /* ideally we'd throw something more specific based on actual failure */
+        dvmThrowException("Ljava/lang/RuntimeException;",
+            "Failure during heap dump -- check log output for details");
+        RETURN_VOID();
+    }
+#else
+    dvmThrowException("Ljava/lang/UnsupportedOperationException;", NULL);
+#endif
+
+    RETURN_VOID();
+}
+
+/*
  * static boolean cacheRegisterMap(String classAndMethodDescr)
  *
  * If the specified class is loaded, and the named method exists, ensure
@@ -876,6 +903,8 @@
         Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
     { "dumpHprofData",              "(Ljava/lang/String;)V",
         Dalvik_dalvik_system_VMDebug_dumpHprofData },
+    { "dumpHprofDataDdms",          "()V",
+        Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
     { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
         Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
     { "dumpReferenceTables",        "()V",
diff --git a/vm/native/dalvik_system_VMRuntime.c b/vm/native/dalvik_system_VMRuntime.c
index 946a427..df0e73b 100644
--- a/vm/native/dalvik_system_VMRuntime.c
+++ b/vm/native/dalvik_system_VMRuntime.c
@@ -188,10 +188,15 @@
     JValue* pResult)
 {
 #if defined(WITH_JIT)
+#if 0
     /*
-     * TODO - experiment the timing and put code here to start JIT'ing
+     * TODO - experiment with the timing.
      * The tentative plan is onResume() will invoke the callback.
      */
+    dvmLockMutex(&gDvmJit.compilerLock);
+    pthread_cond_signal(&gDvmJit.compilerQueueActivity);
+    dvmUnlockMutex(&gDvmJit.compilerLock);
+#endif
 #endif
 
     RETURN_VOID();