Merge "Null annotations for java.lang.Boolean"
diff --git a/annotated_java_files.bp b/annotated_java_files.bp
index e6afe73..ab012cf 100644
--- a/annotated_java_files.bp
+++ b/annotated_java_files.bp
@@ -14,6 +14,7 @@
         "ojluni/src/main/java/java/lang/Iterable.java",
         "ojluni/src/main/java/java/lang/Long.java",
         "ojluni/src/main/java/java/lang/String.java",
+        "ojluni/src/main/java/java/lang/System.java",
         "ojluni/src/main/java/java/lang/Thread.java",
         "ojluni/src/main/java/java/lang/reflect/AccessibleObject.java",
         "ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java",
diff --git a/annotations/ojluni.jaif b/annotations/ojluni.jaif
index 9b9f913..1daba9c 100644
--- a/annotations/ojluni.jaif
+++ b/annotations/ojluni.jaif
@@ -922,6 +922,140 @@
                 inner-type 0, 0: @libcore.util.Nullable
         return: @libcore.util.NonNull
 
+class System:
+    // Ideally, in should be made NonNull - but it IS possible to make this final field
+    // a null using setIn(null). It makes sense to leave this field as a platform
+    // type for convenience reasons - no one sane should expect this to be null,
+    // but it's nice to have kotlin check it.
+    field in:
+
+    // Same as in "in" field
+    field out:
+
+    // Same as in "in" field
+    field err:
+
+
+    method setIn(Ljava/io/InputStream;)V:
+        // While it makes little sense, it's possible to set System.in to null.
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method setOut(Ljava/io/PrintStream;)V:
+        // While it makes little sense, it's possible to set System.out to null.
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method setErr(Ljava/io/PrintStream;)V:
+        // While it makes little sense, it's possible to set System.err to null.
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method console()Ljava/io/Console;:
+        // Always returns an instance
+        return: @libcore.util.Nullable
+
+    method inheritedChannel()Ljava/nio/channels/Channel;:
+        // Null if there's no inherited channel
+        return: @libcore.util.Nullable
+
+    method setSecurityManager(Ljava/lang/SecurityManager;)V:
+        // Null is a valid argument.
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method getSecurityManager()Ljava/lang/SecurityManager;:
+        // Null is valid return value.
+        return: @libcore.util.Nullable
+
+    method arraycopy(Ljava/lang/Object;ILjava/lang/Object;II)V:
+        // NPE on null src
+        parameter #0:
+          type: @libcore.util.NonNull
+        // NPE on null dst
+        parameter #1:
+          type: @libcore.util.NonNull
+
+    method identityHashCode(Ljava/lang/Object;)I:
+        // Null is a valid argument.
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method getProperties()Ljava/util/Properties;:
+        // There's always a properties object
+        return: @libcore.util.NonNull
+
+    method lineSeparator()Ljava/lang/String;:
+        // There's always a line separator string (empty in worst case)
+        return: @libcore.util.NonNull
+
+    method setProperties(Ljava/util/Properties;)V:
+        // Null is a valid argument (will reset to defaults)
+        parameter #0:
+          type: @libcore.util.Nullable
+
+    method getProperty(Ljava/lang/String;)Ljava/lang/String;:
+        // Property key can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Null is valid return value
+        return: @libcore.util.Nullable
+
+    method getProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;:
+        // Property key can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Property value can be null
+        parameter #1:
+          type: @libcore.util.Nullable
+        // Null is valid return value
+        return: @libcore.util.Nullable
+
+    method setProperty(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;:
+        // Property key can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Property value can be null
+        parameter #1:
+          type: @libcore.util.Nullable
+        // Null is valid return value
+        return: @libcore.util.Nullable
+
+    method clearProperty(Ljava/lang/String;)Ljava/lang/String;:
+        // Property key can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Null is valid return value
+        return: @libcore.util.Nullable
+
+    method getenv(Ljava/lang/String;)Ljava/lang/String;:
+        // Name can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Null is valid return value
+        return: @libcore.util.Nullable
+
+    method getenv()Ljava/util/Map;:
+        // Never null
+        return: @libcore.util.NonNull
+
+    method load(Ljava/lang/String;)V:
+        // Filename can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+
+    method loadLibrary(Ljava/lang/String;)V:
+        // Libname can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+
+    method mapLibraryName(Ljava/lang/String;)Ljava/lang/String;:
+        // Libname can't be null
+        parameter #0:
+          type: @libcore.util.NonNull
+        // Never null
+        return: @libcore.util.NonNull
+
 class Thread:
     // Always returns a string instance
     method toString()Ljava/lang/String;:
diff --git a/benchmarks/src/benchmarks/regression/DecimalFormatSymbolsBenchmark.java b/benchmarks/src/benchmarks/regression/DecimalFormatSymbolsBenchmark.java
new file mode 100644
index 0000000..381b9e1
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/DecimalFormatSymbolsBenchmark.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package benchmarks.regression;
+
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+public class DecimalFormatSymbolsBenchmark {
+
+    private static Locale locale = Locale.getDefault(Locale.Category.FORMAT);
+
+    public void time_instantiation(int reps) {
+        for (int i = 0; i < reps; i++) {
+            new DecimalFormatSymbols(locale);
+        }
+    }
+}
diff --git a/benchmarks/src/benchmarks/regression/NumberFormatBenchmark.java b/benchmarks/src/benchmarks/regression/NumberFormatBenchmark.java
new file mode 100644
index 0000000..4e1f433
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/NumberFormatBenchmark.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package benchmarks.regression;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+public class NumberFormatBenchmark {
+
+    private static Locale locale = Locale.getDefault(Locale.Category.FORMAT);
+
+    public void time_instantiation(int reps) {
+        for (int i = 0; i < reps; i++) {
+            NumberFormat.getInstance(locale);
+        }
+    }
+}
diff --git a/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java b/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
index 92ec22f..7fb29e6 100644
--- a/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
+++ b/luni/src/test/java/libcore/java/lang/LambdaImplementationTest.java
@@ -353,9 +353,11 @@
         int classModifiers = lambdaClass.getModifiers();
         assertTrue(Modifier.isFinal(classModifiers));
 
+        // We have seen optimizations that make lambdas public so we do not make any assertions
+        // about class visibility: they can be package-private or public. http://b/73255857
+
         // Unexpected modifiers
         assertFalse(Modifier.isPrivate(classModifiers));
-        assertFalse(Modifier.isPublic(classModifiers));
         assertFalse(Modifier.isProtected(classModifiers));
         assertFalse(Modifier.isStatic(classModifiers));
         assertFalse(Modifier.isSynchronized(classModifiers));
diff --git a/ojluni/src/main/java/java/io/PrintStream.java b/ojluni/src/main/java/java/io/PrintStream.java
index d4ebd84..809d39b 100644
--- a/ojluni/src/main/java/java/io/PrintStream.java
+++ b/ojluni/src/main/java/java/io/PrintStream.java
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -69,6 +70,9 @@
     private BufferedWriter textOut;
     private OutputStreamWriter charOut;
 
+    // Android-added: Lazy initialization of charOut and textOut.
+    private Charset charset;
+
     /**
      * requireNonNull is explicitly declared here so as not to create an extra
      * dependency on java.util.Objects.requireNonNull. PrintStream is loaded
@@ -101,15 +105,18 @@
     private PrintStream(boolean autoFlush, OutputStream out) {
         super(out);
         this.autoFlush = autoFlush;
-        this.charOut = new OutputStreamWriter(this);
-        this.textOut = new BufferedWriter(charOut);
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this);
+        // this.textOut = new BufferedWriter(charOut);
     }
 
     private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {
         super(out);
         this.autoFlush = autoFlush;
-        this.charOut = new OutputStreamWriter(this, charset);
-        this.textOut = new BufferedWriter(charOut);
+        // Android-changed: Lazy initialization of charOut and textOut.
+        // this.charOut = new OutputStreamWriter(this, charset);
+        // this.textOut = new BufferedWriter(charOut);
+        this.charset = charset;
     }
 
     /* Variant of the private constructor so that the given charset name
@@ -345,6 +352,17 @@
 
     private boolean closing = false; /* To avoid recursive closing */
 
+    // BEGIN Android-added: Lazy initialization of charOut and textOut.
+    private BufferedWriter getTextOut() {
+        if (textOut == null) {
+            charOut = charset != null ? new OutputStreamWriter(this, charset) :
+                    new OutputStreamWriter(this);
+            textOut = new BufferedWriter(charOut);
+        }
+        return textOut;
+    }
+    // END Android-added: Lazy initialization of charOut and textOut.
+
     /**
      * Closes the stream.  This is done by flushing the stream and then closing
      * the underlying output stream.
@@ -356,7 +374,12 @@
             if (! closing) {
                 closing = true;
                 try {
-                    textOut.close();
+                    // BEGIN Android-changed: Lazy initialization of charOut and textOut.
+                    // textOut.close();
+                    if (textOut != null) {
+                        textOut.close();
+                    }
+                    // END Android-changed: Lazy initialization of charOut and textOut.
                     out.close();
                 }
                 catch (IOException x) {
@@ -500,6 +523,8 @@
         try {
             synchronized (this) {
                 ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
                 textOut.write(buf);
                 textOut.flushBuffer();
                 charOut.flushBuffer();
@@ -522,6 +547,8 @@
         try {
             synchronized (this) {
                 ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
                 textOut.write(s);
                 textOut.flushBuffer();
                 charOut.flushBuffer();
@@ -541,6 +568,8 @@
         try {
             synchronized (this) {
                 ensureOpen();
+                // Android-added: Lazy initialization of charOut and textOut.
+                BufferedWriter textOut = getTextOut();
                 textOut.newLine();
                 textOut.flushBuffer();
                 charOut.flushBuffer();
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index 397bf09..a9293ba 100644
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -61,9 +61,7 @@
      * @since   JDK1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
-    public static final Class<Boolean> TYPE = (Class<Boolean>) boolean[].class.getComponentType();
+    public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
 
     /**
      * The value of the Boolean.
diff --git a/ojluni/src/main/java/java/lang/Byte.java b/ojluni/src/main/java/java/lang/Byte.java
index 2333afd..e53899c 100644
--- a/ojluni/src/main/java/java/lang/Byte.java
+++ b/ojluni/src/main/java/java/lang/Byte.java
@@ -60,9 +60,7 @@
      * {@code byte}.
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Byte>     TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
-    public static final Class<Byte>     TYPE = (Class<Byte>) byte[].class.getComponentType();
+    public static final Class<Byte>     TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
 
     /**
      * Returns a new {@code String} object representing the
diff --git a/ojluni/src/main/java/java/lang/Character.java b/ojluni/src/main/java/java/lang/Character.java
index d320fe9..454cbbb 100644
--- a/ojluni/src/main/java/java/lang/Character.java
+++ b/ojluni/src/main/java/java/lang/Character.java
@@ -174,9 +174,7 @@
      * @since   1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Character> TYPE = (Class<Character>) Class.getPrimitiveClass("char");
-    public static final Class<Character> TYPE = (Class<Character>) char[].class.getComponentType();
+    public static final Class<Character> TYPE = (Class<Character>) Class.getPrimitiveClass("char");
 
     /*
      * Normative general types
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index ed9f915..f31a42c 100644
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -2279,6 +2279,13 @@
         return null;
     }
 
+    /*
+     * Return the runtime's Class object for the named
+     * primitive type.
+     */
+    @FastNative
+    static native Class<?> getPrimitiveClass(String name);
+
     /**
      * Add a package name prefix if the name is not absolute Remove leading "/"
      * if name is absolute
diff --git a/ojluni/src/main/java/java/lang/Double.java b/ojluni/src/main/java/java/lang/Double.java
index 2721a84..690ca6a 100644
--- a/ojluni/src/main/java/java/lang/Double.java
+++ b/ojluni/src/main/java/java/lang/Double.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -137,9 +136,7 @@
      * @since JDK1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Double>   TYPE = (Class<Double>) Class.getPrimitiveClass("double");
-    public static final Class<Double>   TYPE = (Class<Double>) double[].class.getComponentType();
+    public static final Class<Double>   TYPE = (Class<Double>) Class.getPrimitiveClass("double");
 
     /**
      * Returns a string representation of the {@code double}
diff --git a/ojluni/src/main/java/java/lang/Float.java b/ojluni/src/main/java/java/lang/Float.java
index 6a2b933..5cc28f9 100644
--- a/ojluni/src/main/java/java/lang/Float.java
+++ b/ojluni/src/main/java/java/lang/Float.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -135,9 +134,7 @@
      * @since JDK1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Float> TYPE = (Class<Float>) Class.getPrimitiveClass("float");
-    public static final Class<Float> TYPE = (Class<Float>) float[].class.getComponentType();
+    public static final Class<Float> TYPE = (Class<Float>) Class.getPrimitiveClass("float");
 
     /**
      * Returns a string representation of the {@code float}
diff --git a/ojluni/src/main/java/java/lang/Integer.java b/ojluni/src/main/java/java/lang/Integer.java
index c63b0d5..93ae24c 100644
--- a/ojluni/src/main/java/java/lang/Integer.java
+++ b/ojluni/src/main/java/java/lang/Integer.java
@@ -70,9 +70,7 @@
      * @since   JDK1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
-    public static final Class<Integer>  TYPE = (Class<Integer>) int[].class.getComponentType();
+    public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
 
     /**
      * All possible chars for representing a number as a String
diff --git a/ojluni/src/main/java/java/lang/Long.java b/ojluni/src/main/java/java/lang/Long.java
index c752957..0047125 100644
--- a/ojluni/src/main/java/java/lang/Long.java
+++ b/ojluni/src/main/java/java/lang/Long.java
@@ -72,9 +72,7 @@
      * @since   JDK1.1
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Long>     TYPE = (Class<Long>) Class.getPrimitiveClass("long");
-    public static final Class<Long>     TYPE = (Class<Long>) long[].class.getComponentType();
+    public static final Class<Long>     TYPE = (Class<Long>) Class.getPrimitiveClass("long");
 
     /**
      * Returns a string representation of the first argument in the
diff --git a/ojluni/src/main/java/java/lang/Short.java b/ojluni/src/main/java/java/lang/Short.java
index 0f600a8..9fb3913 100644
--- a/ojluni/src/main/java/java/lang/Short.java
+++ b/ojluni/src/main/java/java/lang/Short.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -60,9 +59,7 @@
      * {@code short}.
      */
     @SuppressWarnings("unchecked")
-    // Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Short>    TYPE = (Class<Short>) Class.getPrimitiveClass("short");
-    public static final Class<Short>    TYPE = (Class<Short>) short[].class.getComponentType();
+    public static final Class<Short>    TYPE = (Class<Short>) Class.getPrimitiveClass("short");
 
     /**
      * Returns a new {@code String} object representing the
diff --git a/ojluni/src/main/java/java/lang/Void.java b/ojluni/src/main/java/java/lang/Void.java
index 14268c7..96dbe6d 100644
--- a/ojluni/src/main/java/java/lang/Void.java
+++ b/ojluni/src/main/java/java/lang/Void.java
@@ -1,5 +1,4 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -26,9 +25,6 @@
 
 package java.lang;
 
-import java.lang.reflect.Method;
-import libcore.util.EmptyArray;
-
 /**
  * The {@code Void} class is an uninstantiable placeholder class to hold a
  * reference to the {@code Class} object representing the Java keyword
@@ -44,13 +40,8 @@
      * The {@code Class} object representing the pseudo-type corresponding to
      * the keyword {@code void}.
      */
-    // BEGIN Android-changed: Avoid use of removed Class.getPrimitiveClass method.
-    // public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");
-    public static final Class<Void> TYPE = lookupType();
-
-    @dalvik.annotation.optimization.FastNative
-    private static native Class<Void> lookupType();
-    // END Android-changed: Avoid use of removed Class.getPrimitiveClass method.
+    @SuppressWarnings("unchecked")
+    public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");
 
     /*
      * The Void class cannot be instantiated.
diff --git a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
index 59b8cdc..070fd1c 100644
--- a/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/ojluni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -648,29 +648,36 @@
     private void initialize( Locale locale ) {
         this.locale = locale;
 
-        // Android-changed: Removed use of DecimalFormatSymbolsProvider. Switched to ICU.
-        // get resource bundle data - try the cache first
-        boolean needCacheUpdate = false;
-        Object[] data = cachedLocaleData.get(locale);
-        if (data == null) {  /* cache miss */
-            locale = LocaleData.mapInvalidAndNullLocales(locale);
-            LocaleData localeData = LocaleData.get(locale);
-            data = new Object[3];
-            String[] values = new String[11];
-            values[0] = String.valueOf(localeData.decimalSeparator);
-            values[1] = String.valueOf(localeData.groupingSeparator);
-            values[2] = String.valueOf(localeData.patternSeparator);
-            values[3] = localeData.percent;
-            values[4] = String.valueOf(localeData.zeroDigit);
-            values[5] = "#";
-            values[6] = localeData.minusSign;
-            values[7] = localeData.exponentSeparator;
-            values[8] = localeData.perMill;
-            values[9] = localeData.infinity;
-            values[10] = localeData.NaN;
-            data[0] = values;
-            needCacheUpdate = true;
+        // BEGIN Android-changed: Removed use of DecimalFormatSymbolsProvider. Switched to ICU.
+        /*
+        // get resource bundle data
+        LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DecimalFormatSymbolsProvider.class, locale);
+        // Avoid potential recursions
+        if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+            adapter = LocaleProviderAdapter.getResourceBundleBased();
         }
+        Object[] data = adapter.getLocaleResources(locale).getDecimalFormatSymbolsData();
+        */
+        if (locale == null) {
+            throw new NullPointerException("locale");
+        }
+        locale = LocaleData.mapInvalidAndNullLocales(locale);
+        LocaleData localeData = LocaleData.get(locale);
+        Object[] data = new Object[3];
+        String[] values = new String[11];
+        values[0] = String.valueOf(localeData.decimalSeparator);
+        values[1] = String.valueOf(localeData.groupingSeparator);
+        values[2] = String.valueOf(localeData.patternSeparator);
+        values[3] = localeData.percent;
+        values[4] = String.valueOf(localeData.zeroDigit);
+        values[5] = "#";
+        values[6] = localeData.minusSign;
+        values[7] = localeData.exponentSeparator;
+        values[8] = localeData.perMill;
+        values[9] = localeData.infinity;
+        values[10] = localeData.NaN;
+        data[0] = values;
+        // END Android-changed: Removed use of DecimalFormatSymbolsProvider. Switched to ICU.
 
         String[] numberElements = (String[]) data[0];
 
@@ -707,8 +714,6 @@
                 currencySymbol = currency.getSymbol(locale);
                 data[1] = intlCurrencySymbol;
                 data[2] = currencySymbol;
-                // Android-added: update cache when necessary.
-                needCacheUpdate = true;
             }
         } else {
             // default values
@@ -723,11 +728,6 @@
         // standard decimal separator for all locales that we support.
         // If that changes, add a new entry to NumberElements.
         monetarySeparator = decimalSeparator;
-
-        // Android-added: update cache when necessary.
-        if (needCacheUpdate) {
-            cachedLocaleData.putIfAbsent(locale, data);
-        }
     }
 
     // Android-changed: maybeStripMarkers added in b/26207216, fixed in b/32465689.
@@ -1139,18 +1139,12 @@
      */
     private int serialVersionOnStream = currentSerialVersion;
 
-    // BEGIN Android-added: cache for locale data and cachedIcuDFS.
-    /**
-     * cache to hold the NumberElements and the Currency
-     * of a Locale.
-     */
-    private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<>(3);
-
+    // BEGIN Android-added: cache for cachedIcuDFS.
     /**
      * Lazily created cached instance of an ICU DecimalFormatSymbols that's equivalent to this one.
      * This field is reset to null whenever any of the relevant fields of this class are modified
      * and will be re-created by {@link #getIcuDecimalFormatSymbols()} as necessary.
      */
     private transient android.icu.text.DecimalFormatSymbols cachedIcuDFS = null;
-    // END Android-added: cache for locale data and cachedIcuDFS.
+    // END Android-added: cache for cachedIcuDFS.
 }
diff --git a/ojluni/src/main/java/java/text/NumberFormat.java b/ojluni/src/main/java/java/text/NumberFormat.java
index 70a0aa9..9ad44ed 100644
--- a/ojluni/src/main/java/java/text/NumberFormat.java
+++ b/ojluni/src/main/java/java/text/NumberFormat.java
@@ -826,33 +826,36 @@
 
     private static NumberFormat getInstance(Locale desiredLocale,
                                            int choice) {
-        // Android-changed: Removed use of NumberFormatProvider. Switched to use ICU.
-        /* try the cache first */
-        String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
-        if (numberPatterns == null) { /* cache miss */
-            LocaleData data = LocaleData.get(desiredLocale);
-            numberPatterns = new String[4];
-            numberPatterns[NUMBERSTYLE] = data.numberPattern;
-            numberPatterns[CURRENCYSTYLE] = data.currencyPattern;
-            numberPatterns[PERCENTSTYLE] = data.percentPattern;
-            numberPatterns[INTEGERSTYLE] = data.integerPattern;
-            /* update cache */
-            cachedLocaleData.put(desiredLocale, numberPatterns);
-        }
+        // BEGIN Android-changed: Removed use of NumberFormatProvider. Switched to use ICU.
+        /*
+        LocaleProviderAdapter adapter;
+        adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class,
+                                                   desiredLocale);
+        NumberFormat numberFormat = getInstance(adapter, desiredLocale, choice);
+        if (numberFormat == null) {
+            numberFormat = getInstance(LocaleProviderAdapter.forJRE(),
+                                       desiredLocale, choice);
+        */
+        String[] numberPatterns = new String[3];
+        LocaleData data = LocaleData.get(desiredLocale);
+        numberPatterns[NUMBERSTYLE] = data.numberPattern;
+        numberPatterns[CURRENCYSTYLE] = data.currencyPattern;
+        numberPatterns[PERCENTSTYLE] = data.percentPattern;
 
+        // Note: the following lines are from NumberFormatProviderImpl upstream.
         DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
         int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
-        DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
+        DecimalFormat numberFormat = new DecimalFormat(numberPatterns[entry], symbols);
 
         if (choice == INTEGERSTYLE) {
-            format.setMaximumFractionDigits(0);
-            format.setDecimalSeparatorAlwaysShown(false);
-            format.setParseIntegerOnly(true);
+            numberFormat.setMaximumFractionDigits(0);
+            numberFormat.setDecimalSeparatorAlwaysShown(false);
+            numberFormat.setParseIntegerOnly(true);
         } else if (choice == CURRENCYSTYLE) {
-            format.adjustForCurrencyDefaultFractionDigits();
+            numberFormat.adjustForCurrencyDefaultFractionDigits();
         }
-
-        return format;
+        // END Android-changed: Removed use of NumberFormatProvider. Switched to use ICU.
+        return numberFormat;
     }
 
     /**
@@ -917,12 +920,6 @@
         stream.defaultWriteObject();
     }
 
-    // Android-added: cachedLocaleData.
-    /**
-     * Cache to hold the NumberPatterns of a Locale.
-     */
-    private static final Hashtable cachedLocaleData = new Hashtable(3);
-
     // Constants used by factory methods to specify a style of format.
     private static final int NUMBERSTYLE = 0;
     private static final int CURRENCYSTYLE = 1;