Merge "Add OP_AUTH_NEEDED KeyStore result code"
diff --git a/api/current.txt b/api/current.txt
index ed80e38..8d650cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16998,6 +16998,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
+    method public boolean contains(java.net.InetAddress);
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getPrefixLength();
@@ -18444,6 +18445,7 @@
 
   public final class NfcEvent {
     field public final android.nfc.NfcAdapter nfcAdapter;
+    field public final byte peerLlcpVersion;
   }
 
   public final class NfcManager {
@@ -26518,6 +26520,7 @@
   public class Script extends android.renderscript.BaseObj {
     method public void bindAllocation(android.renderscript.Allocation, int);
     method protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element);
+    method protected android.renderscript.Script.InvokeID createInvokeID(int);
     method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element);
     method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker);
     method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
@@ -26558,6 +26561,9 @@
   public static final class Script.FieldID extends android.renderscript.BaseObj {
   }
 
+  public static final class Script.InvokeID extends android.renderscript.BaseObj {
+  }
+
   public static final class Script.KernelID extends android.renderscript.BaseObj {
   }
 
@@ -26582,12 +26588,19 @@
   }
 
   public final class ScriptGroup extends android.renderscript.BaseObj {
-    method public void execute();
-    method public void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
-    method public void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method public java.lang.Object[] execute(java.lang.Object...);
+    method public deprecated void execute();
+    method public deprecated void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method public deprecated void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
   }
 
-  public static final class ScriptGroup.Builder {
+  public static final class ScriptGroup.Binding {
+    ctor public ScriptGroup.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+    method public android.renderscript.Script.FieldID getField();
+    method public java.lang.Object getValue();
+  }
+
+  public static final deprecated class ScriptGroup.Builder {
     ctor public ScriptGroup.Builder(android.renderscript.RenderScript);
     method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.FieldID);
     method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.KernelID);
@@ -26595,6 +26608,25 @@
     method public android.renderscript.ScriptGroup create();
   }
 
+  public static final class ScriptGroup.Builder2 {
+    ctor public ScriptGroup.Builder2(android.renderscript.RenderScript);
+    method public android.renderscript.ScriptGroup.Input addInput();
+    method public android.renderscript.ScriptGroup.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+    method public android.renderscript.ScriptGroup.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+    method public android.renderscript.ScriptGroup create(java.lang.String, android.renderscript.ScriptGroup.Future...);
+  }
+
+  public static final class ScriptGroup.Closure extends android.renderscript.BaseObj {
+    method public android.renderscript.ScriptGroup.Future getGlobal(android.renderscript.Script.FieldID);
+    method public android.renderscript.ScriptGroup.Future getReturn();
+  }
+
+  public static final class ScriptGroup.Future {
+  }
+
+  public static final class ScriptGroup.Input {
+  }
+
   public abstract class ScriptIntrinsic extends android.renderscript.Script {
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 8f1b8b2..8af6a95 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -18261,6 +18261,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
+    method public boolean contains(java.net.InetAddress);
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getPrefixLength();
@@ -20028,6 +20029,7 @@
 
   public final class NfcEvent {
     field public final android.nfc.NfcAdapter nfcAdapter;
+    field public final byte peerLlcpVersion;
   }
 
   public final class NfcManager {
@@ -28115,6 +28117,7 @@
   public class Script extends android.renderscript.BaseObj {
     method public void bindAllocation(android.renderscript.Allocation, int);
     method protected android.renderscript.Script.FieldID createFieldID(int, android.renderscript.Element);
+    method protected android.renderscript.Script.InvokeID createInvokeID(int);
     method protected android.renderscript.Script.KernelID createKernelID(int, int, android.renderscript.Element, android.renderscript.Element);
     method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker);
     method protected void forEach(int, android.renderscript.Allocation, android.renderscript.Allocation, android.renderscript.FieldPacker, android.renderscript.Script.LaunchOptions);
@@ -28155,6 +28158,9 @@
   public static final class Script.FieldID extends android.renderscript.BaseObj {
   }
 
+  public static final class Script.InvokeID extends android.renderscript.BaseObj {
+  }
+
   public static final class Script.KernelID extends android.renderscript.BaseObj {
   }
 
@@ -28179,12 +28185,19 @@
   }
 
   public final class ScriptGroup extends android.renderscript.BaseObj {
-    method public void execute();
-    method public void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
-    method public void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method public java.lang.Object[] execute(java.lang.Object...);
+    method public deprecated void execute();
+    method public deprecated void setInput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
+    method public deprecated void setOutput(android.renderscript.Script.KernelID, android.renderscript.Allocation);
   }
 
-  public static final class ScriptGroup.Builder {
+  public static final class ScriptGroup.Binding {
+    ctor public ScriptGroup.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+    method public android.renderscript.Script.FieldID getField();
+    method public java.lang.Object getValue();
+  }
+
+  public static final deprecated class ScriptGroup.Builder {
     ctor public ScriptGroup.Builder(android.renderscript.RenderScript);
     method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.FieldID);
     method public android.renderscript.ScriptGroup.Builder addConnection(android.renderscript.Type, android.renderscript.Script.KernelID, android.renderscript.Script.KernelID);
@@ -28192,6 +28205,25 @@
     method public android.renderscript.ScriptGroup create();
   }
 
+  public static final class ScriptGroup.Builder2 {
+    ctor public ScriptGroup.Builder2(android.renderscript.RenderScript);
+    method public android.renderscript.ScriptGroup.Input addInput();
+    method public android.renderscript.ScriptGroup.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+    method public android.renderscript.ScriptGroup.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+    method public android.renderscript.ScriptGroup create(java.lang.String, android.renderscript.ScriptGroup.Future...);
+  }
+
+  public static final class ScriptGroup.Closure extends android.renderscript.BaseObj {
+    method public android.renderscript.ScriptGroup.Future getGlobal(android.renderscript.Script.FieldID);
+    method public android.renderscript.ScriptGroup.Future getReturn();
+  }
+
+  public static final class ScriptGroup.Future {
+  }
+
+  public static final class ScriptGroup.Input {
+  }
+
   public abstract class ScriptIntrinsic extends android.renderscript.Script {
   }
 
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index dd5e0ea..ce6d7b5 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -56,6 +56,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
 LOCAL_MODULE_STEM := app_process
 LOCAL_ADDRESS_SANITIZER := true
+LOCAL_CLANG := true
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b063209..e32254a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -257,23 +257,18 @@
         }
     }
 
-    static final class AcquiringProviderRecord {
-        IActivityManager.ContentProviderHolder holder;
-        boolean acquiring = true;
-        int requests = 1;
-        // Set if there was a runtime exception when trying to acquire the provider.
-        RuntimeException runtimeException = null;
-    }
-
     // The lock of mProviderMap protects the following variables.
-    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();
-    final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>();
-    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>();
-    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>();
-    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>();
+    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
+        = new ArrayMap<ProviderKey, ProviderClientRecord>();
+    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
+        = new ArrayMap<IBinder, ProviderRefCount>();
+    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
+        = new ArrayMap<IBinder, ProviderClientRecord>();
+    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
+            = new ArrayMap<ComponentName, ProviderClientRecord>();
 
     final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
-            = new ArrayMap<>();
+        = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
 
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
@@ -350,7 +345,7 @@
         }
     }
 
-    static final class ProviderClientRecord {
+    final class ProviderClientRecord {
         final String[] mNames;
         final IContentProvider mProvider;
         final ContentProvider mLocalProvider;
@@ -4653,74 +4648,23 @@
 
     public final IContentProvider acquireProvider(
             Context c, String auth, int userId, boolean stable) {
-        final ProviderKey key = new ProviderKey(auth, userId);
-        final IContentProvider provider = acquireExistingProvider(c, key, stable);
+        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
         if (provider != null) {
             return provider;
         }
-        AcquiringProviderRecord r;
-        boolean first = false;
-        synchronized (mAcquiringProviderMap) {
-            r = mAcquiringProviderMap.get(key);
-            if (r == null) {
-                r = new AcquiringProviderRecord();
-                mAcquiringProviderMap.put(key, r);
-                first = true;
-            } else {
-                r.requests++;
-            }
-        }
 
+        // There is a possible race here.  Another thread may try to acquire
+        // the same provider at the same time.  When this happens, we want to ensure
+        // that the first one wins.
+        // Note that we cannot hold the lock while acquiring and installing the
+        // provider since it might take a long time to run and it could also potentially
+        // be re-entrant in the case where the provider is in the same process.
         IActivityManager.ContentProviderHolder holder = null;
         try {
-            if (first) {
-                // Multiple threads may try to acquire the same provider at the same time.
-                // When this happens, we only let the first one really gets provider.
-                // Other threads just wait for its result.
-                // Note that we cannot hold the lock while acquiring and installing the
-                // provider since it might take a long time to run and it could also potentially
-                // be re-entrant in the case where the provider is in the same process.
-                holder = ActivityManagerNative.getDefault().getContentProvider(
-                        getApplicationThread(), auth, userId, stable);
-            } else {
-                synchronized (r) {
-                    while (r.acquiring) {
-                        try {
-                            r.wait();
-                        } catch (InterruptedException e) {
-                        }
-                    }
-                    holder = r.holder;
-                }
-            }
+            holder = ActivityManagerNative.getDefault().getContentProvider(
+                    getApplicationThread(), auth, userId, stable);
         } catch (RemoteException ex) {
-        } catch (RuntimeException e) {
-            synchronized (r) {
-                r.runtimeException = e;
-            }
-        } finally {
-            if (first) {
-                synchronized (r) {
-                    r.holder = holder;
-                    r.acquiring = false;
-                    r.notifyAll();
-                }
-            }
-
-            synchronized (mAcquiringProviderMap) {
-                if (--r.requests == 0) {
-                    mAcquiringProviderMap.remove(key);
-                }
-            }
-
-            if (r.runtimeException != null) {
-                // Was set when the first thread tried to acquire the provider,
-                // but we should make sure it is thrown for all threads trying to
-                // acquire the provider.
-                throw r.runtimeException;
-            }
         }
-
         if (holder == null) {
             Slog.e(TAG, "Failed to find provider info for " + auth);
             return null;
@@ -4803,12 +4747,8 @@
 
     public final IContentProvider acquireExistingProvider(
             Context c, String auth, int userId, boolean stable) {
-        return acquireExistingProvider(c, new ProviderKey(auth, userId), stable);
-    }
-
-    final IContentProvider acquireExistingProvider(
-            Context c, ProviderKey key, boolean stable) {
         synchronized (mProviderMap) {
+            final ProviderKey key = new ProviderKey(auth, userId);
             final ProviderClientRecord pr = mProviderMap.get(key);
             if (pr == null) {
                 return null;
@@ -4819,7 +4759,7 @@
             if (!jBinder.isBinderAlive()) {
                 // The hosting process of the provider has died; we can't
                 // use this one.
-                Log.i(TAG, "Acquiring provider " + key.authority + " for user " +  key.userId
+                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                         + ": existing object's process dead");
                 handleUnstableProviderDiedLocked(jBinder, true);
                 return null;
@@ -5141,12 +5081,18 @@
                     if (DEBUG_PROVIDER) {
                         Slog.v(TAG, "installProvider: lost the race, updating ref count");
                     }
-                    // The provider has already been installed, so we need
-                    // to increase reference count to the existing one, but
-                    // only if release is needed (that is, it is not running
-                    // in the system process or local to the process).
+                    // We need to transfer our new reference to the existing
+                    // ref count, releasing the old one...  but only if
+                    // release is needed (that is, it is not running in the
+                    // system process).
                     if (!noReleaseNeeded) {
                         incProviderRefLocked(prc, stable);
+                        try {
+                            ActivityManagerNative.getDefault().removeContentProvider(
+                                    holder.connection, stable);
+                        } catch (RemoteException e) {
+                            //do nothing content provider object is dead any way
+                        }
                     }
                 } else {
                     ProviderClientRecord client = installProviderAuthoritiesLocked(
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 24a7d33..3cda39a 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -91,8 +91,6 @@
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
-    private static final Pattern TRIM_SQL_PATTERN = Pattern.compile("[\\s]*\\n+[\\s]*");
-
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private final SQLiteConnectionPool mPool;
@@ -1203,7 +1201,11 @@
     }
 
     private static String trimSqlForDisplay(String sql) {
-        return TRIM_SQL_PATTERN.matcher(sql).replaceAll(" ");
+        // Note: Creating and caching a regular expression is expensive at preload-time
+        //       and stops compile-time initialization. This pattern is only used when
+        //       dumping the connection, which is a rare (mainly error) case. So:
+        //       DO NOT CACHE.
+        return sql.replaceAll("[\\s]*\\n+[\\s]*", " ");
     }
 
     /**
@@ -1437,9 +1439,6 @@
     }
 
     private static final class Operation {
-        private static final SimpleDateFormat sDateFormat =
-                new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-
         public long mStartTime;
         public long mEndTime;
         public String mKind;
@@ -1494,7 +1493,11 @@
         }
 
         private String getFormattedStartTime() {
-            return sDateFormat.format(new Date(mStartTime));
+            // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is
+            //       relatively expensive to create during preloading. This method is only used
+            //       when dumping a connection, which is a rare (mainly error) case. So:
+            //       DO NOT CACHE.
+            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(mStartTime));
         }
     }
 }
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b268986..6b4f2d5 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -170,6 +170,21 @@
     }
 
     /**
+     * Determines whether the prefix contains the specified address.
+     *
+     * @param address An {@link InetAddress} to test.
+     * @return {@code true} if the prefix covers the given address.
+     */
+    public boolean contains(InetAddress address) {
+        byte[] addrBytes = (address == null) ? null : address.getAddress();
+        if (addrBytes == null || addrBytes.length != this.address.length) {
+            return false;
+        }
+        NetworkUtils.maskRawAddress(addrBytes, prefixLength);
+        return Arrays.equals(this.address, addrBytes);
+    }
+
+    /**
      * Returns a string representation of this {@code IpPrefix}.
      *
      * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index cfd20a0..90a2460 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -367,13 +367,7 @@
      * @return {@code true} if the destination and prefix length cover the given address.
      */
     public boolean matches(InetAddress destination) {
-        if (destination == null) return false;
-
-        // match the route destination and destination with prefix length
-        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
-                mDestination.getPrefixLength());
-
-        return mDestination.getAddress().equals(dstNet);
+        return mDestination.contains(destination);
     }
 
     /**
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index fb2f445..5453283 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1657,7 +1657,7 @@
     /**
      * Searches the query string for the first value with the given key.
      *
-     * <p><strong>Warning:</strong> Prior to Ice Cream Sandwich, this decoded
+     * <p><strong>Warning:</strong> Prior to Jelly Bean, this decoded
      * the '+' character as '+' rather than ' '.
      *
      * @param key which will be encoded
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index 9599308..c027d54 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -24,7 +24,7 @@
  */
 interface IAppCallback
 {
-    BeamShareData createBeamShareData();
-    void onNdefPushComplete();
+    BeamShareData createBeamShareData(byte peerLlcpVersion);
+    void onNdefPushComplete(byte peerLlcpVersion);
     void onTagDiscovered(in Tag tag);
 }
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d009295..76bd0ec 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -46,7 +46,6 @@
     static final Boolean DBG = false;
 
     final NfcAdapter mAdapter;
-    final NfcEvent mDefaultEvent;  // cached NfcEvent (its currently always the same)
 
     // All objects in the lists are protected by this
     final List<NfcApplicationState> mApps;  // Application(s) that have NFC state. Usually one
@@ -200,7 +199,6 @@
         mAdapter = adapter;
         mActivities = new LinkedList<NfcActivityState>();
         mApps = new ArrayList<NfcApplicationState>(1);  // Android VM usually has 1 app
-        mDefaultEvent = new NfcEvent(mAdapter);
     }
 
     public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
@@ -354,13 +352,14 @@
 
     /** Callback from NFC service, usually on binder thread */
     @Override
-    public BeamShareData createBeamShareData() {
+    public BeamShareData createBeamShareData(byte peerLlcpVersion) {
         NfcAdapter.CreateNdefMessageCallback ndefCallback;
         NfcAdapter.CreateBeamUrisCallback urisCallback;
         NdefMessage message;
         Activity activity;
         Uri[] uris;
         int flags;
+        NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findResumedActivityState();
             if (state == null) return null;
@@ -375,10 +374,10 @@
 
         // Make callbacks without lock
         if (ndefCallback != null) {
-            message  = ndefCallback.createNdefMessage(mDefaultEvent);
+            message  = ndefCallback.createNdefMessage(event);
         }
         if (urisCallback != null) {
-            uris = urisCallback.createBeamUris(mDefaultEvent);
+            uris = urisCallback.createBeamUris(event);
             if (uris != null) {
                 ArrayList<Uri> validUris = new ArrayList<Uri>();
                 for (Uri uri : uris) {
@@ -412,7 +411,7 @@
 
     /** Callback from NFC service, usually on binder thread */
     @Override
-    public void onNdefPushComplete() {
+    public void onNdefPushComplete(byte peerLlcpVersion) {
         NfcAdapter.OnNdefPushCompleteCallback callback;
         synchronized (NfcActivityManager.this) {
             NfcActivityState state = findResumedActivityState();
@@ -420,10 +419,10 @@
 
             callback = state.onNdefPushCompleteCallback;
         }
-
+        NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
         // Make callback without lock
         if (callback != null) {
-            callback.onNdefPushComplete(mDefaultEvent);
+            callback.onNdefPushComplete(event);
         }
     }
 
diff --git a/core/java/android/nfc/NfcEvent.java b/core/java/android/nfc/NfcEvent.java
index 860700a..cf1d71a 100644
--- a/core/java/android/nfc/NfcEvent.java
+++ b/core/java/android/nfc/NfcEvent.java
@@ -38,7 +38,14 @@
      */
     public final NfcAdapter nfcAdapter;
 
-    NfcEvent(NfcAdapter nfcAdapter) {
+    /**
+     * The LLCP version of the peer associated with the NFC event.
+     * The major version is in the top nibble, the minor version is in the bottom nibble.
+     */
+    public final byte peerLlcpVersion;
+
+    NfcEvent(NfcAdapter nfcAdapter, byte peerLlcpVersion) {
         this.nfcAdapter = nfcAdapter;
+        this.peerLlcpVersion = peerLlcpVersion;
     }
 }
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 00b2ee3..f10e530 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -40,6 +40,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -262,7 +263,7 @@
      * for that category.
      * @return List of AIDs registered by the service
      */
-    public ArrayList<String> getAids() {
+    public List<String> getAids() {
         final ArrayList<String> aids = new ArrayList<String>();
         for (AidGroup group : getAidGroups()) {
             aids.addAll(group.aids);
@@ -270,6 +271,18 @@
         return aids;
     }
 
+    public List<String> getPrefixAids() {
+        final ArrayList<String> prefixAids = new ArrayList<String>();
+        for (AidGroup group : getAidGroups()) {
+            for (String aid : group.aids) {
+                if (aid.endsWith("*")) {
+                    prefixAids.add(aid);
+                }
+            }
+        }
+        return prefixAids;
+    }
+
     /**
      * Returns the registered AID group for this category.
      */
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index c5c5372..cb3e22b 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -211,8 +211,9 @@
                     } else if (obj instanceof Parcelable[]) {
                         Parcelable[] array = (Parcelable[]) obj;
                         for (int n = array.length - 1; n >= 0; n--) {
-                            if ((array[n].describeContents()
-                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
+                            Parcelable p = array[n];
+                            if (p != null && ((p.describeContents()
+                                    & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0)) {
                                 fdFound = true;
                                 break;
                             }
@@ -221,7 +222,8 @@
                         SparseArray<? extends Parcelable> array =
                                 (SparseArray<? extends Parcelable>) obj;
                         for (int n = array.size() - 1; n >= 0; n--) {
-                            if ((array.valueAt(n).describeContents()
+                            Parcelable p = array.valueAt(n);
+                            if (p != null && (p.describeContents()
                                     & Parcelable.CONTENTS_FILE_DESCRIPTOR) != 0) {
                                 fdFound = true;
                                 break;
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2d92c7b..2a60b4d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -34,6 +34,7 @@
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
 
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
@@ -1035,6 +1036,95 @@
     }
 
     /**
+     * Returns the value of a particular runtime statistic or {@code null} if no
+     * such runtime statistic exists.
+     *
+     * <p>The following table lists the runtime statistics that the runtime supports.
+     * Note runtime statistics may be added or removed in a future API level.</p>
+     *
+     * <table>
+     *     <thead>
+     *         <tr>
+     *             <th>Runtime statistic name</th>
+     *             <th>Meaning</th>
+     *             <th>Example</th>
+     *             <th>Supported (API Levels)</th>
+     *         </tr>
+     *     </thead>
+     *     <tbody>
+     *         <tr>
+     *             <td>art.gc.gc-count</td>
+     *             <td>The number of garbage collection runs.</td>
+     *             <td>{@code 164}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.gc-time</td>
+     *             <td>The total duration of garbage collection runs in ms.</td>
+     *             <td>{@code 62364}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.bytes-allocated</td>
+     *             <td>The total number of bytes that the application allocated.</td>
+     *             <td>{@code 1463948408}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.bytes-freed</td>
+     *             <td>The total number of bytes that garbage collection reclaimed.</td>
+     *             <td>{@code 1313493084}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-count</td>
+     *             <td>The number of blocking garbage collection runs.</td>
+     *             <td>{@code 2}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-time</td>
+     *             <td>The total duration of blocking garbage collection runs in ms.</td>
+     *             <td>{@code 804}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.gc-count-rate-histogram</td>
+     *             <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+     *             <td>{@code 0:34503,1:45350,2:11281,3:8088,4:43,5:8}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-count-rate-histogram</td>
+     *             <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+     *             <td>{@code 0:99269,1:1,2:1}</td>
+     *             <td>23</td>
+     *         </tr>
+     *     </tbody>
+     * </table>
+     *
+     * @param statName
+     *            the name of the runtime statistic to look up.
+     * @return the value of the specified runtime statistic or {@code null} if the
+     *         runtime statistic doesn't exist.
+     * @hide
+     */
+    public static String getRuntimeStat(String statName) {
+        return VMDebug.getRuntimeStat(statName);
+    }
+
+    /**
+     * Returns a map of the names/values of the runtime statistics
+     * that {@link #getRuntimeStat(String)} supports.
+     *
+     * @return a map of the names/values of the supported runtime statistics.
+     * @hide
+     */
+    public static Map<String, String> getRuntimeStats() {
+        return VMDebug.getRuntimeStats();
+    }
+
+    /**
      * Returns the size of the native heap.
      * @return The size of the native heap in bytes.
      */
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0de9c70..d2eaed3 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -634,6 +634,9 @@
             if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) {
                 argsForZygote.add("--enable-jit");
             }
+            if ((debugFlags & Zygote.DEBUG_GENERATE_CFI) != 0) {
+                argsForZygote.add("--generate-cfi");
+            }
             if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                 argsForZygote.add("--enable-assert");
             }
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
index 9a1c894..9adde35 100644
--- a/core/java/android/security/keymaster/KeymasterArgument.java
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -42,6 +42,7 @@
                         case KeymasterDefs.KM_INT_REP:
                             return new KeymasterIntArgument(tag, in);
                         case KeymasterDefs.KM_LONG:
+                        case KeymasterDefs.KM_LONG_REP:
                             return new KeymasterLongArgument(tag, in);
                         case KeymasterDefs.KM_DATE:
                             return new KeymasterDateArgument(tag, in);
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index 8ed288c..82f65c7 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -63,6 +63,12 @@
         }
     }
 
+    public void addLongs(int tag, long... values) {
+        for (long value : values) {
+            addLong(tag, value);
+        }
+    }
+
     public void addBoolean(int tag) {
         mArguments.add(new KeymasterBooleanArgument(tag));
     }
@@ -111,8 +117,13 @@
     }
 
     public long getLong(int tag, long defaultValue) {
-        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG) {
-            throw new IllegalArgumentException("Tag is not a long type: " + tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_LONG:
+                break; // Accepted type
+            case KeymasterDefs.KM_LONG_REP:
+                throw new IllegalArgumentException("Repeatable tags must use getLongs: " + tag);
+            default:
+                throw new IllegalArgumentException("Tag is not a long type: " + tag);
         }
         KeymasterArgument arg = getArgumentByTag(tag);
         if (arg == null) {
@@ -175,6 +186,19 @@
         return values;
     }
 
+    public List<Long> getLongs(int tag) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) {
+            throw new IllegalArgumentException("Tag is not a repeating long: " + tag);
+        }
+        List<Long> values = new ArrayList<Long>();
+        for (KeymasterArgument arg : mArguments) {
+            if (arg.tag == tag) {
+                values.add(((KeymasterLongArgument) arg).value);
+            }
+        }
+        return values;
+    }
+
     public int size() {
         return mArguments.size();
     }
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index d3953b3..25ebe75 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -118,9 +118,9 @@
     public static final int KM_DIGEST_SHA_2_512 = 6;
 
     // Key origins.
-    public static final int KM_ORIGIN_HARDWARE = 0;
-    public static final int KM_ORIGIN_SOFTWARE = 1;
+    public static final int KM_ORIGIN_GENERATED = 0;
     public static final int KM_ORIGIN_IMPORTED = 2;
+    public static final int KM_ORIGIN_UNKNOWN = 3;
 
     // Key usability requirements.
     public static final int KM_BLOB_STANDALONE = 0;
@@ -191,6 +191,8 @@
     public static final int KM_ERROR_SECURE_HW_BUSY = -48;
     public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49;
     public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
+    public static final int KM_ERROR_MISSING_NONCE = -51;
+    public static final int KM_ERROR_INVALID_NONCE = -52;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -230,6 +232,8 @@
         sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag");
         sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
+        sErrorCodeToString.put(KM_ERROR_MISSING_NONCE, "Required IV missing");
+        sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index d51d7e6..e04ce5d 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -29,6 +29,7 @@
         super(tag);
         switch (KeymasterDefs.getTagType(tag)) {
             case KeymasterDefs.KM_LONG:
+            case KeymasterDefs.KM_LONG_REP:
                 break; // OK.
             default:
                 throw new IllegalArgumentException("Bad long tag " + tag);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index a237afd..27304f5 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -1040,14 +1040,10 @@
             return methods;
         }
 
-        final ArrayList<Method> declaredMethods = new ArrayList();
-        klass.getDeclaredMethodsUnchecked(false, declaredMethods);
+        methods = klass.getDeclaredMethodsUnchecked(false);
 
         final ArrayList<Method> foundMethods = new ArrayList<Method>();
-        final int count = declaredMethods.size();
-        for (int i = 0; i < count; i++) {
-            final Method method = declaredMethods.get(i);
-
+        for (final Method method : methods) {
             // Ensure the method return and parameter types can be resolved.
             try {
                 method.getReturnType();
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 5eaf20c..ab34064 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -620,7 +620,15 @@
                 // remove based on both its position as well as it's current memory usage, as well
                 // as whether it was directly requested vs. whether it was preloaded by our caching
                 // mechanism.
-                mIndexRemoteViews.remove(getFarthestPositionFrom(pruneFromPosition, visibleWindow));
+                int trimIndex = getFarthestPositionFrom(pruneFromPosition, visibleWindow);
+
+                // Need to check that this is a valid index, to cover the case where you have only
+                // a single view in the cache, but it's larger than the max memory limit
+                if (trimIndex < 0) {
+                    break;
+                }
+
+                mIndexRemoteViews.remove(trimIndex);
             }
 
             // Update the metadata cache
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index b3bafa1..1038acf4 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -256,7 +256,7 @@
                 final Double[] values = (Double[]) data;
                 if (values.length > level && level >= 0) {
                     return values[level];
-                } else if (level < 0) {
+                } else if (level < 0 || values.length == 0) {
                     return 0;
                 } else {
                     return values[values.length - 1];
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 8674a21..86ba780 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -40,6 +40,8 @@
     public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
     /** enable the JIT compiler */
     public static final int DEBUG_ENABLE_JIT         = 1 << 5;
+    /** Force generation of CFI code */
+    public static final int DEBUG_GENERATE_CFI       = 1 << 6;
 
 
     /** No external storage should be mounted. */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 0dc242d..f43cc62 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -322,7 +322,7 @@
 
         /**
          * From --enable-debugger, --enable-checkjni, --enable-assert,
-         * --enable-safemode, --enable-jit, and --enable-jni-logging.
+         * --enable-safemode, --enable-jit, --generate-cfi and --enable-jni-logging.
          */
         int debugFlags;
 
@@ -434,6 +434,8 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
                 } else if (arg.equals("--enable-jit")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_JIT;
+                } else if (arg.equals("--generate-cfi")) {
+                    debugFlags |= Zygote.DEBUG_GENERATE_CFI;
                 } else if (arg.equals("--enable-jni-logging")) {
                     debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
                 } else if (arg.equals("--enable-assert")) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 50ddbd1..d44959b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -267,7 +267,12 @@
                     if (false) {
                         Log.v(TAG, "Preloading " + line + "...");
                     }
-                    Class.forName(line);
+                    // Load and explicitly initialize the given class. Use
+                    // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
+                    // (to derive the caller's class-loader). Use true to force initialization, and
+                    // null for the boot classpath class-loader (could as well cache the
+                    // class-loader of this class in a variable).
+                    Class.forName(line, true, null);
                     count++;
                 } catch (ClassNotFoundException e) {
                     Log.w(TAG, "Class not found for preloading: " + line);
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0bfc0c9..82fe227 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -873,6 +873,19 @@
     snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
     addOption(cpuAbiListBuf);
 
+    /*
+     * When running with debug.gencfi, add --include-cfi to the compiler options so that the boot
+     * image, if it is compiled on device, will include CFI info, as well as other compilations
+     * started by the runtime.
+     */
+    property_get("debug.gencfi", propBuf, "");
+    if (strcmp(propBuf, "true") == 0) {
+        addOption("-Xcompiler-option");
+        addOption("--include-cfi");
+        addOption("-Ximage-compiler-option");
+        addOption("--include-cfi");
+    }
+
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
     initArgs.nOptions = mOptions.size();
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
index 5fa2405..6ee6ffa 100644
--- a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
@@ -5,7 +5,6 @@
 
 LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
 
-LOCAL_JNI_SHARED_LIBRARIES_ZIP_OPTIONS := -0
 LOCAL_PAGE_ALIGN_JNI_SHARED_LIBRARIES := true
 
 include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index cf278fb..fcc6389 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -29,6 +29,10 @@
 
 public class IpPrefixTest extends TestCase {
 
+    private static InetAddress Address(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
     // Explicitly cast everything to byte because "error: possible loss of precision".
     private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
     private static final byte[] IPV6_BYTES = {
@@ -209,6 +213,34 @@
     }
 
     @SmallTest
+    public void testContains() {
+        IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
+        assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
+        assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
+        assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
+        assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
+        assertFalse(p.contains(Address("2001:4868:4860::8888")));
+        assertFalse(p.contains(null));
+        assertFalse(p.contains(Address("8.8.8.8")));
+
+        p = new IpPrefix("192.0.2.0/23");
+        assertTrue(p.contains(Address("192.0.2.43")));
+        assertTrue(p.contains(Address("192.0.3.21")));
+        assertFalse(p.contains(Address("192.0.0.21")));
+        assertFalse(p.contains(Address("8.8.8.8")));
+        assertFalse(p.contains(Address("2001:4868:4860::8888")));
+
+        IpPrefix ipv6Default = new IpPrefix("::/0");
+        assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
+        assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+
+        IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
+        assertTrue(ipv4Default.contains(Address("255.255.255.255")));
+        assertTrue(ipv4Default.contains(Address("192.0.2.1")));
+        assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+    }
+
+    @SmallTest
     public void testHashCode() {
         IpPrefix p;
         int oldCode = -1;
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 0b88bc7..831fefd 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -90,6 +90,7 @@
         assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
         assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
         assertFalse(r.matches(Address("2001:4868:4860::8888")));
+        assertFalse(r.matches(Address("8.8.8.8")));
 
         r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
         assertTrue(r.matches(Address("192.0.2.43")));
diff --git a/docs/html/tools/help/hprof-conv.jd b/docs/html/tools/help/hprof-conv.jd
index f96def2..982f337 100644
--- a/docs/html/tools/help/hprof-conv.jd
+++ b/docs/html/tools/help/hprof-conv.jd
@@ -8,9 +8,13 @@
 generated by the Android SDK tools to a standard format so you
 can view the file in a profiling tool of your choice. </p>
 
-<pre> hprof-conv &lt;infile&gt; &lt;outfile&gt;</pre>
+<pre> hprof-conv [-z] &lt;infile&gt; &lt;outfile&gt;</pre>
 
 <p>
 You can use "-" for <code>&lt;infile&gt;</code> or <code>&lt;outfile&gt;</code>
 to specify stdin or stdout.
 </p>
+
+<p>
+You can use "-z" to filter out zygote allocations shared by all applications.
+</p>
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 0822afd..8de0138 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -372,7 +372,8 @@
     };
 
     // The data for this item, as interpreted according to dataType.
-    uint32_t data;
+    typedef uint32_t data_type;
+    data_type data;
 
     void copyFrom_dtoh(const Res_value& src);
 };
@@ -1502,6 +1503,8 @@
     KeyedVector<String16, uint8_t>  mEntries;
 };
 
+bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
+
 /**
  * Convenience class for accessing data in a ResTable resource.
  */
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
index 5fae831..3b25ba6 100644
--- a/keystore/java/android/security/AndroidKeyPairGenerator.java
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -17,7 +17,7 @@
 package android.security;
 
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-import com.android.org.conscrypt.NativeCrypto;
+import com.android.org.conscrypt.NativeConstants;
 import com.android.org.conscrypt.OpenSSLEngine;
 
 import java.security.InvalidAlgorithmParameterException;
@@ -206,9 +206,9 @@
     }
 
     private static int getDefaultKeySize(int keyType) {
-        if (keyType == NativeCrypto.EVP_PKEY_EC) {
+        if (keyType == NativeConstants.EVP_PKEY_EC) {
             return EC_DEFAULT_KEY_SIZE;
-        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
+        } else if (keyType == NativeConstants.EVP_PKEY_RSA) {
             return RSA_DEFAULT_KEY_SIZE;
         }
         return -1;
@@ -216,12 +216,12 @@
 
     private static void checkValidKeySize(String keyAlgorithm, int keyType, int keySize)
             throws InvalidAlgorithmParameterException {
-        if (keyType == NativeCrypto.EVP_PKEY_EC) {
+        if (keyType == NativeConstants.EVP_PKEY_EC) {
             if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
                 throw new InvalidAlgorithmParameterException("EC keys must be >= "
                         + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE);
             }
-        } else if (keyType == NativeCrypto.EVP_PKEY_RSA) {
+        } else if (keyType == NativeConstants.EVP_PKEY_RSA) {
             if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
                 throw new InvalidAlgorithmParameterException("RSA keys must be >= "
                         + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
@@ -234,7 +234,7 @@
 
     private static void checkCorrectParametersSpec(int keyType, int keySize,
             AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException {
-        if (keyType == NativeCrypto.EVP_PKEY_RSA && spec != null) {
+        if (keyType == NativeConstants.EVP_PKEY_RSA && spec != null) {
             if (spec instanceof RSAKeyGenParameterSpec) {
                 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
                 if (keySize != -1 && keySize != rsaSpec.getKeysize()) {
@@ -260,7 +260,7 @@
 
     private static byte[][] getArgsForKeyType(int keyType, AlgorithmParameterSpec spec) {
         switch (keyType) {
-            case NativeCrypto.EVP_PKEY_RSA:
+            case NativeConstants.EVP_PKEY_RSA:
                 if (spec instanceof RSAKeyGenParameterSpec) {
                     RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) spec;
                     return new byte[][] { rsaSpec.getPublicExponent().toByteArray() };
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index fcee9fc..964fb21 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -55,6 +55,7 @@
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 
 import javax.crypto.SecretKey;
@@ -116,11 +117,15 @@
                 throw new UnrecoverableKeyException("Key algorithm unknown");
             }
 
-            int keymasterDigest =
-                    keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
-            if (keymasterDigest == -1) {
-                keymasterDigest =
-                        keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
+            List<Integer> keymasterDigests =
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
+            int keymasterDigest;
+            if (keymasterDigests.isEmpty()) {
+                keymasterDigest = -1;
+            } else {
+                // More than one digest can be permitted for this key. Use the first one to form the
+                // JCA key algorithm name.
+                keymasterDigest = keymasterDigests.get(0);
             }
 
             String keyAlgorithmString;
diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java
deleted file mode 100644
index 00c142f..0000000
--- a/keystore/java/android/security/CryptoOperationException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2015 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 android.security;
-
-/**
- * Base class for exceptions during cryptographic operations which cannot throw a suitable checked
- * exception.
- *
- * <p>The contract of the majority of crypto primitives/operations (e.g. {@code Cipher} or
- * {@code Signature}) is that they can throw a checked exception during initialization, but are not
- * permitted to throw a checked exception during operation. Because crypto operations can fail
- * for a variety of reasons after initialization, this base class provides type-safety for unchecked
- * exceptions that may be thrown in those cases.
- *
- * @hide
- */
-public class CryptoOperationException extends RuntimeException {
-
-    /**
-     * Constructs a new {@code CryptoOperationException} without detail message and cause.
-     */
-    public CryptoOperationException() {
-        super();
-    }
-
-    /**
-     * Constructs a new {@code CryptoOperationException} with the provided detail message and no
-     * cause.
-     */
-    public CryptoOperationException(String message) {
-        super(message);
-    }
-
-    /**
-     * Constructs a new {@code CryptoOperationException} with the provided detail message and cause.
-     */
-    public CryptoOperationException(String message, Throwable cause) {
-        super(message, cause);
-    }
-
-    /**
-     * Constructs a new {@code CryptoOperationException} with the provided cause.
-     */
-    public CryptoOperationException(Throwable cause) {
-        super(cause);
-    }
-}
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java
index 0f19812..3372da9 100644
--- a/keystore/java/android/security/EcIesParameterSpec.java
+++ b/keystore/java/android/security/EcIesParameterSpec.java
@@ -85,11 +85,10 @@
     }
 
     /**
-     * Default parameter spec: NIST P-256 curve (aka secp256r1 aka prime256v1), compressed point
-     * format, {@code HKDFwithSHA256}, DEM uses 128-bit AES GCM.
+     * Default parameter spec: compressed point format, {@code HKDFwithSHA256}, DEM uses 128-bit AES
+     * GCM.
      */
     public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec(
-            "P-256",
             PointFormat.COMPRESSED,
             "HKDFwithSHA256",
             "AES/GCM/NoPadding",
@@ -97,7 +96,6 @@
             null,
             0);
 
-    private final String mKemCurveName;
     private final @PointFormatEnum int mKemPointFormat;
     private final String mKemKdfAlgorithm;
     private final String mDemCipherTransformation;
@@ -106,14 +104,12 @@
     private final int mDemMacKeySize;
 
     private EcIesParameterSpec(
-            String kemCurveName,
             @PointFormatEnum int kemPointFormat,
             String kemKdfAlgorithm,
             String demCipherTransformation,
             int demCipherKeySize,
             String demMacAlgorithm,
             int demMacKeySize) {
-        mKemCurveName = kemCurveName;
         mKemPointFormat = kemPointFormat;
         mKemKdfAlgorithm = kemKdfAlgorithm;
         mDemCipherTransformation = demCipherTransformation;
@@ -123,13 +119,6 @@
     }
 
     /**
-     * Returns KEM EC curve name (e.g., {@code secp256r1}) or {@code null} if not specified.
-     */
-    public String getKemCurveName() {
-        return mKemCurveName;
-    }
-
-    /**
      * Returns KEM EC point wire format or {@link PointFormat#UNSPECIFIED} if not specified.
      */
     public @PointFormatEnum int getKemPointFormat() {
@@ -188,7 +177,6 @@
      * Builder of {@link EcIesParameterSpec}.
      */
     public static class Builder {
-        private String mKemCurveName;
         private @PointFormatEnum int mKemPointFormat = PointFormat.UNSPECIFIED;
         private String mKemKdfAlgorithm;
         private String mDemCipherTransformation;
@@ -197,16 +185,6 @@
         private int mDemMacKeySize = -1;
 
         /**
-         * Sets KEM EC curve name. For example, {@code P-256} or {@code secp256r1}.
-         *
-         * <p>NOTE: Only curves with cofactor of {@code 1} are supported.
-         */
-        public Builder setKemCurveName(String name) {
-            mKemCurveName = name;
-            return this;
-        }
-
-        /**
          * Sets KEM EC point wire format.
          */
         public Builder setKemPointFormat(@PointFormatEnum int pointFormat) {
@@ -274,7 +252,6 @@
         public EcIesParameterSpec build() {
             int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize;
             return new EcIesParameterSpec(
-                    mKemCurveName,
                     mKemPointFormat,
                     mKemKdfAlgorithm,
                     mDemCipherTransformation,
diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/KeyExpiredException.java
index 35a5acc..e64bffa 100644
--- a/keystore/java/android/security/KeyExpiredException.java
+++ b/keystore/java/android/security/KeyExpiredException.java
@@ -16,13 +16,15 @@
 
 package android.security;
 
+import java.security.InvalidKeyException;
+
 /**
  * Indicates that a cryptographic operation failed because the employed key's validity end date
  * is in the past.
  *
  * @hide
  */
-public class KeyExpiredException extends CryptoOperationException {
+public class KeyExpiredException extends InvalidKeyException {
 
     /**
      * Constructs a new {@code KeyExpiredException} without detail message and cause.
diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/KeyNotYetValidException.java
index f1c2cac..d36d80c 100644
--- a/keystore/java/android/security/KeyNotYetValidException.java
+++ b/keystore/java/android/security/KeyNotYetValidException.java
@@ -16,13 +16,15 @@
 
 package android.security;
 
+import java.security.InvalidKeyException;
+
 /**
  * Indicates that a cryptographic operation failed because the employed key's validity start date
  * is in the future.
  *
  * @hide
  */
-public class KeyNotYetValidException extends CryptoOperationException {
+public class KeyNotYetValidException extends InvalidKeyException {
 
     /**
      * Constructs a new {@code KeyNotYetValidException} without detail message and cause.
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 9d6701a..fce02df 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -52,6 +52,11 @@
  */
 public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
 
+    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
+    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
     private final Context mContext;
 
     private final String mKeystoreAlias;
@@ -144,22 +149,29 @@
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if (subjectDN == null) {
-            throw new IllegalArgumentException("subjectDN == null");
-        } else if (serialNumber == null) {
-            throw new IllegalArgumentException("serialNumber == null");
-        } else if (startDate == null) {
-            throw new IllegalArgumentException("startDate == null");
-        } else if (endDate == null) {
-            throw new IllegalArgumentException("endDate == null");
-        } else if (endDate.before(startDate)) {
-            throw new IllegalArgumentException("endDate < startDate");
         } else if ((userAuthenticationValidityDurationSeconds < 0)
                 && (userAuthenticationValidityDurationSeconds != -1)) {
             throw new IllegalArgumentException(
                     "userAuthenticationValidityDurationSeconds must not be negative");
         }
 
+        if (subjectDN == null) {
+            subjectDN = DEFAULT_CERT_SUBJECT;
+        }
+        if (startDate == null) {
+            startDate = DEFAULT_CERT_NOT_BEFORE;
+        }
+        if (endDate == null) {
+            endDate = DEFAULT_CERT_NOT_AFTER;
+        }
+        if (serialNumber == null) {
+            serialNumber = DEFAULT_CERT_SERIAL_NUMBER;
+        }
+
+        if (endDate.before(startDate)) {
+            throw new IllegalArgumentException("endDate < startDate");
+        }
+
         mContext = context;
         mKeystoreAlias = keyStoreAlias;
         mKeyType = keyType;
@@ -559,6 +571,10 @@
         /**
          * Sets the subject used for the self-signed certificate of the
          * generated key pair.
+         *
+         * <p>The subject must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the subject defaults to {@code CN=fake} if not specified.
          */
         public Builder setSubject(X500Principal subject) {
             if (subject == null) {
@@ -571,6 +587,10 @@
         /**
          * Sets the serial number used for the self-signed certificate of the
          * generated key pair.
+         *
+         * <p>The serial number must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the serial number defaults to {@code 1} if not specified.
          */
         public Builder setSerialNumber(BigInteger serialNumber) {
             if (serialNumber == null) {
@@ -583,6 +603,10 @@
         /**
          * Sets the start of the validity period for the self-signed certificate
          * of the generated key pair.
+         *
+         * <p>The date must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the date defaults to {@code Jan 1 1970} if not specified.
          */
         public Builder setStartDate(Date startDate) {
             if (startDate == null) {
@@ -595,6 +619,10 @@
         /**
          * Sets the end of the validity period for the self-signed certificate
          * of the generated key pair.
+         *
+         * <p>The date must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the date defaults to {@code Jan 1 2048} if not specified.
          */
         public Builder setEndDate(Date endDate) {
             if (endDate == null) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a7b4b7a..896d1c2 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,7 +16,7 @@
 
 package android.security;
 
-import com.android.org.conscrypt.NativeCrypto;
+import com.android.org.conscrypt.NativeConstants;
 
 import android.os.Binder;
 import android.os.IBinder;
@@ -30,6 +30,7 @@
 import android.security.keymaster.OperationResult;
 import android.util.Log;
 
+import java.security.InvalidKeyException;
 import java.util.Locale;
 
 /**
@@ -95,9 +96,9 @@
 
     static int getKeyTypeForAlgorithm(String keyType) {
         if ("RSA".equalsIgnoreCase(keyType)) {
-            return NativeCrypto.EVP_PKEY_RSA;
+            return NativeConstants.EVP_PKEY_RSA;
         } else if ("EC".equalsIgnoreCase(keyType)) {
-            return NativeCrypto.EVP_PKEY_EC;
+            return NativeConstants.EVP_PKEY_EC;
         } else {
             return -1;
         }
@@ -516,7 +517,11 @@
         }
     }
 
-    public static KeyStoreException getKeyStoreException(int errorCode) {
+    /**
+     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
+     * code.
+     */
+    static KeyStoreException getKeyStoreException(int errorCode) {
         if (errorCode > 0) {
             // KeyStore layer error
             switch (errorCode) {
@@ -552,7 +557,11 @@
         }
     }
 
-    public static CryptoOperationException getCryptoOperationException(KeyStoreException e) {
+    /**
+     * Returns an {@link InvalidKeyException} corresponding to the provided
+     * {@link KeyStoreException}.
+     */
+    static InvalidKeyException getInvalidKeyException(KeyStoreException e) {
         switch (e.getErrorCode()) {
             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
                 return new KeyExpiredException();
@@ -561,11 +570,15 @@
             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
                 return new UserNotAuthenticatedException();
             default:
-                return new CryptoOperationException("Crypto operation failed", e);
+                return new InvalidKeyException("Keystore operation failed", e);
         }
     }
 
-    public static CryptoOperationException getCryptoOperationException(int errorCode) {
-        return getCryptoOperationException(getKeyStoreException(errorCode));
+    /**
+     * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
+     * code.
+     */
+    static InvalidKeyException getInvalidKeyException(int errorCode) {
+        return getInvalidKeyException(getKeyStoreException(errorCode));
     }
 }
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 7bc6378..3b13e83 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -136,6 +136,14 @@
     private Long mOperationHandle;
     private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
 
+    /**
+     * Encountered exception which could not be immediately thrown because it was encountered inside
+     * a method that does not throw checked exception. This exception will be thrown from
+     * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and
+     * {@code engineDoFinal} start ignoring input data.
+     */
+    private Exception mCachedException;
+
     protected KeyStoreCipherSpi(
             int keymasterAlgorithm,
             int keymasterBlockMode,
@@ -152,29 +160,62 @@
 
     @Override
     protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
-        init(opmode, key, random);
-        initAlgorithmSpecificParameters();
-        ensureKeystoreOperationInitialized();
+        resetAll();
+
+        boolean success = false;
+        try {
+            init(opmode, key, random);
+            initAlgorithmSpecificParameters();
+            try {
+                ensureKeystoreOperationInitialized();
+            } catch (InvalidAlgorithmParameterException e) {
+                throw new InvalidKeyException(e);
+            }
+            success = true;
+        } finally {
+            if (!success) {
+                resetAll();
+            }
+        }
     }
 
     @Override
     protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
-        init(opmode, key, random);
-        initAlgorithmSpecificParameters(params);
-        ensureKeystoreOperationInitialized();
+        resetAll();
+
+        boolean success = false;
+        try {
+            init(opmode, key, random);
+            initAlgorithmSpecificParameters(params);
+            ensureKeystoreOperationInitialized();
+            success = true;
+        } finally {
+            if (!success) {
+                resetAll();
+            }
+        }
     }
 
     @Override
     protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
             SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
-        init(opmode, key, random);
-        initAlgorithmSpecificParameters(params);
-        ensureKeystoreOperationInitialized();
+        resetAll();
+
+        boolean success = false;
+        try {
+            init(opmode, key, random);
+            initAlgorithmSpecificParameters(params);
+            ensureKeystoreOperationInitialized();
+            success = true;
+        } finally {
+            if (!success) {
+                resetAll();
+            }
+        }
     }
 
     private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
-        resetAll();
         if (!(key instanceof KeyStoreSecretKey)) {
             throw new InvalidKeyException(
                     "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
@@ -207,6 +248,7 @@
         mOperationToken = null;
         mOperationHandle = null;
         mMainDataStreamer = null;
+        mCachedException = null;
     }
 
     private void resetWhilePreservingInitState() {
@@ -218,12 +260,17 @@
         mOperationHandle = null;
         mMainDataStreamer = null;
         mAdditionalEntropyForBegin = null;
+        mCachedException = null;
     }
 
-    private void ensureKeystoreOperationInitialized() {
+    private void ensureKeystoreOperationInitialized() throws InvalidKeyException,
+            InvalidAlgorithmParameterException {
         if (mMainDataStreamer != null) {
             return;
         }
+        if (mCachedException != null) {
+            return;
+        }
         if (mKey == null) {
             throw new IllegalStateException("Not initialized");
         }
@@ -252,11 +299,15 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getCryptoOperationException(opResult.resultCode);
+            switch (opResult.resultCode) {
+                case KeymasterDefs.KM_ERROR_INVALID_NONCE:
+                    throw new InvalidAlgorithmParameterException("Invalid IV");
+            }
+            throw KeyStore.getInvalidKeyException(opResult.resultCode);
         }
 
         if (opResult.token == null) {
-            throw new CryptoOperationException("Keystore returned null operation token");
+            throw new IllegalStateException("Keystore returned null operation token");
         }
         mOperationToken = opResult.token;
         mOperationHandle = opResult.operationHandle;
@@ -270,7 +321,15 @@
 
     @Override
     protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
-        ensureKeystoreOperationInitialized();
+        if (mCachedException != null) {
+            return null;
+        }
+        try {
+            ensureKeystoreOperationInitialized();
+        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+            mCachedException = e;
+            return null;
+        }
 
         if (inputLen == 0) {
             return null;
@@ -280,7 +339,8 @@
         try {
             output = mMainDataStreamer.update(input, inputOffset, inputLen);
         } catch (KeyStoreException e) {
-            throw KeyStore.getCryptoOperationException(e);
+            mCachedException = e;
+            return null;
         }
 
         if (output.length == 0) {
@@ -309,7 +369,16 @@
     @Override
     protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
             throws IllegalBlockSizeException, BadPaddingException {
-        ensureKeystoreOperationInitialized();
+        if (mCachedException != null) {
+            throw (IllegalBlockSizeException)
+                    new IllegalBlockSizeException().initCause(mCachedException);
+        }
+
+        try {
+            ensureKeystoreOperationInitialized();
+        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
+            throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
+        }
 
         byte[] output;
         try {
@@ -323,7 +392,7 @@
                 case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
                     throw new AEADBadTagException();
                 default:
-                    throw KeyStore.getCryptoOperationException(e);
+                    throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
             }
         }
 
@@ -547,18 +616,12 @@
             if (mIvRequired) {
                 // IV is needed
                 if ((mIv == null) && (mEncrypting)) {
-                    // TODO: Switch to keymaster-generated IV code below once keymaster supports
-                    // that.
-                    // IV is needed but was not provided by the caller -- generate an IV.
-                    mIv = new byte[mBlockSizeBytes];
-                    SecureRandom rng = (mRng != null) ? mRng : new SecureRandom();
-                    rng.nextBytes(mIv);
-//                    // IV was not provided by the caller and thus will be generated by keymaster.
-//                    // Mix in some additional entropy from the provided SecureRandom.
-//                    if (mRng != null) {
-//                        mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
-//                        mRng.nextBytes(mAdditionalEntropyForBegin);
-//                    }
+                    // IV was not provided by the caller and thus will be generated by keymaster.
+                    // Mix in some additional entropy from the provided SecureRandom.
+                    if (mRng != null) {
+                        mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
+                        mRng.nextBytes(mAdditionalEntropyForBegin);
+                    }
                 }
             }
         }
@@ -590,11 +653,11 @@
             if (mIv == null) {
                 mIv = returnedIv;
             } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
-                throw new CryptoOperationException("IV in use differs from provided IV");
+                throw new IllegalStateException("IV in use differs from provided IV");
             }
         } else {
             if (returnedIv != null) {
-                throw new CryptoOperationException(
+                throw new IllegalStateException(
                         "IV in use despite IV not being used by this transformation");
             }
         }
diff --git a/keystore/java/android/security/KeyStoreConnectException.java b/keystore/java/android/security/KeyStoreConnectException.java
index 8ed6e04..1aa3aec 100644
--- a/keystore/java/android/security/KeyStoreConnectException.java
+++ b/keystore/java/android/security/KeyStoreConnectException.java
@@ -21,7 +21,7 @@
  *
  * @hide
  */
-public class KeyStoreConnectException extends CryptoOperationException {
+public class KeyStoreConnectException extends IllegalStateException {
     public KeyStoreConnectException() {
         super("Failed to communicate with keystore service");
     }
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index aafd2fa..0619199 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -136,7 +136,7 @@
                     // More input is available, but it wasn't included into the previous chunk
                     // because the chunk reached its maximum permitted size.
                     // Shouldn't have happened.
-                    throw new CryptoOperationException("Nothing consumed from max-sized chunk: "
+                    throw new IllegalStateException("Nothing consumed from max-sized chunk: "
                             + chunk.length + " bytes");
                 }
                 mBuffered = chunk;
@@ -148,7 +148,7 @@
                 mBufferedOffset = opResult.inputConsumed;
                 mBufferedLength = chunk.length - opResult.inputConsumed;
             } else {
-                throw new CryptoOperationException("Consumed more than provided: "
+                throw new IllegalStateException("Consumed more than provided: "
                         + opResult.inputConsumed + ", provided: " + chunk.length);
             }
 
@@ -160,7 +160,7 @@
                         try {
                             bufferedOutput.write(opResult.output);
                         } catch (IOException e) {
-                            throw new CryptoOperationException("Failed to buffer output", e);
+                            throw new IllegalStateException("Failed to buffer output", e);
                         }
                     }
                 } else {
@@ -173,7 +173,7 @@
                         try {
                             bufferedOutput.write(opResult.output);
                         } catch (IOException e) {
-                            throw new CryptoOperationException("Failed to buffer output", e);
+                            throw new IllegalStateException("Failed to buffer output", e);
                         }
                         return bufferedOutput.toByteArray();
                     }
@@ -233,10 +233,10 @@
         }
 
         if (opResult.inputConsumed < chunk.length) {
-            throw new CryptoOperationException("Keystore failed to consume all input. Provided: "
+            throw new IllegalStateException("Keystore failed to consume all input. Provided: "
                     + chunk.length + ", consumed: " + opResult.inputConsumed);
         } else if (opResult.inputConsumed > chunk.length) {
-            throw new CryptoOperationException("Keystore consumed more input than provided"
+            throw new IllegalStateException("Keystore consumed more input than provided"
                     + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
         }
 
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index a19bbda..175369c 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -69,9 +69,10 @@
     private final int mKeymasterDigest;
     private final int mMacSizeBytes;
 
-    private String mKeyAliasInKeyStore;
+    // Fields below are populated by engineInit and should be preserved after engineDoFinal.
+    private KeyStoreSecretKey mKey;
 
-    // The fields below are reset by the engineReset operation.
+    // Fields below are reset when engineDoFinal succeeds.
     private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
     private IBinder mOperationToken;
     private Long mOperationHandle;
@@ -89,28 +90,39 @@
     @Override
     protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
             InvalidAlgorithmParameterException {
+        resetAll();
+
+        boolean success = false;
+        try {
+            init(key, params);
+            ensureKeystoreOperationInitialized();
+            success = true;
+        } finally {
+            if (!success) {
+                resetAll();
+            }
+        }
+    }
+
+    private void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
+        InvalidAlgorithmParameterException {
         if (key == null) {
             throw new InvalidKeyException("key == null");
         } else if (!(key instanceof KeyStoreSecretKey)) {
             throw new InvalidKeyException(
                     "Only Android KeyStore secret keys supported. Key: " + key);
         }
+        mKey = (KeyStoreSecretKey) key;
 
         if (params != null) {
             throw new InvalidAlgorithmParameterException(
                     "Unsupported algorithm parameters: " + params);
         }
 
-        mKeyAliasInKeyStore = ((KeyStoreSecretKey) key).getAlias();
-        if (mKeyAliasInKeyStore == null) {
-            throw new InvalidKeyException("Key's KeyStore alias not known");
-        }
-        engineReset();
-        ensureKeystoreOperationInitialized();
     }
 
-    @Override
-    protected void engineReset() {
+    private void resetAll() {
+        mKey = null;
         IBinder operationToken = mOperationToken;
         if (operationToken != null) {
             mOperationToken = null;
@@ -120,11 +132,26 @@
         mChunkedStreamer = null;
     }
 
-    private void ensureKeystoreOperationInitialized() {
+    private void resetWhilePreservingInitState() {
+        IBinder operationToken = mOperationToken;
+        if (operationToken != null) {
+            mOperationToken = null;
+            mKeyStore.abort(operationToken);
+        }
+        mOperationHandle = null;
+        mChunkedStreamer = null;
+    }
+
+    @Override
+    protected void engineReset() {
+        resetWhilePreservingInitState();
+    }
+
+    private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
         if (mChunkedStreamer != null) {
             return;
         }
-        if (mKeyAliasInKeyStore == null) {
+        if (mKey == null) {
             throw new IllegalStateException("Not initialized");
         }
 
@@ -132,7 +159,8 @@
         keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
         keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
 
-        OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
+        OperationResult opResult = mKeyStore.begin(
+                mKey.getAlias(),
                 KeymasterDefs.KM_PURPOSE_SIGN,
                 true,
                 keymasterArgs,
@@ -141,10 +169,10 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getCryptoOperationException(opResult.resultCode);
+            throw KeyStore.getInvalidKeyException(opResult.resultCode);
         }
         if (opResult.token == null) {
-            throw new CryptoOperationException("Keystore returned null operation token");
+            throw new IllegalStateException("Keystore returned null operation token");
         }
         mOperationToken = opResult.token;
         mOperationHandle = opResult.operationHandle;
@@ -160,31 +188,39 @@
 
     @Override
     protected void engineUpdate(byte[] input, int offset, int len) {
-        ensureKeystoreOperationInitialized();
+        try {
+            ensureKeystoreOperationInitialized();
+        } catch (InvalidKeyException e) {
+            throw new IllegalStateException("Failed to reinitialize MAC", e);
+        }
 
         byte[] output;
         try {
             output = mChunkedStreamer.update(input, offset, len);
         } catch (KeyStoreException e) {
-            throw KeyStore.getCryptoOperationException(e);
+            throw new IllegalStateException("Keystore operation failed", e);
         }
         if ((output != null) && (output.length != 0)) {
-            throw new CryptoOperationException("Update operation unexpectedly produced output");
+            throw new IllegalStateException("Update operation unexpectedly produced output");
         }
     }
 
     @Override
     protected byte[] engineDoFinal() {
-        ensureKeystoreOperationInitialized();
+        try {
+            ensureKeystoreOperationInitialized();
+        } catch (InvalidKeyException e) {
+            throw new IllegalStateException("Failed to reinitialize MAC", e);
+        }
 
         byte[] result;
         try {
             result = mChunkedStreamer.doFinal(null, 0, 0);
         } catch (KeyStoreException e) {
-            throw KeyStore.getCryptoOperationException(e);
+            throw new IllegalStateException("Keystore operation failed", e);
         }
 
-        engineReset();
+        resetWhilePreservingInitState();
         return result;
     }
 
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index 87e7ee6..dde3b8f 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -200,7 +200,8 @@
         int errorCode = mKeyStore.generateKey(
                 keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
         if (errorCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getCryptoOperationException(errorCode);
+            throw new IllegalStateException(
+                    "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
         }
         String keyAlgorithmJCA =
                 KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
index d8ad1d3..1077af4 100644
--- a/keystore/java/android/security/KeyStoreKeyProperties.java
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -226,14 +226,24 @@
         public static final int IMPORTED = 1 << 1;
 
         /**
+         * Origin of the key is unknown. This can occur only for keys backed by an old TEE
+         * implementation which does not record origin information.
+         *
+         * @hide
+         */
+        public static final int UNKNOWN = 1 << 2;
+
+        /**
          * @hide
          */
         public static @OriginEnum int fromKeymaster(int origin) {
             switch (origin) {
-                case KeymasterDefs.KM_ORIGIN_HARDWARE:
+                case KeymasterDefs.KM_ORIGIN_GENERATED:
                     return GENERATED;
                 case KeymasterDefs.KM_ORIGIN_IMPORTED:
                     return IMPORTED;
+                case KeymasterDefs.KM_ORIGIN_UNKNOWN:
+                    return UNKNOWN;
                 default:
                     throw new IllegalArgumentException("Unknown origin: " + origin);
             }
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
index e6342ef..d0410b8 100644
--- a/keystore/java/android/security/UserNotAuthenticatedException.java
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -16,13 +16,15 @@
 
 package android.security;
 
+import java.security.InvalidKeyException;
+
 /**
  * Indicates that a cryptographic operation could not be performed because the user has not been
  * authenticated recently enough.
  *
  * @hide
  */
-public class UserNotAuthenticatedException extends CryptoOperationException {
+public class UserNotAuthenticatedException extends InvalidKeyException {
 
     /**
      * Constructs a new {@code UserNotAuthenticatedException} without detail message and cause.
diff --git a/keystore/tests/src/android/security/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
index 7a88dee..a7046dd2 100644
--- a/keystore/tests/src/android/security/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyStoreTest.java
@@ -18,7 +18,7 @@
 
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
 
-import com.android.org.conscrypt.NativeCrypto;
+import com.android.org.conscrypt.NativeConstants;
 import com.android.org.conscrypt.OpenSSLEngine;
 
 import android.test.AndroidTestCase;
@@ -768,7 +768,7 @@
         assertAliases(new String[] {});
 
         assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
+                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
                 null));
 
         assertAliases(new String[] { TEST_ALIAS_1 });
@@ -797,7 +797,7 @@
         assertAliases(new String[] {});
 
         assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
+                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
                 null));
 
         assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1));
@@ -1963,7 +1963,7 @@
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
             assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
+                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
 
             Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
 
@@ -2019,7 +2019,7 @@
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
             assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
+                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
 
             X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
                     TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
@@ -2032,7 +2032,7 @@
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
             assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
+                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
 
             X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
                     TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
@@ -2064,7 +2064,7 @@
         {
             final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
             assertTrue(mAndroidKeyStore.generate(privateKeyAlias,
-                    android.security.KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024,
+                    android.security.KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024,
                     android.security.KeyStore.FLAG_NONE, null));
 
             X509Certificate cert =
@@ -2116,7 +2116,7 @@
         assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
 
         assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3,
-                KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
+                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
                 null));
 
         assertEquals("The keystore size should match expected", 3, mKeyStore.size());
@@ -2184,7 +2184,7 @@
     private void setupKey() throws Exception {
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
         assertTrue(mAndroidKeyStore
-                .generate(privateKeyAlias, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA, 1024,
+                .generate(privateKeyAlias, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024,
                         KeyStore.FLAG_ENCRYPTED, null));
 
         X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1,
diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
index bc8dd13..681a9ff 100644
--- a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
@@ -24,6 +24,11 @@
 import javax.security.auth.x500.X500Principal;
 
 public class KeyPairGeneratorSpecTest extends AndroidTestCase {
+    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1980
+    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
     private static final String TEST_ALIAS_1 = "test1";
 
     private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
@@ -105,46 +110,37 @@
         }
     }
 
-    public void testConstructor_NullSubjectDN_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when subjectDN is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullSubjectDN_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_SUBJECT, spec.getSubjectDN());
     }
 
-    public void testConstructor_NullSerial_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullSerial_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getSerialNumber());
     }
 
-    public void testConstructor_NullStartDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    null, NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullStartDate_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, null,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getStartDate());
     }
 
-    public void testConstructor_NullEndDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW, null, 0);
-            fail("Should throw IllegalArgumentException when keystoreAlias is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullEndDate_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, null, 0);
+        assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getEndDate());
     }
 
     public void testConstructor_EndBeforeStart_Failure() throws Exception {
         try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW_PLUS_10_YEARS, NOW, 0);
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
+                    SERIAL_1, NOW_PLUS_10_YEARS, NOW, 0);
             fail("Should throw IllegalArgumentException when end is before start");
         } catch (IllegalArgumentException success) {
         }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 1a5552a..916b1ba 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -32,7 +32,7 @@
 import android.test.AssertionFailedError;
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.MediumTest;
-import com.android.org.conscrypt.NativeCrypto;
+import com.android.org.conscrypt.NativeConstants;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Date;
@@ -365,7 +365,7 @@
 
     public void testGenerate_NotInitialized_Fail() throws Exception {
         assertFalse("Should fail when keystore is not initialized",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
     }
 
@@ -373,7 +373,7 @@
         mKeyStore.password(TEST_PASSWD);
         mKeyStore.lock();
         assertFalse("Should fail when keystore is locked",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
     }
 
@@ -381,7 +381,7 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
@@ -391,7 +391,7 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
         assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
@@ -401,7 +401,7 @@
         assertTrue(mKeyStore.password(TEST_PASSWD));
 
         assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID,
-                    NativeCrypto.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
+                    NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
@@ -447,7 +447,7 @@
     public void testSign_Success() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                     RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
@@ -458,7 +458,7 @@
     public void testVerify_Success() throws Exception {
         mKeyStore.password(TEST_PASSWD);
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                     RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
         final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
@@ -486,7 +486,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue("Should be able to grant key to other user",
@@ -520,7 +520,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue("Should be able to grant key to other user",
@@ -554,7 +554,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertFalse("Should not be able to revoke not existent grant",
@@ -566,7 +566,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue("Should be able to grant key to other user",
@@ -584,7 +584,7 @@
                 mKeyStore.password(TEST_PASSWD));
 
         assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                         RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue("Should be able to grant key to other user",
@@ -605,7 +605,7 @@
 
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                     RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
@@ -644,7 +644,7 @@
 
         assertFalse(mKeyStore.contains(TEST_KEYNAME));
 
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeCrypto.EVP_PKEY_RSA,
+        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
                     RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
 
         assertTrue(mKeyStore.contains(TEST_KEYNAME));
diff --git a/libs/androidfw/ObbFile.cpp b/libs/androidfw/ObbFile.cpp
index 195fa9a..95332a3 100644
--- a/libs/androidfw/ObbFile.cpp
+++ b/libs/androidfw/ObbFile.cpp
@@ -337,7 +337,9 @@
         return false;
     }
 
-    ftruncate(fd, mFooterStart);
+    if (ftruncate(fd, mFooterStart) == -1) {
+        return false;
+    }
 
     return true;
 }
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7241069..fbe08ec 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -17,6 +17,16 @@
 #define LOG_TAG "ResourceType"
 //#define LOG_NDEBUG 0
 
+#include <ctype.h>
+#include <memory.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <limits>
+#include <type_traits>
+
 #include <androidfw/ByteBucketArray.h>
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/TypeWrappers.h>
@@ -27,17 +37,10 @@
 #include <utils/String16.h>
 #include <utils/String8.h>
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 #include <binder/TextOutput.h>
 #endif
 
-#include <stdlib.h>
-#include <string.h>
-#include <memory.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <stddef.h>
-
 #ifndef INT32_MAX
 #define INT32_MAX ((int32_t)(2147483647))
 #endif
@@ -4551,8 +4554,7 @@
     return false;
 }
 
-
-bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue)
 {
     while (len > 0 && isspace16(*s)) {
         s++;
@@ -4564,7 +4566,7 @@
     }
 
     size_t i = 0;
-    int32_t val = 0;
+    int64_t val = 0;
     bool neg = false;
 
     if (*s == '-') {
@@ -4576,28 +4578,50 @@
         return false;
     }
 
+    static_assert(std::is_same<uint32_t, Res_value::data_type>::value,
+                  "Res_value::data_type has changed. The range checks in this "
+                  "function are no longer correct.");
+
     // Decimal or hex?
-    if (s[i] == '0' && s[i+1] == 'x') {
-        if (outValue)
-            outValue->dataType = outValue->TYPE_INT_HEX;
+    bool isHex;
+    if (len > 1 && s[i] == '0' && s[i+1] == 'x') {
+        isHex = true;
         i += 2;
+
+        if (neg) {
+            return false;
+        }
+
+        if (i == len) {
+            // Just u"0x"
+            return false;
+        }
+
         bool error = false;
         while (i < len && !error) {
             val = (val*16) + get_hex(s[i], &error);
             i++;
+
+            if (val > std::numeric_limits<uint32_t>::max()) {
+                return false;
+            }
         }
         if (error) {
             return false;
         }
     } else {
-        if (outValue)
-            outValue->dataType = outValue->TYPE_INT_DEC;
+        isHex = false;
         while (i < len) {
             if (s[i] < '0' || s[i] > '9') {
                 return false;
             }
             val = (val*10) + s[i]-'0';
             i++;
+
+            if ((neg && -val < std::numeric_limits<int32_t>::min()) ||
+                (!neg && val > std::numeric_limits<int32_t>::max())) {
+                return false;
+            }
         }
     }
 
@@ -4607,13 +4631,21 @@
         i++;
     }
 
-    if (i == len) {
-        if (outValue)
-            outValue->data = val;
-        return true;
+    if (i != len) {
+        return false;
     }
 
-    return false;
+    if (outValue) {
+        outValue->dataType =
+            isHex ? outValue->TYPE_INT_HEX : outValue->TYPE_INT_DEC;
+        outValue->data = static_cast<Res_value::data_type>(val);
+    }
+    return true;
+}
+
+bool ResTable::stringToInt(const char16_t* s, size_t len, Res_value* outValue)
+{
+    return U16StringToInt(s, len, outValue);
 }
 
 bool ResTable::stringToFloat(const char16_t* s, size_t len, Res_value* outValue)
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index 58b78b5..a353575 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -19,6 +19,7 @@
 # targets here.
 # ==========================================================
 LOCAL_PATH:= $(call my-dir)
+
 testFiles := \
     AttributeFinder_test.cpp \
     ByteBucketArray_test.cpp \
@@ -32,27 +33,33 @@
     TypeWrappers_test.cpp \
     ZipUtils_test.cpp
 
+androidfw_test_cflags := \
+    -Wall \
+    -Werror \
+    -Wunused \
+    -Wunreachable-code \
+    -Wno-missing-field-initializers \
+
+# gtest is broken.
+androidfw_test_cflags += -Wno-unnamed-type-template-args
+
 # ==========================================================
 # Build the host tests: libandroidfw_tests
 # ==========================================================
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libandroidfw_tests
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-# gtest is broken.
-LOCAL_CFLAGS += -Wno-unnamed-type-template-args
-
+LOCAL_CFLAGS := $(androidfw_test_cflags)
 LOCAL_SRC_FILES := $(testFiles)
 LOCAL_STATIC_LIBRARIES := \
     libandroidfw \
     libutils \
     libcutils \
-    liblog
+    liblog \
+    libz \
 
 include $(BUILD_HOST_NATIVE_TEST)
 
-
 # ==========================================================
 # Build the device tests: libandroidfw_tests
 # ==========================================================
@@ -60,14 +67,11 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libandroidfw_tests
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-# gtest is broken.
-LOCAL_CFLAGS += -Wno-unnamed-type-template-args
-
+LOCAL_CFLAGS := $(androidfw_test_cflags)
 LOCAL_SRC_FILES := $(testFiles) \
     BackupData_test.cpp \
-    ObbFile_test.cpp
+    ObbFile_test.cpp \
+
 LOCAL_SHARED_LIBRARIES := \
     libandroidfw \
     libcutils \
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 6a9314e..dcfe91e 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -16,6 +16,10 @@
 
 #include <androidfw/ResourceTypes.h>
 
+#include <codecvt>
+#include <locale>
+#include <string>
+
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include "TestHelpers.h"
@@ -201,4 +205,81 @@
     ASSERT_LT(table.getResource(base::R::integer::number1, &val, MAY_NOT_BE_BAG), 0);
 }
 
+void testU16StringToInt(const char16_t* str, uint32_t expectedValue,
+                        bool expectSuccess, bool expectHex) {
+    size_t len = std::char_traits<char16_t>::length(str);
+
+    // Gtest can't print UTF-16 strings, so we have to convert to UTF-8 :(
+    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+    std::string s = convert.to_bytes(std::u16string(str, len));
+
+    Res_value out = {};
+    ASSERT_EQ(expectSuccess, U16StringToInt(str, len, &out))
+        << "Failed with " << s;
+
+    if (!expectSuccess) {
+        ASSERT_EQ(out.TYPE_NULL, out.dataType) << "Failed with " << s;
+        return;
+    }
+
+    if (expectHex) {
+        ASSERT_EQ(out.TYPE_INT_HEX, out.dataType) << "Failed with " << s;
+    } else {
+        ASSERT_EQ(out.TYPE_INT_DEC, out.dataType) << "Failed with " << s;
+    }
+
+    ASSERT_EQ(expectedValue, out.data) << "Failed with " << s;
+}
+
+TEST(ResTableTest, U16StringToInt) {
+    testU16StringToInt(u"", 0U, false, false);
+    testU16StringToInt(u"    ", 0U, false, false);
+    testU16StringToInt(u"\t\n", 0U, false, false);
+
+    testU16StringToInt(u"abcd", 0U, false, false);
+    testU16StringToInt(u"10abcd", 0U, false, false);
+    testU16StringToInt(u"42 42", 0U, false, false);
+    testU16StringToInt(u"- 42", 0U, false, false);
+    testU16StringToInt(u"-", 0U, false, false);
+
+    testU16StringToInt(u"0x", 0U, false, true);
+    testU16StringToInt(u"0xnope", 0U, false, true);
+    testU16StringToInt(u"0X42", 0U, false, true);
+    testU16StringToInt(u"0x42 0x42", 0U, false, true);
+    testU16StringToInt(u"-0x0", 0U, false, true);
+    testU16StringToInt(u"-0x42", 0U, false, true);
+    testU16StringToInt(u"- 0x42", 0U, false, true);
+
+    // Note that u" 42" would pass. This preserves the old behavior, but it may
+    // not be desired.
+    testU16StringToInt(u"42 ", 0U, false, false);
+    testU16StringToInt(u"0x42 ", 0U, false, true);
+
+    // Decimal cases.
+    testU16StringToInt(u"0", 0U, true, false);
+    testU16StringToInt(u"-0", 0U, true, false);
+    testU16StringToInt(u"42", 42U, true, false);
+    testU16StringToInt(u" 42", 42U, true, false);
+    testU16StringToInt(u"-42", static_cast<uint32_t>(-42), true, false);
+    testU16StringToInt(u" -42", static_cast<uint32_t>(-42), true, false);
+    testU16StringToInt(u"042", 42U, true, false);
+    testU16StringToInt(u"-042", static_cast<uint32_t>(-42), true, false);
+
+    // Hex cases.
+    testU16StringToInt(u"0x0", 0x0, true, true);
+    testU16StringToInt(u"0x42", 0x42, true, true);
+    testU16StringToInt(u" 0x42", 0x42, true, true);
+
+    // Just before overflow cases:
+    testU16StringToInt(u"2147483647", INT_MAX, true, false);
+    testU16StringToInt(u"-2147483648", static_cast<uint32_t>(INT_MIN), true,
+                       false);
+    testU16StringToInt(u"0xffffffff", UINT_MAX, true, true);
+
+    // Overflow cases:
+    testU16StringToInt(u"2147483648", 0U, false, false);
+    testU16StringToInt(u"-2147483649", 0U, false, false);
+    testU16StringToInt(u"0x1ffffffff", 0U, false, true);
+}
+
 }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index ed6ce87..aced5b9 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -58,7 +58,8 @@
  */
 public class AudioManager {
 
-    private final Context mApplicationContext;
+    private Context mOriginalContext;
+    private Context mApplicationContext;
     private long mVolumeKeyUpTime;
     private final boolean mUseMasterVolume;
     private final boolean mUseVolumeKeySounds;
@@ -641,16 +642,35 @@
      * @hide
      */
     public AudioManager(Context context) {
-        mApplicationContext = context.getApplicationContext();
-        mUseMasterVolume = mApplicationContext.getResources().getBoolean(
+        setContext(context);
+        mUseMasterVolume = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_useMasterVolume);
-        mUseVolumeKeySounds = mApplicationContext.getResources().getBoolean(
+        mUseVolumeKeySounds = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_useVolumeKeySounds);
-        mUseFixedVolume = mApplicationContext.getResources().getBoolean(
+        mUseFixedVolume = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
         sAudioPortEventHandler.init();
     }
 
+    private Context getContext() {
+        if (mApplicationContext == null) {
+            setContext(mOriginalContext);
+        }
+        if (mApplicationContext != null) {
+            return mApplicationContext;
+        }
+        return mOriginalContext;
+    }
+
+    private void setContext(Context context) {
+        mApplicationContext = context.getApplicationContext();
+        if (mApplicationContext != null) {
+            mOriginalContext = null;
+        } else {
+            mOriginalContext = context;
+        }
+    }
+
     private static IAudioService getService()
     {
         if (sService != null) {
@@ -685,7 +705,7 @@
      *     or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
      */
     public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
         helper.sendMediaButtonEvent(keyEvent, false);
     }
 
@@ -746,7 +766,7 @@
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
                 if (event.getRepeatCount() == 0) {
-                    MediaSessionLegacyHelper.getHelper(mApplicationContext)
+                    MediaSessionLegacyHelper.getHelper(getContext())
                             .sendVolumeKeyEvent(event, false);
                 }
                 break;
@@ -779,7 +799,7 @@
                 mVolumeKeyUpTime = SystemClock.uptimeMillis();
                 break;
             case KeyEvent.KEYCODE_VOLUME_MUTE:
-                MediaSessionLegacyHelper.getHelper(mApplicationContext)
+                MediaSessionLegacyHelper.getHelper(getContext())
                         .sendVolumeKeyEvent(event, false);
                 break;
         }
@@ -826,10 +846,10 @@
         try {
             if (mUseMasterVolume) {
                 service.adjustMasterVolume(direction, flags,
-                        mApplicationContext.getOpPackageName());
+                        getContext().getOpPackageName());
             } else {
                 service.adjustStreamVolume(streamType, direction, flags,
-                        mApplicationContext.getOpPackageName());
+                        getContext().getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustStreamVolume", e);
@@ -860,10 +880,10 @@
         try {
             if (mUseMasterVolume) {
                 service.adjustMasterVolume(direction, flags,
-                        mApplicationContext.getOpPackageName());
+                        getContext().getOpPackageName());
             } else {
                 MediaSessionLegacyHelper helper =
-                        MediaSessionLegacyHelper.getHelper(mApplicationContext);
+                        MediaSessionLegacyHelper.getHelper(getContext());
                 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
             }
         } catch (RemoteException e) {
@@ -896,10 +916,10 @@
         try {
             if (mUseMasterVolume) {
                 service.adjustMasterVolume(direction, flags,
-                        mApplicationContext.getOpPackageName());
+                        getContext().getOpPackageName());
             } else {
                 MediaSessionLegacyHelper helper =
-                        MediaSessionLegacyHelper.getHelper(mApplicationContext);
+                        MediaSessionLegacyHelper.getHelper(getContext());
                 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
             }
         } catch (RemoteException e) {
@@ -919,7 +939,7 @@
     public void adjustMasterVolume(int steps, int flags) {
         IAudioService service = getService();
         try {
-            service.adjustMasterVolume(steps, flags, mApplicationContext.getOpPackageName());
+            service.adjustMasterVolume(steps, flags, getContext().getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in adjustMasterVolume", e);
         }
@@ -1060,7 +1080,7 @@
         }
         IAudioService service = getService();
         try {
-            service.setRingerModeExternal(ringerMode, mApplicationContext.getOpPackageName());
+            service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setRingerMode", e);
         }
@@ -1082,10 +1102,10 @@
         IAudioService service = getService();
         try {
             if (mUseMasterVolume) {
-                service.setMasterVolume(index, flags, mApplicationContext.getOpPackageName());
+                service.setMasterVolume(index, flags, getContext().getOpPackageName());
             } else {
                 service.setStreamVolume(streamType, index, flags,
-                        mApplicationContext.getOpPackageName());
+                        getContext().getOpPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setStreamVolume", e);
@@ -1151,7 +1171,7 @@
     public void setMasterVolume(int index, int flags) {
         IAudioService service = getService();
         try {
-            service.setMasterVolume(index, flags, mApplicationContext.getOpPackageName());
+            service.setMasterVolume(index, flags, getContext().getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMasterVolume", e);
         }
@@ -1252,7 +1272,7 @@
     public void setMasterMute(boolean state, int flags) {
         IAudioService service = getService();
         try {
-            service.setMasterMute(state, flags, mApplicationContext.getOpPackageName(), mICallBack);
+            service.setMasterMute(state, flags, getContext().getOpPackageName(), mICallBack);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMasterMute", e);
         }
@@ -1490,7 +1510,7 @@
      * @see #startBluetoothSco()
     */
     public boolean isBluetoothScoAvailableOffCall() {
-        return mApplicationContext.getResources().getBoolean(
+        return getContext().getResources().getBoolean(
                com.android.internal.R.bool.config_bluetooth_sco_off_call);
     }
 
@@ -1543,7 +1563,7 @@
         IAudioService service = getService();
         try {
             service.startBluetoothSco(mICallBack,
-                    mApplicationContext.getApplicationInfo().targetSdkVersion);
+                    getContext().getApplicationInfo().targetSdkVersion);
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in startBluetoothSco", e);
         }
@@ -1691,7 +1711,7 @@
     public void setMicrophoneMute(boolean on){
         IAudioService service = getService();
         try {
-            service.setMicrophoneMute(on, mApplicationContext.getOpPackageName());
+            service.setMicrophoneMute(on, getContext().getOpPackageName());
         } catch (RemoteException e) {
             Log.e(TAG, "Dead object in setMicrophoneMute", e);
         }
@@ -2122,7 +2142,7 @@
      * Settings has an in memory cache, so this is fast.
      */
     private boolean querySoundEffectsEnabled(int user) {
-        return Settings.System.getIntForUser(mApplicationContext.getContentResolver(),
+        return Settings.System.getIntForUser(getContext().getContentResolver(),
                 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
     }
 
@@ -2534,7 +2554,7 @@
         try {
             status = service.requestAudioFocus(requestAttributes, durationHint, mICallBack,
                     mAudioFocusDispatcher, getIdForAudioFocusListener(l),
-                    mApplicationContext.getOpPackageName() /* package name */, flags,
+                    getContext().getOpPackageName() /* package name */, flags,
                     ap != null ? ap.cb() : null);
         } catch (RemoteException e) {
             Log.e(TAG, "Can't call requestAudioFocus() on AudioService:", e);
@@ -2559,7 +2579,7 @@
                         .setInternalLegacyStreamType(streamType).build(),
                     durationHint, mICallBack, null,
                     MediaFocusControl.IN_VOICE_COMM_FOCUS_ID,
-                    mApplicationContext.getOpPackageName(),
+                    getContext().getOpPackageName(),
                     AUDIOFOCUS_FLAG_LOCK,
                     null /* policy token */);
         } catch (RemoteException e) {
@@ -2628,7 +2648,7 @@
         if (eventReceiver == null) {
             return;
         }
-        if (!eventReceiver.getPackageName().equals(mApplicationContext.getPackageName())) {
+        if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
             Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
                     "receiver and context package names don't match");
             return;
@@ -2637,7 +2657,7 @@
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         //     the associated intent will be handled by the component being registered
         mediaButtonIntent.setComponent(eventReceiver);
-        PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
+        PendingIntent pi = PendingIntent.getBroadcast(getContext(),
                 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
         registerMediaButtonIntent(pi, eventReceiver);
     }
@@ -2671,8 +2691,8 @@
             Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
             return;
         }
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
-        helper.addMediaButtonListener(pi, eventReceiver, mApplicationContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
+        helper.addMediaButtonListener(pi, eventReceiver, getContext());
     }
 
     /**
@@ -2690,7 +2710,7 @@
         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
         //     the associated intent will be handled by the component being registered
         mediaButtonIntent.setComponent(eventReceiver);
-        PendingIntent pi = PendingIntent.getBroadcast(mApplicationContext,
+        PendingIntent pi = PendingIntent.getBroadcast(getContext(),
                 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
         unregisterMediaButtonIntent(pi);
     }
@@ -2713,7 +2733,7 @@
      * @hide
      */
     public void unregisterMediaButtonIntent(PendingIntent pi) {
-        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mApplicationContext);
+        MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
         helper.removeMediaButtonListener(pi);
     }
 
@@ -2730,7 +2750,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
+        rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
     }
 
     /**
@@ -2745,7 +2765,7 @@
         if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
             return;
         }
-        rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mApplicationContext));
+        rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
     }
 
     /**
@@ -3406,7 +3426,7 @@
      */
     public void setRingerModeInternal(int ringerMode) {
         try {
-            getService().setRingerModeInternal(ringerMode, mApplicationContext.getOpPackageName());
+            getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
         } catch (RemoteException e) {
             Log.w(TAG, "Error calling setRingerModeInternal", e);
         }
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index b2886bb..541d871 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -32,6 +32,7 @@
 import java.net.MalformedURLException;
 import java.net.NoRouteToHostException;
 import java.net.ProtocolException;
+import java.net.UnknownServiceException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -337,7 +338,10 @@
         } catch (NoRouteToHostException e) {
             Log.w(TAG, "readAt " + offset + " / " + size + " => " + e);
             return MEDIA_ERROR_UNSUPPORTED;
-        } catch (IOException e) {
+        } catch (UnknownServiceException e) {
+            Log.w(TAG, "readAt " + offset + " / " + size + " => " + e);
+            return MEDIA_ERROR_UNSUPPORTED;
+        }catch (IOException e) {
             if (VERBOSE) {
                 Log.d(TAG, "readAt " + offset + " / " + size + " => -1");
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 69a4ac0..af5025b 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -4120,8 +4120,9 @@
     /** {@inheritDoc} */
     @Override
     public int finishPostLayoutPolicyLw() {
-        if (mWinShowWhenLocked != null &&
-                mWinShowWhenLocked != mTopFullscreenOpaqueWindowState) {
+        if (mWinShowWhenLocked != null && mTopFullscreenOpaqueWindowState != null &&
+                mWinShowWhenLocked.getAppToken() != mTopFullscreenOpaqueWindowState.getAppToken()
+                && isKeyguardLocked()) {
             // A dialog is dismissing the keyguard. Put the wallpaper behind it and hide the
             // fullscreen window.
             // TODO: Make sure FLAG_SHOW_WALLPAPER is restored when dialog is dismissed. Or not.
diff --git a/preloaded-classes b/preloaded-classes
index 151766f..7a41bb2 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -828,6 +828,11 @@
 android.hardware.usb.UsbDevice
 android.hardware.usb.UsbDeviceConnection
 android.hardware.usb.UsbRequest
+# Initializing android.icu.impl.ICUBinary loads the ICU data.
+# Opening the files in the Zygote avoids StrictMode violations.
+# It also ensures the ICU data files are mapped on boot and all
+# apps will be consistent (even if files are added to /data).
+android.icu.impl.ICUBinary
 android.inputmethodservice.ExtractEditText
 android.location.Location
 android.location.Location$1
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 28547cc..4fa2c81 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -276,7 +276,7 @@
      * @hide
      * Enable/Disable AutoPadding for Vec3 elements.
      *
-     * @param useAutoPadding True: enable AutoPadding; flase: disable AutoPadding
+     * @param useAutoPadding True: enable AutoPadding; False: disable AutoPadding
      *
      */
     public void setAutoPadding(boolean useAutoPadding) {
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 126b8c7..6b1939c 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -332,10 +332,12 @@
       rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
     }
 
-    native long rsnScriptGroup2Create(long con, String cachePath, long[] closures);
-    synchronized long nScriptGroup2Create(String cachePath, long[] closures) {
+    native long rsnScriptGroup2Create(long con, String name, String cachePath,
+                                      long[] closures);
+    synchronized long nScriptGroup2Create(String name, String cachePath,
+                                          long[] closures) {
       validate();
-      return rsnScriptGroup2Create(mContext, cachePath, closures);
+      return rsnScriptGroup2Create(mContext, name, cachePath, closures);
     }
 
     native void rsnScriptGroup2Execute(long con, long groupID);
@@ -949,6 +951,17 @@
         rsnScriptIntrinsicBLAS_Z(mContext, id, func, TransA, TransB, Side, Uplo, Diag, M, N, K, alphaX, alphaY, A, B, betaX, betaY, C, incX, incY, KL, KU);
     }
 
+    native void rsnScriptIntrinsicBLAS_BNNM(long con, long id, int M, int N, int K,
+                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
+                                             int c_mult_int);
+    synchronized void nScriptIntrinsicBLAS_BNNM(long id, int M, int N, int K,
+                                             long A, int a_offset, long B, int b_offset, long C, int c_offset,
+                                             int c_mult_int) {
+        validate();
+        rsnScriptIntrinsicBLAS_BNNM(mContext, id, M, N, K, A, a_offset, B, b_offset, C, c_offset, c_mult_int);
+    }
+
+
 
     long     mDev;
     long     mContext;
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 65056ac..dda468a 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -66,7 +66,6 @@
     }
 
     /**
-     * @hide Pending API review
      * InvokeID is an identifier for an invoke function. It is used
      * as an identifier for ScriptGroup creation.
      *
@@ -86,7 +85,6 @@
 
     private final SparseArray<InvokeID> mIIDs = new SparseArray<InvokeID>();
     /**
-     * @hide Pending API review
      * Only to be used by generated reflected classes.
      */
     protected InvokeID createInvokeID(int slot) {
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 51c838f..be8b0fd 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -16,32 +16,30 @@
 
 package android.renderscript;
 
+import android.util.Log;
+import android.util.Pair;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 /**
- * ScriptGroup creates a group of kernels that are executed
- * together with one execution call as if they were a single kernel.
- * The kernels may be connected internally or to an external allocation.
- * The intermediate results for internal connections are not observable
- * after the execution of the script.
+ * A group of kernels that are executed
+ * together with one execution call as if they were a single kernel
  * <p>
- * External connections are grouped into inputs and outputs.
- * All outputs are produced by a script kernel and placed into a
- * user-supplied allocation. Inputs provide the input of a kernel.
- * Inputs bound to script globals are set directly upon the script.
+ * In addition to kernels, a script group may contain invocable functions as well.
+ * A script group may take inputs and generate outputs, which are consumed and
+ * produced by its member kernels.
+ * Inside a script group, outputs from one kernel can be passed to another kernel as inputs.
+ * The API disallows cyclic dependencies among kernels in a script group,
+ * effectively making it a directed acyclic graph (DAG) of kernels.
  * <p>
- * A ScriptGroup must contain at least one kernel. A ScriptGroup
- * must contain only a single directed acyclic graph (DAG) of
- * script kernels and connections. Attempting to create a
- * ScriptGroup with multiple DAGs or attempting to create
- * a cycle within a ScriptGroup will throw an exception.
- * <p>
- * Currently, all kernels in a ScriptGroup must be from separate
- * Script objects. Attempting to use multiple kernels from the same
- * Script object will result in an {@link android.renderscript.RSInvalidStateException}.
- *
+ * Grouping kernels together allows for more efficient execution. For example,
+ * runtime and compiler optimization can be applied to reduce computation and
+ * communication overhead, and to make better use of the CPU and the GPU.
  **/
 public final class ScriptGroup extends BaseObj {
+    private static final String TAG = "ScriptGroup";
     IO mOutputs[];
     IO mInputs[];
 
@@ -88,15 +86,364 @@
     }
 
 
+    /**
+     * An opaque class for closures
+     * <p>
+     * A closure represents a function call to a kernel or invocable function,
+     * combined with arguments and values for global variables. A closure is
+     * created using the {@link android.renderscript.ScriptGroup.Builder2#addKernel} or
+     * {@link android.renderscript.ScriptGroup.Builder2#addInvoke}
+     * method.
+     */
+
+    public static final class Closure extends BaseObj {
+        private Object[] mArgs;
+        private Allocation mReturnValue;
+        private Map<Script.FieldID, Object> mBindings;
+
+        private Future mReturnFuture;
+        private Map<Script.FieldID, Future> mGlobalFuture;
+
+        private FieldPacker mFP;
+
+        private static final String TAG = "Closure";
+
+        Closure(long id, RenderScript rs) {
+            super(id, rs);
+        }
+
+        Closure(RenderScript rs, Script.KernelID kernelID, Type returnType,
+                       Object[] args, Map<Script.FieldID, Object> globals) {
+            super(0, rs);
+
+            mArgs = args;
+            mReturnValue = Allocation.createTyped(rs, returnType);
+            mBindings = globals;
+            mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+            int numValues = args.length + globals.size();
+
+            long[] fieldIDs = new long[numValues];
+            long[] values = new long[numValues];
+            int[] sizes = new int[numValues];
+            long[] depClosures = new long[numValues];
+            long[] depFieldIDs = new long[numValues];
+
+            int i;
+            for (i = 0; i < args.length; i++) {
+                Object obj = args[i];
+                fieldIDs[i] = 0;
+                if (obj instanceof Input) {
+                    Input unbound = (Input)obj;
+                    unbound.addReference(this, i);
+                } else {
+                    retrieveValueAndDependenceInfo(rs, i, args[i], values, sizes,
+                                                   depClosures, depFieldIDs);
+                }
+            }
+
+            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+                Object obj = entry.getValue();
+                Script.FieldID fieldID = entry.getKey();
+                fieldIDs[i] = fieldID.getID(rs);
+                if (obj instanceof Input) {
+                    Input unbound = (Input)obj;
+                    unbound.addReference(this, fieldID);
+                } else {
+                    retrieveValueAndDependenceInfo(rs, i, obj, values,
+                                                   sizes, depClosures, depFieldIDs);
+                }
+                i++;
+            }
+
+            long id = rs.nClosureCreate(kernelID.getID(rs), mReturnValue.getID(rs),
+                                        fieldIDs, values, sizes, depClosures, depFieldIDs);
+
+            setID(id);
+        }
+
+        Closure(RenderScript rs, Script.InvokeID invokeID,
+                       Object[] args, Map<Script.FieldID, Object> globals) {
+            super(0, rs);
+            mFP = FieldPacker.createFromArray(args);
+
+            mArgs = args;
+            mBindings = globals;
+            mGlobalFuture = new HashMap<Script.FieldID, Future>();
+
+            int numValues = globals.size();
+
+            long[] fieldIDs = new long[numValues];
+            long[] values = new long[numValues];
+            int[] sizes = new int[numValues];
+            long[] depClosures = new long[numValues];
+            long[] depFieldIDs = new long[numValues];
+
+            int i = 0;
+            for (Map.Entry<Script.FieldID, Object> entry : globals.entrySet()) {
+                Object obj = entry.getValue();
+                Script.FieldID fieldID = entry.getKey();
+                fieldIDs[i] = fieldID.getID(rs);
+                if (obj instanceof Input) {
+                    Input unbound = (Input)obj;
+                    unbound.addReference(this, fieldID);
+                } else {
+                    retrieveValueAndDependenceInfo(rs, i, obj, values,
+                                                   sizes, depClosures, depFieldIDs);
+                }
+                i++;
+            }
+
+            long id = rs.nInvokeClosureCreate(invokeID.getID(rs), mFP.getData(), fieldIDs,
+                                              values, sizes);
+
+            setID(id);
+        }
+
+        private static
+                void retrieveValueAndDependenceInfo(RenderScript rs,
+                                                    int index, Object obj,
+                                                    long[] values, int[] sizes,
+                                                    long[] depClosures,
+                                                    long[] depFieldIDs) {
+
+            if (obj instanceof Future) {
+                Future f = (Future)obj;
+                obj = f.getValue();
+                depClosures[index] = f.getClosure().getID(rs);
+                Script.FieldID fieldID = f.getFieldID();
+                depFieldIDs[index] = fieldID != null ? fieldID.getID(rs) : 0;
+                if (obj == null) {
+                    // Value is originally created by the owner closure
+                    values[index] = 0;
+                    sizes[index] = 0;
+                    return;
+                }
+            } else {
+                depClosures[index] = 0;
+                depFieldIDs[index] = 0;
+            }
+
+            ValueAndSize vs = new ValueAndSize(rs, obj);
+            values[index] = vs.value;
+            sizes[index] = vs.size;
+        }
+
+        /**
+         * Returns the future for the return value
+         *
+         * @return a future
+         */
+
+        public Future getReturn() {
+            if (mReturnFuture == null) {
+                mReturnFuture = new Future(this, null, mReturnValue);
+            }
+
+            return mReturnFuture;
+        }
+
+        /**
+         * Returns the future for a global variable
+         *
+         * @param field the field ID for the global variable
+         * @return a future
+         */
+
+        public Future getGlobal(Script.FieldID field) {
+            Future f = mGlobalFuture.get(field);
+
+            if (f == null) {
+                // If the field is not bound to this closure, this will return a future
+                // without an associated value (reference). So this is not working for
+                // cross-module (cross-script) linking in this case where a field not
+                // explicitly bound.
+                f = new Future(this, field, mBindings.get(field));
+                mGlobalFuture.put(field, f);
+            }
+
+            return f;
+        }
+
+        void setArg(int index, Object obj) {
+            mArgs[index] = obj;
+            ValueAndSize vs = new ValueAndSize(mRS, obj);
+            mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
+        }
+
+        void setGlobal(Script.FieldID fieldID, Object obj) {
+            mBindings.put(fieldID, obj);
+            ValueAndSize vs = new ValueAndSize(mRS, obj);
+            mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
+        }
+
+        private static final class ValueAndSize {
+            public ValueAndSize(RenderScript rs, Object obj) {
+                if (obj instanceof Allocation) {
+                    value = ((Allocation)obj).getID(rs);
+                    size = -1;
+                } else if (obj instanceof Boolean) {
+                    value = ((Boolean)obj).booleanValue() ? 1 : 0;
+                    size = 4;
+                } else if (obj instanceof Integer) {
+                    value = ((Integer)obj).longValue();
+                    size = 4;
+                } else if (obj instanceof Long) {
+                    value = ((Long)obj).longValue();
+                    size = 8;
+                } else if (obj instanceof Float) {
+                    value = ((Float)obj).longValue();
+                    size = 4;
+                } else if (obj instanceof Double) {
+                    value = ((Double)obj).longValue();
+                    size = 8;
+                }
+            }
+            public long value;
+            public int size;
+        }
+    }
+
+    /**
+     * An opaque class for futures
+     * <p>
+     * A future represents an output of a closure, either the return value of
+     * the function, or the value of a global variable written by the function.
+     * A future is created by calling the {@link Closure#getReturn}  or
+     * {@link Closure#getGlobal} method.
+     */
+
+    public static final class Future {
+        Closure mClosure;
+        Script.FieldID mFieldID;
+        Object mValue;
+
+        Future(Closure closure, Script.FieldID fieldID, Object value) {
+            mClosure = closure;
+            mFieldID = fieldID;
+            mValue = value;
+        }
+
+        Closure getClosure() { return mClosure; }
+        Script.FieldID getFieldID() { return mFieldID; }
+        Object getValue() { return mValue; }
+    }
+
+    /**
+     * An opaque class for script group inputs
+     * <p>
+     * Created by calling the {@link Builder2#addInput} method. The value
+     * is assigned in {@link ScriptGroup#execute(Object...)} method as
+     * one of its arguments. Arguments to the execute method should be in
+     * the same order as intputs are added using the addInput method.
+     */
+
+    public static final class Input {
+        // Either mFieldID or mArgIndex should be set but not both.
+        List<Pair<Closure, Script.FieldID>> mFieldID;
+        // -1 means unset. Legal values are 0 .. n-1, where n is the number of
+        // arguments for the referencing closure.
+        List<Pair<Closure, Integer>> mArgIndex;
+
+        Input() {
+            mFieldID = new ArrayList<Pair<Closure, Script.FieldID>>();
+            mArgIndex = new ArrayList<Pair<Closure, Integer>>();
+        }
+
+        void addReference(Closure closure, int index) {
+            mArgIndex.add(Pair.create(closure, Integer.valueOf(index)));
+        }
+
+        void addReference(Closure closure, Script.FieldID fieldID) {
+            mFieldID.add(Pair.create(closure, fieldID));
+        }
+
+        void set(Object value) {
+            for (Pair<Closure, Integer> p : mArgIndex) {
+                Closure closure = p.first;
+                int index = p.second.intValue();
+                closure.setArg(index, value);
+            }
+            for (Pair<Closure, Script.FieldID> p : mFieldID) {
+                Closure closure = p.first;
+                Script.FieldID fieldID = p.second;
+                closure.setGlobal(fieldID, value);
+            }
+        }
+    }
+
+    private String mName;
+    private List<Closure> mClosures;
+    private List<Input> mInputs2;
+    private Future[] mOutputs2;
+
     ScriptGroup(long id, RenderScript rs) {
         super(id, rs);
     }
 
+    ScriptGroup(RenderScript rs, String name, List<Closure> closures,
+                 List<Input> inputs, Future[] outputs) {
+        super(0, rs);
+        mName = name;
+        mClosures = closures;
+        mInputs2 = inputs;
+        mOutputs2 = outputs;
+
+        long[] closureIDs = new long[closures.size()];
+        for (int i = 0; i < closureIDs.length; i++) {
+            closureIDs[i] = closures.get(i).getID(rs);
+        }
+        long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
+        setID(id);
+    }
+
+    /**
+     * Executes a script group
+     *
+     * @param inputs inputs to the script group
+     * @return outputs of the script group as an array of objects
+     */
+
+    public Object[] execute(Object... inputs) {
+        if (inputs.length < mInputs2.size()) {
+            Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+                  "less than expected " + mInputs2.size());
+            return null;
+        }
+
+        if (inputs.length > mInputs2.size()) {
+            Log.i(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
+                  "more than expected " + mInputs2.size());
+        }
+
+        for (int i = 0; i < mInputs2.size(); i++) {
+            Object obj = inputs[i];
+            if (obj instanceof Future || obj instanceof Input) {
+                Log.e(TAG, this.toString() + ": input " + i +
+                      " is a future or unbound value");
+                return null;
+            }
+            Input unbound = mInputs2.get(i);
+            unbound.set(obj);
+        }
+
+        mRS.nScriptGroup2Execute(getID(mRS));
+
+        Object[] outputObjs = new Object[mOutputs2.length];
+        int i = 0;
+        for (Future f : mOutputs2) {
+            outputObjs[i++] = f.getValue();
+        }
+        return outputObjs;
+    }
+
     /**
      * Sets an input of the ScriptGroup. This specifies an
      * Allocation to be used for kernels that require an input
      * Allocation provided from outside of the ScriptGroup.
      *
+     * @deprecated Set arguments to {@link #execute(Object...)} instead.
+     *
      * @param s The ID of the kernel where the allocation should be
      *          connected.
      * @param a The allocation to connect.
@@ -117,6 +464,8 @@
      * Allocation to be used for the kernels that require an output
      * Allocation visible after the ScriptGroup is executed.
      *
+     * @deprecated Use return value of {@link #execute(Object...)} instead.
+     *
      * @param s The ID of the kernel where the allocation should be
      *          connected.
      * @param a The allocation to connect.
@@ -136,6 +485,9 @@
      * Execute the ScriptGroup.  This will run all the kernels in
      * the ScriptGroup.  No internal connection results will be visible
      * after execution of the ScriptGroup.
+     *
+     * @deprecated Use {@link #execute} instead.
+     *
      */
     public void execute() {
         mRS.nScriptGroupExecute(getID(mRS));
@@ -164,6 +516,8 @@
      * Once all connections are made, a call to {@link #create} will
      * return the ScriptGroup object.
      *
+     * @deprecated Use {@link Builder2} instead.
+     *
      */
     public static final class Builder {
         private RenderScript mRS;
@@ -464,7 +818,210 @@
 
     }
 
+    /**
+     * Represents a binding of a value to a global variable in a
+     * kernel or invocable function. Used in closure creation.
+     */
+
+    public static final class Binding {
+        private final Script.FieldID mField;
+        private final Object mValue;
+
+        /**
+         * Returns a Binding object that binds value to field
+         *
+         * @param field the Script.FieldID of the global variable
+         * @param value the value
+         */
+
+        public Binding(Script.FieldID field, Object value) {
+            mField = field;
+            mValue = value;
+        }
+
+        /**
+         * Returns the field ID
+         */
+
+        public Script.FieldID getField() { return mField; }
+
+        /**
+         * Returns the value
+         */
+
+        public Object getValue() { return mValue; }
+    }
+
+    /**
+     * The builder class for creating script groups
+     * <p>
+     * A script group is created using closures (see class {@link Closure}).
+     * A closure is a function call to a kernel or
+     * invocable function. Each function argument or global variable accessed inside
+     * the function is bound to 1) a known value, 2) a script group input
+     * (see class {@link Input}), or 3) a
+     * future (see class {@link Future}).
+     * A future is the output of a closure, either the return value of the
+     * function or a global variable written by that function.
+     * <p>
+     * Closures are created using the {@link #addKernel} or {@link #addInvoke}
+     * methods.
+     * When a closure is created, futures from previously created closures
+     * can be used as its inputs.
+     * External script group inputs can be used as inputs to individual closures as well.
+     * An external script group input is created using the {@link #addInput} method.
+     * A script group is created by a call to the {@link #create} method, which
+     * accepts an array of futures as the outputs for the script group.
+     * <p>
+     * Closures in a script group can be evaluated in any order as long as the
+     * following conditions are met:
+     * 1) a closure must be evaluated before any other closures that take its
+     * futures as inputs;
+     * 2) all closures added before an invoke closure must be evaluated
+     * before it;
+     * and 3) all closures added after an invoke closure must be evaluated after
+     * it.
+     * As a special case, the order that the closures are added is a legal
+     * evaluation order. However, other evaluation orders are possible, including
+     * concurrently evaluating independent closures.
+     */
+
+    public static final class Builder2 {
+        RenderScript mRS;
+        List<Closure> mClosures;
+        List<Input> mInputs;
+        private static final String TAG = "ScriptGroup.Builder2";
+
+        /**
+         * Returns a Builder object
+         *
+         * @param rs the RenderScript context
+         */
+        public Builder2(RenderScript rs) {
+            mRS = rs;
+            mClosures = new ArrayList<Closure>();
+            mInputs = new ArrayList<Input>();
+        }
+
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param returnType Allocation type for the return value
+         * @param args arguments to the kernel function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
+        private Closure addKernelInternal(Script.KernelID k, Type returnType, Object[] args,
+                                          Map<Script.FieldID, Object> globalBindings) {
+            Closure c = new Closure(mRS, k, returnType, args, globalBindings);
+            mClosures.add(c);
+            return c;
+        }
+
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param args arguments to the invocable function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
+        private Closure addInvokeInternal(Script.InvokeID invoke, Object[] args,
+                                          Map<Script.FieldID, Object> globalBindings) {
+            Closure c = new Closure(mRS, invoke, args, globalBindings);
+            mClosures.add(c);
+            return c;
+        }
+
+        /**
+         * Adds a script group input
+         *
+         * @return a script group input, which can be used as an argument or a value to
+         *     a global variable for creating closures
+         */
+        public Input addInput() {
+            Input unbound = new Input();
+            mInputs.add(unbound);
+            return unbound;
+        }
+
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
+        public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
+            ArrayList<Object> args = new ArrayList<Object>();
+            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
+            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
+                return null;
+            }
+            return addKernelInternal(k, returnType, args.toArray(), bindingMap);
+        }
+
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
+        public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
+            ArrayList<Object> args = new ArrayList<Object>();
+            Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
+            if (!seperateArgsAndBindings(argsAndBindings, args, bindingMap)) {
+                return null;
+            }
+            return addInvokeInternal(invoke, args.toArray(), bindingMap);
+        }
+
+        /**
+         * Creates a script group
+         *
+         * @param name name for the script group. Legal names can only contain letters, digits,
+         *        '-', or '_'. The name can be no longer than 100 characters.
+         * @param outputs futures intended as outputs of the script group
+         * @return a script group
+         */
+
+        public ScriptGroup create(String name, Future... outputs) {
+            if (name == null || name.isEmpty() || name.length() > 100 ||
+                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
+                throw new RSIllegalArgumentException("invalid script group name");
+            }
+            ScriptGroup ret = new ScriptGroup(mRS, name, mClosures, mInputs, outputs);
+            return ret;
+        }
+
+        private boolean seperateArgsAndBindings(Object[] argsAndBindings,
+                                                ArrayList<Object> args,
+                                                Map<Script.FieldID, Object> bindingMap) {
+            int i;
+            for (i = 0; i < argsAndBindings.length; i++) {
+                if (argsAndBindings[i] instanceof Binding) {
+                    break;
+                }
+                args.add(argsAndBindings[i]);
+            }
+
+            for (; i < argsAndBindings.length; i++) {
+                if (!(argsAndBindings[i] instanceof Binding)) {
+                    return false;
+                }
+                Binding b = (Binding)argsAndBindings[i];
+                bindingMap.put(b.getField(), b.getValue());
+            }
+
+            return true;
+        }
+
+    }
 
 }
-
-
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index 857e9fb..417bbee 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -289,6 +289,7 @@
         }
     }
 
+    String mName;
     List<Closure> mClosures;
     List<UnboundValue> mInputs;
     Future[] mOutputs;
@@ -299,9 +300,10 @@
         super(id, rs);
     }
 
-    ScriptGroup2(RenderScript rs, List<Closure> closures,
+    ScriptGroup2(RenderScript rs, String name, List<Closure> closures,
                  List<UnboundValue> inputs, Future[] outputs) {
         super(0, rs);
+        mName = name;
         mClosures = closures;
         mInputs = inputs;
         mOutputs = outputs;
@@ -310,7 +312,7 @@
         for (int i = 0; i < closureIDs.length; i++) {
             closureIDs[i] = closures.get(i).getID(rs);
         }
-        long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs);
+        long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
         setID(id);
     }
 
@@ -412,8 +414,12 @@
             return addInvoke(invoke, args.toArray(), bindingMap);
         }
 
-        public ScriptGroup2 create(Future... outputs) {
-            ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
+        public ScriptGroup2 create(String name, Future... outputs) {
+            if (name == null || name.isEmpty() || name.length() > 100 ||
+                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
+                throw new RSIllegalArgumentException("invalid script group name");
+            }
+            ScriptGroup2 ret = new ScriptGroup2(mRS, name, mClosures, mInputs, outputs);
             return ret;
         }
 
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
index 90d2300..16b7033 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -176,6 +176,9 @@
     private static final int RsBlas_zherk = 141;
     private static final int RsBlas_zher2k = 142;
 
+    // BLAS extensions start here
+    private static final int RsBlas_bnnm = 1000;
+
     /**
      */
     public static ScriptIntrinsicBLAS create(RenderScript rs) {
@@ -1485,5 +1488,23 @@
     }
 
 
+    /**
+     *
+     * 8-bit GEMM-like operation for neural networks
+     *
+     * @hide
+     **/
+    public void BNNM(Allocation A, int a_offset, Allocation B, int b_offset, Allocation C, int c_offset, int c_mult) {
+        validateL3(Element.U8(mRS), NO_TRANSPOSE, TRANSPOSE, 0, A, B, C);
+
+        int M = -1, N = -1, K = -1;
+        M = A.getType().getY();
+        N = B.getType().getY();
+        K = A.getType().getX();
+
+
+        mRS.nScriptIntrinsicBLAS_BNNM(getID(mRS), M, N, K, A.getID(mRS), a_offset, B.getID(mRS), b_offset, C.getID(mRS), c_offset, c_mult);
+
+    }
 
 }
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 676d94f..6f6729b 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -423,8 +423,9 @@
 }
 
 static long
-nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
+nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
                     jstring cacheDir, jlongArray closureArray) {
+  AutoJavaStringToUTF8 nameUTF(_env, name);
   AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
 
   jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
@@ -435,7 +436,8 @@
   }
 
   return (jlong)(uintptr_t)rsScriptGroup2Create(
-      (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(),
+      (RsContext)con, nameUTF.c_str(), nameUTF.length(),
+      cacheDirUTF.c_str(), cacheDirUTF.length(),
       closures, numClosures);
 }
 
@@ -582,6 +584,32 @@
 
 
 static void
+nScriptIntrinsicBLAS_BNNM(JNIEnv *_env, jobject _this, jlong con, jlong id, jint M, jint N, jint K,
+                                             jlong A, jint a_offset, jlong B, jint b_offset, jlong C, jint c_offset,
+                                             jint c_mult_int) {
+    RsBlasCall call;
+    memset(&call, 0, sizeof(call));
+    call.func = RsBlas_bnnm;
+    call.M = M;
+    call.N = N;
+    call.K = K;
+    call.a_offset = a_offset;
+    call.b_offset = b_offset;
+    call.c_offset = c_offset;
+    call.c_mult_int = c_mult_int;
+
+    RsAllocation in_allocs[3];
+    in_allocs[0] = (RsAllocation)A;
+    in_allocs[1] = (RsAllocation)B;
+    in_allocs[2] = (RsAllocation)C;
+
+    rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
+                         in_allocs, sizeof(in_allocs), nullptr,
+                         &call, sizeof(call), nullptr, 0);
+}
+
+
+static void
 nAssignName(JNIEnv *_env, jobject _this, jlong con, jlong obj, jbyteArray str)
 {
     if (kLogApi) {
@@ -2414,7 +2442,7 @@
 {"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
 {"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create",            "(JLjava/lang/String;[J)J",               (void*)nScriptGroup2Create },
+{"rsnScriptGroup2Create",            "(JLjava/lang/String;Ljava/lang/String;[J)J", (void*)nScriptGroup2Create },
 {"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
@@ -2425,6 +2453,8 @@
 {"rsnScriptIntrinsicBLAS_Complex",   "(JJIIIIIIIIIFFJJFFJIIII)V",             (void*)nScriptIntrinsicBLAS_Complex },
 {"rsnScriptIntrinsicBLAS_Z",         "(JJIIIIIIIIIDDJJDDJIIII)V",             (void*)nScriptIntrinsicBLAS_Z },
 
+{"rsnScriptIntrinsicBLAS_BNNM",      "(JJIIIJIJIJII)V",                       (void*)nScriptIntrinsicBLAS_BNNM },
+
 {"rsnProgramStoreCreate",            "(JZZZZZZIII)J",                         (void*)nProgramStoreCreate },
 
 {"rsnProgramBindConstants",          "(JJIJ)V",                               (void*)nProgramBindConstants },
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 05a4d7e..95a0867 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1287,10 +1287,11 @@
 
     final ServiceThread mHandlerThread;
     final MainHandler mHandler;
+    final UiHandler mUiHandler;
 
-    final class MainHandler extends Handler {
-        public MainHandler(Looper looper) {
-            super(looper, null, true);
+    final class UiHandler extends Handler {
+        public UiHandler() {
+            super(com.android.server.UiThread.get().getLooper(), null, true);
         }
 
         @Override
@@ -1403,15 +1404,6 @@
                 d.show();
                 ensureBootCompleted();
             } break;
-            case UPDATE_CONFIGURATION_MSG: {
-                final ContentResolver resolver = mContext.getContentResolver();
-                Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
-            } break;
-            case GC_BACKGROUND_PROCESSES_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    performAppGcsIfAppropriateLocked();
-                }
-            } break;
             case WAIT_FOR_DEBUGGER_MSG: {
                 synchronized (ActivityManagerService.this) {
                     ProcessRecord app = (ProcessRecord)msg.obj;
@@ -1432,6 +1424,88 @@
                     }
                 }
             } break;
+            case SHOW_UID_ERROR_MSG: {
+                if (mShowDialogs) {
+                    AlertDialog d = new BaseErrorDialog(mContext);
+                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+                    d.setCancelable(false);
+                    d.setTitle(mContext.getText(R.string.android_system_label));
+                    d.setMessage(mContext.getText(R.string.system_error_wipe_data));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                            obtainMessage(DISMISS_DIALOG_MSG, d));
+                    d.show();
+                }
+            } break;
+            case SHOW_FINGERPRINT_ERROR_MSG: {
+                if (mShowDialogs) {
+                    AlertDialog d = new BaseErrorDialog(mContext);
+                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+                    d.setCancelable(false);
+                    d.setTitle(mContext.getText(R.string.android_system_label));
+                    d.setMessage(mContext.getText(R.string.system_error_manufacturer));
+                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
+                            obtainMessage(DISMISS_DIALOG_MSG, d));
+                    d.show();
+                }
+            } break;
+            case SHOW_COMPAT_MODE_DIALOG_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    ActivityRecord ar = (ActivityRecord) msg.obj;
+                    if (mCompatModeDialog != null) {
+                        if (mCompatModeDialog.mAppInfo.packageName.equals(
+                                ar.info.applicationInfo.packageName)) {
+                            return;
+                        }
+                        mCompatModeDialog.dismiss();
+                        mCompatModeDialog = null;
+                    }
+                    if (ar != null && false) {
+                        if (mCompatModePackages.getPackageAskCompatModeLocked(
+                                ar.packageName)) {
+                            int mode = mCompatModePackages.computeCompatModeLocked(
+                                    ar.info.applicationInfo);
+                            if (mode == ActivityManager.COMPAT_MODE_DISABLED
+                                    || mode == ActivityManager.COMPAT_MODE_ENABLED) {
+                                mCompatModeDialog = new CompatModeDialog(
+                                        ActivityManagerService.this, mContext,
+                                        ar.info.applicationInfo);
+                                mCompatModeDialog.show();
+                            }
+                        }
+                    }
+                }
+                break;
+            }
+            case START_USER_SWITCH_MSG: {
+                showUserSwitchDialog(msg.arg1, (String) msg.obj);
+                break;
+            }
+            case DISMISS_DIALOG_MSG: {
+                final Dialog d = (Dialog) msg.obj;
+                d.dismiss();
+                break;
+            }
+            }
+        }
+    }
+
+    final class MainHandler extends Handler {
+        public MainHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case UPDATE_CONFIGURATION_MSG: {
+                final ContentResolver resolver = mContext.getContentResolver();
+                Settings.System.putConfiguration(resolver, (Configuration) msg.obj);
+            } break;
+            case GC_BACKGROUND_PROCESSES_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    performAppGcsIfAppropriateLocked();
+                }
+            } break;
             case SERVICE_TIMEOUT_MSG: {
                 if (mDidDexOpt) {
                     mDidDexOpt = false;
@@ -1496,30 +1570,6 @@
                     }
                 }
             } break;
-            case SHOW_UID_ERROR_MSG: {
-                if (mShowDialogs) {
-                    AlertDialog d = new BaseErrorDialog(mContext);
-                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
-                    d.setCancelable(false);
-                    d.setTitle(mContext.getText(R.string.android_system_label));
-                    d.setMessage(mContext.getText(R.string.system_error_wipe_data));
-                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
-                            mHandler.obtainMessage(DISMISS_DIALOG_MSG, d));
-                    d.show();
-                }
-            } break;
-            case SHOW_FINGERPRINT_ERROR_MSG: {
-                if (mShowDialogs) {
-                    AlertDialog d = new BaseErrorDialog(mContext);
-                    d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
-                    d.setCancelable(false);
-                    d.setTitle(mContext.getText(R.string.android_system_label));
-                    d.setMessage(mContext.getText(R.string.system_error_manufacturer));
-                    d.setButton(DialogInterface.BUTTON_POSITIVE, mContext.getText(R.string.ok),
-                            mHandler.obtainMessage(DISMISS_DIALOG_MSG, d));
-                    d.show();
-                }
-            } break;
             case PROC_START_TIMEOUT_MSG: {
                 if (mDidDexOpt) {
                     mDidDexOpt = false;
@@ -1620,34 +1670,6 @@
                     sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
                 }
             } break;
-            case SHOW_COMPAT_MODE_DIALOG_MSG: {
-                synchronized (ActivityManagerService.this) {
-                    ActivityRecord ar = (ActivityRecord)msg.obj;
-                    if (mCompatModeDialog != null) {
-                        if (mCompatModeDialog.mAppInfo.packageName.equals(
-                                ar.info.applicationInfo.packageName)) {
-                            return;
-                        }
-                        mCompatModeDialog.dismiss();
-                        mCompatModeDialog = null;
-                    }
-                    if (ar != null && false) {
-                        if (mCompatModePackages.getPackageAskCompatModeLocked(
-                                ar.packageName)) {
-                            int mode = mCompatModePackages.computeCompatModeLocked(
-                                    ar.info.applicationInfo);
-                            if (mode == ActivityManager.COMPAT_MODE_DISABLED
-                                    || mode == ActivityManager.COMPAT_MODE_ENABLED) {
-                                mCompatModeDialog = new CompatModeDialog(
-                                        ActivityManagerService.this, mContext,
-                                        ar.info.applicationInfo);
-                                mCompatModeDialog.show();
-                            }
-                        }
-                    }
-                }
-                break;
-            }
             case DISPATCH_PROCESSES_CHANGED: {
                 dispatchProcessesChanged();
                 break;
@@ -1668,10 +1690,6 @@
                 thread.start();
                 break;
             }
-            case START_USER_SWITCH_MSG: {
-                showUserSwitchDialog(msg.arg1, (String) msg.obj);
-                break;
-            }
             case REPORT_USER_SWITCH_MSG: {
                 dispatchUserSwitch((UserStartedState) msg.obj, msg.arg1, msg.arg2);
                 break;
@@ -1779,11 +1797,6 @@
                 }
                 break;
             }
-            case DISMISS_DIALOG_MSG: {
-                final Dialog d = (Dialog) msg.obj;
-                d.dismiss();
-                break;
-            }
             case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
                 synchronized (ActivityManagerService.this) {
                     int i = mTaskStackListeners.beginBroadcast();
@@ -2078,6 +2091,7 @@
                 android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
         mHandlerThread.start();
         mHandler = new MainHandler(mHandlerThread.getLooper());
+        mUiHandler = new UiHandler();
 
         mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                 "foreground", BROADCAST_FG_TIMEOUT, false);
@@ -2443,7 +2457,7 @@
         Message msg = Message.obtain();
         msg.what = SHOW_COMPAT_MODE_DIALOG_MSG;
         msg.obj = r.task.askedCompatMode ? null : r;
-        mHandler.sendMessage(msg);
+        mUiHandler.sendMessage(msg);
     }
 
     private int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
@@ -3002,6 +3016,10 @@
                     debugFlags |= Zygote.DEBUG_ENABLE_JIT;
                 }
             }
+            String genCFIDebugProperty = SystemProperties.get("debug.gencfi");
+            if ("true".equals(genCFIDebugProperty)) {
+                debugFlags |= Zygote.DEBUG_GENERATE_CFI;
+            }
             if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
                 debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
             }
@@ -5100,20 +5118,20 @@
                 map.put("activity", activity);
             }
 
-            mHandler.sendMessage(msg);
+            mUiHandler.sendMessage(msg);
         }
     }
 
     final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
         if (!mLaunchWarningShown) {
             mLaunchWarningShown = true;
-            mHandler.post(new Runnable() {
+            mUiHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     synchronized (ActivityManagerService.this) {
                         final Dialog d = new LaunchWarningWindow(mContext, cur, next);
                         d.show();
-                        mHandler.postDelayed(new Runnable() {
+                        mUiHandler.postDelayed(new Runnable() {
                             @Override
                             public void run() {
                                 synchronized (ActivityManagerService.this) {
@@ -5802,17 +5820,20 @@
             if (app.isolated) {
                 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);
             }
-            app.kill(reason, true);
-            handleAppDiedLocked(app, true, allowRestart);
-            removeLruProcessLocked(app);
-
+            boolean willRestart = false;
             if (app.persistent && !app.isolated) {
                 if (!callerWillRestart) {
-                    addAppLocked(app.info, false, null /* ABI override */);
+                    willRestart = true;
                 } else {
                     needRestart = true;
                 }
             }
+            app.kill(reason, true);
+            handleAppDiedLocked(app, willRestart, allowRestart);
+            if (willRestart) {
+                removeLruProcessLocked(app);
+                addAppLocked(app.info, false, null /* ABI override */);
+            }
         } else {
             mRemovedProcesses.add(app);
         }
@@ -8053,7 +8074,7 @@
             msg.what = WAIT_FOR_DEBUGGER_MSG;
             msg.obj = app;
             msg.arg1 = waiting ? 1 : 0;
-            mHandler.sendMessage(msg);
+            mUiHandler.sendMessage(msg);
         }
     }
 
@@ -11359,7 +11380,7 @@
                     Message msg = Message.obtain();
                     msg.what = SHOW_FACTORY_ERROR_MSG;
                     msg.getData().putCharSequence("msg", errorMsg);
-                    mHandler.sendMessage(msg);
+                    mUiHandler.sendMessage(msg);
                 }
             }
         }
@@ -11409,14 +11430,14 @@
                 if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
                     Slog.e(TAG, "UIDs on the system are inconsistent, you need to wipe your"
                             + " data partition or your device will be unstable.");
-                    mHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget();
+                    mUiHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget();
                 }
             } catch (RemoteException e) {
             }
 
             if (!Build.isFingerprintConsistent()) {
                 Slog.e(TAG, "Build fingerprint is not consistent, warning user");
-                mHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
+                mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget();
             }
 
             long ident = Binder.clearCallingIdentity();
@@ -11702,7 +11723,7 @@
                 data.put("violationMask", violationMask);
                 data.put("info", info);
                 msg.obj = data;
-                mHandler.sendMessage(msg);
+                mUiHandler.sendMessage(msg);
 
                 Binder.restoreCallingIdentity(origId);
             }
@@ -12157,7 +12178,7 @@
             data.put("result", result);
             data.put("app", r);
             msg.obj = data;
-            mHandler.sendMessage(msg);
+            mUiHandler.sendMessage(msg);
 
             Binder.restoreCallingIdentity(origId);
         }
@@ -14891,7 +14912,7 @@
             }
         }
 
-        for (int i=0; i<cpr.connections.size(); i++) {
+        for (int i = cpr.connections.size() - 1; i >= 0; i--) {
             ContentProviderConnection conn = cpr.connections.get(i);
             if (conn.waiting) {
                 // If this connection is waiting for the provider, then we don't
@@ -14983,10 +15004,11 @@
         boolean restart = false;
 
         // Remove published content providers.
-        for (int i=app.pubProviders.size()-1; i>=0; i--) {
+        for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
             ContentProviderRecord cpr = app.pubProviders.valueAt(i);
             final boolean always = app.bad || !allowRestart;
-            if (removeDyingProviderLocked(app, cpr, always) || always) {
+            boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
+            if ((inLaunching || always) && !cpr.connections.isEmpty()) {
                 // We left the provider in the launching list, need to
                 // restart it.
                 restart = true;
@@ -15004,7 +15026,7 @@
 
         // Unregister from connected content providers.
         if (!app.conProviders.isEmpty()) {
-            for (int i=0; i<app.conProviders.size(); i++) {
+            for (int i = app.conProviders.size() - 1; i >= 0; i--) {
                 ContentProviderConnection conn = app.conProviders.get(i);
                 conn.provider.connections.remove(conn);
                 stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
@@ -15019,9 +15041,8 @@
         // XXX Commented out for now.  Trying to figure out a way to reproduce
         // the actual situation to identify what is actually going on.
         if (false) {
-            for (int i=0; i<mLaunchingProviders.size(); i++) {
-                ContentProviderRecord cpr = (ContentProviderRecord)
-                        mLaunchingProviders.get(i);
+            for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+                ContentProviderRecord cpr = mLaunchingProviders.get(i);
                 if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
                     synchronized (cpr) {
                         cpr.launchingApp = null;
@@ -15034,7 +15055,7 @@
         skipCurrentReceiverLocked(app);
 
         // Unregister any receivers.
-        for (int i=app.receivers.size()-1; i>=0; i--) {
+        for (int i = app.receivers.size() - 1; i >= 0; i--) {
             removeReceiverLocked(app.receivers.valueAt(i));
         }
         app.receivers.clear();
@@ -15052,7 +15073,7 @@
             }
         }
 
-        for (int i = mPendingProcessChanges.size()-1; i>=0; i--) {
+        for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
             ProcessChangeItem item = mPendingProcessChanges.get(i);
             if (item.pid == app.pid) {
                 mPendingProcessChanges.remove(i);
@@ -15127,18 +15148,14 @@
         // and if any run in this process then either schedule a restart of
         // the process or kill the client waiting for it if this process has
         // gone bad.
-        int NL = mLaunchingProviders.size();
         boolean restart = false;
-        for (int i=0; i<NL; i++) {
+        for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
             ContentProviderRecord cpr = mLaunchingProviders.get(i);
             if (cpr.launchingApp == app) {
-                if (!alwaysBad && !app.bad) {
+                if (!alwaysBad && !app.bad && !cpr.connections.isEmpty()) {
                     restart = true;
                 } else {
                     removeDyingProviderLocked(app, cpr, true);
-                    // cpr should have been removed from mLaunchingProviders
-                    NL = mLaunchingProviders.size();
-                    i--;
                 }
             }
         }
@@ -18922,8 +18939,8 @@
             userName = userInfo.name;
             mTargetUserId = userId;
         }
-        mHandler.removeMessages(START_USER_SWITCH_MSG);
-        mHandler.sendMessage(mHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));
+        mUiHandler.removeMessages(START_USER_SWITCH_MSG);
+        mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ada16e7..d89fa15 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -780,8 +780,14 @@
     final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
             boolean dontWait) {
         if (mPausingActivity != null) {
-            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity);
-            completePauseLocked(false);
+            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+                    + " state=" + mPausingActivity.state);
+            if (!mService.isSleeping()) {
+                // Avoid recursion among check for sleep and complete pause during sleeping.
+                // Because activity will be paused immediately after resume, just let pause
+                // be completed by the order of activity paused from clients.
+                completePauseLocked(false);
+            }
         }
         ActivityRecord prev = mResumedActivity;
         if (prev == null) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 27ac32a..ad50e05a 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -148,7 +148,7 @@
                 if (timeout >= 0) {
                     // The activity manager declined to abort dispatching.
                     // Wait a bit longer and timeout again later.
-                    return timeout;
+                    return timeout * 1000000L; // nanoseconds
                 }
             } catch (RemoteException ex) {
             }
diff --git a/tools/obbtool/pbkdf2gen.cpp b/tools/obbtool/pbkdf2gen.cpp
index 98d67c0..f1d8d04 100644
--- a/tools/obbtool/pbkdf2gen.cpp
+++ b/tools/obbtool/pbkdf2gen.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>