Merge "Icon updates (1 of many)" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index e2ba28a..8a64dd0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7360,8 +7360,8 @@
     method public int getCount();
     method public int getEventType();
     method public long getFirstTimeStamp();
+    method public long getLastEventTime();
     method public long getLastTimeStamp();
-    method public long getLastTimeUsed();
     method public long getTotalTime();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.usage.EventStats> CREATOR;
@@ -7418,8 +7418,9 @@
 
   public class NetworkStatsManager {
     method public android.app.usage.NetworkStats queryDetails(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
-    method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws android.os.RemoteException, java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUid(int, java.lang.String, long, long, int) throws java.lang.SecurityException;
     method public android.app.usage.NetworkStats queryDetailsForUidTag(int, java.lang.String, long, long, int, int) throws java.lang.SecurityException;
+    method public android.app.usage.NetworkStats queryDetailsForUidTagState(int, java.lang.String, long, long, int, int, int) throws java.lang.SecurityException;
     method public android.app.usage.NetworkStats querySummary(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
     method public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, java.lang.String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
@@ -7469,6 +7470,8 @@
     method public int getStandbyBucket();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
+    field public static final int KEYGUARD_HIDDEN = 18; // 0x12
+    field public static final int KEYGUARD_SHOWN = 17; // 0x11
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
@@ -38578,11 +38581,11 @@
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isStrongBoxBacked();
-    method public boolean isTrustedUserPresenceRequired();
     method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
     method public boolean isUserConfirmationRequired();
+    method public boolean isUserPresenceRequired();
   }
 
   public static final class KeyGenParameterSpec.Builder {
@@ -38606,12 +38609,12 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
     method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserConfirmationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserPresenceRequired(boolean);
   }
 
   public class KeyInfo implements java.security.spec.KeySpec {
@@ -38699,11 +38702,11 @@
     method public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
-    method public boolean isTrustedUserPresenceRequired();
     method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
     method public boolean isUserConfirmationRequired();
+    method public boolean isUserPresenceRequired();
   }
 
   public static final class KeyProtection.Builder {
@@ -38719,15 +38722,26 @@
     method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
     method public android.security.keystore.KeyProtection.Builder setUserConfirmationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserPresenceRequired(boolean);
+  }
+
+  public class SecureKeyImportUnavailableException extends java.security.ProviderException {
+    ctor public SecureKeyImportUnavailableException();
+    ctor public SecureKeyImportUnavailableException(java.lang.String);
+    ctor public SecureKeyImportUnavailableException(java.lang.String, java.lang.Throwable);
+    ctor public SecureKeyImportUnavailableException(java.lang.Throwable);
   }
 
   public class StrongBoxUnavailableException extends java.security.ProviderException {
+    ctor public StrongBoxUnavailableException();
+    ctor public StrongBoxUnavailableException(java.lang.String);
+    ctor public StrongBoxUnavailableException(java.lang.String, java.lang.Throwable);
+    ctor public StrongBoxUnavailableException(java.lang.Throwable);
   }
 
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
diff --git a/api/test-current.txt b/api/test-current.txt
index f66fafe..9f5fa0c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -779,6 +779,12 @@
     method public void setCdmaSystemAndNetworkId(int, int);
   }
 
+  public class TelephonyManager {
+    method public int getCarrierIdListVersion();
+    method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
+    field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
+  }
+
 }
 
 package android.telephony.mbms {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 7fe8e62..5bb2015 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1225,6 +1225,22 @@
 
     // The pid if available. -1 means not available.
     optional sint32 pid = 4;
+
+    optional string package_name = 5;
+
+    enum InstantApp {
+        UNAVAILABLE = 0;
+        FALSE = 1;
+        TRUE = 2;
+    }
+    optional InstantApp is_instant_app = 6;
+
+    enum ForegroundState {
+        UNKNOWN = 0;
+        BACKGROUND = 1;
+        FOREGROUND = 2;
+    }
+    optional ForegroundState foreground_state = 7;
 }
 
 /**
@@ -1266,6 +1282,20 @@
     optional string short_component_name = 3;
 
     optional string reason = 4;
+
+    enum InstantApp {
+        UNAVAILABLE = 0;
+        FALSE = 1;
+        TRUE = 2;
+    }
+    optional InstantApp is_instant_app = 5;
+
+    enum ForegroundState {
+        UNKNOWN = 0;
+        BACKGROUND = 1;
+        FOREGROUND = 2;
+    }
+    optional ForegroundState foreground_state = 6;
 }
 
 /*
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 90308d7..9c7bfb2 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -296,6 +296,7 @@
 Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/LoadedApk;->getAssets()Landroid/content/res/AssetManager;
 Landroid/app/LoadedApk;->getClassLoader()Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
 Landroid/app/LoadedApk;->getDataDirFile()Ljava/io/File;
 Landroid/app/LoadedApk;->getResources()Landroid/content/res/Resources;
 Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
@@ -377,8 +378,10 @@
 Landroid/app/Vr2dDisplayProperties$Builder;->setEnabled(Z)Landroid/app/Vr2dDisplayProperties$Builder;
 Landroid/app/Vr2dDisplayProperties;-><init>(III)V
 Landroid/app/VrManager;->getPersistentVrModeEnabled()Z
+Landroid/app/VrManager;->mService:Landroid/service/vr/IVrManager;
 Landroid/app/VrManager;->registerVrStateCallback(Landroid/app/VrStateCallback;Landroid/os/Handler;)V
 Landroid/app/VrManager;->setVr2dDisplayProperties(Landroid/app/Vr2dDisplayProperties;)V
+Landroid/app/VrManager;->unregisterVrStateCallback(Landroid/app/VrStateCallback;)V
 Landroid/app/WallpaperColors;->getColorHints()I
 Landroid/app/WallpaperManager;->getBitmap()Landroid/graphics/Bitmap;
 Landroid/app/WallpaperManager;->getBitmap(Z)Landroid/graphics/Bitmap;
@@ -447,6 +450,7 @@
 Landroid/content/ContentResolver;->unstableProviderDied(Landroid/content/IContentProvider;)V
 Landroid/content/ContentValues;-><init>(Ljava/util/HashMap;)V
 Landroid/content/ContentValues;->mValues:Ljava/util/HashMap;
+Landroid/content/Context;->getBasePackageName()Ljava/lang/String;
 Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
 Landroid/content/Context;->getThemeResId()I
 Landroid/content/Context;->sendBroadcastAsUser(Landroid/content/Intent;Landroid/os/UserHandle;Ljava/lang/String;I)V
@@ -469,6 +473,7 @@
 Landroid/content/Intent;->mExtras:Landroid/os/Bundle;
 Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/IBinder;)Landroid/content/Intent;
 Landroid/content/pm/ActivityInfo;->resizeMode:I
+Landroid/content/pm/ActivityInfo;->supportsPictureInPicture()Z
 Landroid/content/pm/ApplicationInfo;->enabledSetting:I
 Landroid/content/pm/ApplicationInfo;->getBaseResourcePath()Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->installLocation:I
@@ -2099,6 +2104,8 @@
 Landroid/util/SparseIntArray;->mKeys:[I
 Landroid/util/SparseIntArray;->mSize:I
 Landroid/util/SparseIntArray;->mValues:[I
+Landroid/view/accessibility/AccessibilityInteractionClient;->clearCache()V
+Landroid/view/accessibility/AccessibilityInteractionClient;->getInstance()Landroid/view/accessibility/AccessibilityInteractionClient;
 Landroid/view/accessibility/AccessibilityManager;->getInstance(Landroid/content/Context;)Landroid/view/accessibility/AccessibilityManager;
 Landroid/view/accessibility/AccessibilityManager;->isHighTextContrastEnabled()Z
 Landroid/view/accessibility/AccessibilityManager;->mAccessibilityStateChangeListeners:Landroid/util/ArrayMap;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 4a168fe..e4a0583 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -321,16 +321,20 @@
         }
 
         WindowManager.LayoutParams l = mWindow.getAttributes();
+        boolean restoreSoftInputMode = false;
         if ((l.softInputMode
                 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
-            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
-            nl.copyFrom(l);
-            nl.softInputMode |=
+            l.softInputMode |=
                     WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-            l = nl;
+            restoreSoftInputMode = true;
         }
 
         mWindowManager.addView(mDecor, l);
+        if (restoreSoftInputMode) {
+            l.softInputMode &=
+                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+        }
+
         mShowing = true;
 
         sendShowMessage();
diff --git a/core/java/android/app/usage/EventStats.java b/core/java/android/app/usage/EventStats.java
index b799de9..ea95a05 100644
--- a/core/java/android/app/usage/EventStats.java
+++ b/core/java/android/app/usage/EventStats.java
@@ -41,10 +41,9 @@
     public long mEndTimeStamp;
 
     /**
-     * Last time used by the user with an explicit action (notification, activity launch).
      * {@hide}
      */
-    public long mLastTimeUsed;
+    public long mLastEventTime;
 
     /**
      * {@hide}
@@ -66,7 +65,7 @@
         mEventType = stats.mEventType;
         mBeginTimeStamp = stats.mBeginTimeStamp;
         mEndTimeStamp = stats.mEndTimeStamp;
-        mLastTimeUsed = stats.mLastTimeUsed;
+        mLastEventTime = stats.mLastEventTime;
         mTotalTime = stats.mTotalTime;
         mCount = stats.mCount;
     }
@@ -100,12 +99,12 @@
     }
 
     /**
-     * Get the last time this event was used, measured in milliseconds since the epoch.
+     * Get the last time this event triggered, measured in milliseconds since the epoch.
      * <p/>
      * See {@link System#currentTimeMillis()}.
      */
-    public long getLastTimeUsed() {
-        return mLastTimeUsed;
+    public long getLastEventTime() {
+        return mLastEventTime;
     }
 
     /**
@@ -138,7 +137,7 @@
         // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with
         // regards to their mEndTimeStamp.
         if (right.mBeginTimeStamp > mBeginTimeStamp) {
-            mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
+            mLastEventTime = Math.max(mLastEventTime, right.mLastEventTime);
         }
         mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
         mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp);
@@ -156,7 +155,7 @@
         dest.writeInt(mEventType);
         dest.writeLong(mBeginTimeStamp);
         dest.writeLong(mEndTimeStamp);
-        dest.writeLong(mLastTimeUsed);
+        dest.writeLong(mLastEventTime);
         dest.writeLong(mTotalTime);
         dest.writeInt(mCount);
     }
@@ -168,7 +167,7 @@
             stats.mEventType = in.readInt();
             stats.mBeginTimeStamp = in.readLong();
             stats.mEndTimeStamp = in.readLong();
-            stats.mLastTimeUsed = in.readLong();
+            stats.mLastEventTime = in.readLong();
             stats.mTotalTime = in.readLong();
             stats.mCount = in.readInt();
             return stats;
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index e315e91..7252f02 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -68,6 +68,11 @@
     private int mTag = android.net.NetworkStats.TAG_NONE;
 
     /**
+     * State in case it was not specified in the query.
+     */
+    private int mState = Bucket.STATE_ALL;
+
+    /**
      * The session while the query requires it, null if all the stats have been collected or close()
      * has been called.
      */
@@ -267,6 +272,15 @@
         private long mTxBytes;
         private long mTxPackets;
 
+        private static int convertSet(@State int state) {
+            switch (state) {
+                case STATE_ALL: return android.net.NetworkStats.SET_ALL;
+                case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT;
+                case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND;
+            }
+            return 0;
+        }
+
         private static @State int convertState(int networkStatsSet) {
             switch (networkStatsSet) {
                 case android.net.NetworkStats.SET_ALL : return STATE_ALL;
@@ -527,20 +541,13 @@
     /**
      * Collects history results for uid and resets history enumeration index.
      */
-    void startHistoryEnumeration(int uid) {
-        startHistoryEnumeration(uid, android.net.NetworkStats.TAG_NONE);
-    }
-
-    /**
-     * Collects history results for uid and resets history enumeration index.
-     */
-    void startHistoryEnumeration(int uid, int tag) {
+    void startHistoryEnumeration(int uid, int tag, int state) {
         mHistory = null;
         try {
             mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
-                    android.net.NetworkStats.SET_ALL, tag,
-                    NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
-            setSingleUidTag(uid, tag);
+                    Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL,
+                    mStartTimeStamp, mEndTimeStamp);
+            setSingleUidTagState(uid, tag, state);
         } catch (RemoteException e) {
             Log.w(TAG, e);
             // Leaving mHistory null
@@ -636,6 +643,7 @@
         fillBucketFromSummaryEntry(bucket);
         return bucket;
     }
+
     /**
      * Getting the next item in a history enumeration.
      * @param bucketOut Next item will be set here.
@@ -648,7 +656,7 @@
                         mRecycledHistoryEntry);
                 bucketOut.mUid = Bucket.convertUid(getUid());
                 bucketOut.mTag = Bucket.convertTag(mTag);
-                bucketOut.mState = Bucket.STATE_ALL;
+                bucketOut.mState = mState;
                 bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL;
                 bucketOut.mMetered = Bucket.METERED_ALL;
                 bucketOut.mRoaming = Bucket.ROAMING_ALL;
@@ -691,9 +699,10 @@
         return mUidOrUidIndex;
     }
 
-    private void setSingleUidTag(int uid, int tag) {
+    private void setSingleUidTagState(int uid, int tag, int state) {
         mUidOrUidIndex = uid;
         mTag = tag;
+        mState = state;
     }
 
     private void stepUid() {
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 2357637..b2fe958 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -263,20 +263,31 @@
     /**
      * Query network usage statistics details for a given uid.
      *
-     * #see queryDetailsForUidTag(int, String, long, long, int, int)
+     * #see queryDetailsForUidTagState(int, String, long, long, int, int, int)
      */
     public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
-            long startTime, long endTime, int uid) throws SecurityException, RemoteException {
-        return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid,
-            NetworkStats.Bucket.TAG_NONE);
+            long startTime, long endTime, int uid) throws SecurityException {
+        return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
+            NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
     }
 
     /**
-     * Query network usage statistics details for a given uid and tag. Only usable for uids
-     * belonging to calling user. Result is aggregated over state but not aggregated over time.
-     * This means buckets' start and end timestamps are going to be between 'startTime' and
-     * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the
-     * same as the 'uid' parameter and tag the same as 'tag' parameter.
+     * Query network usage statistics details for a given uid and tag.
+     *
+     * #see queryDetailsForUidTagState(int, String, long, long, int, int, int)
+     */
+    public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+            long startTime, long endTime, int uid, int tag) throws SecurityException {
+        return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
+            tag, NetworkStats.Bucket.STATE_ALL);
+    }
+
+    /**
+     * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
+     * belonging to calling user. Result is not aggregated over time. This means buckets' start and
+     * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
+     * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
+     * the same as the 'state' parameter.
      * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
      * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
      * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
@@ -297,17 +308,18 @@
      * @return Statistics object or null if an error happened during statistics collection.
      * @throws SecurityException if permissions are insufficient to read network statistics.
      */
-    public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
-            long startTime, long endTime, int uid, int tag) throws SecurityException {
+    public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
+            long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
         NetworkTemplate template;
         template = createTemplate(networkType, subscriberId);
 
         NetworkStats result;
         try {
             result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
-            result.startHistoryEnumeration(uid, tag);
+            result.startHistoryEnumeration(uid, tag, state);
         } catch (RemoteException e) {
-            Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
+            Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag
+                    + " state=" + state, e);
             return null;
         }
 
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index a665652..84f57a3 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -152,6 +152,18 @@
          */
         public static final int SCREEN_NON_INTERACTIVE = 16;
 
+        /**
+         * An event type denoting that the screen's keyguard has been shown, whether or not
+         * the screen is off.
+         */
+        public static final int KEYGUARD_SHOWN = 17;
+
+        /**
+         * An event type denoting that the screen's keyguard has been hidden.  This typically
+         * happens when the user unlocks their phone after turning it on.
+         */
+        public static final int KEYGUARD_HIDDEN = 18;
+
         /** @hide */
         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
 
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index eafe91a..7fb97d3 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -319,6 +319,8 @@
      * <ul>
      *     <li>{@link UsageEvents.Event#SCREEN_INTERACTIVE}</li>
      *     <li>{@link UsageEvents.Event#SCREEN_NON_INTERACTIVE}</li>
+     *     <li>{@link UsageEvents.Event#KEYGUARD_SHOWN}</li>
+     *     <li>{@link UsageEvents.Event#KEYGUARD_HIDDEN}</li>
      * </ul>
      *
      * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bc7540f..2f0faf2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -5701,7 +5701,8 @@
                 flag = true,
                 value = {CertCapabilities.INSTALLED_DATA,
                         CertCapabilities.SHARED_USER_ID,
-                        CertCapabilities.PERMISSION })
+                        CertCapabilities.PERMISSION,
+                        CertCapabilities.ROLLBACK})
         public @interface CertCapabilities {
 
             /** accept data from already installed pkg with this cert */
@@ -5712,6 +5713,9 @@
 
             /** grant SIGNATURE permissions to pkgs with this cert */
             int PERMISSION = 4;
+
+            /** allow pkg to update to one signed by this certificate */
+            int ROLLBACK = 8;
         }
 
         /**
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 2252571..411a97e 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2105,8 +2105,8 @@
      * the thumbnail data will also be rotated.</p>
      * <p>Note that this orientation is relative to the orientation of the camera sensor, given
      * by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
-     * <p>To translate from the device orientation given by the Android sensor APIs, the following
-     * sample code may be used:</p>
+     * <p>To translate from the device orientation given by the Android sensor APIs for camera
+     * sensors which are not EXTERNAL, the following sample code may be used:</p>
      * <pre><code>private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
      *     if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0;
      *     int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -2125,6 +2125,8 @@
      *     return jpegOrientation;
      * }
      * </code></pre>
+     * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
+     * also be set to EXTERNAL. The above code is not relevant in such case.</p>
      * <p><b>Units</b>: Degrees in multiples of 90</p>
      * <p><b>Range of valid values:</b><br>
      * 0, 90, 180, 270</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 8df5447..c156616 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2422,8 +2422,8 @@
      * the thumbnail data will also be rotated.</p>
      * <p>Note that this orientation is relative to the orientation of the camera sensor, given
      * by {@link CameraCharacteristics#SENSOR_ORIENTATION android.sensor.orientation}.</p>
-     * <p>To translate from the device orientation given by the Android sensor APIs, the following
-     * sample code may be used:</p>
+     * <p>To translate from the device orientation given by the Android sensor APIs for camera
+     * sensors which are not EXTERNAL, the following sample code may be used:</p>
      * <pre><code>private int getJpegOrientation(CameraCharacteristics c, int deviceOrientation) {
      *     if (deviceOrientation == android.view.OrientationEventListener.ORIENTATION_UNKNOWN) return 0;
      *     int sensorOrientation = c.get(CameraCharacteristics.SENSOR_ORIENTATION);
@@ -2442,6 +2442,8 @@
      *     return jpegOrientation;
      * }
      * </code></pre>
+     * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
+     * also be set to EXTERNAL. The above code is not relevant in such case.</p>
      * <p><b>Units</b>: Degrees in multiples of 90</p>
      * <p><b>Range of valid values:</b><br>
      * 0, 90, 180, 270</p>
diff --git a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
index 93d6001..55130c8 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
@@ -62,14 +62,14 @@
      * exceptions.</p>
      *
      * @param errorFlag error to throw as an exception.
-     * @throws {@link BufferQueueAbandonedException} for -ENODEV.
+     * @throws {@link BufferQueueAbandonedException} for BAD_VALUE.
      * @throws {@link UnsupportedOperationException} for an unknown negative error code.
      * @return {@code errorFlag} if the value was non-negative, throws otherwise.
      */
     public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
         if (errorFlag == NO_ERROR) {
             return NO_ERROR;
-        } else if (errorFlag == -ENODEV) {
+        } else if (errorFlag == BAD_VALUE) {
             throw new BufferQueueAbandonedException();
         }
 
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 292bf8e..f0dd262 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -31,6 +31,7 @@
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -97,6 +98,11 @@
     /** Denotes a request for stats at the interface and UID level. */
     public static final int STATS_PER_UID = 1;
 
+    private static final String CLATD_INTERFACE_PREFIX = "v4-";
+    // Delta between IPv4 header (20b) and IPv6 header (40b).
+    // Used for correct stats accounting on clatd interfaces.
+    private static final int IPV4V6_HEADER_DELTA = 20;
+
     // TODO: move fields to "mVariable" notation
 
     /**
@@ -759,6 +765,75 @@
     }
 
     /**
+     * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
+     *
+     * <p>This mutates both base and stacked traffic stats, to account respectively for
+     * double-counted traffic and IPv4/IPv6 header size difference.
+     *
+     * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
+     * packet on the stacked interface, and once as translated to an IPv6 packet on the
+     * base interface. For correct stats accounting on the base interface, every 464xlat
+     * packet needs to be subtracted from the root UID on the base interface both for tx
+     * and rx traffic (http://b/12249687, http:/b/33681750).
+     *
+     * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
+     * {@code ConcurrentHashMap}
+     * @param baseTraffic Traffic on the base interfaces. Will be mutated.
+     * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
+     * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+     */
+    public static void apply464xlatAdjustments(NetworkStats baseTraffic,
+            NetworkStats stackedTraffic, Map<String, String> stackedIfaces) {
+        // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
+        // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
+        final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
+
+        // For recycling
+        Entry entry = null;
+        Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
+
+        for (int i = 0; i < stackedTraffic.size; i++) {
+            entry = stackedTraffic.getValues(i, entry);
+            if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
+                continue;
+            }
+            final String baseIface = stackedIfaces.get(entry.iface);
+            if (baseIface == null) {
+                continue;
+            }
+            // Subtract any 464lat traffic seen for the root UID on the current base interface.
+            adjust.iface = baseIface;
+            adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
+            adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
+            adjust.rxPackets = -entry.rxPackets;
+            adjust.txPackets = -entry.txPackets;
+            adjustments.combineValues(adjust);
+
+            // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent
+            // on the stacked interface with prefix "v4-" and drops the IPv6 header size after
+            // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
+            // difference for all packets (http://b/12249687, http:/b/33681750).
+            entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA;
+            entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA;
+            stackedTraffic.setValues(i, entry);
+        }
+
+        baseTraffic.combineAllValues(adjustments);
+    }
+
+    /**
+     * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
+     *
+     * <p>This mutates the object this method is called on. Equivalent to calling
+     * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
+     * base and stacked traffic.
+     * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+     */
+    public void apply464xlatAdjustments(Map<String, String> stackedIfaces) {
+        apply464xlatAdjustments(this, this, stackedIfaces);
+    }
+
+    /**
      * Return total statistics grouped by {@link #iface}; doesn't mutate the
      * original structure.
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b0367dc..68fc6c1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9220,8 +9220,8 @@
         public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
 
         /**
-         * Map of package name to application names.  Package names must be lower cased as they are
-         * used as a key in the map.  The application names cannot and will not be localized.
+         * Map of package name to application names. The application names cannot and will not be
+         * localized. App names may not contain colons or semicolons.
          *
          * The value is "packageName1:appName1;packageName2:appName2;..."
          * @hide
diff --git a/core/java/android/security/Scrypt.java b/core/java/android/security/Scrypt.java
new file mode 100644
index 0000000..edf8d31
--- /dev/null
+++ b/core/java/android/security/Scrypt.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * A Java wrapper for the JNI function to perform the password hashing algorithm SCRYPT.
+ *
+ * @hide
+ */
+public class Scrypt {
+
+    native byte[] nativeScrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen);
+
+    /** Computes the password hashing algorithm SCRYPT. */
+    public byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) {
+        return nativeScrypt(password, salt, n, r, p, outLen);
+    }
+}
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index ab3ed91..281822a 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -285,7 +285,17 @@
     public void initRecoveryService(
             @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList)
             throws CertificateException, InternalRecoveryServiceException {
-        throw new CertificateException("Deprecated initRecoveryService method called");
+        try {
+            mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        } catch (ServiceSpecificException e) {
+            if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT
+                    || e.errorCode == ERROR_INVALID_CERTIFICATE) {
+                throw new CertificateException("Invalid certificate for recovery service", e);
+            }
+            throw wrapUnexpectedServiceSpecificException(e);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index c1c5d9d..5eb6699 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -393,6 +393,12 @@
         private int mWindowPositionY;
         private boolean mPendingWindowPositionUpdate;
 
+        // The lock used to synchronize the UI and render threads when a #destroy
+        // is performed on the UI thread and a frame callback on the render thread.
+        // When both mLock and mDestroyLock need to be held at the same time,
+        // mDestroyLock should be acquired before mLock in order to avoid deadlocks.
+        private final Object mDestroyLock = new Object();
+
         InternalPopupWindow(final Context context, final Display display,
                 final Surface parentSurface,
                 final int width, final int height, final float elevation, final float cornerRadius,
@@ -517,9 +523,11 @@
          * Destroys this instance.
          */
         public void destroy() {
+            synchronized (mDestroyLock) {
+                mSurface.destroy();
+            }
             synchronized (mLock) {
                 mRenderer.destroy();
-                mSurface.destroy();
                 mSurfaceControl.destroy();
                 mSurfaceSession.kill();
                 mBitmapRenderNode.destroy();
@@ -567,21 +575,23 @@
                     final int pendingY = mWindowPositionY;
 
                     callback = frame -> {
-                        synchronized (mLock) {
+                        synchronized (mDestroyLock) {
                             if (!mSurface.isValid()) {
                                 return;
                             }
-                            mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
-                            // Show or move the window at the content draw frame.
-                            SurfaceControl.openTransaction();
-                            mSurfaceControl.deferTransactionUntil(mSurface, frame);
-                            if (updateWindowPosition) {
-                                mSurfaceControl.setPosition(pendingX, pendingY);
+                            synchronized (mLock) {
+                                mRenderer.setLightCenter(mDisplay, pendingX, pendingY);
+                                // Show or move the window at the content draw frame.
+                                SurfaceControl.openTransaction();
+                                mSurfaceControl.deferTransactionUntil(mSurface, frame);
+                                if (updateWindowPosition) {
+                                    mSurfaceControl.setPosition(pendingX, pendingY);
+                                }
+                                if (firstDraw) {
+                                    mSurfaceControl.show();
+                                }
+                                SurfaceControl.closeTransaction();
                             }
-                            if (firstDraw) {
-                                mSurfaceControl.show();
-                            }
-                            SurfaceControl.closeTransaction();
                         }
                     };
                 } else {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 6e0ba341..97043c7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -389,6 +389,10 @@
 
     @Override
     public void showTargetDetails(ResolveInfo ri) {
+        if (ri == null) {
+            return;
+        }
+
         ComponentName name = ri.activityInfo.getComponentName();
         boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         ResolverTargetActionsDialogFragment f =
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 0cf5375..98afebc 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -56,11 +56,6 @@
     private static final boolean USE_NATIVE_PARSING = true;
     private static final boolean SANITY_CHECK_NATIVE = false;
 
-    private static final String CLATD_INTERFACE_PREFIX = "v4-";
-    // Delta between IPv4 header (20b) and IPv6 header (40b).
-    // Used for correct stats accounting on clatd interfaces.
-    private static final int IPV4V6_HEADER_DELTA = 20;
-
     /** Path to {@code /proc/net/dev}. */
     private final File mStatsIfaceDev;
     /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
@@ -96,7 +91,7 @@
      * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
      * is called are guaranteed to be included.
      */
-    public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) {
+    public static String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) {
         if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
             return null;
         }
@@ -118,6 +113,15 @@
         return relatedIfaces.toArray(outArray);
     }
 
+    /**
+     * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}.
+     * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map)
+     */
+    public static void apply464xlatAdjustments(NetworkStats baseTraffic,
+            NetworkStats stackedTraffic) {
+        NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces);
+    }
+
     @VisibleForTesting
     public static void clearStackedIfaces() {
         sStackedIfaces.clear();
@@ -289,48 +293,10 @@
             NetworkStats lastStats) throws IOException {
         final NetworkStats stats =
               readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
-        // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
-        // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
-        final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size());
 
-        NetworkStats.Entry entry = null; // For recycling
-
-        // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
-        // packet on the stacked interface, and once as translated to an IPv6 packet on the
-        // base interface. For correct stats accounting on the base interface, every 464xlat
-        // packet needs to be subtracted from the root UID on the base interface both for tx
-        // and rx traffic (http://b/12249687, http:/b/33681750).
-        for (int i = 0; i < stats.size(); i++) {
-            entry = stats.getValues(i, entry);
-            if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
-                continue;
-            }
-            final String baseIface = sStackedIfaces.get(entry.iface);
-            if (baseIface == null) {
-                continue;
-            }
-
-            NetworkStats.Entry adjust =
-                    new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
-            // Subtract any 464lat traffic seen for the root UID on the current base interface.
-            adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
-            adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
-            adjust.rxPackets -= entry.rxPackets;
-            adjust.txPackets -= entry.txPackets;
-            adjustments.combineValues(adjust);
-
-            // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent
-            // on the stacked interface with prefix "v4-" and drops the IPv6 header size after
-            // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
-            // difference for all packets (http://b/12249687, http:/b/33681750).
-            entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA;
-            entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA;
-            entry.rxPackets = 0;
-            entry.txPackets = 0;
-            stats.combineValues(entry);
-        }
-
-        stats.combineAllValues(adjustments);
+        // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap.
+        // TODO: remove this and only apply adjustments in NetworkStatsService.
+        stats.apply464xlatAdjustments(sStackedIfaces);
 
         return stats;
     }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1d22093..302189f 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -195,6 +195,7 @@
         "android_content_res_ObbScanner.cpp",
         "android_content_res_Configuration.cpp",
         "android_animation_PropertyValuesHolder.cpp",
+        "android_security_Scrypt.cpp",
         "com_android_internal_net_NetworkStatsFactory.cpp",
         "com_android_internal_os_ClassLoaderFactory.cpp",
         "com_android_internal_os_FuseAppLoop.cpp",
@@ -228,6 +229,7 @@
         "libseccomp_policy",
         "libselinux",
         "libgrallocusage",
+        "libscrypt_static",
     ],
 
     shared_libs: [
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5ae4a52..f8dd7ac 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -208,6 +208,7 @@
 extern int register_android_content_res_ObbScanner(JNIEnv* env);
 extern int register_android_content_res_Configuration(JNIEnv* env);
 extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
+extern int register_android_security_Scrypt(JNIEnv *env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
@@ -1492,6 +1493,7 @@
     REG_JNI(register_android_content_res_Configuration),
 
     REG_JNI(register_android_animation_PropertyValuesHolder),
+    REG_JNI(register_android_security_Scrypt),
     REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
     REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
     REG_JNI(register_com_android_internal_os_FuseAppLoop),
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index b610b35..e02741f 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -49,6 +49,22 @@
 
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
+// Use BAD_VALUE for surface abandoned error
+#define OVERRIDE_SURFACE_ERROR(err) \
+do {                                \
+    if (err == -ENODEV) {           \
+        err = BAD_VALUE;            \
+    }                               \
+} while (0)
+
+#define UPDATE(md, tag, data, size)               \
+do {                                              \
+    if ((md).update((tag), (data), (size))) {     \
+        ALOGE("Update " #tag " failed!");         \
+        return BAD_VALUE;                         \
+    }                                             \
+} while (0)
+
 /**
  * Convert from RGB 888 to Y'CbCr using the conversion specified in JFIF v1.02
  */
@@ -108,6 +124,7 @@
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
 
@@ -117,6 +134,7 @@
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
                 __FUNCTION__, strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
 
@@ -126,6 +144,7 @@
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
@@ -180,7 +199,12 @@
 
     // TODO: Switch to using Surface::lock and Surface::unlockAndPost
     err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
-    if (err != NO_ERROR) return err;
+    if (err != NO_ERROR) {
+        ALOGE("%s: Failed to dequeue buffer, error %s (%d).", __FUNCTION__,
+                strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
+        return err;
+    }
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
     uint32_t grallocBufWidth = buf->getWidth();
@@ -198,6 +222,7 @@
     if (err != NO_ERROR) {
         ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__,
                 strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
 
@@ -345,6 +370,7 @@
     err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
@@ -420,6 +446,7 @@
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying surface pixel format %s (%d).", __FUNCTION__, strerror(-err),
                 err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return fmt;
@@ -437,6 +464,7 @@
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying surface dataspace  %s (%d).", __FUNCTION__, strerror(-err),
                 err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return fmt;
@@ -466,12 +494,14 @@
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying surface width %s (%d).", __FUNCTION__, strerror(-err),
                 err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1);
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying surface height %s (%d).", __FUNCTION__, strerror(-err),
                 err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf);
@@ -493,6 +523,7 @@
     if(err != NO_ERROR) {
         jniThrowException(env, "java/lang/UnsupportedOperationException;",
             "Error while querying surface usage bits");
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return usage;
@@ -513,6 +544,7 @@
     if(err != NO_ERROR) {
         jniThrowException(env, "java/lang/UnsupportedOperationException;",
             "Error while disconnecting surface");
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
@@ -532,6 +564,7 @@
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying SurfaceTexture width %s (%d)", __FUNCTION__,
                 strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
 
@@ -539,6 +572,7 @@
     if(err != NO_ERROR) {
         ALOGE("%s: Error while querying SurfaceTexture height %s (%d)", __FUNCTION__,
                 strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
 
@@ -559,6 +593,7 @@
     status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
     if (err != NO_ERROR) {
         ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
@@ -609,6 +644,7 @@
     status_t err = native_window_set_buffers_format(anw.get(), pixelFormat);
     if (err != NO_ERROR) {
         ALOGE("%s: Error while setting surface format %s (%d).", __FUNCTION__, strerror(-err), err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
@@ -629,6 +665,7 @@
     if (err != NO_ERROR) {
         ALOGE("%s: Error while setting surface user dimens %s (%d).", __FUNCTION__, strerror(-err),
                 err);
+        OVERRIDE_SURFACE_ERROR(err);
         return err;
     }
     return NO_ERROR;
diff --git a/core/jni/android_security_Scrypt.cpp b/core/jni/android_security_Scrypt.cpp
new file mode 100644
index 0000000..3350804
--- /dev/null
+++ b/core/jni/android_security_Scrypt.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Scrypt"
+
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+
+#include <android_runtime/Log.h>
+#include <utils/Timers.h>
+#include <utils/misc.h>
+#include <utils/String8.h>
+#include <utils/Log.h>
+
+extern "C" {
+#include "crypto_scrypt.h"
+}
+
+namespace android {
+
+static jbyteArray android_security_Scrypt_nativeScrypt(JNIEnv* env, jobject, jbyteArray password, jbyteArray salt, jint N, jint r, jint p, jint outLen) {
+    if (!password || !salt) {
+        return NULL;
+    }
+
+    int passwordLen = env->GetArrayLength(password);
+    int saltLen = env->GetArrayLength(salt);
+    jbyteArray ret = env->NewByteArray(outLen);
+
+    jbyte* passwordPtr = (jbyte*)env->GetByteArrayElements(password, NULL);
+    jbyte* saltPtr = (jbyte*)env->GetByteArrayElements(salt, NULL);
+    jbyte* retPtr = (jbyte*)env->GetByteArrayElements(ret, NULL);
+
+    int rc = crypto_scrypt((const uint8_t *)passwordPtr, passwordLen,
+                       (const uint8_t *)saltPtr, saltLen, N, r, p, (uint8_t *)retPtr,
+                       outLen);
+    env->ReleaseByteArrayElements(password, passwordPtr, JNI_ABORT);
+    env->ReleaseByteArrayElements(salt, saltPtr, JNI_ABORT);
+    env->ReleaseByteArrayElements(ret, retPtr, 0);
+
+    if (!rc) {
+        return ret;
+    } else {
+        SLOGE("scrypt failed");
+        return NULL;
+    }
+}
+
+static const JNINativeMethod sMethods[] = {
+     /* name, signature, funcPtr */
+    {"nativeScrypt", "([B[BIIII)[B", (void*)android_security_Scrypt_nativeScrypt},
+};
+
+int register_android_security_Scrypt(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "android/security/Scrypt",
+                                    sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ea0b825..6467976 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -228,7 +228,7 @@
     ];
 
     optional android.service.print.PrintServiceDumpProto print = 3010 [
-        (section).type = SECTION_DUMPSYS,
+        (section).type = SECTION_NONE, // Turn off until we get approval for it.
         (section).args = "print --proto"
     ];
 
diff --git a/core/proto/android/service/print.proto b/core/proto/android/service/print.proto
index f783b86..994814b 100644
--- a/core/proto/android/service/print.proto
+++ b/core/proto/android/service/print.proto
@@ -75,7 +75,7 @@
     repeated PrintJobInfoProto print_jobs = 1;
 
     // Files used by these print jobs
-    repeated string print_job_files = 2;
+    repeated string print_job_files = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     // Approved print services
     repeated android.content.ComponentNameProto approved_services = 3;
@@ -101,7 +101,7 @@
 }
 
 message PrinterInfoProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
 
     // The id of the printer
     optional PrinterIdProto id = 1;
@@ -123,7 +123,7 @@
         STATUS_UNAVAILABLE = 3;
     }
     // The status of the printer
-    optional Status status = 3;
+    optional Status status = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     // The description of the printer
     optional string description = 4;
@@ -171,13 +171,13 @@
 }
 
 message PrinterIdProto {
-    option (android.msg_privacy).dest = DEST_AUTOMATIC;
+    option (android.msg_privacy).dest = DEST_EXPLICIT;
 
     // Component name of the service that reported the printer
-    optional android.content.ComponentNameProto service_name = 1;
+    optional android.content.ComponentNameProto service_name = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     // Local id of the printer
-    optional string local_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
+    optional string local_id = 2;
 }
 
 message ActivePrintServiceProto {
@@ -331,7 +331,7 @@
     optional string label = 1 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     // Id of the job
-    optional string print_job_id = 2;
+    optional string print_job_id = 2 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     enum State {
         // Unknown state
@@ -366,7 +366,7 @@
     optional PrinterIdProto printer = 4;
 
     // Tag assigned to the job
-    optional string tag = 5;
+    optional string tag = 5 [ (android.privacy).dest = DEST_EXPLICIT ];
 
     // Time the job was created
     optional int64 creation_time = 6;
@@ -401,4 +401,4 @@
 
     // The print job
     optional PrintJobInfoProto print_job = 2;
-}
\ No newline at end of file
+}
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 00dc22e..31abf92 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -59,23 +59,131 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- *  Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
+ *  <p>A class for converting encoded images (like {@code PNG}, {@code JPEG},
+ *  {@code WEBP}, {@code GIF}, or {@code HEIF}) into {@link Drawable} or
+ *  {@link Bitmap} objects.
+ *
+ *  <p>To use it, first create a {@link Source Source} using one of the
+ *  {@code createSource} overloads. For example, to decode from a {@link File}, call
+ *  {@link #createSource(File)} and pass the result to {@link #decodeDrawable(Source)}
+ *  or {@link #decodeBitmap(Source)}:
+ *
+ *  <pre class="prettyprint">
+ *  File file = new File(...);
+ *  ImageDecoder.Source source = ImageDecoder.createSource(file);
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source);
+ *  </pre>
+ *
+ *  <p>To change the default settings, pass the {@link Source Source} and an
+ *  {@link OnHeaderDecodedListener OnHeaderDecodedListener} to
+ *  {@link #decodeDrawable(Source, OnHeaderDecodedListener)} or
+ *  {@link #decodeBitmap(Source, OnHeaderDecodedListener)}. For example, to
+ *  create a sampled image with half the width and height of the original image,
+ *  call {@link #setTargetSampleSize setTargetSampleSize(2)} inside
+ *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}:
+ *
+ *  <pre class="prettyprint">
+ *  OnHeaderDecodedListener listener = new OnHeaderDecodedListener() {
+ *      public void onHeaderDecoded(ImageDecoder decoder, ImageInfo info, Source source) {
+ *          decoder.setTargetSampleSize(2);
+ *      }
+ *  };
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, listener);
+ *  </pre>
+ *
+ *  <p>The {@link ImageInfo ImageInfo} contains information about the encoded image, like
+ *  its width and height, and the {@link Source Source} can be used to match to a particular
+ *  {@link Source Source} if a single {@link OnHeaderDecodedListener OnHeaderDecodedListener}
+ *  is used with multiple {@link Source Source} objects.
+ *
+ *  <p>The {@link OnHeaderDecodedListener OnHeaderDecodedListener} can also be implemented
+ *  as a lambda:
+ *
+ *  <pre class="prettyprint">
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -&gt; {
+ *      decoder.setTargetSampleSize(2);
+ *  });
+ *  </pre>
+ *
+ *  <p>If the encoded image is an animated {@code GIF} or {@code WEBP},
+ *  {@link #decodeDrawable decodeDrawable} will return an {@link AnimatedImageDrawable}. To
+ *  start its animation, call {@link AnimatedImageDrawable#start AnimatedImageDrawable.start()}:
+ *
+ *  <pre class="prettyprint">
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source);
+ *  if (drawable instanceof AnimatedImageDrawable) {
+ *      ((AnimatedImageDrawable) drawable).start();
+ *  }
+ *  </pre>
+ *
+ *  <p>By default, a {@link Bitmap} created by {@link ImageDecoder} (including
+ *  one that is inside a {@link Drawable}) will be immutable (i.e.
+ *  {@link Bitmap#isMutable Bitmap.isMutable()} returns {@code false}), and it
+ *  will typically have {@code Config} {@link Bitmap.Config#HARDWARE}. Although
+ *  these properties can be changed with {@link #setMutableRequired setMutableRequired(true)}
+ *  (which is only compatible with {@link #decodeBitmap(Source)} and
+ *  {@link #decodeBitmap(Source, OnHeaderDecodedListener)}) and {@link #setAllocator},
+ *  it is also possible to apply custom effects regardless of the mutability of
+ *  the final returned object by passing a {@link PostProcessor} to
+ *  {@link #setPostProcessor setPostProcessor}. A {@link PostProcessor} can also be a lambda:
+ *
+ *  <pre class="prettyprint">
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -&gt; {
+ *      decoder.setPostProcessor((canvas) -&gt; {
+ *              // This will create rounded corners.
+ *              Path path = new Path();
+ *              path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+ *              int width = canvas.getWidth();
+ *              int height = canvas.getHeight();
+ *              path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+ *              Paint paint = new Paint();
+ *              paint.setAntiAlias(true);
+ *              paint.setColor(Color.TRANSPARENT);
+ *              paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ *              canvas.drawPath(path, paint);
+ *              return PixelFormat.TRANSLUCENT;
+ *      });
+ *  });
+ *  </pre>
+ *
+ *  <p>If the encoded image is incomplete or contains an error, or if an
+ *  {@link Exception} occurs during decoding, a {@link DecodeException DecodeException}
+ *  will be thrown. In some cases, the {@link ImageDecoder} may have decoded part of
+ *  the image. In order to display the partial image, an
+ *  {@link OnPartialImageListener OnPartialImageListener} must be passed to
+ *  {@link #setOnPartialImageListener setOnPartialImageListener}. For example:
+ *
+ *  <pre class="prettyprint">
+ *  Drawable drawable = ImageDecoder.decodeDrawable(source, (decoder, info, src) -&gt; {
+ *      decoder.setOnPartialImageListener((DecodeException e) -&gt; {
+ *              // Returning true indicates to create a Drawable or Bitmap even
+ *              // if the whole image could not be decoded. Any remaining lines
+ *              // will be blank.
+ *              return true;
+ *      });
+ *  });
+ *  </pre>
  */
 public final class ImageDecoder implements AutoCloseable {
     /** @hide **/
     public static int sApiLevel;
 
     /**
-     *  Source of the encoded image data.
+     *  Source of encoded image data.
      *
-     *  <p>This object references the data that will be used to decode a
-     *  Drawable or Bitmap in {@link #decodeDrawable} or {@link #decodeBitmap}.
-     *  Constructing a {@code Source} (with one of the overloads of
-     *  {@code createSource}) can be done on any thread because the construction
-     *  simply captures values. The real work is done in decodeDrawable or
-     *  decodeBitmap.</p>
+     *  <p>References the data that will be used to decode a {@link Drawable}
+     *  or {@link Bitmap} in {@link #decodeDrawable decodeDrawable} or
+     *  {@link #decodeBitmap decodeBitmap}. Constructing a {@code Source} (with
+     *  one of the overloads of {@code createSource}) can be done on any thread
+     *  because the construction simply captures values. The real work is done
+     *  in {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}.
      *
-     *  <p>Further, a Source object can be reused with different settings, or
+     *  <p>A {@code Source} object can be reused to create multiple versions of the
+     *  same image. For example, to decode a full size image and its thumbnail,
+     *  the same {@code Source} can be used once with no
+     *  {@link OnHeaderDecodedListener OnHeaderDecodedListener} and once with an
+     *  implementation of {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
+     *  that calls {@link #setTargetSize} with smaller dimensions. One {@code Source}
      *  even used simultaneously in multiple threads.</p>
      */
     public static abstract class Source {
@@ -418,7 +526,7 @@
     }
 
     /**
-     *  Contains information about the encoded image.
+     *  Information about an encoded image.
      */
     public static class ImageInfo {
         private final Size mSize;
@@ -448,8 +556,8 @@
         /**
          * Whether the image is animated.
          *
-         * <p>Calling {@link #decodeDrawable} will return an
-         * {@link AnimatedImageDrawable}.</p>
+         * <p>If {@code true}, {@link #decodeDrawable decodeDrawable} will
+         * return an {@link AnimatedImageDrawable}.</p>
          */
         public boolean isAnimated() {
             return mDecoder.mAnimated;
@@ -475,19 +583,25 @@
     public static class IncompleteException extends IOException {};
 
     /**
-     *  Optional listener supplied to {@link #decodeDrawable} or
-     *  {@link #decodeBitmap}.
+     *  Interface for changing the default settings of a decode.
      *
-     *  <p>This is necessary in order to change the default settings of the
-     *  decode.</p>
+     *  <p>Supply an instance to
+     *  {@link #decodeDrawable(Source, OnHeaderDecodedListener) decodeDrawable}
+     *  or {@link #decodeBitmap(Source, OnHeaderDecodedListener) decodeBitmap},
+     *  which will call {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}
+     *  (in the same thread) once the size is known. The implementation of
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded} can then
+     *  change the decode settings as desired.
      */
     public static interface OnHeaderDecodedListener {
         /**
-         *  Called when the header is decoded and the size is known.
+         *  Called by {@link ImageDecoder} when the header has been decoded and
+         *  the image size is known.
          *
-         *  @param decoder allows changing the default settings of the decode.
-         *  @param info Information about the encoded image.
-         *  @param source that created the decoder.
+         *  @param decoder the object performing the decode, for changing
+         *      its default settings.
+         *  @param info information about the encoded image.
+         *  @param source object that created {@code decoder}.
          */
         public void onHeaderDecoded(@NonNull ImageDecoder decoder,
                 @NonNull ImageInfo info, @NonNull Source source);
@@ -570,7 +684,7 @@
         }
 
         /**
-         *  Retrieve the {@link Source} that was interrupted.
+         *  Retrieve the {@link Source Source} that was interrupted.
          *
          *  <p>This can be used for equality checking to find the Source which
          *  failed to completely decode.</p>
@@ -595,25 +709,36 @@
     }
 
     /**
-     *  Optional listener supplied to the ImageDecoder.
+     *  Interface for inspecting a {@link DecodeException DecodeException}
+     *  and potentially preventing it from being thrown.
      *
-     *  Without this listener, errors will throw {@link java.io.IOException}.
+     *  <p>If an instance is passed to
+     *  {@link #setOnPartialImageListener setOnPartialImageListener}, a
+     *  {@link DecodeException DecodeException} that would otherwise have been
+     *  thrown can be inspected inside
+     *  {@link OnPartialImageListener#onPartialImage onPartialImage}.
+     *  If {@link OnPartialImageListener#onPartialImage onPartialImage} returns
+     *  {@code true}, a partial image will be created.
      */
     public static interface OnPartialImageListener {
         /**
-         *  Called when there is only a partial image to display.
+         *  Called by {@link ImageDecoder} when there is only a partial image to
+         *  display.
          *
-         *  If decoding is interrupted after having decoded a partial image,
-         *  this listener lets the client know that and allows them to
-         *  optionally finish the rest of the decode/creation process to create
-         *  a partial {@link Drawable}/{@link Bitmap}.
+         *  <p>If decoding is interrupted after having decoded a partial image,
+         *  this method will be called. The implementation can inspect the
+         *  {@link DecodeException DecodeException} and optionally finish the
+         *  rest of the decode creation process to create a partial {@link Drawable}
+         *  or {@link Bitmap}.
          *
-         *  @param e containing information about the decode interruption.
-         *  @return True to create and return a {@link Drawable}/{@link Bitmap}
-         *      with partial data. False (which is the default) to abort the
-         *      decode and throw {@code e}.
+         *  @param exception exception containing information about the
+         *      decode interruption.
+         *  @return {@code true} to create and return a {@link Drawable} or
+         *      {@link Bitmap} with partial data. {@code false} (which is the
+         *      default) to abort the decode and throw {@code e}. Any undecoded
+         *      lines in the image will be blank.
          */
-        boolean onPartialImage(@NonNull DecodeException e);
+        boolean onPartialImage(@NonNull DecodeException exception);
     };
 
     // Fields
@@ -679,12 +804,13 @@
     }
 
     /**
-     * Create a new {@link Source} from a resource.
+     * Create a new {@link Source Source} from a resource.
      *
      * @param res the {@link Resources} object containing the image data.
      * @param resId resource ID of the image data.
      * @return a new Source object, which can be passed to
-     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
+     *      {@link #decodeDrawable decodeDrawable} or
+     *      {@link #decodeBitmap decodeBitmap}.
      */
     @AnyThread
     @NonNull
@@ -694,12 +820,20 @@
     }
 
     /**
-     * Create a new {@link Source} from a {@link android.net.Uri}.
+     * Create a new {@link Source Source} from a {@link android.net.Uri}.
+     *
+     * <h5>Accepts the following URI schemes:</h5>
+     * <ul>
+     * <li>content ({@link ContentResolver#SCHEME_CONTENT})</li>
+     * <li>android.resource ({@link ContentResolver#SCHEME_ANDROID_RESOURCE})</li>
+     * <li>file ({@link ContentResolver#SCHEME_FILE})</li>
+     * </ul>
      *
      * @param cr to retrieve from.
      * @param uri of the image file.
      * @return a new Source object, which can be passed to
-     *      {@link #decodeDrawable} or {@link #decodeBitmap}.
+     *      {@link #decodeDrawable decodeDrawable} or
+     *      {@link #decodeBitmap decodeBitmap}.
      */
     @AnyThread
     @NonNull
@@ -721,7 +855,7 @@
     }
 
     /**
-     * Create a new {@link Source} from a file in the "assets" directory.
+     * Create a new {@link Source Source} from a file in the "assets" directory.
      */
     @AnyThread
     @NonNull
@@ -730,12 +864,15 @@
     }
 
     /**
-     * Create a new {@link Source} from a byte array.
+     * Create a new {@link Source Source} from a byte array.
      *
      * @param data byte array of compressed image data.
      * @param offset offset into data for where the decoder should begin
      *      parsing.
      * @param length number of bytes, beginning at offset, to parse.
+     * @return a new Source object, which can be passed to
+     *      {@link #decodeDrawable decodeDrawable} or
+     *      {@link #decodeBitmap decodeBitmap}.
      * @throws NullPointerException if data is null.
      * @throws ArrayIndexOutOfBoundsException if offset and length are
      *      not within data.
@@ -767,16 +904,20 @@
     }
 
     /**
-     * Create a new {@link Source} from a {@link java.nio.ByteBuffer}.
+     * Create a new {@link Source Source} from a {@link java.nio.ByteBuffer}.
      *
-     * <p>Decoding will start from {@link java.nio.ByteBuffer#position()}. The
-     * position of {@code buffer} will not be affected.</p>
+     * <p>Decoding will start from {@link java.nio.ByteBuffer#position() buffer.position()}.
+     * The position of {@code buffer} will not be affected.</p>
      *
-     * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable}, and
-     * the encoded image is animated, the returned {@link AnimatedImageDrawable}
+     * <p>Note: If this {@code Source} is passed to {@link #decodeDrawable decodeDrawable},
+     * and the encoded image is animated, the returned {@link AnimatedImageDrawable}
      * will continue reading from the {@code buffer}, so its contents must not
      * be modified, even after the {@code AnimatedImageDrawable} is returned.
      * {@code buffer}'s contents should never be modified during decode.</p>
+     *
+     * @return a new Source object, which can be passed to
+     *      {@link #decodeDrawable decodeDrawable} or
+     *      {@link #decodeBitmap decodeBitmap}.
      */
     @AnyThread
     @NonNull
@@ -812,7 +953,11 @@
     }
 
     /**
-     * Create a new {@link Source} from a {@link java.io.File}.
+     * Create a new {@link Source Source} from a {@link java.io.File}.
+     *
+     * @return a new Source object, which can be passed to
+     *      {@link #decodeDrawable decodeDrawable} or
+     *      {@link #decodeBitmap decodeBitmap}.
      */
     @AnyThread
     @NonNull
@@ -863,14 +1008,17 @@
      *  Specify the size of the output {@link Drawable} or {@link Bitmap}.
      *
      *  <p>By default, the output size will match the size of the encoded
-     *  image, which can be retrieved from the {@link ImageInfo} in
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  image, which can be retrieved from the {@link ImageInfo ImageInfo} in
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
+     *
+     *  <p>This will sample or scale the output to an arbitrary size that may
+     *  be smaller or larger than the encoded size.</p>
      *
      *  <p>Only the last call to this or {@link #setTargetSampleSize} is
      *  respected.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      *  @param width must be greater than 0.
      *  @param height must be greater than 0.
@@ -924,13 +1072,13 @@
      *  Set the target size with a sampleSize.
      *
      *  <p>By default, the output size will match the size of the encoded
-     *  image, which can be retrieved from the {@link ImageInfo} in
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  image, which can be retrieved from the {@link ImageInfo ImageInfo} in
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      *  <p>Requests the decoder to subsample the original image, returning a
-     *  smaller image to save memory. The sample size is the number of pixels
+     *  smaller image to save memory. The {@code sampleSize} is the number of pixels
      *  in either dimension that correspond to a single pixel in the output.
-     *  For example, sampleSize == 4 returns an image that is 1/4 the
+     *  For example, {@code sampleSize == 4} returns an image that is 1/4 the
      *  width/height of the original, and 1/16 the number of pixels.</p>
      *
      *  <p>Must be greater than or equal to 1.</p>
@@ -938,7 +1086,7 @@
      *  <p>Only the last call to this or {@link #setTargetSize} is respected.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      *  @param sampleSize Sampling rate of the encoded image.
      */
@@ -960,7 +1108,8 @@
      *  Will typically result in a {@link Bitmap.Config#HARDWARE}
      *  allocation, but may be software for small images. In addition, this will
      *  switch to software when HARDWARE is incompatible, e.g.
-     *  {@link #setMutableRequired}, {@link #setDecodeAsAlphaMaskEnabled}.
+     *  {@link #setMutableRequired setMutableRequired(true)} or
+     *  {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)}.
      */
     public static final int ALLOCATOR_DEFAULT = 0;
 
@@ -983,9 +1132,10 @@
      *  Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
      *
      *  When this is combined with incompatible options, like
-     *  {@link #setMutableRequired} or {@link #setDecodeAsAlphaMaskEnabled},
-     *  {@link #decodeDrawable} / {@link #decodeBitmap} will throw an
-     *  {@link java.lang.IllegalStateException}.
+     *  {@link #setMutableRequired setMutableRequired(true)} or
+     *  {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)},
+     *  {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}
+     *  will throw an {@link java.lang.IllegalStateException}.
      */
     public static final int ALLOCATOR_HARDWARE = 3;
 
@@ -1002,7 +1152,7 @@
      *  <p>This is ignored for animated drawables.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      *  @param allocator Type of allocator to use.
      */
@@ -1029,13 +1179,13 @@
      *  {@link android.view.View} system (i.e. to a {@link Canvas}). Calling
      *  this method with a value of {@code true} will result in
      *  {@link #decodeBitmap} returning a {@link Bitmap} with unpremultiplied
-     *  pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with
-     *  {@link #decodeDrawable}; attempting to decode an unpremultiplied
-     *  {@link Drawable} will throw an {@link java.lang.IllegalStateException}.
-     *  </p>
+     *  pixels. See {@link Bitmap#isPremultiplied Bitmap.isPremultiplied()}.
+     *  This is incompatible with {@link #decodeDrawable decodeDrawable};
+     *  attempting to decode an unpremultiplied {@link Drawable} will throw an
+     *  {@link java.lang.IllegalStateException}. </p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
     public void setUnpremultipliedRequired(boolean unpremultipliedRequired) {
         mUnpremultipliedRequired = unpremultipliedRequired;
@@ -1072,6 +1222,9 @@
      *  {@link Bitmap}. For a {@code Drawable} or an immutable {@code Bitmap},
      *  this is the only way to process the image after decoding.</p>
      *
+     *  <p>If combined with {@link #setTargetSize} and/or {@link #setCrop},
+     *  {@link PostProcessor#onPostProcess} occurs last.</p>
+     *
      *  <p>If set on a nine-patch image, the nine-patch data is ignored.</p>
      *
      *  <p>For an animated image, the drawing commands drawn on the
@@ -1079,11 +1232,11 @@
      *  frame.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      */
-    public void setPostProcessor(@Nullable PostProcessor p) {
-        mPostProcessor = p;
+    public void setPostProcessor(@Nullable PostProcessor postProcessor) {
+        mPostProcessor = postProcessor;
     }
 
     /**
@@ -1098,18 +1251,18 @@
      *  Set (replace) the {@link OnPartialImageListener} on this object.
      *
      *  <p>Will be called if there is an error in the input. Without one, an
-     *  error will result in an Exception being thrown.</p>
+     *  error will result in an {@code Exception} being thrown.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      */
-    public void setOnPartialImageListener(@Nullable OnPartialImageListener l) {
-        mOnPartialImageListener = l;
+    public void setOnPartialImageListener(@Nullable OnPartialImageListener listener) {
+        mOnPartialImageListener = listener;
     }
 
     /**
-     *  Return the {@link OnPartialImageListener} currently set.
+     *  Return the {@link OnPartialImageListener OnPartialImageListener} currently set.
      */
     @Nullable
     public OnPartialImageListener getOnPartialImageListener() {
@@ -1122,14 +1275,14 @@
      *  <p>{@code subset} must be contained within the size set by
      *  {@link #setTargetSize} or the bounds of the image if setTargetSize was
      *  not called. Otherwise an {@link IllegalStateException} will be thrown by
-     *  {@link #decodeDrawable}/{@link #decodeBitmap}.</p>
+     *  {@link #decodeDrawable decodeDrawable}/{@link #decodeBitmap decodeBitmap}.</p>
      *
      *  <p>NOT intended as a replacement for
-     *  {@link BitmapRegionDecoder#decodeRegion}. This supports all formats,
-     *  but merely crops the output.</p>
+     *  {@link BitmapRegionDecoder#decodeRegion BitmapRegionDecoder.decodeRegion()}.
+     *  This supports all formats, but merely crops the output.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      */
     public void setCrop(@Nullable Rect subset) {
@@ -1151,7 +1304,7 @@
      *  rectangle during decode. Otherwise it will not be modified.
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      *
      *  @hide
      */
@@ -1162,21 +1315,22 @@
     /**
      *  Specify whether the {@link Bitmap} should be mutable.
      *
-     *  <p>By default, a {@link Bitmap} created will be immutable, but that can
-     *  be changed with this call.</p>
+     *  <p>By default, a {@link Bitmap} created by {@link #decodeBitmap decodeBitmap}
+     *  will be immutable i.e. {@link Bitmap#isMutable() Bitmap.isMutable()} returns
+     *  {@code false}. This can be changed with {@code setMutableRequired(true)}.
      *
      *  <p>Mutable Bitmaps are incompatible with {@link #ALLOCATOR_HARDWARE},
      *  because {@link Bitmap.Config#HARDWARE} Bitmaps cannot be mutable.
      *  Attempting to combine them will throw an
      *  {@link java.lang.IllegalStateException}.</p>
      *
-     *  <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable},
+     *  <p>Mutable Bitmaps are also incompatible with {@link #decodeDrawable decodeDrawable},
      *  which would require retrieving the Bitmap from the returned Drawable in
      *  order to modify. Attempting to decode a mutable {@link Drawable} will
      *  throw an {@link java.lang.IllegalStateException}.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
     public void setMutableRequired(boolean mutable) {
         mMutable = mutable;
@@ -1192,7 +1346,7 @@
     }
 
     /**
-     *  Return whether the {@link Bitmap} will be mutable.
+     *  Return whether the decoded {@link Bitmap} will be mutable.
      */
     public boolean isMutableRequired() {
         return mMutable;
@@ -1219,7 +1373,7 @@
      *  the memory used.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
     public void setConserveMemory(boolean conserveMemory) {
         mConserveMemory = conserveMemory;
@@ -1244,12 +1398,12 @@
      *  no effect.</p>
      *
      *  <p>This is incompatible with {@link #ALLOCATOR_HARDWARE}. Trying to
-     *  combine them will result in {@link #decodeDrawable}/
-     *  {@link #decodeBitmap} throwing an
+     *  combine them will result in {@link #decodeDrawable decodeDrawable}/
+     *  {@link #decodeBitmap decodeBitmap} throwing an
      *  {@link java.lang.IllegalStateException}.</p>
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
-     *  {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
     public void setDecodeAsAlphaMaskEnabled(boolean enabled) {
         mDecodeAsAlphaMask = enabled;
@@ -1304,21 +1458,22 @@
     /**
      * Specify the desired {@link ColorSpace} for the output.
      *
-     * <p>If non-null, the decoder will try to decode into this
-     * color space. If it is null, which is the default, or the request cannot
-     * be met, the decoder will pick either the color space embedded in the
-     * image or the color space best suited for the requested image
-     * configuration (for instance {@link ColorSpace.Named#SRGB sRGB} for
-     * the {@link Bitmap.Config#ARGB_8888} configuration).</p>
+     * <p>If non-null, the decoder will try to decode into {@code colorSpace}.
+     * If it is null, which is the default, or the request cannot be met, the
+     * decoder will pick either the color space embedded in the image or the
+     * {@link ColorSpace} best suited for the requested image configuration
+     * (for instance {@link ColorSpace.Named#SRGB sRGB} for the
+     * {@link Bitmap.Config#ARGB_8888} configuration).</p>
      *
      * <p>{@link Bitmap.Config#RGBA_F16} always uses the
-     * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space).
+     * {@link ColorSpace.Named#LINEAR_EXTENDED_SRGB scRGB} color space.
      * Bitmaps in other configurations without an embedded color space are
      * assumed to be in the {@link ColorSpace.Named#SRGB sRGB} color space.</p>
      *
      * <p class="note">Only {@link ColorSpace.Model#RGB} color spaces are
      * currently supported. An <code>IllegalArgumentException</code> will
-     * be thrown by the decode methods when setting a non-RGB color space
+     * be thrown by {@link #decodeDrawable decodeDrawable}/
+     * {@link #decodeBitmap decodeBitmap} when setting a non-RGB color space
      * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
      *
      * <p class="note">The specified color space's transfer function must be
@@ -1328,12 +1483,20 @@
      * specified color space returns null.</p>
      *
      * <p>Like all setters on ImageDecoder, this must be called inside
-     * {@link OnHeaderDecodedListener#onHeaderDecoded}.</p>
+     * {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
     public void setTargetColorSpace(ColorSpace colorSpace) {
         mDesiredColorSpace = colorSpace;
     }
 
+    /**
+     * Closes this resource, relinquishing any underlying resources. This method
+     * is invoked automatically on objects managed by the try-with-resources
+     * statement.
+     *
+     * <p>This is an implementation detail of {@link ImageDecoder}, and should
+     * never be called manually.</p>
+     */
     @Override
     public void close() {
         mCloseGuard.close();
@@ -1421,7 +1584,7 @@
      *  Create a {@link Drawable} from a {@code Source}.
      *
      *  @param src representing the encoded image.
-     *  @param listener for learning the {@link ImageInfo} and changing any
+     *  @param listener for learning the {@link ImageInfo ImageInfo} and changing any
      *      default settings on the {@code ImageDecoder}. This will be called on
      *      the same thread as {@code decodeDrawable} before that method returns.
      *      This is required in order to change any of the default settings.
@@ -1503,8 +1666,8 @@
     /**
      *  Create a {@link Drawable} from a {@code Source}.
      *
-     *  <p>Since there is no {@link OnHeaderDecodedListener}, the default
-     *  settings will be used. In order to change any settings, call
+     *  <p>Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener},
+     *  the default settings will be used. In order to change any settings, call
      *  {@link #decodeDrawable(Source, OnHeaderDecodedListener)} instead.</p>
      *
      *  @param src representing the encoded image.
@@ -1523,7 +1686,7 @@
      *  Create a {@link Bitmap} from a {@code Source}.
      *
      *  @param src representing the encoded image.
-     *  @param listener for learning the {@link ImageInfo} and changing any
+     *  @param listener for learning the {@link ImageInfo ImageInfo} and changing any
      *      default settings on the {@code ImageDecoder}. This will be called on
      *      the same thread as {@code decodeBitmap} before that method returns.
      *      This is required in order to change any of the default settings.
@@ -1616,8 +1779,8 @@
     /**
      *  Create a {@link Bitmap} from a {@code Source}.
      *
-     *  <p>Since there is no {@link OnHeaderDecodedListener}, the default
-     *  settings will be used. In order to change any settings, call
+     *  <p>Since there is no {@link OnHeaderDecodedListener OnHeaderDecodedListener},
+     *  the default settings will be used. In order to change any settings, call
      *  {@link #decodeBitmap(Source, OnHeaderDecodedListener)} instead.</p>
      *
      *  @param src representing the encoded image.
diff --git a/graphics/java/android/graphics/PostProcessor.java b/graphics/java/android/graphics/PostProcessor.java
index b1712e9..6fed39b 100644
--- a/graphics/java/android/graphics/PostProcessor.java
+++ b/graphics/java/android/graphics/PostProcessor.java
@@ -16,25 +16,26 @@
 
 package android.graphics;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Drawable;
 
 /**
  *  Helper interface for adding custom processing to an image.
  *
- *  <p>The image being processed may be a {@link Drawable}, {@link Bitmap} or frame
- *  of an animated image produced by {@link ImageDecoder}. This is called before
- *  the requested object is returned.</p>
+ *  <p>The image being processed may be a {@link Drawable}, a {@link Bitmap}, or
+ *  a frame of an {@link AnimatedImageDrawable} produced by {@link ImageDecoder}.
+ *  This is called before the requested object is returned.</p>
  *
- *  <p>This custom processing also applies to image types that are otherwise
- *  immutable, such as {@link Bitmap.Config#HARDWARE}.</p>
+ *  <p>This custom processing can even be applied to images that will be returned
+ *  as immutable objects, such as a {@link Bitmap} with {@code Config}
+ *  {@link Bitmap.Config#HARDWARE} returned by {@link ImageDecoder}.</p>
  *
- *  <p>On an animated image, the callback will only be called once, but the drawing
- *  commands will be applied to each frame, as if the {@code Canvas} had been
- *  returned by {@link Picture#beginRecording}.<p>
+ *  <p>On an {@link AnimatedImageDrawable}, the callback will only be called once,
+ *  but the drawing commands will be applied to each frame, as if the {@link Canvas}
+ *  had been returned by {@link Picture#beginRecording Picture.beginRecording}.<p>
  *
- *  <p>Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor}.</p>
+ *  <p>Supplied to ImageDecoder via {@link ImageDecoder#setPostProcessor setPostProcessor}.</p>
  */
 public interface PostProcessor {
     /**
@@ -43,43 +44,44 @@
      *  <p>Drawing to the {@link Canvas} will behave as if the initial processing
      *  (e.g. decoding) already exists in the Canvas. An implementation can draw
      *  effects on top of this, or it can even draw behind it using
-     *  {@link PorterDuff.Mode#DST_OVER}. A common effect is to add transparency
-     *  to the corners to achieve rounded corners. That can be done with the
-     *  following code:</p>
+     *  {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER}. A common
+     *  effect is to add transparency to the corners to achieve rounded corners.
+     *  That can be done with the following code:</p>
      *
-     *  <code>
-     *      Path path = new Path();
-     *      path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
-     *      int width = canvas.getWidth();
-     *      int height = canvas.getHeight();
-     *      path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
-     *      Paint paint = new Paint();
-     *      paint.setAntiAlias(true);
-     *      paint.setColor(Color.TRANSPARENT);
-     *      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-     *      canvas.drawPath(path, paint);
-     *      return PixelFormat.TRANSLUCENT;
-     *  </code>
+     *  <pre class="prettyprint">
+     *  Path path = new Path();
+     *  path.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+     *  int width = canvas.getWidth();
+     *  int height = canvas.getHeight();
+     *  path.addRoundRect(0, 0, width, height, 20, 20, Path.Direction.CW);
+     *  Paint paint = new Paint();
+     *  paint.setAntiAlias(true);
+     *  paint.setColor(Color.TRANSPARENT);
+     *  paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+     *  canvas.drawPath(path, paint);
+     *  return PixelFormat.TRANSLUCENT;
+     *  </pre>
      *
      *
      *  @param canvas The {@link Canvas} to draw to.
      *  @return Opacity of the result after drawing.
-     *      {@link PixelFormat#UNKNOWN} means that the implementation did not
-     *      change whether the image has alpha. Return this unless you added
-     *      transparency (e.g. with the code above, in which case you should
-     *      return {@code PixelFormat.TRANSLUCENT}) or you forced the image to
-     *      be opaque (e.g. by drawing everywhere with an opaque color and
-     *      {@code PorterDuff.Mode.DST_OVER}, in which case you should return
-     *      {@code PixelFormat.OPAQUE}).
-     *      {@link PixelFormat#TRANSLUCENT} means that the implementation added
-     *      transparency. This is safe to return even if the image already had
-     *      transparency. This is also safe to return if the result is opaque,
-     *      though it may draw more slowly.
-     *      {@link PixelFormat#OPAQUE} means that the implementation forced the
-     *      image to be opaque. This is safe to return even if the image was
-     *      already opaque.
-     *      {@link PixelFormat#TRANSPARENT} (or any other integer) is not
-     *      allowed, and will result in throwing an
+     *      {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN} means that the
+     *      implementation did not change whether the image has alpha. Return
+     *      this unless you added transparency (e.g. with the code above, in
+     *      which case you should return
+     *      {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT}) or you
+     *      forced the image to be opaque (e.g. by drawing everywhere with an
+     *      opaque color and {@link PorterDuff.Mode#DST_OVER PorterDuff.Mode.DST_OVER},
+     *      in which case you should return {@link PixelFormat#OPAQUE PixelFormat.OPAQUE}).
+     *      {@link PixelFormat#TRANSLUCENT PixelFormat.TRANSLUCENT} means that
+     *      the implementation added transparency. This is safe to return even
+     *      if the image already had transparency. This is also safe to return
+     *      if the result is opaque, though it may draw more slowly.
+     *      {@link PixelFormat#OPAQUE PixelFormat.OPAQUE} means that the
+     *      implementation forced the image to be opaque. This is safe to return
+     *      even if the image was already opaque.
+     *      {@link PixelFormat#TRANSPARENT PixelFormat.TRANSPARENT} (or any other
+     *      integer) is not allowed, and will result in throwing an
      *      {@link java.lang.IllegalArgumentException}.
      */
     @PixelFormat.Opacity
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
index e4cf84a..cc80560 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
@@ -93,15 +93,17 @@
         putSymmetricCipherImpl("AES/CTR/NoPadding",
                 PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
 
-        putSymmetricCipherImpl("DESede/CBC/NoPadding",
+        if ("true".equals(System.getProperty("supports3DES"))) {
+            putSymmetricCipherImpl("DESede/CBC/NoPadding",
                 PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
-        putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
+            putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
                 PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding");
 
-        putSymmetricCipherImpl("DESede/ECB/NoPadding",
+            putSymmetricCipherImpl("DESede/ECB/NoPadding",
                 PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding");
-        putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
+            putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
                 PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding");
+        }
 
         putSymmetricCipherImpl("AES/GCM/NoPadding",
                 PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding");
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index d68a33d..5fc742a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -475,6 +475,12 @@
 
             success = true;
             return keyPair;
+        } catch (ProviderException e) {
+          if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
+              throw new SecureKeyImportUnavailableException(e);
+          } else {
+              throw e;
+          }
         } finally {
             if (!success) {
                 Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 2c45d43..9b7695d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -67,6 +67,8 @@
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
 
+        boolean supports3DES = "true".equals(System.getProperty("supports3DES"));
+
         // java.security.KeyStore
         put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStoreSpi");
 
@@ -80,16 +82,21 @@
 
         // javax.crypto.KeyGenerator
         put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
-        put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
         put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
         put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224");
         put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256");
         put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384");
         put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512");
 
+        if (supports3DES) {
+            put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
+        }
+
         // java.security.SecretKeyFactory
         putSecretKeyFactoryImpl("AES");
-        putSecretKeyFactoryImpl("DESede");
+        if (supports3DES) {
+            putSecretKeyFactoryImpl("DESede");
+        }
         putSecretKeyFactoryImpl("HmacSHA1");
         putSecretKeyFactoryImpl("HmacSHA224");
         putSecretKeyFactoryImpl("HmacSHA256");
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index fc86ca0..3e9853c 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -26,6 +26,7 @@
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyProperties;
 import android.security.keystore.KeyProtection;
+import android.security.keystore.SecureKeyImportUnavailableException;
 import android.security.keystore.WrappedKeyEntry;
 import android.util.Log;
 
@@ -755,7 +756,9 @@
             0, // FIXME fingerprint id?
             mUid,
             new KeyCharacteristics());
-        if (errorCode != KeyStore.NO_ERROR) {
+        if (errorCode == KeymasterDefs.KM_ERROR_UNIMPLEMENTED) {
+          throw new SecureKeyImportUnavailableException("Could not import wrapped key");
+        } else if (errorCode != KeyStore.NO_ERROR) {
             throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
                 + errorCode);
         }
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index c342acd..c0d0fb0 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -259,7 +259,7 @@
     private final boolean mRandomizedEncryptionRequired;
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mTrustedUserPresenceRequred;
+    private final boolean mUserPresenceRequired;
     private final byte[] mAttestationChallenge;
     private final boolean mUniqueIdIncluded;
     private final boolean mUserAuthenticationValidWhileOnBody;
@@ -291,7 +291,7 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean trustedUserPresenceRequired,
+            boolean userPresenceRequired,
             byte[] attestationChallenge,
             boolean uniqueIdIncluded,
             boolean userAuthenticationValidWhileOnBody,
@@ -339,7 +339,7 @@
         mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticationRequired = userAuthenticationRequired;
-        mTrustedUserPresenceRequred = trustedUserPresenceRequired;
+        mUserPresenceRequired = userPresenceRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
         mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
         mUniqueIdIncluded = uniqueIdIncluded;
@@ -595,8 +595,8 @@
      * Returns {@code true} if the key is authorized to be used only if a test of user presence has
      * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
      */
-    public boolean isTrustedUserPresenceRequired() {
-        return mTrustedUserPresenceRequred;
+    public boolean isUserPresenceRequired() {
+        return mUserPresenceRequired;
     }
 
     /**
@@ -673,7 +673,9 @@
     }
 
     /**
-     * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     * Returns {@code true} if the screen must be unlocked for this key to be used for encryption or
+     * signing. Decryption and signature verification will still be available when the screen is
+     * locked.
      *
      * @see Builder#setUnlockedDeviceRequired(boolean)
      */
@@ -712,7 +714,7 @@
         private boolean mRandomizedEncryptionRequired = true;
         private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
-        private boolean mTrustedUserPresenceRequired = false;
+        private boolean mUserPresenceRequired = false;
         private byte[] mAttestationChallenge = null;
         private boolean mUniqueIdIncluded = false;
         private boolean mUserAuthenticationValidWhileOnBody;
@@ -775,7 +777,7 @@
             mUserAuthenticationRequired = sourceSpec.isUserAuthenticationRequired();
             mUserAuthenticationValidityDurationSeconds =
                 sourceSpec.getUserAuthenticationValidityDurationSeconds();
-            mTrustedUserPresenceRequired = sourceSpec.isTrustedUserPresenceRequired();
+            mUserPresenceRequired = sourceSpec.isUserPresenceRequired();
             mAttestationChallenge = sourceSpec.getAttestationChallenge();
             mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
             mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
@@ -1180,8 +1182,8 @@
          * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
          */
         @NonNull
-        public Builder setTrustedUserPresenceRequired(boolean required) {
-            mTrustedUserPresenceRequired = required;
+        public Builder setUserPresenceRequired(boolean required) {
+            mUserPresenceRequired = required;
             return this;
         }
 
@@ -1289,9 +1291,10 @@
 
         /**
          * Sets whether the keystore requires the screen to be unlocked before allowing decryption
-         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
-         * while the screen is locked will fail. A locked device requires a PIN, password,
-         * fingerprint, or other trusted factor to access.
+         * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
+         * key while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+         * still be used for encryption or signature verification.
          */
         @NonNull
         public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
@@ -1324,7 +1327,7 @@
                     mRandomizedEncryptionRequired,
                     mUserAuthenticationRequired,
                     mUserAuthenticationValidityDurationSeconds,
-                    mTrustedUserPresenceRequired,
+                    mUserPresenceRequired,
                     mAttestationChallenge,
                     mUniqueIdIncluded,
                     mUserAuthenticationValidWhileOnBody,
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index f54b6de..f12a659 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -689,7 +689,11 @@
      */
     public static final int ORIGIN_UNKNOWN = 1 << 2;
 
-    /** Key was imported into the AndroidKeyStore in an encrypted wrapper */
+    /**
+     * Key was imported into the AndroidKeyStore in an encrypted wrapper. Unlike imported keys,
+     * securely imported keys can be imported without appearing as plaintext in the device's host
+     * memory.
+     */
     public static final int ORIGIN_SECURELY_IMPORTED = 1 << 3;
 
 
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 22568ce..4daf30c 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -224,7 +224,7 @@
     private final boolean mRandomizedEncryptionRequired;
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
-    private final boolean mTrustedUserPresenceRequired;
+    private final boolean mUserPresenceRequred;
     private final boolean mUserAuthenticationValidWhileOnBody;
     private final boolean mInvalidatedByBiometricEnrollment;
     private final long mBoundToSecureUserId;
@@ -244,7 +244,7 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean trustedUserPresenceRequired,
+            boolean userPresenceRequred,
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             long boundToSecureUserId,
@@ -264,7 +264,7 @@
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-        mTrustedUserPresenceRequired = trustedUserPresenceRequired;
+        mUserPresenceRequred = userPresenceRequred;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mBoundToSecureUserId = boundToSecureUserId;
@@ -446,8 +446,8 @@
      * Returns {@code true} if the key is authorized to be used only if a test of user presence has
      * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
      */
-    public boolean isTrustedUserPresenceRequired() {
-        return mTrustedUserPresenceRequired;
+    public boolean isUserPresenceRequired() {
+        return mUserPresenceRequred;
     }
 
     /**
@@ -508,7 +508,9 @@
     }
 
     /**
-     * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     * Returns {@code true} if the screen must be unlocked for this key to be used for encryption or
+     * signing. Decryption and signature verification will still be available when the screen is
+     * locked.
      *
      * @see Builder#setUnlockedDeviceRequired(boolean)
      */
@@ -532,7 +534,7 @@
         private boolean mRandomizedEncryptionRequired = true;
         private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
-        private boolean mTrustedUserPresenceRequired = false;
+        private boolean mUserPresenceRequired = false;
         private boolean mUserAuthenticationValidWhileOnBody;
         private boolean mInvalidatedByBiometricEnrollment = true;
         private boolean mUserConfirmationRequired;
@@ -841,8 +843,8 @@
          * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
          */
         @NonNull
-        public Builder setTrustedUserPresenceRequired(boolean required) {
-            mTrustedUserPresenceRequired = required;
+        public Builder setUserPresenceRequired(boolean required) {
+            mUserPresenceRequired = required;
             return this;
         }
 
@@ -929,9 +931,10 @@
 
         /**
          * Sets whether the keystore requires the screen to be unlocked before allowing decryption
-         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
-         * while the screen is locked will fail. A locked device requires a PIN, password,
-         * fingerprint, or other trusted factor to access.
+         * using this key. If this is set to {@code true}, any attempt to decrypt or sign using this
+         * key while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access. While the screen is locked, the key can
+         * still be used for encryption or signature verification.
          */
         @NonNull
         public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
@@ -958,7 +961,7 @@
                     mRandomizedEncryptionRequired,
                     mUserAuthenticationRequired,
                     mUserAuthenticationValidityDurationSeconds,
-                    mTrustedUserPresenceRequired,
+                    mUserPresenceRequired,
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
                     mBoundToSecureUserId,
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 14a9970..f829bb7 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -106,7 +106,7 @@
             args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
         }
 
-        if (spec.isTrustedUserPresenceRequired()) {
+        if (spec.isUserPresenceRequired()) {
             args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
         }
 
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index e5fdea7..911bbf8 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -101,7 +101,7 @@
         out.writeBoolean(mSpec.isUniqueIdIncluded());
         out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
         out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
-        out.writeBoolean(mSpec.isTrustedUserPresenceRequired());
+        out.writeBoolean(mSpec.isUserPresenceRequired());
     }
 
     private static Date readDateOrNull(Parcel in) {
@@ -165,7 +165,7 @@
         builder.setUniqueIdIncluded(in.readBoolean());
         builder.setUserAuthenticationValidWhileOnBody(in.readBoolean());
         builder.setInvalidatedByBiometricEnrollment(in.readBoolean());
-        builder.setTrustedUserPresenceRequired(in.readBoolean());
+        builder.setUserPresenceRequired(in.readBoolean());
         mSpec = builder.build();
     }
 
diff --git a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
new file mode 100644
index 0000000..d1cc572
--- /dev/null
+++ b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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.keystore;
+
+import android.security.KeyStore;
+import android.security.KeyStoreException;
+
+import java.security.ProviderException;
+
+/**
+ * Indicates that the Keystore does not support securely importing wrapped keys.
+ */
+public class SecureKeyImportUnavailableException extends ProviderException {
+
+    public SecureKeyImportUnavailableException() {
+        super();
+    }
+
+    public SecureKeyImportUnavailableException(String message) {
+        super(message, new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE,
+                "Secure Key Import not available"));
+    }
+
+    public SecureKeyImportUnavailableException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SecureKeyImportUnavailableException(Throwable cause) {
+        super(cause);
+    }
+}
+
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index 66a77ed..6c7e9a9 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -27,13 +27,22 @@
  */
 public class StrongBoxUnavailableException extends ProviderException {
 
-    /**
-     * @hide
-     */
+    public StrongBoxUnavailableException() {
+        super();
+    }
+
     public StrongBoxUnavailableException(String message) {
         super(message,
                 new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
         );
     }
+
+    public StrongBoxUnavailableException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public StrongBoxUnavailableException(Throwable cause) {
+        super(cause);
+    }
 }
 
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
index ad18ff8..6952060 100644
--- a/keystore/java/android/security/keystore/UserAuthArgs.java
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -32,7 +32,6 @@
     boolean isInvalidatedByBiometricEnrollment();
     boolean isUserConfirmationRequired();
     long getBoundToSpecificSecureUserId();
-    boolean isTrustedUserPresenceRequired();
+    boolean isUserPresenceRequired();
     boolean isUnlockedDeviceRequired();
-
 }
diff --git a/keystore/java/android/security/keystore/WrappedKeyEntry.java b/keystore/java/android/security/keystore/WrappedKeyEntry.java
index a8f4afe..7155686 100644
--- a/keystore/java/android/security/keystore/WrappedKeyEntry.java
+++ b/keystore/java/android/security/keystore/WrappedKeyEntry.java
@@ -21,7 +21,55 @@
 import java.security.spec.AlgorithmParameterSpec;
 
 /**
- * An {@link Entry} that holds a wrapped key.
+ * An {@link Entry} that holds a wrapped key. Wrapped keys contain encrypted key data and
+ * description information that can be used to securely import key material into a hardware-backed
+ * Keystore.
+ *
+ * <p>
+ *   The wrapped key is in DER-encoded ASN.1 format, specified by the following schema:
+ * </p>
+ *
+ * <pre>
+ *     KeyDescription ::= SEQUENCE(
+ *         keyFormat INTEGER,                   # Values from KeyFormat enum.
+ *         keyParams AuthorizationList,
+ *     )
+ *
+ *     SecureKeyWrapper ::= SEQUENCE(
+ *         version INTEGER,                     # Contains value 0
+ *         encryptedTransportKey OCTET_STRING,
+ *         initializationVector OCTET_STRING,
+ *         keyDescription KeyDescription,
+ *         encryptedKey OCTET_STRING,
+ *         tag OCTET_STRING
+ *     )
+ * </pre>
+ * <ul>
+ *     <li>keyFormat is an integer from the KeyFormat enum, defining the format of the plaintext
+ *       key material.
+ *     </li>
+ *     <li>keyParams is the characteristics of the key to be imported (as with generateKey or
+ *       importKey).  If the secure import is successful, these characteristics must be
+ *       associated with the key exactly as if the key material had been insecurely imported
+ *       with importKey. See <a href="https://developer.android.com/training/articles/security-key-attestation.html#certificate_schema">Key Attestation</a> for the AuthorizationList format.
+ *     </li>
+ *     <li>encryptedTransportKey is a 256-bit AES key, XORed with a masking key and then encrypted
+ *       in RSA-OAEP mode (SHA-256 digest, SHA-1 MGF1 digest) with the wrapping key specified by
+ *       wrappingKeyBlob.
+ *     </li>
+ *     <li>keyDescription is a KeyDescription, above.
+ *     </li>
+ *     <li>encryptedKey is the key material of the key to be imported, in format keyFormat, and
+ *       encrypted with encryptedEphemeralKey in AES-GCM mode, with the DER-encoded
+ *       representation of keyDescription provided as additional authenticated data.
+ *     </li>
+ *     <li>tag is the tag produced by the AES-GCM encryption of encryptedKey.
+ *     </li>
+ *</ul>
+ *
+ * <p>
+ *     Imported wrapped keys will have KeymasterDefs.KM_ORIGIN_SECURELY_IMPORTED
+ * </p>
  */
 public class WrappedKeyEntry implements Entry {
 
@@ -30,6 +78,14 @@
     private final String mTransformation;
     private final AlgorithmParameterSpec mAlgorithmParameterSpec;
 
+    /**
+     * Constructs a {@link WrappedKeyEntry} with a binary wrapped key.
+     *
+     * @param wrappedKeyBytes ASN.1 DER encoded wrapped key
+     * @param wrappingKeyAlias identifies the private key that can unwrap the wrapped key
+     * @param transformation used to unwrap the key. ex: "RSA/ECB/OAEPPadding"
+     * @param algorithmParameterSpec spec for the private key used to unwrap the wrapped key
+     */
     public WrappedKeyEntry(byte[] wrappedKeyBytes, String wrappingKeyAlias, String transformation,
             AlgorithmParameterSpec algorithmParameterSpec) {
         mWrappedKeyBytes = wrappedKeyBytes;
@@ -54,3 +110,4 @@
         return mAlgorithmParameterSpec;
     }
 }
+
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 35790b6..592a6e6 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -168,6 +168,7 @@
         "pipeline/skia/ReorderBarrierDrawables.cpp",
         "pipeline/skia/ShaderCache.cpp",
         "pipeline/skia/SkiaDisplayList.cpp",
+        "pipeline/skia/SkiaMemoryTracer.cpp",
         "pipeline/skia/SkiaOpenGLPipeline.cpp",
         "pipeline/skia/SkiaOpenGLReadback.cpp",
         "pipeline/skia/SkiaPipeline.cpp",
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
new file mode 100644
index 0000000..ee99622
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkiaMemoryTracer.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+SkiaMemoryTracer::SkiaMemoryTracer(std::vector<ResourcePair> resourceMap, bool itemizeType)
+            : mResourceMap(resourceMap)
+            , mItemizeType(itemizeType)
+            , mTotalSize("bytes", 0)
+            , mPurgeableSize("bytes", 0) {}
+
+SkiaMemoryTracer::SkiaMemoryTracer(const char* categoryKey, bool itemizeType)
+            : mCategoryKey(categoryKey)
+            , mItemizeType(itemizeType)
+            , mTotalSize("bytes", 0)
+            , mPurgeableSize("bytes", 0) {}
+
+const char* SkiaMemoryTracer::mapName(const char* resourceName) {
+    for (auto& resource : mResourceMap) {
+        if (SkStrContains(resourceName, resource.first)) {
+            return resource.second;
+        }
+    }
+    return nullptr;
+}
+
+void SkiaMemoryTracer::processElement() {
+    if(!mCurrentElement.empty()) {
+        // Only count elements that contain "size", other values just provide metadata.
+        auto sizeResult = mCurrentValues.find("size");
+        if (sizeResult != mCurrentValues.end()) {
+            mTotalSize.value += sizeResult->second.value;
+            mTotalSize.count++;
+        } else {
+            mCurrentElement.clear();
+            mCurrentValues.clear();
+            return;
+        }
+
+        // find the purgeable size if one exists
+        auto purgeableResult = mCurrentValues.find("purgeable_size");
+        if (purgeableResult != mCurrentValues.end()) {
+            mPurgeableSize.value += purgeableResult->second.value;
+            mPurgeableSize.count++;
+        }
+
+        // find the type if one exists
+        const char* type;
+        auto typeResult = mCurrentValues.find("type");
+        if (typeResult != mCurrentValues.end()) {
+            type = typeResult->second.units;
+        } else if (mItemizeType) {
+            type = "Other";
+        }
+
+        // compute the type if we are itemizing or use the default "size" if we are not
+        const char* key = (mItemizeType) ? type : sizeResult->first;
+        SkASSERT(key != nullptr);
+
+        // compute the top level element name using either the map or category key
+        const char* resourceName = mapName(mCurrentElement.c_str());
+        if (mCategoryKey != nullptr) {
+            // find the category if one exists
+            auto categoryResult = mCurrentValues.find(mCategoryKey);
+            if (categoryResult != mCurrentValues.end()) {
+                resourceName = categoryResult->second.units;
+            } else if (mItemizeType) {
+                resourceName = "Other";
+            }
+        }
+
+        // if we don't have a resource name then we don't know how to label the
+        // data and should abort.
+        if (resourceName == nullptr) {
+            mCurrentElement.clear();
+            mCurrentValues.clear();
+            return;
+        }
+
+        auto result = mResults.find(resourceName);
+        if (result != mResults.end()) {
+            auto& resourceValues = result->second;
+            typeResult = resourceValues.find(key);
+            if (typeResult != resourceValues.end()) {
+                SkASSERT(sizeResult->second.units == typeResult->second.units);
+                typeResult->second.value += sizeResult->second.value;
+                typeResult->second.count++;
+            } else {
+                resourceValues.insert({key, sizeResult->second});
+            }
+        } else {
+            mCurrentValues.clear();
+            mCurrentValues.insert({key, sizeResult->second});
+            mResults.insert({resourceName, mCurrentValues});
+        }
+    }
+
+    mCurrentElement.clear();
+    mCurrentValues.clear();
+}
+
+void SkiaMemoryTracer::dumpNumericValue(const char* dumpName, const char* valueName,
+                                        const char* units, uint64_t value) {
+    if (mCurrentElement != dumpName) {
+        processElement();
+        mCurrentElement = dumpName;
+    }
+    mCurrentValues.insert({valueName, {units, value}});
+}
+
+void SkiaMemoryTracer::logOutput(String8& log) {
+    // process any remaining elements
+    processElement();
+
+    for (const auto& namedItem : mResults) {
+        if (mItemizeType) {
+            log.appendFormat("  %s:\n", namedItem.first.c_str());
+            for (const auto& typedValue : namedItem.second) {
+                TraceValue traceValue = convertUnits(typedValue.second);
+                const char* entry = (traceValue.count > 1) ? "entries" : "entry";
+                log.appendFormat("    %s: %.2f %s (%d %s)\n", typedValue.first,
+                                 traceValue.value, traceValue.units, traceValue.count, entry);
+            }
+        } else {
+            auto result = namedItem.second.find("size");
+            if (result != namedItem.second.end()) {
+                TraceValue traceValue = convertUnits(result->second);
+                const char* entry = (traceValue.count > 1) ? "entries" : "entry";
+                log.appendFormat("  %s: %.2f %s (%d %s)\n", namedItem.first.c_str(),
+                                 traceValue.value, traceValue.units, traceValue.count, entry);
+            }
+        }
+    }
+}
+
+void SkiaMemoryTracer::logTotals(String8& log) {
+    TraceValue total = convertUnits(mTotalSize);
+    TraceValue purgeable = convertUnits(mPurgeableSize);
+    log.appendFormat("  %.0f bytes, %.2f %s (%.2f %s is purgeable)\n", mTotalSize.value,
+                     total.value, total.units, purgeable.value, purgeable.units);
+}
+
+SkiaMemoryTracer::TraceValue SkiaMemoryTracer::convertUnits(const TraceValue& value) {
+    TraceValue output(value);
+    if (SkString("bytes") == SkString(output.units) && output.value >= 1024) {
+        output.value = output.value / 1024.0f;
+        output.units = "KB";
+    }
+    if (SkString("KB") == SkString(output.units) && output.value >= 1024) {
+        output.value = output.value / 1024.0f;
+        output.units = "MB";
+    }
+    return output;
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaMemoryTracer.h b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
new file mode 100644
index 0000000..abf1f4b
--- /dev/null
+++ b/libs/hwui/pipeline/skia/SkiaMemoryTracer.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <SkString.h>
+#include <SkTraceMemoryDump.h>
+#include <utils/String8.h>
+#include <unordered_map>
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+typedef std::pair<const char*, const char*> ResourcePair;
+
+class SkiaMemoryTracer : public SkTraceMemoryDump {
+public:
+    SkiaMemoryTracer(std::vector<ResourcePair> resourceMap, bool itemizeType);
+    SkiaMemoryTracer(const char* categoryKey, bool itemizeType);
+    ~SkiaMemoryTracer() override {}
+
+    void logOutput(String8& log);
+    void logTotals(String8& log);
+
+    void dumpNumericValue(const char* dumpName, const char* valueName, const char* units,
+                          uint64_t value) override;
+
+    void dumpStringValue(const char* dumpName, const char* valueName, const char* value) override {
+        // for convenience we just store this in the same format as numerical values
+        dumpNumericValue(dumpName, valueName, value, 0);
+    }
+
+    LevelOfDetail getRequestedDetails() const override {
+        return SkTraceMemoryDump::kLight_LevelOfDetail;
+    }
+
+    bool shouldDumpWrappedObjects() const override { return true; }
+    void setMemoryBacking(const char*, const char*, const char*) override { }
+    void setDiscardableMemoryBacking(const char*, const SkDiscardableMemory&) override { }
+
+private:
+    struct TraceValue {
+        TraceValue(const char* units, uint64_t value) : units(units), value(value), count(1) {}
+        TraceValue(const TraceValue& v) : units(v.units), value(v.value), count(v.count) {}
+
+        const char* units;
+        float value;
+        int count;
+    };
+
+    const char* mapName(const char* resourceName);
+    void processElement();
+    TraceValue convertUnits(const TraceValue& value);
+
+    const std::vector<ResourcePair> mResourceMap;
+    const char* mCategoryKey = nullptr;
+    const bool mItemizeType;
+
+    // variables storing the size of all elements being dumped
+    TraceValue mTotalSize;
+    TraceValue mPurgeableSize;
+
+    // variables storing information on the current node being dumped
+    std::string mCurrentElement;
+    std::unordered_map<const char*, TraceValue> mCurrentValues;
+
+    // variable that stores the final format of the data after the individual elements are processed
+    std::unordered_map<std::string, std::unordered_map<const char*, TraceValue>> mResults;
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
\ No newline at end of file
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 907f2d2..32d4c77 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -20,10 +20,12 @@
 #include "Properties.h"
 #include "RenderThread.h"
 #include "pipeline/skia/ShaderCache.h"
+#include "pipeline/skia/SkiaMemoryTracer.h"
 #include "renderstate/RenderState.h"
 
 #include <GrContextOptions.h>
 #include <SkExecutor.h>
+#include <SkGraphics.h>
 #include <gui/Surface.h>
 #include <math.h>
 #include <set>
@@ -178,12 +180,29 @@
         return;
     }
 
-    size_t bytesCached;
-    mGrContext->getResourceCacheUsage(nullptr, &bytesCached);
+    log.appendFormat("Font Cache (CPU):\n");
+    log.appendFormat("  Size: %.2f kB \n", SkGraphics::GetFontCacheUsed() / 1024.0f);
+    log.appendFormat("  Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
 
-    log.appendFormat("Caches:\n");
+    log.appendFormat("CPU Caches:\n");
+    std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
+            {"skia/sk_resource_cache/bitmap_", "Bitmaps"},
+            {"skia/sk_resource_cache/rrect-blur_", "Masks"},
+            {"skia/sk_resource_cache/rects-blur_", "Masks"},
+            {"skia/sk_resource_cache/tessellated", "Shadows"},
+    };
+    skiapipeline::SkiaMemoryTracer cpuTracer(cpuResourceMap, false);
+    SkGraphics::DumpMemoryStatistics(&cpuTracer);
+    cpuTracer.logOutput(log);
+
+    log.appendFormat("GPU Caches:\n");
+    skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
+    mGrContext->dumpMemoryStatistics(&gpuTracer);
+    gpuTracer.logOutput(log);
+
+    log.appendFormat("Other Caches:\n");
     log.appendFormat("                         Current / Maximum\n");
-    log.appendFormat("  VectorDrawableAtlas  %6.2f kB / %6.2f kB (entries = %zu)\n", 0.0f, 0.0f,
+    log.appendFormat("  VectorDrawableAtlas  %6.2f kB / %6.2f KB (entries = %zu)\n", 0.0f, 0.0f,
                      (size_t)0);
 
     if (renderState) {
@@ -200,14 +219,12 @@
                              layer->getHeight());
             layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
         }
-        log.appendFormat("  Layers Total         %6.2f kB (numLayers = %zu)\n",
+        log.appendFormat("  Layers Total         %6.2f KB (numLayers = %zu)\n",
                          layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
     }
 
-    log.appendFormat("Total memory usage:\n");
-    log.appendFormat("  %zu bytes, %.2f MB (%.2f MB is purgeable)\n", bytesCached,
-                     bytesCached / 1024.0f / 1024.0f,
-                     mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f);
+    log.appendFormat("Total GPU memory usage:\n");
+    gpuTracer.logTotals(log);
 }
 
 } /* namespace renderthread */
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 5173743..7ac1529 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -993,6 +993,9 @@
      * active. The license server returns a secure stop release response
      * message to the app which then deletes the secure stop from persistent
      * memory using {@link #releaseSecureStops}.
+     * <p>
+     * Each secure stop has a unique ID that can be used to identify it during
+     * enumeration, access and removal.
      * @return a list of all secure stops from secure persistent memory
      */
     @NonNull
@@ -1000,6 +1003,8 @@
 
     /**
      * Return a list of all secure stop IDs currently in persistent memory.
+     * The secure stop ID can be used to access or remove the corresponding
+     * secure stop.
      *
      * @return a list of secure stop IDs
      */
@@ -1008,6 +1013,7 @@
 
     /**
      * Access a specific secure stop given its secure stop ID.
+     * Each secure stop has a unique ID.
      *
      * @param ssid the ID of the secure stop to return
      * @return the secure stop identified by ssid
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
index cc69e0e..c4ca339 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserManagerHelper.java
@@ -86,7 +86,7 @@
      * @return List of {@code UserInfo} for each user that is not the current user.
      */
     public List<UserInfo> getAllUsersExcludesCurrentUser() {
-        List<UserInfo> others = mUserManager.getUsers(true);
+        List<UserInfo> others = getAllUsers();
 
         for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) {
             UserInfo userInfo = iterator.next();
@@ -98,6 +98,31 @@
         return others;
     }
 
+    /**
+     * Gets all the other users on the system that are not the system user.
+     *
+     * @return List of {@code UserInfo} for each user that is not the system user.
+     */
+    public List<UserInfo> getAllUsersExcludesSystemUser() {
+        List<UserInfo> others = getAllUsers();
+
+        for (Iterator<UserInfo> iterator = others.iterator(); iterator.hasNext(); ) {
+            UserInfo userInfo = iterator.next();
+            if (userIsSystemUser(userInfo)) {
+                // Remove system user from the list.
+                iterator.remove();
+            }
+        }
+        return others;
+    }
+
+    /**
+     * Gets all the users on the system that are not currently being removed.
+     */
+    public List<UserInfo> getAllUsers() {
+        return mUserManager.getUsers(true /* excludeDying */);
+    }
+
     // User information accessors
 
     /**
@@ -224,7 +249,7 @@
      * @return {@code true} if user is successfully removed, {@code false} otherwise.
      */
     public boolean removeUser(UserInfo userInfo) {
-        if (userInfo.id == UserHandle.USER_SYSTEM) {
+        if (userIsSystemUser(userInfo)) {
             Log.w(TAG, "User " + userInfo.id + " is system user, could not be removed.");
             return false;
         }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
index 325ef3a..3f1fcbb 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/UserManagerHelperTest.java
@@ -113,6 +113,54 @@
     }
 
     @Test
+    public void testGetAllUsersExcludesSystemUser() {
+        UserInfo otherUser1 = createUserInfoForId(10);
+        UserInfo otherUser2 = createUserInfoForId(11);
+        UserInfo otherUser3 = createUserInfoForId(12);
+
+        List<UserInfo> testUsers = new ArrayList<>();
+        testUsers.add(otherUser1);
+        testUsers.add(otherUser2);
+        testUsers.add(mSystemUser);
+        testUsers.add(otherUser3);
+
+        when(mUserManager.getUsers(true)).thenReturn(testUsers);
+
+        // Should return 3 users that don't have SYSTEM USER id.
+        assertThat(mHelper.getAllUsersExcludesSystemUser().size()).isEqualTo(3);
+        // Should not contain system user.
+        assertThat(mHelper.getAllUsersExcludesSystemUser()).doesNotContain(mSystemUser);
+        // Should contain non-system users.
+        assertThat(mHelper.getAllUsersExcludesSystemUser()).contains(otherUser1);
+        assertThat(mHelper.getAllUsersExcludesSystemUser()).contains(otherUser2);
+        assertThat(mHelper.getAllUsersExcludesSystemUser()).contains(otherUser3);
+    }
+
+    @Test
+    public void testGetAllUsers() {
+        int currentUser = UserHandle.myUserId();
+
+        UserInfo otherUser1 = createUserInfoForId(currentUser + 1);
+        UserInfo otherUser2 = createUserInfoForId(currentUser - 1);
+        UserInfo otherUser3 = createUserInfoForId(currentUser + 2);
+
+        List<UserInfo> testUsers = new ArrayList<>();
+        testUsers.add(otherUser1);
+        testUsers.add(otherUser2);
+        testUsers.add(mCurrentUser);
+        testUsers.add(otherUser3);
+
+        when(mUserManager.getUsers(true)).thenReturn(testUsers);
+
+        // Should return 3 users that don't have currentUser id.
+        assertThat(mHelper.getAllUsers().size()).isEqualTo(4);
+        assertThat(mHelper.getAllUsers()).contains(mCurrentUser);
+        assertThat(mHelper.getAllUsers()).contains(otherUser1);
+        assertThat(mHelper.getAllUsers()).contains(otherUser2);
+        assertThat(mHelper.getAllUsers()).contains(otherUser3);
+    }
+
+    @Test
     public void testUserCanBeRemoved() {
         UserInfo testInfo = new UserInfo();
 
@@ -208,11 +256,6 @@
         // Cannot remove system user.
         assertThat(mHelper.removeUser(mSystemUser)).isFalse();
 
-        // Removing current user, calls "switch" to system user.
-        mHelper.removeUser(mCurrentUser);
-        verify(mActivityManager).switchUser(UserHandle.USER_SYSTEM);
-        verify(mUserManager).removeUser(mCurrentUser.id);
-
         // Removing non-current, non-system user, simply calls removeUser.
         UserInfo userToRemove = createUserInfoForId(mCurrentUser.id + 2);
         mHelper.removeUser(userToRemove);
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index 7c97ca61..e217ace 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -22,3 +22,6 @@
 twickham@google.com
 winsonc@google.com
 
+#Android Auto
+stenning@google.com
+
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 72ff653..8c57ae8 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -57,6 +57,8 @@
         android:layout_marginBottom="@dimen/qs_footer_height"
         android:elevation="4dp"
         android:background="@android:color/transparent"
+        android:focusable="true"
+        android:accessibilityTraversalBefore="@id/qs_carrier_text"
     />
 
     <include layout="@layout/quick_status_bar_expanded_header" />
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 54baa4a..5229f9b 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -41,14 +41,13 @@
         android:visibility="invisible">
 
         <ImageView
-            android:id="@+id/next_alarm_icon"
+            android:id="@+id/ringer_mode_icon"
             android:layout_width="@dimen/qs_header_alarm_icon_size"
             android:layout_height="@dimen/qs_header_alarm_icon_size"
-            android:src="@drawable/stat_sys_alarm"
             android:tint="?android:attr/textColorPrimary" />
 
         <TextView
-            android:id="@+id/next_alarm_text"
+            android:id="@+id/ringer_mode_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
@@ -64,13 +63,14 @@
             android:backgroundTint="?android:attr/textColorPrimary" />
 
         <ImageView
-            android:id="@+id/ringer_mode_icon"
+            android:id="@+id/next_alarm_icon"
             android:layout_width="@dimen/qs_header_alarm_icon_size"
             android:layout_height="@dimen/qs_header_alarm_icon_size"
+            android:src="@drawable/stat_sys_alarm"
             android:tint="?android:attr/textColorPrimary" />
 
         <TextView
-            android:id="@+id/ringer_mode_text"
+            android:id="@+id/next_alarm_text"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4074042..da6ecc3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1335,6 +1335,11 @@
     <string name="volume_ringer_status_vibrate">Vibrate</string>
     <string name="volume_ringer_status_silent">Mute</string>
 
+    <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] -->
+    <string name="qs_status_phone_vibrate">Phone on vibrate</string>
+    <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] -->
+    <string name="qs_status_phone_muted">Phone muted</string>
+
     <string name="volume_stream_muted" translatable="false">%s silent</string>
     <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
     <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 8a4f324..ce16efb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -54,7 +54,6 @@
     private static final int MARQUEE_DELAY_MS = 2000;
 
     private final LockPatternUtils mLockPatternUtils;
-    private final AlarmManager mAlarmManager;
     private final IActivityManager mIActivityManager;
     private final float mSmallClockScale;
     private final float mWidgetPadding;
@@ -123,7 +122,6 @@
 
     public KeyguardStatusView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
-        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mIActivityManager = ActivityManager.getService();
         mLockPatternUtils = new LockPatternUtils(getContext());
         mHandler = new Handler(Looper.myLooper());
@@ -223,10 +221,7 @@
     }
 
     private void refresh() {
-        AlarmManager.AlarmClockInfo nextAlarm =
-                mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
-        Patterns.update(mContext, nextAlarm != null);
-
+        Patterns.update(mContext);
         refreshTime();
     }
 
@@ -301,20 +296,16 @@
     // DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
     // This is an optimization to ensure we only recompute the patterns when the inputs change.
     private static final class Patterns {
-        static String dateViewSkel;
         static String clockView12;
         static String clockView24;
         static String cacheKey;
 
-        static void update(Context context, boolean hasAlarm) {
+        static void update(Context context) {
             final Locale locale = Locale.getDefault();
             final Resources res = context.getResources();
-            dateViewSkel = res.getString(hasAlarm
-                    ? R.string.abbrev_wday_month_day_no_year_alarm
-                    : R.string.abbrev_wday_month_day_no_year);
             final String clockView12Skel = res.getString(R.string.clock_12hr_format);
             final String clockView24Skel = res.getString(R.string.clock_24hr_format);
-            final String key = locale.toString() + dateViewSkel + clockView12Skel + clockView24Skel;
+            final String key = locale.toString() + clockView12Skel + clockView24Skel;
             if (key.equals(cacheKey)) return;
 
             clockView12 = DateFormat.getBestDateTimePattern(locale, clockView12Skel);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 5c0576d..a0bdcd0 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -325,6 +325,9 @@
             return;
         }
         bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
+        // In landscape mode, PIP window can go offset while launching IME. We want to align the
+        // the top of the PIP window with the top of the movement bounds in that case.
+        bounds.offset(0, Math.max(0, mMovementBounds.top - bounds.top));
         mMotionHelper.animateToOffset(bounds);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index df65d1f..224c367 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -172,11 +172,11 @@
         boolean ringerVisible = false;
         if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
             mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_vibrate);
-            mRingerModeTextView.setText(R.string.volume_ringer_status_vibrate);
+            mRingerModeTextView.setText(R.string.qs_status_phone_vibrate);
             ringerVisible = true;
         } else if (mRingerMode == AudioManager.RINGER_MODE_SILENT) {
             mRingerModeIcon.setImageResource(R.drawable.stat_sys_ringer_silent);
-            mRingerModeTextView.setText(R.string.volume_ringer_status_silent);
+            mRingerModeTextView.setText(R.string.qs_status_phone_muted);
             ringerVisible = true;
         }
         mRingerModeIcon.setVisibility(ringerVisible ? View.VISIBLE : View.GONE);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 0f83078..862a6a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -16,6 +16,8 @@
 
 import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -127,7 +129,6 @@
     }
 
     protected void setIcon(ImageView iv, QSTile.State state) {
-        updateIcon(iv, state);
         if (state.disabledByPolicy) {
             iv.setColorFilter(getContext().getColor(R.color.qs_tile_disabled_color));
         } else {
@@ -137,7 +138,7 @@
             int color = getColor(state.state);
             mState = state.state;
             if (iv.isShown() && mTint != 0) {
-                animateGrayScale(mTint, color, iv);
+                animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state));
                 mTint = color;
             } else {
                 if (iv instanceof AlphaControlledSlashImageView) {
@@ -147,7 +148,10 @@
                     setTint(iv, color);
                 }
                 mTint = color;
+                updateIcon(iv, state);
             }
+        } else {
+            updateIcon(iv, state);
         }
     }
 
@@ -155,7 +159,8 @@
         return getColorForState(getContext(), state);
     }
 
-    public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
+    public static void animateGrayScale(int fromColor, int toColor, ImageView iv,
+            final Runnable endRunnable) {
         if (iv instanceof AlphaControlledSlashImageView) {
             ((AlphaControlledSlashImageView)iv)
                     .setFinalImageTintList(ColorStateList.valueOf(toColor));
@@ -175,10 +180,16 @@
 
                 setTint(iv, Color.argb(alpha, channel, channel, channel));
             });
-
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    endRunnable.run();
+                }
+            });
             anim.start();
         } else {
             setTint(iv, toColor);
+            endRunnable.run();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 8a1e4da..d8f7b71 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.tileimpl.QSIconViewImpl;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
@@ -60,6 +61,7 @@
 
     protected final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
     private final ActivityStarter mActivityStarter;
+    private boolean mExpectDisabled;
 
     public WifiTile(QSHost host) {
         super(host);
@@ -120,6 +122,15 @@
         // Immediately enter transient state when turning on wifi.
         refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
         mController.setWifiEnabled(!wifiEnabled);
+        mExpectDisabled = wifiEnabled;
+        if (mExpectDisabled) {
+            mHandler.postDelayed(() -> {
+                if (mExpectDisabled) {
+                    mExpectDisabled = false;
+                    refreshState();
+                }
+            }, QSIconViewImpl.QS_ANIM_LENGTH);
+        }
     }
 
     @Override
@@ -143,11 +154,13 @@
     @Override
     protected void handleUpdateState(SignalState state, Object arg) {
         if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
-        final CallbackInfo cb;
-        if (arg != null && arg instanceof CallbackInfo) {
-            cb = (CallbackInfo) arg;
-        } else {
-            cb = mSignalCallback.mInfo;
+        final CallbackInfo cb = mSignalCallback.mInfo;
+        if (mExpectDisabled) {
+            if (cb.enabled) {
+                return; // Ignore updates until disabled event occurs.
+            } else {
+                mExpectDisabled = false;
+            }
         }
         boolean transientEnabling = arg == ARG_SHOW_TRANSIENT_ENABLING;
         boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.ssid != null);
@@ -288,7 +301,7 @@
             if (isShowingDetail()) {
                 mDetailAdapter.updateItems();
             }
-            refreshState(mInfo);
+            refreshState();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 3530e0b..3fb1137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -182,27 +182,6 @@
             // By default, the BatteryMeterView should not be visible. It will be toggled
             // when a device has connected by bluetooth.
             mBatteryMeterView.setVisibility(View.GONE);
-
-            ViewStub stub = fragment.getView().findViewById(R.id.connected_device_signals_stub);
-            View signalsView = stub.inflate();
-
-            // When a ViewStub if inflated, it does not respect the margins on the
-            // inflated view.
-            // As a result, manually add the ending margin.
-            ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
-                    mContext.getResources().getDimensionPixelOffset(
-                            R.dimen.status_bar_connected_device_signal_margin_end));
-
-            if (mConnectedDeviceSignalController != null) {
-                mConnectedDeviceSignalController.stopListening();
-            }
-            mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
-                    signalsView);
-            mConnectedDeviceSignalController.startListening();
-
-            if (Log.isLoggable(TAG, Log.DEBUG)) {
-                Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
-            }
         });
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 861ae83..a1ef1ed 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -910,7 +910,12 @@
 
     private Tethering makeTethering() {
         // TODO: Move other elements into @Overridden getters.
-        final TetheringDependencies deps = new TetheringDependencies();
+        final TetheringDependencies deps = new TetheringDependencies() {
+            @Override
+            public boolean isTetheringSupported() {
+                return ConnectivityService.this.isTetheringSupported();
+            }
+        };
         return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
                 IoThread.get().getLooper(), new MockableSystemProperties(),
                 deps);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fd8998b..f97c6d6 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1530,6 +1530,11 @@
     private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
 
     /**
+     * State of external calls telling us if the device is awake or asleep.
+     */
+    private boolean mKeyguardShown = false;
+
+    /**
      * Set if we are shutting down the system, similar to sleeping.
      */
     boolean mShuttingDown = false;
@@ -13094,6 +13099,12 @@
                 : UsageEvents.Event.SCREEN_NON_INTERACTIVE);
     }
 
+    void reportCurKeyguardUsageEventLocked() {
+        reportGlobalUsageEventLocked(mKeyguardShown
+                ? UsageEvents.Event.KEYGUARD_SHOWN
+                : UsageEvents.Event.KEYGUARD_HIDDEN);
+    }
+
     void onWakefulnessChanged(int wakefulness) {
         synchronized(this) {
             boolean wasAwake = mWakefulness == PowerManagerInternal.WAKEFULNESS_AWAKE;
@@ -13257,6 +13268,10 @@
 
         synchronized(this) {
             long ident = Binder.clearCallingIdentity();
+            if (mKeyguardShown != keyguardShowing) {
+                mKeyguardShown = keyguardShowing;
+                reportCurKeyguardUsageEventLocked();
+            }
             try {
                 mKeyguardController.setKeyguardShown(keyguardShowing, aodShowing,
                         secondaryDisplayShowing);
@@ -15209,7 +15224,17 @@
                 Binder.getCallingUid(),
                 eventType,
                 processName,
-                Binder.getCallingPid());
+                Binder.getCallingPid(),
+                (r != null && r.info != null) ? r.info.packageName : "",
+                (r != null && r.info != null) ? (r.info.isInstantApp()
+                        ? StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE
+                        : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE)
+                        : StatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+                r != null ? (r.isInterestingToUserLocked()
+                        ? StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND
+                        : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND)
+                        : StatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN
+        );
 
         addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index a30a944..1b7e1ed 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -46,6 +46,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
@@ -1205,9 +1206,20 @@
                 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
 
-            if (mStartActivity.getTask() == null) {
+            // True if we are clearing top and resetting of a standard (default) launch mode
+            // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
+            final boolean clearTopAndResetStandardLaunchMode =
+                    (mLaunchFlags & (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED))
+                            == (FLAG_ACTIVITY_CLEAR_TOP | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+                    && mLaunchMode == LAUNCH_MULTIPLE;
+
+            // If mStartActivity does not have a task associated with it, associate it with the
+            // reused activity's task. Do not do so if we're clearing top and resetting for a
+            // standard launchMode activity.
+            if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
                 mStartActivity.setTask(reusedActivity.getTask());
             }
+
             if (reusedActivity.getTask().intent == null) {
                 // This task was started because of movement of the activity based on affinity...
                 // Now that we are actually launching it, we can assign the base intent.
@@ -1266,17 +1278,21 @@
                 resumeTargetStackIfNeeded();
                 return START_RETURN_INTENT_TO_CALLER;
             }
-            setTaskFromIntentActivity(reusedActivity);
 
-            if (!mAddingToTask && mReuseTask == null) {
-                // We didn't do anything...  but it was needed (a.k.a., client don't use that
-                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
-                resumeTargetStackIfNeeded();
-                if (outActivity != null && outActivity.length > 0) {
-                    outActivity[0] = reusedActivity;
+            if (reusedActivity != null) {
+                setTaskFromIntentActivity(reusedActivity);
+
+                if (!mAddingToTask && mReuseTask == null) {
+                    // We didn't do anything...  but it was needed (a.k.a., client don't use that
+                    // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
+
+                    resumeTargetStackIfNeeded();
+                    if (outActivity != null && outActivity.length > 0) {
+                        outActivity[0] = reusedActivity;
+                    }
+
+                    return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
                 }
-
-                return mMovedToFront ? START_TASK_TO_FRONT : START_DELIVERED_TO_TOP;
             }
         }
 
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 7ee20fa2..d5bb7ed 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -1041,7 +1041,15 @@
         }
 
         StatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,
-                activity == null ? "unknown": activity.shortComponentName, annotation);
+                activity == null ? "unknown": activity.shortComponentName, annotation,
+                (app.info != null) ? (app.info.isInstantApp()
+                        ? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE
+                        : StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE)
+                        : StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,
+                app != null ? (app.isInterestingToUserLocked()
+                        ? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND
+                        : StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND)
+                        : StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN);
         mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,
                 cpuInfo, tracesFile, null);
 
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index f710690..a294334 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1593,6 +1593,7 @@
 
     void onSystemReady() {
         updateCurrentProfileIds();
+        mInjector.reportCurWakefulnessUsageEvent();
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index 4eb1930..53a9544 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -20,9 +20,13 @@
 import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
 import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
 
 import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
 
 import android.app.usage.NetworkStatsManager;
 import android.app.usage.NetworkStatsManager.UsageCallback;
@@ -31,24 +35,34 @@
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.Network;
 import android.net.NetworkCapabilities;
+import android.net.NetworkIdentity;
+import android.net.NetworkPolicy;
 import android.net.NetworkPolicyManager;
 import android.net.NetworkRequest;
 import android.net.NetworkStats;
 import android.net.NetworkTemplate;
 import android.net.StringNetworkSpecifier;
+import android.os.BestClock;
 import android.os.Handler;
+import android.os.SystemClock;
 import android.telephony.TelephonyManager;
 import android.util.DebugUtils;
+import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.LocalServices;
 import com.android.server.net.NetworkPolicyManagerInternal;
-import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsManagerInternal;
 
+import java.time.Clock;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.Calendar;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Manages multipath data budgets.
@@ -69,6 +83,8 @@
 
     private final Context mContext;
     private final Handler mHandler;
+    private final Clock mClock;
+    private final Dependencies mDeps;
 
     private ConnectivityManager mCM;
     private NetworkPolicyManager mNPM;
@@ -80,9 +96,28 @@
     // STOPSHIP: replace this with a configurable mechanism.
     private static final long DEFAULT_DAILY_MULTIPATH_QUOTA = 2_500_000;
 
+    /**
+     * Divider to calculate opportunistic quota from user-set data limit or warning: 5% of user-set
+     * limit.
+     */
+    private static final int OPQUOTA_USER_SETTING_DIVIDER = 20;
+
+    public static class Dependencies {
+        public Clock getClock() {
+            return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+                    Clock.systemUTC());
+        }
+    }
+
     public MultipathPolicyTracker(Context ctx, Handler handler) {
+        this(ctx, handler, new Dependencies());
+    }
+
+    public MultipathPolicyTracker(Context ctx, Handler handler, Dependencies deps) {
         mContext = ctx;
         mHandler = handler;
+        mClock = deps.getClock();
+        mDeps = deps;
         // Because we are initialized by the ConnectivityService constructor, we can't touch any
         // connectivity APIs. Service initialization is done in start().
     }
@@ -128,9 +163,11 @@
         private long mMultipathBudget;
         private final NetworkTemplate mNetworkTemplate;
         private final UsageCallback mUsageCallback;
+        private NetworkCapabilities mNetworkCapabilities;
 
         public MultipathTracker(Network network, NetworkCapabilities nc) {
             this.network = network;
+            this.mNetworkCapabilities = new NetworkCapabilities(nc);
             try {
                 subId = Integer.parseInt(
                         ((StringNetworkSpecifier) nc.getNetworkSpecifier()).toString());
@@ -167,32 +204,97 @@
             updateMultipathBudget();
         }
 
-        private long getDailyNonDefaultDataUsage() {
-            Calendar start = Calendar.getInstance();
-            Calendar end = (Calendar) start.clone();
-            start.set(Calendar.HOUR_OF_DAY, 0);
-            start.set(Calendar.MINUTE, 0);
-            start.set(Calendar.SECOND, 0);
-            start.set(Calendar.MILLISECOND, 0);
+        public void setNetworkCapabilities(NetworkCapabilities nc) {
+            mNetworkCapabilities = new NetworkCapabilities(nc);
+        }
 
+        // TODO: calculate with proper timezone information
+        private long getDailyNonDefaultDataUsage() {
+            final ZonedDateTime end =
+                    ZonedDateTime.ofInstant(mClock.instant(), ZoneId.systemDefault());
+            final ZonedDateTime start = end.truncatedTo(ChronoUnit.DAYS);
+
+            final long bytes = getNetworkTotalBytes(
+                    start.toInstant().toEpochMilli(),
+                    end.toInstant().toEpochMilli());
+            if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
+            return bytes;
+        }
+
+        private long getNetworkTotalBytes(long start, long end) {
             try {
-                final long bytes = LocalServices.getService(NetworkStatsManagerInternal.class)
-                        .getNetworkTotalBytes(mNetworkTemplate, start.getTimeInMillis(),
-                                end.getTimeInMillis());
-                if (DBG) Slog.d(TAG, "Non-default data usage: " + bytes);
-                return bytes;
+                return LocalServices.getService(NetworkStatsManagerInternal.class)
+                        .getNetworkTotalBytes(mNetworkTemplate, start, end);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failed to get data usage: " + e);
                 return -1;
             }
         }
 
+        private NetworkIdentity getTemplateMatchingNetworkIdentity(NetworkCapabilities nc) {
+            return new NetworkIdentity(
+                    ConnectivityManager.TYPE_MOBILE,
+                    0 /* subType, unused for template matching */,
+                    subscriberId,
+                    null /* networkId, unused for matching mobile networks */,
+                    !nc.hasCapability(NET_CAPABILITY_NOT_ROAMING),
+                    !nc.hasCapability(NET_CAPABILITY_NOT_METERED),
+                    false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */);
+        }
+
+        private long getRemainingDailyBudget(long limitBytes,
+                Pair<ZonedDateTime, ZonedDateTime> cycle) {
+            final long start = cycle.first.toInstant().toEpochMilli();
+            final long end = cycle.second.toInstant().toEpochMilli();
+            final long totalBytes = getNetworkTotalBytes(start, end);
+            final long remainingBytes = totalBytes == -1 ? 0 : Math.max(0, limitBytes - totalBytes);
+            // 1 + ((end - now - 1) / millisInDay with integers is equivalent to:
+            // ceil((double)(end - now) / millisInDay)
+            final long remainingDays =
+                    1 + ((end - mClock.millis() - 1) / TimeUnit.DAYS.toMillis(1));
+
+            return remainingBytes / Math.max(1, remainingDays);
+        }
+
+        private long getUserPolicyOpportunisticQuotaBytes() {
+            // Keep the most restrictive applicable policy
+            long minQuota = Long.MAX_VALUE;
+            final NetworkIdentity identity = getTemplateMatchingNetworkIdentity(
+                    mNetworkCapabilities);
+
+            final NetworkPolicy[] policies = mNPM.getNetworkPolicies();
+            for (NetworkPolicy policy : policies) {
+                if (hasActiveCycle(policy) && policy.template.matches(identity)) {
+                    // Prefer user-defined warning, otherwise use hard limit
+                    final long policyBytes = (policy.warningBytes == LIMIT_DISABLED)
+                            ? policy.limitBytes : policy.warningBytes;
+
+                    if (policyBytes != LIMIT_DISABLED) {
+                        final long policyBudget = getRemainingDailyBudget(policyBytes,
+                                policy.cycleIterator().next());
+                        minQuota = Math.min(minQuota, policyBudget);
+                    }
+                }
+            }
+
+            if (minQuota == Long.MAX_VALUE) {
+                return OPPORTUNISTIC_QUOTA_UNKNOWN;
+            }
+
+            return minQuota / OPQUOTA_USER_SETTING_DIVIDER;
+        }
+
         void updateMultipathBudget() {
             long quota = LocalServices.getService(NetworkPolicyManagerInternal.class)
                     .getSubscriptionOpportunisticQuota(this.network, QUOTA_TYPE_MULTIPATH);
             if (DBG) Slog.d(TAG, "Opportunistic quota from data plan: " + quota + " bytes");
 
-            if (quota == NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN) {
+            // Fallback to user settings-based quota if not available from phone plan
+            if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
+                quota = getUserPolicyOpportunisticQuotaBytes();
+            }
+
+            if (quota == OPPORTUNISTIC_QUOTA_UNKNOWN) {
                 // STOPSHIP: replace this with a configurable mechanism.
                 quota = DEFAULT_DAILY_MULTIPATH_QUOTA;
                 if (DBG) Slog.d(TAG, "Setting quota: " + quota + " bytes");
@@ -262,6 +364,11 @@
         }
     }
 
+    private static boolean hasActiveCycle(NetworkPolicy policy) {
+        return policy.hasCycle() && policy.lastLimitSnooze <
+                policy.cycleIterator().next().first.toInstant().toEpochMilli();
+    }
+
     // Only ever updated on the handler thread. Accessed from other binder threads to retrieve
     // the tracker for a specific network.
     private final ConcurrentHashMap <Network, MultipathTracker> mMultipathTrackers =
@@ -281,6 +388,7 @@
             public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
                 MultipathTracker existing = mMultipathTrackers.get(network);
                 if (existing != null) {
+                    existing.setNetworkCapabilities(nc);
                     existing.updateMultipathBudget();
                     return;
                 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 1bc7423..d37dd18 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,6 +19,27 @@
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
+import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_INVALID;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -45,7 +66,6 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
 import android.net.IpPrefix;
@@ -148,7 +168,7 @@
             stateMachine = sm;
             // Assume all state machines start out available and with no errors.
             lastState = IControlsTethering.STATE_AVAILABLE;
-            lastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+            lastError = TETHER_ERROR_NO_ERROR;
         }
 
         public boolean isCurrentlyServing() {
@@ -216,7 +236,7 @@
 
         final Handler smHandler = mTetherMasterSM.getHandler();
         mOffloadController = new OffloadController(smHandler,
-                deps.getOffloadHardwareInterface(smHandler, mLog),
+                mDeps.getOffloadHardwareInterface(smHandler, mLog),
                 mContext.getContentResolver(), mNMService,
                 mLog);
         mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
@@ -243,7 +263,7 @@
         mStateReceiver = new StateReceiver();
         filter = new IntentFilter();
         filter.addAction(UsbManager.ACTION_USB_STATE);
-        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        filter.addAction(CONNECTIVITY_ACTION);
         filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
         filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
@@ -265,12 +285,6 @@
         updateConfiguration();
     }
 
-    // We can't do this once in the Tethering() constructor and cache the value, because the
-    // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
-    private ConnectivityManager getConnectivityManager() {
-        return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-    }
-
     private WifiManager getWifiManager() {
         return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
     }
@@ -296,7 +310,7 @@
             if (up) {
                 maybeTrackNewInterfaceLocked(iface);
             } else {
-                if (ifaceNameToType(iface) == ConnectivityManager.TETHERING_BLUETOOTH) {
+                if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
                     stopTrackingInterfaceLocked(iface);
                 } else {
                     // Ignore usb0 down after enabling RNDIS.
@@ -318,13 +332,13 @@
         final TetheringConfiguration cfg = mConfig;
 
         if (cfg.isWifi(iface)) {
-            return ConnectivityManager.TETHERING_WIFI;
+            return TETHERING_WIFI;
         } else if (cfg.isUsb(iface)) {
-            return ConnectivityManager.TETHERING_USB;
+            return TETHERING_USB;
         } else if (cfg.isBluetooth(iface)) {
-            return ConnectivityManager.TETHERING_BLUETOOTH;
+            return TETHERING_BLUETOOTH;
         }
-        return ConnectivityManager.TETHERING_INVALID;
+        return TETHERING_INVALID;
     }
 
     @Override
@@ -426,26 +440,26 @@
         boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
         int result;
         switch (type) {
-            case ConnectivityManager.TETHERING_WIFI:
+            case TETHERING_WIFI:
                 result = setWifiTethering(enable);
-                if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                     scheduleProvisioningRechecks(type);
                 }
                 sendTetherResult(receiver, result);
                 break;
-            case ConnectivityManager.TETHERING_USB:
+            case TETHERING_USB:
                 result = setUsbTethering(enable);
-                if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                     scheduleProvisioningRechecks(type);
                 }
                 sendTetherResult(receiver, result);
                 break;
-            case ConnectivityManager.TETHERING_BLUETOOTH:
+            case TETHERING_BLUETOOTH:
                 setBluetoothTethering(enable, receiver);
                 break;
             default:
                 Log.w(TAG, "Invalid tether type.");
-                sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
+                sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
         }
     }
 
@@ -456,7 +470,7 @@
     }
 
     private int setWifiTethering(final boolean enable) {
-        int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+        int rval = TETHER_ERROR_MASTER_ERROR;
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mPublicSync) {
@@ -464,7 +478,7 @@
                 final WifiManager mgr = getWifiManager();
                 if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
                     (!enable && mgr.stopSoftAp())) {
-                    rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+                    rval = TETHER_ERROR_NO_ERROR;
                 }
             }
         } finally {
@@ -478,7 +492,7 @@
         if (adapter == null || !adapter.isEnabled()) {
             Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
                     (adapter == null));
-            sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
+            sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
             return;
         }
 
@@ -491,12 +505,12 @@
                 ((BluetoothPan) proxy).setBluetoothTethering(enable);
                 // TODO: Enabling bluetooth tethering can fail asynchronously here.
                 // We should figure out a way to bubble up that failure instead of sending success.
-                int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
-                        ConnectivityManager.TETHER_ERROR_NO_ERROR :
-                        ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+                final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
+                        ? TETHER_ERROR_NO_ERROR
+                        : TETHER_ERROR_MASTER_ERROR;
                 sendTetherResult(receiver, result);
                 if (enable && isTetherProvisioningRequired()) {
-                    scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
+                    scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
                 }
                 adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
             }
@@ -510,8 +524,8 @@
 
     private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
         Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
-        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
-        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -534,7 +548,7 @@
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 // If provisioning is successful, enable tethering, otherwise just send the error.
-                if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                if (resultCode == TETHER_ERROR_NO_ERROR) {
                     enableTetheringInternal(type, true, receiver);
                 } else {
                     sendTetherResult(receiver, resultCode);
@@ -554,8 +568,8 @@
 
     private void scheduleProvisioningRechecks(int type) {
         Intent intent = new Intent();
-        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
-        intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
+        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(EXTRA_SET_ALARM, true);
         intent.setComponent(TETHER_SERVICE);
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -572,9 +586,9 @@
 
     private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
         Intent intent = new Intent();
-        intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
-        intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
-        intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+        intent.putExtra(EXTRA_RUN_PROVISION, true);
+        intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
         intent.setComponent(TETHER_SERVICE);
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -585,9 +599,9 @@
     }
 
     private void cancelTetherProvisioningRechecks(int type) {
-        if (getConnectivityManager().isTetheringSupported()) {
+        if (mDeps.isTetheringSupported()) {
             Intent intent = new Intent();
-            intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
+            intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
             intent.setComponent(TETHER_SERVICE);
             final long ident = Binder.clearCallingIdentity();
             try {
@@ -602,8 +616,8 @@
     // TODO: De-duplicate with above code, where possible.
     private void startProvisionIntent(int tetherType) {
         final Intent startProvIntent = new Intent();
-        startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
-        startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
+        startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
+        startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
         startProvIntent.setComponent(TETHER_SERVICE);
         mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
     }
@@ -618,13 +632,13 @@
             TetherState tetherState = mTetherStates.get(iface);
             if (tetherState == null) {
                 Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
-                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+                return TETHER_ERROR_UNKNOWN_IFACE;
             }
             // Ignore the error status of the interface.  If the interface is available,
             // the errors are referring to past tethering attempts anyway.
             if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
                 Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
-                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+                return TETHER_ERROR_UNAVAIL_IFACE;
             }
             // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
             // queue but not yet processed, this will be a no-op and it will not
@@ -633,7 +647,7 @@
             // TODO: reexamine the threading and messaging model.
             tetherState.stateMachine.sendMessage(
                     TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
-            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+            return TETHER_ERROR_NO_ERROR;
         }
     }
 
@@ -643,22 +657,22 @@
             TetherState tetherState = mTetherStates.get(iface);
             if (tetherState == null) {
                 Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
-                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+                return TETHER_ERROR_UNKNOWN_IFACE;
             }
             if (!tetherState.isCurrentlyServing()) {
                 Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
-                return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+                return TETHER_ERROR_UNAVAIL_IFACE;
             }
             tetherState.stateMachine.sendMessage(
                     TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
-            return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+            return TETHER_ERROR_NO_ERROR;
         }
     }
 
     public void untetherAll() {
-        stopTethering(ConnectivityManager.TETHERING_WIFI);
-        stopTethering(ConnectivityManager.TETHERING_USB);
-        stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
+        stopTethering(TETHERING_WIFI);
+        stopTethering(TETHERING_USB);
+        stopTethering(TETHERING_BLUETOOTH);
     }
 
     public int getLastTetherError(String iface) {
@@ -667,7 +681,7 @@
             if (tetherState == null) {
                 Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
                         ", ignoring");
-                return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+                return TETHER_ERROR_UNKNOWN_IFACE;
             }
             return tetherState.lastError;
         }
@@ -675,7 +689,7 @@
 
     // TODO: Figure out how to update for local hotspot mode interfaces.
     private void sendTetherStateChangedBroadcast() {
-        if (!getConnectivityManager().isTetheringSupported()) return;
+        if (!mDeps.isTetheringSupported()) return;
 
         final ArrayList<String> availableList = new ArrayList<>();
         final ArrayList<String> tetherList = new ArrayList<>();
@@ -692,7 +706,7 @@
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
                 String iface = mTetherStates.keyAt(i);
-                if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
                     erroredList.add(iface);
                 } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
                     availableList.add(iface);
@@ -710,13 +724,13 @@
                 }
             }
         }
-        final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+        final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
         bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
                 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
-        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
-        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
-        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
+        bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
+        bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+        bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
+        bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
         mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
         if (DBG) {
             Log.d(TAG, String.format(
@@ -839,7 +853,7 @@
 
             if (action.equals(UsbManager.ACTION_USB_STATE)) {
                 handleUsbAction(intent);
-            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+            } else if (action.equals(CONNECTIVITY_ACTION)) {
                 handleConnectivityAction(intent);
             } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
                 handleWifiApAction(intent);
@@ -850,8 +864,8 @@
         }
 
         private void handleConnectivityAction(Intent intent) {
-            final NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
-                    ConnectivityManager.EXTRA_NETWORK_INFO);
+            final NetworkInfo networkInfo =
+                    (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
             if (networkInfo == null ||
                     networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
                 return;
@@ -887,14 +901,10 @@
             synchronized (Tethering.this.mPublicSync) {
                 if (!usbConnected && mRndisEnabled) {
                     // Turn off tethering if it was enabled and there is a disconnect.
-                    tetherMatchingInterfaces(
-                            IControlsTethering.STATE_AVAILABLE,
-                            ConnectivityManager.TETHERING_USB);
+                    tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
-                    tetherMatchingInterfaces(
-                            IControlsTethering.STATE_TETHERED,
-                            ConnectivityManager.TETHERING_USB);
+                    tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
                 }
                 mRndisEnabled = usbConfigured && rndisEnabled;
             }
@@ -975,7 +985,7 @@
 
         for (int i = 0; i < mTetherStates.size(); i++) {
             TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
-            if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+            if (tism.interfaceType() == TETHERING_WIFI) {
                 tism.unwanted();
                 return;
             }
@@ -1003,7 +1013,7 @@
         }
 
         if (!TextUtils.isEmpty(ifname)) {
-            maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
+            maybeTrackNewInterfaceLocked(ifname, TETHERING_WIFI);
             changeInterfaceState(ifname, ipServingMode);
         } else {
             mLog.e(String.format(
@@ -1062,7 +1072,7 @@
                 Log.wtf(TAG, "Unknown interface state: " + requestedState);
                 return;
         }
-        if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+        if (result != TETHER_ERROR_NO_ERROR) {
             Log.e(TAG, "unable start or stop tethering on iface " + ifname);
             return;
         }
@@ -1104,7 +1114,7 @@
             usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
                     : UsbManager.FUNCTION_NONE);
         }
-        return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+        return TETHER_ERROR_NO_ERROR;
     }
 
     // TODO review API - figure out how to delete these entirely.
@@ -1143,7 +1153,7 @@
         synchronized (mPublicSync) {
             for (int i = 0; i < mTetherStates.size(); i++) {
                 TetherState tetherState = mTetherStates.valueAt(i);
-                if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
                     list.add(mTetherStates.keyAt(i));
                 }
             }
@@ -1189,7 +1199,7 @@
                 }
                 String iface = mTetherStates.keyAt(i);
                 int interfaceType = ifaceNameToType(iface);
-                if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
+                if (interfaceType != TETHERING_INVALID) {
                     tethered.add(interfaceType);
                 }
             }
@@ -1439,7 +1449,7 @@
             }
 
             // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
-            if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+            if (who.interfaceType() == TETHERING_WIFI) {
                 final WifiManager mgr = getWifiManager();
                 final String iface = who.interfaceName();
                 switch (mode) {
@@ -1463,8 +1473,8 @@
             mForwardedDownstreams.remove(who);
 
             // If this is a Wi-Fi interface, tell WifiManager of any errors.
-            if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
-                if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+            if (who.interfaceType() == TETHERING_WIFI) {
+                if (who.lastError() != TETHER_ERROR_NO_ERROR) {
                     getWifiManager().updateInterfaceIpState(
                             who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
                 }
@@ -1669,7 +1679,7 @@
                         who.sendMessage(mErrorNotification);
                         break;
                     case CMD_CLEAR_ERROR:
-                        mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+                        mErrorNotification = TETHER_ERROR_NO_ERROR;
                         transitionTo(mInitialState);
                         break;
                     default:
@@ -1931,7 +1941,7 @@
         // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
         // Thus we give a chance for TetherMasterSM to recover to InitialState
         // by sending CMD_CLEAR_ERROR
-        if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+        if (error == TETHER_ERROR_MASTER_ERROR) {
             mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
         }
         int which;
@@ -1975,7 +1985,7 @@
     private void maybeTrackNewInterfaceLocked(final String iface) {
         // If we don't care about this type of interface, ignore.
         final int interfaceType = ifaceNameToType(iface);
-        if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
+        if (interfaceType == TETHERING_INVALID) {
             mLog.log(iface + " is not a tetherable iface, ignoring");
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 66afb0f..0ac7a36 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -60,4 +60,8 @@
     public INetd getNetdService() {
         return NetdService.getInstance();
     }
+
+    public boolean isTetheringSupported() {
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 594937a..29d2e55 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -149,7 +149,6 @@
 import android.net.wifi.WifiManager;
 import android.os.BestClock;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -367,6 +366,8 @@
     private static final int UID_MSG_STATE_CHANGED = 100;
     private static final int UID_MSG_GONE = 101;
 
+    private static final String PROP_SUB_PLAN_OWNER = "persist.sys.sub_plan_owner";
+
     private final Context mContext;
     private final IActivityManager mActivityManager;
     private NetworkStatsManagerInternal mNetworkStats;
@@ -2796,10 +2797,17 @@
             return;
         }
 
-        // Fourth check: is caller a testing app on a debug build?
-        final boolean enableDebug = Build.IS_USERDEBUG || Build.IS_ENG;
-        if (enableDebug && callingPackage
-                .equals(SystemProperties.get("fw.sub_plan_owner." + subId, null))) {
+        // Fourth check: is caller a testing app?
+        final String testPackage = SystemProperties.get(PROP_SUB_PLAN_OWNER + "." + subId, null);
+        if (!TextUtils.isEmpty(testPackage)
+                && Objects.equals(testPackage, callingPackage)) {
+            return;
+        }
+
+        // Fifth check: is caller a legacy testing app?
+        final String legacyTestPackage = SystemProperties.get("fw.sub_plan_owner." + subId, null);
+        if (!TextUtils.isEmpty(legacyTestPackage)
+                && Objects.equals(legacyTestPackage, callingPackage)) {
             return;
         }
 
@@ -3000,6 +3008,14 @@
         }
     }
 
+    /**
+     * Only visible for testing purposes. This doesn't give any access to
+     * existing plans; it simply lets the debug package define new plans.
+     */
+    void setSubscriptionPlansOwner(int subId, String packageName) {
+        SystemProperties.set(PROP_SUB_PLAN_OWNER + "." + subId, packageName);
+    }
+
     @Override
     public String getSubscriptionPlansOwner(int subId) {
         if (UserHandle.getCallingAppId() != android.os.Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index b65b9d7..56d41c5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -21,7 +21,6 @@
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 
 import android.content.Context;
-import android.net.INetworkPolicyManager;
 import android.net.NetworkPolicyManager;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
@@ -33,10 +32,10 @@
 
 class NetworkPolicyManagerShellCommand extends ShellCommand {
 
-    private final INetworkPolicyManager mInterface;
+    private final NetworkPolicyManagerService mInterface;
     private final WifiManager mWifiManager;
 
-    NetworkPolicyManagerShellCommand(Context context, INetworkPolicyManager service) {
+    NetworkPolicyManagerShellCommand(Context context, NetworkPolicyManagerService service) {
         mInterface = service;
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
     }
@@ -97,6 +96,8 @@
         pw.println("    Toggles whether the given wi-fi network is metered.");
         pw.println("  set restrict-background BOOLEAN");
         pw.println("    Sets the global restrict background usage status.");
+        pw.println("  set sub-plan-owner subId [packageName]");
+        pw.println("    Sets the data plan owner package for subId.");
     }
 
     private int runGet() throws RemoteException {
@@ -126,6 +127,8 @@
                 return setMeteredWifiNetwork();
             case "restrict-background":
                 return setRestrictBackground();
+            case "sub-plan-owner":
+                return setSubPlanOwner();
         }
         pw.println("Error: unknown set type '" + type + "'");
         return -1;
@@ -227,6 +230,13 @@
         return 0;
     }
 
+    private int setSubPlanOwner() throws RemoteException {
+        final int subId = Integer.parseInt(getNextArgRequired());
+        final String packageName = getNextArg();
+        mInterface.setSubscriptionPlansOwner(subId, packageName);
+        return 0;
+    }
+
     private int setUidPolicy(int policy) throws RemoteException {
         final int uid = getUidFromNextArg();
         if (uid < 0) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 57828ca..4e848f8 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -148,7 +148,6 @@
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 
 /**
  * Collect and persist detailed network statistics, and provide this data to
@@ -769,7 +768,7 @@
     public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
         try {
             final String[] ifacesToQuery =
-                    NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces);
+                    NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces);
             return getNetworkStatsUidDetail(ifacesToQuery);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error compiling UID stats", e);
@@ -1527,12 +1526,14 @@
     private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
             throws RemoteException {
 
+        // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here.
         final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL,
                 ifaces);
 
         // fold tethering stats and operations into uid snapshot
         final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
         tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
+        NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot);
         uidSnapshot.combineAllValues(tetherSnapshot);
 
         final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -1542,13 +1543,12 @@
         final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
         if (vtStats != null) {
             vtStats.filter(UID_ALL, ifaces, TAG_ALL);
+            NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats);
             uidSnapshot.combineAllValues(vtStats);
         }
 
         uidSnapshot.combineAllValues(mUidOperations);
 
-        // TODO: apply tethering & VC 464xlat adjustments here
-
         return uidSnapshot;
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7f83f38..2e530af 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8766,7 +8766,10 @@
                 && !pkgSetting.isSystem()) {
 
             if (!pkg.mSigningDetails.checkCapability(pkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
+                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                            && !pkgSetting.signatures.mSigningDetails.checkCapability(
+                                    pkg.mSigningDetails,
+                                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
                 logCriticalInfo(Log.WARN,
                         "System package signature mismatch;"
                         + " name: " + pkgSetting.name);
@@ -10227,7 +10230,7 @@
         }
 
         if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
-            for (int i = changedAbiCodePath.size() - 1; i <= 0; --i) {
+            for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                 final String codePathString = changedAbiCodePath.get(i);
                 try {
                     mInstaller.rmdex(codePathString,
@@ -16217,7 +16220,10 @@
 
                 // default to original signature matching
                 if (!pkg.mSigningDetails.checkCapability(oldPackage.mSigningDetails,
-                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
+                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                                && !oldPackage.mSigningDetails.checkCapability(
+                                        pkg.mSigningDetails,
+                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
                     res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
                             "New package has a different signature: " + pkgName);
                     return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 853081a..4b907f4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -576,7 +576,10 @@
             PackageParser.collectCertificates(disabledPkgSetting.pkg, true /* skipVerify */);
             if (pkgSetting.signatures.mSigningDetails.checkCapability(
                     disabledPkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)) {
+                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                    || disabledPkgSetting.signatures.mSigningDetails.checkCapability(
+                            pkgSetting.signatures.mSigningDetails,
+                            PackageParser.SigningDetails.CertCapabilities.ROLLBACK)) {
                 return true;
             } else {
                 logCriticalInfo(Log.ERROR, "Updated system app mismatches cert on /system: " +
@@ -616,7 +619,10 @@
             // Already existing package. Make sure signatures match
             boolean match = parsedSignatures.checkCapability(
                     pkgSetting.signatures.mSigningDetails,
-                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA);
+                    PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                            || pkgSetting.signatures.mSigningDetails.checkCapability(
+                                    parsedSignatures,
+                                    PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
             if (!match && compareCompat) {
                 match = matchSignaturesCompat(packageName, pkgSetting.signatures,
                         parsedSignatures);
@@ -627,7 +633,12 @@
                         packageName,
                         pkgSetting.signatures.mSigningDetails,
                         parsedSignatures,
-                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA);
+                        PackageParser.SigningDetails.CertCapabilities.INSTALLED_DATA)
+                                || matchSignaturesRecover(
+                                        packageName,
+                                        parsedSignatures,
+                                        pkgSetting.signatures.mSigningDetails,
+                                        PackageParser.SigningDetails.CertCapabilities.ROLLBACK);
             }
 
             if (!match && isApkVerificationForced(disabledPkgSetting)) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fd02347..9a25dcc 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4976,13 +4976,14 @@
     private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
             boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
             DisplayFrames displayFrames) {
-        if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
-            // Here's a special case: if this attached window is a panel that is above the dock
-            // window, and the window it is attached to is below the dock window, then the frames we
-            // computed for the window it is attached to can not be used because the dock is
-            // effectively part of the underlying window and the attached window is floating on top
-            // of the whole thing. So, we ignore the attached window and explicitly compute the
-            // frames that would be appropriate without the dock.
+        if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
+            // Here's a special case: if the child window is not the 'dock window'
+            // or input method target, and the window it is attached to is below
+            // the dock window, then the frames we computed for the window it is
+            // attached to can not be used because the dock is effectively part
+            // of the underlying window and the attached window is floating on top
+            // of the whole thing. So, we ignore the attached window and explicitly
+            // compute the frames that would be appropriate without the dock.
             vf.set(displayFrames.mDock);
             cf.set(displayFrames.mDock);
             of.set(displayFrames.mDock);
@@ -5009,7 +5010,7 @@
                 cf.set(attached.getContentFrameLw());
                 if (attached.isVoiceInteraction()) {
                     cf.intersectUnchecked(displayFrames.mVoiceContent);
-                } else if (attached.getSurfaceLayer() < mDockLayer) {
+                } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
                     cf.intersectUnchecked(displayFrames.mContent);
                 }
             }
@@ -5500,7 +5501,6 @@
 
         win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf, displayFrames.mDisplayCutout,
                 parentFrameWasClippedByDisplayCutout);
-
         // Dock windows carve out the bottom of the screen, so normal windows
         // can't appear underneath them.
         if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 0a6ae4e..ccbf502 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -474,6 +474,8 @@
 
         public boolean isInputMethodWindow();
 
+        public boolean isInputMethodTarget();
+
         public int getDisplayId();
 
         /**
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 30bbfe0..54c2e9b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -897,7 +897,7 @@
             }
             final WindowState imeWin = mService.mInputMethodWindow;
             // IME is up and obscuring this window. Adjust the window position so it is visible.
-            if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this) {
+            if (imeWin != null && imeWin.isVisibleNow() && isInputMethodTarget()) {
                 if (inFreeformWindowingMode()
                         && mContainingFrame.bottom > contentFrame.bottom) {
                     // In freeform we want to move the top up directly.
@@ -1691,13 +1691,6 @@
             return changed;
         }
 
-        // Next up we will notify the client that it's visibility has changed.
-        // We need to prevent it from destroying child surfaces until
-        // the animation has finished.
-        if (!visible && isVisibleNow()) {
-            mWinAnimator.detachChildren();
-        }
-
         if (visible != isVisibleNow()) {
             if (!runningAppAnimation) {
                 final AccessibilityController accessibilityController =
@@ -1885,7 +1878,7 @@
         }
 
         final DisplayContent dc = getDisplayContent();
-        if (mService.mInputMethodTarget == this) {
+        if (isInputMethodTarget()) {
             dc.computeImeTarget(true /* updateImeTarget */);
         }
 
@@ -3949,7 +3942,7 @@
     private boolean applyInOrderWithImeWindows(ToBooleanFunction<WindowState> callback,
             boolean traverseTopToBottom) {
         if (traverseTopToBottom) {
-            if (mService.mInputMethodTarget == this) {
+            if (isInputMethodTarget()) {
                 // This window is the current IME target, so we need to process the IME windows
                 // directly above it.
                 if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
@@ -3963,7 +3956,7 @@
             if (callback.apply(this)) {
                 return true;
             }
-            if (mService.mInputMethodTarget == this) {
+            if (isInputMethodTarget()) {
                 // This window is the current IME target, so we need to process the IME windows
                 // directly above it.
                 if (getDisplayContent().forAllImeWindows(callback, traverseTopToBottom)) {
@@ -4673,7 +4666,7 @@
     void assignLayer(Transaction t, int layer) {
         // See comment in assignRelativeLayerForImeTargetChild
         if (!isChildWindow()
-                || (mService.mInputMethodTarget != getParentWindow())
+                || (!getParentWindow().isInputMethodTarget())
                 || !inSplitScreenWindowingMode()) {
             super.assignLayer(t, layer);
             return;
@@ -4741,6 +4734,11 @@
         mTapExcludeRegionHolder.amendRegion(region, getBounds());
     }
 
+    @Override
+    public boolean isInputMethodTarget() {
+        return mService.mInputMethodTarget == this;
+    }
+
     private final class MoveAnimationSpec implements AnimationSpec {
 
         private final long mDuration;
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index d190432..d5ff2dd 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -16,21 +16,21 @@
 
 package android.net.apf;
 
+import static android.net.util.NetworkConstants.*;
 import static android.system.OsConstants.*;
-
 import static com.android.internal.util.BitUtils.bytesToBEInt;
 import static com.android.internal.util.BitUtils.getUint16;
 import static com.android.internal.util.BitUtils.getUint32;
 import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint16;
 import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
 
-import android.os.SystemClock;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
-import android.net.apf.ApfGenerator;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
 import android.net.ip.IpClient;
@@ -39,31 +39,29 @@
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.RaEvent;
 import android.net.util.InterfaceParams;
+import android.os.PowerManager;
+import android.os.SystemClock;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.PacketSocketAddress;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Pair;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.HexDump;
 import com.android.internal.util.IndentingPrintWriter;
-
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.lang.Thread;
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.SocketException;
 import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
 import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
-
 import libcore.io.IoBridge;
 
 /**
@@ -215,10 +213,6 @@
             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
 
     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
-    private static final int ICMP6_ROUTER_SOLICITATION = 133;
-    private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
-    private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
-    private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
 
     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
@@ -258,9 +252,26 @@
     private long mUniqueCounter;
     @GuardedBy("this")
     private boolean mMulticastFilter;
+    @GuardedBy("this")
+    private boolean mInDozeMode;
     private final boolean mDrop802_3Frames;
     private final int[] mEthTypeBlackList;
 
+    // Detects doze mode state transitions.
+    private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
+                PowerManager powerManager =
+                        (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+                final boolean deviceIdle = powerManager.isDeviceIdleMode();
+                setDozeMode(deviceIdle);
+            }
+        }
+    };
+    private final Context mContext;
+
     // Our IPv4 address, if we have just one, otherwise null.
     @GuardedBy("this")
     private byte[] mIPv4Address;
@@ -269,13 +280,14 @@
     private int mIPv4PrefixLength;
 
     @VisibleForTesting
-    ApfFilter(ApfConfiguration config, InterfaceParams ifParams,
+    ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
             IpClient.Callback ipClientCallback, IpConnectivityLog log) {
         mApfCapabilities = config.apfCapabilities;
         mIpClientCallback = ipClientCallback;
         mInterfaceParams = ifParams;
         mMulticastFilter = config.multicastFilter;
         mDrop802_3Frames = config.ieee802_3Filter;
+        mContext = context;
 
         // Now fill the black list from the passed array
         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
@@ -284,6 +296,10 @@
 
         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
         maybeStartFilter();
+
+        // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
+        mContext.registerReceiver(mDeviceIdleReceiver,
+                new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
     }
 
     private void log(String s) {
@@ -522,7 +538,7 @@
             // to our packet socket. b/29586253
             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
-                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
+                    getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
                 throw new InvalidRaException("Not an ICMP6 router advertisement");
             }
 
@@ -889,10 +905,11 @@
     private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
         // Here's a basic summary of what the IPv6 filter program does:
         //
-        // if it's not ICMPv6:
-        //   if it's multicast and we're dropping multicast:
-        //     drop
-        //   pass
+        // if we're dropping multicast
+        //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
+        //     if it's multicast:
+        //       drop
+        //     pass
         // if it's ICMPv6 RS to any:
         //   drop
         // if it's ICMPv6 NA to ff02::1:
@@ -902,28 +919,44 @@
 
         // Drop multicast if the multicast filter is enabled.
         if (mMulticastFilter) {
-            // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
-            String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
-            gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
+            final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
+            final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
 
-            // Drop all other packets sent to ff00::/8.
+            // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
+            // While awake, let all ICMPv6 multicasts through.
+            if (mInDozeMode) {
+                // Not ICMPv6? -> Proceed to multicast filtering
+                gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
+
+                // ICMPv6 but not ECHO? -> Skip the multicast filter.
+                // (ICMPv6 ECHO requests will go through the multicast filter below).
+                gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+                gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
+            } else {
+                gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
+            }
+
+            // Drop all other packets sent to ff00::/8 (multicast prefix).
+            gen.defineLabel(dropAllIPv6MulticastsLabel);
             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
             gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
-            // Not multicast and not ICMPv6. Pass.
+            // Not multicast. Pass.
             gen.addJump(gen.PASS_LABEL);
-            gen.defineLabel(skipIpv6MulticastFilterLabel);
+            gen.defineLabel(skipIPv6MulticastFilterLabel);
         } else {
             // If not ICMPv6, pass.
             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
         }
 
+        // If we got this far, the packet is ICMPv6.  Drop some specific types.
+
         // Add unsolicited multicast neighbor announcements filter
         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
         // Drop all router solicitations (b/32833400)
-        gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+        gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, gen.DROP_LABEL);
         // If not neighbor announcements, skip filter.
-        gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
+        gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
         // If to ff02::1, drop.
         // TODO: Drop only if they don't contain the address of on-link neighbours.
         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
@@ -1168,9 +1201,9 @@
      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
      * filtering using APF programs.
      */
-    public static ApfFilter maybeCreate(ApfConfiguration config,
+    public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
             InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
-        if (config == null || ifParams == null) return null;
+        if (context == null || config == null || ifParams == null) return null;
         ApfCapabilities apfCapabilities =  config.apfCapabilities;
         if (apfCapabilities == null) return null;
         if (apfCapabilities.apfVersionSupported == 0) return null;
@@ -1187,7 +1220,8 @@
             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
             return null;
         }
-        return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog());
+
+        return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
     }
 
     public synchronized void shutdown() {
@@ -1197,12 +1231,11 @@
             mReceiveThread = null;
         }
         mRas.clear();
+        mContext.unregisterReceiver(mDeviceIdleReceiver);
     }
 
     public synchronized void setMulticastFilter(boolean isEnabled) {
-        if (mMulticastFilter == isEnabled) {
-            return;
-        }
+        if (mMulticastFilter == isEnabled) return;
         mMulticastFilter = isEnabled;
         if (!isEnabled) {
             mNumProgramUpdatesAllowingMulticast++;
@@ -1210,6 +1243,13 @@
         installNewProgramLocked();
     }
 
+    @VisibleForTesting
+    public synchronized void setDozeMode(boolean isEnabled) {
+        if (mInDozeMode == isEnabled) return;
+        mInDozeMode = isEnabled;
+        installNewProgramLocked();
+    }
+
     /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
     private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
         LinkAddress ipv4Address = null;
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 9863370..a184b22 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -1490,7 +1490,7 @@
                     mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
             apfConfig.ethTypeBlackList =
                     mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
-            mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback);
+            mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
             // rest of this IP configuration startup.
             if (mApfFilter == null) {
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 984c9f8..53fd01f 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -136,6 +136,8 @@
      *     - https://tools.ietf.org/html/rfc4861
      */
     public static final int ICMPV6_HEADER_MIN_LEN = 4;
+    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+    public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
     public static final int ICMPV6_ROUTER_SOLICITATION    = 133;
     public static final int ICMPV6_ROUTER_ADVERTISEMENT   = 134;
     public static final int ICMPV6_NEIGHBOR_SOLICITATION  = 135;
@@ -147,7 +149,6 @@
     public static final int ICMPV6_ND_OPTION_TLLA = 2;
     public static final int ICMPV6_ND_OPTION_MTU  = 5;
 
-    public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
 
     /**
      * UDP constants.
diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
index 56ba047..7487d44 100644
--- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
+++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java
@@ -258,4 +258,9 @@
     public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId){
         throw new UnsupportedOperationException("not implemented");
     }
+
+    @Override
+    public boolean isInputMethodTarget() {
+        return false;
+    }
 }
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index b070e03..c914689 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -30,12 +30,10 @@
     public long beginTime;
     public long endTime;
     public long lastTimeSaved;
-    public long lastInteractiveTime;
-    public long lastNonInteractiveTime;
-    public long interactiveDuration;
-    public int interactiveCount;
-    public long nonInteractiveDuration;
-    public int nonInteractiveCount;
+    public final EventTracker interactiveTracker = new EventTracker();
+    public final EventTracker nonInteractiveTracker = new EventTracker();
+    public final EventTracker keyguardShownTracker = new EventTracker();
+    public final EventTracker keyguardHiddenTracker = new EventTracker();
     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
     public Configuration activeConfiguration;
@@ -47,6 +45,44 @@
     // strings that had identical copies in the cache.
     private final ArraySet<String> mStringCache = new ArraySet<>();
 
+    public static final class EventTracker {
+        public long curStartTime;
+        public long lastEventTime;
+        public long duration;
+        public int count;
+
+        public void commitTime(long timeStamp) {
+            if (curStartTime != 0) {
+                duration += timeStamp - duration;
+                curStartTime = 0;
+            }
+        }
+
+        public void update(long timeStamp) {
+            if (curStartTime == 0) {
+                // If we aren't already running, time to bump the count.
+                count++;
+            }
+            commitTime(timeStamp);
+            curStartTime = timeStamp;
+            lastEventTime = timeStamp;
+        }
+
+        void addToEventStats(List<EventStats> out, int event, long beginTime, long endTime) {
+            if (count != 0 || duration != 0) {
+                EventStats ev = new EventStats();
+                ev.mEventType = event;
+                ev.mCount = count;
+                ev.mTotalTime = duration;
+                ev.mLastEventTime = lastEventTime;
+                ev.mBeginTimeStamp = beginTime;
+                ev.mEndTimeStamp = endTime;
+                out.add(ev);
+            }
+        }
+
+    }
+
     /**
      * Gets the UsageStats object for the given package, or creates one and adds it internally.
      */
@@ -180,58 +216,42 @@
         usageStats.mAppLaunchCount += 1;
     }
 
-    private void commitInteractiveTime(long timeStamp) {
-        if (lastInteractiveTime != 0) {
-            interactiveDuration += timeStamp - lastInteractiveTime;
-            lastInteractiveTime = 0;
-        }
-        if (lastNonInteractiveTime != 0) {
-            nonInteractiveDuration += timeStamp - lastNonInteractiveTime;
-            lastNonInteractiveTime = 0;
-        }
-    }
-
     void commitTime(long timeStamp) {
-        commitInteractiveTime(timeStamp);
+        interactiveTracker.commitTime(timeStamp);
+        nonInteractiveTracker.commitTime(timeStamp);
+        keyguardShownTracker.commitTime(timeStamp);
+        keyguardHiddenTracker.commitTime(timeStamp);
     }
 
     void updateScreenInteractive(long timeStamp) {
-        if (lastInteractiveTime != 0) {
-            // Already interactive, just keep running.
-            return;
-        }
-        commitInteractiveTime(timeStamp);
-        lastInteractiveTime = timeStamp;
-        interactiveCount++;
+        interactiveTracker.update(timeStamp);
+        nonInteractiveTracker.commitTime(timeStamp);
     }
 
     void updateScreenNonInteractive(long timeStamp) {
-        if (lastNonInteractiveTime != 0) {
-            // Already non-interactive, just keep running.
-            return;
-        }
-        commitInteractiveTime(timeStamp);
-        lastNonInteractiveTime = timeStamp;
-        nonInteractiveCount++;
+        nonInteractiveTracker.update(timeStamp);
+        interactiveTracker.commitTime(timeStamp);
     }
 
-    private void addOneEventStats(List<EventStats> out, int event, int count, long duration) {
-        if (count != 0 || duration != 0) {
-            EventStats ev = new EventStats();
-            ev.mEventType = event;
-            ev.mCount = count;
-            ev.mTotalTime = duration;
-            ev.mBeginTimeStamp = beginTime;
-            ev.mEndTimeStamp = endTime;
-            out.add(ev);
-        }
+    void updateKeyguardShown(long timeStamp) {
+        keyguardShownTracker.update(timeStamp);
+        keyguardHiddenTracker.commitTime(timeStamp);
+    }
+
+    void updateKeyguardHidden(long timeStamp) {
+        keyguardHiddenTracker.update(timeStamp);
+        keyguardShownTracker.commitTime(timeStamp);
     }
 
     void addEventStatsTo(List<EventStats> out) {
-        addOneEventStats(out, UsageEvents.Event.SCREEN_INTERACTIVE, interactiveCount,
-                interactiveDuration);
-        addOneEventStats(out, UsageEvents.Event.SCREEN_NON_INTERACTIVE, nonInteractiveCount,
-                nonInteractiveDuration);
+        interactiveTracker.addToEventStats(out, UsageEvents.Event.SCREEN_INTERACTIVE,
+                beginTime, endTime);
+        nonInteractiveTracker.addToEventStats(out, UsageEvents.Event.SCREEN_NON_INTERACTIVE,
+                beginTime, endTime);
+        keyguardShownTracker.addToEventStats(out, UsageEvents.Event.KEYGUARD_SHOWN,
+                beginTime, endTime);
+        keyguardHiddenTracker.addToEventStats(out, UsageEvents.Event.KEYGUARD_HIDDEN,
+                beginTime, endTime);
     }
 
     private String getCachedStringRef(String str) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 2287b27..fe3a884 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -40,6 +40,8 @@
 
     private static final String INTERACTIVE_TAG = "interactive";
     private static final String NON_INTERACTIVE_TAG = "non-interactive";
+    private static final String KEYGUARD_SHOWN_TAG = "keyguard-shown";
+    private static final String KEYGUARD_HIDDEN_TAG = "keyguard-hidden";
 
     private static final String PACKAGES_TAG = "packages";
     private static final String PACKAGE_TAG = "package";
@@ -103,12 +105,12 @@
         }
     }
 
-    private static Pair<Integer, Long> loadCountAndTime(XmlPullParser parser)
+    private static void loadCountAndTime(XmlPullParser parser,
+            IntervalStats.EventTracker tracker)
             throws IOException, XmlPullParserException {
-        int count = XmlUtils.readIntAttribute(parser, COUNT_ATTR, 0);
-        long time = XmlUtils.readLongAttribute(parser, TIME_ATTR, 0);
+        tracker.count = XmlUtils.readIntAttribute(parser, COUNT_ATTR, 0);
+        tracker.duration = XmlUtils.readLongAttribute(parser, TIME_ATTR, 0);
         XmlUtils.skipCurrentTag(parser);
-        return new Pair<>(count, time);
     }
 
     private static void loadChooserCounts(
@@ -340,17 +342,21 @@
 
             final String tag = parser.getName();
             switch (tag) {
-                case INTERACTIVE_TAG: {
-                    Pair<Integer, Long> result = loadCountAndTime(parser);
-                    statsOut.interactiveCount = result.first;
-                    statsOut.interactiveDuration = result.second;
-                } break;
+                case INTERACTIVE_TAG:
+                    loadCountAndTime(parser, statsOut.interactiveTracker);
+                    break;
 
-                case NON_INTERACTIVE_TAG: {
-                    Pair<Integer, Long> result = loadCountAndTime(parser);
-                    statsOut.nonInteractiveCount = result.first;
-                    statsOut.nonInteractiveDuration = result.second;
-                } break;
+                case NON_INTERACTIVE_TAG:
+                    loadCountAndTime(parser, statsOut.nonInteractiveTracker);
+                    break;
+
+                case KEYGUARD_SHOWN_TAG:
+                    loadCountAndTime(parser, statsOut.keyguardShownTracker);
+                    break;
+
+                case KEYGUARD_HIDDEN_TAG:
+                    loadCountAndTime(parser, statsOut.keyguardHiddenTracker);
+                    break;
 
                 case PACKAGE_TAG:
                     loadUsageStats(parser, statsOut);
@@ -378,10 +384,14 @@
     public static void write(XmlSerializer xml, IntervalStats stats) throws IOException {
         XmlUtils.writeLongAttribute(xml, END_TIME_ATTR, stats.endTime - stats.beginTime);
 
-        writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveCount, stats.interactiveDuration);
-
-        writeCountAndTime(xml, NON_INTERACTIVE_TAG, stats.nonInteractiveCount,
-                stats.nonInteractiveDuration);
+        writeCountAndTime(xml, INTERACTIVE_TAG, stats.interactiveTracker.count,
+                stats.interactiveTracker.duration);
+        writeCountAndTime(xml, NON_INTERACTIVE_TAG, stats.nonInteractiveTracker.count,
+                stats.nonInteractiveTracker.duration);
+        writeCountAndTime(xml, KEYGUARD_SHOWN_TAG, stats.keyguardShownTracker.count,
+                stats.keyguardShownTracker.duration);
+        writeCountAndTime(xml, KEYGUARD_HIDDEN_TAG, stats.keyguardHiddenTracker.count,
+                stats.keyguardHiddenTracker.duration);
 
         xml.startTag(null, PACKAGES_TAG);
         final int statsCount = stats.packageStats.size();
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 6ad374b..d9fc066 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -211,6 +211,12 @@
                 case UsageEvents.Event.SCREEN_NON_INTERACTIVE: {
                     stats.updateScreenNonInteractive(event.mTimeStamp);
                 } break;
+                case UsageEvents.Event.KEYGUARD_SHOWN: {
+                    stats.updateKeyguardShown(event.mTimeStamp);
+                } break;
+                case UsageEvents.Event.KEYGUARD_HIDDEN: {
+                    stats.updateKeyguardHidden(event.mTimeStamp);
+                } break;
                 default: {
                     stats.update(event.mPackage, event.mTimeStamp, event.mEventType);
                     if (incrementAppLaunch) {
@@ -665,14 +671,19 @@
         }
     }
 
-    void printEventAggregation(IndentingPrintWriter pw, String label, int count, long duration,
-            boolean prettyDates) {
-        if (count != 0 || duration != 0) {
+    void printEventAggregation(IndentingPrintWriter pw, String label,
+            IntervalStats.EventTracker tracker, boolean prettyDates) {
+        if (tracker.count != 0 || tracker.duration != 0) {
             pw.print(label);
             pw.print(": ");
-            pw.print(count);
+            pw.print(tracker.count);
             pw.print("x for ");
-            pw.print(formatElapsedTime(duration, prettyDates));
+            pw.print(formatElapsedTime(tracker.duration, prettyDates));
+            if (tracker.curStartTime != 0) {
+                pw.print(" (now running, started at ");
+                formatDateTime(tracker.curStartTime, prettyDates);
+                pw.print(")");
+            }
             pw.println();
         }
     }
@@ -752,10 +763,14 @@
             pw.decreaseIndent();
             pw.println("event aggregations");
             pw.increaseIndent();
-            printEventAggregation(pw, "screen-interactive", stats.interactiveCount,
-                    stats.interactiveDuration, prettyDates);
-            printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveCount,
-                    stats.nonInteractiveDuration, prettyDates);
+            printEventAggregation(pw, "screen-interactive", stats.interactiveTracker,
+                    prettyDates);
+            printEventAggregation(pw, "screen-non-interactive", stats.nonInteractiveTracker,
+                    prettyDates);
+            printEventAggregation(pw, "keyguard-shown", stats.keyguardShownTracker,
+                    prettyDates);
+            printEventAggregation(pw, "keyguard-hidden", stats.keyguardHiddenTracker,
+                    prettyDates);
             pw.decreaseIndent();
         }
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 7664b94..754fe68 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -505,7 +505,7 @@
     public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
 
     private final Context mContext;
-    private INetworkPolicyManager mNetworkPolicy;
+    private volatile INetworkPolicyManager mNetworkPolicy;
 
     /**
      * A listener class for monitoring changes to {@link SubscriptionInfo} records.
@@ -1794,7 +1794,7 @@
             @DurationMillisLong long timeoutMillis) {
         try {
             final int overrideValue = overrideUnmetered ? OVERRIDE_UNMETERED : 0;
-            mNetworkPolicy.setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue,
+            getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_UNMETERED, overrideValue,
                     timeoutMillis, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -1828,7 +1828,7 @@
             @DurationMillisLong long timeoutMillis) {
         try {
             final int overrideValue = overrideCongested ? OVERRIDE_CONGESTED : 0;
-            mNetworkPolicy.setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue,
+            getNetworkPolicy().setSubscriptionOverride(subId, OVERRIDE_CONGESTED, overrideValue,
                     timeoutMillis, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/telephony/java/android/telephony/SubscriptionPlan.java b/telephony/java/android/telephony/SubscriptionPlan.java
index 9411652..4ffb70b 100644
--- a/telephony/java/android/telephony/SubscriptionPlan.java
+++ b/telephony/java/android/telephony/SubscriptionPlan.java
@@ -34,6 +34,7 @@
 import java.time.Period;
 import java.time.ZonedDateTime;
 import java.util.Iterator;
+import java.util.Objects;
 
 /**
  * Description of a billing relationship plan between a carrier and a specific
@@ -124,6 +125,27 @@
                 .append("}").toString();
     }
 
+    @Override
+    public int hashCode() {
+        return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior,
+                dataUsageBytes, dataUsageTime);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SubscriptionPlan) {
+            final SubscriptionPlan other = (SubscriptionPlan) obj;
+            return Objects.equals(cycleRule, other.cycleRule)
+                    && Objects.equals(title, other.title)
+                    && Objects.equals(summary, other.summary)
+                    && dataLimitBytes == other.dataLimitBytes
+                    && dataLimitBehavior == other.dataLimitBehavior
+                    && dataUsageBytes == other.dataUsageBytes
+                    && dataUsageTime == other.dataUsageTime;
+        }
+        return false;
+    }
+
     public static final Parcelable.Creator<SubscriptionPlan> CREATOR = new Parcelable.Creator<SubscriptionPlan>() {
         @Override
         public SubscriptionPlan createFromParcel(Parcel source) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 15e0632..e15d35b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -27,6 +27,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.WorkerThread;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
@@ -1067,6 +1068,13 @@
     public static final int UNKNOWN_CARRIER_ID = -1;
 
     /**
+     * An unknown carrier id list version.
+     * @hide
+     */
+    @TestApi
+    public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1;
+
+    /**
      * Broadcast Action: The subscription carrier identity has changed.
      * This intent could be sent on the following events:
      * <ul>
@@ -7808,4 +7816,49 @@
             }
         }
     }
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+     * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
+            String gid2, String plmn, String spn) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.setCarrierTestOverride(
+                        getSubId(), mccmnc, imsi, iccid, gid1, gid2, plmn, spn);
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+    }
+
+    /**
+     * A test API to return installed carrier id list version
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
+     *
+     * @hide
+     */
+    @TestApi
+    public int getCarrierIdListVersion() {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getCarrierIdListVersion(getSubId());
+            }
+        } catch (RemoteException ex) {
+            // This could happen if binder process crashes.
+        }
+        return UNKNOWN_CARRIER_ID_LIST_VERSION;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index fbb69ad..03fc84d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1486,4 +1486,17 @@
      * screen is off) we want to turn on those indications even when the screen is off.
      */
     void setRadioIndicationUpdateMode(int subId, int filters, int mode);
+
+    /**
+     * A test API to override carrier information including mccmnc, imsi, iccid, gid1, gid2,
+     * plmn and spn. This would be handy for, eg, forcing a particular carrier id, carrier's config
+     * (also any country or carrier overlays) to be loaded when using a test SIM with a call box.
+     */
+    void setCarrierTestOverride(int subId, String mccmnc, String imsi, String iccid, String gid1,
+            String gid2, String plmn, String spn);
+
+    /**
+     * A test API to return installed carrier id list version.
+     */
+    int getCarrierIdListVersion(int subId);
 }
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 0530a86..8f18d07 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -39,8 +39,10 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.os.Process;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.SmallTest;
+import android.util.ArrayMap;
 
 import com.google.android.collect.Sets;
 
@@ -773,6 +775,88 @@
         assertEquals(entry2, stats.getValues(1, null));
     }
 
+    @Test
+    public void testApply464xlatAdjustments() {
+        final String v4Iface = "v4-wlan0";
+        final String baseIface = "wlan0";
+        final String otherIface = "other";
+        final int appUid = 10001;
+        final int rootUid = Process.ROOT_UID;
+        ArrayMap<String, String> stackedIface = new ArrayMap<>();
+        stackedIface.put(v4Iface, baseIface);
+
+        NetworkStats.Entry otherEntry = new NetworkStats.Entry(
+                otherIface, appUid, SET_DEFAULT, TAG_NONE,
+                2600  /* rxBytes */,
+                2 /* rxPackets */,
+                3800 /* txBytes */,
+                3 /* txPackets */,
+                0 /* operations */);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 3)
+                .addValues(v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+                        30501490  /* rxBytes */,
+                        22401 /* rxPackets */,
+                        876235 /* txBytes */,
+                        13805 /* txPackets */,
+                        0 /* operations */)
+                .addValues(baseIface, rootUid, SET_DEFAULT, TAG_NONE,
+                        31113087,
+                        22588,
+                        1169942,
+                        13902,
+                        0)
+                .addValues(otherEntry);
+
+        stats.apply464xlatAdjustments(stackedIface);
+
+        assertEquals(3, stats.size());
+        assertValues(stats, 0, v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+                30949510,
+                22401,
+                1152335,
+                13805,
+                0);
+        assertValues(stats, 1, baseIface, 0, SET_DEFAULT, TAG_NONE,
+                METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+                163577,
+                187,
+                17607,
+                97,
+                0);
+        assertEquals(otherEntry, stats.getValues(2, null));
+    }
+
+    @Test
+    public void testApply464xlatAdjustments_noStackedIface() {
+        NetworkStats.Entry firstEntry = new NetworkStats.Entry(
+                "if1", 10002, SET_DEFAULT, TAG_NONE,
+                2600  /* rxBytes */,
+                2 /* rxPackets */,
+                3800 /* txBytes */,
+                3 /* txPackets */,
+                0 /* operations */);
+        NetworkStats.Entry secondEntry = new NetworkStats.Entry(
+                "if2", 10002, SET_DEFAULT, TAG_NONE,
+                5000  /* rxBytes */,
+                3 /* rxPackets */,
+                6000 /* txBytes */,
+                4 /* txPackets */,
+                0 /* operations */);
+
+        NetworkStats stats = new NetworkStats(TEST_START, 2)
+                .addValues(firstEntry)
+                .addValues(secondEntry);
+
+        // Empty map: no adjustment
+        stats.apply464xlatAdjustments(new ArrayMap<>());
+
+        assertEquals(2, stats.size());
+        assertEquals(firstEntry, stats.getValues(0, null));
+        assertEquals(secondEntry, stats.getValues(1, null));
+    }
+
     private static void assertContains(NetworkStats stats,  String iface, int uid, int set,
             int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
             long txBytes, long txPackets, long operations) {
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 9b75a50..fef702e 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -16,6 +16,7 @@
 
 package android.net.apf;
 
+import static android.net.util.NetworkConstants.*;
 import static android.system.OsConstants.*;
 import static com.android.internal.util.BitUtils.bytesToBEInt;
 import static com.android.internal.util.BitUtils.put;
@@ -26,6 +27,7 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.verify;
 
+import android.content.Context;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkUtils;
@@ -82,6 +84,7 @@
     private static final int TIMEOUT_MS = 500;
 
     @Mock IpConnectivityLog mLog;
+    @Mock Context mContext;
 
     @Before
     public void setUp() throws Exception {
@@ -633,9 +636,9 @@
         private FileDescriptor mWriteSocket;
         private final long mFixedTimeMs = SystemClock.elapsedRealtime();
 
-        public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
-                IpConnectivityLog log) throws Exception {
-            super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
+        public TestApfFilter(Context context, ApfConfiguration config,
+                IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception {
+            super(context, config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
         }
 
         // Pretend an RA packet has been received and show it to ApfFilter.
@@ -757,6 +760,17 @@
     private static final byte[] ANOTHER_IPV4_ADDR        = {10, 0, 0, 2};
     private static final byte[] IPV4_ANY_HOST_ADDR       = {0, 0, 0, 0};
 
+    // Helper to initialize a default apfFilter.
+    private ApfFilter setupApfFilter(IpManager.Callback ipManagerCallback, ApfConfiguration config)
+            throws Exception {
+        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+        LinkProperties lp = new LinkProperties();
+        lp.addLinkAddress(link);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+        apfFilter.setLinkProperties(lp);
+        return apfFilter;
+    }
+
     @Test
     public void testApfFilterIPv4() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -766,7 +780,7 @@
 
         ApfConfiguration config = getDefaultConfig();
         config.multicastFilter = DROP_MULTICAST;
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -818,7 +832,7 @@
     public void testApfFilterIPv6() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         ApfConfiguration config = getDefaultConfig();
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify empty IPv6 packet is passed
@@ -861,7 +875,7 @@
 
         ApfConfiguration config = getDefaultConfig();
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
 
         byte[] program = ipManagerCallback.getApfProgram();
@@ -925,7 +939,7 @@
         apfFilter.shutdown();
         config.multicastFilter = DROP_MULTICAST;
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
         apfFilter.setLinkProperties(lp);
         program = ipManagerCallback.getApfProgram();
         assertDrop(program, mcastv4packet.array());
@@ -941,16 +955,47 @@
     }
 
     @Test
+    public void testApfFilterMulticastPingWhileDozing() throws Exception {
+        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+        ApfFilter apfFilter = setupApfFilter(ipManagerCallback, getDefaultConfig());
+
+        // Construct a multicast ICMPv6 ECHO request.
+        final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+        packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+        packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
+        put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
+
+        // Normally, we let multicast pings alone...
+        assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+        // ...and even while dozing...
+        apfFilter.setDozeMode(true);
+        assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+        // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
+        apfFilter.setMulticastFilter(true);
+        assertDrop(ipManagerCallback.getApfProgram(), packet.array());
+
+        // However, we should still let through all other ICMPv6 types.
+        ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
+        raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
+        assertPass(ipManagerCallback.getApfProgram(), raPacket.array());
+
+        // Now wake up from doze mode to ensure that we no longer drop the packets.
+        // (The multicast filter is still enabled at this point).
+        apfFilter.setDozeMode(false);
+        assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+        apfFilter.shutdown();
+    }
+
+    @Test
     public void testApfFilter802_3() throws Exception {
         MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
-
         ApfConfiguration config = getDefaultConfig();
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
+        ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify empty packet of 100 zero bytes is passed
@@ -970,8 +1015,7 @@
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
-        apfFilter.setLinkProperties(lp);
+        apfFilter = setupApfFilter(ipManagerCallback, config);
         program = ipManagerCallback.getApfProgram();
 
         // Verify that IEEE802.3 frame is dropped
@@ -992,18 +1036,13 @@
 
     @Test
     public void testApfFilterEthTypeBL() throws Exception {
-        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
-        LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
-        LinkProperties lp = new LinkProperties();
-        lp.addLinkAddress(link);
         final int[] emptyBlackList = {};
         final int[] ipv4BlackList = {ETH_P_IP};
         final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
 
+        MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
         ApfConfiguration config = getDefaultConfig();
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
-        apfFilter.setLinkProperties(lp);
-
+        ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
         byte[] program = ipManagerCallback.getApfProgram();
 
         // Verify empty packet of 100 zero bytes is passed
@@ -1023,8 +1062,7 @@
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
         config.ethTypeBlackList = ipv4BlackList;
-        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
-        apfFilter.setLinkProperties(lp);
+        apfFilter = setupApfFilter(ipManagerCallback, config);
         program = ipManagerCallback.getApfProgram();
 
         // Verify that IPv4 frame will be dropped
@@ -1039,8 +1077,7 @@
         ipManagerCallback.resetApfProgramWait();
         apfFilter.shutdown();
         config.ethTypeBlackList = ipv4Ipv6BlackList;
-        apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
-        apfFilter.setLinkProperties(lp);
+        apfFilter = setupApfFilter(ipManagerCallback, config);
         program = ipManagerCallback.getApfProgram();
 
         // Verify that IPv4 frame will be dropped
@@ -1081,7 +1118,7 @@
         ApfConfiguration config = getDefaultConfig();
         config.multicastFilter = DROP_MULTICAST;
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
 
         // Verify initially ARP request filter is off, and GARP filter is on.
         verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1205,7 +1242,7 @@
         ApfConfiguration config = getDefaultConfig();
         config.multicastFilter = DROP_MULTICAST;
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
         byte[] program = ipManagerCallback.getApfProgram();
 
         final int ROUTER_LIFETIME = 1000;
@@ -1351,7 +1388,7 @@
         ApfConfiguration config = getDefaultConfig();
         config.multicastFilter = DROP_MULTICAST;
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
         for (int i = 0; i < 1000; i++) {
             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
             r.nextBytes(packet);
@@ -1372,7 +1409,7 @@
         ApfConfiguration config = getDefaultConfig();
         config.multicastFilter = DROP_MULTICAST;
         config.ieee802_3Filter = DROP_802_3_FRAMES;
-        TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+        TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
         for (int i = 0; i < 1000; i++) {
             byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
             r.nextBytes(packet);
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 27f90f2..6142a7c 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -19,8 +19,14 @@
 import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
 import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
 import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -54,7 +60,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Resources;
 import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.INetworkPolicyManager;
 import android.net.INetworkStatsService;
@@ -125,7 +130,6 @@
 
     @Mock private ApplicationInfo mApplicationInfo;
     @Mock private Context mContext;
-    @Mock private ConnectivityManager mConnectivityManager;
     @Mock private INetworkManagementService mNMService;
     @Mock private INetworkStatsService mStatsService;
     @Mock private INetworkPolicyManager mPolicyManager;
@@ -173,7 +177,6 @@
 
         @Override
         public Object getSystemService(String name) {
-            if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
             if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
             if (Context.USB_SERVICE.equals(name)) return mUsbManager;
             return super.getSystemService(name);
@@ -181,8 +184,15 @@
     }
 
     public class MockTetheringDependencies extends TetheringDependencies {
-        private StateMachine upstreamNetworkMonitorMasterSM;
-        private ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+        StateMachine upstreamNetworkMonitorMasterSM;
+        ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+        int isTetheringSupportedCalls;
+
+        public void reset() {
+            upstreamNetworkMonitorMasterSM = null;
+            ipv6CoordinatorNotifyList = null;
+            isTetheringSupportedCalls = 0;
+        }
 
         @Override
         public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
@@ -222,11 +232,17 @@
             return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
                     MacAddress.ALL_ZEROS_ADDRESS);
         }
+
+        @Override
+        public boolean isTetheringSupported() {
+            isTetheringSupportedCalls++;
+            return true;
+        }
     }
 
     private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
             boolean with464xlat) {
-        final NetworkInfo info = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, null, null);
+        final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
         info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
         final LinkProperties prop = new LinkProperties();
         prop.setInterfaceName(TEST_MOBILE_IFNAME);
@@ -308,7 +324,8 @@
             }
         };
         mServiceContext.registerReceiver(mBroadcastReceiver,
-                new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+                new IntentFilter(ACTION_TETHER_STATE_CHANGED));
+        mTetheringDependencies.reset();
         mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
                                    mLooper.getLooper(), mSystemProperties,
                                    mTetheringDependencies);
@@ -404,7 +421,7 @@
     private void verifyTetheringBroadcast(String ifname, String whichExtra) {
         // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
         final Intent bcast = mIntents.get(0);
-        assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+        assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
         final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
         assertTrue(ifnames.contains(ifname));
         mIntents.remove(bcast);
@@ -412,8 +429,6 @@
 
     public void failingLocalOnlyHotspotLegacyApBroadcast(
             boolean emulateInterfaceStatusChanged) throws Exception {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
@@ -427,16 +442,14 @@
         // then it creates a TetherInterfaceStateMachine and sends out a
         // broadcast indicating that the interface is "available".
         if (emulateInterfaceStatusChanged) {
-            verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-            verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+            assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+            verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
         }
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
     }
 
     private void prepareUsbTethering(NetworkState upstreamState) {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
                 .thenReturn(upstreamState);
 
@@ -454,7 +467,6 @@
         prepareUsbTethering(upstreamState);
 
         // This should produce no activity of any kind.
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
 
         // Pretend we then receive USB configured broadcast.
@@ -481,8 +493,6 @@
 
     public void workingLocalOnlyHotspotEnrichedApBroadcast(
             boolean emulateInterfaceStatusChanged) throws Exception {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
         // Emulate externally-visible WifiManager effects, causing the
         // per-interface state machine to start up, and telling us that
         // hotspot mode is to be started.
@@ -493,18 +503,17 @@
         mLooper.dispatchAll();
 
         verifyInterfaceServingModeStarted();
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
         verify(mWifiManager).updateInterfaceIpState(
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
         verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
         verify(mUpstreamNetworkMonitor, times(1)).start();
         // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyNoMoreInteractions(mConnectivityManager);
+        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
 
         // Emulate externally-visible WifiManager effects, when hotspot mode
         // is being torn down.
@@ -523,8 +532,7 @@
         verifyNoMoreInteractions(mWifiManager);
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
-        assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
-                mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
     }
 
     /**
@@ -648,7 +656,6 @@
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failingWifiTetheringLegacyApBroadcast() throws Exception {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
@@ -656,7 +663,6 @@
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
 
         // Emulate externally-visible WifiManager effects, causing the
@@ -666,9 +672,8 @@
         sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
         mLooper.dispatchAll();
 
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
-        verifyNoMoreInteractions(mConnectivityManager);
+        assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
         verifyNoMoreInteractions(mNMService);
         verifyNoMoreInteractions(mWifiManager);
     }
@@ -676,7 +681,6 @@
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
@@ -684,7 +688,6 @@
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
 
         // Emulate externally-visible WifiManager effects, causing the
@@ -695,21 +698,20 @@
         mLooper.dispatchAll();
 
         verifyInterfaceServingModeStarted();
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         verify(mNMService, times(1)).startTethering(any(String[].class));
         verifyNoMoreInteractions(mNMService);
         verify(mWifiManager).updateInterfaceIpState(
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
         verifyNoMoreInteractions(mWifiManager);
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_TETHER);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
         verify(mUpstreamNetworkMonitor, times(1)).start();
         // In tethering mode, in the default configuration, an explicit request
         // for a mobile network is also made.
         verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
         // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyNoMoreInteractions(mConnectivityManager);
+        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
 
         /////
         // We do not currently emulate any upstream being found.
@@ -723,7 +725,6 @@
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).stopSoftAp();
         verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
 
         // Emulate externally-visible WifiManager effects, when tethering mode
@@ -743,14 +744,12 @@
         verifyNoMoreInteractions(mWifiManager);
         // Asking for the last error after the per-interface state machine
         // has been reaped yields an unknown interface error.
-        assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
-                mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+        assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
     }
 
     // TODO: Test with and without interfaceStatusChanged().
     @Test
     public void failureEnablingIpForwarding() throws Exception {
-        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
         doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
 
@@ -759,7 +758,6 @@
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
 
         // Emulate externally-visible WifiManager effects, causing the
@@ -778,8 +776,9 @@
         verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
         verify(mWifiManager).updateInterfaceIpState(
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
-        verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
-        verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+        // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
+        assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+        verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
         // This is called, but will throw.
         verify(mNMService, times(1)).setIpForwardingEnabled(true);
         // This never gets called because of the exception thrown above.
@@ -792,7 +791,6 @@
                 TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
 
         verifyNoMoreInteractions(mWifiManager);
-        verifyNoMoreInteractions(mConnectivityManager);
         verifyNoMoreInteractions(mNMService);
     }