Merge "Add permission hint, update permission slice structure" into pi-dev
diff --git a/Android.mk b/Android.mk
index e219661..d7d9c90 100644
--- a/Android.mk
+++ b/Android.mk
@@ -252,6 +252,11 @@
 		-federate SupportLib https://developer.android.com \
 		-federationapi SupportLib prebuilts/sdk/current/support-api.txt
 
+# Federate AndroidX references against local API file.
+framework_docs_LOCAL_DROIDDOC_OPTIONS += \
+		-federate AndroidX https://developer.android.com \
+		-federationapi AndroidX prebuilts/sdk/current/androidx-api.txt
+
 # ====  Public API diff ===========================
 include $(CLEAR_VARS)
 
diff --git a/api/current.txt b/api/current.txt
index 7251e8f..9968258 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6115,8 +6115,12 @@
     method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats();
     method public android.view.WindowContentFrameStats getWindowContentFrameStats(int);
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
+    method public void grantRuntimePermission(java.lang.String, java.lang.String);
+    method public void grantRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle);
     method public boolean injectInputEvent(android.view.InputEvent, boolean);
     method public boolean performGlobalAction(int);
+    method public void revokeRuntimePermission(java.lang.String, java.lang.String);
+    method public void revokeRuntimePermissionAsUser(java.lang.String, java.lang.String, android.os.UserHandle);
     method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
     method public boolean setRotation(int);
     method public void setRunAsMonkey(boolean);
@@ -6501,7 +6505,7 @@
     method public boolean installExistingPackage(android.content.ComponentName, java.lang.String);
     method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
     method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
-    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean);
+    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, int);
     method public boolean isActivePasswordSufficient();
     method public boolean isAdminActive(android.content.ComponentName);
     method public boolean isAffiliatedUser();
@@ -6685,6 +6689,8 @@
     field public static final int ID_TYPE_IMEI = 4; // 0x4
     field public static final int ID_TYPE_MEID = 8; // 0x8
     field public static final int ID_TYPE_SERIAL = 2; // 0x2
+    field public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1; // 0x1
+    field public static final int INSTALLKEY_SET_USER_SELECTABLE = 2; // 0x2
     field public static final int KEYGUARD_DISABLE_BIOMETRICS = 416; // 0x1a0
     field public static final int KEYGUARD_DISABLE_FACE = 128; // 0x80
     field public static final int KEYGUARD_DISABLE_FEATURES_ALL = 2147483647; // 0x7fffffff
@@ -13645,7 +13651,6 @@
     method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
     method public android.graphics.PostProcessor getPostProcessor();
     method public boolean getRequireUnpremultiplied();
-    method public android.util.Size getSampledSize(int);
     method public android.graphics.ImageDecoder setAllocator(int);
     method public android.graphics.ImageDecoder setConserveMemory(boolean);
     method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
@@ -13654,8 +13659,9 @@
     method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
     method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
     method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
-    method public android.graphics.ImageDecoder setResize(int, int);
-    method public android.graphics.ImageDecoder setResize(int);
+    method public android.graphics.ImageDecoder setTargetColorSpace(android.graphics.ColorSpace);
+    method public android.graphics.ImageDecoder setTargetSampleSize(int);
+    method public android.graphics.ImageDecoder setTargetSize(int, int);
     field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
     field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
@@ -13671,6 +13677,7 @@
   }
 
   public static class ImageDecoder.ImageInfo {
+    method public android.graphics.ColorSpace getColorSpace();
     method public java.lang.String getMimeType();
     method public android.util.Size getSize();
     method public boolean isAnimated();
@@ -23455,9 +23462,6 @@
     field public static final int HDCP_V2 = 3; // 0x3
     field public static final int HDCP_V2_1 = 4; // 0x4
     field public static final int HDCP_V2_2 = 5; // 0x5
-    field public static final int HW_SECURE_ALL = 5; // 0x5
-    field public static final int HW_SECURE_CRYPTO = 3; // 0x3
-    field public static final int HW_SECURE_DECODE = 4; // 0x4
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
     field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -23466,9 +23470,12 @@
     field public static final java.lang.String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
     field public static final java.lang.String PROPERTY_VENDOR = "vendor";
     field public static final java.lang.String PROPERTY_VERSION = "version";
+    field public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5; // 0x5
+    field public static final int SECURITY_LEVEL_HW_SECURE_CRYPTO = 3; // 0x3
+    field public static final int SECURITY_LEVEL_HW_SECURE_DECODE = 4; // 0x4
+    field public static final int SECURITY_LEVEL_SW_SECURE_CRYPTO = 1; // 0x1
+    field public static final int SECURITY_LEVEL_SW_SECURE_DECODE = 2; // 0x2
     field public static final int SECURITY_LEVEL_UNKNOWN = 0; // 0x0
-    field public static final int SW_SECURE_CRYPTO = 1; // 0x1
-    field public static final int SW_SECURE_DECODE = 2; // 0x2
   }
 
   public final class MediaDrm.CryptoSession {
@@ -25759,6 +25766,7 @@
   public final class MediaSession {
     ctor public MediaSession(android.content.Context, java.lang.String);
     method public android.media.session.MediaController getController();
+    method public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isActive();
     method public void release();
@@ -25825,6 +25833,7 @@
     method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName);
     method public void addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, android.content.ComponentName, android.os.Handler);
     method public java.util.List<android.media.session.MediaController> getActiveSessions(android.content.ComponentName);
+    method public boolean isTrustedForMediaControl(android.media.session.MediaSessionManager.RemoteUserInfo);
     method public void removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener);
   }
 
@@ -25832,6 +25841,13 @@
     method public abstract void onActiveSessionsChanged(java.util.List<android.media.session.MediaController>);
   }
 
+  public static final class MediaSessionManager.RemoteUserInfo {
+    ctor public MediaSessionManager.RemoteUserInfo(java.lang.String, int, int);
+    method public java.lang.String getPackageName();
+    method public int getPid();
+    method public int getUid();
+  }
+
   public final class PlaybackState implements android.os.Parcelable {
     method public int describeContents();
     method public long getActions();
@@ -39169,6 +39185,7 @@
     ctor public MediaBrowserService();
     method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
     method public final android.os.Bundle getBrowserRootHints();
+    method public final android.media.session.MediaSessionManager.RemoteUserInfo getCurrentBrowserInfo();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public void notifyChildrenChanged(java.lang.String);
     method public void notifyChildrenChanged(java.lang.String, android.os.Bundle);
@@ -50403,9 +50420,9 @@
     ctor public TextClassification.Options();
     method public int describeContents();
     method public android.os.LocaleList getDefaultLocales();
-    method public java.util.Calendar getReferenceTime();
+    method public java.time.ZonedDateTime getReferenceTime();
     method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
-    method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar);
+    method public android.view.textclassifier.TextClassification.Options setReferenceTime(java.time.ZonedDateTime);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassification.Options> CREATOR;
   }
diff --git a/api/removed.txt b/api/removed.txt
index 9fe25c9..5863e77 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -184,6 +184,8 @@
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public deprecated boolean getAsAlphaMask();
     method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    method public deprecated android.graphics.ImageDecoder setResize(int, int);
+    method public deprecated android.graphics.ImageDecoder setResize(int);
     field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
     field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1
     field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
diff --git a/api/system-current.txt b/api/system-current.txt
index 5568dba..ed763ba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -57,6 +57,7 @@
     field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
     field public static final java.lang.String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
     field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
+    field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
     field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
     field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
     field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN";
@@ -1252,6 +1253,7 @@
     method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
     method public android.graphics.Point getStableDisplaySize();
     method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
+    method public void setSaturationLevel(float);
   }
 
 }
@@ -2101,6 +2103,7 @@
     method public java.lang.String getVersion();
     method public boolean isBackgroundScanningSupported();
     method public boolean isCaptureSupported();
+    method public boolean isInitializationRequired();
     method public boolean isProgramIdentifierSupported(int);
     method public boolean isProgramTypeSupported(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index d323725..b520dfb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1,8 +1,10 @@
 package android {
 
   public static final class Manifest.permission {
+    field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
     field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
     field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
+    field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
   }
 
 }
@@ -127,8 +129,8 @@
   public final class UiAutomation {
     method public void destroy();
     method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String);
-    method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
-    method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public deprecated boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public deprecated boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
   }
 
   public class UiModeManager {
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 9df229c..6676196 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -264,13 +264,13 @@
                     } else if ("q".equals(line) || "quit".equals(line)) {
                         break;
                     } else if ("play".equals(line)) {
-                        mController.play();
+                        mController.play("");
                     } else if ("pause".equals(line)) {
-                        mController.pause();
+                        mController.pause("");
                     } else if ("next".equals(line)) {
-                        mController.next();
+                        mController.next("");
                     } else if ("previous".equals(line)) {
-                        mController.previous();
+                        mController.previous("");
                     } else {
                         System.out.println("Invalid command: " + line);
                     }
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index a458c07..c1ff275 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -79,8 +79,6 @@
       mSendBroadcast(sendBroadcast),
       mTimeBaseSec(timeBaseSec),
       mLastLogTimestamp(0) {
-    StatsPullerManager statsPullerManager;
-    statsPullerManager.SetTimeBaseSec(mTimeBaseSec);
 }
 
 StatsLogProcessor::~StatsLogProcessor() {
@@ -177,7 +175,7 @@
 
     uint64_t curTimeSec = getElapsedRealtimeSec();
     if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
-        mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec);
+        mStatsPullerManager.ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
         mLastPullerCacheClearTimeSec = curTimeSec;
     }
 
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b03b4b4..9f70c75 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -595,7 +595,7 @@
 status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
     int s = atoi(args[1].c_str());
     vector<shared_ptr<LogEvent> > stats;
-    if (mStatsPullerManager.Pull(s, &stats)) {
+    if (mStatsPullerManager.Pull(s, getElapsedRealtimeNs(), &stats)) {
         for (const auto& it : stats) {
             fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
         }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 5e75359..cfb9d87 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -245,7 +245,7 @@
  * Logs when the ble scan state changes.
  *
  * Logged from:
- *   frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ *   packages/apps/Bluetooth/src/com/android/bluetooth/gatt/AppScanStats.java
  */
 // TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
 message BleScanStateChanged {
diff --git a/cmds/statsd/src/external/StatsPuller.cpp b/cmds/statsd/src/external/StatsPuller.cpp
index 3b0cd34..ec5a5d6 100644
--- a/cmds/statsd/src/external/StatsPuller.cpp
+++ b/cmds/statsd/src/external/StatsPuller.cpp
@@ -35,26 +35,31 @@
 // ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
 StatsPuller::StatsPuller(const int tagId)
     : mTagId(tagId) {
-    mCoolDownSec = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownSec;
-    VLOG("Puller for tag %d created. Cooldown set to %ld", mTagId, mCoolDownSec);
+    mCoolDownNs = StatsPullerManagerImpl::kAllPullAtomInfo.find(tagId)->second.coolDownNs;
+    VLOG("Puller for tag %d created. Cooldown set to %lld", mTagId, (long long)mCoolDownNs);
 }
 
-bool StatsPuller::Pull(std::vector<std::shared_ptr<LogEvent>>* data) {
+bool StatsPuller::Pull(const int64_t elapsedTimeNs, std::vector<std::shared_ptr<LogEvent>>* data) {
     lock_guard<std::mutex> lock(mLock);
+    int64_t wallClockTimeNs = getWallClockNs();
     StatsdStats::getInstance().notePull(mTagId);
-    long curTime = getElapsedRealtimeSec();
-    if (curTime - mLastPullTimeSec < mCoolDownSec) {
+    if (elapsedTimeNs - mLastPullTimeNs < mCoolDownNs) {
         (*data) = mCachedData;
         StatsdStats::getInstance().notePullFromCache(mTagId);
         return true;
     }
-    if (mMinPullIntervalSec > curTime - mLastPullTimeSec) {
-        mMinPullIntervalSec = curTime - mLastPullTimeSec;
-        StatsdStats::getInstance().updateMinPullIntervalSec(mTagId, mMinPullIntervalSec);
+    if (mMinPullIntervalNs > elapsedTimeNs - mLastPullTimeNs) {
+        mMinPullIntervalNs = elapsedTimeNs - mLastPullTimeNs;
+        StatsdStats::getInstance().updateMinPullIntervalSec(mTagId,
+                                                            mMinPullIntervalNs / NS_PER_SEC);
     }
     mCachedData.clear();
-    mLastPullTimeSec = curTime;
+    mLastPullTimeNs = elapsedTimeNs;
     bool ret = PullInternal(&mCachedData);
+    for (const shared_ptr<LogEvent>& data : mCachedData) {
+        data->setElapsedTimestampNs(elapsedTimeNs);
+        data->setLogdWallClockTimestampNs(wallClockTimeNs);
+    }
     if (ret) {
       mergeIsolatedUidsToHostUid(mCachedData, mUidMap, mTagId);
       (*data) = mCachedData;
@@ -70,12 +75,12 @@
     lock_guard<std::mutex> lock(mLock);
     int ret = mCachedData.size();
     mCachedData.clear();
-    mLastPullTimeSec = 0;
+    mLastPullTimeNs = 0;
     return ret;
 }
 
-int StatsPuller::ClearCacheIfNecessary(long timestampSec) {
-    if (timestampSec - mLastPullTimeSec > mCoolDownSec) {
+int StatsPuller::ClearCacheIfNecessary(int64_t timestampNs) {
+    if (timestampNs - mLastPullTimeNs > mCoolDownNs) {
         return clearCache();
     } else {
         return 0;
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 936c47e..caac677 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -37,13 +37,13 @@
 
     virtual ~StatsPuller() {}
 
-    bool Pull(std::vector<std::shared_ptr<LogEvent>>* data);
+    bool Pull(const int64_t timeNs, std::vector<std::shared_ptr<LogEvent>>* data);
 
     // Clear cache immediately
     int ForceClearCache();
 
     // Clear cache if elapsed time is more than cooldown time
-    int ClearCacheIfNecessary(long timestampSec);
+    int ClearCacheIfNecessary(int64_t timestampNs);
 
     static void SetUidMap(const sp<UidMap>& uidMap);
 
@@ -59,9 +59,9 @@
     // If a pull request comes before cooldown, a cached version from purevious pull
     // will be returned.
     // The actual value should be determined by individual pullers.
-    long mCoolDownSec;
+    int64_t mCoolDownNs;
     // For puller stats
-    long mMinPullIntervalSec = LONG_MAX;
+    int64_t mMinPullIntervalNs = LONG_MAX;
 
     virtual bool PullInternal(std::vector<std::shared_ptr<LogEvent>>* data) = 0;
 
@@ -69,7 +69,7 @@
     // cached data will be returned.
     std::vector<std::shared_ptr<LogEvent>> mCachedData;
 
-    long mLastPullTimeSec;
+    int64_t mLastPullTimeNs;
 
     int clearCache();
 
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index 2717d5c..83d59c0 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -26,10 +26,9 @@
  public:
     virtual ~StatsPullerManager() {}
 
-    virtual void RegisterReceiver(int tagId,
-                                  wp <PullDataReceiver> receiver,
-                                  long intervalMs) {
-        mPullerManager.RegisterReceiver(tagId, receiver, intervalMs);
+    virtual void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, int64_t nextPullTimeNs,
+                                  int64_t intervalNs) {
+        mPullerManager.RegisterReceiver(tagId, receiver, nextPullTimeNs, intervalNs);
     };
 
     virtual void UnRegisterReceiver(int tagId, wp <PullDataReceiver> receiver) {
@@ -45,13 +44,9 @@
         mPullerManager.OnAlarmFired();
     }
 
-    virtual bool
-    Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) {
-        return mPullerManager.Pull(tagId, data);
-    }
-
-    void SetTimeBaseSec(const long timeBaseSec) {
-        mPullerManager.SetTimeBaseSec(timeBaseSec);
+    virtual bool Pull(const int tagId, const int64_t timesNs,
+                      vector<std::shared_ptr<LogEvent>>* data) {
+        return mPullerManager.Pull(tagId, timesNs, data);
     }
 
     int ForceClearPullerCache() {
@@ -62,8 +57,8 @@
         mPullerManager.SetStatsCompanionService(statsCompanionService);
     }
 
-    int ClearPullerCacheIfNecessary(long timestampSec) {
-        return mPullerManager.ClearPullerCacheIfNecessary(timestampSec);
+    int ClearPullerCacheIfNecessary(int64_t timestampNs) {
+        return mPullerManager.ClearPullerCacheIfNecessary(timestampNs);
     }
 
  private:
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index dd6406b..0e23bf0 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -19,15 +19,17 @@
 
 #include <android/os/IStatsCompanionService.h>
 #include <cutils/log.h>
+#include <math.h>
 #include <algorithm>
 #include <climits>
+#include "../StatsService.h"
 #include "../logd/LogEvent.h"
 #include "../stats_log_util.h"
 #include "../statscompanion_util.h"
 #include "ResourceHealthManagerPuller.h"
 #include "ResourceThermalManagerPuller.h"
 #include "StatsCompanionServicePuller.h"
-#include "StatsService.h"
+#include "StatsPullerManagerImpl.h"
 #include "SubsystemSleepStatePuller.h"
 #include "statslog.h"
 
@@ -47,89 +49,136 @@
 const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
         // wifi_bytes_transfer
         {android::util::WIFI_BYTES_TRANSFER,
-         {{2, 3, 4, 5}, {}, 1,
+         {{2, 3, 4, 5},
+          {},
+          1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER)}},
         // wifi_bytes_transfer_by_fg_bg
         {android::util::WIFI_BYTES_TRANSFER_BY_FG_BG,
-         {{3, 4, 5, 6}, {2}, 1,
+         {{3, 4, 5, 6},
+          {2},
+          1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
         // mobile_bytes_transfer
         {android::util::MOBILE_BYTES_TRANSFER,
-         {{2, 3, 4, 5}, {}, 1,
+         {{2, 3, 4, 5},
+          {},
+          1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER)}},
         // mobile_bytes_transfer_by_fg_bg
         {android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG,
-         {{3, 4, 5, 6}, {2}, 1,
+         {{3, 4, 5, 6},
+          {2},
+          1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::MOBILE_BYTES_TRANSFER_BY_FG_BG)}},
         // bluetooth_bytes_transfer
         {android::util::BLUETOOTH_BYTES_TRANSFER,
-         {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
+         {{2, 3},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::BLUETOOTH_BYTES_TRANSFER)}},
         // kernel_wakelock
         {android::util::KERNEL_WAKELOCK,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
         // subsystem_sleep_state
         {android::util::SUBSYSTEM_SLEEP_STATE,
-         {{}, {}, 1, new SubsystemSleepStatePuller()}},
+         {{}, {}, 1 * NS_PER_SEC, new SubsystemSleepStatePuller()}},
         // cpu_time_per_freq
         {android::util::CPU_TIME_PER_FREQ,
-         {{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+         {{3},
+          {2},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
         // cpu_time_per_uid
         {android::util::CPU_TIME_PER_UID,
-         {{2, 3}, {}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
+         {{2, 3},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID)}},
         // cpu_time_per_uid_freq
-        // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+        // the throttling is 3sec, handled in
+        // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {android::util::CPU_TIME_PER_UID_FREQ,
-         {{4}, {2,3}, 0, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
+         {{4},
+          {2, 3},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CPU_TIME_PER_UID_FREQ)}},
         // cpu_active_time
-        // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+        // the throttling is 3sec, handled in
+        // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {android::util::CPU_ACTIVE_TIME,
-         {{2}, {}, 0, new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
+         {{2},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CPU_ACTIVE_TIME)}},
         // cpu_cluster_time
-        // the throttling is 3sec, handled in frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
+        // the throttling is 3sec, handled in
+        // frameworks/base/core/java/com/android/internal/os/KernelCpuProcReader
         {android::util::CPU_CLUSTER_TIME,
-         {{3}, {2}, 0, new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
+         {{3},
+          {2},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::CPU_CLUSTER_TIME)}},
         // wifi_activity_energy_info
         {android::util::WIFI_ACTIVITY_ENERGY_INFO,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
         // modem_activity_info
         {android::util::MODEM_ACTIVITY_INFO,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
         // bluetooth_activity_info
         {android::util::BLUETOOTH_ACTIVITY_INFO,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
         // system_elapsed_realtime
         {android::util::SYSTEM_ELAPSED_REALTIME,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
         // system_uptime
         {android::util::SYSTEM_UPTIME,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
         // disk_space
         {android::util::DISK_SPACE,
-         {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
+         {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
         // remaining_battery_capacity
         {android::util::REMAINING_BATTERY_CAPACITY,
-         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
         // full_battery_capacity
         {android::util::FULL_BATTERY_CAPACITY,
-         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
+         {{},
+          {},
+          1 * NS_PER_SEC,
+          new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}},
         // process_memory_state
         {android::util::PROCESS_MEMORY_STATE,
-         {{4,5,6,7,8},
-          {2,3},
-          0,
+         {{4, 5, 6, 7, 8},
+          {2, 3},
+          1 * NS_PER_SEC,
           new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}},
         // temperature
         {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}};
 
-StatsPullerManagerImpl::StatsPullerManagerImpl()
-    : mCurrentPullingInterval(LONG_MAX) {
+StatsPullerManagerImpl::StatsPullerManagerImpl() : mNextPullTimeNs(LONG_MAX) {
 }
 
-bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
+bool StatsPullerManagerImpl::Pull(const int tagId, const int64_t timeNs,
+                                  vector<shared_ptr<LogEvent>>* data) {
     VLOG("Initiating pulling %d", tagId);
 
     if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
-        bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
+        bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(timeNs, data);
         VLOG("pulled %d items", (int)data->size());
         return ret;
     } else {
@@ -148,12 +197,14 @@
 }
 
 void StatsPullerManagerImpl::updateAlarmLocked() {
-    long currentTimeMs = getElapsedRealtimeMillis();
-    long nextAlarmTimeMs = currentTimeMs + mCurrentPullingInterval -
-        (currentTimeMs - mTimeBaseSec * 1000) % mCurrentPullingInterval;
+    if (mNextPullTimeNs == LONG_MAX) {
+        VLOG("No need to set alarms. Skipping");
+        return;
+    }
+
     sp<IStatsCompanionService> statsCompanionServiceCopy = mStatsCompanionService;
     if (statsCompanionServiceCopy != nullptr) {
-        statsCompanionServiceCopy->setPullingAlarms(nextAlarmTimeMs, mCurrentPullingInterval);
+        statsCompanionServiceCopy->setPullingAlarm(mNextPullTimeNs / 1000000);
     } else {
         VLOG("StatsCompanionService not available. Alarm not set.");
     }
@@ -174,7 +225,7 @@
 }
 
 void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver,
-                                              long intervalMs) {
+                                              int64_t nextPullTimeNs, int64_t intervalNs) {
     AutoMutex _l(mLock);
     auto& receivers = mReceivers[tagId];
     for (auto it = receivers.begin(); it != receivers.end(); it++) {
@@ -185,21 +236,24 @@
     }
     ReceiverInfo receiverInfo;
     receiverInfo.receiver = receiver;
-    receiverInfo.timeInfo.first = intervalMs;
-    receivers.push_back(receiverInfo);
 
     // Round it to the nearest minutes. This is the limit of alarm manager.
-    // In practice, we should limit it higher.
-    long roundedIntervalMs = intervalMs/1000/60 * 1000 * 60;
+    // In practice, we should always have larger buckets.
+    int64_t roundedIntervalNs = intervalNs / NS_PER_SEC / 60 * NS_PER_SEC * 60;
     // Scheduled pulling should be at least 1 min apart.
     // This can be lower in cts tests, in which case we round it to 1 min.
-    if (roundedIntervalMs < 60 * 1000) {
-        roundedIntervalMs = 60 * 1000;
+    if (roundedIntervalNs < 60 * (int64_t)NS_PER_SEC) {
+        roundedIntervalNs = 60 * (int64_t)NS_PER_SEC;
     }
+
+    receiverInfo.intervalNs = roundedIntervalNs;
+    receiverInfo.nextPullTimeNs = nextPullTimeNs;
+    receivers.push_back(receiverInfo);
+
     // There is only one alarm for all pulled events. So only set it to the smallest denom.
-    if (roundedIntervalMs < mCurrentPullingInterval) {
-        VLOG("Updating pulling interval %ld", intervalMs);
-        mCurrentPullingInterval = roundedIntervalMs;
+    if (nextPullTimeNs < mNextPullTimeNs) {
+        VLOG("Updating next pull time %lld", (long long)mNextPullTimeNs);
+        mNextPullTimeNs = nextPullTimeNs;
         updateAlarmLocked();
     }
     VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
@@ -224,16 +278,22 @@
 void StatsPullerManagerImpl::OnAlarmFired() {
     AutoMutex _l(mLock);
 
-    uint64_t currentTimeMs = getElapsedRealtimeMillis();
+    int64_t currentTimeNs = getElapsedRealtimeNs();
+
+    int64_t minNextPullTimeNs = LONG_MAX;
 
     vector<pair<int, vector<ReceiverInfo*>>> needToPull =
             vector<pair<int, vector<ReceiverInfo*>>>();
     for (auto& pair : mReceivers) {
         vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
         if (pair.second.size() != 0) {
-            for (auto& receiverInfo : pair.second) {
-                if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) {
+            for (ReceiverInfo& receiverInfo : pair.second) {
+                if (receiverInfo.nextPullTimeNs < currentTimeNs) {
                     receivers.push_back(&receiverInfo);
+                } else {
+                    if (receiverInfo.nextPullTimeNs < minNextPullTimeNs) {
+                        minNextPullTimeNs = receiverInfo.nextPullTimeNs;
+                    }
                 }
             }
             if (receivers.size() > 0) {
@@ -244,18 +304,29 @@
 
     for (const auto& pullInfo : needToPull) {
         vector<shared_ptr<LogEvent>> data;
-        if (Pull(pullInfo.first, &data)) {
+        if (Pull(pullInfo.first, currentTimeNs, &data)) {
             for (const auto& receiverInfo : pullInfo.second) {
                 sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
                 if (receiverPtr != nullptr) {
                     receiverPtr->onDataPulled(data);
-                    receiverInfo->timeInfo.second = currentTimeMs;
+                    // we may have just come out of a coma, compute next pull time
+                    receiverInfo->nextPullTimeNs =
+                            ceil((double_t)(currentTimeNs - receiverInfo->nextPullTimeNs) /
+                                 receiverInfo->intervalNs) *
+                                    receiverInfo->intervalNs +
+                            receiverInfo->nextPullTimeNs;
+                    if (receiverInfo->nextPullTimeNs < minNextPullTimeNs) {
+                        minNextPullTimeNs = receiverInfo->nextPullTimeNs;
+                    }
                 } else {
                     VLOG("receiver already gone.");
                 }
             }
         }
     }
+
+    mNextPullTimeNs = minNextPullTimeNs;
+    updateAlarmLocked();
 }
 
 int StatsPullerManagerImpl::ForceClearPullerCache() {
@@ -266,10 +337,10 @@
     return totalCleared;
 }
 
-int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(long timestampSec) {
+int StatsPullerManagerImpl::ClearPullerCacheIfNecessary(int64_t timestampNs) {
     int totalCleared = 0;
     for (const auto& pulledAtom : kAllPullAtomInfo) {
-        totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampSec);
+        totalCleared += pulledAtom.second.puller->ClearCacheIfNecessary(timestampNs);
     }
     return totalCleared;
 }
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.h b/cmds/statsd/src/external/StatsPullerManagerImpl.h
index 682ad33..8c771f3 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.h
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.h
@@ -41,7 +41,7 @@
   std::vector<int> nonAdditiveFields;
   // How long should the puller wait before doing an actual pull again. Default
   // 1 sec. Set this to 0 if this is handled elsewhere.
-  long coolDownSec = 1;
+  int64_t coolDownNs = 1 * NS_PER_SEC;
   // The actual puller
   sp<StatsPuller> puller;
 } PullAtomInfo;
@@ -50,7 +50,8 @@
 public:
     static StatsPullerManagerImpl& GetInstance();
 
-    void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, long intervalMs);
+    void RegisterReceiver(int tagId, wp<PullDataReceiver> receiver, int64_t nextPullTimeNs,
+                          int64_t intervalNs);
 
     void UnRegisterReceiver(int tagId, wp<PullDataReceiver> receiver);
 
@@ -59,13 +60,11 @@
 
     void OnAlarmFired();
 
-    bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data);
-
-    void SetTimeBaseSec(long timeBaseSec) {mTimeBaseSec = timeBaseSec;};
+    bool Pull(const int tagId, const int64_t timeNs, vector<std::shared_ptr<LogEvent>>* data);
 
     int ForceClearPullerCache();
 
-    int ClearPullerCacheIfNecessary(long timestampSec);
+    int ClearPullerCacheIfNecessary(int64_t timestampNs);
 
     void SetStatsCompanionService(sp<IStatsCompanionService> statsCompanionService);
 
@@ -77,8 +76,8 @@
     sp<IStatsCompanionService> mStatsCompanionService = nullptr;
 
     typedef struct {
-        // pull_interval_sec : last_pull_time_sec
-        std::pair<uint64_t, uint64_t> timeInfo;
+        int64_t nextPullTimeNs;
+        int64_t intervalNs;
         wp<PullDataReceiver> receiver;
     } ReceiverInfo;
 
@@ -90,12 +89,7 @@
 
     void updateAlarmLocked();
 
-    long mCurrentPullingInterval;
-
-    // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest
-    // bucket size. All pulled metrics start pulling based on this time, so that they can be
-    // correctly attributed to the correct buckets.
-    long mTimeBaseSec;
+    int64_t mNextPullTimeNs;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index f0e0df1..b13c3e7 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -112,7 +112,8 @@
 
     // Kicks off the puller immediately.
     if (mPullTagId != -1 && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
-        mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills);
+        mStatsPullerManager->RegisterReceiver(
+                mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs);
     }
 
     VLOG("Gauge metric %lld created. bucket size %lld start_time: %lld sliced %d",
@@ -255,7 +256,7 @@
     }
 
     vector<std::shared_ptr<LogEvent>> allData;
-    if (!mStatsPullerManager->Pull(mPullTagId, &allData)) {
+    if (!mStatsPullerManager->Pull(mPullTagId, getElapsedRealtimeNs(), &allData)) {
         ALOGE("Gauge Stats puller failed for tag: %d", mPullTagId);
         return;
     }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index e19e236..bd3c78c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -110,10 +110,12 @@
     }
     mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0);
 
-    if (!metric.has_condition() && mPullTagId != -1) {
-        VLOG("Setting up periodic pulling for %d", mPullTagId);
-        mStatsPullerManager->RegisterReceiver(mPullTagId, this, bucketSizeMills);
+    // Kicks off the puller immediately.
+    if (mPullTagId != -1) {
+        mStatsPullerManager->RegisterReceiver(
+            mPullTagId, this, mCurrentBucketStartTimeNs + mBucketSizeNs, mBucketSizeNs);
     }
+
     VLOG("value metric %lld created. bucket size %lld start_time: %lld",
         (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
@@ -194,26 +196,21 @@
     // TODO: Clear mDimensionKeyMap once the report is dumped.
 }
 
-void ValueMetricProducer::onConditionChangedLocked(const bool condition, const uint64_t eventTime) {
+void ValueMetricProducer::onConditionChangedLocked(const bool condition,
+                                                   const uint64_t eventTimeNs) {
     mCondition = condition;
 
-    if (eventTime < mCurrentBucketStartTimeNs) {
-        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTime,
+    if (eventTimeNs < mCurrentBucketStartTimeNs) {
+        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
         return;
     }
 
-    flushIfNeededLocked(eventTime);
+    flushIfNeededLocked(eventTimeNs);
 
     if (mPullTagId != -1) {
-        if (mCondition == true) {
-            mStatsPullerManager->RegisterReceiver(mPullTagId, this, mBucketSizeNs / 1000 / 1000);
-        } else if (mCondition == false) {
-            mStatsPullerManager->UnRegisterReceiver(mPullTagId, this);
-        }
-
         vector<shared_ptr<LogEvent>> allData;
-        if (mStatsPullerManager->Pull(mPullTagId, &allData)) {
+        if (mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData)) {
             if (allData.size() == 0) {
                 return;
             }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 796e83a..ebc6e81 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -53,7 +53,7 @@
 
         if (mPullTagId != -1) {
             vector<shared_ptr<LogEvent>> allData;
-            mStatsPullerManager->Pull(mPullTagId, &allData);
+            mStatsPullerManager->Pull(mPullTagId, eventTimeNs, &allData);
             if (allData.size() == 0) {
                 // This shouldn't happen since this valuemetric is not useful now.
             }
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index cab61e9..efd810f 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -221,7 +221,8 @@
 
 int64_t TimeUnitToBucketSizeInMillisGuardrailed(int uid, TimeUnit unit) {
     int64_t bucketSizeMillis = TimeUnitToBucketSizeInMillis(unit);
-    if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL) {
+    if (bucketSizeMillis > 1000 && bucketSizeMillis < 5 * 60 * 1000LL && uid != AID_SHELL &&
+        uid != AID_ROOT) {
         bucketSizeMillis = 5 * 60 * 1000LL;
     }
     return bucketSizeMillis;
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 2583c95..7ca66fd 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -63,7 +63,7 @@
     // For now we still need this so that it doesn't do real pulling.
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
@@ -213,10 +213,11 @@
 
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs);
                 event->write("some value");
@@ -281,10 +282,11 @@
 
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
                 event->write("some value");
@@ -372,10 +374,11 @@
 
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
                 event->write(1000);
@@ -420,7 +423,7 @@
 
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     GaugeMetric metric;
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index a8eb2703..a0224ec 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -62,7 +62,7 @@
     // For now we still need this so that it doesn't do real pulling.
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
 
     ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
@@ -141,11 +141,12 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
                 event->write(tagId);
@@ -154,7 +155,8 @@
                 data->push_back(event);
                 return true;
             }))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
                 event->write(tagId);
@@ -260,10 +262,11 @@
     sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     shared_ptr<MockStatsPullerManager> pullerManager =
             make_shared<StrictMock<MockStatsPullerManager>>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, Pull(tagId, _))
-            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+    EXPECT_CALL(*pullerManager, Pull(tagId, _, _))
+            .WillOnce(Invoke([](int tagId, int64_t timeNs,
+                                vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
                 shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
                 event->write(tagId);
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
index f040bf9..5afaba6 100644
--- a/cmds/statsd/tests/metrics/metrics_test_helper.h
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -35,9 +35,11 @@
 
 class MockStatsPullerManager : public StatsPullerManager {
 public:
-    MOCK_METHOD3(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver, long intervalMs));
+    MOCK_METHOD4(RegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver,
+                                        int64_t nextPulltimeNs, int64_t intervalNs));
     MOCK_METHOD2(UnRegisterReceiver, void(int tagId, wp<PullDataReceiver> receiver));
-    MOCK_METHOD2(Pull, bool(const int pullCode, vector<std::shared_ptr<LogEvent>>* data));
+    MOCK_METHOD3(Pull, bool(const int pullCode, const int64_t timeNs,
+                            vector<std::shared_ptr<LogEvent>>* data));
 };
 
 class MockUidMap : public UidMap {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 3af6105..70e3fad 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1,4 +1,5 @@
 Landroid/accounts/AccountManager;->mContext:Landroid/content/Context;
+Landroid/accounts/IAccountAuthenticatorResponse$Stub;-><init>()V
 Landroid/accounts/IAccountManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/accounts/IAccountManager;
 Landroid/accounts/IAccountManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/animation/LayoutTransition;->cancel()V
@@ -236,6 +237,7 @@
 Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
 Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V
 Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
+Landroid/app/IActivityManager;->requestBugReport(I)V
 Landroid/app/IActivityManager;->resumeAppSwitches()V
 Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
 Landroid/app/IActivityManager;->setTaskResizeable(II)V
@@ -609,6 +611,11 @@
 Landroid/graphics/Camera;->native_instance:J
 Landroid/graphics/Canvas;-><init>(J)V
 Landroid/graphics/Canvas;->release()V
+Landroid/graphics/Canvas;->save(I)I
+Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I
+Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I
+Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I
+Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I
 Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
 Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
 Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray;
@@ -943,6 +950,7 @@
 Landroid/media/IAudioService;->setStreamVolume(IIILjava/lang/String;)V
 Landroid/media/IAudioService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IAudioService;
 Landroid/media/IAudioService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/media/IRemoteDisplayCallback;->onStateChanged(Landroid/media/RemoteDisplayState;)V
 Landroid/media/IVolumeController$Stub;->asInterface(Landroid/os/IBinder;)Landroid/media/IVolumeController;
 Landroid/media/JetPlayer;->mNativePlayerInJavaObj:J
 Landroid/media/JetPlayer;->postEventFromNative(Ljava/lang/Object;III)V
@@ -995,6 +1003,8 @@
 Landroid/media/RemoteDisplay;->notifyDisplayConnected(Landroid/view/Surface;IIII)V
 Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V
 Landroid/media/RemoteDisplay;->notifyDisplayError(I)V
+Landroid/media/RemoteDisplayState;->displays:Ljava/util/ArrayList;
+Landroid/media/RemoteDisplayState;-><init>()V
 Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone;
 Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper;
 Landroid/media/session/MediaSession;->mCallback:Landroid/media/session/MediaSession$CallbackMessageHandler;
@@ -1006,6 +1016,11 @@
 Landroid/media/soundtrigger/SoundTriggerManager;->stopRecognition(Ljava/util/UUID;)I
 Landroid/media/soundtrigger/SoundTriggerManager;->unloadSoundModel(Ljava/util/UUID;)I
 Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler;
+Landroid/media/SubtitleTrack$RenderingWidget;->draw(Landroid/graphics/Canvas;)V
+Landroid/media/SubtitleTrack$RenderingWidget;->onAttachedToWindow()V
+Landroid/media/SubtitleTrack$RenderingWidget;->onDetachedFromWindow()V
+Landroid/media/SubtitleTrack$RenderingWidget;->setOnChangedListener(Landroid/media/SubtitleTrack$RenderingWidget$OnChangedListener;)V
+Landroid/media/SubtitleTrack$RenderingWidget;->setSize(II)V
 Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap;
 Landroid/media/ToneGenerator;->mNativeContext:J
 Landroid/media/VolumeShaper$Configuration;-><init>(IIIDI[F[F)V
@@ -1111,6 +1126,8 @@
 Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
+Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
+Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I
 Landroid/net/wifi/ScanResult;->anqpDomainId:I
 Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
 Landroid/net/wifi/ScanResult;->distanceCm:I
@@ -1961,6 +1978,7 @@
 Landroid/util/Rational;->mNumerator:I
 Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
 Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
+Landroid/util/Slog;->w(Ljava/lang/String;Ljava/lang/String;)I
 Landroid/util/SparseIntArray;->mKeys:[I
 Landroid/util/SparseIntArray;->mSize:I
 Landroid/util/SparseIntArray;->mValues:[I
@@ -2280,6 +2298,7 @@
 Landroid/webkit/IWebViewUpdateService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/webkit/WebResourceResponse;->mImmutable:Z
 Landroid/webkit/WebSyncManager;->mHandler:Landroid/os/Handler;
+Landroid/webkit/WebViewClient;->onUnhandledInputEvent(Landroid/webkit/WebView;Landroid/view/InputEvent;)V
 Landroid/webkit/WebView;->debugDump()V
 Landroid/webkit/WebView;->disablePlatformNotifications()V
 Landroid/webkit/WebView;->emulateShiftHeld()V
@@ -2709,11 +2728,15 @@
 Lcom/android/internal/R$styleable;->CheckBoxPreference_summaryOn:I
 Lcom/android/internal/R$styleable;->CompoundButton_button:I
 Lcom/android/internal/R$styleable;->CompoundButton:[I
+Lcom/android/internal/R$styleable;->DialogPreference_dialogTitle:I
+Lcom/android/internal/R$styleable;->DialogPreference:[I
 Lcom/android/internal/R$styleable;->EdgeEffect_colorEdgeEffect:I
 Lcom/android/internal/R$styleable;->EdgeEffect:[I
 Lcom/android/internal/R$styleable;->IconMenuView:[I
 Lcom/android/internal/R$styleable;->ImageView:[I
 Lcom/android/internal/R$styleable;->ImageView_src:I
+Lcom/android/internal/R$styleable;->ListPreference_entries:I
+Lcom/android/internal/R$styleable;->ListPreference:[I
 Lcom/android/internal/R$styleable;->Preference_defaultValue:I
 Lcom/android/internal/R$styleable;->Preference_dependency:I
 Lcom/android/internal/R$styleable;->Preference_enabled:I
@@ -2779,6 +2802,7 @@
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ITelephony$Stub;->TRANSACTION_getDeviceId:I
 Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Lcom/android/internal/util/AsyncChannel;->sendMessage(III)V
 Lcom/android/internal/util/FastPrintWriter;-><init>(Ljava/io/OutputStream;)V
 Lcom/android/internal/util/XmlUtils;->readMapXml(Ljava/io/InputStream;)Ljava/util/HashMap;
 Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager;
@@ -2955,6 +2979,7 @@
 Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
 Ljava/lang/Short;->value:S
 Ljava/lang/String;-><init>(II[C)V
+Ljava/lang/System;->arraycopy([II[III)V
 Ljava/lang/System;-><init>()V
 Ljava/lang/Thread;->daemon:Z
 Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V
@@ -3066,5 +3091,7 @@
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
 Lorg/json/JSONArray;->values:Ljava/util/List;
+Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
+Lorg/json/JSONObject;->keySet()Ljava/util/Set;
 Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt
index 77bb0bb..61ae6e7 100644
--- a/config/hiddenapi-vendor-list.txt
+++ b/config/hiddenapi-vendor-list.txt
@@ -32,7 +32,6 @@
 Landroid/app/IActivityManager;->getTaskSnapshot(IZ)Landroid/app/ActivityManager$TaskSnapshot;
 Landroid/app/IActivityManager;->registerTaskStackListener(Landroid/app/ITaskStackListener;)V
 Landroid/app/IActivityManager;->removeTask(I)Z
-Landroid/app/IActivityManager;->requestBugReport(I)V
 Landroid/app/IActivityManager;->startActivityAsUser(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;I)I
 Landroid/app/IActivityManager;->startActivityFromRecents(ILandroid/os/Bundle;)I
 Landroid/app/IActivityManager;->startActivity(Landroid/app/IApplicationThread;Ljava/lang/String;Landroid/content/Intent;Ljava/lang/String;Landroid/os/IBinder;Ljava/lang/String;IILandroid/app/ProfilerInfo;Landroid/os/Bundle;)I
@@ -108,11 +107,6 @@
 Landroid/graphics/Bitmap;->createHardwareBitmap(Landroid/graphics/GraphicBuffer;)Landroid/graphics/Bitmap;
 Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;Landroid/graphics/Region$Op;)Z
 Landroid/graphics/Canvas;->clipRegion(Landroid/graphics/Region;)Z
-Landroid/graphics/Canvas;->save(I)I
-Landroid/graphics/Canvas;->saveLayerAlpha(FFFFII)I
-Landroid/graphics/Canvas;->saveLayerAlpha(Landroid/graphics/RectF;II)I
-Landroid/graphics/Canvas;->saveLayer(FFFFLandroid/graphics/Paint;I)I
-Landroid/graphics/Canvas;->saveLayer(Landroid/graphics/RectF;Landroid/graphics/Paint;I)I
 Landroid/graphics/drawable/Drawable;->isProjected()Z
 Landroid/graphics/drawable/Drawable;->updateTintFilter(Landroid/graphics/PorterDuffColorFilter;Landroid/content/res/ColorStateList;Landroid/graphics/PorterDuff$Mode;)Landroid/graphics/PorterDuffColorFilter;
 Landroid/hardware/camera2/CaptureRequest$Key;-><init>(Ljava/lang/String;Ljava/lang/Class;)V
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d3c1e99..4326ee3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1219,11 +1219,11 @@
     public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
 
     /**
-     * This is set on the notification shown by the activity manager about all apps
-     * running in the background.  It indicates that the notification should be shown
-     * only if any of the given apps do not already have a {@link #FLAG_FOREGROUND_SERVICE}
-     * notification currently visible to the user.  This is a string array of all
-     * package names of the apps.
+     * This is set on the notifications shown by system_server about apps running foreground
+     * services. It indicates that the notification should be shown
+     * only if any of the given apps do not already have a properly tagged
+     * {@link #FLAG_FOREGROUND_SERVICE} notification currently visible to the user.
+     * This is a string array of all package names of the apps.
      * @hide
      */
     public static final String EXTRA_FOREGROUND_APPS = "android.foregroundApps";
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 8f01685..bd4933a 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -24,7 +24,6 @@
 import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -47,6 +46,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 import android.view.accessibility.IAccessibilityInteractionConnection;
+
 import libcore.io.IoUtils;
 
 import java.io.IOException;
@@ -876,15 +876,35 @@
     }
 
     /**
+     * Grants a runtime permission to a package.
+     * @param packageName The package to which to grant.
+     * @param permission The permission to grant.
+     * @throws SecurityException if unable to grant the permission.
+     */
+    public void grantRuntimePermission(String packageName, String permission) {
+        grantRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle());
+    }
+
+    /**
+     * @deprecated replaced by
+     *             {@link #grantRuntimePermissionAsUser(String, String, UserHandle)}.
+     * @hide
+     */
+    @Deprecated
+    @TestApi
+    public boolean grantRuntimePermission(String packageName, String permission,
+            UserHandle userHandle) {
+        grantRuntimePermissionAsUser(packageName, permission, userHandle);
+        return true;
+    }
+
+    /**
      * Grants a runtime permission to a package for a user.
      * @param packageName The package to which to grant.
      * @param permission The permission to grant.
-     * @return Whether granting succeeded.
-     *
-     * @hide
+     * @throws SecurityException if unable to grant the permission.
      */
-    @TestApi
-    public boolean grantRuntimePermission(String packageName, String permission,
+    public void grantRuntimePermissionAsUser(String packageName, String permission,
             UserHandle userHandle) {
         synchronized (mLock) {
             throwIfNotConnectedLocked();
@@ -896,25 +916,42 @@
             // Calling out without a lock held.
             mUiAutomationConnection.grantRuntimePermission(packageName,
                     permission, userHandle.getIdentifier());
-            // TODO: The package manager API should return boolean.
-            return true;
-        } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error granting runtime permission", re);
+        } catch (Exception e) {
+            throw new SecurityException("Error granting runtime permission", e);
         }
-        return false;
     }
 
     /**
-     * Revokes a runtime permission from a package for a user.
-     * @param packageName The package from which to revoke.
-     * @param permission The permission to revoke.
-     * @return Whether revoking succeeded.
-     *
+     * Revokes a runtime permission from a package.
+     * @param packageName The package to which to grant.
+     * @param permission The permission to grant.
+     * @throws SecurityException if unable to revoke the permission.
+     */
+    public void revokeRuntimePermission(String packageName, String permission) {
+        revokeRuntimePermissionAsUser(packageName, permission, android.os.Process.myUserHandle());
+    }
+
+    /**
+     * @deprecated replaced by
+     *             {@link #revokeRuntimePermissionAsUser(String, String, UserHandle)}.
      * @hide
      */
+    @Deprecated
     @TestApi
     public boolean revokeRuntimePermission(String packageName, String permission,
             UserHandle userHandle) {
+        revokeRuntimePermissionAsUser(packageName, permission, userHandle);
+        return true;
+    }
+
+    /**
+     * Revokes a runtime permission from a package.
+     * @param packageName The package to which to grant.
+     * @param permission The permission to grant.
+     * @throws SecurityException if unable to revoke the permission.
+     */
+    public void revokeRuntimePermissionAsUser(String packageName, String permission,
+            UserHandle userHandle) {
         synchronized (mLock) {
             throwIfNotConnectedLocked();
         }
@@ -925,12 +962,9 @@
             // Calling out without a lock held.
             mUiAutomationConnection.revokeRuntimePermission(packageName,
                     permission, userHandle.getIdentifier());
-            // TODO: The package manager API should return boolean.
-            return true;
-        } catch (RemoteException re) {
-            Log.e(LOG_TAG, "Error revoking runtime permission", re);
+        } catch (Exception e) {
+            throw new SecurityException("Error granting runtime permission", e);
         }
-        return false;
     }
 
     /**
@@ -949,6 +983,7 @@
         synchronized (mLock) {
             throwIfNotConnectedLocked();
         }
+        warnIfBetterCommand(command);
 
         ParcelFileDescriptor source = null;
         ParcelFileDescriptor sink = null;
@@ -991,6 +1026,7 @@
         synchronized (mLock) {
             throwIfNotConnectedLocked();
         }
+        warnIfBetterCommand(command);
 
         ParcelFileDescriptor source_read = null;
         ParcelFileDescriptor sink_read = null;
@@ -1056,6 +1092,16 @@
         }
     }
 
+    private void warnIfBetterCommand(String cmd) {
+        if (cmd.startsWith("pm grant ")) {
+            Log.w(LOG_TAG, "UiAutomation.grantRuntimePermission() "
+                    + "is more robust and should be used instead of 'pm grant'");
+        } else if (cmd.startsWith("pm revoke ")) {
+            Log.w(LOG_TAG, "UiAutomation.revokeRuntimePermission() "
+                    + "is more robust and should be used instead of 'pm revoke'");
+        }
+    }
+
     private class IAccessibilityServiceClientImpl extends IAccessibilityServiceClientWrapper {
 
         public IAccessibilityServiceClientImpl(Looper looper) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index aec33b3..1534a15 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -124,6 +124,7 @@
 @SystemService(Context.DEVICE_POLICY_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_DEVICE_ADMIN)
 public class DevicePolicyManager {
+
     private static String TAG = "DevicePolicyManager";
 
     private final Context mContext;
@@ -1612,8 +1613,6 @@
      *     <li>keyguard
      * </ul>
      *
-     * This is the default configuration for LockTask.
-     *
      * @see #setLockTaskFeatures(ComponentName, int)
      */
     public static final int LOCK_TASK_FEATURE_NONE = 0;
@@ -1631,7 +1630,10 @@
     /**
      * Enable notifications during LockTask mode. This includes notification icons on the status
      * bar, heads-up notifications, and the expandable notification shade. Note that the Quick
-     * Settings panel will still be disabled.
+     * Settings panel remains disabled. This feature flag can only be used in combination with
+     * {@link #LOCK_TASK_FEATURE_HOME}. {@link #setLockTaskFeatures(ComponentName, int)}
+     * throws an {@link IllegalArgumentException} if this feature flag is defined without
+     * {@link #LOCK_TASK_FEATURE_HOME}.
      *
      * @see #setLockTaskFeatures(ComponentName, int)
      */
@@ -1664,6 +1666,9 @@
      * the user long-presses the power button, for example. Note that the user may not be able to
      * power off the device if this flag is not set.
      *
+     * <p>This flag is enabled by default until {@link #setLockTaskFeatures(ComponentName, int)} is
+     * called for the first time.
+     *
      * @see #setLockTaskFeatures(ComponentName, int)
      */
     public static final int LOCK_TASK_FEATURE_GLOBAL_ACTIONS = 1 << 4;
@@ -1747,6 +1752,25 @@
     public static final int ID_TYPE_MEID = 8;
 
     /**
+     * Specifies that the calling app should be granted access to the installed credentials
+     * immediately. Otherwise, access to the credentials will be gated by user approval.
+     * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)}
+     *
+     * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)
+     */
+    public static final int INSTALLKEY_REQUEST_CREDENTIALS_ACCESS = 1;
+
+    /**
+     * Specifies that a user can select the key via the Certificate Selection prompt.
+     * If this flag is not set when calling {@link #installKeyPair}, the key can only be granted
+     * access by implementing {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}.
+     * For use with {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)}
+     *
+     * @see #installKeyPair(ComponentName, PrivateKey, Certificate[], String, int)
+     */
+    public static final int INSTALLKEY_SET_USER_SELECTABLE = 2;
+
+    /**
      * Broadcast action: sent when the profile owner is set, changed or cleared.
      *
      * This broadcast is sent only to the user managed by the new profile owner.
@@ -4122,7 +4146,11 @@
      */
     public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
             @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) {
-        return installKeyPair(admin, privKey, certs, alias, requestAccess, true);
+        int flags = INSTALLKEY_SET_USER_SELECTABLE;
+        if (requestAccess) {
+            flags |= INSTALLKEY_REQUEST_CREDENTIALS_ACCESS;
+        }
+        return installKeyPair(admin, privKey, certs, alias, flags);
     }
 
     /**
@@ -4146,13 +4174,9 @@
      *        {@link android.security.KeyChain#getCertificateChain}.
      * @param alias The private key alias under which to install the certificate. If a certificate
      *        with that alias already exists, it will be overwritten.
-     * @param requestAccess {@code true} to request that the calling app be granted access to the
-     *        credentials immediately. Otherwise, access to the credentials will be gated by user
-     *        approval.
-     * @param isUserSelectable {@code true} to indicate that a user can select this key via the
-     *        Certificate Selection prompt, false to indicate that this key can only be granted
-     *        access by implementing
-     *        {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}.
+     * @param flags Flags to request that the calling app be granted access to the credentials
+     *        and set the key to be user-selectable. See {@link #INSTALLKEY_SET_USER_SELECTABLE} and
+     *        {@link #INSTALLKEY_REQUEST_CREDENTIALS_ACCESS}.
      * @return {@code true} if the keys were installed, {@code false} otherwise.
      * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile
      *         owner.
@@ -4161,9 +4185,12 @@
      * @see #DELEGATION_CERT_INSTALL
      */
     public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey,
-            @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess,
-            boolean isUserSelectable) {
+            @NonNull Certificate[] certs, @NonNull String alias, int flags) {
         throwIfParentInstance("installKeyPair");
+        boolean requestAccess = (flags & INSTALLKEY_REQUEST_CREDENTIALS_ACCESS)
+                == INSTALLKEY_REQUEST_CREDENTIALS_ACCESS;
+        boolean isUserSelectable = (flags & INSTALLKEY_SET_USER_SELECTABLE)
+                == INSTALLKEY_SET_USER_SELECTABLE;
         try {
             final byte[] pemCert = Credentials.convertToPem(certs[0]);
             byte[] pemChain = null;
@@ -4242,6 +4269,8 @@
      *         algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec}
      *         or {@code ECGenParameterSpec}, or if Device ID attestation was requested but the
      *         {@code keySpec} does not contain an attestation challenge.
+     * @throws UnsupportedOperationException if Device ID attestation was requested but the
+     *         underlying hardware does not support it.
      * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])
      */
     public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin,
@@ -6359,6 +6388,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
     public @Nullable List<String> getPermittedInputMethodsForCurrentUser() {
         throwIfParentInstance("getPermittedInputMethodsForCurrentUser");
         if (mService != null) {
@@ -7186,30 +7216,24 @@
     }
 
     /**
-     * Sets which system features to enable for LockTask mode.
-     * <p>
-     * Feature flags set through this method will only take effect for the duration when the device
-     * is in LockTask mode. If this method is not called, none of the features listed here will be
-     * enabled.
-     * <p>
-     * This function can only be called by the device owner, a profile owner of an affiliated user
-     * or profile, or the profile owner when no device owner is set. See {@link #isAffiliatedUser}.
-     * Any features set via this method will be cleared if the user becomes unaffiliated.
+     * Sets which system features are enabled when the device runs in lock task mode. This method
+     * doesn't affect the features when lock task mode is inactive. Any system features not included
+     * in {@code flags} are implicitly disabled when calling this method. By default, only
+     * {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS} is enabled—all the other features are disabled. To
+     * disable the global actions dialog, call this method omitting
+     * {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS}.
+     *
+     * <p>This method can only be called by the device owner, a profile owner of an affiliated
+     * user or profile, or the profile owner when no device owner is set. See
+     * {@link #isAffiliatedUser}.
+     * Any features set using this method are cleared if the user becomes unaffiliated.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param flags Bitfield of feature flags:
-     *              {@link #LOCK_TASK_FEATURE_NONE} (default),
-     *              {@link #LOCK_TASK_FEATURE_SYSTEM_INFO},
-     *              {@link #LOCK_TASK_FEATURE_NOTIFICATIONS},
-     *              {@link #LOCK_TASK_FEATURE_HOME},
-     *              {@link #LOCK_TASK_FEATURE_OVERVIEW},
-     *              {@link #LOCK_TASK_FEATURE_GLOBAL_ACTIONS},
-     *              {@link #LOCK_TASK_FEATURE_KEYGUARD}
+     * @param flags The system features enabled during lock task mode.
      * @throws SecurityException if {@code admin} is not the device owner, the profile owner of an
      * affiliated user or profile, or the profile owner when no device owner is set.
      * @see #isAffiliatedUser
-     * @throws SecurityException if {@code admin} is not the device owner or the profile owner.
-     */
+     **/
     public void setLockTaskFeatures(@NonNull ComponentName admin, @LockTaskFeature int flags) {
         throwIfParentInstance("setLockTaskFeatures");
         if (mService != null) {
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 6feb527..d272652 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -179,6 +179,13 @@
     public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT     = 0x0007;
     /** @hide */
     public static final int REASON_SUB_USAGE_SYNC_ADAPTER       = 0x0008;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_SLICE_PINNED       = 0x0009;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;
+
+    /** @hide */
+    public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;
 
     /** @hide */
     @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
@@ -616,36 +623,47 @@
                 break;
             case REASON_MAIN_PREDICTED:
                 sb.append("p");
+                switch (standbyReason & REASON_SUB_MASK) {
+                    case REASON_SUB_PREDICTED_RESTORED:
+                        sb.append("-r");
+                        break;
+                }
                 break;
             case REASON_MAIN_TIMEOUT:
                 sb.append("t");
                 break;
             case REASON_MAIN_USAGE:
-                sb.append("u-");
+                sb.append("u");
                 switch (standbyReason & REASON_SUB_MASK) {
                     case REASON_SUB_USAGE_SYSTEM_INTERACTION:
-                        sb.append("si");
+                        sb.append("-si");
                         break;
                     case REASON_SUB_USAGE_NOTIFICATION_SEEN:
-                        sb.append("ns");
+                        sb.append("-ns");
                         break;
                     case REASON_SUB_USAGE_USER_INTERACTION:
-                        sb.append("ui");
+                        sb.append("-ui");
                         break;
                     case REASON_SUB_USAGE_MOVE_TO_FOREGROUND:
-                        sb.append("mf");
+                        sb.append("-mf");
                         break;
                     case REASON_SUB_USAGE_MOVE_TO_BACKGROUND:
-                        sb.append("mb");
+                        sb.append("-mb");
                         break;
                     case REASON_SUB_USAGE_SYSTEM_UPDATE:
-                        sb.append("su");
+                        sb.append("-su");
                         break;
                     case REASON_SUB_USAGE_ACTIVE_TIMEOUT:
-                        sb.append("at");
+                        sb.append("-at");
                         break;
                     case REASON_SUB_USAGE_SYNC_ADAPTER:
-                        sb.append("sa");
+                        sb.append("-sa");
+                        break;
+                    case REASON_SUB_USAGE_SLICE_PINNED:
+                        sb.append("slp");
+                        break;
+                    case REASON_SUB_USAGE_SLICE_PINNED_PRIV:
+                        sb.append("slpp");
                         break;
                 }
                 break;
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index cb1d106..af99bf7 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -701,29 +701,6 @@
     }
 
     /**
-     * Sends Virtual Cable Unplug to currently connected host.
-     *
-     * @return
-     * {@hide}
-     */
-    public boolean unplug(BluetoothDevice device) {
-        boolean result = false;
-
-        final IBluetoothHidDevice service = mService;
-        if (service != null) {
-            try {
-                result = service.unplug(device);
-            } catch (RemoteException e) {
-                Log.e(TAG, e.toString());
-            }
-        } else {
-            Log.w(TAG, "Proxy not attached to service");
-        }
-
-        return result;
-    }
-
-    /**
      * Initiates connection to host which is currently paired with this device. If the application
      * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
      * tracked by the application by handling callback from Callback#onConnectionStateChanged. The
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index a3b2d22..efb9517 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -535,6 +535,19 @@
     }
 
     /**
+     * Set the level of color saturation to apply to the display.
+     * @param level The amount of saturation to apply, between 0 and 1 inclusive.
+     * 0 produces a grayscale image, 1 is normal.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.CONTROL_DISPLAY_SATURATION)
+    public void setSaturationLevel(float level) {
+        mGlobal.setSaturationLevel(level);
+    }
+
+    /**
      * Creates a virtual display.
      *
      * @see #createVirtualDisplay(String, int, int, int, Surface, int,
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 1f67a6b..2d0ef2f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -384,6 +384,17 @@
         }
     }
 
+    /**
+     * Set the level of color saturation to apply to the display.
+     */
+    public void setSaturationLevel(float level) {
+        try {
+            mDm.setSaturationLevel(level);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
     public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
             String name, int width, int height, int densityDpi, Surface surface, int flags,
             VirtualDisplay.Callback callback, Handler handler, String uniqueId) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 9fcb9d3..b77de748 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -65,6 +65,9 @@
     // Requires CONFIGURE_DISPLAY_COLOR_MODE
     void requestColorMode(int displayId, int colorMode);
 
+    // Requires CONTROL_DISPLAY_SATURATION
+    void setSaturationLevel(float level);
+
     // Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
     // MediaProjection token for certain combinations of flags.
     int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index b2aa9ba..e6f523c 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -263,6 +263,17 @@
         /**
          * @hide for framework use only
          */
+        public Filter() {
+            mIdentifierTypes = Collections.emptySet();
+            mIdentifiers = Collections.emptySet();
+            mIncludeCategories = false;
+            mExcludeModifications = false;
+            mVendorFilter = null;
+        }
+
+        /**
+         * @hide for framework use only
+         */
         public Filter(@Nullable Map<String, String> vendorFilter) {
             mIdentifierTypes = Collections.emptySet();
             mIdentifiers = Collections.emptySet();
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 8fde82e..8263bb8 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -211,6 +211,7 @@
         private final String mSerial;
         private final int mNumTuners;
         private final int mNumAudioSources;
+        private final boolean mIsInitializationRequired;
         private final boolean mIsCaptureSupported;
         private final BandDescriptor[] mBands;
         private final boolean mIsBgScanSupported;
@@ -222,7 +223,8 @@
         /** @hide */
         public ModuleProperties(int id, String serviceName, int classId, String implementor,
                 String product, String version, String serial, int numTuners, int numAudioSources,
-                boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported,
+                boolean isInitializationRequired, boolean isCaptureSupported,
+                BandDescriptor[] bands, boolean isBgScanSupported,
                 @ProgramSelector.ProgramType int[] supportedProgramTypes,
                 @ProgramSelector.IdentifierType int[] supportedIdentifierTypes,
                 @Nullable Map<String, Integer> dabFrequencyTable,
@@ -236,6 +238,7 @@
             mSerial = serial;
             mNumTuners = numTuners;
             mNumAudioSources = numAudioSources;
+            mIsInitializationRequired = isInitializationRequired;
             mIsCaptureSupported = isCaptureSupported;
             mBands = bands;
             mIsBgScanSupported = isBgScanSupported;
@@ -329,6 +332,18 @@
             return mNumAudioSources;
         }
 
+        /**
+         * Checks, if BandConfig initialization (after {@link RadioManager#openTuner})
+         * is required to be done before other operations or not.
+         *
+         * If it is, the client has to wait for {@link RadioTuner.Callback#onConfigurationChanged}
+         * callback before executing any other operations. Otherwise, such operation will fail
+         * returning {@link RadioManager#STATUS_INVALID_OPERATION} error code.
+         */
+        public boolean isInitializationRequired() {
+            return mIsInitializationRequired;
+        }
+
         /** {@code true} if audio capture is possible from radio tuner output.
          * This indicates if routing to audio devices not connected to the same HAL as the FM radio
          * is possible (e.g. to USB) or DAR (Digital Audio Recorder) feature can be implemented.
@@ -419,6 +434,7 @@
             mSerial = in.readString();
             mNumTuners = in.readInt();
             mNumAudioSources = in.readInt();
+            mIsInitializationRequired = in.readInt() == 1;
             mIsCaptureSupported = in.readInt() == 1;
             Parcelable[] tmp = in.readParcelableArray(BandDescriptor.class.getClassLoader());
             mBands = new BandDescriptor[tmp.length];
@@ -454,6 +470,7 @@
             dest.writeString(mSerial);
             dest.writeInt(mNumTuners);
             dest.writeInt(mNumAudioSources);
+            dest.writeInt(mIsInitializationRequired ? 1 : 0);
             dest.writeInt(mIsCaptureSupported ? 1 : 0);
             dest.writeParcelableArray(mBands, flags);
             dest.writeInt(mIsBgScanSupported ? 1 : 0);
@@ -476,6 +493,7 @@
                     + ", mVersion=" + mVersion + ", mSerial=" + mSerial
                     + ", mNumTuners=" + mNumTuners
                     + ", mNumAudioSources=" + mNumAudioSources
+                    + ", mIsInitializationRequired=" + mIsInitializationRequired
                     + ", mIsCaptureSupported=" + mIsCaptureSupported
                     + ", mIsBgScanSupported=" + mIsBgScanSupported
                     + ", mBands=" + Arrays.toString(mBands) + "]";
@@ -484,8 +502,8 @@
         @Override
         public int hashCode() {
             return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion,
-                mSerial, mNumTuners, mNumAudioSources, mIsCaptureSupported, mBands,
-                mIsBgScanSupported, mDabFrequencyTable, mVendorInfo);
+                mSerial, mNumTuners, mNumAudioSources, mIsInitializationRequired,
+                mIsCaptureSupported, mBands, mIsBgScanSupported, mDabFrequencyTable, mVendorInfo);
         }
 
         @Override
@@ -503,6 +521,7 @@
             if (!Objects.equals(mSerial, other.mSerial)) return false;
             if (mNumTuners != other.mNumTuners) return false;
             if (mNumAudioSources != other.mNumAudioSources) return false;
+            if (mIsInitializationRequired != other.mIsInitializationRequired) return false;
             if (mIsCaptureSupported != other.mIsCaptureSupported) return false;
             if (!Objects.equals(mBands, other.mBands)) return false;
             if (mIsBgScanSupported != other.mIsBgScanSupported) return false;
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 85f3115..be2846f 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -60,6 +60,7 @@
                 mLegacyListProxy.close();
                 mLegacyListProxy = null;
             }
+            mCallback.close();
         }
         try {
             mTuner.close();
@@ -278,6 +279,7 @@
             try {
                 mTuner.startProgramListUpdates(filter);
             } catch (UnsupportedOperationException ex) {
+                Log.i(TAG, "Program list is not supported with this hardware");
                 return null;
             } catch (RemoteException ex) {
                 mCallback.setProgramListObserver(null, () -> { });
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 7437c40..0fb93e5 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -53,6 +53,12 @@
         }
     }
 
+    void close() {
+        synchronized (mLock) {
+            if (mProgramList != null) mProgramList.close();
+        }
+    }
+
     void setProgramListObserver(@Nullable ProgramList programList,
             @NonNull ProgramList.OnCloseListener closeListener) {
         Objects.requireNonNull(closeListener);
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 402c995..116262e 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -47,10 +47,10 @@
       * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
       * and alarm is inexact.
       */
-    oneway void setPullingAlarms(long timestampMs, long intervalMs);
+    oneway void setPullingAlarm(long nextPullTimeMs);
 
     /** Cancel any repeating pulling alarm. */
-    oneway void cancelPullingAlarms();
+    oneway void cancelPullingAlarm();
 
     /**
       * Register an alarm when we want to trigger subscribers at the given
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 5be72bc..094f004 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -158,7 +158,7 @@
      * @hide
      */
     public static boolean isCore(int uid) {
-        if (uid > 0) {
+        if (uid >= 0) {
             final int appId = getAppId(uid);
             return appId < Process.FIRST_APPLICATION_UID;
         } else {
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index ca4c796..b9dd376 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -32,6 +32,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.UUID;
 
@@ -158,6 +159,13 @@
     private final Object mLock = new Object();
 
     /**
+     * List of exemptions to the API blacklist. These are prefix matches on the runtime format
+     * symbol signature. Any matching symbol is treated by the runtime as being on the light grey
+     * list.
+     */
+    private List<String> mApiBlacklistExemptions = Collections.emptyList();
+
+    /**
      * The state of the connection to the primary zygote.
      */
     private ZygoteState primaryZygoteState;
@@ -175,7 +183,7 @@
      * The process will continue running after this function returns.
      *
      * <p>If processes are not enabled, a new thread in the caller's
-     * process is created and main() of <var>processClass</var> called there.
+     * process is created and main() of <var>processclass</var> called there.
      *
      * <p>The niceName parameter, if not an empty string, is a custom name to
      * give to the process instead of using processClass.  This allows you to
@@ -454,6 +462,49 @@
     }
 
     /**
+     * Push hidden API blacklisting exemptions into the zygote process(es).
+     *
+     * <p>The list of exemptions will take affect for all new processes forked from the zygote after
+     * this call.
+     *
+     * @param exemptions List of hidden API exemption prefixes.
+     */
+    public void setApiBlacklistExemptions(List<String> exemptions) {
+        synchronized (mLock) {
+            mApiBlacklistExemptions = exemptions;
+            maybeSetApiBlacklistExemptions(primaryZygoteState, true);
+            maybeSetApiBlacklistExemptions(secondaryZygoteState, true);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void maybeSetApiBlacklistExemptions(ZygoteState state, boolean sendIfEmpty) {
+        if (state == null || state.isClosed()) {
+            return;
+        }
+        if (!sendIfEmpty && mApiBlacklistExemptions.isEmpty()) {
+            return;
+        }
+        try {
+            state.writer.write(Integer.toString(mApiBlacklistExemptions.size() + 1));
+            state.writer.newLine();
+            state.writer.write("--set-api-blacklist-exemptions");
+            state.writer.newLine();
+            for (int i = 0; i < mApiBlacklistExemptions.size(); ++i) {
+                state.writer.write(mApiBlacklistExemptions.get(i));
+                state.writer.newLine();
+            }
+            state.writer.flush();
+            int status = state.inputStream.readInt();
+            if (status != 0) {
+                Slog.e(LOG_TAG, "Failed to set API blacklist exemptions; status " + status);
+            }
+        } catch (IOException ioe) {
+            Slog.e(LOG_TAG, "Failed to set API blacklist exemptions", ioe);
+        }
+    }
+
+    /**
      * Tries to open socket to Zygote process if not already open. If
      * already open, does nothing.  May block and retry.  Requires that mLock be held.
      */
@@ -467,8 +518,8 @@
             } catch (IOException ioe) {
                 throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
             }
+            maybeSetApiBlacklistExemptions(primaryZygoteState, false);
         }
-
         if (primaryZygoteState.matches(abi)) {
             return primaryZygoteState;
         }
@@ -480,6 +531,7 @@
             } catch (IOException ioe) {
                 throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
             }
+            maybeSetApiBlacklistExemptions(secondaryZygoteState, false);
         }
 
         if (secondaryZygoteState.matches(abi)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 70f343e..b7f6cde 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7809,6 +7809,14 @@
                 "suppress_auto_battery_saver_suggestion";
 
         /**
+         * List of packages, which data need to be unconditionally cleared before full restore.
+         * Type: string
+         * @hide
+         */
+        public static final String PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE =
+                "packages_to_clear_data_before_full_restore";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
index 2a66206..4af1af5 100644
--- a/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
+++ b/core/java/android/security/keystore/recovery/KeyChainProtectionParams.java
@@ -50,6 +50,22 @@
  */
 @SystemApi
 public final class KeyChainProtectionParams implements Parcelable {
+
+    // IMPORTANT! PLEASE READ!
+    // -----------------------
+    // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
+    // - Update the #writeToParcel(Parcel) method below
+    // - Update the #(Parcel) constructor below
+    // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
+    //     accidentally breaks your fields in the Parcel in the future.
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly serialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly deserialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
+    //     in the future.
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"TYPE_"}, value = {TYPE_LOCKSCREEN})
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index 24ff182..e46c34c 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -48,6 +48,22 @@
  */
 @SystemApi
 public final class KeyChainSnapshot implements Parcelable {
+
+    // IMPORTANT! PLEASE READ!
+    // -----------------------
+    // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
+    // - Update the #writeToParcel(Parcel) method below
+    // - Update the #(Parcel) constructor below
+    // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
+    //     accidentally breaks your fields in the Parcel in the future.
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly serialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly deserialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
+    //     in the future.
+
     private static final int DEFAULT_MAX_ATTEMPTS = 10;
     private static final long DEFAULT_COUNTER_ID = 1L;
 
diff --git a/core/java/android/security/keystore/recovery/KeyDerivationParams.java b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
index 225b592..d16f3ea 100644
--- a/core/java/android/security/keystore/recovery/KeyDerivationParams.java
+++ b/core/java/android/security/keystore/recovery/KeyDerivationParams.java
@@ -35,6 +35,22 @@
  */
 @SystemApi
 public final class KeyDerivationParams implements Parcelable {
+
+    // IMPORTANT! PLEASE READ!
+    // -----------------------
+    // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
+    // - Update the #writeToParcel(Parcel) method below
+    // - Update the #(Parcel) constructor below
+    // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
+    //     accidentally breaks your fields in the Parcel in the future.
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly serialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly deserialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
+    //     in the future.
+
     private final int mAlgorithm;
     private final byte[] mSalt;
     private final int mMemoryDifficulty;
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index 714e35a..32952db 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -42,6 +42,21 @@
     // The only supported format is AES-256 symmetric key.
     private byte[] mEncryptedKeyMaterial;
 
+    // IMPORTANT! PLEASE READ!
+    // -----------------------
+    // If you edit this file (e.g., to add new fields), please MAKE SURE to also do the following:
+    // - Update the #writeToParcel(Parcel) method below
+    // - Update the #(Parcel) constructor below
+    // - Update android.security.keystore.recovery.KeyChainSnapshotTest to make sure nobody
+    //     accidentally breaks your fields in the Parcel in the future.
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly serialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeyChainSnapshotSerializer to correctly deserialize your new field
+    // - Update com.android.server.locksettings.recoverablekeystore.serialization
+    //     .KeychainSnapshotSerializerTest to make sure nobody breaks serialization of your field
+    //     in the future.
+
     /**
      * Builder for creating {@link WrappedApplicationKey}.
      */
diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java
index cf16749..99d45f4 100644
--- a/core/java/android/service/autofill/AutofillFieldClassificationService.java
+++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java
@@ -113,23 +113,67 @@
     /**
      * Calculates field classification scores in a batch.
      *
-     * <p>See {@link AutofillFieldClassificationService} for more info about field classification
-     * scores.
+     * <p>A field classification score is a {@code float} representing how well an
+     * {@link AutofillValue} filled matches a expected value predicted by an autofill service
+     * &mdash;a full-match is {@code 1.0} (representing 100%), while a full mismatch is {@code 0.0}.
      *
-     * @param algorithm name of the algorithm to be used to calculate the scores. If invalid, the
-     * default algorithm will be used instead.
-     * @param args optional arguments to be passed to the algorithm.
+     * <p>The exact score depends on the algorithm used to calculate it&mdash; the service must
+     * provide at least one default algorithm (which is used when the algorithm is not specified
+     * or is invalid), but it could provide more (in which case the algorithm name should be
+     * specifiied by the caller when calculating the scores).
+     *
+     * <p>For example, if the service provides an algorithm named {@code EXACT_MATCH} that
+     * returns {@code 1.0} if all characters in match or {@code 0.0} otherwise, a call to:
+     *
+     * <pre>
+     * service.onGetScores("EXACT_MATCH", null,
+     *   Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")),
+     *   Arrays.asList("email1", "phone1"));
+     * </pre>
+     *
+     * <p>Returns:
+     *
+     * <pre>
+     * [
+     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
+     *   [0.0, 0.0]  // "PHONE1" compared against ["email1", "phone1"]
+     * ];
+     * </pre>
+     *
+     * <p>If the same algorithm allows the caller to specify whether the comparisons should be
+     * case sensitive by passing a boolean option named {@code "case_sensitive"}, then a call to:
+     *
+     * <pre>
+     * Bundle algorithmOptions = new Bundle();
+     * algorithmOptions.putBoolean("case_sensitive", false);
+     *
+     * service.onGetScores("EXACT_MATCH", algorithmOptions,
+     *   Arrays.asList(AutofillValue.forText("email1"), AutofillValue.forText("PHONE1")),
+     *   Arrays.asList("email1", "phone1"));
+     * </pre>
+     *
+     * <p>Returns:
+     *
+     * <pre>
+     * [
+     *   [1.0, 0.0], // "email1" compared against ["email1", "phone1"]
+     *   [0.0, 1.0]  // "PHONE1" compared against ["email1", "phone1"]
+     * ];
+     * </pre>
+     *
+     * @param algorithm name of the algorithm to be used to calculate the scores. If invalid or
+     * {@code null}, the default algorithm is used instead.
+     * @param algorithmOptions optional arguments to be passed to the algorithm.
      * @param actualValues values entered by the user.
      * @param userDataValues values predicted from the user data.
-     * @return the calculated scores, with the first dimension representing actual values and the
-     * second dimension values from {@link UserData}.
+     * @return the calculated scores of {@code actualValues} x {@code userDataValues}.
      *
      * {@hide}
      */
     @Nullable
     @SystemApi
     public float[][] onGetScores(@Nullable String algorithm,
-            @Nullable Bundle args, @NonNull List<AutofillValue> actualValues,
+            @Nullable Bundle algorithmOptions, @NonNull List<AutofillValue> actualValues,
             @NonNull List<String> userDataValues) {
         Log.e(TAG, "service implementation (" + getClass() + " does not implement onGetScore()");
         return null;
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 630007b..b413d48 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -43,8 +43,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -512,7 +512,7 @@
     public static final class Options implements Parcelable {
 
         private @Nullable LocaleList mDefaultLocales;
-        private @Nullable Calendar mReferenceTime;
+        private @Nullable ZonedDateTime mReferenceTime;
 
         public Options() {}
 
@@ -531,7 +531,7 @@
          *      be interpreted. This should usually be the time when the text was originally
          *      composed. If no reference time is set, now is used.
          */
-        public Options setReferenceTime(Calendar referenceTime) {
+        public Options setReferenceTime(ZonedDateTime referenceTime) {
             mReferenceTime = referenceTime;
             return this;
         }
@@ -550,7 +550,7 @@
          *      interpreted.
          */
         @Nullable
-        public Calendar getReferenceTime() {
+        public ZonedDateTime getReferenceTime() {
             return mReferenceTime;
         }
 
@@ -567,7 +567,7 @@
             }
             dest.writeInt(mReferenceTime != null ? 1 : 0);
             if (mReferenceTime != null) {
-                dest.writeSerializable(mReferenceTime);
+                dest.writeString(mReferenceTime.toString());
             }
         }
 
@@ -589,7 +589,7 @@
                 mDefaultLocales = LocaleList.CREATOR.createFromParcel(in);
             }
             if (in.readInt() > 0) {
-                mReferenceTime = (Calendar) in.readSerializable();
+                mReferenceTime = ZonedDateTime.parse(in.readString());
             }
         }
     }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5ba470a..8d1ed0e 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -16,6 +16,8 @@
 
 package android.view.textclassifier;
 
+import static java.time.temporal.ChronoUnit.MILLIS;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
@@ -45,9 +47,10 @@
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.time.Instant;
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -119,7 +122,7 @@
                     && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final String localesString = concatenateLocales(locales);
-                final Calendar refTime = Calendar.getInstance();
+                final ZonedDateTime refTime = ZonedDateTime.now();
                 final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed();
                 final TextClassifierImplNative nativeImpl = getNative(locales);
                 final String string = text.toString();
@@ -143,8 +146,8 @@
                             nativeImpl.classifyText(
                                     string, start, end,
                                     new TextClassifierImplNative.ClassificationOptions(
-                                            refTime.getTimeInMillis(),
-                                            refTime.getTimeZone().getID(),
+                                            refTime.toInstant().toEpochMilli(),
+                                            refTime.getZone().getId(),
                                             localesString));
                     final int size = results.length;
                     for (int i = 0; i < size; i++) {
@@ -183,19 +186,20 @@
                 final String string = text.toString();
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final String localesString = concatenateLocales(locales);
-                final Calendar refTime = (options != null && options.getReferenceTime() != null)
-                        ? options.getReferenceTime() : Calendar.getInstance();
+                final ZonedDateTime refTime =
+                        (options != null && options.getReferenceTime() != null)
+                                ? options.getReferenceTime() : ZonedDateTime.now();
 
                 final TextClassifierImplNative.ClassificationResult[] results =
                         getNative(locales)
                                 .classifyText(string, startIndex, endIndex,
                                         new TextClassifierImplNative.ClassificationOptions(
-                                                refTime.getTimeInMillis(),
-                                                refTime.getTimeZone().getID(),
+                                                refTime.toInstant().toEpochMilli(),
+                                                refTime.getZone().getId(),
                                                 localesString));
                 if (results.length > 0) {
                     return createClassificationResult(
-                            results, string, startIndex, endIndex, refTime);
+                            results, string, startIndex, endIndex, refTime.toInstant());
                 }
             }
         } catch (Throwable t) {
@@ -224,7 +228,7 @@
         try {
             final long startTimeMs = System.currentTimeMillis();
             final LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
-            final Calendar refTime = Calendar.getInstance();
+            final ZonedDateTime refTime = ZonedDateTime.now();
             final Collection<String> entitiesToIdentify =
                     options != null && options.getEntityConfig() != null
                             ? options.getEntityConfig().resolveEntityListModifications(
@@ -236,8 +240,8 @@
                     nativeImpl.annotate(
                         textString,
                         new TextClassifierImplNative.AnnotationOptions(
-                                refTime.getTimeInMillis(),
-                                refTime.getTimeZone().getID(),
+                                refTime.toInstant().toEpochMilli(),
+                                refTime.getZone().getId(),
                                 concatenateLocales(defaultLocales)));
             for (TextClassifierImplNative.AnnotatedSpan span : annotations) {
                 final TextClassifierImplNative.ClassificationResult[] results =
@@ -416,7 +420,7 @@
 
     private TextClassification createClassificationResult(
             TextClassifierImplNative.ClassificationResult[] classifications,
-            String text, int start, int end, @Nullable Calendar referenceTime) {
+            String text, int start, int end, @Nullable Instant referenceTime) {
         final String classifiedText = text.substring(start, end);
         final TextClassification.Builder builder = new TextClassification.Builder()
                 .setText(classifiedText);
@@ -646,7 +650,7 @@
         @NonNull
         public static List<LabeledIntent> create(
                 Context context,
-                @Nullable Calendar referenceTime,
+                @Nullable Instant referenceTime,
                 TextClassifierImplNative.ClassificationResult classification,
                 String text) {
             final String type = classification.getCollection().trim().toLowerCase(Locale.ENGLISH);
@@ -663,10 +667,9 @@
                 case TextClassifier.TYPE_DATE:
                 case TextClassifier.TYPE_DATE_TIME:
                     if (classification.getDatetimeResult() != null) {
-                        Calendar eventTime = Calendar.getInstance();
-                        eventTime.setTimeInMillis(
+                        final Instant parsedTime = Instant.ofEpochMilli(
                                 classification.getDatetimeResult().getTimeMsUtc());
-                        return createForDatetime(context, type, referenceTime, eventTime);
+                        return createForDatetime(context, type, referenceTime, parsedTime);
                     } else {
                         return new ArrayList<>();
                     }
@@ -758,18 +761,17 @@
 
         @NonNull
         private static List<LabeledIntent> createForDatetime(
-                Context context, String type, @Nullable Calendar referenceTime,
-                Calendar eventTime) {
+                Context context, String type, @Nullable Instant referenceTime,
+                Instant parsedTime) {
             if (referenceTime == null) {
                 // If no reference time was given, use now.
-                referenceTime = Calendar.getInstance();
+                referenceTime = Instant.now();
             }
             List<LabeledIntent> actions = new ArrayList<>();
-            actions.add(createCalendarViewIntent(context, eventTime));
-            final long millisSinceReference =
-                    eventTime.getTimeInMillis() - referenceTime.getTimeInMillis();
-            if (millisSinceReference > MIN_EVENT_FUTURE_MILLIS) {
-                actions.add(createCalendarCreateEventIntent(context, eventTime, type));
+            actions.add(createCalendarViewIntent(context, parsedTime));
+            final long millisUntilEvent = referenceTime.until(parsedTime, MILLIS);
+            if (millisUntilEvent > MIN_EVENT_FUTURE_MILLIS) {
+                actions.add(createCalendarCreateEventIntent(context, parsedTime, type));
             }
             return actions;
         }
@@ -784,10 +786,10 @@
         }
 
         @NonNull
-        private static LabeledIntent createCalendarViewIntent(Context context, Calendar eventTime) {
+        private static LabeledIntent createCalendarViewIntent(Context context, Instant parsedTime) {
             Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon();
             builder.appendPath("time");
-            ContentUris.appendId(builder, eventTime.getTimeInMillis());
+            ContentUris.appendId(builder, parsedTime.toEpochMilli());
             return new LabeledIntent(
                     context.getString(com.android.internal.R.string.view_calendar),
                     context.getString(com.android.internal.R.string.view_calendar_desc),
@@ -796,7 +798,7 @@
 
         @NonNull
         private static LabeledIntent createCalendarCreateEventIntent(
-                Context context, Calendar eventTime, @EntityType String type) {
+                Context context, Instant parsedTime, @EntityType String type) {
             final boolean isAllDay = TextClassifier.TYPE_DATE.equals(type);
             return new LabeledIntent(
                     context.getString(com.android.internal.R.string.add_calendar_event),
@@ -805,9 +807,9 @@
                             .setData(CalendarContract.Events.CONTENT_URI)
                             .putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, isAllDay)
                             .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME,
-                                    eventTime.getTimeInMillis())
+                                    parsedTime.toEpochMilli())
                             .putExtra(CalendarContract.EXTRA_EVENT_END_TIME,
-                                    eventTime.getTimeInMillis() + DEFAULT_EVENT_DURATION));
+                                    parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION));
         }
     }
 }
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index b049db3..f4b7032 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -187,11 +187,27 @@
 
     @Override
     public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
+        return performBackup(packageInfo, data, /*flags=*/ 0);
+    }
+
+    @Override
+    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data, int flags) {
+        boolean isIncremental = (flags & FLAG_INCREMENTAL) != 0;
+        boolean isNonIncremental = (flags & FLAG_NON_INCREMENTAL) != 0;
+
+        if (isIncremental) {
+            Log.i(TAG, "Performing incremental backup for " + packageInfo.packageName);
+        } else if (isNonIncremental) {
+            Log.i(TAG, "Performing non-incremental backup for " + packageInfo.packageName);
+        } else {
+            Log.i(TAG, "Performing backup for " + packageInfo.packageName);
+        }
+
         if (DEBUG) {
             try {
-            StructStat ss = Os.fstat(data.getFileDescriptor());
-            Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName
-                    + " size=" + ss.st_size);
+                StructStat ss = Os.fstat(data.getFileDescriptor());
+                Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName
+                        + " size=" + ss.st_size + " flags=" + flags);
             } catch (ErrnoException e) {
                 Log.w(TAG, "Unable to stat input file in performBackup() on "
                         + packageInfo.packageName);
@@ -199,7 +215,26 @@
         }
 
         File packageDir = new File(mCurrentSetIncrementalDir, packageInfo.packageName);
-        packageDir.mkdirs();
+        boolean hasDataForPackage = !packageDir.mkdirs();
+
+        if (isIncremental) {
+            if (mParameters.isNonIncrementalOnly() || !hasDataForPackage) {
+                if (mParameters.isNonIncrementalOnly()) {
+                    Log.w(TAG, "Transport is in non-incremental only mode.");
+
+                } else {
+                    Log.w(TAG,
+                            "Requested incremental, but transport currently stores no data for the "
+                                    + "package, requesting non-incremental retry.");
+                }
+                return TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED;
+            }
+        }
+        if (isNonIncremental && hasDataForPackage) {
+            Log.w(TAG, "Requested non-incremental, deleting existing data.");
+            clearBackupData(packageInfo);
+            packageDir.mkdirs();
+        }
 
         // Each 'record' in the restore set is kept in its own file, named by
         // the record key.  Wind through the data file, extracting individual
diff --git a/core/java/com/android/internal/backup/LocalTransportParameters.java b/core/java/com/android/internal/backup/LocalTransportParameters.java
index 154e79d..2427d39 100644
--- a/core/java/com/android/internal/backup/LocalTransportParameters.java
+++ b/core/java/com/android/internal/backup/LocalTransportParameters.java
@@ -26,8 +26,10 @@
     private static final String TAG = "LocalTransportParams";
     private static final String SETTING = Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS;
     private static final String KEY_FAKE_ENCRYPTION_FLAG = "fake_encryption_flag";
+    private static final String KEY_NON_INCREMENTAL_ONLY = "non_incremental_only";
 
     private boolean mFakeEncryptionFlag;
+    private boolean mIsNonIncrementalOnly;
 
     LocalTransportParameters(Handler handler, ContentResolver resolver) {
         super(handler, resolver, Settings.Secure.getUriFor(SETTING));
@@ -37,11 +39,16 @@
         return mFakeEncryptionFlag;
     }
 
+    boolean isNonIncrementalOnly() {
+        return mIsNonIncrementalOnly;
+    }
+
     public String getSettingValue(ContentResolver resolver) {
         return Settings.Secure.getString(resolver, SETTING);
     }
 
     public void update(KeyValueListParser parser) {
         mFakeEncryptionFlag = parser.getBoolean(KEY_FAKE_ENCRYPTION_FLAG, false);
+        mIsNonIncrementalOnly = parser.getBoolean(KEY_NON_INCREMENTAL_ONLY, false);
     }
 }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index cd83c57..5d40a73 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -47,6 +47,8 @@
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Arrays;
+
 import libcore.io.IoUtils;
 
 /**
@@ -159,6 +161,11 @@
             return null;
         }
 
+        if (parsedArgs.apiBlacklistExemptions != null) {
+            handleApiBlacklistExemptions(parsedArgs.apiBlacklistExemptions);
+            return null;
+        }
+
         if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
             throw new ZygoteSecurityException("Client may not specify capabilities: " +
                     "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
@@ -278,6 +285,15 @@
         }
     }
 
+    private void handleApiBlacklistExemptions(String[] exemptions) {
+        try {
+            ZygoteInit.setApiBlacklistExemptions(exemptions);
+            mSocketOutStream.writeInt(0);
+        } catch (IOException ioe) {
+            throw new IllegalStateException("Error writing to command socket", ioe);
+        }
+    }
+
     protected void preload() {
         ZygoteInit.lazyPreload();
     }
@@ -439,6 +455,12 @@
         boolean startChildZygote;
 
         /**
+         * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
+         * or when they change, via --set-api-blacklist-exemptions.
+         */
+        String[] apiBlacklistExemptions;
+
+        /**
          * Constructs instance and parses args
          * @param args zygote command-line args
          * @throws IllegalArgumentException
@@ -592,6 +614,11 @@
                     preloadDefault = true;
                 } else if (arg.equals("--start-child-zygote")) {
                     startChildZygote = true;
+                } else if (arg.equals("--set-api-blacklist-exemptions")) {
+                    // consume all remaining args; this is a stand-alone command, never included
+                    // with the regular fork command.
+                    apiBlacklistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length);
+                    curArg = args.length;
                 } else {
                     break;
                 }
@@ -606,7 +633,7 @@
                     throw new IllegalArgumentException(
                             "Unexpected arguments after --preload-package.");
                 }
-            } else if (!preloadDefault) {
+            } else if (!preloadDefault && apiBlacklistExemptions == null) {
                 if (!seenRuntimeArgs) {
                     throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
                 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9467ecc..c5d41db 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -514,6 +514,10 @@
         /* should never reach here */
     }
 
+    public static void setApiBlacklistExemptions(String[] exemptions) {
+        VMRuntime.getRuntime().setHiddenApiExemptions(exemptions);
+    }
+
     /**
      * Creates a PathClassLoader for the given class path that is associated with a shared
      * namespace, i.e., this classloader can access platform-private native libraries. The
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 726c450..825b7a0 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -210,7 +210,7 @@
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
-                                          jboolean asAlphaMask) {
+                                          jboolean asAlphaMask, jobject jcolorSpace) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
     SkAndroidCodec* codec = decoder->mCodec.get();
     const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
@@ -264,7 +264,8 @@
         // This is currently the only way to know that we should decode to F16.
         colorType = codec->computeOutputColorType(colorType);
     }
-    sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+    sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(env, jcolorSpace);
+    colorSpace = codec->computeOutputColorSpace(colorType, colorSpace);
     decodeInfo = decodeInfo.makeColorType(colorType).makeColorSpace(colorSpace);
 
     SkBitmap bm;
@@ -507,18 +508,26 @@
     return encodedFormatToString(env, decoder->mCodec->getEncodedFormat());
 }
 
+static jobject ImageDecoder_nGetColorSpace(JNIEnv* env, jobject /*clazz*/, jlong nativePtr) {
+    auto* codec = reinterpret_cast<ImageDecoder*>(nativePtr)->mCodec.get();
+    auto colorType = codec->computeOutputColorType(codec->getInfo().colorType());
+    sk_sp<SkColorSpace> colorSpace = codec->computeOutputColorSpace(colorType);
+    return GraphicsJNI::getColorSpace(env, colorSpace, colorType);
+}
+
 static const JNINativeMethod gImageDecoderMethods[] = {
     { "nCreate",        "(JLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;",    (void*) ImageDecoder_nCreateAsset },
     { "nCreate",        "(Ljava/nio/ByteBuffer;IILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteBuffer },
     { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZ)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZLandroid/graphics/ColorSpace;)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
     { "nClose",         "(J)V",                                  (void*) ImageDecoder_nClose},
     { "nGetMimeType",   "(J)Ljava/lang/String;",                 (void*) ImageDecoder_nGetMimeType },
+    { "nGetColorSpace", "(J)Landroid/graphics/ColorSpace;",      (void*) ImageDecoder_nGetColorSpace },
 };
 
 int register_android_graphics_ImageDecoder(JNIEnv* env) {
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index d3d6882..97abd82 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -37,6 +37,14 @@
 class SkPathGlue {
 public:
 
+    static void finalizer(SkPath* obj) {
+        // Purge entries from the HWUI path cache if this path's data is unique
+        if (obj->unique() && android::uirenderer::Caches::hasInstance()) {
+            android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
+        }
+        delete obj;
+    }
+
     // ---------------- Regular JNI -----------------------------
 
     static jlong init(JNIEnv* env, jclass clazz) {
@@ -48,13 +56,8 @@
         return reinterpret_cast<jlong>(new SkPath(*val));
     }
 
-    static void finalize(JNIEnv* env, jclass clazz, jlong objHandle) {
-        SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
-        // Purge entries from the HWUI path cache if this path's data is unique
-        if (obj->unique() && android::uirenderer::Caches::hasInstance()) {
-            android::uirenderer::Caches::getInstance().pathCache.removeDeferred(obj);
-        }
-        delete obj;
+    static jlong getFinalizer(JNIEnv* env, jclass clazz) {
+        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
     }
 
     static void set(JNIEnv* env, jclass clazz, jlong dstHandle, jlong srcHandle) {
@@ -469,7 +472,9 @@
         SkRect rect;
         SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
         jboolean result = obj->isRect(&rect);
-        GraphicsJNI::rect_to_jrectf(rect, env, jrect);
+        if (jrect) {
+            GraphicsJNI::rect_to_jrectf(rect, env, jrect);
+        }
         return result;
     }
 
@@ -510,7 +515,7 @@
 static const JNINativeMethod methods[] = {
     {"nInit","()J", (void*) SkPathGlue::init},
     {"nInit","(J)J", (void*) SkPathGlue::init_Path},
-    {"nFinalize", "(J)V", (void*) SkPathGlue::finalize},
+    {"nGetFinalizer", "()J", (void*) SkPathGlue::getFinalizer},
     {"nSet","(JJ)V", (void*) SkPathGlue::set},
     {"nComputeBounds","(JLandroid/graphics/RectF;)V", (void*) SkPathGlue::computeBounds},
     {"nIncReserve","(JI)V", (void*) SkPathGlue::incReserve},
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index cfb8980..593747d 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -145,6 +145,7 @@
         optional SettingProto transport = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto manager_constants = 5;
         optional SettingProto local_transport_parameters = 6;
+        optional SettingProto packages_to_clear_data_before_full_restore = 7;
     }
     optional Backup backup = 10;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 48d394a..f4715fc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2016,11 +2016,11 @@
     <permission android:name="android.permission.REMOVE_TASKS"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
+    <!-- @SystemApi @TestApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
         android:protectionLevel="signature|privileged|development" />
 
-    <!-- @SystemApi @hide Allows an application to embed other activities -->
+    <!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
     <permission android:name="android.permission.ACTIVITY_EMBEDDING"
                 android:protectionLevel="signature|privileged|development" />
 
@@ -3121,6 +3121,12 @@
     <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_MODE"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to control the color saturation of the display.
+         @hide
+         @SystemApi -->
+    <permission android:name="android.permission.CONTROL_DISPLAY_SATURATION"
+        android:protectionLevel="signature|privileged" />
+
     <!-- Allows an application to collect usage infomation about brightness slider changes.
          <p>Not for use by third-party applications.</p>
          @hide
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 2a3fcad..4b9465d 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -587,7 +587,8 @@
                  Settings.Secure.BLUETOOTH_ON_WHILE_DRIVING,
                  Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
                  Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
-                 Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION);
+                 Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION,
+                 Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index afc4bd5..5d58f55 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -37,9 +37,10 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Locale;
-import java.util.TimeZone;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -163,8 +164,9 @@
 
     @Test
     public void testParcelOptions() {
-        Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
-        referenceTime.setTimeInMillis(946771200000L);  // 2000-01-02
+        ZonedDateTime referenceTime = ZonedDateTime.ofInstant(
+                Instant.ofEpochMilli(946771200000L),  // 2000-01-02
+                ZoneId.of("UTC"));
 
         TextClassification.Options reference = new TextClassification.Options();
         reference.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY));
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 5ca0ad6..6051f88 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -432,6 +432,18 @@
         public boolean isAnimated() {
             return mDecoder.mAnimated;
         }
+
+        /**
+         * If known, the color space the decoded bitmap will have. Note that the
+         * output color space is not guaranteed to be the color space the bitmap
+         * is encoded with. If not known (when the config is
+         * {@link Bitmap.Config#ALPHA_8} for instance), or there is an error,
+         * it is set to null.
+         */
+        @Nullable
+        public ColorSpace getColorSpace() {
+            return mDecoder.getColorSpace();
+        }
     };
 
     /** @removed
@@ -582,16 +594,17 @@
     private final int     mHeight;
     private final boolean mAnimated;
 
-    private int     mDesiredWidth;
-    private int     mDesiredHeight;
-    private int     mAllocator = ALLOCATOR_DEFAULT;
-    private boolean mRequireUnpremultiplied = false;
-    private boolean mMutable = false;
-    private boolean mConserveMemory = false;
-    private boolean mDecodeAsAlphaMask = false;
-    private Rect    mCropRect;
-    private Rect    mOutPaddingRect;
-    private Source  mSource;
+    private int        mDesiredWidth;
+    private int        mDesiredHeight;
+    private int        mAllocator = ALLOCATOR_DEFAULT;
+    private boolean    mRequireUnpremultiplied = false;
+    private boolean    mMutable = false;
+    private boolean    mConserveMemory = false;
+    private boolean    mDecodeAsAlphaMask = false;
+    private ColorSpace mDesiredColorSpace = null;
+    private Rect       mCropRect;
+    private Rect       mOutPaddingRect;
+    private Source     mSource;
 
     private PostProcessor          mPostProcessor;
     private OnPartialImageListener mOnPartialImageListener;
@@ -766,7 +779,7 @@
      *
      *  <p>This takes an input that functions like
      *  {@link BitmapFactory.Options#inSampleSize}. It returns a width and
-     *  height that can be acheived by sampling the encoded image. Other widths
+     *  height that can be achieved by sampling the encoded image. Other widths
      *  and heights may be supported, but will require an additional (internal)
      *  scaling step. Such internal scaling is *not* supported with
      *  {@link #setRequireUnpremultiplied} set to {@code true}.</p>
@@ -774,6 +787,8 @@
      *  @param sampleSize Sampling rate of the encoded image.
      *  @return {@link android.util.Size} of the width and height after
      *      sampling.
+     *
+     *  @hide
      */
     @NonNull
     public Size getSampledSize(int sampleSize) {
@@ -789,14 +804,29 @@
     }
 
     // Modifiers
+    /** @removed
+     * @deprecated Renamed to {@link #setTargetSize}.
+     */
+    @java.lang.Deprecated
+    public ImageDecoder setResize(int width, int height) {
+        return this.setTargetSize(width, height);
+    }
+
     /**
-     *  Resize the output to have the following size.
+     *  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>
+     *
+     *  <p>Only the last call to this or {@link #setTargetSampleSize} is
+     *  respected.</p>
      *
      *  @param width must be greater than 0.
      *  @param height must be greater than 0.
      *  @return this object for chaining.
      */
-    public ImageDecoder setResize(int width, int height) {
+    public ImageDecoder setTargetSize(int width, int height) {
         if (width <= 0 || height <= 0) {
             throw new IllegalArgumentException("Dimensions must be positive! "
                     + "provided (" + width + ", " + height + ")");
@@ -807,18 +837,65 @@
         return this;
     }
 
+    /** @removed
+     * @deprecated Renamed to {@link #setTargetSampleSize}.
+     */
+    @java.lang.Deprecated
+    public ImageDecoder setResize(int sampleSize) {
+        return this.setTargetSampleSize(sampleSize);
+    }
+
+    private int getTargetDimension(int original, int sampleSize, int computed) {
+        // Sampling will never result in a smaller size than 1.
+        if (sampleSize >= original) {
+            return 1;
+        }
+
+        // Use integer divide to find the desired size. If that is what
+        // getSampledSize computed, that is the size to use.
+        int target = original / sampleSize;
+        if (computed == target) {
+            return computed;
+        }
+
+        // If sampleSize does not divide evenly into original, the decoder
+        // may round in either direction. It just needs to get a result that
+        // is close.
+        int reverse = computed * sampleSize;
+        if (Math.abs(reverse - original) < sampleSize) {
+            // This is the size that can be decoded most efficiently.
+            return computed;
+        }
+
+        // The decoder could not get close (e.g. it is a DNG image).
+        return target;
+    }
+
     /**
-     *  Resize based on a sample size.
+     *  Set the target size with a sampleSize.
      *
-     *  <p>This has the same effect as passing the result of
-     *  {@link #getSampledSize} to {@link #setResize(int, int)}.</p>
+     *  <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>
+     *
+     *  <p>Requests the decoder to subsample the original image, returning a
+     *  smaller image to save memory. The sample size 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
+     *  width/height of the original, and 1/16 the number of pixels.</p>
+     *
+     *  <p>Must be greater than or equal to 1.</p>
+     *
+     *  <p>Only the last call to this or {@link #setTargetSize} is respected.</p>
      *
      *  @param sampleSize Sampling rate of the encoded image.
      *  @return this object for chaining.
      */
-    public ImageDecoder setResize(int sampleSize) {
+    public ImageDecoder setTargetSampleSize(int sampleSize) {
         Size size = this.getSampledSize(sampleSize);
-        return this.setResize(size.getWidth(), size.getHeight());
+        int targetWidth = getTargetDimension(mWidth, sampleSize, size.getWidth());
+        int targetHeight = getTargetDimension(mHeight, sampleSize, size.getHeight());
+        return this.setTargetSize(targetWidth, targetHeight);
     }
 
     private boolean requestedResize() {
@@ -972,8 +1049,8 @@
      *  Crop the output to {@code subset} of the (possibly) scaled image.
      *
      *  <p>{@code subset} must be contained within the size set by
-     *  {@link #setResize} or the bounds of the image if setResize was not
-     *  called. Otherwise an {@link IllegalStateException} will be thrown 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>
      *
      *  <p>NOT intended as a replacement for
@@ -1116,6 +1193,37 @@
         return this.getDecodeAsAlphaMask();
     }
 
+    /**
+     * 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>{@link Bitmap.Config#RGBA_F16} always uses the
+     * {@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
+     * such as {@link ColorSpace.Named#CIE_LAB Lab}.</p>
+     *
+     * <p class="note">The specified color space's transfer function must be
+     * an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}. An
+     * <code>IllegalArgumentException</code> will be thrown by the decode methods
+     * if calling {@link ColorSpace.Rgb#getTransferParameters()} on the
+     * specified color space returns null.</p>
+     */
+    public ImageDecoder setTargetColorSpace(ColorSpace colorSpace) {
+        mDesiredColorSpace = colorSpace;
+        return this;
+    }
+
     @Override
     public void close() {
         mCloseGuard.close();
@@ -1154,6 +1262,17 @@
         if (mPostProcessor != null && mRequireUnpremultiplied) {
             throw new IllegalStateException("Cannot draw to unpremultiplied pixels!");
         }
+
+        if (mDesiredColorSpace != null) {
+            if (!(mDesiredColorSpace instanceof ColorSpace.Rgb)) {
+                throw new IllegalArgumentException("The target color space must use the "
+                            + "RGB color model - provided: " + mDesiredColorSpace);
+            }
+            if (((ColorSpace.Rgb) mDesiredColorSpace).getTransferParameters() == null) {
+                throw new IllegalArgumentException("The target color space must use an "
+                            + "ICC parametric transfer function - provided: " + mDesiredColorSpace);
+            }
+        }
     }
 
     private static void checkSubset(int width, int height, Rect r) {
@@ -1172,7 +1291,7 @@
         return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
                 mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mRequireUnpremultiplied,
-                mConserveMemory, mDecodeAsAlphaMask);
+                mConserveMemory, mDecodeAsAlphaMask, mDesiredColorSpace);
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1353,7 +1472,7 @@
         float scale = (float) dstDensity / srcDensity;
         int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
         int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
-        decoder.setResize(scaledWidth, scaledHeight);
+        decoder.setTargetSize(scaledWidth, scaledHeight);
         return dstDensity;
     }
 
@@ -1362,6 +1481,11 @@
         return nGetMimeType(mNativePtr);
     }
 
+    @Nullable
+    private ColorSpace getColorSpace() {
+        return nGetColorSpace(mNativePtr);
+    }
+
     /**
      *  See {@link #decodeBitmap(Source, OnHeaderDecodedListener)}.
      */
@@ -1411,11 +1535,13 @@
             int width, int height,
             @Nullable Rect cropRect, boolean mutable,
             int allocator, boolean requireUnpremul,
-            boolean conserveMemory, boolean decodeAsAlphaMask)
+            boolean conserveMemory, boolean decodeAsAlphaMask,
+            @Nullable ColorSpace desiredColorSpace)
         throws IOException;
     private static native Size nGetSampledSize(long nativePtr,
                                                int sampleSize);
     private static native void nGetPadding(long nativePtr, @NonNull Rect outRect);
     private static native void nClose(long nativePtr);
     private static native String nGetMimeType(long nativePtr);
+    private static native ColorSpace nGetColorSpace(long nativePtr);
 }
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 098cdc6..cd0862c 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -24,6 +24,8 @@
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
+import libcore.util.NativeAllocationRegistry;
+
 /**
  * The Path class encapsulates compound (multiple contour) geometric paths
  * consisting of straight line segments, quadratic curves, and cubic curves.
@@ -32,10 +34,14 @@
  * text on a path.
  */
 public class Path {
+
+    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                Path.class.getClassLoader(), nGetFinalizer(), 48 /* dummy size */);
+
     /**
      * @hide
      */
-    public long mNativePath;
+    public final long mNativePath;
 
     /**
      * @hide
@@ -52,6 +58,7 @@
      */
     public Path() {
         mNativePath = nInit();
+        sRegistry.registerNativeAllocation(this, mNativePath);
     }
 
     /**
@@ -69,6 +76,7 @@
             }
         }
         mNativePath = nInit(valNative);
+        sRegistry.registerNativeAllocation(this, mNativePath);
     }
 
     /**
@@ -297,7 +305,7 @@
      *             a rectangle
      * @return     true if the path specifies a rectangle
      */
-    public boolean isRect(RectF rect) {
+    public boolean isRect(@Nullable  RectF rect) {
         return nIsRect(mNativePath, rect);
     }
 
@@ -771,15 +779,6 @@
         nTransform(mNativePath, matrix.native_instance);
     }
 
-    protected void finalize() throws Throwable {
-        try {
-            nFinalize(mNativePath);
-            mNativePath = 0;  //  Other finalizers can still call us.
-        } finally {
-            super.finalize();
-        }
-    }
-
     /** @hide */
     public final long readOnlyNI() {
         return mNativePath;
@@ -820,7 +819,7 @@
 
     private static native long nInit();
     private static native long nInit(long nPath);
-    private static native void nFinalize(long nPath);
+    private static native long nGetFinalizer();
     private static native void nSet(long native_dst, long nSrc);
     private static native void nComputeBounds(long nPath, RectF bounds);
     private static native void nIncReserve(long nPath, int extraPtCount);
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 5a8fa07..0d32075 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -33,8 +33,8 @@
     boolean isUserSelectable(String alias);
     void setUserSelectable(String alias, boolean isUserSelectable);
 
-    boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
-    boolean attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
+    int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec);
+    int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags,
             out KeymasterCertificateChain chain);
     boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain);
 
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 2daf733..46a7fa8 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -246,6 +246,82 @@
     public static final String EXTRA_KEY_ACCESSIBLE = "android.security.extra.KEY_ACCESSIBLE";
 
     /**
+     * Indicates that a call to {@link #generateKeyPair} was successful.
+     * @hide
+     */
+    public static final int KEY_GEN_SUCCESS = 0;
+
+    /**
+     * An alias was missing from the key specifications when calling {@link #generateKeyPair}.
+     * @hide
+     */
+    public static final int KEY_GEN_MISSING_ALIAS = 1;
+
+    /**
+     * A key attestation challenge was provided to {@link #generateKeyPair}, but it shouldn't
+     * have been provided.
+     * @hide
+     */
+    public static final int KEY_GEN_SUPERFLUOUS_ATTESTATION_CHALLENGE = 2;
+
+    /**
+     * Algorithm not supported by {@link #generateKeyPair}
+     * @hide
+     */
+    public static final int KEY_GEN_NO_SUCH_ALGORITHM = 3;
+
+    /**
+     * Invalid algorithm parameters when calling {@link #generateKeyPair}
+     * @hide
+     */
+    public static final int KEY_GEN_INVALID_ALGORITHM_PARAMETERS = 4;
+
+    /**
+     * Keystore is not available when calling {@link #generateKeyPair}
+     * @hide
+     */
+    public static final int KEY_GEN_NO_KEYSTORE_PROVIDER = 5;
+
+    /**
+     * General failure while calling {@link #generateKeyPair}
+     * @hide
+     */
+    public static final int KEY_GEN_FAILURE = 6;
+
+    /**
+     * Successful call to {@link #attestKey}
+     * @hide
+     */
+    public static final int KEY_ATTESTATION_SUCCESS = 0;
+
+    /**
+     * Attestation challenge missing when calling {@link #attestKey}
+     * @hide
+     */
+    public static final int KEY_ATTESTATION_MISSING_CHALLENGE = 1;
+
+    /**
+     * The caller requested Device ID attestation when calling {@link #attestKey}, but has no
+     * permissions to get device identifiers.
+     * @hide
+     */
+    public static final int KEY_ATTESTATION_CANNOT_COLLECT_DATA = 2;
+
+    /**
+     * The underlying hardware does not support Device ID attestation or cannot attest to the
+     * identifiers that are stored on the device. This indicates permanent inability
+     * to get attestation records on the device.
+     * @hide
+     */
+    public static final int KEY_ATTESTATION_CANNOT_ATTEST_IDS = 3;
+
+    /**
+     * General failure when calling {@link #attestKey}
+     * @hide
+     */
+    public static final int KEY_ATTESTATION_FAILURE = 4;
+
+    /**
      * Returns an {@code Intent} that can be used for credential
      * installation. The intent may be used without any extras, in
      * which case the user will be able to install credentials from
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 1924bbe..1e2ebf8 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -66,6 +66,7 @@
     public static final int VALUE_CORRUPTED = 8;
     public static final int UNDEFINED_ACTION = 9;
     public static final int WRONG_PASSWORD = 10;
+    public static final int CANNOT_ATTEST_IDS = -66;
     public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
 
     /**
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 98e67c2..3643ca4 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -224,7 +224,9 @@
     s.append("GNSS_KPI_END").append("\n");
     GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats();
     if (stats != null) {
-      s.append("Power Metrics").append('\n');
+      s.append("Power Metrics").append("\n");
+      s.append("  Time on battery (min): "
+          + stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
       long[] t = stats.getTimeInGpsSignalQualityLevel();
       if (t != null && t.length == NUM_GPS_SIGNAL_QUALITY_LEVELS) {
         s.append("  Amount of time (while on battery) Top 4 Avg CN0 > " +
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index e0c567b..8d62cac 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -654,9 +654,11 @@
      * ID is returned.
      *
      * @param level the new security level, one of
-     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
-     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
-     * {@link #HW_SECURE_ALL}.
+     * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO},
+     * {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
+     * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO},
+     * {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or
+     * {@link #SECURITY_LEVEL_HW_SECURE_ALL}.
      *
      * @throws NotProvisionedException if provisioning is needed
      * @throws ResourceBusyException if required resources are in use
@@ -1140,8 +1142,9 @@
      * implementation.
      */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE,
-            HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
+    @IntDef({SECURITY_LEVEL_UNKNOWN, SECURITY_LEVEL_SW_SECURE_CRYPTO,
+            SECURITY_LEVEL_SW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_CRYPTO,
+            SECURITY_LEVEL_HW_SECURE_DECODE, SECURITY_LEVEL_HW_SECURE_ALL})
     public @interface SecurityLevel {}
 
     /**
@@ -1153,31 +1156,31 @@
     /**
      * DRM key management uses software-based whitebox crypto.
      */
-    public static final int SW_SECURE_CRYPTO = 1;
+    public static final int SECURITY_LEVEL_SW_SECURE_CRYPTO = 1;
 
     /**
      * DRM key management and decoding use software-based whitebox crypto.
      */
-    public static final int SW_SECURE_DECODE = 2;
+    public static final int SECURITY_LEVEL_SW_SECURE_DECODE = 2;
 
     /**
      * DRM key management and crypto operations are performed within a hardware
      * backed trusted execution environment.
      */
-    public static final int HW_SECURE_CRYPTO = 3;
+    public static final int SECURITY_LEVEL_HW_SECURE_CRYPTO = 3;
 
     /**
      * DRM key management, crypto operations and decoding of content are
      * performed within a hardware backed trusted execution environment.
      */
-    public static final int HW_SECURE_DECODE = 4;
+    public static final int SECURITY_LEVEL_HW_SECURE_DECODE = 4;
 
     /**
      * DRM key management, crypto operations, decoding of content and all
      * handling of the media (compressed and uncompressed) is handled within a
      * hardware backed trusted execution environment.
      */
-    public static final int HW_SECURE_ALL = 5;
+    public static final int SECURITY_LEVEL_HW_SECURE_ALL = 5;
 
     /**
      * The maximum security level supported by the device. This is the default
@@ -1203,9 +1206,9 @@
      * @param sessionId the session to query.
      * <p>
      * @return one of {@link #SECURITY_LEVEL_UNKNOWN},
-     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
-     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
-     * {@link #HW_SECURE_ALL}.
+     * {@link #SECURITY_LEVEL_SW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_SW_SECURE_DECODE},
+     * {@link #SECURITY_LEVEL_HW_SECURE_CRYPTO}, {@link #SECURITY_LEVEL_HW_SECURE_DECODE} or
+     * {@link #SECURITY_LEVEL_HW_SECURE_ALL}.
      */
     @SecurityLevel
     public native int getSecurityLevel(@NonNull byte[] sessionId);
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 3affee5c0..bd0019f 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -50,6 +50,4 @@
     void setPlaybackToLocal(in AudioAttributes attributes);
     void setPlaybackToRemote(int control, int max);
     void setCurrentVolume(int currentVolume);
-
-    String getCallingPackage();
 }
diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl
index 893bd3c..9634c7f 100644
--- a/media/java/android/media/session/ISessionCallback.aidl
+++ b/media/java/android/media/session/ISessionCallback.aidl
@@ -25,30 +25,33 @@
  * @hide
  */
 oneway interface ISessionCallback {
-    void onCommand(String command, in Bundle args, in ResultReceiver cb);
-    void onMediaButton(in Intent mediaButtonIntent, int sequenceNumber, in ResultReceiver cb);
+    void onCommand(String packageName, int pid, int uid, String command, in Bundle args,
+            in ResultReceiver cb);
+    void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
+            int sequenceNumber, in ResultReceiver cb);
 
     // These callbacks are for the TransportPerformer
-    void onPrepare();
-    void onPrepareFromMediaId(String mediaId, in Bundle extras);
-    void onPrepareFromSearch(String query, in Bundle extras);
-    void onPrepareFromUri(in Uri uri, in Bundle extras);
-    void onPlay();
-    void onPlayFromMediaId(String mediaId, in Bundle extras);
-    void onPlayFromSearch(String query, in Bundle extras);
-    void onPlayFromUri(in Uri uri, in Bundle extras);
-    void onSkipToTrack(long id);
-    void onPause();
-    void onStop();
-    void onNext();
-    void onPrevious();
-    void onFastForward();
-    void onRewind();
-    void onSeekTo(long pos);
-    void onRate(in Rating rating);
-    void onCustomAction(String action, in Bundle args);
+    void onPrepare(String packageName, int pid, int uid);
+    void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
+            in Bundle extras);
+    void onPrepareFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
+    void onPrepareFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
+    void onPlay(String packageName, int pid, int uid);
+    void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId, in Bundle extras);
+    void onPlayFromSearch(String packageName, int pid, int uid, String query, in Bundle extras);
+    void onPlayFromUri(String packageName, int pid, int uid, in Uri uri, in Bundle extras);
+    void onSkipToTrack(String packageName, int pid, int uid, long id);
+    void onPause(String packageName, int pid, int uid);
+    void onStop(String packageName, int pid, int uid);
+    void onNext(String packageName, int pid, int uid);
+    void onPrevious(String packageName, int pid, int uid);
+    void onFastForward(String packageName, int pid, int uid);
+    void onRewind(String packageName, int pid, int uid);
+    void onSeekTo(String packageName, int pid, int uid, long pos);
+    void onRate(String packageName, int pid, int uid, in Rating rating);
+    void onCustomAction(String packageName, int pid, int uid, String action, in Bundle args);
 
     // These callbacks are for volume handling
-    void onAdjustVolume(int direction);
-    void onSetVolumeTo(int value);
+    void onAdjustVolume(String packageName, int pid, int uid, int direction);
+    void onSetVolumeTo(String packageName, int pid, int uid, int value);
 }
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 249bcdc..06f5863 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -36,8 +36,8 @@
  * @hide
  */
 interface ISessionController {
-    void sendCommand(String command, in Bundle args, in ResultReceiver cb);
-    boolean sendMediaButton(in KeyEvent mediaButton);
+    void sendCommand(String packageName, String command, in Bundle args, in ResultReceiver cb);
+    boolean sendMediaButton(String packageName, in KeyEvent mediaButton);
     void registerCallbackListener(in ISessionControllerCallback cb);
     void unregisterCallbackListener(in ISessionControllerCallback cb);
     boolean isTransportControlEnabled();
@@ -46,28 +46,28 @@
     PendingIntent getLaunchPendingIntent();
     long getFlags();
     ParcelableVolumeInfo getVolumeAttributes();
-    void adjustVolume(int direction, int flags, String packageName);
-    void setVolumeTo(int value, int flags, String packageName);
+    void adjustVolume(String packageName, int direction, int flags);
+    void setVolumeTo(String packageName, int value, int flags);
 
     // These commands are for the TransportControls
-    void prepare();
-    void prepareFromMediaId(String mediaId, in Bundle extras);
-    void prepareFromSearch(String string, in Bundle extras);
-    void prepareFromUri(in Uri uri, in Bundle extras);
-    void play();
-    void playFromMediaId(String mediaId, in Bundle extras);
-    void playFromSearch(String string, in Bundle extras);
-    void playFromUri(in Uri uri, in Bundle extras);
-    void skipToQueueItem(long id);
-    void pause();
-    void stop();
-    void next();
-    void previous();
-    void fastForward();
-    void rewind();
-    void seekTo(long pos);
-    void rate(in Rating rating);
-    void sendCustomAction(String action, in Bundle args);
+    void prepare(String packageName);
+    void prepareFromMediaId(String packageName, String mediaId, in Bundle extras);
+    void prepareFromSearch(String packageName, String string, in Bundle extras);
+    void prepareFromUri(String packageName, in Uri uri, in Bundle extras);
+    void play(String packageName);
+    void playFromMediaId(String packageName, String mediaId, in Bundle extras);
+    void playFromSearch(String packageName, String string, in Bundle extras);
+    void playFromUri(String packageName, in Uri uri, in Bundle extras);
+    void skipToQueueItem(String packageName, long id);
+    void pause(String packageName);
+    void stop(String packageName);
+    void next(String packageName);
+    void previous(String packageName);
+    void fastForward(String packageName);
+    void rewind(String packageName);
+    void seekTo(String packageName, long pos);
+    void rate(String packageName, in Rating rating);
+    void sendCustomAction(String packageName, String action, in Bundle args);
     MediaMetadata getMetadata();
     PlaybackState getPlaybackState();
     ParceledListSlice getQueue();
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 622900f..f16804c 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -133,7 +133,7 @@
             return false;
         }
         try {
-            return mSessionBinder.sendMediaButton(keyEvent);
+            return mSessionBinder.sendMediaButton(mContext.getPackageName(), keyEvent);
         } catch (RemoteException e) {
             // System is dead. =(
         }
@@ -301,7 +301,7 @@
      */
     public void setVolumeTo(int value, int flags) {
         try {
-            mSessionBinder.setVolumeTo(value, flags, mContext.getPackageName());
+            mSessionBinder.setVolumeTo(mContext.getPackageName(), value, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling setVolumeTo.", e);
         }
@@ -322,7 +322,7 @@
      */
     public void adjustVolume(int direction, int flags) {
         try {
-            mSessionBinder.adjustVolume(direction, flags, mContext.getPackageName());
+            mSessionBinder.adjustVolume(mContext.getPackageName(), direction, flags);
         } catch (RemoteException e) {
             Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
         }
@@ -388,7 +388,7 @@
             throw new IllegalArgumentException("command cannot be null or empty");
         }
         try {
-            mSessionBinder.sendCommand(command, args, cb);
+            mSessionBinder.sendCommand(mContext.getPackageName(), command, args, cb);
         } catch (RemoteException e) {
             Log.d(TAG, "Dead object in sendCommand.", e);
         }
@@ -600,7 +600,7 @@
          */
         public void prepare() {
             try {
-                mSessionBinder.prepare();
+                mSessionBinder.prepare(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare.", e);
             }
@@ -624,7 +624,7 @@
                         "You must specify a non-empty String for prepareFromMediaId.");
             }
             try {
-                mSessionBinder.prepareFromMediaId(mediaId, extras);
+                mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mediaId, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
             }
@@ -650,7 +650,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.prepareFromSearch(query, extras);
+                mSessionBinder.prepareFromSearch(mContext.getPackageName(), query, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
             }
@@ -674,7 +674,7 @@
                         "You must specify a non-empty Uri for prepareFromUri.");
             }
             try {
-                mSessionBinder.prepareFromUri(uri, extras);
+                mSessionBinder.prepareFromUri(mContext.getPackageName(), uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
             }
@@ -685,7 +685,7 @@
          */
         public void play() {
             try {
-                mSessionBinder.play();
+                mSessionBinder.play(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play.", e);
             }
@@ -704,7 +704,7 @@
                         "You must specify a non-empty String for playFromMediaId.");
             }
             try {
-                mSessionBinder.playFromMediaId(mediaId, extras);
+                mSessionBinder.playFromMediaId(mContext.getPackageName(), mediaId, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
             }
@@ -726,7 +726,7 @@
                 query = "";
             }
             try {
-                mSessionBinder.playFromSearch(query, extras);
+                mSessionBinder.playFromSearch(mContext.getPackageName(), query, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + query + ").", e);
             }
@@ -745,7 +745,7 @@
                         "You must specify a non-empty Uri for playFromUri.");
             }
             try {
-                mSessionBinder.playFromUri(uri, extras);
+                mSessionBinder.playFromUri(mContext.getPackageName(), uri, extras);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling play(" + uri + ").", e);
             }
@@ -757,7 +757,7 @@
          */
         public void skipToQueueItem(long id) {
             try {
-                mSessionBinder.skipToQueueItem(id);
+                mSessionBinder.skipToQueueItem(mContext.getPackageName(), id);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
             }
@@ -769,7 +769,7 @@
          */
         public void pause() {
             try {
-                mSessionBinder.pause();
+                mSessionBinder.pause(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling pause.", e);
             }
@@ -781,7 +781,7 @@
          */
         public void stop() {
             try {
-                mSessionBinder.stop();
+                mSessionBinder.stop(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling stop.", e);
             }
@@ -794,7 +794,7 @@
          */
         public void seekTo(long pos) {
             try {
-                mSessionBinder.seekTo(pos);
+                mSessionBinder.seekTo(mContext.getPackageName(), pos);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling seekTo.", e);
             }
@@ -806,7 +806,7 @@
          */
         public void fastForward() {
             try {
-                mSessionBinder.fastForward();
+                mSessionBinder.fastForward(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling fastForward.", e);
             }
@@ -817,7 +817,7 @@
          */
         public void skipToNext() {
             try {
-                mSessionBinder.next();
+                mSessionBinder.next(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling next.", e);
             }
@@ -829,7 +829,7 @@
          */
         public void rewind() {
             try {
-                mSessionBinder.rewind();
+                mSessionBinder.rewind(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rewind.", e);
             }
@@ -840,7 +840,7 @@
          */
         public void skipToPrevious() {
             try {
-                mSessionBinder.previous();
+                mSessionBinder.previous(mContext.getPackageName());
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling previous.", e);
             }
@@ -855,7 +855,7 @@
          */
         public void setRating(Rating rating) {
             try {
-                mSessionBinder.rate(rating);
+                mSessionBinder.rate(mContext.getPackageName(), rating);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling rate.", e);
             }
@@ -890,7 +890,7 @@
                 throw new IllegalArgumentException("CustomAction cannot be null.");
             }
             try {
-                mSessionBinder.sendCustomAction(action, args);
+                mSessionBinder.sendCustomAction(mContext.getPackageName(), action, args);
             } catch (RemoteException e) {
                 Log.d(TAG, "Dead object in sendCustomAction.", e);
             }
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index b8d01c4..5e8b8ca 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -39,6 +39,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
 import android.util.Log;
@@ -103,6 +104,16 @@
      */
     public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
 
+    /**
+     * @hide
+     */
+    public static final int INVALID_UID = -1;
+
+    /**
+     * @hide
+     */
+    public static final int INVALID_PID = -1;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, value = {
@@ -501,6 +512,22 @@
     }
 
     /**
+     * Gets the controller information who sent the current request.
+     * <p>
+     * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
+     *
+     * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
+     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+     */
+    public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
+        if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
+            throw new IllegalStateException(
+                    "This should be called inside of MediaSession.Callback methods");
+        }
+        return mCallback.mCurrentControllerInfo;
+    }
+
+    /**
      * Notify the system that the remote volume changed.
      *
      * @param provider The provider that is handling volume changes.
@@ -528,16 +555,14 @@
      * @hide
      */
     public String getCallingPackage() {
-        try {
-            return mBinder.getCallingPackage();
-        } catch (RemoteException e) {
-            Log.wtf(TAG, "Dead object in getCallingPackage.", e);
+        if (mCallback != null) {
+            return mCallback.mCurrentControllerInfo.getPackageName();
         }
         return null;
     }
 
-    private void dispatchPrepare() {
-        postToCallback(CallbackMessageHandler.MSG_PREPARE);
+    private void dispatchPrepare(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_PREPARE, null, extras);
     }
 
     private void dispatchPrepareFromMediaId(String mediaId, Bundle extras) {
@@ -552,8 +577,8 @@
         postToCallback(CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
     }
 
-    private void dispatchPlay() {
-        postToCallback(CallbackMessageHandler.MSG_PLAY);
+    private void dispatchPlay(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_PLAY, null, extras);
     }
 
     private void dispatchPlayFromMediaId(String mediaId, Bundle extras) {
@@ -568,69 +593,61 @@
         postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
     }
 
-    private void dispatchSkipToItem(long id) {
-        postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id);
+    private void dispatchSkipToItem(long id, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, extras);
     }
 
-    private void dispatchPause() {
-        postToCallback(CallbackMessageHandler.MSG_PAUSE);
+    private void dispatchPause(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_PAUSE, null, extras);
     }
 
-    private void dispatchStop() {
-        postToCallback(CallbackMessageHandler.MSG_STOP);
+    private void dispatchStop(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_STOP, null, extras);
     }
 
-    private void dispatchNext() {
-        postToCallback(CallbackMessageHandler.MSG_NEXT);
+    private void dispatchNext(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_NEXT, null, extras);
     }
 
-    private void dispatchPrevious() {
-        postToCallback(CallbackMessageHandler.MSG_PREVIOUS);
+    private void dispatchPrevious(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_PREVIOUS, null, extras);
     }
 
-    private void dispatchFastForward() {
-        postToCallback(CallbackMessageHandler.MSG_FAST_FORWARD);
+    private void dispatchFastForward(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_FAST_FORWARD, null, extras);
     }
 
-    private void dispatchRewind() {
-        postToCallback(CallbackMessageHandler.MSG_REWIND);
+    private void dispatchRewind(Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_REWIND, null, extras);
     }
 
-    private void dispatchSeekTo(long pos) {
-        postToCallback(CallbackMessageHandler.MSG_SEEK_TO, pos);
+    private void dispatchSeekTo(long pos, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_SEEK_TO, pos, extras);
     }
 
-    private void dispatchRate(Rating rating) {
-        postToCallback(CallbackMessageHandler.MSG_RATE, rating);
+    private void dispatchRate(Rating rating, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_RATE, rating, extras);
     }
 
-    private void dispatchCustomAction(String action, Bundle args) {
-        postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
+    private void dispatchCustomAction(String action, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, extras);
     }
 
-    private void dispatchMediaButton(Intent mediaButtonIntent) {
-        postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent);
+    private void dispatchMediaButton(Intent mediaButtonIntent, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, extras);
     }
 
-    private void dispatchAdjustVolume(int direction) {
-        postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction);
+    private void dispatchAdjustVolume(int direction, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, extras);
     }
 
-    private void dispatchSetVolumeTo(int volume) {
-        postToCallback(CallbackMessageHandler.MSG_SET_VOLUME, volume);
+    private void dispatchSetVolumeTo(int volume, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_SET_VOLUME, volume, extras);
     }
 
-    private void postToCallback(int what) {
-        postToCallback(what, null);
-    }
-
-    private void postCommand(String command, Bundle args, ResultReceiver resultCb) {
+    private void postCommand(String command, Bundle args, ResultReceiver resultCb, Bundle extras) {
         Command cmd = new Command(command, args, resultCb);
-        postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd);
-    }
-
-    private void postToCallback(int what, Object obj) {
-        postToCallback(what, obj, null);
+        postToCallback(CallbackMessageHandler.MSG_COMMAND, cmd, extras);
     }
 
     private void postToCallback(int what, Object obj, Bundle extras) {
@@ -734,9 +751,13 @@
      * and the system. A callback may be set using {@link #setCallback}.
      */
     public abstract static class Callback {
+
         private MediaSession mSession;
         private CallbackMessageHandler mHandler;
         private boolean mMediaPlayPauseKeyPending;
+        private String mCallingPackage;
+        private int mCallingPid;
+        private int mCallingUid;
 
         public Callback() {
         }
@@ -1023,24 +1044,26 @@
         private WeakReference<MediaSession> mMediaSession;
 
         public CallbackStub(MediaSession session) {
-            mMediaSession = new WeakReference<MediaSession>(session);
+            mMediaSession = new WeakReference<>(session);
         }
 
         @Override
-        public void onCommand(String command, Bundle args, ResultReceiver cb) {
+        public void onCommand(String packageName, int pid, int uid, String command, Bundle args,
+                ResultReceiver cb) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.postCommand(command, args, cb);
+                session.postCommand(command, args, cb, createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onMediaButton(Intent mediaButtonIntent, int sequenceNumber,
-                ResultReceiver cb) {
+        public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
+                int sequenceNumber, ResultReceiver cb) {
             MediaSession session = mMediaSession.get();
             try {
                 if (session != null) {
-                    session.dispatchMediaButton(mediaButtonIntent);
+                    session.dispatchMediaButton(
+                            mediaButtonIntent, createExtraBundle(packageName, pid, uid));
                 }
             } finally {
                 if (cb != null) {
@@ -1050,165 +1073,191 @@
         }
 
         @Override
-        public void onPrepare() {
+        public void onPrepare(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepare();
+                session.dispatchPrepare(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onPrepareFromMediaId(String mediaId, Bundle extras) {
+        public void onPrepareFromMediaId(String packageName, int pid, int uid, String mediaId,
+                Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepareFromMediaId(mediaId, extras);
+                session.dispatchPrepareFromMediaId(
+                        mediaId, createExtraBundle(packageName, pid, uid, extras));
             }
         }
 
         @Override
-        public void onPrepareFromSearch(String query, Bundle extras) {
+        public void onPrepareFromSearch(String packageName, int pid, int uid, String query,
+                Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepareFromSearch(query, extras);
+                session.dispatchPrepareFromSearch(
+                        query, createExtraBundle(packageName, pid, uid, extras));
             }
         }
 
         @Override
-        public void onPrepareFromUri(Uri uri, Bundle extras) {
+        public void onPrepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrepareFromUri(uri, extras);
+                session.dispatchPrepareFromUri(uri,
+                        createExtraBundle(packageName, pid, uid, extras));
             }
         }
 
         @Override
-        public void onPlay() {
+        public void onPlay(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlay();
+                session.dispatchPlay(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onPlayFromMediaId(String mediaId, Bundle extras) {
+        public void onPlayFromMediaId(String packageName, int pid, int uid, String mediaId,
+                Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromMediaId(mediaId, extras);
+                session.dispatchPlayFromMediaId(
+                        mediaId, createExtraBundle(packageName, pid, uid, extras));
             }
         }
 
         @Override
-        public void onPlayFromSearch(String query, Bundle extras) {
+        public void onPlayFromSearch(String packageName, int pid, int uid, String query,
+                Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromSearch(query, extras);
+                session.dispatchPlayFromSearch(query, createExtraBundle(packageName, pid, uid,
+                        extras));
             }
         }
 
         @Override
-        public void onPlayFromUri(Uri uri, Bundle extras) {
+        public void onPlayFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayFromUri(uri, extras);
+                session.dispatchPlayFromUri(uri, createExtraBundle(packageName, pid, uid, extras));
             }
         }
 
         @Override
-        public void onSkipToTrack(long id) {
+        public void onSkipToTrack(String packageName, int pid, int uid, long id) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSkipToItem(id);
+                session.dispatchSkipToItem(id, createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onPause() {
+        public void onPause(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPause();
+                session.dispatchPause(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onStop() {
+        public void onStop(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchStop();
+                session.dispatchStop(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onNext() {
+        public void onNext(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchNext();
+                session.dispatchNext(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onPrevious() {
+        public void onPrevious(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPrevious();
+                session.dispatchPrevious(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onFastForward() {
+        public void onFastForward(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchFastForward();
+                session.dispatchFastForward(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onRewind() {
+        public void onRewind(String packageName, int pid, int uid) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchRewind();
+                session.dispatchRewind(createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onSeekTo(long pos) {
+        public void onSeekTo(String packageName, int pid, int uid, long pos) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSeekTo(pos);
+                session.dispatchSeekTo(pos, createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onRate(Rating rating) {
+        public void onRate(String packageName, int pid, int uid, Rating rating) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchRate(rating);
+                session.dispatchRate(rating, createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onCustomAction(String action, Bundle args) {
+        public void onCustomAction(String packageName, int pid, int uid, String action,
+                Bundle args) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchCustomAction(action, args);
+                session.dispatchCustomAction(
+                        action, createExtraBundle(packageName, pid, uid, args));
             }
         }
 
         @Override
-        public void onAdjustVolume(int direction) {
+        public void onAdjustVolume(String packageName, int pid, int uid, int direction) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchAdjustVolume(direction);
+                session.dispatchAdjustVolume(direction, createExtraBundle(packageName, pid, uid));
             }
         }
 
         @Override
-        public void onSetVolumeTo(int value) {
+        public void onSetVolumeTo(String packageName, int pid, int uid, int value) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchSetVolumeTo(value);
+                session.dispatchSetVolumeTo(value, createExtraBundle(packageName, pid, uid));
             }
         }
 
+        private Bundle createExtraBundle(String packageName, int pid, int uid) {
+            return createExtraBundle(packageName, pid, uid, null);
+        }
+
+        private Bundle createExtraBundle(String packageName, int pid, int uid,
+                Bundle originalBundle) {
+            Bundle bundle = new Bundle();
+            bundle.putString(CallbackMessageHandler.EXTRA_KEY_CALLING_PACKAGE, packageName);
+            bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_PID, pid);
+            bundle.putInt(CallbackMessageHandler.EXTRA_KEY_CALLING_UID, uid);
+            if (originalBundle != null) {
+                bundle.putBundle(CallbackMessageHandler.EXTRA_KEY_ORIGINAL_BUNDLE, originalBundle);
+            }
+            return bundle;
+        }
     }
 
     /**
@@ -1272,7 +1321,8 @@
             return 0;
         }
 
-        public static final Creator<MediaSession.QueueItem> CREATOR = new Creator<MediaSession.QueueItem>() {
+        public static final Creator<MediaSession.QueueItem> CREATOR =
+                new Creator<MediaSession.QueueItem>() {
 
             @Override
             public MediaSession.QueueItem createFromParcel(Parcel p) {
@@ -1329,6 +1379,15 @@
 
     private class CallbackMessageHandler extends Handler {
 
+        private static final String EXTRA_KEY_CALLING_PACKAGE =
+                "android.media.session.extra.CALLING_PACKAGE";
+        private static final String EXTRA_KEY_CALLING_PID =
+                "android.media.session.extra.CALLING_PID";
+        private static final String EXTRA_KEY_CALLING_UID =
+                "android.media.session.extra.CALLING_UID";
+        private static final String EXTRA_KEY_ORIGINAL_BUNDLE =
+                "android.media.session.extra.ORIGINAL_BUNDLE";
+
         private static final int MSG_COMMAND = 1;
         private static final int MSG_MEDIA_BUTTON = 2;
         private static final int MSG_PREPARE = 3;
@@ -1355,6 +1414,8 @@
 
         private MediaSession.Callback mCallback;
 
+        private RemoteUserInfo mCurrentControllerInfo;
+
         public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
             super(looper, null, true);
             mCallback = callback;
@@ -1367,21 +1428,17 @@
             msg.sendToTarget();
         }
 
-        public void post(int what, Object obj) {
-            obtainMessage(what, obj).sendToTarget();
-        }
-
-        public void post(int what) {
-            post(what, null);
-        }
-
-        public void post(int what, Object obj, int arg1) {
-            obtainMessage(what, arg1, 0, obj).sendToTarget();
-        }
-
         @Override
         public void handleMessage(Message msg) {
             VolumeProvider vp;
+            Bundle bundle = msg.getData();
+            Bundle originalBundle = bundle.getBundle(EXTRA_KEY_ORIGINAL_BUNDLE);
+
+            mCurrentControllerInfo = new RemoteUserInfo(
+                    bundle.getString(EXTRA_KEY_CALLING_PACKAGE),
+                    bundle.getInt(EXTRA_KEY_CALLING_PID, INVALID_PID),
+                    bundle.getInt(EXTRA_KEY_CALLING_UID, INVALID_UID));
+
             switch (msg.what) {
                 case MSG_COMMAND:
                     Command cmd = (Command) msg.obj;
@@ -1394,25 +1451,25 @@
                     mCallback.onPrepare();
                     break;
                 case MSG_PREPARE_MEDIA_ID:
-                    mCallback.onPrepareFromMediaId((String) msg.obj, msg.getData());
+                    mCallback.onPrepareFromMediaId((String) msg.obj, originalBundle);
                     break;
                 case MSG_PREPARE_SEARCH:
-                    mCallback.onPrepareFromSearch((String) msg.obj, msg.getData());
+                    mCallback.onPrepareFromSearch((String) msg.obj, originalBundle);
                     break;
                 case MSG_PREPARE_URI:
-                    mCallback.onPrepareFromUri((Uri) msg.obj, msg.getData());
+                    mCallback.onPrepareFromUri((Uri) msg.obj, originalBundle);
                     break;
                 case MSG_PLAY:
                     mCallback.onPlay();
                     break;
                 case MSG_PLAY_MEDIA_ID:
-                    mCallback.onPlayFromMediaId((String) msg.obj, msg.getData());
+                    mCallback.onPlayFromMediaId((String) msg.obj, originalBundle);
                     break;
                 case MSG_PLAY_SEARCH:
-                    mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
+                    mCallback.onPlayFromSearch((String) msg.obj, originalBundle);
                     break;
                 case MSG_PLAY_URI:
-                    mCallback.onPlayFromUri((Uri) msg.obj, msg.getData());
+                    mCallback.onPlayFromUri((Uri) msg.obj, originalBundle);
                     break;
                 case MSG_SKIP_TO_ITEM:
                     mCallback.onSkipToQueueItem((Long) msg.obj);
@@ -1442,7 +1499,7 @@
                     mCallback.onSetRating((Rating) msg.obj);
                     break;
                 case MSG_CUSTOM_ACTION:
-                    mCallback.onCustomAction((String) msg.obj, msg.getData());
+                    mCallback.onCustomAction((String) msg.obj, originalBundle);
                     break;
                 case MSG_ADJUST_VOLUME:
                     synchronized (mLock) {
@@ -1464,6 +1521,7 @@
                     mCallback.handleMediaPlayPauseKeySingleTapIfPending();
                     break;
             }
+            mCurrentControllerInfo = null;
         }
     }
 }
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 3b12fca..519af1b 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -37,7 +37,9 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.service.media.MediaBrowserService;
 import android.service.notification.NotificationListenerService;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -340,19 +342,20 @@
     }
 
     /**
-     * Returns whether the api
+     * Returns whether the app is trusted.
+     * <p>
+     * An app is trusted if the app holds the android.Manifest.permission.MEDIA_CONTENT_CONTROL
+     * permission or has an enabled notification listener.
      *
-     * @param packageName packageName
-     * @param pid pid of the app
-     * @param uid uid of the app
-     * @hide
+     * @param userInfo The remote user info
      */
-    public boolean isTrusted(@NonNull String packageName, int pid, int uid) {
-        if (packageName == null) {
+    public boolean isTrustedForMediaControl(RemoteUserInfo userInfo) {
+        if (userInfo.getPackageName() == null) {
             return false;
         }
         try {
-            return mService.isTrusted(packageName, pid, uid);
+            return mService.isTrusted(
+                    userInfo.getPackageName(), userInfo.getPid(), userInfo.getUid());
         } catch (RemoteException e) {
             Log.wtf(TAG, "Cannot communicate with the service.", e);
         }
@@ -763,6 +766,56 @@
         public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
     }
 
+    /**
+     * Information of a remote user of {@link MediaSession} or {@link MediaBrowserService}.
+     * This can be used to decide whether the remote user is trusted app.
+     *
+     * @see #isTrustedForMediaControl(RemoteUserInfo)
+     */
+    public static final class RemoteUserInfo {
+        private String mPackageName;
+        private int mPid;
+        private int mUid;
+
+        public RemoteUserInfo(String packageName, int pid, int uid) {
+            mPackageName = packageName;
+            mPid = pid;
+            mUid = uid;
+        }
+
+        /**
+         * @return package name of the controller
+         */
+        public String getPackageName() {
+            return mPackageName;
+        }
+
+        /**
+         * @return pid of the controller
+         */
+        public int getPid() {
+            return mPid;
+        }
+
+        /**
+         * @return uid of the controller
+         */
+        public int getUid() {
+            return mUid;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof RemoteUserInfo)) {
+                return false;
+            }
+            RemoteUserInfo otherUserInfo = (RemoteUserInfo) obj;
+            return TextUtils.equals(mPackageName, otherUserInfo.mPackageName)
+                    && mPid == otherUserInfo.mPid
+                    && mUid == otherUserInfo.mUid;
+        }
+    }
+
     private static final class SessionsChangedWrapper {
         private Context mContext;
         private OnActiveSessionsChangedListener mListener;
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 4fc43ea..6d1bd45 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -31,6 +31,8 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.RemoteUserInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -112,6 +114,8 @@
      */
     private class ConnectionRecord implements IBinder.DeathRecipient {
         String pkg;
+        int uid;
+        int pid;
         Bundle rootHints;
         IMediaBrowserServiceCallbacks callbacks;
         BrowserRoot root;
@@ -199,6 +203,7 @@
         public void connect(final String pkg, final Bundle rootHints,
                 final IMediaBrowserServiceCallbacks callbacks) {
 
+            final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             if (!isValidPackage(pkg, uid)) {
                 throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
@@ -215,9 +220,14 @@
 
                         final ConnectionRecord connection = new ConnectionRecord();
                         connection.pkg = pkg;
+                        connection.pid = pid;
+                        connection.uid = uid;
                         connection.rootHints = rootHints;
                         connection.callbacks = callbacks;
+
+                        mCurConnection = connection;
                         connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
+                        mCurConnection = null;
 
                         // If they didn't return something, don't allow this client.
                         if (connection.root == null) {
@@ -505,21 +515,36 @@
      * media browser service when connecting and retrieving the root id for browsing, or null if
      * none. The contents of this bundle may affect the information returned when browsing.
      *
-     * @throws IllegalStateException If this method is called outside of {@link #onLoadChildren} or
-     *             {@link #onLoadItem}.
+     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
+     *             {@link #onLoadChildren} or {@link #onLoadItem}.
      * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
      * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
      * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
      */
     public final Bundle getBrowserRootHints() {
         if (mCurConnection == null) {
-            throw new IllegalStateException("This should be called inside of onLoadChildren or"
-                    + " onLoadItem methods");
+            throw new IllegalStateException("This should be called inside of onGetRoot or"
+                    + " onLoadChildren or onLoadItem methods");
         }
         return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
     }
 
     /**
+     * Gets the browser information who sent the current request.
+     *
+     * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
+     *             {@link #onLoadChildren} or {@link #onLoadItem}.
+     * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
+     */
+    public final RemoteUserInfo getCurrentBrowserInfo() {
+        if (mCurConnection == null) {
+            throw new IllegalStateException("This should be called inside of onGetRoot or"
+                    + " onLoadChildren or onLoadItem methods");
+        }
+        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
+    }
+
+    /**
      * Notifies all connected media browsers that the children of
      * the specified parent id have changed in some way.
      * This will cause browsers to fetch subscribed content again.
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4c20f05..54541f0 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -729,15 +729,15 @@
 
     GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_UNKNOWN", "I");
     gSecurityLevels.kSecurityLevelUnknown = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_CRYPTO", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_CRYPTO", "I");
     gSecurityLevels.kSecurityLevelSwSecureCrypto = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "SW_SECURE_DECODE", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_SW_SECURE_DECODE", "I");
     gSecurityLevels.kSecurityLevelSwSecureDecode = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_CRYPTO", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_CRYPTO", "I");
     gSecurityLevels.kSecurityLevelHwSecureCrypto = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_DECODE", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_DECODE", "I");
     gSecurityLevels.kSecurityLevelHwSecureDecode = env->GetStaticIntField(clazz, field);
-    GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I");
+    GET_STATIC_FIELD_ID(field, clazz, "SECURITY_LEVEL_HW_SECURE_ALL", "I");
     gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
 
     jmethodID getMaxSecurityLevel;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 4cd23f9..9347674 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -50,7 +50,9 @@
                 }
             };
     private final NetworkRequest mNetworkRequest = new NetworkRequest.Builder()
-            .clearCapabilities().addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+            .clearCapabilities()
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+            .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
     private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager
             .NetworkCallback() {
         @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 8f80527..a128b54 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -213,6 +213,7 @@
 
         mNetworkRequest = new NetworkRequest.Builder()
                 .clearCapabilities()
+                .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                 .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                 .build();
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index a444ac8..f43e719 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1724,6 +1724,9 @@
         dumpSetting(s, p,
                 Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS,
                 SecureSettingsProto.Backup.LOCAL_TRANSPORT_PARAMETERS);
+        dumpSetting(s, p,
+                Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
+                SecureSettingsProto.Backup.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE);
         p.end(backupToken);
 
         // Settings.Secure.BLUETOOTH_ON intentionally excluded since it's deprecated.
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 68293d9..df21151 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -56,7 +56,8 @@
     SystemUI-tags \
     SystemUI-proto
 
-LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common \
+    android.car
 
 LOCAL_PACKAGE_NAME := SystemUI
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 3d49e5c..3488168 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -205,6 +205,9 @@
     <!-- Listen app op changes -->
     <uses-permission android:name="android.permission.WATCH_APPOPS" />
 
+    <!-- to read and change hvac values in a car -->
+    <uses-permission android:name="android.car.permission.ADJUST_CAR_CLIMATE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
index 726d814..c0e0e59 100644
--- a/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_1x_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M5.62,16.29H4.58V9.06l-1.79,0.8V8.88l2.67-1.17h0.16V16.29z" />
+        android:pathData="M3.77,13.48H2.55V5.05L0.46,5.98V4.84l3.12-1.36h0.19V13.48z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M11.08,11.02l1.61-3.27h1.26l-2.22,4.23l2.27,4.3h-1.27l-1.64-3.33l-1.65,3.33H8.16l2.28-4.3L8.21,7.75h1.25L11.08,11.02z" />
+        android:pathData="M10.14,7.34l1.87-3.81h1.47L10.9,8.46l2.65,5.02h-1.48l-1.91-3.88l-1.92,3.88H6.74L9.4,8.46l-2.6-4.94h1.46L10.14,7.34z" />
     <path
-        android:pathData="M 0 0 H 13.99 V 24 H 0 V 0 Z" />
-</vector>
\ No newline at end of file
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
index 7a539ff..e4a5bf8 100644
--- a/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_3g_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.83,11.38h0.66c0.43,0,0.75-0.13,0.98-0.39s0.35-0.62,0.35-1.07c0-1-0.39-1.5-1.16-1.5c-0.37,0-0.66,0.13-0.87,0.4 S3.47,9.44,3.47,9.88H2.44c0-0.68,0.21-1.25,0.62-1.69s0.95-0.67,1.6-0.67c0.67,0,1.21,0.21,1.6,0.63s0.59,1.01,0.59,1.78 c0,0.39-0.1,0.76-0.31,1.1s-0.47,0.59-0.8,0.75c0.8,0.3,1.21,0.96,1.21,2c0,0.76-0.21,1.37-0.64,1.82s-0.98,0.68-1.66,0.68 c-0.68,0-1.22-0.21-1.64-0.64s-0.62-1-0.62-1.73h1.04c0,0.45,0.11,0.81,0.33,1.08s0.52,0.4,0.9,0.4c0.39,0,0.69-0.13,0.92-0.39 s0.34-0.66,0.34-1.2c0-1.04-0.49-1.55-1.47-1.55H3.83V11.38z" />
+        android:pathData="M1.9,7.88h0.77c0.5,0,0.88-0.15,1.15-0.46s0.4-0.72,0.4-1.25c0-1.17-0.45-1.75-1.35-1.75c-0.43,0-0.77,0.16-1.02,0.47 S1.49,5.62,1.49,6.13h-1.2c0-0.8,0.24-1.46,0.73-1.97s1.11-0.78,1.86-0.78c0.78,0,1.41,0.25,1.87,0.73S5.43,5.31,5.43,6.2 c0,0.46-0.12,0.89-0.36,1.29S4.52,8.18,4.14,8.37c0.94,0.35,1.41,1.12,1.41,2.33c0,0.89-0.25,1.6-0.74,2.12 c-0.49,0.53-1.14,0.79-1.94,0.79c-0.79,0-1.43-0.25-1.91-0.75c-0.49-0.5-0.73-1.17-0.73-2.01h1.21c0,0.53,0.13,0.95,0.38,1.26 c0.26,0.31,0.6,0.47,1.05,0.47c0.45,0,0.81-0.15,1.08-0.46s0.4-0.77,0.4-1.39c0-1.21-0.57-1.81-1.72-1.81H1.9V7.88z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M14,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.81-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.19-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.15-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92H14V15.11z" />
+        android:pathData="M13.77,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 C12.47,5.82,12.3,5.33,12,4.98s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.59,6.37,8.58,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H10.7V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
-</vector>
\ No newline at end of file
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
index b2fab0c8..e98560b 100644
--- a/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_4g_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="14dp"
+    android:height="17dp"
+    android:viewportWidth="14"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.42,13.3h0.95v0.88H6.42v1.98H5.38v-1.98H2.16v-0.64l3.17-5.91h1.09C6.42,7.63,6.42,13.3,6.42,13.3z M3.31,13.3h2.07 V9.25L3.31,13.3z" />
+        android:pathData="M5.07,10.13h1.11v1.03H5.07v2.31H3.86v-2.31H0.1v-0.75l3.7-6.9h1.27V10.13z M1.44,10.13h2.42V5.4L1.44,10.13z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M13.99,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.8-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.2-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.14-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92h2.62V15.11z" />
+        android:pathData="M13.9,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.72,6.37,8.71,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 14 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
index bdbb2df3..bf39ea2 100644
--- a/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_4g_plus_mobiledata.xml
@@ -14,20 +14,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="20dp"
-        android:height="24dp"
-        android:viewportWidth="20"
-        android:viewportHeight="24">
+    android:width="22dp"
+    android:height="17dp"
+    android:viewportWidth="22"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.18,13.3h0.95v0.88H6.18v1.98H5.14v-1.98H1.92v-0.64l3.17-5.91h1.09V13.3z M3.07,13.3h2.07V9.25L3.07,13.3z" />
+        android:pathData="M5.32,10.13h1.11v1.03H5.32v2.31H4.11v-2.31H0.35v-0.75l3.7-6.9h1.27V10.13z M1.69,10.13h2.42V5.4L1.69,10.13z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M13.75,15.11l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.8-2.59V11.1 c0-1.2,0.24-2.09,0.72-2.69s1.2-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68s0.71,1.1,0.76,1.94h-1.07 c-0.04-0.53-0.19-0.95-0.44-1.25s-0.63-0.45-1.14-0.45c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74 c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96h-1.56v-0.92h2.63V15.11z" />
+        android:pathData="M14.15,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13s1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H12.9 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7S8.97,6.37,8.96,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 20 9.64 L 18 9.64 L 18 7.64 L 17 7.64 L 17 9.64 L 15 9.64 L 15 10.64 L 17 10.64 L 17 12.64 L 18 12.64 L 18 10.64 L 20 10.64 Z" />
+        android:pathData="M 19.3 5.74 L 19.3 3.39 L 18 3.39 L 18 5.74 L 15.65 5.74 L 15.65 7.04 L 18 7.04 L 18 9.39 L 19.3 9.39 L 19.3 7.04 L 21.65 7.04 L 21.65 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 20 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 22 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
index 1a4a2e3..ca601d6 100644
--- a/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_e_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="7dp"
-        android:height="24dp"
-        android:viewportWidth="7"
-        android:viewportHeight="24">
+    android:width="6dp"
+    android:height="17dp"
+    android:viewportWidth="6"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M6.5,12.32H3.48v3.02H7v0.92H2.41V7.73h4.53v0.92H3.48v2.75H6.5V12.32z" />
+        android:pathData="M5.1,8.88H1.57v3.53h4.1v1.07H0.32V3.52h5.28V4.6H1.57V7.8H5.1V8.88z" />
     <path
-        android:pathData="M 0 0 H 7 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 6 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
index d6a0488..8ff6d7a 100644
--- a/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_g_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8dp"
-        android:height="24dp"
-        android:viewportWidth="8"
-        android:viewportHeight="24">
+    android:width="7dp"
+    android:height="17dp"
+    android:viewportWidth="7"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M8,15.21l-0.19,0.23c-0.54,0.63-1.33,0.94-2.37,0.94c-0.92,0-1.65-0.31-2.17-0.92s-0.79-1.48-0.81-2.59V11.2 c0-1.2,0.24-2.09,0.72-2.69s1.19-0.89,2.15-0.89c0.81,0,1.45,0.23,1.91,0.68S7.95,9.39,8,10.23H6.93C6.88,9.7,6.74,9.28,6.49,8.99 S5.85,8.54,5.34,8.54c-0.61,0-1.06,0.2-1.35,0.6s-0.43,1.04-0.45,1.92v1.74c0,0.86,0.16,1.52,0.49,1.98s0.8,0.69,1.41,0.69 c0.58,0,1.02-0.14,1.32-0.42l0.16-0.15v-1.96H5.37v-0.92H8V15.21z" />
+        android:pathData="M6.73,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13S2.5,3.39,3.62,3.39c0.95,0,1.69,0.26,2.23,0.79s0.83,1.28,0.89,2.26H5.48 c-0.05-0.62-0.22-1.1-0.52-1.45S4.22,4.46,3.62,4.46c-0.72,0-1.24,0.23-1.57,0.7S1.54,6.37,1.53,7.4v2.03c0,1,0.19,1.77,0.57,2.31 c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59H3.66V8.52h3.07V12.24z" />
     <path
-        android:pathData="M 0 0 H 8 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
index be85bbb..68ea58e 100644
--- a/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_h_mobiledata.xml
@@ -14,14 +14,14 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="8dp"
-        android:height="24dp"
-        android:viewportWidth="8"
-        android:viewportHeight="24">
+    android:width="7dp"
+    android:height="17dp"
+    android:viewportWidth="7"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M8,16.27H6.92v-3.94H3.49v3.94H2.42V7.73h1.07v3.67h3.43V7.73H8V16.27z" />
+        android:pathData="M6.76,13.48H5.5v-4.6H1.49v4.6H0.24V3.52h1.25V7.8H5.5V3.52h1.26V13.48z" />
     <path
-        android:pathData="M 0 0 H 8 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 7 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
index f31f83c..42128002 100644
--- a/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_h_plus_mobiledata.xml
@@ -14,17 +14,17 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="14dp"
-        android:height="24dp"
-        android:viewportWidth="14"
-        android:viewportHeight="24">
+    android:width="15dp"
+    android:height="17dp"
+    android:viewportWidth="15"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M7.64,16.27H6.56v-3.94H3.13v3.94H2.06V7.73h1.07v3.67h3.43V7.73h1.08V16.27z" />
+        android:pathData="M7.01,13.48H5.75v-4.6H1.74v4.6H0.49V3.52h1.25V7.8h4.01V3.52h1.26V13.48z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 14 9.73 L 12 9.73 L 12 7.73 L 11 7.73 L 11 9.73 L 9 9.73 L 9 10.73 L 11 10.73 L 11 12.73 L 12 12.73 L 12 10.73 L 14 10.73 Z" />
+        android:pathData="M 12.16 5.74 L 12.16 3.39 L 10.86 3.39 L 10.86 5.74 L 8.51 5.74 L 8.51 7.04 L 10.86 7.04 L 10.86 9.39 L 12.16 9.39 L 12.16 7.04 L 14.51 7.04 L 14.51 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 14 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 15 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
index e45b5e0..7536f51 100644
--- a/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_lte_mobiledata.xml
@@ -14,20 +14,20 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="18dp"
-        android:height="24dp"
-        android:viewportWidth="18"
-        android:viewportHeight="24">
+    android:width="18dp"
+    android:height="17dp"
+    android:viewportWidth="18"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.79,15.35h3.35v0.92H2.71V7.73h1.08V15.35z" />
+        android:pathData="M1.34,12.4h3.9v1.07H0.08V3.52h1.26V12.4z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M12.15,8.65H9.91v7.61H8.84V8.65H6.6V7.73h5.55V8.65z" />
+        android:pathData="M11.1,4.6H8.48v8.88H7.23V4.6H4.62V3.52h6.48V4.6z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M17.5,12.32h-3.02v3.02H18v0.92h-4.59V7.73h4.53v0.92h-3.46v2.75h3.02V12.32z" />
+        android:pathData="M17.34,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
     <path
-        android:pathData="M 0 0 H 18 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 18 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
index 553a5bd..302e3bd 100644
--- a/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
+++ b/packages/SystemUI/res/drawable/ic_lte_plus_mobiledata.xml
@@ -14,23 +14,23 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
+    android:width="26dp"
+    android:height="17dp"
+    android:viewportWidth="26"
+    android:viewportHeight="17">
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M3.91,15.35h3.35v0.92H2.84V7.73h1.08V15.35z" />
+        android:pathData="M1.59,12.4h3.9v1.07H0.33V3.52h1.26V12.4z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M12.28,8.65h-2.24v7.61H8.96V8.65H6.73V7.73h5.55V8.65z" />
+        android:pathData="M11.35,4.6H8.73v8.88H7.48V4.6H4.87V3.52h6.48V4.6z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M17.63,12.32h-3.02v3.02h3.52v0.92h-4.59V7.73h4.53v0.92h-3.46v2.75h3.02V12.32z" />
+        android:pathData="M17.59,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M 24 9.76 L 22 9.76 L 22 7.76 L 21 7.76 L 21 9.76 L 19 9.76 L 19 10.76 L 21 10.76 L 21 12.76 L 22 12.76 L 22 10.76 L 24 10.76 Z" />
+        android:pathData="M 23.32 5.74 L 23.32 3.39 L 22.02 3.39 L 22.02 5.74 L 19.67 5.74 L 19.67 7.04 L 22.02 7.04 L 22.02 9.39 L 23.32 9.39 L 23.32 7.04 L 25.67 7.04 L 25.67 5.74 Z" />
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:pathData="M 0 0 H 26 V 17 H 0 V 0 Z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/qs_header_status_dot.xml b/packages/SystemUI/res/drawable/qs_header_status_dot.xml
deleted file mode 100644
index 69bfd49..0000000
--- a/packages/SystemUI/res/drawable/qs_header_status_dot.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <solid android:color="@android:color/white"/>
-</shape>
diff --git a/packages/SystemUI/res/drawable/stat_sys_roaming.xml b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
index bd2edf3..0dd9f5a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_roaming.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_roaming.xml
@@ -1,28 +1,27 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+     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
+     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
+          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.
+     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.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="@dimen/signal_icon_size"
         android:height="@dimen/signal_icon_size"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M7.8,7.2L9,10H7L5.87,7.33H4V10H2V2h5c1.13,0,2,0.87,2,2v1.33C9,6.13,8.47,6.87,7.8,7.2z M7,4H4v1.33h3V4z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M0,0h24v24H0V0z" />
-</vector>
\ No newline at end of file
+        android:viewportWidth="17"
+        android:viewportHeight="17">
+
+<path
+    android:fillColor="#FFFFFFFF"
+    android:pathData="M2.93,4.81H1.81V7.4H1V1h1.79c0.63,0,1.1,0.16,1.42,0.49S4.7,2.29,4.7,2.92c0,0.4-0.09,0.74-0.26,1.04 C4.26,4.25,4.02,4.48,3.7,4.63l1.24,2.72V7.4H4.07L2.93,4.81z M1.81,4.12h0.98c0.34,0,0.61-0.11,0.81-0.33 c0.2-0.22,0.3-0.51,0.3-0.87c0-0.82-0.37-1.23-1.12-1.23H1.81V4.12z" />
+<path
+    android:pathData="M 0 0 H 17 V 17 H 0 V 0 Z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/car_facet_button.xml b/packages/SystemUI/res/layout/car_facet_button.xml
index f432d36..ad86049 100644
--- a/packages/SystemUI/res/layout/car_facet_button.xml
+++ b/packages/SystemUI/res/layout/car_facet_button.xml
@@ -42,6 +42,7 @@
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
             android:animateLayoutChanges="true"
+            android:src="@drawable/car_ic_arrow"
             android:background="@android:color/transparent"
             android:scaleType="fitCenter">
         </com.android.keyguard.AlphaOptimizedImageButton>
diff --git a/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
new file mode 100644
index 0000000..a65ff16
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_left_navigation_bar_unprovisioned.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="vertical"
+    android:background="@drawable/system_bar_background">
+
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:id="@+id/nav_buttons"
+        android:orientation="vertical"
+        android:gravity="top"
+        android:paddingTop="30dp"
+        android:layout_weight="1"
+        android:background="@drawable/system_bar_background"
+        android:animateLayoutChanges="true">
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/home"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+            android:src="@drawable/car_ic_overview"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/hvac"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
+            systemui:broadcast="true"
+            android:src="@drawable/car_ic_hvac"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+    </LinearLayout>
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
new file mode 100644
index 0000000..b0488ae
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_navigation_bar_unprovisioned.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:background="@drawable/system_bar_background">
+
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        android:orientation="horizontal"
+        android:id="@+id/nav_buttons"
+        android:gravity="left"
+        android:paddingLeft="30dp"
+        android:layout_weight="1"
+        android:animateLayoutChanges="true">
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/home"
+            android:layout_height="match_parent"
+            android:layout_width="wrap_content"
+            systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+            android:src="@drawable/car_ic_overview"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingLeft="30dp"
+            android:paddingRight="30dp"
+        />
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/hvac"
+            android:layout_height="match_parent"
+            android:layout_width="wrap_content"
+            systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
+            systemui:broadcast="true"
+            android:src="@drawable/car_ic_hvac"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingLeft="30dp"
+            android:paddingRight="30dp"
+        />
+    </LinearLayout>
+</com.android.systemui.statusbar.car.CarNavigationBarView>
+
diff --git a/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml b/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
new file mode 100644
index 0000000..a65ff16
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_right_navigation_bar_unprovisioned.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:orientation="vertical"
+    android:background="@drawable/system_bar_background">
+
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:id="@+id/nav_buttons"
+        android:orientation="vertical"
+        android:gravity="top"
+        android:paddingTop="30dp"
+        android:layout_weight="1"
+        android:background="@drawable/system_bar_background"
+        android:animateLayoutChanges="true">
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/home"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;end"
+            android:src="@drawable/car_ic_overview"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+
+        <com.android.systemui.statusbar.car.CarNavigationButton
+            android:id="@+id/hvac"
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end"
+            systemui:broadcast="true"
+            android:src="@drawable/car_ic_hvac"
+            android:background="?android:attr/selectableItemBackground"
+            android:paddingTop="30dp"
+            android:paddingBottom="30dp"
+        />
+    </LinearLayout>
+</com.android.systemui.statusbar.car.CarNavigationBarView>
diff --git a/packages/SystemUI/res/layout/car_status_bar_header.xml b/packages/SystemUI/res/layout/car_status_bar_header.xml
index 158907e..f2ef301 100644
--- a/packages/SystemUI/res/layout/car_status_bar_header.xml
+++ b/packages/SystemUI/res/layout/car_status_bar_header.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<!-- Extends RelativeLayout -->
+<!-- Extends LinearLayout -->
 <com.android.systemui.qs.car.CarStatusBarHeader
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
@@ -23,22 +23,21 @@
     android:paddingStart="8dp"
     android:paddingEnd="8dp" >
 
-    <include
-        layout="@layout/system_icons"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_alignParentStart="true"
-        android:layout_centerVertical="true" />
+    <include layout="@layout/system_icons"
+             android:layout_width="wrap_content"
+             android:layout_height="match_parent"
+             android:gravity="center_vertical|end"
+             android:layout_weight="1"
+    />
 
     <com.android.systemui.statusbar.policy.Clock
         android:id="@+id/clock"
         android:textAppearance="@style/TextAppearance.StatusBar.Clock"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
-        android:layout_alignParentEnd="true"
-        android:layout_centerVertical="true"
         android:singleLine="true"
         android:paddingStart="@dimen/status_bar_clock_starting_padding"
         android:paddingEnd="@dimen/status_bar_clock_end_padding"
-        systemui:showDark="false" />
+        android:gravity="center_vertical|end"
+    />
 </com.android.systemui.qs.car.CarStatusBarHeader>
diff --git a/packages/SystemUI/res/layout/car_top_navigation_bar.xml b/packages/SystemUI/res/layout/car_top_navigation_bar.xml
new file mode 100644
index 0000000..e16014b
--- /dev/null
+++ b/packages/SystemUI/res/layout/car_top_navigation_bar.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+** Copyright 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.
+*/
+-->
+
+<com.android.systemui.statusbar.car.CarNavigationBarView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent"
+    android:background="@drawable/system_bar_background">
+
+    <com.android.systemui.statusbar.policy.Clock
+        android:id="@+id/clock"
+        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:singleLine="true"
+        android:paddingStart="@dimen/status_bar_clock_starting_padding"
+        android:paddingEnd="@dimen/status_bar_clock_end_padding"
+        android:gravity="center_vertical"
+    />
+
+</com.android.systemui.statusbar.car.CarNavigationBarView>
+
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index cc6e3bf..5ecd380 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -50,7 +50,8 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:layout_gravity="center_vertical"
-        android:paddingEnd="1dp"
+        android:paddingStart="1dp"
+        android:paddingEnd="2dp"
         android:visibility="gone" />
     <Space
         android:id="@+id/mobile_roaming_space"
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 03e8451..54baa4a 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -54,15 +54,14 @@
             android:layout_marginStart="@dimen/qs_header_alarm_text_margin_start"
             android:textAppearance="@style/TextAppearance.QS.TileLabel" />
 
-        <ImageView
+        <View
             android:id="@+id/status_separator"
-            android:layout_width="2dp"
-            android:layout_height="2dp"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_gravity="center_vertical"
-            android:src="@drawable/qs_header_status_dot"
-            android:tint="?android:attr/textColorPrimary" />
+            android:layout_width="1dp"
+            android:layout_height="match_parent"
+            android:layout_marginStart="10dp"
+            android:layout_marginEnd="10dp"
+            android:background="@android:color/white"
+            android:backgroundTint="?android:attr/textColorPrimary" />
 
         <ImageView
             android:id="@+id/ringer_mode_icon"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 2e7ab7f..f15ca9e 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -55,19 +55,6 @@
         android:paddingStart="8dp"
         />
 
-    <!-- TODO: remove -->
-    <ImageButton
-        android:id="@+id/helper"
-        android:layout_width="48dp"
-        android:layout_height="@*android:dimen/notification_header_height"
-        android:layout_gravity="top|end"
-        android:layout_marginEnd="6dp"
-        android:src="@drawable/ic_dnd"
-        android:tint="#FF0000"
-        android:background="@drawable/ripple_drawable"
-        android:visibility="visible"
-    />
-
     <ViewStub
         android:layout="@layout/notification_children_container"
         android:id="@+id/child_container_stub"
diff --git a/packages/SystemUI/res/values/attrs_car.xml b/packages/SystemUI/res/values/attrs_car.xml
index b1097c3..5e4bd79 100644
--- a/packages/SystemUI/res/values/attrs_car.xml
+++ b/packages/SystemUI/res/values/attrs_car.xml
@@ -27,6 +27,13 @@
         <attr name="categories" format="string"/>
         <!-- package names that will be added as extras to the fired intents -->
         <attr name="packages" format="string" />
+        <!-- Alpha value to used when in selected state.  Defaults 1f  -->
+        <attr name="selectedAlpha" format="float" />
+        <!-- Alpha value to used when in un-selected state.  Defaults 0.7f  -->
+        <attr name="unselectedAlpha" format="float" />
+        <!-- Render a "more" icon. Defaults true  -->
+        <attr name="useMoreIcon" format="boolean" />
+
     </declare-styleable>
 
 
@@ -39,4 +46,11 @@
         <!-- start the intent as a broad cast instead of an activity if true-->
         <attr name="broadcast" format="boolean"/>
     </declare-styleable>
+
+    <!-- Custom attributes to configure hvac values -->
+    <declare-styleable name="TemperatureView">
+        <attr name="hvacAreaId" format="integer"/>
+        <attr name="hvacPropertyId" format="integer"/>
+        <attr name="hvacTempFormat" format="string"/>
+    </declare-styleable>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 816c598..8cff56d 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -228,9 +228,14 @@
         mHandler.removeCallbacks(mConnectionRunnable);
         Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
-        boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
-                mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
-                UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+        boolean bound = false;
+        try {
+            bound = mContext.bindServiceAsUser(launcherServiceIntent,
+                    mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
+                    UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+        } catch (SecurityException e) {
+            Log.e(TAG_OPS, "Unable to bind because of security error", e);
+        }
         if (!bound) {
             // Retry after exponential backoff timeout
             final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
diff --git a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
index 245d240..9459ce1 100644
--- a/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/car/CarSystemUIFactory.java
@@ -21,6 +21,8 @@
 import com.android.systemui.Dependency.DependencyProvider;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.NotificationEntryManager;
+import com.android.systemui.statusbar.car.CarFacetButtonController;
+import com.android.systemui.statusbar.car.hvac.HvacController;
 
 /**
  * Class factory to provide car specific SystemUI components.
@@ -32,5 +34,7 @@
         super.injectDependencies(providers, context);
         providers.put(NotificationEntryManager.class,
                 () -> new CarNotificationEntryManager(context));
+        providers.put(CarFacetButtonController.class, () -> new CarFacetButtonController(context));
+        providers.put(HvacController.class, () -> new HvacController(context));
     }
 }
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 3ba3d0e..5c0576d 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -284,14 +284,19 @@
                 // Defer the update of the current movement bounds until after the user finishes
                 // touching the screen
             } else {
-                final Rect toMovementBounds = mMenuState == MENU_STATE_FULL
-                        ? expandedMovementBounds
-                        : normalMovementBounds;
-                animateToOffset(animatingBounds, toMovementBounds,
-                        fromImeAdjustment,
-                        fromImeAdjustment ? mIsImeShowing : mIsShelfShowing,
-                        // Shelf height serves as an offset, but does not change movement bounds.
-                        fromImeAdjustment ? mImeOffset : mShelfHeight);
+                final int adjustedOffset = Math.max(mIsImeShowing ? mImeHeight + mImeOffset : 0,
+                        mIsShelfShowing ? mShelfHeight : 0);
+                Rect normalAdjustedBounds = new Rect();
+                mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalAdjustedBounds,
+                        adjustedOffset);
+                Rect expandedAdjustedBounds = new Rect();
+                mSnapAlgorithm.getMovementBounds(mExpandedBounds, insetBounds,
+                        expandedAdjustedBounds, adjustedOffset);
+                final Rect toAdjustedBounds = mMenuState == MENU_STATE_FULL
+                        ? expandedAdjustedBounds
+                        : normalAdjustedBounds;
+
+                animateToOffset(animatingBounds, toAdjustedBounds);
             }
         }
 
@@ -313,23 +318,13 @@
         }
     }
 
-    private void animateToOffset(Rect animatingBounds, Rect toMovementBounds,
-            boolean fromImeAdjustment, boolean showing, int offset) {
+    private void animateToOffset(Rect animatingBounds, Rect toAdjustedBounds) {
         final Rect bounds = new Rect(animatingBounds);
-        if (showing) {
-            // IME/shelf visible, apply the IME/shelf offset if the space allows for it
-            final int calculatedOffset = toMovementBounds.bottom - Math.max(toMovementBounds.top,
-                    toMovementBounds.bottom - offset);
-            bounds.offset(0,
-                    Math.min(0, toMovementBounds.bottom - calculatedOffset - bounds.top));
-        } else {
-            // IME/shelf hidden
-            if (bounds.top >= (mMovementBounds.bottom - offset)) {
-                bounds.offset(0, toMovementBounds.bottom - bounds.top -
-                        // Counter going back home from search where keyboard is up.
-                        (fromImeAdjustment ? mShelfHeight : 0));
-            }
+        if (toAdjustedBounds.bottom < mMovementBounds.bottom
+                && bounds.top < toAdjustedBounds.bottom) {
+            return;
         }
+        bounds.offset(0, toAdjustedBounds.bottom - bounds.top);
         mMotionHelper.animateToOffset(bounds);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
index 6797bb9..ec18376 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarStatusBarHeader.java
@@ -19,7 +19,7 @@
 import android.support.annotation.IdRes;
 import android.util.AttributeSet;
 import android.view.View;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.BatteryMeterView;
@@ -30,7 +30,7 @@
  * A view that forms the header of the notification panel. This view will ensure that any
  * status icons that are displayed are tinted accordingly to the current theme.
  */
-public class CarStatusBarHeader extends RelativeLayout {
+public class CarStatusBarHeader extends LinearLayout {
     public CarStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 05a5a8e..03b263d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -183,7 +183,6 @@
     private AboveShelfChangedListener mAboveShelfChangedListener;
     private HeadsUpManager mHeadsUpManager;
     private Consumer<Boolean> mHeadsUpAnimatingAwayListener;
-    private View mHelperButton;
     private boolean mChildIsExpanding;
 
     private boolean mJustClicked;
@@ -401,8 +400,6 @@
         updateLimits();
         updateIconVisibilities();
         updateShelfIconColor();
-
-        showBlockingHelperButton(mEntry.userSentiment == USER_SENTIMENT_NEGATIVE);
         updateRippleAllowed();
     }
 
@@ -1426,10 +1423,6 @@
         requestLayout();
     }
 
-    public void showBlockingHelperButton(boolean show) {
-        mHelperButton.setVisibility(show ? View.VISIBLE : View.GONE);
-    }
-
     public void showAppOpsIcons(ArraySet<Integer> activeOps) {
         if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) {
             mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps);
@@ -1459,11 +1452,6 @@
         mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
         mLayouts = new NotificationContentView[] {mPrivateLayout, mPublicLayout};
 
-        mHelperButton = findViewById(R.id.helper);
-        mHelperButton.setOnClickListener(view -> {
-            doLongClickCallback();
-        });
-
         for (NotificationContentView l : mLayouts) {
             l.setExpandClickListener(mExpandClickListener);
             l.setContainingNotification(this);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 775faee..4b6ab64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -18,25 +18,21 @@
 
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
-import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
 
+import android.Manifest;
 import android.app.AppGlobals;
-import android.app.AppOpsManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.Context;
 import android.graphics.drawable.Icon;
-import android.os.AsyncTask;
-import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.SystemClock;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.SnoozeCriterion;
@@ -46,10 +42,8 @@
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
-import android.Manifest;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.Dependency;
@@ -454,47 +448,44 @@
         return Ranking.VISIBILITY_NO_OVERRIDE;
     }
 
-    public boolean shouldSuppressFullScreenIntent(String key) {
+    public boolean shouldSuppressFullScreenIntent(StatusBarNotification sbn) {
+        return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_FULL_SCREEN_INTENT);
+    }
+
+    public boolean shouldSuppressPeek(StatusBarNotification sbn) {
+        return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_PEEK);
+    }
+
+    public boolean shouldSuppressStatusBar(StatusBarNotification sbn) {
+        return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_STATUS_BAR);
+    }
+
+    public boolean shouldSuppressAmbient(StatusBarNotification sbn) {
+        return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_AMBIENT);
+    }
+
+    public boolean shouldSuppressNotificationList(StatusBarNotification sbn) {
+        return shouldSuppressVisualEffect(sbn, SUPPRESSED_EFFECT_NOTIFICATION_LIST);
+    }
+
+    private boolean shouldSuppressVisualEffect(StatusBarNotification sbn, int effect) {
+        if (isExemptFromDndVisualSuppression(sbn)) {
+            return false;
+        }
+        String key = sbn.getKey();
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
-            return (mTmpRanking.getSuppressedVisualEffects()
-                    & SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0;
+            return (mTmpRanking.getSuppressedVisualEffects() & effect) != 0;
         }
         return false;
     }
 
-    public boolean shouldSuppressPeek(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return (mTmpRanking.getSuppressedVisualEffects()
-                    & SUPPRESSED_EFFECT_PEEK) != 0;
+    protected boolean isExemptFromDndVisualSuppression(StatusBarNotification sbn) {
+        if ((sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+            return true;
         }
-        return false;
-    }
-
-    public boolean shouldSuppressStatusBar(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return (mTmpRanking.getSuppressedVisualEffects()
-                    & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
-        }
-        return false;
-    }
-
-    public boolean shouldSuppressAmbient(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return (mTmpRanking.getSuppressedVisualEffects()
-                    & SUPPRESSED_EFFECT_AMBIENT) != 0;
-        }
-        return false;
-    }
-
-    public boolean shouldSuppressNotificationList(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return (mTmpRanking.getSuppressedVisualEffects()
-                    & SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
+        if (sbn.getNotification().isMediaNotification()) {
+            return true;
         }
         return false;
     }
@@ -620,11 +611,11 @@
             return true;
         }
 
-        if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn.getKey())) {
+        if (mEnvironment.isDozing() && shouldSuppressAmbient(sbn)) {
             return true;
         }
 
-        if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn.getKey())) {
+        if (!mEnvironment.isDozing() && shouldSuppressNotificationList(sbn)) {
             return true;
         }
 
@@ -641,9 +632,14 @@
             // this is a foreground-service disclosure for a user that does not need to show one
             return true;
         }
-        if (mFsc.isSystemAlertNotification(sbn) && !mFsc.isSystemAlertWarningNeeded(
-                sbn.getUserId(), sbn.getPackageName())) {
-            return true;
+        if (mFsc.isSystemAlertNotification(sbn)) {
+            final String[] apps = sbn.getNotification().extras.getStringArray(
+                    Notification.EXTRA_FOREGROUND_APPS);
+            if (apps != null && apps.length >= 1) {
+                if (!mFsc.isSystemAlertWarningNeeded(sbn.getUserId(), apps[0])) {
+                    return true;
+                }
+            }
         }
 
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 7a7cc99..45df450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -299,12 +299,12 @@
         updateNotifications();
     }
 
-    private boolean shouldSuppressFullScreenIntent(String key) {
+    private boolean shouldSuppressFullScreenIntent(StatusBarNotification sbn) {
         if (mPresenter.isDeviceInVrMode()) {
             return true;
         }
 
-        return mNotificationData.shouldSuppressFullScreenIntent(key);
+        return mNotificationData.shouldSuppressFullScreenIntent(sbn);
     }
 
     private void inflateViews(NotificationData.Entry entry, ViewGroup parent) {
@@ -690,7 +690,7 @@
         NotificationData.Entry shadeEntry = createNotificationViews(notification);
         boolean isHeadsUped = shouldPeek(shadeEntry);
         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
-            if (shouldSuppressFullScreenIntent(key)) {
+            if (shouldSuppressFullScreenIntent(notification)) {
                 if (DEBUG) {
                     Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + key);
                 }
@@ -846,13 +846,13 @@
             return false;
         }
 
-        if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn.getKey())) {
+        if (!mPresenter.isDozing() && mNotificationData.shouldSuppressPeek(sbn)) {
             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
             return false;
         }
 
         // Peeking triggers an ambient display pulse, so disable peek is ambient is active
-        if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn.getKey())) {
+        if (mPresenter.isDozing() && mNotificationData.shouldSuppressAmbient(sbn)) {
             if (DEBUG) Log.d(TAG, "No peeking: suppressed by DND: " + sbn.getKey());
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index a2f336e..82ad74e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -165,6 +165,7 @@
         mIsForeground =
                 (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
         mIsForBlockingHelper = isForBlockingHelper;
+        mAppUid = mSbn.getUid();
 
         int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
                 pkg, mAppUid, false /* includeDeleted */);
@@ -173,9 +174,9 @@
         } else  {
             // Special behavior for the Default channel if no other channels have been defined.
             mIsSingleDefaultChannel = mNumNotificationChannels == 1
-                    && mSingleNotificationChannel.getId()
-                    .equals(NotificationChannel.DEFAULT_CHANNEL_ID)
-                    && numTotalChannels <= 1;
+                    && mSingleNotificationChannel.getId().equals(
+                            NotificationChannel.DEFAULT_CHANNEL_ID)
+                    && numTotalChannels == 1;
         }
 
         try {
@@ -210,7 +211,6 @@
                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                             | PackageManager.MATCH_DIRECT_BOOT_AWARE);
             if (info != null) {
-                mAppUid = mSbn.getUid();
                 mAppName = String.valueOf(mPm.getApplicationLabel(info));
                 pkgicon = mPm.getApplicationIcon(info);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index b1e08b8..fd3a9d5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -350,9 +350,6 @@
                 }
             }
 
-            row.showBlockingHelperButton(entry.userSentiment ==
-                    NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
-
             row.showAppOpsIcons(entry.mActiveAppOps);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 53101a5..5f3e2e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -3,6 +3,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -10,6 +11,7 @@
 import android.widget.LinearLayout;
 
 import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
 /**
@@ -21,9 +23,6 @@
  * other music apps installed.
  */
 public class CarFacetButton extends LinearLayout {
-    private static final float SELECTED_ALPHA = 1f;
-    private static final float UNSELECTED_ALPHA = 0.7f;
-
     private static final String FACET_FILTER_DELIMITER = ";";
     /**
      * Extra information to be sent to a helper to make the decision of what app to launch when
@@ -42,6 +41,10 @@
     private String[] mFacetCategories;
     /** App packages that are allowed to be used with this widget */
     private String[] mFacetPackages;
+    private int mIconResourceId;
+    private boolean mUseMoreIcon = true;
+    private float mSelectedAlpha = 1f;
+    private float mUnselectedAlpha = 1f;
 
 
     public CarFacetButton(Context context, AttributeSet attrs) {
@@ -53,6 +56,10 @@
         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
         setupIntents(typedArray);
         setupIcons(typedArray);
+        CarFacetButtonController carFacetButtonController = Dependency.get(
+                CarFacetButtonController.class);
+        carFacetButtonController.addFacetButton(this);
+
     }
 
     /**
@@ -96,21 +103,25 @@
 
 
     private void setupIcons(TypedArray styledAttributes) {
+        mSelectedAlpha = styledAttributes.getFloat(
+                R.styleable.CarFacetButton_selectedAlpha, mSelectedAlpha);
+        mUnselectedAlpha = styledAttributes.getFloat(
+                R.styleable.CarFacetButton_unselectedAlpha, mUnselectedAlpha);
         mIcon = findViewById(R.id.car_nav_button_icon);
         mIcon.setScaleType(ImageView.ScaleType.CENTER);
         mIcon.setClickable(false);
-        mIcon.setAlpha(UNSELECTED_ALPHA);
-        int iconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
-        if (iconResourceId == 0)  {
+        mIcon.setAlpha(mUnselectedAlpha);
+        mIconResourceId = styledAttributes.getResourceId(R.styleable.CarFacetButton_icon, 0);
+        if (mIconResourceId == 0)  {
             throw new RuntimeException("specified icon resource was not found and is required");
         }
-        mIcon.setImageResource(iconResourceId);
+        mIcon.setImageResource(mIconResourceId);
 
         mMoreIcon = findViewById(R.id.car_nav_button_more_icon);
         mMoreIcon.setClickable(false);
-        mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
-        mMoreIcon.setAlpha(UNSELECTED_ALPHA);
+        mMoreIcon.setAlpha(mSelectedAlpha);
         mMoreIcon.setVisibility(GONE);
+        mUseMoreIcon = styledAttributes.getBoolean(R.styleable.CarFacetButton_useMoreIcon, true);
     }
 
     /**
@@ -145,17 +156,27 @@
     /**
      * Updates the visual state to let the user know if it's been selected.
      * @param selected true if should update the alpha of the icon to selected, false otherwise
-     * @param showMoreIcon true if the "more icon" should be shown, false otherwise
+     * @param showMoreIcon true if the "more icon" should be shown, false otherwise. Note this
+     *                     is ignored if the attribute useMoreIcon is set to false
      */
     public void setSelected(boolean selected, boolean showMoreIcon) {
         mSelected = selected;
         if (selected) {
-            mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
-            mMoreIcon.setAlpha(SELECTED_ALPHA);
-            mIcon.setAlpha(SELECTED_ALPHA);
+            if (mUseMoreIcon) {
+                mMoreIcon.setVisibility(showMoreIcon ? VISIBLE : GONE);
+            }
+            mIcon.setAlpha(mSelectedAlpha);
         } else {
             mMoreIcon.setVisibility(GONE);
-            mIcon.setAlpha(UNSELECTED_ALPHA);
+            mIcon.setAlpha(mUnselectedAlpha);
+        }
+    }
+
+    public void setIcon(Drawable d) {
+        if (d != null) {
+            mIcon.setImageDrawable(d);
+        } else {
+            mIcon.setImageResource(mIconResourceId);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
index e8c9a5e..2841136 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarFacetButtonController.java
@@ -5,8 +5,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.view.View;
-import android.view.ViewGroup;
 
 import java.util.HashMap;
 import java.util.List;
@@ -29,39 +27,25 @@
     }
 
     /**
-     * Goes through the supplied CarNavigationBarView and keeps track of all the CarFacetButtons
-     * such that it can select and unselect them based on running task chages
-     * @param bar that may contain CarFacetButtons
+     * Add facet button to this controller. The expected use is for the facet button
+     * to get a reference to this controller via {@link com.android.systemui.Dependency}
+     * and self add.
+     * @param facetButton
      */
-    public void addCarNavigationBar(CarNavigationBarView bar) {
-        findFacets(bar);
-    }
+    public void addFacetButton(CarFacetButton facetButton) {
+        String[] categories = facetButton.getCategories();
+        for (int j = 0; j < categories.length; j++) {
+            String category = categories[j];
+            mButtonsByCategory.put(category, facetButton);
+        }
 
-    private void findFacets(ViewGroup root) {
-        final int childCount = root.getChildCount();
-
-        for (int i = 0; i < childCount; ++i) {
-            final View v = root.getChildAt(i);
-            if (v instanceof CarFacetButton) {
-                CarFacetButton facetButton = (CarFacetButton) v;
-                String[] categories = facetButton.getCategories();
-                for (int j = 0; j < categories.length; j++) {
-                    String category = categories[j];
-                    mButtonsByCategory.put(category, facetButton);
-                }
-
-                String[] facetPackages = facetButton.getFacetPackages();
-                for (int j = 0; j < facetPackages.length; j++) {
-                    String facetPackage = facetPackages[j];
-                    mButtonsByPackage.put(facetPackage, facetButton);
-                }
-            } else if (v instanceof ViewGroup) {
-                findFacets((ViewGroup) v);
-            }
+        String[] facetPackages = facetButton.getFacetPackages();
+        for (int j = 0; j < facetPackages.length; j++) {
+            String facetPackage = facetPackages[j];
+            mButtonsByPackage.put(facetPackage, facetButton);
         }
     }
 
-
     /**
      * This will unselect the currently selected CarFacetButton and determine which one should be
      * selected next. It does this by reading the properties on the CarFacetButton and seeing if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
index 1d9ef61..e73b173 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.view.View;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import com.android.keyguard.AlphaOptimizedImageButton;
 import com.android.systemui.R;
@@ -36,9 +37,11 @@
     private LinearLayout mNavButtons;
     private AlphaOptimizedImageButton mNotificationsButton;
     private CarStatusBar mCarStatusBar;
+    private Context mContext;
 
     public CarNavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mContext = context;
     }
 
     @Override
@@ -46,7 +49,9 @@
         mNavButtons = findViewById(R.id.nav_buttons);
 
         mNotificationsButton = findViewById(R.id.notifications);
-        mNotificationsButton.setOnClickListener(this::onNotificationsClick);
+        if (mNotificationsButton != null) {
+            mNotificationsButton.setOnClickListener(this::onNotificationsClick);
+        }
     }
 
     void setStatusBar(CarStatusBar carStatusBar) {
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 c15a013..a95d0a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -17,13 +17,9 @@
 package com.android.systemui.statusbar.car;
 
 import android.app.ActivityManager;
-import android.app.ActivityOptions;
-import android.content.Intent;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
+import android.os.SystemProperties;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.View;
@@ -45,8 +41,8 @@
 import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.car.hvac.HvacController;
 import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
-import com.android.systemui.statusbar.phone.NavigationBarView;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -60,6 +56,8 @@
 public class CarStatusBar extends StatusBar implements
         CarBatteryController.BatteryViewHandler {
     private static final String TAG = "CarStatusBar";
+    public static final boolean ENABLE_HVAC_CONNECTION
+            = !SystemProperties.getBoolean("android.car.hvac.demo", true);
 
     private TaskStackListenerImpl mTaskStackListener;
 
@@ -93,6 +91,11 @@
 
         createBatteryController();
         mCarBatteryController.startListening();
+
+        if (ENABLE_HVAC_CONNECTION) {
+            Log.d(TAG, "Connecting to HVAC service");
+            Dependency.get(HvacController.class).connectToCarService();
+        }
     }
 
     @Override
@@ -164,7 +167,7 @@
 
     @Override
     protected void createNavigationBar() {
-        mCarFacetButtonController = new CarFacetButtonController(mContext);
+        mCarFacetButtonController = Dependency.get(CarFacetButtonController.class);
         if (mNavigationBarView != null) {
             return;
         }
@@ -225,7 +228,6 @@
         lp.windowAnimations = 0;
 
 
-        mCarFacetButtonController.addCarNavigationBar(mNavigationBarView);
         mWindowManager.addView(mNavigationBarWindow, lp);
     }
 
@@ -243,7 +245,6 @@
             throw new RuntimeException("Unable to build left nav bar due to missing layout");
         }
         mLeftNavigationBarView.setStatusBar(this);
-        mCarFacetButtonController.addCarNavigationBar(mLeftNavigationBarView);
 
         WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
                 widthForSides, LayoutParams.MATCH_PARENT,
@@ -275,7 +276,6 @@
             throw new RuntimeException("Unable to build right nav bar due to missing layout");
         }
         mRightNavigationBarView.setStatusBar(this);
-        mCarFacetButtonController.addCarNavigationBar(mRightNavigationBarView);
 
         WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
                 widthForSides, LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
new file mode 100644
index 0000000..23bf887
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/HvacController.java
@@ -0,0 +1,205 @@
+/*
+ * 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 com.android.systemui.statusbar.car.hvac;
+
+import android.car.Car;
+import android.car.CarNotConnectedException;
+import android.car.hardware.CarPropertyValue;
+import android.car.hardware.hvac.CarHvacManager;
+import android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Manages the connection to the Car service and delegates value changes to the registered
+ * {@link TemperatureView}s
+ */
+public class HvacController {
+
+    public static final String TAG = "HvacController";
+    public final static int BIND_TO_HVAC_RETRY_DELAY = 5000;
+
+    private Context mContext;
+    private Handler mHandler;
+    private Car mCar;
+    private CarHvacManager mHvacManager;
+    private HashMap<HvacKey, TemperatureView> mTempComponents = new HashMap<>();
+
+    public HvacController(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Create connection to the Car service. Note: call backs from the Car service
+     * ({@link CarHvacManager}) will happen on the same thread this method was called from.
+     */
+    public void connectToCarService() {
+        mHandler = new Handler();
+        mCar = Car.createCar(mContext, mServiceConnection, mHandler);
+        if (mCar != null) {
+            // note: this connect call handles the retries
+            mCar.connect();
+        }
+    }
+
+    /**
+     * Registers callbacks and initializes components upon connection.
+     */
+    private ServiceConnection mServiceConnection = new ServiceConnection() {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            try {
+                service.linkToDeath(mRestart, 0);
+                mHvacManager = (CarHvacManager) mCar.getCarManager(Car.HVAC_SERVICE);
+                mHvacManager.registerCallback(mHardwareCallback);
+                initComponents();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to correctly connect to HVAC", e);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            destroyHvacManager();
+        }
+    };
+
+    private void destroyHvacManager() {
+        if (mHvacManager != null) {
+            mHvacManager.unregisterCallback(mHardwareCallback);
+            mHvacManager = null;
+        }
+    }
+
+    /**
+     * If the connection to car service goes away then restart it.
+     */
+    private final IBinder.DeathRecipient mRestart = new IBinder.DeathRecipient() {
+        @Override
+        public void binderDied() {
+            Log.d(TAG, "Death of HVAC triggering a restart");
+            if (mCar != null) {
+                mCar.disconnect();
+            }
+            destroyHvacManager();
+            mHandler.postDelayed(() -> mCar.connect(), BIND_TO_HVAC_RETRY_DELAY);
+        }
+    };
+
+    /**
+     * Add component to list and initialize it if the connection is up.
+     * @param temperatureView
+     */
+    public void addHvacTextView(TemperatureView temperatureView) {
+        mTempComponents.put(
+                new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId()),
+                temperatureView);
+        initComponent(temperatureView);
+    }
+
+    private void initComponents() {
+        Iterator<Map.Entry<HvacKey, TemperatureView>> iterator =
+                mTempComponents.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<HvacKey, TemperatureView> next = iterator.next();
+            initComponent(next.getValue());
+        }
+    }
+
+
+    private void initComponent(TemperatureView view) {
+        int id = view.getPropertyId();
+        int zone = view.getAreaId();
+        try {
+            if (mHvacManager == null || !mHvacManager.isPropertyAvailable(id, zone)) {
+                view.setTemp(Float.NaN);
+                return;
+            }
+            view.setTemp(mHvacManager.getFloatProperty(id, zone));
+        } catch (CarNotConnectedException e) {
+            view.setTemp(Float.NaN);
+            Log.e(TAG, "Failed to get value from hvac service", e);
+        }
+    }
+
+    /**
+     * Callback for getting changes from {@link CarHvacManager} and setting the UI elements to
+     * match.
+     */
+    private final CarHvacEventCallback mHardwareCallback = new CarHvacEventCallback() {
+        @Override
+        public void onChangeEvent(final CarPropertyValue val) {
+            try {
+                int areaId = val.getAreaId();
+                int propertyId = val.getPropertyId();
+                TemperatureView temperatureView = mTempComponents.get(
+                        new HvacKey(propertyId, areaId));
+                if (temperatureView != null) {
+                    float value = (float) val.getValue();
+                    temperatureView.setTemp(value);
+                } // else the data is not of interest
+            } catch (Exception e) {
+                // catch all so we don't take down the sysui if a new data type is
+                // introduced.
+                Log.e(TAG, "Failed handling hvac change event", e);
+            }
+        }
+
+        @Override
+        public void onErrorEvent(final int propertyId, final int zone) {
+            Log.d(TAG, "HVAC error event, propertyId: " + propertyId +
+                    " zone: " + zone);
+        }
+    };
+
+    /**
+     * Key for storing {@link TemperatureView}s in a hash map
+     */
+    private static class HvacKey {
+
+        int mPropertyId;
+        int mAreaId;
+
+        public HvacKey(int propertyId, int areaId) {
+            mPropertyId = propertyId;
+            mAreaId = areaId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            HvacKey hvacKey = (HvacKey) o;
+            return mPropertyId == hvacKey.mPropertyId &&
+                    mAreaId == hvacKey.mAreaId;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mPropertyId, mAreaId);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
new file mode 100644
index 0000000..4049ec3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/hvac/TemperatureView.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.android.systemui.statusbar.car.hvac;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.R;
+
+/**
+ * Simple text display of HVAC properties, It is designed to show temperature and is configured in
+ * the XML.
+ * XML properties:
+ * hvacPropertyId - Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
+ * hvacAreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+ * hvacTempFormat - Example: "%.1f\u00B0" (1 decimal and the degree symbol)
+ *
+ * Note: It registers itself with {@link HvacController}
+ */
+public class TemperatureView extends TextView {
+
+    private final int mAreaId;
+    private final int mPropertyId;
+    private final String mTempFormat;
+
+    public TemperatureView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TemperatureView);
+        mAreaId = typedArray.getInt(R.styleable.TemperatureView_hvacAreaId,-1);
+        mPropertyId = typedArray.getInt(R.styleable.TemperatureView_hvacPropertyId, -1);
+        String format = typedArray.getString(R.styleable.TemperatureView_hvacTempFormat);
+        mTempFormat = (format == null) ? "%.1f\u00B0" : format;
+
+        // register with controller
+        HvacController hvacController = Dependency.get(HvacController.class);
+        hvacController.addHvacTextView(this);
+    }
+
+    /**
+     * Formats the float for display
+     * @param temp - The current temp or NaN
+     */
+    public void setTemp(float temp) {
+        if (Float.isNaN(temp)) {
+            setText("--");
+            return;
+        }
+        setText(String.format(mTempFormat, temp));
+    }
+
+    /**
+     * @return propertiyId  Example: CarHvacManager.ID_ZONED_TEMP_SETPOINT (16385)
+     */
+    public int getPropertyId() {
+        return mPropertyId;
+    }
+
+    /**
+     * @return hvac AreaId - Example: VehicleSeat.SEAT_ROW_1_LEFT (1)
+     */
+    public int getAreaId() {
+        return mAreaId;
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index fcd4e8f..df2b817 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -334,6 +334,20 @@
         return mKeyguardView != null && mKeyguardView.hasDismissActions();
     }
 
+    public int getTop() {
+        if (mKeyguardView == null) {
+            return 0;
+        }
+
+        int top = mKeyguardView.getTop();
+        // The password view has an extra top padding that should be ignored.
+        if (mKeyguardView.getCurrentSecurityMode() == SecurityMode.Password) {
+            View messageArea = mKeyguardView.findViewById(R.id.keyguard_message_area);
+            top += messageArea.getTop();
+        }
+        return top;
+    }
+
     protected void ensureView() {
         // Removal of the view might be deferred to reduce unlock latency,
         // in this case we need to force the removal, otherwise we'll
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 19e8295..3d7067d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -114,6 +114,11 @@
     private boolean mTracking;
 
     /**
+     * Distance in pixels between the top of the screen and the first view of the bouncer.
+     */
+    private int mBouncerTop;
+
+    /**
      * Refreshes the dimension values.
      */
     public void loadDimens(Resources res) {
@@ -129,7 +134,7 @@
 
     public void setup(int minTopMargin, int maxShadeBottom, int notificationStackHeight,
             float expandedHeight, float maxPanelHeight, int parentHeight, int keyguardStatusHeight,
-            float dark, boolean secure, boolean tracking) {
+            float dark, boolean secure, boolean tracking, int bouncerTop) {
         mMinTopMargin = minTopMargin + mContainerTopPadding;
         mMaxShadeBottom = maxShadeBottom;
         mNotificationStackHeight = notificationStackHeight;
@@ -140,6 +145,7 @@
         mDarkAmount = dark;
         mCurrentlySecure = secure;
         mTracking = tracking;
+        mBouncerTop = bouncerTop;
     }
 
     public void run(Result result) {
@@ -189,8 +195,10 @@
     private int getClockY() {
         // Dark: Align the bottom edge of the clock at about half of the screen:
         final float clockYDark = getMaxClockY() + burnInPreventionOffsetY();
-        float clockYRegular = getExpandedClockPosition();
-        float clockYTarget = mCurrentlySecure ? mMinTopMargin : -mKeyguardStatusHeight;
+        final float clockYRegular = getExpandedClockPosition();
+        final boolean hasEnoughSpace = mMinTopMargin + mKeyguardStatusHeight < mBouncerTop;
+        float clockYTarget = mCurrentlySecure && hasEnoughSpace ?
+                mMinTopMargin : -mKeyguardStatusHeight;
 
         // Move clock up while collapsing the shade
         float shadeExpansion = mExpandedHeight / mMaxPanelHeight;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 9063dea..b6a11f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -150,7 +150,7 @@
 
         // showAmbient == show in shade but not shelf
         if (!showAmbient && mEntryManager.getNotificationData().shouldSuppressStatusBar(
-                entry.key)) {
+                entry.notification)) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index cccda90..27ca0d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -160,6 +160,7 @@
     protected int mQsMinExpansionHeight;
     protected int mQsMaxExpansionHeight;
     private int mQsPeekHeight;
+    private int mBouncerTop;
     private boolean mStackScrollerOverscrolling;
     private boolean mQsExpansionFromOverscroll;
     private float mLastOverscroll;
@@ -476,7 +477,8 @@
                     mKeyguardStatusView.getHeight(),
                     mDarkAmount,
                     mStatusBar.isKeyguardCurrentlySecure(),
-                    mTracking);
+                    mTracking,
+                    mBouncerTop);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockX, mClockPositionResult.clockY);
@@ -550,6 +552,11 @@
         return count;
     }
 
+    public void setBouncerTop(int bouncerTop) {
+        mBouncerTop = bouncerTop;
+        positionClockAndNotifications();
+    }
+
     private void startClockAnimation(int x, int y) {
         if (mClockAnimationTargetX == x && mClockAnimationTargetY == y) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index c326fee..33c3ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -363,16 +363,16 @@
             zenDescription = mContext.getString(R.string.interruption_level_priority);
         }
 
-        if (DndTile.isVisible(mContext) && !DndTile.isCombinedIcon(mContext)
-                && audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
-            volumeVisible = true;
-            volumeIconId = R.drawable.stat_sys_ringer_silent;
-            volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
-        } else if (zen != Global.ZEN_MODE_NO_INTERRUPTIONS && zen != Global.ZEN_MODE_ALARMS &&
+        if (zen != Global.ZEN_MODE_NO_INTERRUPTIONS && zen != Global.ZEN_MODE_ALARMS &&
                 audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_vibrate;
             volumeDescription = mContext.getString(R.string.accessibility_ringer_vibrate);
+        } else if (zen != Global.ZEN_MODE_NO_INTERRUPTIONS && zen != Global.ZEN_MODE_ALARMS &&
+                audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_SILENT) {
+            volumeVisible = true;
+            volumeIconId = R.drawable.stat_sys_ringer_silent;
+            volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
         }
 
         if (zenVisible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c03ecb3..beeba83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -562,7 +562,7 @@
     };
 
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
-    private UserSwitcherController mUserSwitcherController;
+    protected UserSwitcherController mUserSwitcherController;
     private NetworkController mNetworkController;
     private KeyguardMonitorImpl mKeyguardMonitor
             = (KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
@@ -588,7 +588,7 @@
         }
     };
     private boolean mNoAnimationOnNextBarModeChange;
-    private FalsingManager mFalsingManager;
+    protected FalsingManager mFalsingManager;
 
     private final KeyguardUpdateMonitorCallback mUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -3448,6 +3448,13 @@
         return updateIsKeyguard();
     }
 
+    /**
+     * @return True if StatusBar state is FULLSCREEN_USER_SWITCHER.
+     */
+    public boolean isFullScreenUserSwitcherState() {
+        return mState == StatusBarState.FULLSCREEN_USER_SWITCHER;
+    }
+
     private boolean updateIsKeyguard() {
         boolean wakeAndUnlocking = mFingerprintUnlockController.getMode()
                 == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 5975608..6b6ea10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -135,26 +135,34 @@
         mFingerprintUnlockController = fingerprintUnlockController;
         mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
                 mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry);
+        mContainer.addOnLayoutChangeListener(this::onContainerLayout);
         mNotificationPanelView = notificationPanelView;
         notificationPanelView.setExpansionListener(this::onPanelExpansionChanged);
     }
 
+    private void onContainerLayout(View v, int left, int top, int right, int bottom,
+            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+        mNotificationPanelView.setBouncerTop(mBouncer.getTop());
+    }
+
     private void onPanelExpansionChanged(float expansion, boolean tracking) {
         // We don't want to translate the bounce when:
         // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
         //   conserve the original animation.
         // • The user quickly taps on the display and we show "swipe up to unlock."
         // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
+        // • Full-screen user switcher is displayed.
         final boolean noLongerTracking = mLastTracking != tracking && !tracking;
         if (mOccluded || mNotificationPanelView.isUnlockHintRunning()
-                || mBouncer.willDismissWithAction()) {
+                || mBouncer.willDismissWithAction()
+                || mStatusBar.isFullScreenUserSwitcherState()) {
             mBouncer.setExpansion(0);
         } else if (mShowing && mStatusBar.isKeyguardCurrentlySecure() && !mDozing) {
             mBouncer.setExpansion(expansion);
             if (expansion == 1) {
                 mBouncer.onFullyHidden();
             } else if (!mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
-                mBouncer.show(false /* resetSecuritySelection */, false /* notifyFalsing */);
+                mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
             } else if (noLongerTracking) {
                 // Notify that falsing manager should stop its session when user stops touching,
                 // even before the animation ends, to guarantee that we're not recording sensitive
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 7ffca173..d527465 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -323,10 +323,10 @@
 
         if (notif != null) {
             mNotificationManager.notifyAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
-                    notif, UserHandle.ALL);
+                    notif, UserHandle.of(vol.getMountUserId()));
         } else {
             mNotificationManager.cancelAsUser(vol.getId(), SystemMessage.NOTE_STORAGE_PUBLIC,
-                    UserHandle.ALL);
+                    UserHandle.of(vol.getMountUserId()));
         }
     }
 
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 107ce1e..a6b09ce 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -75,7 +75,7 @@
     android.test.runner \
     telephony-common \
     android.test.base \
-
+    android.car
 
 LOCAL_AAPT_FLAGS := --extra-packages com.android.systemui:com.android.keyguard
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
index 2000bff..5e27fde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java
@@ -35,6 +35,7 @@
 import android.app.NotificationChannel;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.media.session.MediaSession;
 import android.os.Bundle;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.StatusBarNotification;
@@ -61,6 +62,7 @@
     private static final int UID_NORMAL = 123;
     private static final int UID_ALLOW_DURING_SETUP = 456;
     private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
+    private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
 
     private final StatusBarNotification mMockStatusBarNotification =
             mock(StatusBarNotification.class);
@@ -226,12 +228,21 @@
     public void testSuppressSystemAlertNotification() {
         when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
         when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
+        StatusBarNotification sbn = mRow.getEntry().notification;
+        Bundle bundle = new Bundle();
+        bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"});
+        sbn.getNotification().extras = bundle;
 
         assertTrue(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
     }
 
     @Test
     public void testDoNotSuppressSystemAlertNotification() {
+        StatusBarNotification sbn = mRow.getEntry().notification;
+        Bundle bundle = new Bundle();
+        bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"});
+        sbn.getNotification().extras = bundle;
+
         when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
         when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
 
@@ -249,7 +260,24 @@
     }
 
     @Test
+    public void testDoNotSuppressMalformedSystemAlertNotification() {
+        when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
+
+        // missing extra
+        assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+
+        StatusBarNotification sbn = mRow.getEntry().notification;
+        Bundle bundle = new Bundle();
+        bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {});
+        sbn.getNotification().extras = bundle;
+
+        // extra missing values
+        assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification));
+    }
+
+    @Test
     public void testShouldFilterHiddenNotifications() {
+        initStatusBarNotification(false);
         // setup
         when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
         when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
@@ -264,6 +292,33 @@
         assertFalse(mNotificationData.shouldFilterOut(mMockStatusBarNotification));
     }
 
+    @Test
+    public void testIsExemptFromDndVisualSuppression_foreground() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        Notification n = mMockStatusBarNotification.getNotification();
+        n.flags = Notification.FLAG_FOREGROUND_SERVICE;
+
+        assertTrue(mNotificationData.isExemptFromDndVisualSuppression(mMockStatusBarNotification));
+        assertFalse(mNotificationData.shouldSuppressAmbient(mMockStatusBarNotification));
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_media() {
+        initStatusBarNotification(false);
+        when(mMockStatusBarNotification.getKey()).thenReturn(
+                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+        Notification n = mMockStatusBarNotification.getNotification();
+        Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
+        nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
+        n = nb.build();
+        when(mMockStatusBarNotification.getNotification()).thenReturn(n);
+
+        assertTrue(mNotificationData.isExemptFromDndVisualSuppression(mMockStatusBarNotification));
+        assertFalse(mNotificationData.shouldSuppressAmbient(mMockStatusBarNotification));
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
@@ -293,6 +348,13 @@
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
                         outRanking.canShowBadge(), outRanking.getUserSentiment(), true);
+            } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
+                outRanking.populate(key, outRanking.getRank(),
+                        outRanking.matchesInterruptionFilter(),
+                        outRanking.getVisibilityOverride(), 255,
+                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
+                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
+                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true);
             } else {
                 outRanking.populate(key, outRanking.getRank(),
                         outRanking.matchesInterruptionFilter(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 7dda8b2..c2cb5b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -218,6 +218,18 @@
     }
 
     @Test
+    public void testBindNotification_DefaultChannelUsesChannelNameIfMoreChannelsExist()
+            throws Exception {
+        // Package has one channel by default.
+        when(mMockINotificationManager.getNumNotificationChannelsForPackage(
+                eq(TEST_PACKAGE_NAME), eq(TEST_UID), anyBoolean())).thenReturn(10);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mDefaultNotificationChannel, 1, mSbn, null, null, null, null);
+        final TextView textView = mNotificationInfo.findViewById(R.id.channel_name);
+        assertEquals(VISIBLE, textView.getVisibility());
+    }
+
+    @Test
     public void testBindNotification_UnblockablePackageUsesChannelName() throws Exception {
         mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
                 TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 4a66bb7..b31a2dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -41,6 +41,7 @@
 import android.app.StatusBarManager;
 import android.app.trust.TrustManager;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.hardware.fingerprint.FingerprintManager;
 import android.metrics.LogMaker;
 import android.os.Binder;
@@ -71,6 +72,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.statusbar.ActivatableNotificationView;
@@ -91,6 +93,7 @@
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
@@ -98,6 +101,7 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
@@ -134,6 +138,7 @@
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
+    @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
 
     private TestableStatusBar mStatusBar;
     private FakeMetricsLogger mMetricsLogger;
@@ -146,9 +151,7 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(AssistManager.class);
         mDependency.injectMockDependency(DeviceProvisionedController.class);
-        mDependency.injectMockDependency(NotificationGroupManager.class);
         mDependency.injectMockDependency(NotificationGutsManager.class);
-        mDependency.injectMockDependency(NotificationRemoteInputManager.class);
         mDependency.injectMockDependency(NotificationMediaManager.class);
         mDependency.injectMockDependency(ForegroundServiceController.class);
         mDependency.injectTestDependency(NotificationViewHierarchyManager.class,
@@ -202,7 +205,12 @@
                 mPowerManager, mNotificationPanelView, mBarService, mNotificationListener,
                 mNotificationLogger, mVisualStabilityManager, mViewHierarchyManager,
                 mEntryManager, mScrimController, mFingerprintUnlockController,
-                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator);
+                mock(ActivityLaunchAnimator.class), mKeyguardViewMediator,
+                mock(NotificationRemoteInputManager.class), mock(NotificationGroupManager.class),
+                mock(FalsingManager.class), mock(StatusBarWindowManager.class),
+                mock(NotificationIconAreaController.class), mock(DozeScrimController.class),
+                mock(NotificationShelf.class), mLockscreenUserManager,
+                mock(CommandQueue.class));
         mStatusBar.mContext = mContext;
         mStatusBar.mComponents = mContext.getComponents();
         mEntryManager.setUpForTest(mStatusBar, mStackScroller, mStatusBar, mHeadsUpManager,
@@ -529,11 +537,7 @@
     @Test
     @RunWithLooper(setAsMainLooper = true)
     public void testUpdateKeyguardState_DoesNotCrash() {
-        mStatusBar.mStatusBarWindow = mock(StatusBarWindowView.class);
         mStatusBar.mState = StatusBarState.KEYGUARD;
-        mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
-        mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
-        mStatusBar.mLockscreenUserManager = mock(NotificationLockscreenUserManager.class);
         when(mStatusBar.mLockscreenUserManager.getCurrentProfiles()).thenReturn(
                 new SparseArray<>());
         mStatusBar.updateKeyguardState(false, false);
@@ -541,9 +545,6 @@
 
     @Test
     public void testFingerprintNotification_UpdatesScrims() {
-        mStatusBar.mStatusBarWindowManager = mock(StatusBarWindowManager.class);
-        mStatusBar.mDozeScrimController = mock(DozeScrimController.class);
-        mStatusBar.mNotificationIconAreaController = mock(NotificationIconAreaController.class);
         mStatusBar.notifyFpAuthModeChanged();
         verify(mScrimController).transitionTo(any(), any());
     }
@@ -629,6 +630,32 @@
         verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
     }
 
+    @Test
+    public void testSetState_changesIsFullScreenUserSwitcherState() {
+        mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
+        assertFalse(mStatusBar.isFullScreenUserSwitcherState());
+
+        mStatusBar.setBarStateForTest(StatusBarState.FULLSCREEN_USER_SWITCHER);
+        assertTrue(mStatusBar.isFullScreenUserSwitcherState());
+    }
+
+    @Test
+    public void testShowKeyguardImplementation_setsState() {
+        when(mLockscreenUserManager.getCurrentProfiles()).thenReturn(new SparseArray<>());
+
+        mStatusBar.setBarStateForTest(StatusBarState.SHADE);
+
+        // By default, showKeyguardImpl sets state to KEYGUARD.
+        mStatusBar.showKeyguardImpl();
+        assertTrue(mStatusBar.mState == StatusBarState.KEYGUARD);
+
+        // If useFullscreenUserSwitcher is true, state is set to FULLSCREEN_USER_SWITCHER.
+        mStatusBar.mUserSwitcherController = mock(UserSwitcherController.class);
+        when(mStatusBar.mUserSwitcherController.useFullscreenUserSwitcher()).thenReturn(true);
+        mStatusBar.showKeyguardImpl();
+        assertTrue(mStatusBar.mState == StatusBarState.FULLSCREEN_USER_SWITCHER);
+    }
+
     static class TestableStatusBar extends StatusBar {
         public TestableStatusBar(StatusBarKeyguardViewManager man,
                 UnlockMethodCache unlock, KeyguardIndicationController key,
@@ -640,7 +667,16 @@
                 NotificationViewHierarchyManager viewHierarchyManager,
                 TestableNotificationEntryManager entryManager, ScrimController scrimController,
                 FingerprintUnlockController fingerprintUnlockController,
-                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator) {
+                ActivityLaunchAnimator launchAnimator, KeyguardViewMediator keyguardViewMediator,
+                NotificationRemoteInputManager notificationRemoteInputManager,
+                NotificationGroupManager notificationGroupManager,
+                FalsingManager falsingManager,
+                StatusBarWindowManager statusBarWindowManager,
+                NotificationIconAreaController notificationIconAreaController,
+                DozeScrimController dozeScrimController,
+                NotificationShelf notificationShelf,
+                NotificationLockscreenUserManager notificationLockscreenUserManager,
+                CommandQueue commandQueue) {
             mStatusBarKeyguardViewManager = man;
             mUnlockMethodCache = unlock;
             mKeyguardIndicationController = key;
@@ -660,6 +696,15 @@
             mActivityLaunchAnimator = launchAnimator;
             mKeyguardViewMediator = keyguardViewMediator;
             mClearAllEnabled = true;
+            mRemoteInputManager = notificationRemoteInputManager;
+            mGroupManager = notificationGroupManager;
+            mFalsingManager = falsingManager;
+            mStatusBarWindowManager = statusBarWindowManager;
+            mNotificationIconAreaController = notificationIconAreaController;
+            mDozeScrimController = dozeScrimController;
+            mNotificationShelf = notificationShelf;
+            mLockscreenUserManager = notificationLockscreenUserManager;
+            mCommandQueue = commandQueue;
         }
 
         private WakefulnessLifecycle createAwakeWakefulnessLifecycle() {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8941b49..de112f9 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -853,11 +853,7 @@
             if (mSecurityPolicy.findA11yWindowInfoById(windowId) == null) {
                 return null;
             }
-            IBinder token = mGlobalWindowTokens.get(windowId);
-            if (token != null) {
-                return token;
-            }
-            return getCurrentUserStateLocked().mWindowTokens.get(windowId);
+            return findWindowTokenLocked(windowId);
         }
     }
 
@@ -2527,6 +2523,14 @@
         getInteractionBridge().clearAccessibilityFocusNotLocked(windowId);
     }
 
+    private IBinder findWindowTokenLocked(int windowId) {
+        IBinder token = mGlobalWindowTokens.get(windowId);
+        if (token != null) {
+            return token;
+        }
+        return getCurrentUserStateLocked().mWindowTokens.get(windowId);
+    }
+
     private int findWindowIdLocked(IBinder token) {
         final int globalIndex = mGlobalWindowTokens.indexOfValue(token);
         if (globalIndex >= 0) {
@@ -2986,7 +2990,7 @@
                 // the accessibility layer reports which are windows
                 // that a sighted user can touch.
                 default: {
-                    return isRetrievalAllowingWindow(event.getWindowId());
+                    return isRetrievalAllowingWindowLocked(event.getWindowId());
                 }
             }
         }
@@ -3438,7 +3442,8 @@
 
         public boolean canGetAccessibilityNodeInfoLocked(
                 AbstractAccessibilityServiceConnection service, int windowId) {
-            return canRetrieveWindowContentLocked(service) && isRetrievalAllowingWindow(windowId);
+            return canRetrieveWindowContentLocked(service)
+                    && isRetrievalAllowingWindowLocked(windowId);
         }
 
         public boolean canRetrieveWindowsLocked(AbstractAccessibilityServiceConnection service) {
@@ -3523,17 +3528,40 @@
                     || userId == UserHandle.USER_CURRENT_OR_SELF);
         }
 
-        private boolean isRetrievalAllowingWindow(int windowId) {
+        private boolean isRetrievalAllowingWindowLocked(int windowId) {
             // The system gets to interact with any window it wants.
             if (Binder.getCallingUid() == Process.SYSTEM_UID) {
                 return true;
             }
+            if (Binder.getCallingUid() == Process.SHELL_UID) {
+                if (!isShellAllowedToRetrieveWindowLocked(windowId)) {
+                    return false;
+                }
+            }
             if (windowId == mActiveWindowId) {
                 return true;
             }
             return findA11yWindowInfoById(windowId) != null;
         }
 
+        private boolean isShellAllowedToRetrieveWindowLocked(int windowId) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                IBinder windowToken = findWindowTokenLocked(windowId);
+                if (windowToken == null) {
+                    return false;
+                }
+                int userId = mWindowManagerService.getWindowOwnerUserId(windowToken);
+                if (userId == UserHandle.USER_NULL) {
+                    return false;
+                }
+                return !mUserManager.hasUserRestriction(
+                        UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         public AccessibilityWindowInfo findA11yWindowInfoById(int windowId) {
             return mA11yWindowInfoById.get(windowId);
         }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index d4ecd8b..3253f2e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -19,7 +19,6 @@
 import static android.Manifest.permission.MANAGE_AUTO_FILL;
 import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
 
-import static com.android.server.autofill.Helper.bundleToString;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sFullScreenMode;
 import static com.android.server.autofill.Helper.sPartitionMaxCount;
@@ -193,8 +192,7 @@
                 if (disabledBefore == disabledNow) {
                     // Nothing changed, do nothing.
                     if (sDebug) {
-                        Slog.d(TAG, "Autofill restriction did not change for user " + userId + ": "
-                                + bundleToString(newRestrictions));
+                        Slog.d(TAG, "Autofill restriction did not change for user " + userId);
                         return;
                     }
                 }
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index a202aaf..78526f5 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -79,28 +79,6 @@
         throw new UnsupportedOperationException("contains static members only");
     }
 
-    static void append(StringBuilder builder, Bundle bundle) {
-        if (bundle == null || !sVerbose) {
-            builder.append("null");
-            return;
-        }
-        final Set<String> keySet = bundle.keySet();
-        builder.append("[Bundle with ").append(keySet.size()).append(" extras:");
-        for (String key : keySet) {
-            final Object value = bundle.get(key);
-            builder.append(' ').append(key).append('=');
-            builder.append((value instanceof Object[])
-                    ? Arrays.toString((Objects[]) value) : value);
-        }
-        builder.append(']');
-    }
-
-    static String bundleToString(Bundle bundle) {
-        final StringBuilder builder = new StringBuilder();
-        append(builder, bundle);
-        return builder.toString();
-    }
-
     @Nullable
     static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) {
         if (set == null) return null;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 706fb1a..706a6ab 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2502,8 +2502,10 @@
         }
 
         pw.print(prefix); pw.print("mHasCallback: "); pw.println(mHasCallback);
-        pw.print(prefix); pw.print("mClientState: "); pw.println(
-                Helper.bundleToString(mClientState));
+        if (mClientState != null) {
+            pw.print(prefix); pw.println("mClientState: "); pw.print(mClientState.getSize()); pw
+                .println(" items");
+        }
         pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
         pw.print(prefix); pw.print("mUrlBar: ");
         if (mUrlBar == null) {
diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
index 4de2c9b..49fa1cc 100644
--- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
+++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
@@ -21,6 +21,7 @@
 import android.provider.Settings;
 import android.util.KeyValueListParser;
 import android.util.KeyValueSettingObserver;
+import android.util.Slog;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -31,6 +32,8 @@
  * are represented as a comma-delimited key value list.
  */
 public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
+    private static final String TAG = "BackupAgentTimeout";
+
     @VisibleForTesting
     public static final String SETTING = Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS;
 
@@ -120,30 +123,50 @@
 
     public long getKvBackupAgentTimeoutMillis() {
         synchronized (mLock) {
+            if (BackupManagerService.DEBUG_SCHEDULING) {
+                Slog.v(TAG, "getKvBackupAgentTimeoutMillis(): " + mKvBackupAgentTimeoutMillis);
+            }
             return mKvBackupAgentTimeoutMillis;
         }
     }
 
     public long getFullBackupAgentTimeoutMillis() {
         synchronized (mLock) {
+            if (BackupManagerService.DEBUG_SCHEDULING) {
+                Slog.v(TAG, "getFullBackupAgentTimeoutMillis(): " + mFullBackupAgentTimeoutMillis);
+            }
             return mFullBackupAgentTimeoutMillis;
         }
     }
 
     public long getSharedBackupAgentTimeoutMillis() {
         synchronized (mLock) {
+            if (BackupManagerService.DEBUG_SCHEDULING) {
+                Slog.v(
+                        TAG,
+                        "getSharedBackupAgentTimeoutMillis(): " + mSharedBackupAgentTimeoutMillis);
+            }
             return mSharedBackupAgentTimeoutMillis;
         }
     }
 
     public long getRestoreAgentTimeoutMillis() {
         synchronized (mLock) {
+            if (BackupManagerService.DEBUG_SCHEDULING) {
+                Slog.v(TAG, "getRestoreAgentTimeoutMillis(): " + mRestoreAgentTimeoutMillis);
+            }
             return mRestoreAgentTimeoutMillis;
         }
     }
 
     public long getRestoreAgentFinishedTimeoutMillis() {
         synchronized (mLock) {
+            if (BackupManagerService.DEBUG_SCHEDULING) {
+                Slog.v(
+                        TAG,
+                        "getRestoreAgentFinishedTimeoutMillis(): "
+                                + mRestoreAgentFinishedTimeoutMillis);
+            }
             return mRestoreAgentFinishedTimeoutMillis;
         }
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index d6f6c6c..bd51af2 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -215,13 +215,6 @@
     // Timeout interval for deciding that a bind or clear-data has taken too long
     private static final long TIMEOUT_INTERVAL = 10 * 1000;
 
-    // Timeout intervals for agent backup & restore operations
-    public static final long TIMEOUT_BACKUP_INTERVAL = 30 * 1000;
-    public static final long TIMEOUT_FULL_BACKUP_INTERVAL = 5 * 60 * 1000;
-    public static final long TIMEOUT_SHARED_BACKUP_INTERVAL = 30 * 60 * 1000;
-    public static final long TIMEOUT_RESTORE_INTERVAL = 60 * 1000;
-    public static final long TIMEOUT_RESTORE_FINISHED_INTERVAL = 30 * 1000;
-
     // User confirmation timeout for a full backup/restore operation.  It's this long in
     // order to give them time to enter the backup password.
     private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000;
@@ -232,6 +225,7 @@
     private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
 
     private BackupManagerConstants mConstants;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private Context mContext;
     private PackageManager mPackageManager;
     private IPackageManager mPackageManagerBinder;
@@ -315,6 +309,10 @@
         return mConstants;
     }
 
+    public BackupAgentTimeoutParameters getAgentTimeoutParameters() {
+        return mAgentTimeoutParameters;
+    }
+
     public Context getContext() {
         return mContext;
     }
@@ -799,6 +797,10 @@
 
         mBackupManagerBinder = Trampoline.asInterface(parent.asBinder());
 
+        mAgentTimeoutParameters = new
+                BackupAgentTimeoutParameters(Handler.getMain(), mContext.getContentResolver());
+        mAgentTimeoutParameters.start();
+
         // spin up the backup/restore handler thread
         mBackupHandler = new BackupHandler(this, backupThread.getLooper());
 
@@ -3407,7 +3409,7 @@
             }
             mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport);
             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
-                    TIMEOUT_RESTORE_INTERVAL);
+                    mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
         }
         return mActiveRestoreSession;
     }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
index 7b021c6..aabe7f6 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
@@ -191,4 +191,7 @@
   void dump(FileDescriptor fd, PrintWriter pw, String[] args);
 
   IBackupManager getBackupManagerBinder();
+
+  // Gets access to the backup/restore agent timeout parameters.
+  BackupAgentTimeoutParameters getAgentTimeoutParameters();
 }
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index 4755877..7f0030a 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -4,8 +4,8 @@
 import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
 import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
 import static android.os.ParcelFileDescriptor.MODE_TRUNCATE;
+
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL;
 
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
@@ -19,6 +19,7 @@
 import android.os.SELinux;
 import android.util.Slog;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.backup.utils.FullBackupUtils;
 
 import libcore.io.IoUtils;
@@ -59,6 +60,7 @@
     private ParcelFileDescriptor mSavedState;
     private ParcelFileDescriptor mBackupData;
     private ParcelFileDescriptor mNewState;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public KeyValueAdbBackupEngine(OutputStream output, PackageInfo packageInfo,
             BackupManagerServiceInterface backupManagerService, PackageManager packageManager,
@@ -81,6 +83,9 @@
                 pkg + BACKUP_KEY_VALUE_NEW_STATE_FILENAME_SUFFIX);
 
         mManifestFile = new File(mDataDir, BackupManagerService.BACKUP_MANIFEST_FILENAME);
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     public void backupOnePackage() throws IOException {
@@ -148,8 +153,9 @@
     // Return true on backup success, false otherwise
     private boolean invokeAgentForAdbBackup(String packageName, IBackupAgent agent) {
         int token = mBackupManagerService.generateRandomIntegerToken();
+        long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
         try {
-            mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null,
+            mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null,
                     OP_TYPE_BACKUP_WAIT);
 
             // Start backup and wait for BackupManagerService to get callback for success or timeout
@@ -231,14 +237,14 @@
     }
 
     private void writeBackupData() throws IOException {
-
         int token = mBackupManagerService.generateRandomIntegerToken();
+        long kvBackupAgentTimeoutMillis = mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
 
         ParcelFileDescriptor[] pipes = null;
         try {
             pipes = ParcelFileDescriptor.createPipe();
 
-            mBackupManagerService.prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL, null,
+            mBackupManagerService.prepareOperationTimeout(token, kvBackupAgentTimeoutMillis, null,
                     OP_TYPE_BACKUP_WAIT);
 
             // We will have to create a runnable that will read the manifest and backup data we
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 0582aba..5694659 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -25,9 +25,6 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
-import static com.android.server.backup.BackupManagerService
-        .TIMEOUT_SHARED_BACKUP_INTERVAL;
 
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
@@ -44,9 +41,11 @@
 import android.util.Slog;
 import android.util.StringBuilderPrinter;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
-import com.android.server.backup.BackupRestoreTask;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
+import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.utils.FullBackupUtils;
 
 import java.io.BufferedOutputStream;
@@ -75,6 +74,7 @@
     private final long mQuota;
     private final int mOpToken;
     private final int mTransportFlags;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     class FullBackupRunner implements Runnable {
 
@@ -137,8 +137,8 @@
                 final boolean isSharedStorage =
                         mPackage.packageName.equals(SHARED_BACKUP_AGENT_PACKAGE);
                 final long timeout = isSharedStorage ?
-                        TIMEOUT_SHARED_BACKUP_INTERVAL :
-                        TIMEOUT_FULL_BACKUP_INTERVAL;
+                        mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
+                        mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
 
                 if (DEBUG) {
                     Slog.d(TAG, "Calling doFullBackup() on " + mPackage.packageName);
@@ -180,6 +180,9 @@
         mQuota = quota;
         mOpToken = opToken;
         mTransportFlags = transportFlags;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     public int preflightCheck() throws RemoteException {
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
index 40b6967..bc7d9fc 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupObbConnection.java
@@ -19,7 +19,6 @@
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.app.backup.IBackupManager;
 import android.content.ComponentName;
@@ -33,6 +32,8 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IObbBackupService;
+import com.android.internal.util.Preconditions;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.utils.FullBackupUtils;
 
@@ -46,10 +47,14 @@
 
     private BackupManagerService backupManagerService;
     volatile IObbBackupService mService;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public FullBackupObbConnection(BackupManagerService backupManagerService) {
         this.backupManagerService = backupManagerService;
         mService = null;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     public void establish() {
@@ -75,8 +80,10 @@
         try {
             pipes = ParcelFileDescriptor.createPipe();
             int token = backupManagerService.generateRandomIntegerToken();
+            long fullBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    token, TIMEOUT_FULL_BACKUP_INTERVAL, null, OP_TYPE_BACKUP_WAIT);
+                    token, fullBackupAgentTimeoutMillis, null, OP_TYPE_BACKUP_WAIT);
             mService.backupObbs(pkg.packageName, pipes[1], token,
                     backupManagerService.getBackupManagerBinder());
             FullBackupUtils.routeSocketDataToOutput(pipes[0], out);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index 2c2dd85..a40afc3 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -22,7 +22,6 @@
 import static com.android.server.backup.BackupManagerService.OP_PENDING;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.annotation.Nullable;
 import android.app.IBackupAgent;
@@ -43,7 +42,9 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FullBackupJob;
 import com.android.server.backup.BackupManagerService;
@@ -146,6 +147,7 @@
     private volatile boolean mIsDoingBackup;
     private volatile boolean mCancelAll;
     private final int mCurrentOpToken;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public PerformFullTransportBackupTask(BackupManagerService backupManagerService,
             TransportClient transportClient,
@@ -167,6 +169,9 @@
         mUserInitiated = userInitiated;
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
         mBackupRunnerOpToken = backupManagerService.generateRandomIntegerToken();
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
 
         if (backupManagerService.isBackupOperationInProgress()) {
             if (DEBUG) {
@@ -698,9 +703,11 @@
         @Override
         public int preflightFullBackup(PackageInfo pkg, IBackupAgent agent) {
             int result;
+            long fullBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
                 backupManagerService.prepareOperationTimeout(
-                        mCurrentOpToken, TIMEOUT_FULL_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT);
+                        mCurrentOpToken, fullBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
                 backupManagerService.addBackupTrace("preflighting");
                 if (MORE_DEBUG) {
                     Slog.d(TAG, "Preflighting full payload of " + pkg.packageName);
@@ -713,7 +720,7 @@
                 // timeout had been produced.  In case of a real backstop timeout, mResult
                 // will still contain the value it was constructed with, AGENT_ERROR, which
                 // intentionaly falls into the "just report failure" code.
-                mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+                mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
 
                 long totalSize = mResult.get();
                 // If preflight timed out, mResult will contain error code as int.
@@ -769,8 +776,10 @@
 
         @Override
         public long getExpectedSizeOrErrorCode() {
+            long fullBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+                mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
                 return mResult.get();
             } catch (InterruptedException e) {
                 return BackupTransport.NO_MORE_DATA;
@@ -863,8 +872,10 @@
         // If preflight succeeded, returns positive number - preflight size,
         // otherwise return negative error code.
         long getPreflightResultBlocking() {
+            long fullBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mPreflightLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+                mPreflightLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
                 if (mIsCancelled) {
                     return BackupManager.ERROR_BACKUP_CANCELLED;
                 }
@@ -879,8 +890,10 @@
         }
 
         int getBackupResultBlocking() {
+            long fullBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
             try {
-                mBackupLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+                mBackupLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
                 if (mIsCancelled) {
                     return BackupManager.ERROR_BACKUP_CANCELLED;
                 }
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 136fada..69f08ae 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -19,7 +19,6 @@
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
 
 import android.app.backup.RestoreSet;
 import android.content.Intent;
@@ -33,7 +32,9 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
@@ -81,10 +82,14 @@
     public static final int MSG_OP_COMPLETE = 21;
 
     private final BackupManagerService backupManagerService;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public BackupHandler(BackupManagerService backupManagerService, Looper looper) {
         super(looper);
         this.backupManagerService = backupManagerService;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     public void handleMessage(Message msg) {
@@ -322,7 +327,8 @@
 
                     // Done: reset the session timeout clock
                     removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
-                    sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT, TIMEOUT_RESTORE_INTERVAL);
+                    sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
+                            mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
 
                     params.listener.onFinished(callerLogString);
                 }
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 11394e66..ac605b1 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -24,7 +24,6 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP;
 import static com.android.server.backup.BackupManagerService.OP_TYPE_BACKUP_WAIT;
 import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_BACKUP_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
 
@@ -55,8 +54,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
@@ -142,6 +143,7 @@
     private boolean mFinished;
     private final boolean mUserInitiated;
     private final boolean mNonIncremental;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     private volatile boolean mCancelAll;
 
@@ -162,6 +164,9 @@
         mPendingFullBackups = pendingFullBackups;
         mUserInitiated = userInitiated;
         mNonIncremental = nonIncremental;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
 
         mStateDir = new File(backupManagerService.getBaseStateDir(), dirName);
         mCurrentOpToken = backupManagerService.generateRandomIntegerToken();
@@ -711,8 +716,10 @@
 
             // Initiate the target's backup pass
             backupManagerService.addBackupTrace("setting timeout");
+            long kvBackupAgentTimeoutMillis =
+                    mAgentTimeoutParameters.getKvBackupAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    mEphemeralOpToken, TIMEOUT_BACKUP_INTERVAL, this, OP_TYPE_BACKUP_WAIT);
+                    mEphemeralOpToken, kvBackupAgentTimeoutMillis, this, OP_TYPE_BACKUP_WAIT);
             backupManagerService.addBackupTrace("calling agent doBackup()");
 
             agent.doBackup(
diff --git a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
index e4f3a9d..a8c7ce6 100644
--- a/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
+++ b/services/backup/java/com/android/server/backup/restore/AdbRestoreFinishedLatch.java
@@ -18,10 +18,11 @@
 
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
 
 import android.util.Slog;
 
+import com.android.internal.util.Preconditions;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 
@@ -37,18 +38,24 @@
     private BackupManagerService backupManagerService;
     final CountDownLatch mLatch;
     private final int mCurrentOpToken;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     public AdbRestoreFinishedLatch(BackupManagerService backupManagerService,
             int currentOpToken) {
         this.backupManagerService = backupManagerService;
         mLatch = new CountDownLatch(1);
         mCurrentOpToken = currentOpToken;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     void await() {
         boolean latched = false;
+        long fullBackupAgentTimeoutMillis =
+                mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
         try {
-            latched = mLatch.await(TIMEOUT_FULL_BACKUP_INTERVAL, TimeUnit.MILLISECONDS);
+            latched = mLatch.await(fullBackupAgentTimeoutMillis, TimeUnit.MILLISECONDS);
         } catch (InterruptedException e) {
             Slog.w(TAG, "Interrupted!");
         }
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index c1a1c1d..6bc7530 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -23,9 +23,6 @@
 import static com.android.server.backup.BackupManagerService.OP_TYPE_RESTORE_WAIT;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
-import static com.android.server.backup.BackupManagerService
-        .TIMEOUT_SHARED_BACKUP_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 
 import android.app.ApplicationThreadConstants;
@@ -40,13 +37,17 @@
 import android.content.pm.Signature;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
+import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupAgentTimeoutParameters;
+import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
-import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.fullbackup.FullBackupObbConnection;
 import com.android.server.backup.utils.BytesReadListener;
 import com.android.server.backup.utils.FullBackupRestoreObserverUtils;
@@ -56,8 +57,11 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * Full restore engine, used by both adb restore and transport-based full restore.
@@ -121,6 +125,8 @@
 
     final int mEphemeralOpToken;
 
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
+
     public FullRestoreEngine(BackupManagerService backupManagerService,
             BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
             IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks,
@@ -135,6 +141,9 @@
         mAllowObbs = allowObbs;
         mBuffer = new byte[32 * 1024];
         mBytes = 0;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
     }
 
     public IBackupAgent getAgent() {
@@ -320,12 +329,17 @@
                                             pkg, 0);
 
                             // If we haven't sent any data to this app yet, we probably
-                            // need to clear it first.  Check that.
+                            // need to clear it first. Check that.
                             if (!mClearedPackages.contains(pkg)) {
-                                // apps with their own backup agents are
-                                // responsible for coherently managing a full
-                                // restore.
-                                if (mTargetApp.backupAgentName == null) {
+                                // Apps with their own backup agents are responsible for coherently
+                                // managing a full restore.
+                                // In some rare cases they can't, especially in case of deferred
+                                // restore. In this case check whether this app should be forced to
+                                // clear up.
+                                // TODO: Fix this properly with manifest parameter.
+                                boolean forceClear = shouldForceClearAppDataOnFullRestore(
+                                        mTargetApp.packageName);
+                                if (mTargetApp.backupAgentName == null || forceClear) {
                                     if (DEBUG) {
                                         Slog.d(TAG,
                                                 "Clearing app data preparatory to full restore");
@@ -381,8 +395,8 @@
                         long toCopy = info.size;
                         final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
                         final long timeout = isSharedStorage ?
-                                TIMEOUT_SHARED_BACKUP_INTERVAL :
-                                TIMEOUT_RESTORE_INTERVAL;
+                                mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
+                                mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
                         try {
                             mBackupManagerService.prepareOperationTimeout(token,
                                     timeout,
@@ -623,6 +637,24 @@
         return true;
     }
 
+    /**
+     * Returns whether the package is in the list of the packages for which clear app data should
+     * be called despite the fact that they have backup agent.
+     *
+     * <p>The list is read from {@link Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE}.
+     */
+    private boolean shouldForceClearAppDataOnFullRestore(String packageName) {
+        String packageListString = Settings.Secure.getString(
+                mBackupManagerService.getContext().getContentResolver(),
+                Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE);
+        if (TextUtils.isEmpty(packageListString)) {
+            return false;
+        }
+
+        List<String> packages = Arrays.asList(packageListString.split(";"));
+        return packages.contains(packageName);
+    }
+
     void sendOnRestorePackage(String name) {
         if (mObserver != null) {
             try {
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index dacde0b..77163d3 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -16,8 +16,6 @@
 
 package com.android.server.backup.restore;
 
-import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
-import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
 import static com.android.server.backup.BackupManagerService.BACKUP_FILE_HEADER_MAGIC;
 import static com.android.server.backup.BackupManagerService.BACKUP_FILE_VERSION;
 import static com.android.server.backup.BackupManagerService.BACKUP_MANIFEST_FILENAME;
@@ -28,8 +26,8 @@
 import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE;
 import static com.android.server.backup.BackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_FULL_BACKUP_INTERVAL;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
+import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 
 import android.app.ApplicationThreadConstants;
@@ -48,7 +46,9 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -101,6 +101,7 @@
     private byte[] mWidgetData = null;
 
     private long mBytes;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     // Runner that can be placed on a separate thread to do in-process invocation
     // of the "restore finished" API asynchronously.  Used by adb restore.
@@ -155,6 +156,9 @@
         mAgentPackage = null;
         mTargetApp = null;
         mObbConnection = new FullBackupObbConnection(backupManagerService);
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
 
         // Which packages we've already wiped data on.  We prepopulate this
         // with a whitelist of packages known to be unclearable.
@@ -643,9 +647,11 @@
                     if (okay) {
                         boolean agentSuccess = true;
                         long toCopy = info.size;
+                        long restoreAgentTimeoutMillis =
+                                mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
                         try {
                             mBackupManagerService.prepareOperationTimeout(
-                                    token, TIMEOUT_RESTORE_INTERVAL, null, OP_TYPE_RESTORE_WAIT);
+                                    token, restoreAgentTimeoutMillis, null, OP_TYPE_RESTORE_WAIT);
 
                             if (FullBackup.OBB_TREE_TOKEN.equals(info.domain)) {
                                 if (DEBUG) {
@@ -820,10 +826,12 @@
                 // In the adb restore case, we do restore-finished here
                 if (doRestoreFinished) {
                     final int token = mBackupManagerService.generateRandomIntegerToken();
+                    long fullBackupAgentTimeoutMillis =
+                            mAgentTimeoutParameters.getFullBackupAgentTimeoutMillis();
                     final AdbRestoreFinishedLatch latch = new AdbRestoreFinishedLatch(
                             mBackupManagerService, token);
                     mBackupManagerService.prepareOperationTimeout(
-                            token, TIMEOUT_FULL_BACKUP_INTERVAL, latch, OP_TYPE_RESTORE_WAIT);
+                            token, fullBackupAgentTimeoutMillis, latch, OP_TYPE_RESTORE_WAIT);
                     if (mTargetApp.processName.equals("system")) {
                         if (MORE_DEBUG) {
                             Slog.d(TAG, "system agent - restoreFinished on thread");
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 4b467e5..12d72d8 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -23,9 +23,6 @@
 import static com.android.server.backup.BackupManagerService.PACKAGE_MANAGER_SENTINEL;
 import static com.android.server.backup.BackupManagerService.SETTINGS_PACKAGE;
 import static com.android.server.backup.BackupManagerService.TAG;
-import static com.android.server.backup.BackupManagerService
-        .TIMEOUT_RESTORE_FINISHED_INTERVAL;
-import static com.android.server.backup.BackupManagerService.TIMEOUT_RESTORE_INTERVAL;
 import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTORE_STEP;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
@@ -56,9 +53,11 @@
 import android.util.Slog;
 
 import com.android.internal.backup.IBackupTransport;
+import com.android.internal.util.Preconditions;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.BackupUtils;
 import com.android.server.backup.PackageManagerBackupAgent;
@@ -160,6 +159,7 @@
     ParcelFileDescriptor mNewState;
 
     private final int mEphemeralOpToken;
+    private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
 
     // This task can assume that the wakelock is properly held for it and doesn't have to worry
     // about releasing it.
@@ -190,6 +190,9 @@
         mFinished = false;
         mDidLaunch = false;
         mListener = listener;
+        mAgentTimeoutParameters = Preconditions.checkNotNull(
+                backupManagerService.getAgentTimeoutParameters(),
+                "Timeout parameters cannot be null");
 
         if (targetPackage != null) {
             // Single package restore
@@ -760,8 +763,9 @@
             // Kick off the restore, checking for hung agents.  The timeout or
             // the operationComplete() callback will schedule the next step,
             // so we do not do that here.
+            long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
             backupManagerService.prepareOperationTimeout(
-                    mEphemeralOpToken, TIMEOUT_RESTORE_INTERVAL, this, OP_TYPE_RESTORE_WAIT);
+                    mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
             mAgent.doRestore(mBackupData, appVersionCode, mNewState,
                     mEphemeralOpToken, backupManagerService.getBackupManagerBinder());
         } catch (Exception e) {
@@ -813,9 +817,11 @@
             Slog.d(TAG, "restoreFinished packageName=" + mCurrentPackage.packageName);
         }
         try {
+            long restoreAgentFinishedTimeoutMillis =
+                    mAgentTimeoutParameters.getRestoreAgentFinishedTimeoutMillis();
             backupManagerService
                     .prepareOperationTimeout(mEphemeralOpToken,
-                            TIMEOUT_RESTORE_FINISHED_INTERVAL, this,
+                            restoreAgentFinishedTimeoutMillis, this,
                             OP_TYPE_RESTORE_WAIT);
             mAgent.doRestoreFinished(mEphemeralOpToken,
                     backupManagerService.getBackupManagerBinder());
@@ -1109,9 +1115,10 @@
         } else {
             // We were invoked via an active restore session, not by the Package
             // Manager, so start up the session timeout again.
+            long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
             backupManagerService.getBackupHandler().sendEmptyMessageDelayed(
                     MSG_RESTORE_SESSION_TIMEOUT,
-                    TIMEOUT_RESTORE_INTERVAL);
+                    restoreAgentTimeoutMillis);
         }
 
         // Kick off any work that may be needed regarding app widget restores
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e3584e6..08e5d44 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2873,13 +2873,15 @@
     }
 
     /**
-     * Encapsulates the globla setting "hidden_api_blacklist_exemptions", including tracking the
+     * Encapsulates the global setting "hidden_api_blacklist_exemptions", including tracking the
      * latest value via a content observer.
      */
     static class HiddenApiBlacklist extends ContentObserver {
 
         private final Context mContext;
         private boolean mBlacklistDisabled;
+        private String mExemptionsStr;
+        private List<String> mExemptions = Collections.emptyList();
 
         public HiddenApiBlacklist(Handler handler, Context context) {
             super(handler);
@@ -2895,8 +2897,22 @@
         }
 
         private void update() {
-            mBlacklistDisabled = "*".equals(Settings.Global.getString(mContext.getContentResolver(),
-                    Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS));
+            String exemptions = Settings.Global.getString(mContext.getContentResolver(),
+                    Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS);
+            if (!TextUtils.equals(exemptions, mExemptionsStr)) {
+                mExemptionsStr = exemptions;
+                if ("*".equals(exemptions)) {
+                    mBlacklistDisabled = true;
+                    mExemptions = Collections.emptyList();
+                } else {
+                    mBlacklistDisabled = false;
+                    mExemptions = TextUtils.isEmpty(exemptions)
+                            ? Collections.emptyList()
+                            : Arrays.asList(exemptions.split(","));
+                }
+                zygoteProcess.setApiBlacklistExemptions(mExemptions);
+            }
+
         }
 
         boolean isDisabled() {
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index 106b37f..bef650b 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -285,6 +285,16 @@
         return false;
     }
 
+    /**
+     * @return the root task of the lock task.
+     */
+    TaskRecord getRootTask() {
+        if (mLockTaskModeTasks.isEmpty()) {
+            return null;
+        }
+        return mLockTaskModeTasks.get(0);
+    }
+
     private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
         // TODO: Double check what's going on here. If the task is already in lock task mode, it's
         // likely whitelisted, so will return false below.
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index fcf00ce..1d305fb 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -1155,6 +1155,11 @@
                 }
         }
 
+        // If we're in lock task mode, ignore the root task
+        if (task == mService.mLockTaskController.getRootTask()) {
+            return false;
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index 73a7c3eb..9df321c 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -42,18 +42,13 @@
 class RecentsAnimation implements RecentsAnimationCallbacks {
     private static final String TAG = RecentsAnimation.class.getSimpleName();
 
-    private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000;
-
     private final ActivityManagerService mService;
     private final ActivityStackSupervisor mStackSupervisor;
     private final ActivityStartController mActivityStartController;
     private final WindowManagerService mWindowManager;
     private final UserController mUserController;
-    private final Handler mHandler;
     private final int mCallingPid;
 
-    private final Runnable mCancelAnimationRunnable;
-
     // The stack to restore the home stack behind when the animation is finished
     private ActivityStack mRestoreHomeBehindStack;
 
@@ -63,16 +58,9 @@
         mService = am;
         mStackSupervisor = stackSupervisor;
         mActivityStartController = activityStartController;
-        mHandler = new Handler(mStackSupervisor.mLooper);
         mWindowManager = wm;
         mUserController = userController;
         mCallingPid = callingPid;
-
-        mCancelAnimationRunnable = () -> {
-            // The caller has not finished the animation in a predefined amount of time, so
-            // force-cancel the animation
-            mWindowManager.cancelRecentsAnimation();
-        };
     }
 
     void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
@@ -133,10 +121,6 @@
             // duration of the gesture that is driven by the recents component
             homeActivity.mLaunchTaskBehind = true;
 
-            // Post a timeout for the animation. This needs to happen before initializing the
-            // recents animation on the WM side since we may decide to cancel the animation there
-            mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT);
-
             // Fetch all the surface controls and pass them to the client to get the animation
             // started
             mWindowManager.cancelRecentsAnimation();
@@ -157,7 +141,6 @@
 
     @Override
     public void onAnimationFinished(boolean moveHomeToTop) {
-        mHandler.removeCallbacks(mCancelAnimationRunnable);
         synchronized (mService) {
             if (mWindowManager.getRecentsAnimationController() == null) return;
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 32b1d1a..7a6d964 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -17,6 +17,7 @@
 package com.android.server.broadcastradio.hal1;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.radio.ITuner;
 import android.hardware.radio.ITunerCallback;
 import android.hardware.radio.ProgramList;
@@ -87,8 +88,9 @@
         mTuner.close();
     }
 
-    void startProgramListUpdates(@NonNull ProgramList.Filter filter) {
-        mProgramListFilter.set(Objects.requireNonNull(filter));
+    void startProgramListUpdates(@Nullable ProgramList.Filter filter) {
+        if (filter == null) filter = new ProgramList.Filter();
+        mProgramListFilter.set(filter);
         sendProgramListUpdate();
     }
 
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
index 6919282..9730c9a 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/Convert.java
@@ -232,6 +232,7 @@
                  * HAL implementation instance. */
                 1,      // numTuners
                 1,      // numAudioSources
+                false,  // isInitializationRequired
                 false,  // isCaptureSupported
 
                 amfmConfigToBands(amfmConfig),
@@ -374,7 +375,9 @@
         );
     }
 
-    static @NonNull ProgramFilter programFilterToHal(@NonNull ProgramList.Filter filter) {
+    static @NonNull ProgramFilter programFilterToHal(@Nullable ProgramList.Filter filter) {
+        if (filter == null) filter = new ProgramList.Filter();
+
         ProgramFilter hwFilter = new ProgramFilter();
 
         filter.getIdentifierTypes().stream().forEachOrdered(hwFilter.identifierTypes::add);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c4b2b5e..c7ae1f4 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -695,6 +695,27 @@
         }
     }
 
+    private void setSaturationLevelInternal(float level) {
+        if (level < 0 || level > 1) {
+            throw new IllegalArgumentException("Saturation level must be between 0 and 1");
+        }
+        float[] matrix = (level == 1.0f ? null : computeSaturationMatrix(level));
+        DisplayTransformManager dtm = LocalServices.getService(DisplayTransformManager.class);
+        dtm.setColorMatrix(DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION, matrix);
+    }
+
+    private static float[] computeSaturationMatrix(float saturation) {
+        float desaturation = 1.0f - saturation;
+        float[] luminance = {0.231f * desaturation, 0.715f * desaturation, 0.072f * desaturation};
+        float[] matrix = {
+            luminance[0] + saturation, luminance[0], luminance[0], 0,
+            luminance[1], luminance[1] + saturation, luminance[1], 0,
+            luminance[2], luminance[2], luminance[2] + saturation, 0,
+            0, 0, 0, 1
+        };
+        return matrix;
+    }
+
     private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
             IMediaProjection projection, int callingUid, String packageName, String name, int width,
             int height, int densityDpi, Surface surface, int flags, String uniqueId) {
@@ -1687,6 +1708,19 @@
         }
 
         @Override // Binder call
+        public void setSaturationLevel(float level) {
+            mContext.enforceCallingOrSelfPermission(
+                   Manifest.permission.CONTROL_DISPLAY_SATURATION,
+                   "Permission required to set display saturation level");
+            final long token = Binder.clearCallingIdentity();
+            try {
+                setSaturationLevelInternal(level);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override // Binder call
         public int createVirtualDisplay(IVirtualDisplayCallback callback,
                 IMediaProjection projection, String packageName, String name,
                 int width, int height, int densityDpi, Surface surface, int flags,
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index 000fcf3..a94f049 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -17,7 +17,6 @@
 package com.android.server.display;
 
 import android.app.ActivityManager;
-import android.app.IActivityManager;
 import android.opengl.Matrix;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -28,7 +27,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
-
 import com.android.internal.app.ColorDisplayController;
 import java.util.Arrays;
 
@@ -46,6 +44,10 @@
      */
     public static final int LEVEL_COLOR_MATRIX_NIGHT_DISPLAY = 100;
     /**
+     * Color transform level used to adjust the color saturation of the display.
+     */
+    public static final int LEVEL_COLOR_MATRIX_SATURATION = 150;
+    /**
      * Color transform level used by A11y services to make the display monochromatic.
      */
     public static final int LEVEL_COLOR_MATRIX_GRAYSCALE = 200;
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 3374b30..c445f73 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -2576,9 +2576,9 @@
             // register for connectivity change events, this is equivalent to the deprecated way of
             // registering for CONNECTIVITY_ACTION broadcasts
             NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
-            networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
+            networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+            networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+            networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
             NetworkRequest networkRequest = networkRequestBuilder.build();
             mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
index 30125f8..77d7c3c 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java
@@ -31,7 +31,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.os.Binder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.os.UserHandle;
@@ -100,7 +99,6 @@
     private final RecoverableKeyGenerator mRecoverableKeyGenerator;
     private final RecoverySnapshotStorage mSnapshotStorage;
     private final PlatformKeyManager mPlatformKeyManager;
-    private final KeyStore mKeyStore;
     private final ApplicationKeyStorage mApplicationKeyStorage;
 
     /**
@@ -126,11 +124,10 @@
 
             mInstance = new RecoverableKeyStoreManager(
                     context.getApplicationContext(),
-                    keystore,
                     db,
                     new RecoverySessionStorage(),
                     Executors.newSingleThreadExecutor(),
-                    new RecoverySnapshotStorage(),
+                    RecoverySnapshotStorage.newInstance(),
                     new RecoverySnapshotListenersStorage(),
                     platformKeyManager,
                     applicationKeyStorage);
@@ -141,7 +138,6 @@
     @VisibleForTesting
     RecoverableKeyStoreManager(
             Context context,
-            KeyStore keystore,
             RecoverableKeyStoreDb recoverableKeyStoreDb,
             RecoverySessionStorage recoverySessionStorage,
             ExecutorService executorService,
@@ -150,7 +146,6 @@
             PlatformKeyManager platformKeyManager,
             ApplicationKeyStorage applicationKeyStorage) {
         mContext = context;
-        mKeyStore = keystore;
         mDatabase = recoverableKeyStoreDb;
         mRecoverySessionStorage = recoverySessionStorage;
         mExecutorService = executorService;
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
new file mode 100644
index 0000000..f789155
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotDeserializer.java
@@ -0,0 +1,409 @@
+/*
+ * 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 com.android.server.locksettings.recoverablekeystore.serialization;
+
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERTIFICATE_FACTORY_TYPE;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS;
+
+import static com.android.server.locksettings.recoverablekeystore.serialization
+        .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE;
+
+import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
+import android.security.keystore.recovery.WrappedApplicationKey;
+import android.util.Base64;
+import android.util.Xml;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Deserializes a {@link android.security.keystore.recovery.KeyChainSnapshot} instance from XML.
+ */
+public class KeyChainSnapshotDeserializer {
+
+    /**
+     * Deserializes a {@link KeyChainSnapshot} instance from the XML in the {@code inputStream}.
+     *
+     * @throws IOException if there is an IO error reading from the stream.
+     * @throws KeyChainSnapshotParserException if the XML does not conform to the expected XML for
+     *     a snapshot.
+     */
+    public static KeyChainSnapshot deserialize(InputStream inputStream)
+            throws KeyChainSnapshotParserException, IOException {
+        try {
+            return deserializeInternal(inputStream);
+        } catch (XmlPullParserException e) {
+            throw new KeyChainSnapshotParserException("Malformed KeyChainSnapshot XML", e);
+        }
+    }
+
+    private static KeyChainSnapshot deserializeInternal(InputStream inputStream) throws IOException,
+            XmlPullParserException, KeyChainSnapshotParserException {
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(inputStream, OUTPUT_ENCODING);
+
+        parser.nextTag();
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
+
+        KeyChainSnapshot.Builder builder = new KeyChainSnapshot.Builder();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            switch (name) {
+                case TAG_SNAPSHOT_VERSION:
+                    builder.setSnapshotVersion(readIntTag(parser, TAG_SNAPSHOT_VERSION));
+                    break;
+
+                case TAG_RECOVERY_KEY_MATERIAL:
+                    builder.setEncryptedRecoveryKeyBlob(
+                            readBlobTag(parser, TAG_RECOVERY_KEY_MATERIAL));
+                    break;
+
+                case TAG_COUNTER_ID:
+                    builder.setCounterId(readLongTag(parser, TAG_COUNTER_ID));
+                    break;
+
+                case TAG_SERVER_PARAMS:
+                    builder.setServerParams(readBlobTag(parser, TAG_SERVER_PARAMS));
+                    break;
+
+                case TAG_MAX_ATTEMPTS:
+                    builder.setMaxAttempts(readIntTag(parser, TAG_MAX_ATTEMPTS));
+                    break;
+
+                case TAG_TRUSTED_HARDWARE_CERT_PATH:
+                    try {
+                        builder.setTrustedHardwareCertPath(
+                                readCertPathTag(parser, TAG_TRUSTED_HARDWARE_CERT_PATH));
+                    } catch (CertificateException e) {
+                        throw new KeyChainSnapshotParserException(
+                                "Could not set trustedHardwareCertPath", e);
+                    }
+                    break;
+
+                case TAG_BACKEND_PUBLIC_KEY:
+                    builder.setTrustedHardwarePublicKey(
+                            readBlobTag(parser, TAG_BACKEND_PUBLIC_KEY));
+                    break;
+
+                case TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST:
+                    builder.setKeyChainProtectionParams(readKeyChainProtectionParamsList(parser));
+                    break;
+
+                case TAG_APPLICATION_KEYS:
+                    builder.setWrappedApplicationKeys(readWrappedApplicationKeys(parser));
+                    break;
+
+                default:
+                    throw new KeyChainSnapshotParserException(String.format(
+                            Locale.US, "Unexpected tag %s in keyChainSnapshot", name));
+            }
+        }
+
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
+        try {
+            return builder.build();
+        } catch (NullPointerException e) {
+            throw new KeyChainSnapshotParserException("Failed to build KeyChainSnapshot", e);
+        }
+    }
+
+    private static List<WrappedApplicationKey> readWrappedApplicationKeys(XmlPullParser parser)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEYS);
+        ArrayList<WrappedApplicationKey> keys = new ArrayList<>();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            keys.add(readWrappedApplicationKey(parser));
+        }
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_APPLICATION_KEYS);
+        return keys;
+    }
+
+    private static WrappedApplicationKey readWrappedApplicationKey(XmlPullParser parser)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_APPLICATION_KEY);
+        WrappedApplicationKey.Builder builder = new WrappedApplicationKey.Builder();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            switch (name) {
+                case TAG_ALIAS:
+                    builder.setAlias(readStringTag(parser, TAG_ALIAS));
+                    break;
+
+                case TAG_KEY_MATERIAL:
+                    builder.setEncryptedKeyMaterial(readBlobTag(parser, TAG_KEY_MATERIAL));
+                    break;
+
+                default:
+                    throw new KeyChainSnapshotParserException(String.format(
+                            Locale.US, "Unexpected tag %s in wrappedApplicationKey", name));
+            }
+        }
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_APPLICATION_KEY);
+
+        try {
+            return builder.build();
+        } catch (NullPointerException e) {
+            throw new KeyChainSnapshotParserException("Failed to build WrappedApplicationKey", e);
+        }
+    }
+
+    private static List<KeyChainProtectionParams> readKeyChainProtectionParamsList(
+            XmlPullParser parser) throws IOException, XmlPullParserException,
+            KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
+
+        ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList = new ArrayList<>();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            keyChainProtectionParamsList.add(readKeyChainProtectionParams(parser));
+        }
+
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
+        return keyChainProtectionParamsList;
+    }
+
+    private static KeyChainProtectionParams readKeyChainProtectionParams(XmlPullParser parser)
+        throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
+
+        KeyChainProtectionParams.Builder builder = new KeyChainProtectionParams.Builder();
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            switch (name) {
+                case TAG_LOCK_SCREEN_UI_TYPE:
+                    builder.setLockScreenUiFormat(readIntTag(parser, TAG_LOCK_SCREEN_UI_TYPE));
+                    break;
+
+                case TAG_USER_SECRET_TYPE:
+                    builder.setUserSecretType(readIntTag(parser, TAG_USER_SECRET_TYPE));
+                    break;
+
+                case TAG_KEY_DERIVATION_PARAMS:
+                    builder.setKeyDerivationParams(readKeyDerivationParams(parser));
+                    break;
+
+                default:
+                    throw new KeyChainSnapshotParserException(String.format(
+                            Locale.US,
+                            "Unexpected tag %s in keyChainProtectionParams",
+                            name));
+
+            }
+        }
+
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
+
+        try {
+            return builder.build();
+        } catch (NullPointerException e) {
+            throw new KeyChainSnapshotParserException(
+                    "Failed to build KeyChainProtectionParams", e);
+        }
+    }
+
+    private static KeyDerivationParams readKeyDerivationParams(XmlPullParser parser)
+            throws XmlPullParserException, IOException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
+
+        int memoryDifficulty = -1;
+        int algorithm = -1;
+        byte[] salt = null;
+
+        while (parser.next() != XmlPullParser.END_TAG) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            String name = parser.getName();
+
+            switch (name) {
+                case TAG_MEMORY_DIFFICULTY:
+                    memoryDifficulty = readIntTag(parser, TAG_MEMORY_DIFFICULTY);
+                    break;
+
+                case TAG_ALGORITHM:
+                    algorithm = readIntTag(parser, TAG_ALGORITHM);
+                    break;
+
+                case TAG_SALT:
+                    salt = readBlobTag(parser, TAG_SALT);
+                    break;
+
+                default:
+                    throw new KeyChainSnapshotParserException(
+                            String.format(
+                                    Locale.US,
+                                    "Unexpected tag %s in keyDerivationParams",
+                                    name));
+            }
+        }
+
+        if (salt == null) {
+            throw new KeyChainSnapshotParserException("salt was not set in keyDerivationParams");
+        }
+
+        KeyDerivationParams keyDerivationParams = null;
+
+        switch (algorithm) {
+            case KeyDerivationParams.ALGORITHM_SHA256:
+                keyDerivationParams = KeyDerivationParams.createSha256Params(salt);
+                break;
+
+            case KeyDerivationParams.ALGORITHM_SCRYPT:
+                keyDerivationParams = KeyDerivationParams.createScryptParams(
+                        salt, memoryDifficulty);
+                break;
+
+            default:
+                throw new KeyChainSnapshotParserException(
+                        "Unknown algorithm in keyDerivationParams");
+        }
+
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
+        return keyDerivationParams;
+    }
+
+    private static int readIntTag(XmlPullParser parser, String tagName)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName);
+        try {
+            return Integer.valueOf(text);
+        } catch (NumberFormatException e) {
+            throw new KeyChainSnapshotParserException(
+                    String.format(
+                            Locale.US, "%s expected int but got '%s'", tagName, text), e);
+        }
+    }
+
+    private static long readLongTag(XmlPullParser parser, String tagName)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName);
+        try {
+            return Long.valueOf(text);
+        } catch (NumberFormatException e) {
+            throw new KeyChainSnapshotParserException(
+                    String.format(
+                            Locale.US, "%s expected long but got '%s'", tagName, text), e);
+        }
+    }
+
+    private static String readStringTag(XmlPullParser parser, String tagName)
+            throws IOException, XmlPullParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName);
+        return text;
+    }
+
+    private static byte[] readBlobTag(XmlPullParser parser, String tagName)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        parser.require(XmlPullParser.START_TAG, NAMESPACE, tagName);
+        String text = readText(parser);
+        parser.require(XmlPullParser.END_TAG, NAMESPACE, tagName);
+
+        try {
+            return Base64.decode(text, /*flags=*/ Base64.DEFAULT);
+        } catch (IllegalArgumentException e) {
+            throw new KeyChainSnapshotParserException(
+                    String.format(
+                            Locale.US,
+                            "%s expected base64 encoded bytes but got '%s'",
+                            tagName, text), e);
+        }
+    }
+
+    private static CertPath readCertPathTag(XmlPullParser parser, String tagName)
+            throws IOException, XmlPullParserException, KeyChainSnapshotParserException {
+        byte[] bytes = readBlobTag(parser, tagName);
+        try {
+            return CertificateFactory.getInstance(CERTIFICATE_FACTORY_TYPE)
+                    .generateCertPath(new ByteArrayInputStream(bytes));
+        } catch (CertificateException e) {
+            throw new KeyChainSnapshotParserException("Could not parse CertPath in tag " + tagName,
+                    e);
+        }
+    }
+
+    private static String readText(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        String result = "";
+        if (parser.next() == XmlPullParser.TEXT) {
+            result = parser.getText();
+            parser.nextTag();
+        }
+        return result;
+    }
+
+    // Statics only
+    private KeyChainSnapshotDeserializer() {}
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.java
new file mode 100644
index 0000000..a3208af
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotParserException.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 com.android.server.locksettings.recoverablekeystore.serialization;
+
+/**
+ * Error thrown when parsing invalid XML, while trying to read a
+ * {@link android.security.keystore.recovery.KeyChainSnapshot}.
+ */
+public class KeyChainSnapshotParserException extends Exception {
+
+    public KeyChainSnapshotParserException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public KeyChainSnapshotParserException(String message) {
+        super(message);
+    }
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
new file mode 100644
index 0000000..ff30ecd
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSchema.java
@@ -0,0 +1,58 @@
+/*
+ * 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 com.android.server.locksettings.recoverablekeystore.serialization;
+
+/**
+ * Describes the XML schema of the {@link android.security.keystore.recovery.KeyChainSnapshot} file.
+ */
+class KeyChainSnapshotSchema {
+    static final String NAMESPACE = null;
+
+    static final String OUTPUT_ENCODING = "UTF-8";
+
+    static final String CERTIFICATE_FACTORY_TYPE = "X.509";
+    static final String CERT_PATH_ENCODING = "PkiPath";
+
+    static final String TAG_KEY_CHAIN_SNAPSHOT = "keyChainSnapshot";
+
+    static final String TAG_SNAPSHOT_VERSION = "snapshotVersion";
+    static final String TAG_COUNTER_ID = "counterId";
+    static final String TAG_MAX_ATTEMPTS = "maxAttempts";
+    static final String TAG_RECOVERY_KEY_MATERIAL = "recoveryKeyMaterial";
+    static final String TAG_SERVER_PARAMS = "serverParams";
+    static final String TAG_TRUSTED_HARDWARE_CERT_PATH = "thmCertPath";
+    static final String TAG_BACKEND_PUBLIC_KEY = "backendPublicKey";
+
+    static final String TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST =
+            "keyChainProtectionParamsList";
+    static final String TAG_KEY_CHAIN_PROTECTION_PARAMS = "keyChainProtectionParams";
+    static final String TAG_USER_SECRET_TYPE = "userSecretType";
+    static final String TAG_LOCK_SCREEN_UI_TYPE = "lockScreenUiType";
+
+    static final String TAG_KEY_DERIVATION_PARAMS = "keyDerivationParams";
+    static final String TAG_ALGORITHM = "algorithm";
+    static final String TAG_MEMORY_DIFFICULTY = "memoryDifficulty";
+    static final String TAG_SALT = "salt";
+
+    static final String TAG_APPLICATION_KEYS = "applicationKeysList";
+    static final String TAG_APPLICATION_KEY = "applicationKey";
+    static final String TAG_ALIAS = "alias";
+    static final String TAG_KEY_MATERIAL = "keyMaterial";
+
+    // Statics only
+    private KeyChainSnapshotSchema() {}
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
new file mode 100644
index 0000000..17a16bf
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializer.java
@@ -0,0 +1,203 @@
+/*
+ * 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 com.android.server.locksettings.recoverablekeystore.serialization;
+
+
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.CERT_PATH_ENCODING;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.NAMESPACE;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.OUTPUT_ENCODING;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALGORITHM;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_ALIAS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_APPLICATION_KEYS;
+
+import static com.android.server.locksettings.recoverablekeystore.serialization
+        .KeyChainSnapshotSchema.TAG_BACKEND_PUBLIC_KEY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_COUNTER_ID;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_RECOVERY_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_CHAIN_SNAPSHOT;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_DERIVATION_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_KEY_MATERIAL;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_LOCK_SCREEN_UI_TYPE;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MAX_ATTEMPTS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_MEMORY_DIFFICULTY;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SALT;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SERVER_PARAMS;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_SNAPSHOT_VERSION;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_TRUSTED_HARDWARE_CERT_PATH;
+import static com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSchema.TAG_USER_SECRET_TYPE;
+
+import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
+import android.security.keystore.recovery.WrappedApplicationKey;
+import android.util.Base64;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateEncodingException;
+import java.util.List;
+
+/**
+ * Serializes a {@link KeyChainSnapshot} instance to XML.
+ */
+public class KeyChainSnapshotSerializer {
+
+    /**
+     * Serializes {@code keyChainSnapshot} to XML, writing to {@code outputStream}.
+     *
+     * @throws IOException if there was an IO error writing to the stream.
+     * @throws CertificateEncodingException if the {@link CertPath} from
+     *     {@link KeyChainSnapshot#getTrustedHardwareCertPath()} is not encoded correctly.
+     */
+    public static void serialize(KeyChainSnapshot keyChainSnapshot, OutputStream outputStream)
+            throws IOException, CertificateEncodingException {
+        XmlSerializer xmlSerializer = Xml.newSerializer();
+        xmlSerializer.setOutput(outputStream, OUTPUT_ENCODING);
+        xmlSerializer.startDocument(
+                /*encoding=*/ null,
+                /*standalone=*/ null);
+        xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
+        writeKeyChainSnapshotProperties(xmlSerializer, keyChainSnapshot);
+        writeKeyChainProtectionParams(xmlSerializer,
+                keyChainSnapshot.getKeyChainProtectionParams());
+        writeApplicationKeys(xmlSerializer,
+                keyChainSnapshot.getWrappedApplicationKeys());
+        xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_SNAPSHOT);
+        xmlSerializer.endDocument();
+    }
+
+    private static void writeApplicationKeys(
+            XmlSerializer xmlSerializer, List<WrappedApplicationKey> wrappedApplicationKeys)
+            throws IOException {
+        xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEYS);
+        for (WrappedApplicationKey key : wrappedApplicationKeys) {
+            xmlSerializer.startTag(NAMESPACE, TAG_APPLICATION_KEY);
+            writeApplicationKeyProperties(xmlSerializer, key);
+            xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEY);
+        }
+        xmlSerializer.endTag(NAMESPACE, TAG_APPLICATION_KEYS);
+    }
+
+    private static void writeApplicationKeyProperties(
+            XmlSerializer xmlSerializer, WrappedApplicationKey applicationKey) throws IOException {
+        writePropertyTag(xmlSerializer, TAG_ALIAS, applicationKey.getAlias());
+        writePropertyTag(xmlSerializer, TAG_KEY_MATERIAL, applicationKey.getEncryptedKeyMaterial());
+    }
+
+    private static void writeKeyChainProtectionParams(
+            XmlSerializer xmlSerializer,
+            List<KeyChainProtectionParams> keyChainProtectionParamsList) throws IOException {
+        xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
+        for (KeyChainProtectionParams keyChainProtectionParams : keyChainProtectionParamsList) {
+            xmlSerializer.startTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
+            writeKeyChainProtectionParamsProperties(xmlSerializer, keyChainProtectionParams);
+            xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS);
+        }
+        xmlSerializer.endTag(NAMESPACE, TAG_KEY_CHAIN_PROTECTION_PARAMS_LIST);
+    }
+
+    private static void writeKeyChainProtectionParamsProperties(
+            XmlSerializer xmlSerializer, KeyChainProtectionParams keyChainProtectionParams)
+            throws IOException {
+        writePropertyTag(xmlSerializer, TAG_USER_SECRET_TYPE,
+                keyChainProtectionParams.getUserSecretType());
+        writePropertyTag(xmlSerializer, TAG_LOCK_SCREEN_UI_TYPE,
+                keyChainProtectionParams.getLockScreenUiFormat());
+
+        // NOTE: Do not serialize the 'secret' field. It should never be set anyway for snapshots
+        // we generate.
+
+        writeKeyDerivationParams(xmlSerializer, keyChainProtectionParams.getKeyDerivationParams());
+    }
+
+    private static void writeKeyDerivationParams(
+            XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+            throws IOException {
+        xmlSerializer.startTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
+        writeKeyDerivationParamsProperties(
+                xmlSerializer, keyDerivationParams);
+        xmlSerializer.endTag(NAMESPACE, TAG_KEY_DERIVATION_PARAMS);
+    }
+
+    private static void writeKeyDerivationParamsProperties(
+            XmlSerializer xmlSerializer, KeyDerivationParams keyDerivationParams)
+            throws IOException {
+        writePropertyTag(xmlSerializer, TAG_ALGORITHM, keyDerivationParams.getAlgorithm());
+        writePropertyTag(xmlSerializer, TAG_SALT, keyDerivationParams.getSalt());
+        writePropertyTag(xmlSerializer, TAG_MEMORY_DIFFICULTY,
+                keyDerivationParams.getMemoryDifficulty());
+    }
+
+    private static void writeKeyChainSnapshotProperties(
+            XmlSerializer xmlSerializer, KeyChainSnapshot keyChainSnapshot)
+            throws IOException, CertificateEncodingException {
+
+        writePropertyTag(xmlSerializer, TAG_SNAPSHOT_VERSION,
+                keyChainSnapshot.getSnapshotVersion());
+        writePropertyTag(xmlSerializer, TAG_MAX_ATTEMPTS, keyChainSnapshot.getMaxAttempts());
+        writePropertyTag(xmlSerializer, TAG_COUNTER_ID, keyChainSnapshot.getCounterId());
+        writePropertyTag(xmlSerializer, TAG_RECOVERY_KEY_MATERIAL,
+                keyChainSnapshot.getEncryptedRecoveryKeyBlob());
+        writePropertyTag(xmlSerializer, TAG_SERVER_PARAMS, keyChainSnapshot.getServerParams());
+        writePropertyTag(xmlSerializer, TAG_TRUSTED_HARDWARE_CERT_PATH,
+                keyChainSnapshot.getTrustedHardwareCertPath());
+        if (keyChainSnapshot.getTrustedHardwarePublicKey() != null) {
+            writePropertyTag(xmlSerializer, TAG_BACKEND_PUBLIC_KEY,
+                    keyChainSnapshot.getTrustedHardwarePublicKey());
+        }
+    }
+
+    private static void writePropertyTag(
+            XmlSerializer xmlSerializer, String propertyName, long propertyValue)
+            throws IOException {
+        xmlSerializer.startTag(NAMESPACE, propertyName);
+        xmlSerializer.text(Long.toString(propertyValue));
+        xmlSerializer.endTag(NAMESPACE, propertyName);
+    }
+
+    private static void writePropertyTag(
+            XmlSerializer xmlSerializer, String propertyName, String propertyValue)
+            throws IOException {
+        xmlSerializer.startTag(NAMESPACE, propertyName);
+        xmlSerializer.text(propertyValue);
+        xmlSerializer.endTag(NAMESPACE, propertyName);
+    }
+
+    private static void writePropertyTag(
+            XmlSerializer xmlSerializer, String propertyName, byte[] propertyValue)
+            throws IOException {
+        xmlSerializer.startTag(NAMESPACE, propertyName);
+        xmlSerializer.text(Base64.encodeToString(propertyValue, /*flags=*/ Base64.DEFAULT));
+        xmlSerializer.endTag(NAMESPACE, propertyName);
+    }
+
+    private static void writePropertyTag(
+            XmlSerializer xmlSerializer, String propertyName, CertPath certPath)
+            throws IOException, CertificateEncodingException {
+        writePropertyTag(xmlSerializer, propertyName, certPath.getEncoded(CERT_PATH_ENCODING));
+    }
+
+    // Statics only
+    private KeyChainSnapshotSerializer() {}
+}
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
index 1eff2d4..7ee809a 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java
@@ -70,121 +70,6 @@
     }
 
     /**
-     * Table holding encrypted snapshots of the recoverable key store.
-     */
-    static class SnapshotsEntry implements BaseColumns {
-        static final String TABLE_NAME = "snapshots";
-
-        /**
-         * The version number of the snapshot.
-         */
-        static final String COLUMN_NAME_VERSION = "version";
-
-        /**
-         * The ID of the user whose keystore was snapshotted.
-         */
-        static final String COLUMN_NAME_USER_ID = "user_id";
-
-        /**
-         * The UID of the app that owns the snapshot (i.e., the recovery agent).
-         */
-        static final String COLUMN_NAME_UID = "uid";
-
-        /**
-         * The maximum number of attempts allowed to attempt to decrypt the recovery key.
-         */
-        static final String COLUMN_NAME_MAX_ATTEMPTS = "max_attempts";
-
-        /**
-         * The ID of the counter in the trusted hardware module.
-         */
-        static final String COLUMN_NAME_COUNTER_ID = "counter_id";
-
-        /**
-         * Server parameters used to help identify the device (during recovery).
-         */
-        static final String SERVER_PARAMS = "server_params";
-
-        /**
-         * The public key of the trusted hardware module. This key has been used to encrypt the
-         * snapshot, to ensure that it can only be read by the trusted module.
-         */
-        static final String TRUSTED_HARDWARE_PUBLIC_KEY = "thm_public_key";
-
-        /**
-         * {@link java.security.cert.CertPath} signing the trusted hardware module to whose public
-         * key this snapshot is encrypted.
-         */
-        static final String CERT_PATH = "cert_path";
-
-        /**
-         * The recovery key, encrypted with the user's lock screen and the trusted hardware module's
-         * public key.
-         */
-        static final String ENCRYPTED_RECOVERY_KEY = "encrypted_recovery_key";
-    }
-
-    /**
-     * Table holding encrypted keys belonging to a particular snapshot.
-     */
-    static class SnapshotKeysEntry implements BaseColumns {
-        static final String TABLE_NAME = "snapshot_keys";
-
-        /**
-         * ID of the associated snapshot entry in {@link SnapshotsEntry}.
-         */
-        static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id";
-
-        /**
-         * Alias of the key.
-         */
-        static final String COLUMN_NAME_ALIAS = "alias";
-
-        /**
-         * Key material, encrypted with the recovery key from the snapshot.
-         */
-        static final String COLUMN_NAME_ENCRYPTED_BYTES = "encrypted_key_bytes";
-    }
-
-    /**
-     * A layer of protection associated with a snapshot.
-     */
-    static class SnapshotProtectionParams implements BaseColumns {
-        static final String TABLE_NAME = "snapshot_protection_params";
-
-        /**
-         * ID of the associated snapshot entry in {@link SnapshotsEntry}.
-         */
-        static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id";
-
-        /**
-         * Type of secret used to generate recovery key. One of
-         * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} or
-         */
-        static final String COLUMN_NAME_SECRET_TYPE = "secret_type";
-
-        /**
-         * If a lock screen, the type of UI used. One of
-         * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PATTERN},
-         * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PIN}, or
-         * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PASSWORD}.
-         */
-        static final String COLUMN_NAME_LOCKSCREEN_UI_TYPE = "lock_screen_ui_type";
-
-        /**
-         * The algorithm used to derive cryptographic material from the key and salt. One of
-         * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or
-         * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SCRYPT}.
-         */
-        static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm";
-
-        /**
-         * The salt used along with the secret to generate cryptographic material.
-         */
-        static final String COLUMN_NAME_KEY_DERIVATION_SALT = "key_derivation_salt";
-    }
-
-    /**
      * Recoverable KeyStore metadata for a specific user profile.
      */
     static class UserMetadataEntry implements BaseColumns {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
index 3f93cc6..c02b103 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorage.java
@@ -17,13 +17,28 @@
 package com.android.server.locksettings.recoverablekeystore.storage;
 
 import android.annotation.Nullable;
+import android.os.Environment;
 import android.security.keystore.recovery.KeyChainSnapshot;
+import android.util.Log;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.locksettings.recoverablekeystore.serialization
+        .KeyChainSnapshotDeserializer;
+import com.android.server.locksettings.recoverablekeystore.serialization
+        .KeyChainSnapshotParserException;
+import com.android.server.locksettings.recoverablekeystore.serialization.KeyChainSnapshotSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.cert.CertificateEncodingException;
+import java.util.Locale;
 
 /**
- * In-memory storage for recovery snapshots.
+ * Storage for recovery snapshots. Stores snapshots in memory, backed by disk storage.
  *
  * <p>Recovery snapshots are generated after a successful screen unlock. They are only generated if
  * the recoverable keystore has been mutated since the previous snapshot. This class stores only the
@@ -33,14 +48,46 @@
  * {@link com.android.server.locksettings.recoverablekeystore.KeySyncTask} thread.
  */
 public class RecoverySnapshotStorage {
+
+    private static final String TAG = "RecoverySnapshotStorage";
+
+    private static final String ROOT_PATH = "system";
+    private static final String STORAGE_PATH = "recoverablekeystore/snapshots/";
+
     @GuardedBy("this")
     private final SparseArray<KeyChainSnapshot> mSnapshotByUid = new SparseArray<>();
 
+    private final File rootDirectory;
+
+    /**
+     * A new instance, storing snapshots in /data/system/recoverablekeystore/snapshots.
+     *
+     * <p>NOTE: calling this multiple times DOES NOT return the same instance, so will NOT be backed
+     * by the same in-memory store.
+     */
+    public static RecoverySnapshotStorage newInstance() {
+        return new RecoverySnapshotStorage(
+                new File(Environment.getDataDirectory(), ROOT_PATH));
+    }
+
+    @VisibleForTesting
+    public RecoverySnapshotStorage(File rootDirectory) {
+        this.rootDirectory = rootDirectory;
+    }
+
     /**
      * Sets the latest {@code snapshot} for the recovery agent {@code uid}.
      */
     public synchronized void put(int uid, KeyChainSnapshot snapshot) {
         mSnapshotByUid.put(uid, snapshot);
+
+        try {
+            writeToDisk(uid, snapshot);
+        } catch (IOException | CertificateEncodingException e) {
+            Log.e(TAG,
+                    String.format(Locale.US, "Error persisting snapshot for %d to disk", uid),
+                    e);
+        }
     }
 
     /**
@@ -48,7 +95,17 @@
      */
     @Nullable
     public synchronized KeyChainSnapshot get(int uid) {
-        return mSnapshotByUid.get(uid);
+        KeyChainSnapshot snapshot = mSnapshotByUid.get(uid);
+        if (snapshot != null) {
+            return snapshot;
+        }
+
+        try {
+            return readFromDisk(uid);
+        } catch (IOException | KeyChainSnapshotParserException e) {
+            Log.e(TAG, String.format(Locale.US, "Error reading snapshot for %d from disk", uid), e);
+            return null;
+        }
     }
 
     /**
@@ -56,5 +113,66 @@
      */
     public synchronized void remove(int uid) {
         mSnapshotByUid.remove(uid);
+        getSnapshotFile(uid).delete();
+    }
+
+    /**
+     * Writes the snapshot for recovery agent {@code uid} to disk.
+     *
+     * @throws IOException if an IO error occurs writing to disk.
+     */
+    private void writeToDisk(int uid, KeyChainSnapshot snapshot)
+            throws IOException, CertificateEncodingException {
+        File snapshotFile = getSnapshotFile(uid);
+
+        try (
+            FileOutputStream fileOutputStream = new FileOutputStream(snapshotFile)
+        ) {
+            KeyChainSnapshotSerializer.serialize(snapshot, fileOutputStream);
+        } catch (IOException | CertificateEncodingException e) {
+            // If we fail to write the latest snapshot, we should delete any older snapshot that
+            // happens to be around. Otherwise snapshot syncs might end up going 'back in time'.
+            snapshotFile.delete();
+            throw e;
+        }
+    }
+
+    /**
+     * Reads the last snapshot for recovery agent {@code uid} from disk.
+     *
+     * @return The snapshot, or null if none existed.
+     * @throws IOException if an IO error occurs reading from disk.
+     */
+    @Nullable
+    private KeyChainSnapshot readFromDisk(int uid)
+            throws IOException, KeyChainSnapshotParserException {
+        File snapshotFile = getSnapshotFile(uid);
+
+        try (
+            FileInputStream fileInputStream = new FileInputStream(snapshotFile)
+        ) {
+            return KeyChainSnapshotDeserializer.deserialize(fileInputStream);
+        } catch (IOException | KeyChainSnapshotParserException e) {
+            // If we fail to read the latest snapshot, we should delete it in case it is in some way
+            // corrupted. We can regenerate snapshots anyway.
+            snapshotFile.delete();
+            throw e;
+        }
+    }
+
+    private File getSnapshotFile(int uid) {
+        File folder = getStorageFolder();
+        String fileName = getSnapshotFileName(uid);
+        return new File(folder, fileName);
+    }
+
+    private String getSnapshotFileName(int uid) {
+        return String.format(Locale.US, "%d.xml", uid);
+    }
+
+    private File getStorageFolder() {
+        File folder = new File(rootDirectory, STORAGE_PATH);
+        folder.mkdirs();
+        return folder;
     }
 }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 664d2f9..0d1644b 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -71,8 +71,6 @@
      */
     private static final int OPTIMISTIC_VOLUME_TIMEOUT = 1000;
 
-    private static final int UID_NOT_SET = -1;
-
     private final MessageHandler mHandler;
 
     private final int mOwnerPid;
@@ -117,9 +115,6 @@
     private boolean mIsActive = false;
     private boolean mDestroyed = false;
 
-    private int mCallingUid = UID_NOT_SET;
-    private String mCallingPackage;
-
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
             ISessionCallback cb, String tag, MediaSessionService service, Looper handlerLooper) {
         mOwnerPid = ownerPid;
@@ -234,14 +229,14 @@
      * {@link AudioManager#ADJUST_LOWER}, {@link AudioManager#ADJUST_RAISE},
      * {@link AudioManager#ADJUST_SAME}.
      *
+     * @param packageName The package that made the original volume request.
+     * @param pid The pid that made the original volume request.
+     * @param uid The uid that made the original volume request.
      * @param direction The direction to adjust volume in.
      * @param flags Any of the flags from {@link AudioManager}.
-     * @param packageName The package that made the original volume request.
-     * @param uid The uid that made the original volume request.
      * @param useSuggested True to use adjustSuggestedStreamVolume instead of
-     *            adjustStreamVolume.
      */
-    public void adjustVolume(int direction, int flags, String packageName, int uid,
+    public void adjustVolume(String packageName, int pid, int uid, int direction, int flags,
             boolean useSuggested) {
         int previousFlagPlaySound = flags & AudioManager.FLAG_PLAY_SOUND;
         if (isPlaybackActive() || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
@@ -263,7 +258,7 @@
                 Log.w(TAG, "Muting remote playback is not supported");
                 return;
             }
-            mSessionCb.adjustVolume(direction);
+            mSessionCb.adjustVolume(packageName, pid, uid, direction);
 
             int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
             mOptimisticVolume = volumeBefore + direction;
@@ -282,7 +277,7 @@
         }
     }
 
-    public void setVolumeTo(int value, int flags, String packageName, int uid) {
+    public void setVolumeTo(String packageName, int pid, int uid, int value, int flags) {
         if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
             int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
             mAudioManagerInternal.setStreamVolumeForUid(stream, value, flags, packageName, uid);
@@ -292,7 +287,7 @@
                 return;
             }
             value = Math.max(0, Math.min(value, mMaxVolume));
-            mSessionCb.setVolumeTo(value);
+            mSessionCb.setVolumeTo(packageName, pid, uid, value);
 
             int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
             mOptimisticVolume = Math.max(0, Math.min(value, mMaxVolume));
@@ -423,10 +418,9 @@
         return mSessionCb.mCb;
     }
 
-    public void sendMediaButton(KeyEvent ke, int sequenceId,
-            ResultReceiver cb, int uid, String packageName) {
-        updateCallingPackage(uid, packageName);
-        mSessionCb.sendMediaButton(ke, sequenceId, cb);
+    public void sendMediaButton(String packageName, int pid, int uid, KeyEvent ke, int sequenceId,
+            ResultReceiver cb) {
+        mSessionCb.sendMediaButton(packageName, pid, uid, ke, sequenceId, cb);
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -703,22 +697,6 @@
         return -1;
     }
 
-    private void updateCallingPackage() {
-        updateCallingPackage(UID_NOT_SET, null);
-    }
-
-    private void updateCallingPackage(int uid, String packageName) {
-        if (uid == UID_NOT_SET) {
-            uid = Binder.getCallingUid();
-        }
-        synchronized (mLock) {
-            if (mCallingUid == UID_NOT_SET || mCallingUid != uid) {
-                mCallingUid = uid;
-                mCallingPackage = packageName != null ? packageName : getPackageName(uid);
-            }
-        }
-    }
-
     private String getPackageName(int uid) {
         Context context = mService.getContext();
         if (context == null) {
@@ -920,11 +898,6 @@
                 mHandler.post(MessageHandler.MSG_UPDATE_VOLUME);
             }
         }
-
-        @Override
-        public String getCallingPackage() {
-            return mCallingPackage;
-        }
     }
 
     class SessionCb {
@@ -934,11 +907,12 @@
             mCb = cb;
         }
 
-        public boolean sendMediaButton(KeyEvent keyEvent, int sequenceId, ResultReceiver cb) {
+        public boolean sendMediaButton(String packageName, int pid, int uid, KeyEvent keyEvent,
+                int sequenceId, ResultReceiver cb) {
             Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
             mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
             try {
-                mCb.onMediaButton(mediaButtonIntent, sequenceId, cb);
+                mCb.onMediaButton(packageName, pid, uid, mediaButtonIntent, sequenceId, cb);
                 return true;
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendMediaRequest.", e);
@@ -946,169 +920,176 @@
             return false;
         }
 
-        public void sendCommand(String command, Bundle args, ResultReceiver cb) {
+        public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
+                ResultReceiver cb) {
             try {
-                mCb.onCommand(command, args, cb);
+                mCb.onCommand(packageName, pid, uid, command, args, cb);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendCommand.", e);
             }
         }
 
-        public void sendCustomAction(String action, Bundle args) {
+        public void sendCustomAction(String packageName, int pid, int uid, String action,
+                Bundle args) {
             try {
-                mCb.onCustomAction(action, args);
+                mCb.onCustomAction(packageName, pid, uid, action, args);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in sendCustomAction.", e);
             }
         }
 
-        public void prepare() {
+        public void prepare(String packageName, int pid, int uid) {
             try {
-                mCb.onPrepare();
+                mCb.onPrepare(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepare.", e);
             }
         }
 
-        public void prepareFromMediaId(String mediaId, Bundle extras) {
+        public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
+                Bundle extras) {
             try {
-                mCb.onPrepareFromMediaId(mediaId, extras);
+                mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromMediaId.", e);
             }
         }
 
-        public void prepareFromSearch(String query, Bundle extras) {
+        public void prepareFromSearch(String packageName, int pid, int uid, String query,
+                Bundle extras) {
             try {
-                mCb.onPrepareFromSearch(query, extras);
+                mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromSearch.", e);
             }
         }
 
-        public void prepareFromUri(Uri uri, Bundle extras) {
+        public void prepareFromUri(String packageName, int pid, int uid, Uri uri,
+                Bundle extras) {
             try {
-                mCb.onPrepareFromUri(uri, extras);
+                mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in prepareFromUri.", e);
             }
         }
 
-        public void play() {
+        public void play(String packageName, int pid, int uid) {
             try {
-                mCb.onPlay();
+                mCb.onPlay(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in play.", e);
             }
         }
 
-        public void playFromMediaId(String mediaId, Bundle extras) {
+        public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
+                Bundle extras) {
             try {
-                mCb.onPlayFromMediaId(mediaId, extras);
+                mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromMediaId.", e);
             }
         }
 
-        public void playFromSearch(String query, Bundle extras) {
+        public void playFromSearch(String packageName, int pid, int uid, String query,
+                Bundle extras) {
             try {
-                mCb.onPlayFromSearch(query, extras);
+                mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromSearch.", e);
             }
         }
 
-        public void playFromUri(Uri uri, Bundle extras) {
+        public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
             try {
-                mCb.onPlayFromUri(uri, extras);
+                mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playFromUri.", e);
             }
         }
 
-        public void skipToTrack(long id) {
+        public void skipToTrack(String packageName, int pid, int uid, long id) {
             try {
-                mCb.onSkipToTrack(id);
+                mCb.onSkipToTrack(packageName, pid, uid, id);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in skipToTrack", e);
             }
         }
 
-        public void pause() {
+        public void pause(String packageName, int pid, int uid) {
             try {
-                mCb.onPause();
+                mCb.onPause(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in pause.", e);
             }
         }
 
-        public void stop() {
+        public void stop(String packageName, int pid, int uid) {
             try {
-                mCb.onStop();
+                mCb.onStop(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in stop.", e);
             }
         }
 
-        public void next() {
+        public void next(String packageName, int pid, int uid) {
             try {
-                mCb.onNext();
+                mCb.onNext(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in next.", e);
             }
         }
 
-        public void previous() {
+        public void previous(String packageName, int pid, int uid) {
             try {
-                mCb.onPrevious();
+                mCb.onPrevious(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in previous.", e);
             }
         }
 
-        public void fastForward() {
+        public void fastForward(String packageName, int pid, int uid) {
             try {
-                mCb.onFastForward();
+                mCb.onFastForward(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in fastForward.", e);
             }
         }
 
-        public void rewind() {
+        public void rewind(String packageName, int pid, int uid) {
             try {
-                mCb.onRewind();
+                mCb.onRewind(packageName, pid, uid);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in rewind.", e);
             }
         }
 
-        public void seekTo(long pos) {
+        public void seekTo(String packageName, int pid, int uid, long pos) {
             try {
-                mCb.onSeekTo(pos);
+                mCb.onSeekTo(packageName, pid, uid, pos);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in seekTo.", e);
             }
         }
 
-        public void rate(Rating rating) {
+        public void rate(String packageName, int pid, int uid, Rating rating) {
             try {
-                mCb.onRate(rating);
+                mCb.onRate(packageName, pid, uid, rating);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in rate.", e);
             }
         }
 
-        public void adjustVolume(int direction) {
+        public void adjustVolume(String packageName, int pid, int uid, int direction) {
             try {
-                mCb.onAdjustVolume(direction);
+                mCb.onAdjustVolume(packageName, pid, uid, direction);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in adjustVolume.", e);
             }
         }
 
-        public void setVolumeTo(int value) {
+        public void setVolumeTo(String packageName, int pid, int uid, int value) {
             try {
-                mCb.onSetVolumeTo(value);
+                mCb.onSetVolumeTo(packageName, pid, uid, value);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in setVolumeTo.", e);
             }
@@ -1117,16 +1098,16 @@
 
     class ControllerStub extends ISessionController.Stub {
         @Override
-        public void sendCommand(String command, Bundle args, ResultReceiver cb)
-                throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.sendCommand(command, args, cb);
+        public void sendCommand(String packageName, String command, Bundle args,
+                ResultReceiver cb) {
+            mSessionCb.sendCommand(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    command, args, cb);
         }
 
         @Override
-        public boolean sendMediaButton(KeyEvent mediaButtonIntent) {
-            updateCallingPackage();
-            return mSessionCb.sendMediaButton(mediaButtonIntent, 0, null);
+        public boolean sendMediaButton(String packageName, KeyEvent mediaButtonIntent) {
+            return mSessionCb.sendMediaButton(packageName, Binder.getCallingPid(),
+                    Binder.getCallingUid(), mediaButtonIntent, 0, null);
         }
 
         @Override
@@ -1207,137 +1188,125 @@
         }
 
         @Override
-        public void adjustVolume(int direction, int flags, String packageName) {
-            updateCallingPackage();
+        public void adjustVolume(String packageName, int direction, int flags) {
+            int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.adjustVolume(direction, flags, packageName, uid, false);
+                MediaSessionRecord.this.adjustVolume(packageName, pid, uid, direction, flags,
+                        false /* useSuggested */);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
-        public void setVolumeTo(int value, int flags, String packageName) {
-            updateCallingPackage();
+        public void setVolumeTo(String packageName, int value, int flags) {
+            int pid = Binder.getCallingPid();
             int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
-                MediaSessionRecord.this.setVolumeTo(value, flags, packageName, uid);
+                MediaSessionRecord.this.setVolumeTo(packageName, pid, uid, value, flags);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         }
 
         @Override
-        public void prepare() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.prepare();
+        public void prepare(String packageName) {
+            mSessionCb.prepare(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void prepareFromMediaId(String mediaId, Bundle extras)
-                throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.prepareFromMediaId(mediaId, extras);
+        public void prepareFromMediaId(String packageName, String mediaId, Bundle extras) {
+            mSessionCb.prepareFromMediaId(packageName, Binder.getCallingPid(),
+                    Binder.getCallingUid(), mediaId, extras);
         }
 
         @Override
-        public void prepareFromSearch(String query, Bundle extras) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.prepareFromSearch(query, extras);
+        public void prepareFromSearch(String packageName, String query, Bundle extras) {
+            mSessionCb.prepareFromSearch(packageName, Binder.getCallingPid(),
+                    Binder.getCallingUid(), query, extras);
         }
 
         @Override
-        public void prepareFromUri(Uri uri, Bundle extras) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.prepareFromUri(uri, extras);
+        public void prepareFromUri(String packageName, Uri uri, Bundle extras) {
+            mSessionCb.prepareFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    uri, extras);
         }
 
         @Override
-        public void play() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.play();
+        public void play(String packageName) {
+            mSessionCb.play(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.playFromMediaId(mediaId, extras);
+        public void playFromMediaId(String packageName, String mediaId, Bundle extras) {
+            mSessionCb.playFromMediaId(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    mediaId, extras);
         }
 
         @Override
-        public void playFromSearch(String query, Bundle extras) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.playFromSearch(query, extras);
+        public void playFromSearch(String packageName, String query, Bundle extras) {
+            mSessionCb.playFromSearch(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    query, extras);
         }
 
         @Override
-        public void playFromUri(Uri uri, Bundle extras) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.playFromUri(uri, extras);
+        public void playFromUri(String packageName, Uri uri, Bundle extras) {
+            mSessionCb.playFromUri(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    uri, extras);
         }
 
         @Override
-        public void skipToQueueItem(long id) {
-            updateCallingPackage();
-            mSessionCb.skipToTrack(id);
+        public void skipToQueueItem(String packageName, long id) {
+            mSessionCb.skipToTrack(packageName, Binder.getCallingPid(), Binder.getCallingUid(), id);
         }
 
         @Override
-        public void pause() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.pause();
+        public void pause(String packageName) {
+            mSessionCb.pause(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void stop() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.stop();
+        public void stop(String packageName) {
+            mSessionCb.stop(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void next() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.next();
+        public void next(String packageName) {
+            mSessionCb.next(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void previous() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.previous();
+        public void previous(String packageName) {
+            mSessionCb.previous(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void fastForward() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.fastForward();
+        public void fastForward(String packageName) {
+            mSessionCb.fastForward(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void rewind() throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.rewind();
+        public void rewind(String packageName) {
+            mSessionCb.rewind(packageName, Binder.getCallingPid(), Binder.getCallingUid());
         }
 
         @Override
-        public void seekTo(long pos) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.seekTo(pos);
+        public void seekTo(String packageName, long pos) {
+            mSessionCb.seekTo(packageName, Binder.getCallingPid(), Binder.getCallingUid(), pos);
         }
 
         @Override
-        public void rate(Rating rating) throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.rate(rating);
+        public void rate(String packageName, Rating rating) {
+            mSessionCb.rate(packageName, Binder.getCallingPid(), Binder.getCallingUid(), rating);
         }
 
         @Override
-        public void sendCustomAction(String action, Bundle args)
-                throws RemoteException {
-            updateCallingPackage();
-            mSessionCb.sendCustomAction(action, args);
+        public void sendCustomAction(String packageName, String action, Bundle args) {
+            mSessionCb.sendCustomAction(packageName, Binder.getCallingPid(), Binder.getCallingUid(),
+                    action, args);
         }
 
 
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 0eb906d..6413ba9 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1804,8 +1804,8 @@
                     }
                 });
             } else {
-                session.adjustVolume(direction, flags, getContext().getPackageName(),
-                        Process.SYSTEM_UID, true);
+                session.adjustVolume(getContext().getPackageName(), Process.myPid(),
+                        Process.SYSTEM_UID, direction, flags, true);
             }
         }
 
@@ -1843,10 +1843,12 @@
                     mKeyEventReceiver.aquireWakeLockLocked();
                 }
                 // If we don't need a wakelock use -1 as the id so we won't release it later.
-                session.sendMediaButton(keyEvent,
+                session.sendMediaButton(getContext().getPackageName(),
+                        Process.myPid(),
+                        Process.SYSTEM_UID,
+                        keyEvent,
                         needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
-                        mKeyEventReceiver, Process.SYSTEM_UID,
-                        getContext().getPackageName());
+                        mKeyEventReceiver);
                 if (mCurrentFullUserRecord.mCallback != null) {
                     try {
                         mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 210857e..31b0461 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2149,7 +2149,8 @@
                 final NotificationChannel channel = channels.get(i);
                 Preconditions.checkNotNull(channel, "channel in list is null");
                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
-                        true /* fromTargetApp */);
+                        true /* fromTargetApp */, mConditionProviders.isPackageOrComponentAllowed(
+                                pkg, UserHandle.getUserId(uid)));
                 mListeners.notifyNotificationChannelChanged(pkg,
                         UserHandle.getUserHandleForUid(uid),
                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
@@ -4691,11 +4692,12 @@
 
     private boolean playSound(final NotificationRecord record, Uri soundUri) {
         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
-        // do not play notifications if there is a user of exclusive audio focus
-        // or the device is in vibrate mode
-        if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
-                != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
-                AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
+        // play notifications if there is no user of exclusive audio focus
+        // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
+        //   VIBRATE ringer mode)
+        if (!mAudioManager.isAudioFocusExclusive()
+                && (mAudioManager.getStreamVolume(
+                        AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
             final long identity = Binder.clearCallingIdentity();
             try {
                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index b1b0bf2..af64683 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -38,7 +38,7 @@
     ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid, boolean includeDeleted, boolean includeNonGrouped);
     void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
-            boolean fromTargetApp);
+            boolean fromTargetApp, boolean hasDndAccess);
     void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
     NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted);
     void deleteNotificationChannel(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index f163113..98d5c9a 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -569,7 +569,7 @@
 
     @Override
     public void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
-            boolean fromTargetApp) {
+            boolean fromTargetApp, boolean hasDndAccess) {
         Preconditions.checkNotNull(pkg);
         Preconditions.checkNotNull(channel);
         Preconditions.checkNotNull(channel.getId());
@@ -610,8 +610,9 @@
                 existing.setImportance(channel.getImportance());
             }
 
-            // system apps can bypass dnd if the user hasn't changed any fields on the channel yet
-            if (existing.getUserLockedFields() == 0 & isSystemApp) {
+            // system apps and dnd access apps can bypass dnd if the user hasn't changed any
+            // fields on the channel yet
+            if (existing.getUserLockedFields() == 0 && (isSystemApp || hasDndAccess)) {
                 existing.setBypassDnd(channel.canBypassDnd());
             }
 
@@ -624,7 +625,7 @@
         }
 
         // Reset fields that apps aren't allowed to set.
-        if (fromTargetApp && !isSystemApp) {
+        if (fromTargetApp && !(isSystemApp || hasDndAccess)) {
             channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
         }
         if (fromTargetApp) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 61c6be7..9807342 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -449,13 +449,15 @@
             pw.increaseIndent();
 
             for (String isa : dexCodeInstructionSets) {
-                String status = null;
                 try {
-                    status = DexFile.getDexFileStatus(path, isa);
+                    String[] status = DexFile.getDexFileOptimizationStatus(path, isa);
+                    String compilationStatus = status[0];
+                    String compilationReason = status[1];
+                    pw.println(isa + ": [status=" + compilationStatus
+                            +"] reason=[" + compilationReason + "]");
                 } catch (IOException ioe) {
-                     status = "[Exception]: " + ioe.getMessage();
+                    pw.println(isa + ": [Exception]: " + ioe.getMessage());
                 }
-                pw.println(isa + ": " + status);
             }
 
             if (useInfo.isUsedByOtherApps(path)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 775fdaa8..b0b313b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -828,11 +828,9 @@
                     //
                     // OverlayManagerService will update each of them with a correct gid from its
                     // target package app id.
-                    synchronized (mInstallLock) {
-                        mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
-                                UserHandle.getSharedAppGid(
-                                        UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
-                    }
+                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
+                            UserHandle.getSharedAppGid(
+                                    UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
                     if (overlayPathList == null) {
                         overlayPathList = new ArrayList<String>();
                     }
@@ -847,13 +845,15 @@
 
         String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
             List<PackageParser.Package> overlayPackages;
-            synchronized (mPackages) {
-                overlayPackages = getStaticOverlayPackages(
-                        mPackages.values(), targetPackageName);
+            synchronized (mInstallLock) {
+                synchronized (mPackages) {
+                    overlayPackages = getStaticOverlayPackages(
+                            mPackages.values(), targetPackageName);
+                }
+                // It is safe to keep overlayPackages without holding mPackages because static overlay
+                // packages can't be uninstalled or disabled.
+                return getStaticOverlayPaths(overlayPackages, targetPath);
             }
-            // It is safe to keep overlayPackages without holding mPackages because static overlay
-            // packages can't be uninstalled or disabled.
-            return getStaticOverlayPaths(overlayPackages, targetPath);
         }
 
         @Override public final String[] getOverlayApks(String targetPackageName) {
@@ -886,7 +886,9 @@
         synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
             // We can trust mOverlayPackages without holding mPackages because package uninstall
             // can't happen while running parallel parsing.
-            // Moreover holding mPackages on each parsing thread causes dead-lock.
+            // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
+            // because mInstallLock is held before running parallel parsing.
+            // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
             return mOverlayPackages == null ? null :
                     getStaticOverlayPaths(
                             getStaticOverlayPackages(mOverlayPackages, targetPackageName),
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2e6e348..fd02347 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1330,6 +1330,9 @@
             mHandler.post(mHiddenNavPanic);
         }
 
+        // Abort possibly stuck animations.
+        mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
+
         // Latch power key state to detect screenshot chord.
         if (interactive && !mScreenshotChordPowerKeyTriggered
                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
@@ -4362,6 +4365,9 @@
      * given the situation with the keyguard.
      */
     void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
+        // Abort possibly stuck animations.
+        mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
+
         if (respectKeyguard) {
             if (isKeyguardShowingAndNotOccluded()) {
                 // don't launch home if keyguard showing
@@ -7175,7 +7181,7 @@
     }
 
     @Override
-    public int rotationForOrientationLw(int orientation, int lastRotation) {
+    public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) {
         if (false) {
             Slog.v(TAG, "rotationForOrientationLw(orient="
                         + orientation + ", last=" + lastRotation
@@ -7196,7 +7202,11 @@
             }
 
             final int preferredRotation;
-            if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
+            if (!defaultDisplay) {
+                // For secondary displays we ignore things like displays sensors, docking mode and
+                // rotation lock, and always prefer a default rotation.
+                preferredRotation = Surface.ROTATION_0;
+            } else if (mLidState == LID_OPEN && mLidOpenRotation >= 0) {
                 // Ignore sensor when lid switch is open and rotation is forced.
                 preferredRotation = mLidOpenRotation;
             } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index ec0521d..0a6ae4e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -407,7 +407,10 @@
         /**
          * Returns true if this window has been shown on screen at some time in
          * the past.  Must be called with the window manager lock held.
+         *
+         * @deprecated Use {@link #isDrawnLw} or any of the other drawn/visibility methods.
          */
+        @Deprecated
         public boolean hasDrawnLw();
 
         /**
@@ -649,6 +652,12 @@
                     return Integer.toString(lens);
             }
         }
+
+        /**
+         * Hint to window manager that the user has started a navigation action that should
+         * abort animations that have no timeout, in case they got stuck.
+         */
+        void triggerAnimationFailsafe();
     }
 
     /** Window has been added to the screen. */
@@ -1426,10 +1435,13 @@
      * @param orientation An orientation constant, such as
      * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
      * @param lastRotation The most recently used rotation.
+     * @param defaultDisplay Flag indicating whether the rotation is computed for the default
+     *                       display. Currently for all non-default displays sensors, docking mode,
+     *                       rotation lock and other factors are ignored.
      * @return The surface rotation to use.
      */
     public int rotationForOrientationLw(@ActivityInfo.ScreenOrientation int orientation,
-            int lastRotation);
+            int lastRotation, boolean defaultDisplay);
 
     /**
      * Given an orientation constant and a rotation, returns true if the rotation
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index b3d28fc..d252a56 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -466,34 +466,32 @@
     }
 
     @Override // Binder call
-    public void setPullingAlarms(long timestampMs, long intervalMs) {
-        enforceCallingPermission();
-        if (DEBUG)
-            Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
-            // only fire when it awakens.
-            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
-            // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
-            mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, timestampMs, intervalMs,
-                    mPullingAlarmIntent);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
+    public void setPullingAlarm(long nextPullTimeMs) {
+      enforceCallingPermission();
+      if (DEBUG)
+        Slog.d(TAG,
+            "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime()));
+      final long callingToken = Binder.clearCallingIdentity();
+      try {
+        // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+        // only fire when it awakens.
+        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent);
+      } finally {
+        Binder.restoreCallingIdentity(callingToken);
+      }
     }
 
     @Override // Binder call
-    public void cancelPullingAlarms() {
-        enforceCallingPermission();
-        if (DEBUG)
-            Slog.d(TAG, "Cancelling pulling alarm");
-        final long callingToken = Binder.clearCallingIdentity();
-        try {
-            mAlarmManager.cancel(mPullingAlarmIntent);
-        } finally {
-            Binder.restoreCallingIdentity(callingToken);
-        }
+    public void cancelPullingAlarm() {
+      enforceCallingPermission();
+      if (DEBUG)
+        Slog.d(TAG, "Cancelling pulling alarm");
+      final long callingToken = Binder.clearCallingIdentity();
+      try {
+        mAlarmManager.cancel(mPullingAlarmIntent);
+      } finally {
+        Binder.restoreCallingIdentity(callingToken);
+      }
     }
 
     private void addNetworkStats(
@@ -1109,7 +1107,7 @@
             mContext.unregisterReceiver(mUserUpdateReceiver);
             mContext.unregisterReceiver(mShutdownEventReceiver);
             cancelAnomalyAlarm();
-            cancelPullingAlarms();
+            cancelPullingAlarm();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 9b787de..9177d25 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -37,6 +37,8 @@
 import android.graphics.drawable.Drawable;
 
 import android.net.Uri;
+import android.os.Bundle;
+
 import com.android.internal.R;
 import com.android.server.policy.IconUtilities;
 
@@ -109,6 +111,8 @@
 
         final String message = context.getString(R.string.alert_windows_notification_message,
                 appName);
+        Bundle extras = new Bundle();
+        extras.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {mPackageName});
         final Notification.Builder builder = new Notification.Builder(context, mNotificationTag)
                 .setOngoing(true)
                 .setContentTitle(
@@ -118,6 +122,7 @@
                 .setColor(context.getColor(R.color.system_notification_accent_color))
                 .setStyle(new Notification.BigTextStyle().bigText(message))
                 .setLocalOnly(true)
+                .addExtras(extras)
                 .setContentIntent(getContentIntent(context, mPackageName));
 
         if (aInfo != null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 56c9e51..f19c554 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1485,7 +1485,7 @@
         if (w == null || winHint != null && w != winHint) {
             return;
         }
-        final boolean surfaceReady = w.hasDrawnLw()  // Regular case
+        final boolean surfaceReady = w.isDrawnLw()  // Regular case
                 || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
                 || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
         final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2ffdbfd..c9ff9e3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -909,6 +909,7 @@
         return mRotation;
     }
 
+    @VisibleForTesting
     void setRotation(int newRotation) {
         mRotation = newRotation;
     }
@@ -974,7 +975,11 @@
         final int oldRotation = mRotation;
         final int lastOrientation = mLastOrientation;
         final boolean oldAltOrientation = mAltOrientation;
-        int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
+        final int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation,
+                isDefaultDisplay);
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
+                + mDisplayId + " based on lastOrientation=" + lastOrientation
+                + " and oldRotation=" + oldRotation);
         boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
                 rotation);
 
@@ -1010,7 +1015,8 @@
         final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw(
                 lastOrientation, rotation);
 
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+                + " selected orientation " + lastOrientation
                 + ", got rotation " + rotation + " which has "
                 + (altOrientation ? "incompatible" : "compatible") + " metrics");
 
@@ -1019,7 +1025,8 @@
             return false;
         }
 
-        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+                + " rotation changed to " + rotation
                 + (altOrientation ? " (alt)" : "") + " from " + oldRotation
                 + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
 
@@ -1647,8 +1654,8 @@
 
         if (mService.mDisplayFrozen) {
             if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "Display is frozen, return " + mLastWindowForcedOrientation);
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+                        + " is frozen, return " + mLastWindowForcedOrientation);
                 // If the display is frozen, some activities may be in the middle of restarting, and
                 // thus have removed their old window. If the window has the flag to hide the lock
                 // screen, then the lock screen can re-appear and inflict its own orientation on us.
@@ -1660,8 +1667,8 @@
                 // window. We don't want to check the show when locked window directly though as
                 // things aren't stable while the display is frozen, for example the window could be
                 // momentarily unavailable due to activity relaunch.
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display is frozen while keyguard locked, "
-                        + "return " + mLastOrientation);
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+                        + " is frozen while keyguard locked, return " + mLastOrientation);
                 return mLastOrientation;
             }
         } else {
@@ -3503,19 +3510,22 @@
                 // In a car, you cannot physically rotate the screen, so it doesn't make sense to
                 // allow anything but the default orientation.
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "Forcing UNSPECIFIED orientation in car. Ignoring " + orientation);
+                        "Forcing UNSPECIFIED orientation in car for display id=" + mDisplayId
+                                + ". Ignoring " + orientation);
                 return SCREEN_ORIENTATION_UNSPECIFIED;
             }
 
             if (orientation != SCREEN_ORIENTATION_UNSET
                     && orientation != SCREEN_ORIENTATION_BEHIND) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                        "App is requesting an orientation, return " + orientation);
+                        "App is requesting an orientation, return " + orientation
+                                + " for display id=" + mDisplayId);
                 return orientation;
             }
 
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
-                    "No app is requesting an orientation, return " + mLastOrientation);
+                    "No app is requesting an orientation, return " + mLastOrientation
+                            + " for display id=" + mDisplayId);
             // The next app has not been requested to be visible, so we keep the current orientation
             // to prevent freezing/unfreezing the display too early.
             return mLastOrientation;
@@ -3708,7 +3718,8 @@
                         return SCREEN_ORIENTATION_UNSET;
                     }
                 }
-                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req);
+                if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req
+                        + " for display id=" + mDisplayId);
                 return (mLastWindowForcedOrientation = req);
             }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 1018848..7274aee 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -34,6 +34,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.ArraySet;
@@ -61,15 +62,17 @@
  * window manager when the animation is completed. In addition, window manager may also notify the
  * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
  */
-public class RecentsAnimationController {
+public class RecentsAnimationController implements DeathRecipient {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentsAnimationController" : TAG_WM;
     private static final boolean DEBUG = false;
+    private static final long FAILSAFE_DELAY = 1000;
 
     private final WindowManagerService mService;
     private final IRecentsAnimationRunner mRunner;
     private final RecentsAnimationCallbacks mCallbacks;
     private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
     private final int mDisplayId;
+    private final Runnable mFailsafeRunnable = this::cancelAnimation;
 
     // The recents component app token that is shown behind the visibile tasks
     private AppWindowToken mHomeAppToken;
@@ -223,6 +226,13 @@
             return;
         }
 
+        try {
+            mRunner.asBinder().linkToDeath(this, 0);
+        } catch (RemoteException e) {
+            cancelAnimation();
+            return;
+        }
+
         // Adjust the wallpaper visibility for the showing home activity
         final AppWindowToken recentsComponentAppToken =
                 dc.getHomeStack().getTopChild().getTopFullscreenAppToken();
@@ -296,6 +306,7 @@
                 // We've already canceled the animation
                 return;
             }
+            mService.mH.removeCallbacks(mFailsafeRunnable);
             mCanceled = true;
             try {
                 mRunner.onAnimationCanceled();
@@ -321,10 +332,21 @@
         }
         mPendingAnimations.clear();
 
+        mRunner.asBinder().unlinkToDeath(this, 0);
+
         mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
         mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
     }
 
+    void scheduleFailsafe() {
+        mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
+    }
+
+    @Override
+    public void binderDied() {
+        cancelAnimation();
+    }
+
     void checkAnimationReady(WallpaperController wallpaperController) {
         if (mPendingStart) {
             final boolean wallpaperReady = !isHomeAppOverWallpaper()
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 379a1a1..3be7b235 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -26,6 +26,7 @@
 import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder.DeathRecipient;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
@@ -47,7 +48,7 @@
 /**
  * Helper class to run app animations in a remote process.
  */
-class RemoteAnimationController {
+class RemoteAnimationController implements DeathRecipient {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM;
     private static final long TIMEOUT_MS = 2000;
 
@@ -56,12 +57,10 @@
     private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>();
     private final Rect mTmpRect = new Rect();
     private final Handler mHandler;
-    private FinishedCallback mFinishedCallback;
+    private final Runnable mTimeoutRunnable = this::cancelAnimation;
 
-    private final Runnable mTimeoutRunnable = () -> {
-        onAnimationFinished();
-        invokeAnimationCancelled();
-    };
+    private FinishedCallback mFinishedCallback;
+    private boolean mCanceled;
 
     RemoteAnimationController(WindowManagerService service,
             RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
@@ -90,7 +89,7 @@
      * Called when the transition is ready to be started, and all leashes have been set up.
      */
     void goodToGo() {
-        if (mPendingAnimations.isEmpty()) {
+        if (mPendingAnimations.isEmpty() || mCanceled) {
             onAnimationFinished();
             return;
         }
@@ -107,8 +106,8 @@
         }
         mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
             try {
-                mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
-                        mFinishedCallback);
+                mRemoteAnimationAdapter.getRunner().asBinder().linkToDeath(this, 0);
+                mRemoteAnimationAdapter.getRunner().onAnimationStart(animations, mFinishedCallback);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to start remote animation", e);
                 onAnimationFinished();
@@ -120,6 +119,17 @@
         }
     }
 
+    private void cancelAnimation() {
+        synchronized (mService.getWindowManagerLock()) {
+            if (mCanceled) {
+                return;
+            }
+            mCanceled = true;
+        }
+        onAnimationFinished();
+        invokeAnimationCancelled();
+    }
+
     private void writeStartDebugStatement() {
         Slog.i(TAG, "Starting remote animation");
         final StringWriter sw = new StringWriter();
@@ -154,6 +164,7 @@
 
     private void onAnimationFinished() {
         mHandler.removeCallbacks(mTimeoutRunnable);
+        mRemoteAnimationAdapter.getRunner().asBinder().unlinkToDeath(this, 0);
         synchronized (mService.mWindowMap) {
             releaseFinishedCallback();
             mService.openSurfaceTransaction();
@@ -193,6 +204,11 @@
         mService.sendSetRunningRemoteAnimation(pid, running);
     }
 
+    @Override
+    public void binderDied() {
+        cancelAnimation();
+    }
+
     private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub {
 
         RemoteAnimationController mOuter;
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6bceda5..6686b80 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -419,4 +419,10 @@
      * @see android.view.IWindowManager#lockNow
      */
     public abstract void lockNow();
+
+    /**
+     * Return the user that owns the given window, {@link android.os.UserHandle#USER_NULL} if
+     * the window token is not found.
+     */
+    public abstract int getWindowOwnerUserId(IBinder windowToken);
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0b5c006..f1cd46b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -25,12 +25,10 @@
 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
 import static android.app.StatusBarManager.DISABLE_MASK;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
-import static android.content.Intent.EXTRA_USER_HANDLE;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.myPid;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.WindowManager.DOCKED_INVALID;
@@ -181,7 +179,6 @@
 import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
@@ -2423,8 +2420,8 @@
         final int oldRotation = defaultDisplayContent.getRotation();
         final boolean oldAltOrientation = defaultDisplayContent.getAltOrientation();
 
-        final int rotation = mPolicy.rotationForOrientationLw(lastOrientation,
-                oldRotation);
+        final int rotation = mPolicy.rotationForOrientationLw(lastOrientation, oldRotation,
+                true /* defaultDisplay */);
         boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
                 lastOrientation, rotation);
         if (oldRotation == rotation && oldAltOrientation == altOrientation) {
@@ -2793,6 +2790,11 @@
         mTaskSnapshotController.screenTurningOff(listener);
     }
 
+    @Override
+    public void triggerAnimationFailsafe() {
+        mH.sendEmptyMessage(H.ANIMATION_FAILSAFE);
+    }
+
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -4566,6 +4568,7 @@
         public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57;
         public static final int SET_HAS_OVERLAY_UI = 58;
         public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
+        public static final int ANIMATION_FAILSAFE = 60;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -4984,6 +4987,14 @@
                     mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1);
                 }
                 break;
+                case ANIMATION_FAILSAFE: {
+                    synchronized (mWindowMap) {
+                        if (mRecentsAnimationController != null) {
+                            mRecentsAnimationController.scheduleFailsafe();
+                        }
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
@@ -7351,6 +7362,17 @@
         public void lockNow() {
             WindowManagerService.this.lockNow(null);
         }
+
+        @Override
+        public int getWindowOwnerUserId(IBinder token) {
+            synchronized (mWindowMap) {
+                WindowState window = mWindowMap.get(token);
+                if (window != null) {
+                    return UserHandle.getUserId(window.mOwnerUid);
+                }
+                return UserHandle.USER_NULL;
+            }
+        }
     }
 
     void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 847222a..61b48c2 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -380,6 +380,7 @@
     auto jProduct = make_javastr(env, prop10.product);
     auto jVersion = make_javastr(env, prop10.version);
     auto jSerial = make_javastr(env, prop10.serial);
+    constexpr bool isInitializationRequired = true;
     bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
     auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
 
@@ -394,9 +395,9 @@
     return make_javaref(env, env->NewObject(gjni.ModuleProperties.clazz,
             gjni.ModuleProperties.cstor, moduleId, jServiceName.get(), prop10.classId,
             jImplementor.get(), jProduct.get(), jVersion.get(), jSerial.get(), prop10.numTuners,
-            prop10.numAudioSources, prop10.supportsCapture, jBands.get(), isBgScanSupported,
-            jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(), nullptr,
-            jVendorInfo.get()));
+            prop10.numAudioSources, isInitializationRequired, prop10.supportsCapture, jBands.get(),
+            isBgScanSupported, jSupportedProgramTypes.get(), jSupportedIdentifierTypes.get(),
+            nullptr, jVendorInfo.get()));
 }
 
 JavaRef<jobject> ModulePropertiesFromHal(JNIEnv *env, const V1_0::Properties &properties,
@@ -712,7 +713,7 @@
     gjni.ModuleProperties.clazz = MakeGlobalRefOrDie(env, modulePropertiesClass);
     gjni.ModuleProperties.cstor = GetMethodIDOrDie(env, modulePropertiesClass, "<init>",
             "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;"
-            "Ljava/lang/String;IIZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
+            "Ljava/lang/String;IIZZ[Landroid/hardware/radio/RadioManager$BandDescriptor;Z"
             "[I[ILjava/util/Map;Ljava/util/Map;)V");
 
     auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2fd7764..02cd3b6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -51,6 +51,7 @@
 import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
 import static android.app.admin.DevicePolicyManager.LEAVE_ALL_SYSTEM_APPS_ENABLED;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_HOME;
+import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_NOTIFICATIONS;
 import static android.app.admin.DevicePolicyManager.LOCK_TASK_FEATURE_OVERVIEW;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
@@ -590,7 +591,8 @@
         List<String> mLockTaskPackages = new ArrayList<>();
 
         // Bitfield of feature flags to be enabled during LockTask mode.
-        int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_NONE;
+        // We default on the power button menu, in order to be consistent with pre-P behaviour.
+        int mLockTaskFeatures = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
 
         boolean mStatusBarDisabled = false;
 
@@ -5531,10 +5533,11 @@
                         .setAttestationChallenge(null)
                         .build();
 
-                final boolean generationResult = keyChain.generateKeyPair(algorithm,
+                final int generationResult = keyChain.generateKeyPair(algorithm,
                     new ParcelableKeyGenParameterSpec(noAttestationSpec));
-                if (!generationResult) {
-                    Log.e(LOG_TAG, "KeyChain failed to generate a keypair.");
+                if (generationResult != KeyChain.KEY_GEN_SUCCESS) {
+                    Log.e(LOG_TAG, String.format(
+                            "KeyChain failed to generate a keypair, error %d.", generationResult));
                     return false;
                 }
 
@@ -5547,12 +5550,17 @@
 
                 final byte[] attestationChallenge = keySpec.getAttestationChallenge();
                 if (attestationChallenge != null) {
-                    final boolean attestationResult = keyChain.attestKey(
+                    final int attestationResult = keyChain.attestKey(
                             alias, attestationChallenge, attestationUtilsFlags, attestationChain);
-                    if (!attestationResult) {
+                    if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) {
                         Log.e(LOG_TAG, String.format(
-                                "Attestation for %s failed, deleting key.", alias));
+                                "Attestation for %s failed (rc=%d), deleting key.",
+                                alias, attestationResult));
                         keyChain.removeKeyPair(alias);
+                        if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) {
+                            throw new UnsupportedOperationException(
+                                    "Device does not support Device ID attestation.");
+                        }
                         return false;
                     }
                 }
@@ -8738,6 +8746,7 @@
 
     @Override
     public List getPermittedInputMethodsForCurrentUser() {
+        enforceManageUsers();
         UserInfo currentUser;
         try {
             currentUser = mInjector.getIActivityManager().getCurrentUser();
@@ -9909,6 +9918,9 @@
         boolean hasOverview = (flags & LOCK_TASK_FEATURE_OVERVIEW) != 0;
         Preconditions.checkArgument(hasHome || !hasOverview,
                 "Cannot use LOCK_TASK_FEATURE_OVERVIEW without LOCK_TASK_FEATURE_HOME");
+        boolean hasNotification = (flags & LOCK_TASK_FEATURE_NOTIFICATIONS) != 0;
+        Preconditions.checkArgument(hasHome || !hasNotification,
+            "Cannot use LOCK_TASK_FEATURE_NOTIFICATIONS without LOCK_TASK_FEATURE_HOME");
 
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index f603a09..fa41220 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -147,6 +147,15 @@
 
         Looper backupLooper = startBackupThreadAndGetLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
+
+        Handler mainHandler = new Handler(Looper.getMainLooper());
+        BackupAgentTimeoutParameters agentTimeoutParameters =
+                new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver());
+        agentTimeoutParameters.start();
+
+        // We need to mock BMS timeout parameters before initializing the BackupHandler since
+        // the constructor of BackupHandler relies on the timeout parameters.
+        when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
         mBackupHandler = new BackupHandler(mBackupManagerService, backupLooper);
 
         mBackupManager = spy(FakeIBackupManager.class);
@@ -157,7 +166,8 @@
                 mTransportManager,
                 packageManager,
                 mBackupHandler,
-                mWakeLock);
+                mWakeLock,
+                agentTimeoutParameters);
         when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
         when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
         when(mBackupManagerService.getBackupManagerBinder()).thenReturn(mBackupManager);
diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
index 03792b1..92d6bbd 100644
--- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
+++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java
@@ -41,12 +41,14 @@
 import android.app.backup.RestoreSet;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.os.Handler;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 
 import com.android.server.EventLogTags;
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.internal.BackupHandler;
@@ -115,6 +117,15 @@
 
         Looper backupLooper = startBackupThreadAndGetLooper();
         mShadowBackupLooper = shadowOf(backupLooper);
+
+        Handler mainHandler = new Handler(Looper.getMainLooper());
+        BackupAgentTimeoutParameters agentTimeoutParameters =
+                new BackupAgentTimeoutParameters(mainHandler, application.getContentResolver());
+        agentTimeoutParameters.start();
+
+        // We need to mock BMS timeout parameters before initializing the BackupHandler since
+        // the constructor of BackupHandler relies on it.
+        when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
         BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper);
 
         mWakeLock = createBackupWakeLock(application);
@@ -125,7 +136,8 @@
                 mTransportManager,
                 application.getPackageManager(),
                 backupHandler,
-                mWakeLock);
+                mWakeLock,
+                agentTimeoutParameters);
         when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>());
     }
 
diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
index c210fde..5a886e3 100644
--- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java
@@ -28,6 +28,7 @@
 import android.os.PowerManager;
 import android.util.SparseArray;
 
+import com.android.server.backup.BackupAgentTimeoutParameters;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.TransportManager;
 import com.android.server.backup.internal.BackupHandler;
@@ -43,7 +44,8 @@
             TransportManager transportManager,
             PackageManager packageManager,
             BackupHandler backupHandler,
-            PowerManager.WakeLock wakeLock) {
+            PowerManager.WakeLock wakeLock,
+            BackupAgentTimeoutParameters agentTimeoutParameters) {
         when(backupManagerService.getContext()).thenReturn(context);
         when(backupManagerService.getTransportManager()).thenReturn(transportManager);
         when(backupManagerService.getPackageManager()).thenReturn(packageManager);
@@ -53,6 +55,7 @@
         when(backupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
         when(backupManagerService.getActivityManager()).thenReturn(mock(IActivityManager.class));
         when(backupManagerService.getWakelock()).thenReturn(wakeLock);
+        when(backupManagerService.getAgentTimeoutParameters()).thenReturn(agentTimeoutParameters);
     }
 
     public static PowerManager.WakeLock createBackupWakeLock(Application application) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 290de2b7..fe47de6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3719,7 +3719,8 @@
     }
 
     private void verifyLockTaskState(int userId) throws Exception {
-        verifyLockTaskState(userId, new String[0], DevicePolicyManager.LOCK_TASK_FEATURE_NONE);
+        verifyLockTaskState(userId, new String[0],
+                DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS);
     }
 
     private void verifyLockTaskState(int userId, String[] packages, int flags) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
index 9ae45ea..81a73efd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.FileUtils;
 import android.security.keystore.AndroidKeyStoreSecretKey;
 import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyProperties;
@@ -49,7 +50,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import android.util.Log;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
 import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnapshotStorage;
 
@@ -72,6 +72,9 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class KeySyncTaskTest {
+
+    private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore";
+
     private static final String KEY_ALGORITHM = "AES";
     private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
     private static final String TEST_ROOT_CERT_ALIAS = "trusted_root";
@@ -117,7 +120,7 @@
                 TEST_ROOT_CERT_ALIAS);
         mRecoverableKeyStoreDb.setActiveRootOfTrust(TEST_USER_ID, TEST_RECOVERY_AGENT_UID2,
                 TEST_ROOT_CERT_ALIAS);
-        mRecoverySnapshotStorage = new RecoverySnapshotStorage();
+        mRecoverySnapshotStorage = new RecoverySnapshotStorage(context.getFilesDir());
 
         mKeySyncTask = new KeySyncTask(
                 mRecoverableKeyStoreDb,
@@ -139,6 +142,10 @@
     public void tearDown() {
         mRecoverableKeyStoreDb.close();
         mDatabaseFile.delete();
+
+        File file = new File(InstrumentationRegistry.getTargetContext().getFilesDir(),
+                SNAPSHOT_TOP_LEVEL_DIRECTORY);
+        FileUtils.deleteContentsAndDir(file);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
index f5f5027..18a3885 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java
@@ -189,7 +189,6 @@
 
         mRecoverableKeyStoreManager = new RecoverableKeyStoreManager(
                 mMockContext,
-                KeyStore.getInstance(),
                 mRecoverableKeyStoreDb,
                 mRecoverySessionStorage,
                 Executors.newSingleThreadExecutor(),
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java
new file mode 100644
index 0000000..2f4da86
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/serialization/KeyChainSnapshotSerializerTest.java
@@ -0,0 +1,250 @@
+/*
+ * 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 com.android.server.locksettings.recoverablekeystore.serialization;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.security.keystore.recovery.KeyChainProtectionParams;
+import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
+import android.security.keystore.recovery.WrappedApplicationKey;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.locksettings.recoverablekeystore.TestData;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.security.cert.CertPath;
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyChainSnapshotSerializerTest {
+    private static final int COUNTER_ID = 2134;
+    private static final int SNAPSHOT_VERSION = 125;
+    private static final int MAX_ATTEMPTS = 21;
+    private static final byte[] SERVER_PARAMS = new byte[] { 8, 2, 4 };
+    private static final byte[] KEY_BLOB = new byte[] { 124, 53, 53, 53 };
+    private static final byte[] PUBLIC_KEY_BLOB = new byte[] { 6, 6, 6, 6, 6, 6, 7 };
+    private static final CertPath CERT_PATH = TestData.CERT_PATH_1;
+    private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN;
+    private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PASSWORD;
+    private static final byte[] SALT = new byte[] { 5, 4, 3, 2, 1 };
+    private static final int MEMORY_DIFFICULTY = 45;
+    private static final int ALGORITHM = KeyDerivationParams.ALGORITHM_SCRYPT;
+    private static final byte[] SECRET = new byte[] { 1, 2, 3, 4 };
+
+    private static final String TEST_KEY_1_ALIAS = "key1";
+    private static final byte[] TEST_KEY_1_BYTES = new byte[] { 66, 77, 88 };
+
+    private static final String TEST_KEY_2_ALIAS = "key2";
+    private static final byte[] TEST_KEY_2_BYTES = new byte[] { 99, 33, 11 };
+
+    private static final String TEST_KEY_3_ALIAS = "key3";
+    private static final byte[] TEST_KEY_3_BYTES = new byte[] { 2, 8, 100 };
+
+    @Test
+    public void roundTrip_persistsCounterId() throws Exception {
+        assertThat(roundTrip().getCounterId()).isEqualTo(COUNTER_ID);
+    }
+
+    @Test
+    public void roundTrip_persistsSnapshotVersion() throws Exception {
+        assertThat(roundTrip().getSnapshotVersion()).isEqualTo(SNAPSHOT_VERSION);
+    }
+
+    @Test
+    public void roundTrip_persistsMaxAttempts() throws Exception {
+        assertThat(roundTrip().getMaxAttempts()).isEqualTo(MAX_ATTEMPTS);
+    }
+
+    @Test
+    public void roundTrip_persistsRecoveryKey() throws Exception {
+        assertThat(roundTrip().getEncryptedRecoveryKeyBlob()).isEqualTo(KEY_BLOB);
+    }
+
+    @Test
+    public void roundTrip_persistsServerParams() throws Exception {
+        assertThat(roundTrip().getServerParams()).isEqualTo(SERVER_PARAMS);
+    }
+
+    @Test
+    public void roundTrip_persistsCertPath() throws Exception {
+        assertThat(roundTrip().getTrustedHardwareCertPath()).isEqualTo(CERT_PATH);
+    }
+
+    @Test
+    public void roundTrip_persistsBackendPublicKey() throws Exception {
+        assertThat(roundTrip().getTrustedHardwarePublicKey()).isEqualTo(PUBLIC_KEY_BLOB);
+    }
+
+    @Test
+    public void roundTrip_persistsParamsList() throws Exception {
+        assertThat(roundTrip().getKeyChainProtectionParams()).hasSize(1);
+    }
+
+    @Test
+    public void roundTripParams_persistsUserSecretType() throws Exception {
+        assertThat(roundTripParams().getUserSecretType()).isEqualTo(SECRET_TYPE);
+    }
+
+    @Test
+    public void roundTripParams_persistsLockScreenUi() throws Exception {
+        assertThat(roundTripParams().getLockScreenUiFormat()).isEqualTo(LOCK_SCREEN_UI);
+    }
+
+    @Test
+    public void roundTripParams_persistsSalt() throws Exception {
+        assertThat(roundTripParams().getKeyDerivationParams().getSalt()).isEqualTo(SALT);
+    }
+
+    @Test
+    public void roundTripParams_persistsAlgorithm() throws Exception {
+        assertThat(roundTripParams().getKeyDerivationParams().getAlgorithm()).isEqualTo(ALGORITHM);
+    }
+
+    @Test
+    public void roundTripParams_persistsMemoryDifficulty() throws Exception {
+        assertThat(roundTripParams().getKeyDerivationParams().getMemoryDifficulty())
+                .isEqualTo(MEMORY_DIFFICULTY);
+    }
+
+    @Test
+    public void roundTripParams_doesNotPersistSecret() throws Exception {
+        assertThat(roundTripParams().getSecret()).isEmpty();
+    }
+
+    @Test
+    public void roundTripKeys_hasCorrectLength() throws Exception {
+        assertThat(roundTripKeys()).hasSize(3);
+    }
+
+    @Test
+    public void roundTripKeys_0_persistsAlias() throws Exception {
+        assertThat(roundTripKeys().get(0).getAlias()).isEqualTo(TEST_KEY_1_ALIAS);
+    }
+
+    @Test
+    public void roundTripKeys_0_persistsKeyBytes() throws Exception {
+        assertThat(roundTripKeys().get(0).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_1_BYTES);
+    }
+
+    @Test
+    public void roundTripKeys_1_persistsAlias() throws Exception {
+        assertThat(roundTripKeys().get(1).getAlias()).isEqualTo(TEST_KEY_2_ALIAS);
+    }
+
+    @Test
+    public void roundTripKeys_1_persistsKeyBytes() throws Exception {
+        assertThat(roundTripKeys().get(1).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_2_BYTES);
+    }
+
+    @Test
+    public void roundTripKeys_2_persistsAlias() throws Exception {
+        assertThat(roundTripKeys().get(2).getAlias()).isEqualTo(TEST_KEY_3_ALIAS);
+    }
+
+    @Test
+    public void roundTripKeys_2_persistsKeyBytes() throws Exception {
+        assertThat(roundTripKeys().get(2).getEncryptedKeyMaterial()).isEqualTo(TEST_KEY_3_BYTES);
+    }
+
+    @Test
+    public void serialize_doesNotThrowForNullPublicKey() throws Exception {
+        KeyChainSnapshotSerializer.serialize(
+                createTestKeyChainSnapshotNoPublicKey(), new ByteArrayOutputStream());
+    }
+
+    private static List<WrappedApplicationKey> roundTripKeys() throws Exception {
+        return roundTrip().getWrappedApplicationKeys();
+    }
+
+    private static KeyChainProtectionParams roundTripParams() throws Exception {
+        return roundTrip().getKeyChainProtectionParams().get(0);
+    }
+
+    public static KeyChainSnapshot roundTrip() throws Exception {
+        KeyChainSnapshot snapshot = createTestKeyChainSnapshot();
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        KeyChainSnapshotSerializer.serialize(snapshot, byteArrayOutputStream);
+        return KeyChainSnapshotDeserializer.deserialize(
+                new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
+    }
+
+    private static KeyChainSnapshot createTestKeyChainSnapshot() throws Exception {
+        return new KeyChainSnapshot.Builder()
+                .setCounterId(COUNTER_ID)
+                .setSnapshotVersion(SNAPSHOT_VERSION)
+                .setServerParams(SERVER_PARAMS)
+                .setMaxAttempts(MAX_ATTEMPTS)
+                .setEncryptedRecoveryKeyBlob(KEY_BLOB)
+                .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
+                .setWrappedApplicationKeys(createKeys())
+                .setTrustedHardwareCertPath(CERT_PATH)
+                .setTrustedHardwarePublicKey(PUBLIC_KEY_BLOB)
+                .build();
+    }
+
+    private static KeyChainSnapshot createTestKeyChainSnapshotNoPublicKey() throws Exception {
+        return new KeyChainSnapshot.Builder()
+                .setCounterId(COUNTER_ID)
+                .setSnapshotVersion(SNAPSHOT_VERSION)
+                .setServerParams(SERVER_PARAMS)
+                .setMaxAttempts(MAX_ATTEMPTS)
+                .setEncryptedRecoveryKeyBlob(KEY_BLOB)
+                .setKeyChainProtectionParams(createKeyChainProtectionParamsList())
+                .setWrappedApplicationKeys(createKeys())
+                .setTrustedHardwareCertPath(CERT_PATH)
+                .build();
+    }
+
+    private static List<WrappedApplicationKey> createKeys() {
+        ArrayList<WrappedApplicationKey> keyList = new ArrayList<>();
+        keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES));
+        keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES));
+        keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES));
+        return keyList;
+    }
+
+    private static List<KeyChainProtectionParams> createKeyChainProtectionParamsList() {
+        KeyDerivationParams keyDerivationParams =
+                KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY);
+        KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder()
+                .setKeyDerivationParams(keyDerivationParams)
+                .setUserSecretType(SECRET_TYPE)
+                .setLockScreenUiFormat(LOCK_SCREEN_UI)
+                .setSecret(SECRET)
+                .build();
+        ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList =
+                new ArrayList<>(1);
+        keyChainProtectionParamsList.add(keyChainProtectionParams);
+        return keyChainProtectionParamsList;
+    }
+
+    private static WrappedApplicationKey createKey(String alias, byte[] bytes) {
+        return new WrappedApplicationKey.Builder()
+                .setAlias(alias)
+                .setEncryptedKeyMaterial(bytes)
+                .build();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
index c772956..ad14c3a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
@@ -1,27 +1,82 @@
 package com.android.server.locksettings.recoverablekeystore.storage;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+import android.os.FileUtils;
+import android.security.keystore.recovery.KeyChainProtectionParams;
 import android.security.keystore.recovery.KeyChainSnapshot;
+import android.security.keystore.recovery.KeyDerivationParams;
+import android.security.keystore.recovery.WrappedApplicationKey;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.locksettings.recoverablekeystore.TestData;
 
+import com.google.common.io.Files;
+
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.security.cert.CertPath;
 import java.security.cert.CertificateException;
 import java.util.ArrayList;
+import java.util.List;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class RecoverySnapshotStorageTest {
-    private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT =
-            createMinimalKeyChainSnapshot();
+    private static final int COUNTER_ID = 432546;
+    private static final int MAX_ATTEMPTS = 10;
+    private static final byte[] SERVER_PARAMS = new byte[] { 12, 8, 2, 4, 15, 64 };
+    private static final byte[] KEY_BLOB = new byte[] { 124, 56, 53, 99, 0, 0, 1 };
+    private static final CertPath CERT_PATH = TestData.CERT_PATH_2;
+    private static final int SECRET_TYPE = KeyChainProtectionParams.TYPE_LOCKSCREEN;
+    private static final int LOCK_SCREEN_UI = KeyChainProtectionParams.UI_FORMAT_PATTERN;
+    private static final byte[] SALT = new byte[] { 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 };
+    private static final int MEMORY_DIFFICULTY = 12;
+    private static final byte[] SECRET = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0 };
 
-    private final RecoverySnapshotStorage mRecoverySnapshotStorage = new RecoverySnapshotStorage();
+    private static final String TEST_KEY_1_ALIAS = "alias1";
+    private static final byte[] TEST_KEY_1_BYTES = new byte[] { 100, 32, 43, 66, 77, 88 };
+
+    private static final String TEST_KEY_2_ALIAS = "alias11";
+    private static final byte[] TEST_KEY_2_BYTES = new byte[] { 100, 0, 0, 99, 33, 11 };
+
+    private static final String TEST_KEY_3_ALIAS = "alias111";
+    private static final byte[] TEST_KEY_3_BYTES = new byte[] { 1, 1, 1, 0, 2, 8, 100 };
+
+    private static final int TEST_UID = 1000;
+    private static final String SNAPSHOT_DIRECTORY = "recoverablekeystore/snapshots";
+    private static final String SNAPSHOT_FILE_PATH = "1000.xml";
+    private static final String SNAPSHOT_TOP_LEVEL_DIRECTORY = "recoverablekeystore";
+
+    private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT =
+            createTestKeyChainSnapshot(1);
+
+    private Context mContext;
+    private RecoverySnapshotStorage mRecoverySnapshotStorage;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mRecoverySnapshotStorage = new RecoverySnapshotStorage(mContext.getFilesDir());
+    }
+
+    @After
+    public void tearDown() {
+        File file = new File(mContext.getFilesDir(), SNAPSHOT_TOP_LEVEL_DIRECTORY);
+        FileUtils.deleteContentsAndDir(file);
+    }
 
     @Test
     public void get_isNullForNonExistentSnapshot() {
@@ -30,37 +85,153 @@
 
     @Test
     public void get_returnsSetSnapshot() {
-        int userId = 1000;
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
 
-        mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT);
-
-        assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(userId));
+        assertEquals(MINIMAL_KEYCHAIN_SNAPSHOT, mRecoverySnapshotStorage.get(TEST_UID));
     }
 
     @Test
-    public void remove_removesSnapshots() {
-        int userId = 1000;
+    public void get_readsFromDiskIfNoneInMemory() {
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
+        RecoverySnapshotStorage storage = new RecoverySnapshotStorage(mContext.getFilesDir());
 
-        mRecoverySnapshotStorage.put(userId, MINIMAL_KEYCHAIN_SNAPSHOT);
-        mRecoverySnapshotStorage.remove(userId);
-
-        assertNull(mRecoverySnapshotStorage.get(1000));
+        assertKeyChainSnapshotsAreEqual(MINIMAL_KEYCHAIN_SNAPSHOT, storage.get(TEST_UID));
     }
 
-    private static KeyChainSnapshot createMinimalKeyChainSnapshot() {
+    @Test
+    public void get_deletesFileIfItIsInvalidSnapshot() throws Exception {
+        File folder = new File(mContext.getFilesDir(), SNAPSHOT_DIRECTORY);
+        folder.mkdirs();
+        File file = new File(folder, SNAPSHOT_FILE_PATH);
+        byte[] fileContents = "<keyChainSnapshot></keyChainSnapshot>".getBytes(
+                StandardCharsets.UTF_8);
+        Files.write(fileContents, file);
+        assertTrue(file.exists());
+
+        assertNull(mRecoverySnapshotStorage.get(TEST_UID));
+
+        assertFalse(file.exists());
+    }
+
+    @Test
+    public void put_overwritesOldFiles() {
+        int snapshotVersion = 2;
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
+
+        mRecoverySnapshotStorage.put(TEST_UID, createTestKeyChainSnapshot(snapshotVersion));
+
+        KeyChainSnapshot snapshot = new RecoverySnapshotStorage(mContext.getFilesDir())
+                .get(TEST_UID);
+        assertEquals(snapshotVersion, snapshot.getSnapshotVersion());
+    }
+
+    @Test
+    public void put_doesNotThrowIfCannotCreateFiles() throws Exception {
+        File evilFile = new File(mContext.getFilesDir(), "recoverablekeystore");
+        Files.write(new byte[] { 1 }, evilFile);
+
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
+
+        assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID));
+    }
+
+    @Test
+    public void remove_removesSnapshotsFromMemory() {
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
+        mRecoverySnapshotStorage.remove(TEST_UID);
+
+        assertNull(mRecoverySnapshotStorage.get(TEST_UID));
+    }
+
+    @Test
+    public void remove_removesSnapshotsFromDisk() {
+        mRecoverySnapshotStorage.put(TEST_UID, MINIMAL_KEYCHAIN_SNAPSHOT);
+
+        new RecoverySnapshotStorage(mContext.getFilesDir()).remove(TEST_UID);
+
+        assertNull(new RecoverySnapshotStorage(mContext.getFilesDir()).get(TEST_UID));
+    }
+
+    private void assertKeyChainSnapshotsAreEqual(KeyChainSnapshot a, KeyChainSnapshot b) {
+        assertEquals(b.getCounterId(), a.getCounterId());
+        assertEquals(b.getSnapshotVersion(), a.getSnapshotVersion());
+        assertArrayEquals(b.getServerParams(), a.getServerParams());
+        assertEquals(b.getMaxAttempts(), a.getMaxAttempts());
+        assertArrayEquals(b.getEncryptedRecoveryKeyBlob(), a.getEncryptedRecoveryKeyBlob());
+        assertEquals(b.getTrustedHardwareCertPath(), a.getTrustedHardwareCertPath());
+
+        List<WrappedApplicationKey> aKeys = a.getWrappedApplicationKeys();
+        List<WrappedApplicationKey> bKeys = b.getWrappedApplicationKeys();
+        assertEquals(bKeys.size(), aKeys.size());
+        for (int i = 0; i < aKeys.size(); i++) {
+            assertWrappedApplicationKeysAreEqual(aKeys.get(i), bKeys.get(i));
+        }
+
+        List<KeyChainProtectionParams> aParams = a.getKeyChainProtectionParams();
+        List<KeyChainProtectionParams> bParams = b.getKeyChainProtectionParams();
+        assertEquals(bParams.size(), aParams.size());
+        for (int i = 0; i < aParams.size(); i++) {
+            assertKeyChainProtectionParamsAreEqual(aParams.get(i), bParams.get(i));
+        }
+    }
+
+    private void assertWrappedApplicationKeysAreEqual(
+            WrappedApplicationKey a, WrappedApplicationKey b) {
+        assertEquals(b.getAlias(), a.getAlias());
+        assertArrayEquals(b.getEncryptedKeyMaterial(), a.getEncryptedKeyMaterial());
+    }
+
+    private void assertKeyChainProtectionParamsAreEqual(
+            KeyChainProtectionParams a, KeyChainProtectionParams b) {
+        assertEquals(b.getUserSecretType(), a.getUserSecretType());
+        assertEquals(b.getLockScreenUiFormat(), a.getLockScreenUiFormat());
+        assertKeyDerivationParamsAreEqual(a.getKeyDerivationParams(), b.getKeyDerivationParams());
+    }
+
+    private void assertKeyDerivationParamsAreEqual(KeyDerivationParams a, KeyDerivationParams b) {
+        assertEquals(b.getAlgorithm(), a.getAlgorithm());
+        assertEquals(b.getMemoryDifficulty(), a.getMemoryDifficulty());
+        assertArrayEquals(b.getSalt(), a.getSalt());
+    }
+
+    private static KeyChainSnapshot createTestKeyChainSnapshot(int snapshotVersion) {
+        KeyDerivationParams keyDerivationParams =
+                KeyDerivationParams.createScryptParams(SALT, MEMORY_DIFFICULTY);
+        KeyChainProtectionParams keyChainProtectionParams = new KeyChainProtectionParams.Builder()
+                .setKeyDerivationParams(keyDerivationParams)
+                .setUserSecretType(SECRET_TYPE)
+                .setLockScreenUiFormat(LOCK_SCREEN_UI)
+                .setSecret(SECRET)
+                .build();
+        ArrayList<KeyChainProtectionParams> keyChainProtectionParamsList =
+                new ArrayList<>(1);
+        keyChainProtectionParamsList.add(keyChainProtectionParams);
+
+        ArrayList<WrappedApplicationKey> keyList = new ArrayList<>();
+        keyList.add(createKey(TEST_KEY_1_ALIAS, TEST_KEY_1_BYTES));
+        keyList.add(createKey(TEST_KEY_2_ALIAS, TEST_KEY_2_BYTES));
+        keyList.add(createKey(TEST_KEY_3_ALIAS, TEST_KEY_3_BYTES));
+
         try {
             return new KeyChainSnapshot.Builder()
-                    .setCounterId(1)
-                    .setSnapshotVersion(1)
-                    .setServerParams(new byte[0])
-                    .setMaxAttempts(10)
-                    .setEncryptedRecoveryKeyBlob(new byte[0])
-                    .setKeyChainProtectionParams(new ArrayList<>())
-                    .setWrappedApplicationKeys(new ArrayList<>())
-                    .setTrustedHardwareCertPath(TestData.CERT_PATH_1)
+                    .setCounterId(COUNTER_ID)
+                    .setSnapshotVersion(snapshotVersion)
+                    .setServerParams(SERVER_PARAMS)
+                    .setMaxAttempts(MAX_ATTEMPTS)
+                    .setEncryptedRecoveryKeyBlob(KEY_BLOB)
+                    .setKeyChainProtectionParams(keyChainProtectionParamsList)
+                    .setWrappedApplicationKeys(keyList)
+                    .setTrustedHardwareCertPath(CERT_PATH)
                     .build();
         } catch (CertificateException e) {
             throw new RuntimeException(e);
         }
     }
+
+    private static WrappedApplicationKey createKey(String alias, byte[] bytes) {
+        return new WrappedApplicationKey.Builder()
+                .setAlias(alias)
+                .setEncryptedKeyMaterial(bytes)
+                .build();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 601999d..c2a0ccf 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -281,6 +281,7 @@
         MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
         mInjector = new MyInjector(myContext, Looper.getMainLooper());
         mController = setupController();
+        setChargingState(mController, false);
     }
 
     @Test
@@ -381,8 +382,6 @@
 
     @Test
     public void testForcedIdle() throws Exception {
-        setChargingState(mController, false);
-
         mController.forceIdleState(PACKAGE_1, USER_ID, true);
         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
@@ -395,8 +394,6 @@
 
     @Test
     public void testNotificationEvent() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
         mInjector.mElapsedRealtime = 1;
@@ -410,8 +407,6 @@
 
     @Test
     public void testSlicePinnedEvent() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
         mInjector.mElapsedRealtime = 1;
@@ -425,8 +420,6 @@
 
     @Test
     public void testSlicePinnedPrivEvent() throws Exception {
-        setChargingState(mController, false);
-
         mController.forceIdleState(PACKAGE_1, USER_ID, true);
         reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime);
         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
@@ -434,14 +427,13 @@
 
     @Test
     public void testPredictionTimedout() throws Exception {
-        setChargingState(mController, false);
         // Set it to timeout or usage, so that prediction can override it
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
-                REASON_MAIN_TIMEOUT, 1 * HOUR_MS);
+                REASON_MAIN_TIMEOUT, HOUR_MS);
         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController));
 
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
-                REASON_MAIN_PREDICTED, 1 * HOUR_MS);
+                REASON_MAIN_PREDICTED, HOUR_MS);
         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
 
         // Fast forward 12 hours
@@ -464,7 +456,6 @@
 
     @Test
     public void testOverrides() throws Exception {
-        setChargingState(mController, false);
         // Can force to NEVER
         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
                 REASON_MAIN_FORCED, 1 * HOUR_MS);
@@ -494,8 +485,6 @@
 
     @Test
     public void testTimeout() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -505,19 +494,19 @@
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
         // bucketing works after timeout
-        mInjector.mElapsedRealtime = FREQUENT_THRESHOLD - 100;
+        mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100;
         mController.checkIdleStates(USER_ID);
-        assertBucket(STANDBY_BUCKET_WORKING_SET);
-
-        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
-                REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+        // Use recent prediction
         assertBucket(STANDBY_BUCKET_FREQUENT);
+
+        // Way past prediction timeout, use system thresholds
+        mInjector.mElapsedRealtime = RARE_THRESHOLD * 4;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_RARE);
     }
 
     @Test
     public void testCascadingTimeouts() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -539,8 +528,6 @@
 
     @Test
     public void testOverlappingTimeouts() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -596,8 +583,6 @@
 
     @Test
     public void testPredictionNotOverridden() throws Exception {
-        setChargingState(mController, false);
-
         reportEvent(mController, USER_INTERACTION, 0);
         assertBucket(STANDBY_BUCKET_ACTIVE);
 
@@ -623,6 +608,31 @@
     }
 
     @Test
+    public void testPredictionStrikesBack() throws Exception {
+        reportEvent(mController, USER_INTERACTION, 0);
+        assertBucket(STANDBY_BUCKET_ACTIVE);
+
+        // Predict to FREQUENT
+        mInjector.mElapsedRealtime = RARE_THRESHOLD;
+        mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
+                REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
+        assertBucket(STANDBY_BUCKET_FREQUENT);
+
+        // Add a short timeout event
+        mInjector.mElapsedRealtime += 1000;
+        reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime);
+        assertBucket(STANDBY_BUCKET_ACTIVE);
+        mInjector.mElapsedRealtime += 1000;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_ACTIVE);
+
+        // Verify it reverted to predicted
+        mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2;
+        mController.checkIdleStates(USER_ID);
+        assertBucket(STANDBY_BUCKET_FREQUENT);
+    }
+
+    @Test
     public void testAddActiveDeviceAdmin() {
         assertActiveAdmins(USER_ID, (String[]) null);
         assertActiveAdmins(USER_ID2, (String[]) null);
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 553d658..95361f0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -17,14 +17,20 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Binder;
+import android.os.IInterface;
+import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
@@ -50,7 +56,7 @@
  * atest FrameworksServicesTests:com.android.server.wm.RemoteAnimationControllerTest
  */
 @SmallTest
-@FlakyTest(detail = "Promote to presubmit if non-flakyness is established")
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class RemoteAnimationControllerTest extends WindowTestsBase {
 
@@ -67,6 +73,7 @@
     public void setUp() throws Exception {
         super.setUp();
         MockitoAnnotations.initMocks(this);
+        when(mMockRunner.asBinder()).thenReturn(new Binder());
         mAdapter = new RemoteAnimationAdapter(mMockRunner, 100, 50);
         mAdapter.setCallingPid(123);
         sWm.mH.runWithScissors(() -> {
@@ -166,7 +173,7 @@
     @Test
     public void testZeroAnimations() throws Exception {
         mController.goodToGo();
-        verifyZeroInteractions(mMockRunner);
+        verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
     @Test
@@ -175,7 +182,7 @@
         mController.createAnimationAdapter(win.mAppToken,
                 new Point(50, 100), new Rect(50, 100, 150, 150));
         mController.goodToGo();
-        verifyZeroInteractions(mMockRunner);
+        verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
     }
 
     @Test
@@ -206,7 +213,12 @@
         adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
         win.mAppToken.removeImmediately();
         mController.goodToGo();
-        verifyZeroInteractions(mMockRunner);
+        verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
         verify(mFinishedCallback).onAnimationFinished(eq(adapter));
     }
+
+    private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
+        verify(binder, atLeast(0)).asBinder();
+        verifyNoMoreInteractions(binder);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 6d9167f..1af344b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -445,8 +445,7 @@
     }
 
     @Override
-    public int rotationForOrientationLw(int orientation,
-            int lastRotation) {
+    public int rotationForOrientationLw(int orientation, int lastRotation, boolean defaultDisplay) {
         return rotationToReport;
     }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index 09d88fd..0815876 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -367,8 +367,8 @@
 
         mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
         mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
 
         mHelper.setShowBadge(PKG, UID, true);
 
@@ -427,10 +427,10 @@
 
         mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
         mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, false);
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
+        mHelper.createNotificationChannel(PKG, UID, channel3, false, false);
+        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false);
 
         mHelper.setShowBadge(PKG, UID, true);
 
@@ -481,7 +481,7 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
 
@@ -507,7 +507,7 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
 
         loadStreamXml(baos, true);
@@ -528,7 +528,7 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
 
         loadStreamXml(baos, true);
@@ -569,7 +569,7 @@
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(null, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId());
 
         loadStreamXml(baos, true);
@@ -593,9 +593,9 @@
 
         mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
         mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
+        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
 
         mHelper.deleteNotificationChannel(PKG, UID, channel1.getId());
         mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId());
@@ -701,7 +701,7 @@
     @Test
     public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
         mHelper.createNotificationChannel(PKG, UID,
-                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
 
@@ -721,7 +721,7 @@
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
         mHelper.createNotificationChannel(PKG, UID,
-                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
 
         loadStreamXml(baos, false);
 
@@ -734,36 +734,39 @@
         mHelper.setImportance(PKG, UID, IMPORTANCE_NONE);
 
         mHelper.createNotificationChannel(PKG, UID,
-                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
     }
 
     @Test
     public void testCreateChannel_badImportance() throws Exception {
         try {
             mHelper.createNotificationChannel(PKG, UID,
-                    new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true);
+                    new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1),
+                    true, false);
             fail("Was allowed to create a channel with invalid importance");
         } catch (IllegalArgumentException e) {
             // yay
         }
         try {
             mHelper.createNotificationChannel(PKG, UID,
-                    new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true);
+                    new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED),
+                    true, false);
             fail("Was allowed to create a channel with invalid importance");
         } catch (IllegalArgumentException e) {
             // yay
         }
         try {
             mHelper.createNotificationChannel(PKG, UID,
-                    new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true);
+                    new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1),
+                    true, false);
             fail("Was allowed to create a channel with invalid importance");
         } catch (IllegalArgumentException e) {
             // yay
         }
         mHelper.createNotificationChannel(PKG, UID,
-                new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true);
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false);
         mHelper.createNotificationChannel(PKG, UID,
-                new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true);
+                new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false);
     }
 
 
@@ -777,7 +780,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, false);
+        mHelper.createNotificationChannel(PKG, UID, channel, false, false);
 
         // same id, try to update all fields
         final NotificationChannel channel2 =
@@ -824,7 +827,7 @@
     public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
         final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, false);
+        mHelper.createNotificationChannel(PKG, UID, channel, false, false);
         assertTrue(mHelper.canShowBadge(PKG, UID));
         assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
         assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
@@ -865,7 +868,7 @@
         }
         channel.lockFields(lockMask);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
 
         NotificationChannel savedChannel =
                 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
@@ -894,7 +897,7 @@
         }
         channel.lockFields(lockMask);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
 
         NotificationChannel savedChannel =
                 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
@@ -920,7 +923,7 @@
 
     @Test
     public void testLockFields_soundAndVibration() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setSound(new Uri.Builder().scheme("test").build(),
@@ -944,7 +947,7 @@
 
     @Test
     public void testLockFields_vibrationAndLights() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setVibrationPattern(new long[]{7945, 46 ,246});
@@ -964,7 +967,7 @@
 
     @Test
     public void testLockFields_lightsAndImportance() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
 
         final NotificationChannel update1 = getChannel();
         update1.setLightColor(Color.GREEN);
@@ -984,7 +987,7 @@
 
     @Test
     public void testLockFields_visibilityAndDndAndBadge() throws Exception {
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
         assertEquals(0,
                 mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
                         .getUserLockedFields());
@@ -1029,7 +1032,7 @@
         channel.enableVibration(true);
         channel.setVibrationPattern(new long[]{100, 67, 145, 156});
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
 
         // Does not return deleted channel
@@ -1058,8 +1061,8 @@
         NotificationChannel channel2 =
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
         channelMap.put(channel2.getId(), channel2);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
 
         mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
 
@@ -1091,9 +1094,9 @@
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
         NotificationChannel channel3 =
                 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, true);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
 
         mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
         mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
@@ -1109,14 +1112,14 @@
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
 
         NotificationChannel newChannel = new NotificationChannel(
                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
         newChannel.setVibrationPattern(new long[]{100});
 
-        mHelper.createNotificationChannel(PKG, UID, newChannel, true);
+        mHelper.createNotificationChannel(PKG, UID, newChannel, true, false);
 
         // No long deleted, using old settings
         compareChannels(channel,
@@ -1128,7 +1131,7 @@
         assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID));
         assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2));
 
-        mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
+        mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false);
         assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID));
     }
 
@@ -1136,7 +1139,7 @@
     public void testCreateChannel_defaultChannelId() throws Exception {
         try {
             mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
-                    NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true);
+                    NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false);
             fail("Allowed to create default channel");
         } catch (IllegalArgumentException e) {
             // pass
@@ -1150,13 +1153,13 @@
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
         channel.setVibrationPattern(vibration);
 
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
 
         NotificationChannel newChannel = new NotificationChannel(
                 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
         newChannel.setVibrationPattern(new long[]{100});
 
-        mHelper.createNotificationChannel(PKG, UID, newChannel, true);
+        mHelper.createNotificationChannel(PKG, UID, newChannel, true, false);
 
         // Old settings not overridden
         compareChannels(channel,
@@ -1169,7 +1172,7 @@
         final NotificationChannel channel = new NotificationChannel("id2", "name2",
                  NotificationManager.IMPORTANCE_DEFAULT);
         channel.setSound(sound, mAudioAttributes);
-        mHelper.createNotificationChannel(PKG, UID, channel, true);
+        mHelper.createNotificationChannel(PKG, UID, channel, true, false);
         assertEquals(sound, mHelper.getNotificationChannel(
                 PKG, UID, channel.getId(), false).getSound());
     }
@@ -1181,8 +1184,8 @@
         NotificationChannel channel2 =
                 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
 
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
-        mHelper.createNotificationChannel(PKG, UID, channel2, false);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
+        mHelper.createNotificationChannel(PKG, UID, channel2, false, false);
 
         mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
 
@@ -1205,9 +1208,9 @@
 
         mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true);
         mHelper.createNotificationChannelGroup(PKG, UID, deleted, true);
-        mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true);
-        mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true);
-        mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true);
+        mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true, false);
+        mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true, false);
+        mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true, false);
 
         mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId());
 
@@ -1264,14 +1267,14 @@
         // Deleted
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
         assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
 
         // Not deleted
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
 
         mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
         assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
@@ -1302,7 +1305,7 @@
     @Test
     public void testOnPackageChange_downgradeTargetSdk() throws Exception {
         // create channel as api 26
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);
+        mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false);
 
         // install new app version targeting 25
         final ApplicationInfo legacy = new ApplicationInfo();
@@ -1338,7 +1341,7 @@
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup("garbage");
         try {
-            mHelper.createNotificationChannel(PKG, UID, channel1, true);
+            mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
             fail("Created a channel with a bad group");
         } catch (IllegalArgumentException e) {
         }
@@ -1351,7 +1354,7 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
 
         assertEquals(ncg.getId(),
                 mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup());
@@ -1369,20 +1372,20 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
         NotificationChannel channel1a =
                 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1a.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1a, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1a, true, false);
 
         NotificationChannel channel2 =
                 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel2.setGroup(ncg2.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel2, true);
+        mHelper.createNotificationChannel(PKG, UID, channel2, true, false);
 
         NotificationChannel channel3 =
                 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, channel3, true);
+        mHelper.createNotificationChannel(PKG, UID, channel3, true, false);
 
         List<NotificationChannelGroup> actual =
                 mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
@@ -1416,7 +1419,7 @@
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
         channel1.setGroup(ncg.getId());
-        mHelper.createNotificationChannel(PKG, UID, channel1, true);
+        mHelper.createNotificationChannel(PKG, UID, channel1, true, false);
         mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList();
 
         channel1.setImportance(IMPORTANCE_LOW);
@@ -1436,12 +1439,12 @@
     @Test
     public void testCreateChannel_updateName() throws Exception {
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
-        mHelper.createNotificationChannel(PKG, UID, nc, true);
+        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
         NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
         assertEquals("hello", actual.getName());
 
         nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(PKG, UID, nc, true);
+        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
 
         actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
         assertEquals("goodbye", actual.getName());
@@ -1455,13 +1458,13 @@
         NotificationChannelGroup group = new NotificationChannelGroup("group", "");
         mHelper.createNotificationChannelGroup(PKG, UID, group, true);
         NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
-        mHelper.createNotificationChannel(PKG, UID, nc, true);
+        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
         NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
         assertNull(actual.getGroup());
 
         nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
         nc.setGroup(group.getId());
-        mHelper.createNotificationChannel(PKG, UID, nc, true);
+        mHelper.createNotificationChannel(PKG, UID, nc, true, false);
 
         actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
         assertNotNull(actual.getGroup());
@@ -1486,7 +1489,7 @@
             int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
             for (int j = 0; j < numChannels; j++) {
                 mHelper.createNotificationChannel(pkgName, UID,
-                        new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true);
+                        new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false);
             }
             expectedChannels.put(pkgName, numChannels);
         }
@@ -1621,10 +1624,10 @@
         c.setGroup(group.getId());
         NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
 
-        mHelper.createNotificationChannel(PKG, UID, a, true);
-        mHelper.createNotificationChannel(PKG, UID, b, true);
-        mHelper.createNotificationChannel(PKG, UID, c, true);
-        mHelper.createNotificationChannel(PKG, UID, d, true);
+        mHelper.createNotificationChannel(PKG, UID, a, true, false);
+        mHelper.createNotificationChannel(PKG, UID, b, true, false);
+        mHelper.createNotificationChannel(PKG, UID, c, true, false);
+        mHelper.createNotificationChannel(PKG, UID, d, true, false);
         mHelper.deleteNotificationChannel(PKG, UID, c.getId());
 
         NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels(
@@ -1641,22 +1644,31 @@
 
     @Test
     public void testAndroidPkgCanBypassDnd_creation() {
-
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         test.setBypassDnd(true);
 
-        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true);
+        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
 
         assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
                 .canBypassDnd());
     }
 
     @Test
+    public void testDndPkgCanBypassDnd_creation() {
+        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
+        test.setBypassDnd(true);
+
+        mHelper.createNotificationChannel(PKG, UID, test, true, true);
+
+        assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd());
+    }
+
+    @Test
     public void testNormalPkgCannotBypassDnd_creation() {
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         test.setBypassDnd(true);
 
-        mHelper.createNotificationChannel(PKG, 1000, test, true);
+        mHelper.createNotificationChannel(PKG, 1000, test, true, false);
 
         assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
     }
@@ -1664,11 +1676,11 @@
     @Test
     public void testAndroidPkgCanBypassDnd_update() throws Exception {
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true);
+        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false);
 
         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         update.setBypassDnd(true);
-        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true);
+        mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false);
 
         assertTrue(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false)
                 .canBypassDnd());
@@ -1678,12 +1690,24 @@
     }
 
     @Test
-    public void testNormalPkgCannotBypassDnd_update() {
+    public void testDndPkgCanBypassDnd_update() throws Exception {
         NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
-        mHelper.createNotificationChannel(PKG, 1000, test, true);
+        mHelper.createNotificationChannel(PKG, UID, test, true, true);
+
         NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
         update.setBypassDnd(true);
-        mHelper.createNotificationChannel(PKG, 1000, update, true);
+        mHelper.createNotificationChannel(PKG, UID, update, true, true);
+
+        assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd());
+    }
+
+    @Test
+    public void testNormalPkgCannotBypassDnd_update() {
+        NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG, 1000, test, true, false);
+        NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW);
+        update.setBypassDnd(true);
+        mHelper.createNotificationChannel(PKG, 1000, update, true, false);
         assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd());
     }
 }
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index fd28b65..271f813 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -70,6 +70,8 @@
     private SparseArray<ArrayMap<String,AppUsageHistory>> mIdleHistory = new SparseArray<>();
     private static final long ONE_MINUTE = 60 * 1000;
 
+    private static final int STANDBY_BUCKET_UNKNOWN = -1;
+
     @VisibleForTesting
     static final String APP_IDLE_FILENAME = "app_idle_stats.xml";
     private static final String TAG_PACKAGES = "packages";
@@ -111,6 +113,9 @@
         long lastUsedScreenTime;
         // Last predicted time using elapsed timebase
         long lastPredictedTime;
+        // Last predicted bucket
+        @UsageStatsManager.StandbyBuckets
+        int lastPredictedBucket = STANDBY_BUCKET_UNKNOWN;
         // Standby bucket
         @UsageStatsManager.StandbyBuckets
         int currentBucket;
@@ -342,6 +347,7 @@
         appUsageHistory.bucketingReason = reason;
         if ((reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED) {
             appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
+            appUsageHistory.lastPredictedBucket = bucket;
         }
         if (DEBUG) {
             Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
@@ -350,6 +356,17 @@
     }
 
     /**
+     * Update the prediction for the app but don't change the actual bucket
+     * @param app The app for which the prediction was made
+     * @param elapsedTimeAdjusted The elapsed time in the elapsed duration timebase
+     * @param bucket The predicted bucket
+     */
+    public void updateLastPrediction(AppUsageHistory app, long elapsedTimeAdjusted, int bucket) {
+        app.lastPredictedTime = elapsedTimeAdjusted;
+        app.lastPredictedBucket = bucket;
+    }
+
+    /**
      * Marks the last time a job was run, with the given elapsedRealtime. The time stored is
      * based on the elapsed timebase.
      * @param packageName
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 9139a4c..571ed00a 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -22,6 +22,7 @@
 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
+import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -30,13 +31,14 @@
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_UPDATE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SLICE_PINNED_PRIV;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
-
 import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
 import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
 
@@ -538,19 +540,30 @@
                 }
                 final int oldBucket = app.currentBucket;
                 int newBucket = Math.max(oldBucket, STANDBY_BUCKET_ACTIVE); // Undo EXEMPTED
-                boolean predictionLate = false;
+                boolean predictionLate = predictionTimedOut(app, elapsedRealtime);
                 // Compute age-based bucket
                 if (oldMainReason == REASON_MAIN_DEFAULT
                         || oldMainReason == REASON_MAIN_USAGE
                         || oldMainReason == REASON_MAIN_TIMEOUT
-                        || (predictionLate = predictionTimedOut(app, elapsedRealtime))) {
-                    newBucket = getBucketForLocked(packageName, userId,
-                            elapsedRealtime);
-                    if (DEBUG) {
-                        Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
+                        || predictionLate) {
+
+                    if (!predictionLate && app.lastPredictedBucket >= STANDBY_BUCKET_ACTIVE
+                            && app.lastPredictedBucket <= STANDBY_BUCKET_RARE) {
+                        newBucket = app.lastPredictedBucket;
+                        reason = REASON_MAIN_PREDICTED | REASON_SUB_PREDICTED_RESTORED;
+                        if (DEBUG) {
+                            Slog.d(TAG, "Restored predicted newBucket = " + newBucket);
+                        }
+                    } else {
+                        newBucket = getBucketForLocked(packageName, userId,
+                                elapsedRealtime);
+                        if (DEBUG) {
+                            Slog.d(TAG, "Evaluated AOSP newBucket = " + newBucket);
+                        }
+                        reason = REASON_MAIN_TIMEOUT;
                     }
-                    reason = REASON_MAIN_TIMEOUT;
                 }
+
                 // Check if the app is within one of the timeouts for forced bucket elevation
                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
                 if (newBucket >= STANDBY_BUCKET_ACTIVE
@@ -587,8 +600,7 @@
 
     /** Returns true if there hasn't been a prediction for the app in a while. */
     private boolean predictionTimedOut(AppIdleHistory.AppUsageHistory app, long elapsedRealtime) {
-        return (app.bucketingReason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED
-                && app.lastPredictedTime > 0
+        return app.lastPredictedTime > 0
                 && mAppIdleHistory.getElapsedTime(elapsedRealtime)
                     - app.lastPredictedTime > mPredictionTimeoutMillis;
     }
@@ -747,6 +759,8 @@
             case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
             case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
             case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
+            case UsageEvents.Event.SLICE_PINNED: return REASON_SUB_USAGE_SLICE_PINNED;
+            case UsageEvents.Event.SLICE_PINNED_PRIV: return REASON_SUB_USAGE_SLICE_PINNED_PRIV;
             default: return 0;
         }
     }
@@ -1032,6 +1046,10 @@
             if (predicted) {
                 // Check if the app is within one of the timeouts for forced bucket elevation
                 final long elapsedTimeAdjusted = mAppIdleHistory.getElapsedTime(elapsedRealtime);
+                // In case of not using the prediction, just keep track of it for applying after
+                // ACTIVE or WORKING_SET timeout.
+                mAppIdleHistory.updateLastPrediction(app, elapsedTimeAdjusted, newBucket);
+
                 if (newBucket > STANDBY_BUCKET_ACTIVE
                         && app.bucketActiveTimeoutTime > elapsedTimeAdjusted) {
                     newBucket = STANDBY_BUCKET_ACTIVE;
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index 9dc07c1..da04a0d 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -920,11 +920,11 @@
         try {
             if (!token.createNewFile()) {
                 throw new RuntimeException("Failed to create download token for request "
-                        + request);
+                        + request + ". Token location is " + token.getPath());
             }
         } catch (IOException e) {
             throw new RuntimeException("Failed to create download token for request " + request
-                    + " due to IOException " + e);
+                    + " due to IOException " + e + ". Attempted to write to " + token.getPath());
         }
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index da5bd84..15e0632 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7752,11 +7752,25 @@
      */
     public static final int INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED    = 0x4;
 
+    /**
+     * The indication for link capacity estimate update.
+     * @hide
+     */
+    public static final int INDICATION_FILTER_LINK_CAPACITY_ESTIMATE        = 0x8;
+
+    /**
+     * The indication for physical channel config update.
+     * @hide
+     */
+    public static final int INDICATION_FILTER_PHYSICAL_CHANNEL_CONFIG       = 0x10;
+
     /** @hide */
     @IntDef(flag = true, prefix = { "INDICATION_FILTER_" }, value = {
             INDICATION_FILTER_SIGNAL_STRENGTH,
             INDICATION_FILTER_FULL_NETWORK_STATE,
-            INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED
+            INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED,
+            INDICATION_FILTER_LINK_CAPACITY_ESTIMATE,
+            INDICATION_FILTER_PHYSICAL_CHANNEL_CONFIG
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface IndicationFilters{}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index b0c00c6..fe7533f 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -297,7 +297,9 @@
         for (Uri tempFileUri : tempFiles) {
             if (verifyTempFilePath(context, request.getFileServiceId(), tempFileUri)) {
                 File tempFile = new File(tempFileUri.getSchemeSpecificPart());
-                tempFile.delete();
+                if (!tempFile.delete()) {
+                    Log.w(LOG_TAG, "Failed to delete temp file at " + tempFile.getPath());
+                }
             }
         }
     }
@@ -474,6 +476,8 @@
 
         if (!MbmsUtils.isContainedIn(
                 MbmsUtils.getEmbmsTempFileDirForService(context, serviceId), tempFile)) {
+            Log.w(LOG_TAG, "File at " + path + " is not contained in the temp file root," +
+                    " which is " + MbmsUtils.getEmbmsTempFileDirForService(context, serviceId));
             return false;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index ee7084a..d25fd3f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -419,6 +419,8 @@
     int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 145;
     int RIL_REQUEST_START_KEEPALIVE = 146;
     int RIL_REQUEST_STOP_KEEPALIVE = 147;
+    int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 148;
+    int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 149;
 
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
 
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 300c701..499f254 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -211,7 +211,7 @@
         signature != atoms.signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "void\n");
+        fprintf(out, "int\n");
         fprintf(out, "stats_write(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -251,7 +251,7 @@
                             " diff length: %s vs %s\");\n",
                             attributionDecl.fields.front().name.c_str(),
                             chainField.name.c_str());
-                        fprintf(out, "        return;\n");
+                        fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }
                 }
@@ -284,7 +284,7 @@
             argIndex++;
         }
 
-        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
         fprintf(out, "}\n");
         fprintf(out, "\n");
     }
@@ -293,7 +293,7 @@
         signature != atoms.non_chained_signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "void\n");
+        fprintf(out, "int\n");
         fprintf(out, "stats_write_non_chained(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
@@ -327,7 +327,7 @@
             argIndex++;
         }
 
-        fprintf(out, "    event.write(LOG_ID_STATS);\n");
+        fprintf(out, "    return event.write(LOG_ID_STATS);\n");
         fprintf(out, "}\n");
         fprintf(out, "\n");
     }
@@ -377,7 +377,7 @@
     const AtomDecl &attributionDecl) {
     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
             signature != signatures.end(); signature++) {
-        fprintf(out, "void %s(int32_t code ", method_name.c_str());
+        fprintf(out, "int %s(int32_t code ", method_name.c_str());
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -522,7 +522,7 @@
     const AtomDecl &attributionDecl) {
     for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
         signature != signatures.end(); signature++) {
-        fprintf(out, "    public static native void %s(int code", method_name.c_str());
+        fprintf(out, "    public static native int %s(int code", method_name.c_str());
         int argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -719,7 +719,7 @@
             result += java_type_signature(*arg);
         }
     }
-    result += ")V";
+    result += ")I";
     return result;
 }
 
@@ -732,7 +732,7 @@
         signature != signatures.end(); signature++) {
         int argIndex;
 
-        fprintf(out, "static void\n");
+        fprintf(out, "static int\n");
         fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
                 jni_function_name(java_method_name, *signature).c_str());
         argIndex = 1;
@@ -779,7 +779,7 @@
                             "\"java/lang/IllegalArgumentException\", "
                             "\"invalid attribution field(%s) length.\");\n",
                             chainField.name.c_str());
-                        fprintf(out, "        return;\n");
+                        fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }
                     if (chainField.javaType == JAVA_TYPE_INT) {
@@ -822,7 +822,7 @@
 
         // stats_write call
         argIndex = 1;
-        fprintf(out, "    android::util::%s(code", cpp_method_name.c_str());
+        fprintf(out, "   int ret =  android::util::%s(code", cpp_method_name.c_str());
         for (vector<java_type_t>::const_iterator arg = signature->begin();
                 arg != signature->end(); arg++) {
             if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -868,6 +868,7 @@
             }
             argIndex++;
         }
+        fprintf(out, "    return ret;\n");
 
         fprintf(out, "}\n");
         fprintf(out, "\n");
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c8df087..433285b 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1317,6 +1317,7 @@
         if (pin) {
             NetworkRequest request = new NetworkRequest.Builder()
                     .clearCapabilities()
+                    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                     .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                     .build();
             NetworkPinner.pin(mContext, request);