Merge "ByteStringUtils: fix hex parsing to include lowercase input."
diff --git a/Android.bp b/Android.bp
index c5d64fb..05fb3c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -670,8 +670,9 @@
         "android.hardware.tv.input-V1.0-java-constants",
         "android.hardware.usb-V1.0-java-constants",
         "android.hardware.usb-V1.1-java-constants",
-        "android.hardware.vibrator-V1.0-java-constants",
-        "android.hardware.vibrator-V1.1-java-constants",
+        "android.hardware.vibrator-V1.0-java",
+        "android.hardware.vibrator-V1.1-java",
+        "android.hardware.vibrator-V1.2-java",
         "android.hardware.wifi-V1.0-java-constants",
         "android.hardware.radio-V1.0-java",
         "android.hardware.usb.gadget-V1.0-java",
diff --git a/Android.mk b/Android.mk
index 7e2f472..a78a01a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -827,35 +827,35 @@
 
 # ==== hiddenapi lists =======================================
 
-# Copy light greylist and dark greylist over into the build folder.
+# Copy blacklist and light greylist over into the build folder.
 # This is for ART buildbots which need to mock these lists and have alternative
 # rules for building them. Other rules in the build system should depend on the
 # files in the build folder.
 
+$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\
+                            $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)))
 $(eval $(call copy-one-file,frameworks/base/config/hiddenapi-light-greylist.txt,\
                             $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)))
-$(eval $(call copy-one-file,frameworks/base/config/hiddenapi-dark-greylist.txt,\
-                            $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)))
 
-# Generate blacklist as private API minus (light greylist plus dark greylist).
+# Generate dark greylist as private API minus (blacklist plus light greylist).
 
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): DARK_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
-$(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
-                                          $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST) \
-                                          $(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST)
-	if [ ! -z "`comm -12 <(sort $(LIGHT_GREYLIST)) <(sort $(DARK_GREYLIST))`" ]; then \
-		echo "There should be no overlap between $(LIGHT_GREYLIST) and $(DARK_GREYLIST)" 1>&2; \
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): BLACKLIST := $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): LIGHT_GREYLIST := $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
+$(INTERNAL_PLATFORM_HIDDENAPI_DARK_GREYLIST): $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE) \
+                                              $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST) \
+                                              $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST)
+	if [ ! -z "`comm -12 <(sort $(BLACKLIST)) <(sort $(LIGHT_GREYLIST))`" ]; then \
+		echo "There should be no overlap between $(BLACKLIST) and $(LIGHT_GREYLIST)" 1>&2; \
 		exit 1; \
+	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST))`" ]; then \
+		echo "$(BLACKLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
+		exit 2; \
 	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST))`" ]; then \
 		echo "$(LIGHT_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
-		exit 2; \
-	elif [ ! -z "`comm -13 <(sort $(PRIVATE_API)) <(sort $(DARK_GREYLIST))`" ]; then \
-		echo "$(DARK_GREYLIST) must be a subset of $(PRIVATE_API)" 1>&2; \
 		exit 3; \
 	fi
-	comm -23 <(sort $(PRIVATE_API)) <(sort $(LIGHT_GREYLIST) $(DARK_GREYLIST)) > $@
+	comm -23 <(sort $(PRIVATE_API)) <(sort $(BLACKLIST) $(LIGHT_GREYLIST)) > $@
 
 # Include subdirectory makefiles
 # ============================================================
diff --git a/api/current.txt b/api/current.txt
index 9204289..3944b45 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -73,6 +73,7 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
+    field public static final java.lang.String FOREGROUND_SERVICE = "android.permission.FOREGROUND_SERVICE";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
diff --git a/api/system-current.txt b/api/system-current.txt
index 6b229af..3dbb333 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -361,6 +361,7 @@
   }
 
   public final class StatsManager {
+    method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String);
     method public boolean addConfiguration(long, byte[]);
     method public byte[] getData(long);
     method public byte[] getMetadata();
@@ -688,6 +689,12 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.app.usage.CacheQuotaService";
   }
 
+  public static final class UsageEvents.Event {
+    method public int getStandbyBucket();
+    field public static final int NOTIFICATION_SEEN = 10; // 0xa
+    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
+  }
+
   public final class UsageStatsManager {
     method public int getAppStandbyBucket(java.lang.String);
     method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
@@ -822,6 +829,7 @@
     field public static final java.lang.String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
     field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field public static final deprecated java.lang.String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
+    field public static final java.lang.String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
     field public static final java.lang.String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
     field public static final java.lang.String ACTION_USER_REMOVED = "android.intent.action.USER_REMOVED";
     field public static final java.lang.String ACTION_VOICE_ASSIST = "android.intent.action.VOICE_ASSIST";
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 24243af..7662c40 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 #include "statslog.h"
 
@@ -169,7 +169,7 @@
 
 void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    ALOGD("Updated configuration for key %s", key.ToString().c_str());
+    VLOG("Updated configuration for key %s", key.ToString().c_str());
     sp<MetricsManager> newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap);
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 183a995..c24efec 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "StatsService.h"
diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
index 4912648..72d29d0 100644
--- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyMonitor.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true
+#define DEBUG false
 #include "Log.h"
 
 #include "anomaly/AnomalyMonitor.h"
@@ -36,10 +36,10 @@
     sp<IStatsCompanionService> tmpForLock = mStatsCompanionService;
     mStatsCompanionService = statsCompanionService;
     if (statsCompanionService == nullptr) {
-        if (DEBUG) ALOGD("Erasing link to statsCompanionService");
+        VLOG("Erasing link to statsCompanionService");
         return;
     }
-    if (DEBUG) ALOGD("Creating link to statsCompanionService");
+    VLOG("Creating link to statsCompanionService");
     const sp<const AnomalyAlarm> top = mPq.top();
     if (top != nullptr) {
         updateRegisteredAlarmTime_l(top->timestampSec);
@@ -58,7 +58,7 @@
         return;
     }
     // TODO: Ensure that refractory period is respected.
-    if (DEBUG) ALOGD("Adding alarm with time %u", alarm->timestampSec);
+    VLOG("Adding alarm with time %u", alarm->timestampSec);
     mPq.push(alarm);
     if (mRegisteredAlarmTimeSec < 1 ||
         alarm->timestampSec + mMinUpdateTimeSec < mRegisteredAlarmTimeSec) {
@@ -72,16 +72,16 @@
         ALOGW("Asked to remove a null alarm.");
         return;
     }
-    if (DEBUG) ALOGD("Removing alarm with time %u", alarm->timestampSec);
+    VLOG("Removing alarm with time %u", alarm->timestampSec);
     bool wasPresent = mPq.remove(alarm);
     if (!wasPresent) return;
     if (mPq.empty()) {
-        if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+        VLOG("Queue is empty. Cancel any alarm.");
         cancelRegisteredAlarmTime_l();
         return;
     }
     uint32_t soonestAlarmTimeSec = mPq.top()->timestampSec;
-    if (DEBUG) ALOGD("Soonest alarm is %u", soonestAlarmTimeSec);
+    VLOG("Soonest alarm is %u", soonestAlarmTimeSec);
     if (soonestAlarmTimeSec > mRegisteredAlarmTimeSec + mMinUpdateTimeSec) {
         updateRegisteredAlarmTime_l(soonestAlarmTimeSec);
     }
@@ -91,7 +91,7 @@
 // updates to the registered alarm.
 unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> AnomalyMonitor::popSoonerThan(
         uint32_t timestampSec) {
-    if (DEBUG) ALOGD("Removing alarms with time <= %u", timestampSec);
+    VLOG("Removing alarms with time <= %u", timestampSec);
     unordered_set<sp<const AnomalyAlarm>, SpHash<AnomalyAlarm>> oldAlarms;
     std::lock_guard<std::mutex> lock(mLock);
 
@@ -103,7 +103,7 @@
     // Always update registered alarm time (if anything has changed).
     if (!oldAlarms.empty()) {
         if (mPq.empty()) {
-            if (DEBUG) ALOGD("Queue is empty. Cancel any alarm.");
+            VLOG("Queue is empty. Cancel any alarm.");
             cancelRegisteredAlarmTime_l();
         } else {
             // Always update the registered alarm in this case (unlike remove()).
@@ -114,7 +114,7 @@
 }
 
 void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) {
-    if (DEBUG) ALOGD("Updating reg alarm time to %u", timestampSec);
+    VLOG("Updating reg alarm time to %u", timestampSec);
     mRegisteredAlarmTimeSec = timestampSec;
     if (mStatsCompanionService != nullptr) {
         mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec));
@@ -123,7 +123,7 @@
 }
 
 void AnomalyMonitor::cancelRegisteredAlarmTime_l() {
-    if (DEBUG) ALOGD("Cancelling reg alarm.");
+    VLOG("Cancelling reg alarm.");
     mRegisteredAlarmTimeSec = 0;
     if (mStatsCompanionService != nullptr) {
         mStatsCompanionService->cancelAnomalyAlarm();
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7c5e45e..63f6e2a 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "AnomalyTracker.h"
diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
index e459f76..fa0bc0c 100644
--- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "DurationAnomalyTracker.h"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 6bca16f..4c6a36b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -24,6 +24,7 @@
 import "frameworks/base/core/proto/android/app/enums.proto";
 import "frameworks/base/core/proto/android/os/enums.proto";
 import "frameworks/base/core/proto/android/server/enums.proto";
+import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
 
@@ -98,6 +99,7 @@
         DaveyOccurred davey_occurred = 58;
         OverlayStateChanged overlay_state_changed = 59;
         ForegroundServiceStateChanged foreground_service_state_changed = 60;
+        CallStateChanged call_state_changed = 61;
         // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
     }
 
@@ -725,6 +727,33 @@
     optional int64 time_since_last_boot = 6;
 }
 
+
+/**
+ * Logs call state and disconnect cause (if applicable).
+ *
+ * Logged from:
+ *   packages/services/Telecomm/src/com/android/server/telecom/Call.java
+ */
+message CallStateChanged {
+    // The state of the call. Eg. DIALING, ACTIVE, ON_HOLD, DISCONNECTED.
+    // From frameworks/base/core/proto/android/telecomm/enums.proto.
+    optional android.telecom.CallStateEnum call_state = 1;
+
+    // The reason the call disconnected. Eg. ERROR, MISSED, REJECTED, BUSY.
+    // This value is only applicable when the call_state is DISCONNECTED, and
+    // should always be UNKNOWN if the call_state is not DISCONNECTED.
+    // From frameworks/base/core/proto/android/telecomm/enums.proto.
+    optional android.telecom.DisconnectCauseEnum disconnect_cause = 2;
+
+    // True if the call is self-managed, which are apps that use the
+    // telecom infrastructure to make their own calls.
+    optional bool self_managed = 3;
+
+    // True if call is external. External calls are calls on connected Wear
+    // devices but show up in Telecom so the user can pull them onto the device.
+    optional bool external_call = 4;
+}
+
 /**
  * Logs the duration of a davey (jank of >=700ms) when it occurs
  *
diff --git a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
index a751273..d0d2f93 100644
--- a/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidFreqPuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
index e7ea4b9..d9aeb46 100644
--- a/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
+++ b/cmds/statsd/src/external/CpuTimePerUidPuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
index 7a2d199..0e126e7 100644
--- a/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuActiveTimeReader.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
index 7426e74..7684ed4 100644
--- a/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
+++ b/cmds/statsd/src/external/KernelUidCpuClusterTimeReader.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <fstream>
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 1d8a968..b09d373 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"  // Alert
@@ -36,7 +37,7 @@
 namespace statsd {
 
 bool CollectPerfettoTraceAndUploadToDropbox(const PerfettoDetails& config) {
-    ALOGD("Starting trace collection through perfetto");
+    VLOG("Starting trace collection through perfetto");
 
     if (!config.has_trace_config()) {
         ALOGE("The perfetto trace config is empty, aborting");
@@ -118,7 +119,7 @@
         return false;
     }
 
-    ALOGD("CollectPerfettoTraceAndUploadToDropbox() succeeded");
+    VLOG("CollectPerfettoTraceAndUploadToDropbox() succeeded");
     return true;
 }
 
diff --git a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index b955f1c..8210c8d 100644
--- a/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true
+#define DEBUG false
 #include "Log.h"
 
 #include <android/os/IStatsCompanionService.h>
@@ -64,7 +64,7 @@
             std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
             data->push_back(make_shared<LogEvent>(tmp));
         }
-        ALOGD("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
+        VLOG("StatsCompanionServicePuller::pull succeeded for %d", mTagId);
         return true;
     } else {
         ALOGW("statsCompanion not found!");
diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
index 0b772b3..4c676a7 100644
--- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
+++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp
@@ -48,116 +48,73 @@
 namespace statsd {
 
 const std::map<int, PullAtomInfo> StatsPullerManagerImpl::kAllPullAtomInfo = {
-    // wifi_bytes_transfer
-    {android::util::WIFI_BYTES_TRANSFER,
-     {{2, 3, 4, 5},
-      {},
-      1,
-      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,
-      new StatsCompanionServicePuller(
-          android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
-    // mobile_bytes_transfer
-    {android::util::MOBILE_BYTES_TRANSFER,
-     {{2, 3, 4, 5},
-      {},
-      1,
-      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,
-      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)}},
-    // kernel_wakelock
-    {android::util::KERNEL_WAKELOCK,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
-    // subsystem_sleep_state
-    {android::util::SUBSYSTEM_SLEEP_STATE,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::SUBSYSTEM_SLEEP_STATE)}},
-    // cpu_time_per_freq
-    {android::util::CPU_TIME_PER_FREQ,
-     {{3},
-      {2},
-      1,
-      new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
-    // cpu_time_per_uid
-    {android::util::CPU_TIME_PER_UID,
-     {{2, 3}, {}, 1, new CpuTimePerUidPuller()}},
-    // cpu_time_per_uid_freq
-    {android::util::CPU_TIME_PER_UID_FREQ,
-     {{3}, {2}, 1, new CpuTimePerUidFreqPuller()}},
-    // wifi_activity_energy_info
-    {android::util::WIFI_ACTIVITY_ENERGY_INFO,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(
-          android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
-    // modem_activity_info
-    {android::util::MODEM_ACTIVITY_INFO,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
-    // bluetooth_activity_info
-    {android::util::BLUETOOTH_ACTIVITY_INFO,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
-    // system_elapsed_realtime
-    {android::util::SYSTEM_ELAPSED_REALTIME,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
-    // system_uptime
-    {android::util::SYSTEM_UPTIME,
-     {{},
-      {},
-      1,
-      new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
-    // cpu_active_time
-    {android::util::CPU_ACTIVE_TIME,
-     {{3}, {2}, 1, new KernelUidCpuActiveTimeReader()}},
-    // cpu_cluster_time
-    {android::util::CPU_CLUSTER_TIME,
-     {{3}, {2}, 1, new KernelUidCpuClusterTimeReader()}},
-    // disk_space
-    {android::util::DISK_SPACE,
-     {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
-    // remaining_battery_capacity
-    {android::util::REMAINING_BATTERY_CAPACITY,
-     {{},
-      {},
-      1,
-      new ResourceHealthManagerPuller(
-          android::util::REMAINING_BATTERY_CAPACITY)}},
-    // full_battery_capacity
-    {android::util::FULL_BATTERY_CAPACITY,
-     {{},
-      {},
-      1,
-      new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}};
+        // wifi_bytes_transfer
+        {android::util::WIFI_BYTES_TRANSFER,
+         {{2, 3, 4, 5},
+          {},
+          1,
+          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,
+          new StatsCompanionServicePuller(android::util::WIFI_BYTES_TRANSFER_BY_FG_BG)}},
+        // mobile_bytes_transfer
+        {android::util::MOBILE_BYTES_TRANSFER,
+         {{2, 3, 4, 5},
+          {},
+          1,
+          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,
+          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)}},
+        // kernel_wakelock
+        {android::util::KERNEL_WAKELOCK,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::KERNEL_WAKELOCK)}},
+        // subsystem_sleep_state
+        {android::util::SUBSYSTEM_SLEEP_STATE, {{}, {}, 1, new SubsystemSleepStatePuller()}},
+        // cpu_time_per_freq
+        {android::util::CPU_TIME_PER_FREQ,
+         {{3}, {2}, 1, new StatsCompanionServicePuller(android::util::CPU_TIME_PER_FREQ)}},
+        // cpu_time_per_uid
+        {android::util::CPU_TIME_PER_UID, {{2, 3}, {}, 1, new CpuTimePerUidPuller()}},
+        // cpu_time_per_uid_freq
+        {android::util::CPU_TIME_PER_UID_FREQ, {{3}, {2}, 1, new CpuTimePerUidFreqPuller()}},
+        // wifi_activity_energy_info
+        {android::util::WIFI_ACTIVITY_ENERGY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::WIFI_ACTIVITY_ENERGY_INFO)}},
+        // modem_activity_info
+        {android::util::MODEM_ACTIVITY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::MODEM_ACTIVITY_INFO)}},
+        // bluetooth_activity_info
+        {android::util::BLUETOOTH_ACTIVITY_INFO,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::BLUETOOTH_ACTIVITY_INFO)}},
+        // system_elapsed_realtime
+        {android::util::SYSTEM_ELAPSED_REALTIME,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_ELAPSED_REALTIME)}},
+        // system_uptime
+        {android::util::SYSTEM_UPTIME,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}},
+        // cpu_active_time
+        {android::util::CPU_ACTIVE_TIME, {{3}, {2}, 1, new KernelUidCpuActiveTimeReader()}},
+        // cpu_cluster_time
+        {android::util::CPU_CLUSTER_TIME, {{3}, {2}, 1, new KernelUidCpuClusterTimeReader()}},
+        // disk_space
+        {android::util::DISK_SPACE,
+         {{}, {}, 1, new StatsCompanionServicePuller(android::util::DISK_SPACE)}},
+        // remaining_battery_capacity
+        {android::util::REMAINING_BATTERY_CAPACITY,
+         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::REMAINING_BATTERY_CAPACITY)}},
+        // full_battery_capacity
+        {android::util::FULL_BATTERY_CAPACITY,
+         {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}};
 
 StatsPullerManagerImpl::StatsPullerManagerImpl()
     : mCurrentPullingInterval(LONG_MAX) {
@@ -165,14 +122,14 @@
 }
 
 bool StatsPullerManagerImpl::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
-    if (DEBUG) ALOGD("Initiating pulling %d", tagId);
+    VLOG("Initiating pulling %d", tagId);
 
     if (kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end()) {
-      bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
-      ALOGD("pulled %d items", (int)data->size());
-      return ret;
+        bool ret = kAllPullAtomInfo.find(tagId)->second.puller->Pull(data);
+        VLOG("pulled %d items", (int)data->size());
+        return ret;
     } else {
-        ALOGD("Unknown tagId %d", tagId);
+        VLOG("Unknown tagId %d", tagId);
         return false;  // Return early since we don't know what to pull.
     }
 }
@@ -183,7 +140,7 @@
 }
 
 bool StatsPullerManagerImpl::PullerForMatcherExists(int tagId) const {
-  return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
+    return kAllPullAtomInfo.find(tagId) != kAllPullAtomInfo.end();
 }
 
 void StatsPullerManagerImpl::RegisterReceiver(int tagId, wp<PullDataReceiver> receiver,
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
index 550a064..65a1df0e 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <android/hardware/power/1.0/IPower.h>
diff --git a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
index e1947c4..01c7587 100644
--- a/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
+++ b/cmds/statsd/src/guardrail/MemoryLeakTrackUtil.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include <sstream>
@@ -63,7 +63,7 @@
     size_t count;
     if (info == nullptr || overallSize == 0 || infoSize == 0 ||
         (count = overallSize / infoSize) == 0) {
-        ALOGD("no malloc info, libc.debug.malloc.program property should be set");
+        VLOG("no malloc info, libc.debug.malloc.program property should be set");
         return std::string();
     }
 
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 77f5456..06c5b00 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "StatsdStats.h"
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index c8857aa..e1ab5d5 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "logd/LogEvent.h"
 
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index eb6f0cb..6c21b05 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 #include "MetricsManager.h"
 #include "statslog.h"
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index a0173ee..205c8e4 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "../condition/CombinationConditionTracker.h"
@@ -541,7 +541,7 @@
         ALOGE("initLogMatchingTrackers failed");
         return false;
     }
-    ALOGD("initLogMatchingTrackers succeed...");
+    VLOG("initLogMatchingTrackers succeed...");
 
     if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
                         trackerToConditionMap)) {
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 691423e..0d7b722 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "guardrail/StatsdStats.h"
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 00d8658..23bd5561 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG true  // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 
 #include "android-base/stringprintf.h"
diff --git a/config/hiddenapi-blacklist.txt b/config/hiddenapi-blacklist.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/hiddenapi-blacklist.txt
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index ffe2d4d..71de479 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -46,7 +46,6 @@
 Landroid/app/ActivityThread$H;->CREATE_SERVICE:I
 Landroid/app/ActivityThread$H;->EXIT_APPLICATION:I
 Landroid/app/ActivityThread$H;->RECEIVER:I
-Landroid/app/ActivityThread$H;->RELAUNCH_ACTIVITY:I
 Landroid/app/ActivityThread$H;->REMOVE_PROVIDER:I
 Landroid/app/ActivityThread$H;->SERVICE_ARGS:I
 Landroid/app/ActivityThread$H;->STOP_SERVICE:I
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3d088ff..5a63319 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -113,6 +113,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.LogPrinter;
+import android.util.MergedConfiguration;
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
@@ -166,9 +167,9 @@
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.text.DateFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -204,7 +205,7 @@
     private static final boolean DEBUG_SERVICE = false;
     public static final boolean DEBUG_MEMORY_TRIM = false;
     private static final boolean DEBUG_PROVIDER = false;
-    private static final boolean DEBUG_ORDER = false;
+    public static final boolean DEBUG_ORDER = false;
     private static final long MIN_TIME_BETWEEN_GCS = 5*1000;
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
     private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
@@ -222,7 +223,7 @@
     private static final boolean REPORT_TO_ACTIVITY = true;
 
     // Maximum number of recent tokens to maintain for debugging purposes
-    private static final int MAX_RECENT_TOKENS = 10;
+    private static final int MAX_DESTROYED_ACTIVITIES = 10;
 
     /**
      * Denotes an invalid sequence number corresponding to a process state change.
@@ -256,7 +257,7 @@
     final H mH = new H();
     final Executor mExecutor = new HandlerExecutor(mH);
     final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
-    final ArrayDeque<Integer> mRecentTokens = new ArrayDeque<>();
+    final ArrayList<DestroyedActivityInfo> mRecentDestroyedActivities = new ArrayList<>();
 
     // List of new activities (via ActivityRecord.nextIdle) that should
     // be reported when next we idle.
@@ -339,6 +340,26 @@
         }
     }
 
+    /**
+     * TODO(b/71506345): Remove this once bug is resolved.
+     */
+    private static final class DestroyedActivityInfo {
+        private final Integer mToken;
+        private final String mReason;
+        private final long mTime;
+
+        DestroyedActivityInfo(Integer token, String reason) {
+            mToken = token;
+            mReason = reason;
+            mTime = System.currentTimeMillis();
+        }
+
+        void dump(PrintWriter pw, String prefix) {
+            pw.println(prefix + "[token:" + mToken + " | time:" + mTime + " | reason:" + mReason
+                    + "]");
+        }
+    }
+
     // The lock of mProviderMap protects the following variables.
     final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
         = new ArrayMap<ProviderKey, ProviderClientRecord>();
@@ -398,7 +419,6 @@
         boolean startsNotResumed;
         public final boolean isForward;
         int pendingConfigChanges;
-        boolean onlyLocalRequest;
 
         Window mPendingRemoveWindow;
         WindowManager mPendingRemoveWindowManager;
@@ -520,7 +540,6 @@
             sb.append(", startsNotResumed=").append(startsNotResumed);
             sb.append(", isForward=").append(isForward);
             sb.append(", pendingConfigChanges=").append(pendingConfigChanges);
-            sb.append(", onlyLocalRequest=").append(onlyLocalRequest);
             sb.append(", preserveWindow=").append(mPreserveWindow);
             if (activity != null) {
                 sb.append(", Activity{");
@@ -765,15 +784,6 @@
             sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
         }
 
-        @Override
-        public final void scheduleRelaunchActivity(IBinder token,
-                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-                int configChanges, boolean notResumed, Configuration config,
-                Configuration overrideConfig, boolean preserveWindow) {
-            requestRelaunchActivity(token, pendingResults, pendingNewIntents,
-                    configChanges, notResumed, config, overrideConfig, true, preserveWindow);
-        }
-
         public final void scheduleReceiver(Intent intent, ActivityInfo info,
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                 boolean sync, int sendingUser, int processState) {
@@ -1531,7 +1541,6 @@
         public static final int UNBIND_SERVICE          = 122;
         public static final int DUMP_SERVICE            = 123;
         public static final int LOW_MEMORY              = 124;
-        public static final int RELAUNCH_ACTIVITY       = 126;
         public static final int PROFILER_CONTROL        = 127;
         public static final int CREATE_BACKUP_AGENT     = 128;
         public static final int DESTROY_BACKUP_AGENT    = 129;
@@ -1577,7 +1586,6 @@
                     case UNBIND_SERVICE: return "UNBIND_SERVICE";
                     case DUMP_SERVICE: return "DUMP_SERVICE";
                     case LOW_MEMORY: return "LOW_MEMORY";
-                    case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
                     case PROFILER_CONTROL: return "PROFILER_CONTROL";
                     case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
                     case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
@@ -1611,12 +1619,6 @@
         public void handleMessage(Message msg) {
             if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
             switch (msg.what) {
-                case RELAUNCH_ACTIVITY: {
-                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
-                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
-                    handleRelaunchActivity(r);
-                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
-                } break;
                 case BIND_APPLICATION:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                     AppBindData data = (AppBindData)msg.obj;
@@ -2182,14 +2184,28 @@
 
     @Override
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "mActivities:");
+        pw.println(prefix + "Activities:");
 
-        for (ArrayMap.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-            pw.println(prefix + "  [token:" + entry.getKey().hashCode() + " record:"
-                    + entry.getValue().toString() + "]");
+        if (!mActivities.isEmpty()) {
+            final Iterator<Map.Entry<IBinder, ActivityClientRecord>> activitiesIterator =
+                    mActivities.entrySet().iterator();
+
+            while (activitiesIterator.hasNext()) {
+                final ArrayMap.Entry<IBinder, ActivityClientRecord> entry =
+                        activitiesIterator.next();
+                pw.println(prefix + "  [token:" + entry.getKey().hashCode() + " record:"
+                        + entry.getValue().toString() + "]");
+            }
         }
 
-        pw.println(prefix + "mRecentTokens:" + mRecentTokens);
+        if (!mRecentDestroyedActivities.isEmpty()) {
+            pw.println(prefix + "Recent destroyed activities:");
+            for (int i = 0, size = mRecentDestroyedActivities.size(); i < size; i++) {
+                final DestroyedActivityInfo info = mRecentDestroyedActivities.get(i);
+                pw.print(prefix);
+                info.dump(pw, "  ");
+            }
+        }
     }
 
     public static void dumpMemInfoTable(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
@@ -2876,11 +2892,6 @@
             r.setState(ON_CREATE);
 
             mActivities.put(r.token, r);
-            mRecentTokens.push(r.token.hashCode());
-
-            if (mRecentTokens.size() > MAX_RECENT_TOKENS) {
-                mRecentTokens.removeLast();
-            }
 
         } catch (SuperNotCalledException e) {
             throw e;
@@ -3726,20 +3737,6 @@
                 }
                 r.activity.performResume(r.startsNotResumed);
 
-                synchronized (mResourcesManager) {
-                    // If there is a pending local relaunch that was requested when the activity was
-                    // paused, it will put the activity into paused state when it finally happens.
-                    // Since the activity resumed before being relaunched, we don't want that to
-                    // happen, so we need to clear the request to relaunch paused.
-                    for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
-                        final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
-                        if (relaunching.token == r.token
-                                && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
-                            relaunching.startsNotResumed = false;
-                        }
-                    }
-                }
-
                 EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
                         r.activity.getComponentName().getClassName(), reason);
 
@@ -3888,14 +3885,12 @@
                 }
             }
 
-            if (!r.onlyLocalRequest) {
-                r.nextIdle = mNewActivities;
-                mNewActivities = r;
-                if (localLOGV) Slog.v(
-                    TAG, "Scheduling idle handler for " + r);
-                Looper.myQueue().addIdleHandler(new Idler());
+            r.nextIdle = mNewActivities;
+            mNewActivities = r;
+            if (localLOGV) {
+                Slog.v(TAG, "Scheduling idle handler for " + r);
             }
-            r.onlyLocalRequest = false;
+            Looper.myQueue().addIdleHandler(new Idler());
         } else {
             // If an exception was thrown when trying to resume, then
             // just end this activity.
@@ -4453,7 +4448,7 @@
 
     /** Core implementation of activity destroy call. */
     ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
-            int configChanges, boolean getNonConfigInstance) {
+            int configChanges, boolean getNonConfigInstance, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         Class<? extends Activity> activityClass = null;
         if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
@@ -4505,6 +4500,12 @@
             r.setState(ON_DESTROY);
         }
         mActivities.remove(token);
+        mRecentDestroyedActivities.add(0, new DestroyedActivityInfo(token.hashCode(), reason));
+
+        final int recentDestroyedActivitiesSize = mRecentDestroyedActivities.size();
+        if (recentDestroyedActivitiesSize > MAX_DESTROYED_ACTIVITIES) {
+            mRecentDestroyedActivities.remove(recentDestroyedActivitiesSize - 1);
+        }
         StrictMode.decrementExpectedActivityCount(activityClass);
         return r;
     }
@@ -4516,9 +4517,9 @@
 
     @Override
     public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
-            boolean getNonConfigInstance) {
+            boolean getNonConfigInstance, String reason) {
         ActivityClientRecord r = performDestroyActivity(token, finishing,
-                configChanges, getNonConfigInstance);
+                configChanges, getNonConfigInstance, reason);
         if (r != null) {
             cleanUpPendingRemoveWindows(r, finishing);
             WindowManager wm = r.activity.getWindowManager();
@@ -4586,15 +4587,12 @@
         mSomeActivitiesChanged = true;
     }
 
-    /**
-     * @param preserveWindow Whether the activity should try to reuse the window it created,
-     *                        including the decor view after the relaunch.
-     */
-    public final void requestRelaunchActivity(IBinder token,
+    @Override
+    public ActivityClientRecord prepareRelaunchActivity(IBinder token,
             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, boolean notResumed, Configuration config,
-            Configuration overrideConfig, boolean fromServer, boolean preserveWindow) {
+            int configChanges, MergedConfiguration config, boolean preserveWindow) {
         ActivityClientRecord target = null;
+        boolean scheduleRelaunch = false;
 
         synchronized (mResourcesManager) {
             for (int i=0; i<mRelaunchingActivities.size(); i++) {
@@ -4616,57 +4614,31 @@
                             r.pendingIntents = pendingNewIntents;
                         }
                     }
-
-                    // For each relaunch request, activity manager expects an answer
-                    if (!r.onlyLocalRequest && fromServer) {
-                        try {
-                            ActivityManager.getService().activityRelaunched(token);
-                        } catch (RemoteException e) {
-                            throw e.rethrowFromSystemServer();
-                        }
-                    }
                     break;
                 }
             }
 
             if (target == null) {
-                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
-                        + fromServer);
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null");
                 target = new ActivityClientRecord();
                 target.token = token;
                 target.pendingResults = pendingResults;
                 target.pendingIntents = pendingNewIntents;
                 target.mPreserveWindow = preserveWindow;
-                if (!fromServer) {
-                    final ActivityClientRecord existing = mActivities.get(token);
-                    if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
-                    if (existing != null) {
-                        if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
-                                + existing.paused);;
-                        target.startsNotResumed = existing.paused;
-                        target.overrideConfig = existing.overrideConfig;
-                    }
-                    target.onlyLocalRequest = true;
-                }
                 mRelaunchingActivities.add(target);
-                sendMessage(H.RELAUNCH_ACTIVITY, target);
+                scheduleRelaunch = true;
             }
-
-            if (fromServer) {
-                target.startsNotResumed = notResumed;
-                target.onlyLocalRequest = false;
-            }
-            if (config != null) {
-                target.createdConfig = config;
-            }
-            if (overrideConfig != null) {
-                target.overrideConfig = overrideConfig;
-            }
+            target.createdConfig = config.getGlobalConfiguration();
+            target.overrideConfig = config.getOverrideConfiguration();
             target.pendingConfigChanges |= configChanges;
         }
+
+        return scheduleRelaunch ? target : null;
     }
 
-    private void handleRelaunchActivity(ActivityClientRecord tmp) {
+    @Override
+    public void handleRelaunchActivity(ActivityClientRecord tmp,
+            PendingTransactionActions pendingActions) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -4735,18 +4707,10 @@
         ActivityClientRecord r = mActivities.get(tmp.token);
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
         if (r == null) {
-            if (!tmp.onlyLocalRequest) {
-                try {
-                    ActivityManager.getService().activityRelaunched(tmp.token);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
-            }
             return;
         }
 
         r.activity.mConfigChangeFlags |= configChanges;
-        r.onlyLocalRequest = tmp.onlyLocalRequest;
         r.mPreserveWindow = tmp.mPreserveWindow;
 
         r.activity.mChangingConfigurations = true;
@@ -4763,9 +4727,9 @@
         // preserved by the server, so we want to notify it that we are preparing to replace
         // everything
         try {
-            if (r.mPreserveWindow || r.onlyLocalRequest) {
+            if (r.mPreserveWindow) {
                 WindowManagerGlobal.getWindowSession().prepareToReplaceWindows(
-                        r.token, !r.onlyLocalRequest);
+                        r.token, true /* childrenOnly */);
             }
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -4780,7 +4744,7 @@
             callActivityOnStop(r, true /* saveState */, "handleRelaunchActivity");
         }
 
-        handleDestroyActivity(r.token, false, configChanges, true);
+        handleDestroyActivity(r.token, false, configChanges, true, "handleRelaunchActivity");
 
         r.activity = null;
         r.window = null;
@@ -4804,24 +4768,22 @@
         r.startsNotResumed = tmp.startsNotResumed;
         r.overrideConfig = tmp.overrideConfig;
 
-        // TODO(lifecycler): Move relaunch to lifecycler.
-        PendingTransactionActions pendingActions = new PendingTransactionActions();
         handleLaunchActivity(r, pendingActions);
-        handleStartActivity(r, pendingActions);
-        handleResumeActivity(r.token, false /* clearHide */, r.isForward, "relaunch");
-        if (r.startsNotResumed) {
-            performPauseActivity(r, false /* finished */, "relaunch", pendingActions);
-        }
+        // Only report a successful relaunch to WindowManager.
+        pendingActions.setReportRelaunchToWindowManager(true);
+    }
 
-        if (!tmp.onlyLocalRequest) {
-            try {
-                ActivityManager.getService().activityRelaunched(r.token);
-                if (r.window != null) {
-                    r.window.reportActivityRelaunched();
-                }
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
+    @Override
+    public void reportRelaunch(IBinder token, PendingTransactionActions pendingActions) {
+        try {
+            ActivityManager.getService().activityRelaunched(token);
+            final ActivityClientRecord r = mActivities.get(token);
+            if (pendingActions.shouldReportRelaunchToWindowManager() && r != null
+                    && r.window != null) {
+                r.window.reportActivityRelaunched();
             }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5890,21 +5852,23 @@
 
         // Preload fonts resources
         FontsContract.setApplicationContextForResources(appContext);
-        try {
-            final ApplicationInfo info =
-                    getPackageManager().getApplicationInfo(
-                            data.appInfo.packageName,
-                            PackageManager.GET_META_DATA /*flags*/,
-                            UserHandle.myUserId());
-            if (info.metaData != null) {
-                final int preloadedFontsResource = info.metaData.getInt(
-                        ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
-                if (preloadedFontsResource != 0) {
-                    data.info.getResources().preloadFonts(preloadedFontsResource);
+        if (!Process.isIsolated()) {
+            try {
+                final ApplicationInfo info =
+                        getPackageManager().getApplicationInfo(
+                                data.appInfo.packageName,
+                                PackageManager.GET_META_DATA /*flags*/,
+                                UserHandle.myUserId());
+                if (info.metaData != null) {
+                    final int preloadedFontsResource = info.metaData.getInt(
+                            ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
+                    if (preloadedFontsResource != 0) {
+                        data.info.getResources().preloadFonts(preloadedFontsResource);
+                    }
                 }
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
         }
     }
 
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index 5b61fdf..310965e 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -21,6 +21,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.os.IBinder;
+import android.util.MergedConfiguration;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -60,7 +61,7 @@
 
     /** Destroy the activity. */
     public abstract void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
-            boolean getNonConfigInstance);
+            boolean getNonConfigInstance, String reason);
 
     /** Pause the activity. */
     public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving,
@@ -124,6 +125,39 @@
     public abstract ActivityThread.ActivityClientRecord getActivityClient(IBinder token);
 
     /**
+     * Prepare activity relaunch to update internal bookkeeping. This is used to track multiple
+     * relaunch and config update requests.
+     * @param token Activity token.
+     * @param pendingResults Activity results to be delivered.
+     * @param pendingNewIntents New intent messages to be delivered.
+     * @param configChanges Mask of configuration changes that have occurred.
+     * @param config New configuration applied to the activity.
+     * @param preserveWindow Whether the activity should try to reuse the window it created,
+     *                        including the decor view after the relaunch.
+     * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during
+     *         relaunch, or {@code null} if relaunch cancelled.
+     */
+    public abstract ActivityThread.ActivityClientRecord prepareRelaunchActivity(IBinder token,
+            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
+            int configChanges, MergedConfiguration config, boolean preserveWindow);
+
+    /**
+     * Perform activity relaunch.
+     * @param r Activity client record prepared for relaunch.
+     * @param pendingActions Pending actions to be used on later stages of activity transaction.
+     * */
+    public abstract void handleRelaunchActivity(ActivityThread.ActivityClientRecord r,
+            PendingTransactionActions pendingActions);
+
+    /**
+     * Report that relaunch request was handled.
+     * @param token Target activity token.
+     * @param pendingActions Pending actions initialized on earlier stages of activity transaction.
+     *                       Used to check if we should report relaunch to WM.
+     * */
+    public abstract void reportRelaunch(IBinder token, PendingTransactionActions pendingActions);
+
+    /**
      * Debugging output.
      * @param pw {@link PrintWriter} to write logs to.
      * @param prefix Prefix to prepend to output.
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4a9b2bc..a1ba13d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -409,6 +409,7 @@
         return sp;
     }
 
+    @GuardedBy("ContextImpl.class")
     private ArrayMap<File, SharedPreferencesImpl> getSharedPreferencesCacheLocked() {
         if (sSharedPrefsCache == null) {
             sSharedPrefsCache = new ArrayMap<>();
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 9e99a78..ae9b83e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -83,9 +83,6 @@
             int resultCode, in String data, in Bundle extras, boolean ordered,
             boolean sticky, int sendingUser, int processState);
     void scheduleLowMemory();
-    void scheduleRelaunchActivity(IBinder token, in List<ResultInfo> pendingResults,
-            in List<ReferrerIntent> pendingNewIntents, int configChanges, boolean notResumed,
-            in Configuration config, in Configuration overrideConfig, boolean preserveWindow);
     void scheduleSleeping(IBinder token, boolean sleeping);
     void profilerControl(boolean start, in ProfilerInfo profilerInfo, int profileType);
     void setSchedulingGroup(int group);
diff --git a/core/java/android/app/LocalActivityManager.java b/core/java/android/app/LocalActivityManager.java
index 1d34595..e297719 100644
--- a/core/java/android/app/LocalActivityManager.java
+++ b/core/java/android/app/LocalActivityManager.java
@@ -380,7 +380,7 @@
         }
         if (localLOGV) Log.v(TAG, r.id + ": destroying");
         mActivityThread.performDestroyActivity(r, finish, 0 /* configChanges */,
-                false /* getNonConfigInstance */);
+                false /* getNonConfigInstance */, "LocalActivityManager::performDestroy");
         r.activity = null;
         r.window = null;
         if (finish) {
@@ -645,7 +645,7 @@
             LocalActivityRecord r = mActivityArray.get(i);
             if (localLOGV) Log.v(TAG, r.id + ": destroying");
             mActivityThread.performDestroyActivity(r, finishing, 0 /* configChanges */,
-                    false /* getNonConfigInstance */);
+                    false /* getNonConfigInstance */, "LocalActivityManager::dispatchDestroy");
         }
         mActivities.clear();
         mActivityArray.clear();
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 256c479..ea0fd75 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -471,14 +471,6 @@
      * {@link #onStart} and returns either {@link #START_STICKY}
      * or {@link #START_STICKY_COMPATIBILITY}.
      * 
-     * <p>If you need your application to run on platform versions prior to API
-     * level 5, you can use the following model to handle the older {@link #onStart}
-     * callback in that case.  The <code>handleCommand</code> method is implemented by
-     * you as appropriate:
-     * 
-     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
-     *   start_compatibility}
-     *
      * <p class="caution">Note that the system calls this on your
      * service's main thread.  A service's main thread is the same
      * thread where UI operations take place for Activities running in the
@@ -687,6 +679,10 @@
      * {@link #startService(Intent)} first to tell the system it should keep the service running,
      * and then use this method to tell it to keep it running harder.</p>
      *
+     * <p>Apps targeting API {@link android.os.Build.VERSION_CODES#P} or later must request
+     * the permission {@link android.Manifest.permission#FOREGROUND_SERVICE} in order to use
+     * this API.</p>
+     *
      * @param id The identifier for this notification as per
      * {@link NotificationManager#notify(int, Notification)
      * NotificationManager.notify(int, Notification)}; must not be 0.
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 88e42d5..c2c91c2 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -33,6 +33,7 @@
 public final class StatsManager {
     IStatsManager mService;
     private static final String TAG = "StatsManager";
+    private static final boolean DEBUG = false;
 
     /**
      * Long extra of uid that added the relevant stats config.
@@ -74,6 +75,14 @@
     }
 
     /**
+     * Temporary. Will be deleted.
+     */
+    @RequiresPermission(Manifest.permission.DUMP)
+    public boolean addConfiguration(long configKey, byte[] config, String a, String b) {
+        return addConfiguration(configKey, config);
+    }
+
+    /**
      * Clients can send a configuration and simultaneously registers the name of a broadcast
      * receiver that listens for when it should request data.
      *
@@ -88,12 +97,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when adding configuration");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when adding configuration");
                     return false;
                 }
                 return service.addConfiguration(configKey, config);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when adding configuration");
+                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when adding configuration");
                 return false;
             }
         }
@@ -111,12 +120,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when removing configuration");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when removing configuration");
                     return false;
                 }
                 return service.removeConfiguration(configKey);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connect to statsd when removing configuration");
+                if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when removing configuration");
                 return false;
             }
         }
@@ -225,12 +234,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting data");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting data");
                     return null;
                 }
                 return service.getData(configKey);
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting data");
+                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data");
                 return null;
             }
         }
@@ -249,12 +258,12 @@
             try {
                 IStatsManager service = getIStatsManagerLocked();
                 if (service == null) {
-                    Slog.d(TAG, "Failed to find statsd when getting metadata");
+                    if (DEBUG) Slog.d(TAG, "Failed to find statsd when getting metadata");
                     return null;
                 }
                 return service.getMetadata();
             } catch (RemoteException e) {
-                Slog.d(TAG, "Failed to connecto statsd when getting metadata");
+                if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting metadata");
                 return null;
             }
         }
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
new file mode 100644
index 0000000..d8a7463
--- /dev/null
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.servertransaction;
+
+import static android.app.ActivityThread.DEBUG_ORDER;
+
+import android.app.ActivityThread;
+import android.app.ClientTransactionHandler;
+import android.app.ResultInfo;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Trace;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+
+import com.android.internal.content.ReferrerIntent;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity relaunch callback.
+ * @hide
+ */
+public class ActivityRelaunchItem extends ClientTransactionItem {
+
+    private static final String TAG = "ActivityRelaunchItem";
+
+    private List<ResultInfo> mPendingResults;
+    private List<ReferrerIntent> mPendingNewIntents;
+    private int mConfigChanges;
+    private MergedConfiguration mConfig;
+    private boolean mPreserveWindow;
+
+    /**
+     * A record that was properly configured for relaunch. Execution will be cancelled if not
+     * initialized after {@link #preExecute(ClientTransactionHandler, IBinder)}.
+     */
+    private ActivityThread.ActivityClientRecord mActivityClientRecord;
+
+    @Override
+    public void preExecute(ClientTransactionHandler client, IBinder token) {
+        mActivityClientRecord = client.prepareRelaunchActivity(token, mPendingResults,
+                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
+    }
+
+    @Override
+    public void execute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        if (mActivityClientRecord == null) {
+            if (DEBUG_ORDER) Slog.d(TAG, "Activity relaunch cancelled");
+            return;
+        }
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
+        client.handleRelaunchActivity(mActivityClientRecord, pendingActions);
+        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+    }
+
+    @Override
+    public void postExecute(ClientTransactionHandler client, IBinder token,
+            PendingTransactionActions pendingActions) {
+        client.reportRelaunch(token, pendingActions);
+    }
+
+    // ObjectPoolItem implementation
+
+    private ActivityRelaunchItem() {}
+
+    /** Obtain an instance initialized with provided params. */
+    public static ActivityRelaunchItem obtain(List<ResultInfo> pendingResults,
+            List<ReferrerIntent> pendingNewIntents, int configChanges, MergedConfiguration config,
+            boolean preserveWindow) {
+        ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
+        if (instance == null) {
+            instance = new ActivityRelaunchItem();
+        }
+        instance.mPendingResults = pendingResults;
+        instance.mPendingNewIntents = pendingNewIntents;
+        instance.mConfigChanges = configChanges;
+        instance.mConfig = config;
+        instance.mPreserveWindow = preserveWindow;
+
+        return instance;
+    }
+
+    @Override
+    public void recycle() {
+        mPendingResults = null;
+        mPendingNewIntents = null;
+        mConfigChanges = 0;
+        mConfig = null;
+        mPreserveWindow = false;
+        mActivityClientRecord = null;
+        ObjectPool.recycle(this);
+    }
+
+
+    // Parcelable implementation
+
+    /** Write to Parcel. */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeTypedList(mPendingResults, flags);
+        dest.writeTypedList(mPendingNewIntents, flags);
+        dest.writeInt(mConfigChanges);
+        dest.writeTypedObject(mConfig, flags);
+        dest.writeBoolean(mPreserveWindow);
+    }
+
+    /** Read from Parcel. */
+    private ActivityRelaunchItem(Parcel in) {
+        mPendingResults = in.createTypedArrayList(ResultInfo.CREATOR);
+        mPendingNewIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
+        mConfigChanges = in.readInt();
+        mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
+        mPreserveWindow = in.readBoolean();
+    }
+
+    public static final Creator<ActivityRelaunchItem> CREATOR =
+            new Creator<ActivityRelaunchItem>() {
+                public ActivityRelaunchItem createFromParcel(Parcel in) {
+                    return new ActivityRelaunchItem(in);
+                }
+
+                public ActivityRelaunchItem[] newArray(int size) {
+                    return new ActivityRelaunchItem[size];
+                }
+            };
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        final ActivityRelaunchItem other = (ActivityRelaunchItem) o;
+        return Objects.equals(mPendingResults, other.mPendingResults)
+                && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
+                && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
+                && mPreserveWindow == other.mPreserveWindow;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + Objects.hashCode(mPendingResults);
+        result = 31 * result + Objects.hashCode(mPendingNewIntents);
+        result = 31 * result + mConfigChanges;
+        result = 31 * result + Objects.hashCode(mConfig);
+        result = 31 * result + (mPreserveWindow ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "ActivityRelaunchItem{pendingResults=" + mPendingResults
+                + ",pendingNewIntents=" + mPendingNewIntents + ",configChanges="  + mConfigChanges
+                + ",config=" + mConfig + ",preserveWindow" + mPreserveWindow + "}";
+    }
+}
diff --git a/core/java/android/app/servertransaction/DestroyActivityItem.java b/core/java/android/app/servertransaction/DestroyActivityItem.java
index cbcf6c7..48a79f7 100644
--- a/core/java/android/app/servertransaction/DestroyActivityItem.java
+++ b/core/java/android/app/servertransaction/DestroyActivityItem.java
@@ -37,7 +37,7 @@
             PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
         client.handleDestroyActivity(token, mFinished, mConfigChanges,
-                false /* getNonConfigInstance */);
+                false /* getNonConfigInstance */, getDescription());
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/servertransaction/PendingTransactionActions.java b/core/java/android/app/servertransaction/PendingTransactionActions.java
index 073d28c..af7b7a2 100644
--- a/core/java/android/app/servertransaction/PendingTransactionActions.java
+++ b/core/java/android/app/servertransaction/PendingTransactionActions.java
@@ -44,6 +44,7 @@
     private boolean mCallOnPostCreate;
     private Bundle mOldState;
     private StopInfo mStopInfo;
+    private boolean mReportRelaunchToWM;
 
     public PendingTransactionActions() {
         clear();
@@ -91,6 +92,24 @@
         mStopInfo = stopInfo;
     }
 
+    /**
+     * Check if we should report an activity relaunch to WindowManager. We report back for every
+     * relaunch request to ActivityManager, but only for those that were actually finished to we
+     * report to WindowManager.
+     */
+    public boolean shouldReportRelaunchToWindowManager() {
+        return mReportRelaunchToWM;
+    }
+
+    /**
+     * Set if we should report an activity relaunch to WindowManager. We report back for every
+     * relaunch request to ActivityManager, but only for those that were actually finished we report
+     * to WindowManager.
+     */
+    public void setReportRelaunchToWindowManager(boolean reportToWm) {
+        mReportRelaunchToWM = reportToWm;
+    }
+
     /** Reports to server about activity stop. */
     public static class StopInfo implements Runnable {
         private static final String TAG = "ActivityStopInfo";
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 78b393a..840fef8 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -194,7 +194,9 @@
                     break;
                 case ON_DESTROY:
                     mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */,
-                            0 /* configChanges */, false /* getNonConfigInstance */);
+                            0 /* configChanges */, false /* getNonConfigInstance */,
+                            "performLifecycleSequence. cycling to:"
+                                    + mLifecycleSequence.get(size - 1));
                     break;
                 case ON_RESTART:
                     mTransactionHandler.performRestartActivity(r.token, false /* start */);
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index edb992b..6b573e9 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -16,6 +16,7 @@
 package android.app.usage;
 
 import android.annotation.IntDef;
+import android.annotation.SystemApi;
 import android.content.res.Configuration;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -104,12 +105,14 @@
          * An event type denoting that a notification was viewed by the user.
          * @hide
          */
+        @SystemApi
         public static final int NOTIFICATION_SEEN = 10;
 
         /**
          * An event type denoting a change in App Standby Bucket.
          * @hide
          */
+        @SystemApi
         public static final int STANDBY_BUCKET_CHANGED = 11;
 
         /** @hide */
@@ -257,6 +260,17 @@
             return mShortcutId;
         }
 
+        /**
+         * Returns the standby bucket of the app, if the event is of type
+         * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
+         * @return the standby bucket associated with the event.
+         * @hide
+         */
+        @SystemApi
+        public int getStandbyBucket() {
+            return mBucket;
+        }
+
         /** @hide */
         public Event getObfuscatedIfInstantApp() {
             if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index bb37eb31b..15f3777 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -560,6 +560,7 @@
      *
      * @param resId Resource id for the CharSequence text
      */
+    @NonNull
     public final CharSequence getText(@StringRes int resId) {
         return getResources().getText(resId);
     }
@@ -616,12 +617,11 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return An object that can be used to draw this resource, or
-     *         {@code null} if the resource could not be resolved.
+     * @return An object that can be used to draw this resource.
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @Nullable
+    @NonNull
     public final Drawable getDrawable(@DrawableRes int id) {
         return getResources().getDrawable(id, getTheme());
     }
@@ -633,12 +633,11 @@
      * @param id The desired resource identifier, as generated by the aapt
      *           tool. This integer encodes the package, type, and resource
      *           entry. The value 0 is an invalid identifier.
-     * @return A color state list, or {@code null} if the resource could not be
-     *         resolved.
+     * @return A color state list.
      * @throws android.content.res.Resources.NotFoundException if the given ID
      *         does not exist.
      */
-    @Nullable
+    @NonNull
     public final ColorStateList getColorStateList(@ColorRes int id) {
         return getResources().getColorStateList(id, getTheme());
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fa73e3c..12d4079 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2399,6 +2399,26 @@
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
+
+    /**
+     * Broadcast Action: The current device {@link android.content.res.Configuration} has changed
+     * such that the device may be eligible for the installation of additional configuration splits.
+     * Configuration properties that can trigger this broadcast include locale and display density.
+     *
+     * <p class="note">
+     * Unlike {@link #ACTION_CONFIGURATION_CHANGED}, you <em>can</em> receive this through
+     * components declared in manifests. However, the receiver <em>must</em> hold the
+     * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
+     *
+     * <p class="note">
+     * This is a protected intent that can only be sent by the system.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SPLIT_CONFIGURATION_CHANGED =
+            "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
     /**
      * Broadcast Action: The current device's locale has changed.
      *
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
index 02d0a6d..79bc9a3 100644
--- a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -274,6 +274,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void scheduleNextMessageIfNeededLocked() {
             if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
                 Message nextMessage = mPendingWork.remove(0);
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 24116b4..bb90700 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -143,6 +143,7 @@
     /**
      * This must be called from Zygote so that system assets are shared by all applications.
      */
+    @GuardedBy("sSync")
     private static void createSystemAssetsInZygoteLocked() {
         if (sSystem != null) {
             return;
@@ -366,6 +367,7 @@
      * The AssetManager may have been closed, but references to it still exist
      * and therefore the native implementation is not destroyed.
      */
+    @GuardedBy("this")
     private void ensureValidLocked() {
         if (mObject == 0) {
             throw new RuntimeException("AssetManager has been destroyed");
@@ -376,6 +378,7 @@
      * Ensures that the AssetManager has not been explicitly closed. If this method passes,
      * then this implies that ensureValidLocked() also passes.
      */
+    @GuardedBy("this")
     private void ensureOpenLocked() {
         // If mOpen is true, this implies that mObject != 0.
         if (!mOpen) {
@@ -1189,6 +1192,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void incRefsLocked(long id) {
         if (DEBUG_REFS) {
             if (mRefStacks == null) {
@@ -1201,6 +1205,7 @@
         mNumRefs++;
     }
 
+    @GuardedBy("this")
     private void decRefsLocked(long id) {
         if (DEBUG_REFS && mRefStacks != null) {
             mRefStacks.remove(id);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 8f58891..d813382 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -867,8 +867,9 @@
      * @param theme The theme used to style the drawable attributes, may be {@code null}.
      * @return Drawable An object that can be used to draw this resource.
      * @throws NotFoundException Throws NotFoundException if the given ID does
-     *             not exist.
+     *             not exist, or cannot be decoded.
      */
+    @NonNull
     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
         final TypedValue value = obtainTempTypedValue();
         try {
@@ -980,7 +981,7 @@
      *         or multiple colors that can be selected based on a state.
      * @deprecated Use {@link #getColorStateList(int, Theme)} instead.
      */
-    @Nullable
+    @NonNull
     @Deprecated
     public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException {
         final ColorStateList csl = getColorStateList(id, null);
@@ -1011,7 +1012,7 @@
      * @return A themed ColorStateList object containing either a single solid
      *         color or multiple colors that can be selected based on a state.
      */
-    @Nullable
+    @NonNull
     public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
             throws NotFoundException {
         final TypedValue value = obtainTempTypedValue();
@@ -1024,7 +1025,7 @@
         }
     }
 
-    @Nullable
+    @NonNull
     ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
             throws NotFoundException {
         return mResourcesImpl.loadColorStateList(this, value, id, theme);
@@ -1033,7 +1034,7 @@
     /**
      * @hide
      */
-    @Nullable
+    @NonNull
     public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
         return mResourcesImpl.loadComplexColor(this, value, id, theme);
     }
@@ -1139,6 +1140,7 @@
      *         
      * @see #getXml
      */
+    @NonNull
     public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "layout");
     }
@@ -1163,6 +1165,7 @@
      *         
      * @see #getXml
      */
+    @NonNull
     public XmlResourceParser getAnimation(@AnimatorRes @AnimRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "anim");
     }
@@ -1188,6 +1191,7 @@
      *         
      * @see android.util.AttributeSet
      */
+    @NonNull
     public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException {
         return loadXmlResourceParser(id, "xml");
     }
@@ -1203,8 +1207,8 @@
      * @return InputStream Access to the resource data.
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
-     * 
      */
+    @NonNull
     public InputStream openRawResource(@RawRes int id) throws NotFoundException {
         final TypedValue value = obtainTempTypedValue();
         try {
@@ -1261,6 +1265,7 @@
      *
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
+    @NonNull
     public InputStream openRawResource(@RawRes int id, TypedValue value)
             throws NotFoundException {
         return mResourcesImpl.openRawResource(id, value);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 80e3860..08a1613 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,11 +27,9 @@
 import android.annotation.StyleableRes;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
-import android.content.res.AssetManager.AssetInputStream;
 import android.content.res.Configuration.NativeConfig;
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
-import android.graphics.ImageDecoder;
 import android.graphics.Typeface;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -544,7 +542,7 @@
         }
     }
 
-    @Nullable
+    @NonNull
     Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id,
             int density, @Nullable Resources.Theme theme)
             throws NotFoundException {
@@ -628,7 +626,7 @@
             } else if (isColorDrawable) {
                 dr = new ColorDrawable(value.data);
             } else {
-                dr = loadDrawableForCookie(wrapper, value, id, density, null);
+                dr = loadDrawableForCookie(wrapper, value, id, density);
             }
             // DrawableContainer' constant state has drawables instances. In order to leave the
             // constant state intact in the cache, we need to create a new DrawableContainer after
@@ -755,8 +753,9 @@
     /**
      * Loads a drawable from XML or resources stream.
      */
+    @NonNull
     private Drawable loadDrawableForCookie(@NonNull Resources wrapper, @NonNull TypedValue value,
-            int id, int density, @Nullable Resources.Theme theme) {
+            int id, int density) {
         if (value.string == null) {
             throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
                     + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
@@ -775,22 +774,23 @@
             }
         }
 
-        // For prelaod tracing.
+        // For preload tracing.
         long startTime = 0;
         int startBitmapCount = 0;
         long startBitmapSize = 0;
-        int startDrwableCount = 0;
+        int startDrawableCount = 0;
         if (TRACE_FOR_DETAILED_PRELOAD) {
             startTime = System.nanoTime();
             startBitmapCount = Bitmap.sPreloadTracingNumInstantiatedBitmaps;
             startBitmapSize = Bitmap.sPreloadTracingTotalBitmapsSize;
-            startDrwableCount = sPreloadTracingNumLoadedDrawables;
+            startDrawableCount = sPreloadTracingNumLoadedDrawables;
         }
 
         if (DEBUG_LOAD) {
             Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
         }
 
+
         final Drawable dr;
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
@@ -805,18 +805,13 @@
                 if (file.endsWith(".xml")) {
                     final XmlResourceParser rp = loadXmlResourceParser(
                             file, id, value.assetCookie, "drawable");
-                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
+                    dr = Drawable.createFromXmlForDensity(wrapper, rp, density, null);
                     rp.close();
                 } else {
                     final InputStream is = mAssets.openNonAsset(
                             value.assetCookie, file, AssetManager.ACCESS_STREAMING);
-                    AssetInputStream ais = (AssetInputStream) is;
-                    // ImageDecoder will close the input stream.
-                    ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
-                            wrapper, value);
-                    dr = ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
-                        decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
-                    });
+                    dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+                    is.close();
                 }
             } finally {
                 stack.pop();
@@ -840,7 +835,7 @@
                     final long loadedBitmapSize =
                             Bitmap.sPreloadTracingTotalBitmapsSize - startBitmapSize;
                     final int loadedDrawables =
-                            sPreloadTracingNumLoadedDrawables - startDrwableCount;
+                            sPreloadTracingNumLoadedDrawables - startDrawableCount;
 
                     sPreloadTracingNumLoadedDrawables++;
 
@@ -916,6 +911,7 @@
      * first try to load CSL from the cache. If not found, try to get from the constant state.
      * Last, parse the XML and generate the CSL.
      */
+    @NonNull
     private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
             TypedValue value, int id) {
         final long key = (((long) value.assetCookie) << 32) | value.data;
@@ -935,17 +931,15 @@
             complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
         }
 
-        if (complexColor != null) {
-            complexColor.setBaseChangingConfigurations(value.changingConfigurations);
+        complexColor.setBaseChangingConfigurations(value.changingConfigurations);
 
-            if (mPreloading) {
-                if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
-                        0, value.resourceId, "color")) {
-                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
-                }
-            } else {
-                cache.put(key, theme, complexColor.getConstantState());
+        if (mPreloading) {
+            if (verifyPreloadConfig(complexColor.getChangingConfigurations(),
+                    0, value.resourceId, "color")) {
+                sPreloadedComplexColors.put(key, complexColor.getConstantState());
             }
+        } else {
+            cache.put(key, theme, complexColor.getConstantState());
         }
         return complexColor;
     }
@@ -991,7 +985,7 @@
         return complexColor;
     }
 
-    @Nullable
+    @NonNull
     ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
             Resources.Theme theme)
             throws NotFoundException {
@@ -1051,7 +1045,7 @@
      *
      * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
      */
-    @Nullable
+    @NonNull
     private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
             Resources.Theme theme) {
         if (value.string == null) {
diff --git a/core/java/android/database/sqlite/SQLiteConnectionPool.java b/core/java/android/database/sqlite/SQLiteConnectionPool.java
index b211700..dc60612 100644
--- a/core/java/android/database/sqlite/SQLiteConnectionPool.java
+++ b/core/java/android/database/sqlite/SQLiteConnectionPool.java
@@ -422,6 +422,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private boolean recycleConnectionLocked(SQLiteConnection connection,
             AcquiredConnectionStatus status) {
         if (status == AcquiredConnectionStatus.RECONFIGURE) {
@@ -531,6 +532,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeAvailableConnectionsAndLogExceptionsLocked() {
         closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked();
 
@@ -541,6 +543,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private boolean closeAvailableConnectionLocked(int connectionId) {
         final int count = mAvailableNonPrimaryConnections.size();
         for (int i = count - 1; i >= 0; i--) {
@@ -562,6 +565,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeAvailableNonPrimaryConnectionsAndLogExceptionsLocked() {
         final int count = mAvailableNonPrimaryConnections.size();
         for (int i = 0; i < count; i++) {
@@ -581,6 +585,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeExcessConnectionsAndLogExceptionsLocked() {
         int availableCount = mAvailableNonPrimaryConnections.size();
         while (availableCount-- > mMaxConnectionPoolSize - 1) {
@@ -591,6 +596,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void closeConnectionAndLogExceptionsLocked(SQLiteConnection connection) {
         try {
             connection.close(); // might throw
@@ -609,6 +615,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void reconfigureAllConnectionsLocked() {
         if (mAvailablePrimaryConnection != null) {
             try {
@@ -776,6 +783,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void cancelConnectionWaiterLocked(ConnectionWaiter waiter) {
         if (waiter.mAssignedConnection != null || waiter.mException != null) {
             // Waiter is done waiting but has not woken up yet.
@@ -848,6 +856,7 @@
     }
 
     // Can't throw.
+    @GuardedBy("mLock")
     private void wakeConnectionWaitersLocked() {
         // Unpark all waiters that have requests that we can fulfill.
         // This method is designed to not throw runtime exceptions, although we might send
@@ -910,6 +919,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private SQLiteConnection tryAcquirePrimaryConnectionLocked(int connectionFlags) {
         // If the primary connection is available, acquire it now.
         SQLiteConnection connection = mAvailablePrimaryConnection;
@@ -935,6 +945,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private SQLiteConnection tryAcquireNonPrimaryConnectionLocked(
             String sql, int connectionFlags) {
         // Try to acquire the next connection in the queue.
@@ -974,6 +985,7 @@
     }
 
     // Might throw.
+    @GuardedBy("mLock")
     private void finishAcquireConnectionLocked(SQLiteConnection connection, int connectionFlags) {
         try {
             final boolean readOnly = (connectionFlags & CONNECTION_FLAG_READ_ONLY) != 0;
diff --git a/core/java/android/hardware/display/AmbientBrightnessDayStats.java b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
index 00f3c36..1aa2557 100644
--- a/core/java/android/hardware/display/AmbientBrightnessDayStats.java
+++ b/core/java/android/hardware/display/AmbientBrightnessDayStats.java
@@ -47,6 +47,11 @@
     private final float[] mStats;
 
     /**
+     * Initialize day stats from the given state. The time spent in each of the bucket is
+     * initialized to 0.
+     *
+     * @param localDate        The date for which stats are being tracked
+     * @param bucketBoundaries Bucket boundaries used from creating the buckets from
      * @hide
      */
     public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
@@ -55,6 +60,11 @@
     }
 
     /**
+     * Initialize day stats from the given state
+     *
+     * @param localDate        The date for which stats are being tracked
+     * @param bucketBoundaries Bucket boundaries used from creating the buckets from
+     * @param stats            Time spent in each of the buckets (in seconds)
      * @hide
      */
     public AmbientBrightnessDayStats(@NonNull LocalDate localDate,
@@ -81,14 +91,26 @@
         mStats = stats;
     }
 
+    /**
+     * @return The {@link LocalDate} for which brightness stats are being tracked.
+     */
     public LocalDate getLocalDate() {
         return mLocalDate;
     }
 
+    /**
+     * @return Aggregated stats of time spent (in seconds) in various buckets.
+     */
     public float[] getStats() {
         return mStats;
     }
 
+    /**
+     * Returns the bucket boundaries (in lux) used for creating buckets. For eg., if the bucket
+     * boundaries array is {b1, b2, b3}, the buckets will be [b1, b2), [b2, b3), [b3, inf).
+     *
+     * @return The list of bucket boundaries.
+     */
     public float[] getBucketBoundaries() {
         return mBucketBoundaries;
     }
@@ -169,7 +191,14 @@
         dest.writeFloatArray(mStats);
     }
 
-    /** @hide */
+    /**
+     * Updates the stats by incrementing the time spent for the appropriate bucket based on ambient
+     * brightness reading.
+     *
+     * @param ambientBrightness Ambient brightness reading (in lux)
+     * @param durationSec       Time spent with the given reading (in seconds)
+     * @hide
+     */
     public void log(float ambientBrightness, float durationSec) {
         int bucketIndex = getBucketIndex(ambientBrightness);
         if (bucketIndex >= 0) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index a817f33..017674f 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1818,9 +1818,9 @@
     }
 
     /**
-     * Called when the input method window has been shown to the user, after
-     * previously not being visible.  This is done after all of the UI setup
-     * for the window has occurred (creating its views etc).
+     * Called immediately before the input method window is shown to the user.
+     * You could override this to prepare for the window to be shown
+     * (update view structure etc).
      */
     public void onWindowShown() {
         // Intentionally empty
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index a734719..8b4f02e 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -323,4 +323,16 @@
     public long getLongProperty(int id) {
         return queryProperty(id);
     }
+
+    /**
+     * Return true if the plugType given is wired
+     * @param plugType {@link #BATTERY_PLUGGED_AC}, {@link #BATTERY_PLUGGED_USB},
+     *        or {@link #BATTERY_PLUGGED_WIRELESS}
+     *
+     * @return true if plugType is wired
+     * @hide
+     */
+    public static boolean isPlugWired(int plugType) {
+        return plugType == BATTERY_PLUGGED_USB || plugType == BATTERY_PLUGGED_AC;
+    }
 }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 48f5684..fc78861 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -894,6 +894,14 @@
 
         /**
          * P.
+         *
+         * <p>Applications targeting this or a later release will get these
+         * new changes in behavior:</p>
+         * <ul>
+         * <li>{@link android.app.Service#startForeground Service.startForeground} requires
+         * that apps hold the permission
+         * {@link android.Manifest.permission#FOREGROUND_SERVICE}.</li>
+         * </ul>
          */
         public static final int P = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
     }
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index b6f16a7..e9b4853 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -16,10 +16,15 @@
 
 package android.os;
 
-import android.hardware.vibrator.V1_0.Constants.EffectStrength;
-import android.hardware.vibrator.V1_1.Constants.Effect_1_1;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.vibrator.V1_0.EffectStrength;
+import android.hardware.vibrator.V1_2.Effect;
+import android.net.Uri;
 import android.util.MathUtils;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.Arrays;
 
 /**
@@ -49,7 +54,7 @@
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_CLICK = Effect_1_1.CLICK;
+    public static final int EFFECT_CLICK = Effect.CLICK;
 
     /**
      * A double click effect.
@@ -57,14 +62,62 @@
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_DOUBLE_CLICK = Effect_1_1.DOUBLE_CLICK;
+    public static final int EFFECT_DOUBLE_CLICK = Effect.DOUBLE_CLICK;
 
     /**
      * A tick effect.
      * @see #get(int)
      * @hide
      */
-    public static final int EFFECT_TICK = Effect_1_1.TICK;
+    public static final int EFFECT_TICK = Effect.TICK;
+
+    /**
+     * A thud effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_THUD = Effect.THUD;
+
+    /**
+     * A pop effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_POP = Effect.POP;
+
+    /**
+     * A heavy click effect.
+     * @see #get(int)
+     * @hide
+     */
+    public static final int EFFECT_HEAVY_CLICK = Effect.HEAVY_CLICK;
+
+
+    /**
+     * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+     * pattern that can be played as a ringtone with any audio, depending on the device.
+     *
+     * @see #get(Uri, Context)
+     * @hide
+     */
+    @VisibleForTesting
+    public static final int[] RINGTONES = {
+        Effect.RINGTONE_1,
+        Effect.RINGTONE_2,
+        Effect.RINGTONE_3,
+        Effect.RINGTONE_4,
+        Effect.RINGTONE_5,
+        Effect.RINGTONE_6,
+        Effect.RINGTONE_7,
+        Effect.RINGTONE_8,
+        Effect.RINGTONE_9,
+        Effect.RINGTONE_10,
+        Effect.RINGTONE_11,
+        Effect.RINGTONE_12,
+        Effect.RINGTONE_13,
+        Effect.RINGTONE_14,
+        Effect.RINGTONE_15
+    };
 
     /** @hide to prevent subclassing from outside of the framework */
     public VibrationEffect() { }
@@ -198,6 +251,37 @@
         return effect;
     }
 
+    /**
+     * Get a predefined vibration effect associated with a given URI.
+     *
+     * Predefined effects are a set of common vibration effects that should be identical, regardless
+     * of the app they come from, in order to provide a cohesive experience for users across
+     * the entire device. They also may be custom tailored to the device hardware in order to
+     * provide a better experience than you could otherwise build using the generic building
+     * blocks.
+     *
+     * @param uri The URI associated with the haptic effect.
+     * @param context The context used to get the URI to haptic effect association.
+     *
+     * @return The desired effect, or {@code null} if there's no associated effect.
+     *
+     * @hide
+     */
+    @Nullable
+    public static VibrationEffect get(Uri uri, Context context) {
+        String[] uris = context.getResources().getStringArray(
+                com.android.internal.R.array.config_ringtoneEffectUris);
+        for (int i = 0; i < uris.length && i < RINGTONES.length; i++) {
+            if (uris[i] == null) {
+                continue;
+            }
+            if (Uri.parse(uris[i]).equals(uri)) {
+                return get(RINGTONES[i]);
+            }
+        }
+        return null;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -548,10 +632,15 @@
                 case EFFECT_CLICK:
                 case EFFECT_DOUBLE_CLICK:
                 case EFFECT_TICK:
+                case EFFECT_THUD:
+                case EFFECT_POP:
+                case EFFECT_HEAVY_CLICK:
                     break;
                 default:
-                    throw new IllegalArgumentException(
-                            "Unknown prebaked effect type (value=" + mEffectId + ")");
+                    if (mEffectId < RINGTONES[0] || mEffectId > RINGTONES[RINGTONES.length - 1]) {
+                        throw new IllegalArgumentException(
+                                "Unknown prebaked effect type (value=" + mEffectId + ")");
+                    }
             }
             if (!isValidEffectStrength(mEffectStrength)) {
                 throw new IllegalArgumentException(
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 12a495b..fb22194 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -80,4 +80,11 @@
      *  ("28", ["libjpeg.so", "libbase.so"])]
      */
     public static native Map<String, String[]> getVndkSnapshots();
+
+    /**
+     * @return target FCM version, a number specified in the device manifest
+     * indicating the FCM version that the device manifest implements. Null if
+     * device manifest doesn't specify this number (for legacy devices).
+     */
+    public static native Long getTargetFrameworkCompatibilityMatrixVersion();
 }
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 670f794..4a97640 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -61,18 +61,27 @@
     /**
      * The name of the socket used to communicate with the primary zygote.
      */
-    private final String mSocket;
+    private final LocalSocketAddress mSocket;
 
     /**
      * The name of the secondary (alternate ABI) zygote socket.
      */
-    private final String mSecondarySocket;
+    private final LocalSocketAddress mSecondarySocket;
 
     public ZygoteProcess(String primarySocket, String secondarySocket) {
+        this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
+                new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
+    }
+
+    public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
         mSocket = primarySocket;
         mSecondarySocket = secondarySocket;
     }
 
+    public LocalSocketAddress getPrimarySocketAddress() {
+        return mSocket;
+    }
+
     /**
      * State for communicating with the zygote process.
      */
@@ -92,14 +101,13 @@
             this.abiList = abiList;
         }
 
-        public static ZygoteState connect(String socketAddress) throws IOException {
+        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
             DataInputStream zygoteInputStream = null;
             BufferedWriter zygoteWriter = null;
             final LocalSocket zygoteSocket = new LocalSocket();
 
             try {
-                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
-                        LocalSocketAddress.Namespace.RESERVED));
+                zygoteSocket.connect(address);
 
                 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
 
@@ -115,8 +123,8 @@
             }
 
             String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
-            Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
-                    + abiListString);
+            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
+                    + address.getName() + " opened, supported ABIS: " + abiListString);
 
             return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                     Arrays.asList(abiListString.split(",")));
@@ -514,9 +522,19 @@
      * @param socketName The name of the socket to connect to.
      */
     public static void waitForConnectionToZygote(String socketName) {
+        final LocalSocketAddress address =
+                new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
+        waitForConnectionToZygote(address);
+    }
+
+    /**
+     * Try connecting to the Zygote over and over again until we hit a time-out.
+     * @param address The name of the socket to connect to.
+     */
+    public static void waitForConnectionToZygote(LocalSocketAddress address) {
         for (int n = 20; n >= 0; n--) {
             try {
-                final ZygoteState zs = ZygoteState.connect(socketName);
+                final ZygoteState zs = ZygoteState.connect(address);
                 zs.close();
                 return;
             } catch (IOException ioe) {
@@ -529,6 +547,6 @@
             } catch (InterruptedException ie) {
             }
         }
-        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + socketName);
+        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
     }
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b7b2b2d..422e36b 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1343,6 +1343,7 @@
     /**
      * @hide
      */
+    @GuardedBy("mLock")
     public final void applyUpdateLocked(NotificationRankingUpdate update) {
         mRankingMap = new RankingMap(update);
     }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 3c3190b..1ead0b4 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -37,12 +37,11 @@
     private static final Map<String, String> DEFAULT_FLAGS;
     static {
         DEFAULT_FLAGS = new HashMap<>();
-        DEFAULT_FLAGS.put("device_info_v2", "true");
         DEFAULT_FLAGS.put("settings_connected_device_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_v2", "true");
         DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
         DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
-        DEFAULT_FLAGS.put("settings_about_phone_v2", "false");
+        DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_data_usage_v2", "false");
     }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 37e9815..7251b71 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -20,6 +20,7 @@
 import static android.view.DisplayInfoProto.APP_WIDTH;
 import static android.view.DisplayInfoProto.LOGICAL_HEIGHT;
 import static android.view.DisplayInfoProto.LOGICAL_WIDTH;
+import static android.view.DisplayInfoProto.NAME;
 
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
@@ -685,6 +686,7 @@
         protoOutputStream.write(LOGICAL_HEIGHT, logicalHeight);
         protoOutputStream.write(APP_WIDTH, appWidth);
         protoOutputStream.write(APP_HEIGHT, appHeight);
+        protoOutputStream.write(NAME, name);
         protoOutputStream.end(token);
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0910c11..5de25ba 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -4806,6 +4806,7 @@
 
             Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M;
             Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O;
+            Canvas.setCompatibilityVersion(targetSdkVersion);
 
             // In M and newer, our widgets can pass a "hint" value in the size
             // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 5131a8a..8b64bad 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -619,6 +619,7 @@
     /**
      * @hide
      */
+    @GuardedBy("mLock")
     public boolean isCompatibilityModeEnabledLocked() {
         return mCompatibilityBridge != null;
     }
@@ -709,6 +710,7 @@
         notifyViewEntered(view, 0);
     }
 
+    @GuardedBy("mLock")
     private boolean shouldIgnoreViewEnteredLocked(@NonNull View view, int flags) {
         if (isDisabledByServiceLocked()) {
             if (sVerbose) {
@@ -749,6 +751,7 @@
     }
 
     /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+    @GuardedBy("mLock")
     private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) {
         if (shouldIgnoreViewEnteredLocked(view, flags)) return null;
 
@@ -792,6 +795,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void notifyViewExitedLocked(@NonNull View view) {
         ensureServiceClientAddedIfNeededLocked();
 
@@ -893,6 +897,7 @@
     }
 
     /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */
+    @GuardedBy("mLock")
     private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds,
                                                      int flags) {
         AutofillCallback callback = null;
@@ -936,6 +941,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void notifyViewExitedLocked(@NonNull View view, int virtualId) {
         ensureServiceClientAddedIfNeededLocked();
 
@@ -1087,6 +1093,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void commitLocked() {
         if (!mEnabled && !isActiveLocked()) {
             return;
@@ -1115,6 +1122,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void cancelLocked() {
         if (!mEnabled && !isActiveLocked()) {
             return;
@@ -1378,6 +1386,7 @@
         return new AutofillId(parent.getAutofillViewId(), virtualId);
     }
 
+    @GuardedBy("mLock")
     private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
             @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
@@ -1408,6 +1417,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void finishSessionLocked() {
         if (sVerbose) Log.v(TAG, "finishSessionLocked(): " + getStateAsStringLocked());
 
@@ -1422,6 +1432,7 @@
         resetSessionLocked();
     }
 
+    @GuardedBy("mLock")
     private void cancelSessionLocked() {
         if (sVerbose) Log.v(TAG, "cancelSessionLocked(): " + getStateAsStringLocked());
 
@@ -1436,6 +1447,7 @@
         resetSessionLocked();
     }
 
+    @GuardedBy("mLock")
     private void resetSessionLocked() {
         mSessionId = NO_SESSION;
         mState = STATE_UNKNOWN;
@@ -1444,6 +1456,7 @@
         mSaveTriggerId = null;
     }
 
+    @GuardedBy("mLock")
     private void updateSessionLocked(AutofillId id, Rect bounds, AutofillValue value, int action,
             int flags) {
         if (sVerbose && action != ACTION_VIEW_EXITED) {
@@ -1478,6 +1491,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void ensureServiceClientAddedIfNeededLocked() {
         if (getClient() == null) {
             return;
@@ -1947,6 +1961,7 @@
         pw.print(" verbose: "); pw.println(sVerbose);
     }
 
+    @GuardedBy("mLock")
     private String getStateAsStringLocked() {
         switch (mState) {
             case STATE_UNKNOWN:
@@ -1964,14 +1979,17 @@
         }
     }
 
+    @GuardedBy("mLock")
     private boolean isActiveLocked() {
         return mState == STATE_ACTIVE;
     }
 
+    @GuardedBy("mLock")
     private boolean isDisabledByServiceLocked() {
         return mState == STATE_DISABLED_BY_SERVICE;
     }
 
+    @GuardedBy("mLock")
     private boolean isFinishedLocked() {
         return mState == STATE_FINISHED;
     }
@@ -2167,6 +2185,7 @@
                     AutofillValue.forText(node.getText()));
         }
 
+        @GuardedBy("mLock")
         private void updateTrackedViewsLocked() {
             if (mTrackedViews != null) {
                 mTrackedViews.onVisibleForAutofillChangedLocked();
@@ -2311,6 +2330,7 @@
          * @param id the id of the view/virtual view whose visibility changed.
          * @param isVisible visible if the view is visible in the view hierarchy.
          */
+        @GuardedBy("mLock")
         void notifyViewVisibilityChangedLocked(@NonNull AutofillId id, boolean isVisible) {
             if (sDebug) {
                 Log.d(TAG, "notifyViewVisibilityChangedLocked(): id=" + id + " isVisible="
@@ -2344,6 +2364,7 @@
          *
          * @see AutofillClient#autofillClientIsVisibleForAutofill()
          */
+        @GuardedBy("mLock")
         void onVisibleForAutofillChangedLocked() {
             // The visibility of the views might have changed while the client was not be visible,
             // hence update the visibility state for all views.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 467e2a4..eb58b09 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3828,6 +3828,7 @@
         mActiveHistoryStates2 = 0xffffffff;
     }
 
+    @GuardedBy("this")
     public void updateTimeBasesLocked(boolean unplugged, int screenState, long uptime,
             long realtime) {
         final boolean screenOff = !isScreenOn(screenState);
@@ -3905,6 +3906,7 @@
      * This should only be called after the cpu times have been read.
      * @see #scheduleRemoveIsolatedUidLocked(int, int)
      */
+    @GuardedBy("this")
     public void removeIsolatedUidLocked(int isolatedUid) {
         StatsLog.write(
                 StatsLog.ISOLATED_UID_CHANGED, mIsolatedUids.get(isolatedUid, -1),
@@ -4734,6 +4736,7 @@
         return;
     }
 
+    @GuardedBy("this")
     public void noteScreenStateLocked(int state) {
         state = mPretendScreenOff ? Display.STATE_OFF : state;
 
@@ -9650,6 +9653,7 @@
             return ps;
         }
 
+        @GuardedBy("mBsi")
         public void updateUidProcessStateLocked(int procState) {
             int uidRunningState;
             // Make special note of Foreground Services
@@ -11762,6 +11766,7 @@
      * and we are on battery with screen off, we give more of the cpu time to those apps holding
      * wakelocks. If the screen is on, we just assign the actual cpu time an app used.
      */
+    @GuardedBy("this")
     public void updateCpuTimeLocked() {
         if (mPowerProfile == null) {
             return;
@@ -12207,6 +12212,7 @@
         return false;
     }
 
+    @GuardedBy("this")
     protected void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime,
             final boolean onBattery, final int oldStatus, final int level, final int chargeUAh) {
         boolean doWrite = false;
@@ -12383,6 +12389,7 @@
     // This should probably be exposed in the API, though it's not critical
     public static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
 
+    @GuardedBy("this")
     public void setBatteryStateLocked(final int status, final int health, final int plugType,
             final int level, /* not final */ int temp, final int volt, final int chargeUAh,
             final int chargeFullUAh) {
@@ -13198,6 +13205,7 @@
         }
     }
 
+    @GuardedBy("this")
     public void dumpConstantsLocked(PrintWriter pw) {
         mConstants.dumpLocked(pw);
     }
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 088e726..12405eb 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -283,6 +283,7 @@
         return -OsConstants.EBADF;
     }
 
+    @GuardedBy("mLock")
     private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
         final CallbackEntry entry = mCallbackMap.get(checkInode(inode));
         if (entry == null) {
@@ -291,12 +292,14 @@
         return entry;
     }
 
+    @GuardedBy("mLock")
     private void recycleLocked(Args args) {
         if (mArgsPool.size() < ARGS_POOL_SIZE) {
             mArgsPool.add(args);
         }
     }
 
+    @GuardedBy("mLock")
     private void replySimpleLocked(long unique, int result) {
         if (mInstance != 0) {
             native_replySimple(mInstance, unique, result);
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index f70d3c2..221bf88 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -35,7 +35,7 @@
     void animateCollapsePanels();
     void togglePanel();
 
-    void showChargingAnimation(int batteryLevel);
+    void showWirelessChargingAnimation(int batteryLevel);
 
     /**
      * Notifies the status bar of a System UI visibility flag change.
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index efd98e2..95534e2 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -72,6 +72,7 @@
         SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
 
     private static final File TOMBSTONE_DIR = new File("/data/tombstones");
+    private static final String TAG_TOMBSTONE = "SYSTEM_TOMBSTONE";
 
     // The pre-froyo package and class of the system updater, which
     // ran in the system process.  We need to remove its packages here
@@ -265,7 +266,7 @@
                     File file = new File(TOMBSTONE_DIR, path);
                     if (file.isFile()) {
                         addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
-                                "SYSTEM_TOMBSTONE");
+                                TAG_TOMBSTONE);
                     }
                 } catch (IOException e) {
                     Slog.e(TAG, "Can't log tombstone", e);
@@ -299,9 +300,20 @@
 
         timestamps.put(filename, fileTime);
 
+
+        String fileContents = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
+        String text = headers + fileContents + footers;
+        // Create an additional report for system server native crashes, with a special tag.
+        if (tag.equals(TAG_TOMBSTONE) && fileContents.contains(">>> system_server <<<")) {
+            addTextToDropBox(db, "system_server_native_crash", text, filename, maxSize);
+        }
+        addTextToDropBox(db, tag, text, filename, maxSize);
+    }
+
+    private static void addTextToDropBox(DropBoxManager db, String tag, String text,
+            String filename, int maxSize) {
         Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
-        db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") +
-                footers);
+        db.addText(tag, text);
         EventLog.writeEvent(DropboxLogTags.DROPBOX_FILE_COPY, filename, maxSize, tag);
     }
 
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 6b961f5..06de5da 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -573,6 +573,11 @@
     minikin::Layout::purgeCaches();
 }
 
+static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
+    Canvas::setCompatibilityVersion(apiLevel);
+}
+
+
 }; // namespace CanvasJNI
 
 static const JNINativeMethod gMethods[] = {
@@ -580,6 +585,7 @@
     {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
+    {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
 
     // ------------ @FastNative ----------------
     {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 1659168..e8ef349 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -32,10 +32,13 @@
 static jclass gHashMapClazz;
 static jmethodID gHashMapInit;
 static jmethodID gHashMapPut;
+static jclass gLongClazz;
+static jmethodID gLongValueOf;
 
 namespace android {
 
 using vintf::HalManifest;
+using vintf::Level;
 using vintf::SchemaType;
 using vintf::VintfObject;
 using vintf::XmlConverter;
@@ -154,6 +157,14 @@
     return jMap;
 }
 
+static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) {
+    std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest();
+    if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) {
+        return nullptr;
+    }
+    return env->CallStaticObjectMethod(gLongClazz, gLongValueOf, static_cast<jlong>(manifest->level()));
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gVintfObjectMethods[] = {
@@ -163,6 +174,7 @@
     {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
     {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
     {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
+    {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;", (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion},
 };
 
 const char* const kVintfObjectPathName = "android/os/VintfObject";
@@ -175,6 +187,8 @@
     gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
     gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
             "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+    gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long"));
+    gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;");
 
     return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
             NELEM(gVintfObjectMethods));
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c623ca6..2334e03 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -403,38 +403,30 @@
     return nullptr;
   }
 
-  std::vector<std::string> all_file_paths;
-  {
-    StringPiece normalized_path = path_utf8.c_str();
-    if (normalized_path.data()[0] == '/') {
-      normalized_path = normalized_path.substr(1);
-    }
-    std::string root_path = StringPrintf("assets/%s", normalized_path.data());
-    ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-    for (const ApkAssets* assets : assetmanager->GetApkAssets()) {
-      assets->ForEachFile(root_path, [&](const StringPiece& file_path, FileType type) {
-        if (type == FileType::kFileTypeRegular) {
-          all_file_paths.push_back(file_path.to_string());
-        }
-      });
-    }
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  std::unique_ptr<AssetDir> asset_dir =
+      assetmanager->OpenDir(path_utf8.c_str());
+  if (asset_dir == nullptr) {
+    jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
+    return nullptr;
   }
 
-  jobjectArray array = env->NewObjectArray(all_file_paths.size(), g_stringClass, nullptr);
+  const size_t file_count = asset_dir->getFileCount();
+
+  jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
   if (array == nullptr) {
     return nullptr;
   }
 
-  jsize index = 0;
-  for (const std::string& file_path : all_file_paths) {
-    jstring java_string = env->NewStringUTF(file_path.c_str());
+  for (size_t i = 0; i < file_count; i++) {
+    jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
 
     // Check for errors creating the strings (if malformed or no memory).
     if (env->ExceptionCheck()) {
      return nullptr;
     }
 
-    env->SetObjectArrayElement(array, index++, java_string);
+    env->SetObjectArrayElement(array, i, java_string);
 
     // If we have a large amount of string in our array, we might overflow the
     // local reference table of the VM.
diff --git a/core/proto/android/telecomm/enums.proto b/core/proto/android/telecomm/enums.proto
new file mode 100644
index 0000000..7a2ba62
--- /dev/null
+++ b/core/proto/android/telecomm/enums.proto
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+package android.telecom;
+
+option java_outer_classname = "TelecomProtoEnums";
+option java_multiple_files = true;
+
+/**
+ * Call states, primarily used in CallState.java,
+ * Call.java, and CallsManager.java in packages/services.
+ */
+enum CallStateEnum {
+    /**
+     * Indicates that a call is new and not connected. This is used as the default state internally
+     * within Telecom and should not be used between Telecom and call services. Call services are
+     * not expected to ever interact with NEW calls, but {@link android.telecom.InCallService}s will
+     * see calls in this state.
+     */
+    NEW = 0;
+
+    /**
+     * The initial state of an outgoing {@code Call}.
+     * Common transitions are to {@link #DIALING} state for a successful call or
+     * {@link #DISCONNECTED} if it failed.
+     */
+    CONNECTING = 1;
+
+    /**
+     * The state of an outgoing {@code Call} when waiting on user to select a
+     * {@link android.telecom.PhoneAccount} through which to place the call.
+     */
+    SELECT_PHONE_ACCOUNT = 2;
+
+    /**
+     * Indicates that a call is outgoing and in the dialing state. A call transitions to this state
+     * once an outgoing call has begun (e.g., user presses the dial button in Dialer). Calls in this
+     * state usually transition to {@link #ACTIVE} if the call was answered or {@link #DISCONNECTED}
+     * if the call was disconnected somehow (e.g., failure or cancellation of the call by the user).
+     */
+    DIALING = 3;
+
+    /**
+     * Indicates that a call is incoming and the user still has the option of answering, rejecting,
+     * or doing nothing with the call. This state is usually associated with some type of audible
+     * ringtone. Normal transitions are to {@link #ACTIVE} if answered or {@link #DISCONNECTED}
+     * otherwise.
+     */
+    RINGING = 4;
+
+    /**
+     * Indicates that a call is currently connected to another party and a communication channel is
+     * open between them. The normal transition to this state is by the user answering a
+     * {@link #DIALING} call or a {@link #RINGING} call being answered by the other party.
+     */
+    ACTIVE = 5;
+
+    /**
+     * Indicates that the call is currently on hold. In this state, the call is not terminated
+     * but no communication is allowed until the call is no longer on hold. The typical transition
+     * to this state is by the user putting an {@link #ACTIVE} call on hold by explicitly performing
+     * an action, such as clicking the hold button.
+     */
+    ON_HOLD = 6;
+
+    /**
+     * Indicates that a call is currently disconnected. All states can transition to this state
+     * by the call service giving notice that the connection has been severed. When the user
+     * explicitly ends a call, it will not transition to this state until the call service confirms
+     * the disconnection or communication was lost to the call service currently responsible for
+     * this call (e.g., call service crashes).
+     */
+    DISCONNECTED = 7;
+
+    /**
+     * Indicates that the call was attempted (mostly in the context of outgoing, at least at the
+     * time of writing) but cancelled before it was successfully connected.
+     */
+    ABORTED = 8;
+
+    /**
+     * Indicates that the call is in the process of being disconnected and will transition next
+     * to a {@link #DISCONNECTED} state.
+     * <p>
+     * This state is not expected to be communicated from the Telephony layer, but will be reported
+     * to the InCall UI for calls where disconnection has been initiated by the user but the
+     * ConnectionService has confirmed the call as disconnected.
+     */
+    DISCONNECTING = 9;
+
+    /**
+     * Indicates that the call is in the process of being pulled to the local device.
+     * <p>
+     * This state should only be set on a call with
+     * {@link android.telecom.Connection#PROPERTY_IS_EXTERNAL_CALL} and
+     * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL}.
+     */
+    PULLING = 10;
+}
+
+// Disconnect causes for a call. Primarily used by android/telecom/DisconnectCause.java
+enum DisconnectCauseEnum {
+    /**
+     * Disconnected because of an unknown or unspecified reason.
+     */
+    UNKNOWN = 0;
+
+    /**
+     * Disconnected because there was an error, such as a problem with the network.
+     */
+    ERROR = 1;
+
+    /**
+     * Disconnected because of a local user-initiated action, such as hanging up.
+     */
+    LOCAL = 2;
+
+    /**
+     * Disconnected because of a remote user-initiated action, such as the other party hanging up
+     * up.
+     */
+    REMOTE = 3;
+
+    /**
+     * Disconnected because it has been canceled.
+     */
+    CANCELED = 4;
+
+    /**
+     * Disconnected because there was no response to an incoming call.
+     */
+    MISSED = 5;
+
+    /**
+     * Disconnected because the user rejected an incoming call.
+     */
+    REJECTED = 6;
+
+    /**
+     * Disconnected because the other party was busy.
+     */
+    BUSY = 7;
+
+    /**
+     * Disconnected because of a restriction on placing the call, such as dialing in airplane
+     * mode.
+     */
+    RESTRICTED = 8;
+
+    /**
+     * Disconnected for reason not described by other disconnect codes.
+     */
+    OTHER = 9;
+
+    /**
+     * Disconnected because the connection manager did not support the call. The call will be tried
+     * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
+     */
+    CONNECTION_MANAGER_NOT_SUPPORTED = 10;
+
+    /**
+     * Disconnected because the user did not locally answer the incoming call, but it was answered
+     * on another device where the call was ringing.
+     */
+    ANSWERED_ELSEWHERE = 11;
+
+    /**
+     * Disconnected because the call was pulled from the current device to another device.
+     */
+    CALL_PULLED = 12;
+}
diff --git a/core/proto/android/view/displayinfo.proto b/core/proto/android/view/displayinfo.proto
index 3ac8f3b..cbd06fd 100644
--- a/core/proto/android/view/displayinfo.proto
+++ b/core/proto/android/view/displayinfo.proto
@@ -29,4 +29,5 @@
   optional int32 logical_height = 2;
   optional int32 app_width = 3;
   optional int32 app_height = 4;
+  optional string name = 5;
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index deefddb..f6f1d81 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -53,6 +53,7 @@
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
     <protected-broadcast android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
     <protected-broadcast android:name="android.intent.action.CONFIGURATION_CHANGED" />
+    <protected-broadcast android:name="android.intent.action.SPLIT_CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.intent.action.LOCALE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.BATTERY_LOW" />
@@ -3784,6 +3785,15 @@
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
+    <!-- Allows a regular application to use {@link android.app.Service#startForeground
+         Service.startForeground}.
+         <p>Protection level: normal
+    -->
+    <permission android:name="android.permission.FOREGROUND_SERVICE"
+        android:description="@string/permdesc_foregroundService"
+        android:label="@string/permlab_foregroundService"
+        android:protectionLevel="normal|instant" />
+
     <!-- @hide Allows system components to access all app shortcuts. -->
     <permission android:name="android.permission.ACCESS_SHORTCUTS"
         android:protectionLevel="signature" />
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index ce4ac61..e80f16c 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -79,8 +79,8 @@
     <item name="secondary_content_alpha_material_light" format="float" type="dimen">0.54</item>
 
     <item name="highlight_alpha_material_light" format="float" type="dimen">0.16</item>
-    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.32</item>
-    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.48</item>
+    <item name="highlight_alpha_material_dark" format="float" type="dimen">0.16</item>
+    <item name="highlight_alpha_material_colored" format="float" type="dimen">0.16</item>
 
     <!-- Primary & accent colors -->
     <eat-comment />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c8032a2..d2194ba 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1075,6 +1075,14 @@
         <item>10</item>
     </integer-array>
 
+    <!-- The URI to associate with each ringtone effect constant, intended to be used with the
+         android.os.VibrationEffect#get(Uri, Context) API.
+         The position of the string in the string-array determines which ringtone effect is chosen.
+         For example, if the URI passed into get match the third string in the string-array, then
+         RINGTONE_3 will be the returned effect -->
+    <string-array translatable="false" name="config_ringtoneEffectUris">
+    </string-array>
+
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
     <!-- Display low battery warning when battery level dips to this value.
@@ -2486,9 +2494,9 @@
     <string-array translatable="false" name="config_globalActionsList">
         <item>power</item>
         <item>restart</item>
-        <item>screenshot</item>
-        <item>logout</item>
         <item>lockdown</item>
+        <item>logout</item>
+        <item>screenshot</item>
         <item>bugreport</item>
         <item>users</item>
     </string-array>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ec81df7..2b7b056 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -916,6 +916,11 @@
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_foregroundService">run foreground service</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_foregroundService">Allows the app to make use of foreground services.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getPackageSize">measure app storage space</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getPackageSize">Allows the app to retrieve its code, data, and cache sizes</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f7b6f06a..ca698ef 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3252,4 +3252,6 @@
   <java-symbol type="string" name="screenshot_edit" />
 
   <java-symbol type="bool" name="config_keepRestrictedProfilesInBackground" />
+
+  <java-symbol type="array" name="config_ringtoneEffectUris" />
 </resources>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 7d5c60a..53c22f6 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -51,6 +51,7 @@
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index aefc47e..fb0f534 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -17,6 +17,7 @@
 package android.app.servertransaction;
 
 import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.mergedConfig;
 import static android.app.servertransaction.TestUtils.referrerIntentList;
 import static android.app.servertransaction.TestUtils.resultInfoList;
 
@@ -151,6 +152,25 @@
     }
 
     @Test
+    public void testRecycleActivityRelaunchItem() {
+        ActivityRelaunchItem emptyItem = ActivityRelaunchItem.obtain(null, null, 0, null, false);
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.assetsSeq = 5;
+        ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 42, mergedConfig(), true);
+        assertNotSame(item, emptyItem);
+        assertFalse(item.equals(emptyItem));
+
+        item.recycle();
+        assertEquals(item, emptyItem);
+
+        ActivityRelaunchItem item2 = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 42, mergedConfig(), true);
+        assertSame(item, item2);
+        assertFalse(item2.equals(emptyItem));
+    }
+
+    @Test
     public void testRecycleMoveToDisplayItem() {
         MoveToDisplayItem emptyItem = MoveToDisplayItem.obtain(0, null);
         MoveToDisplayItem item = MoveToDisplayItem.obtain(4, config());
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index e923516..d125fe7 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -21,6 +21,7 @@
 import android.app.ResultInfo;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.util.MergedConfiguration;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -38,6 +39,15 @@
         return config;
     }
 
+    static MergedConfiguration mergedConfig() {
+        Configuration config = config();
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.densityDpi = 30;
+        overrideConfig.screenWidthDp = 40;
+        overrideConfig.smallestScreenWidthDp = 15;
+        return new MergedConfiguration(config, overrideConfig);
+    }
+
     static List<ResultInfo> resultInfoList() {
         String resultWho1 = "resultWho1";
         int requestCode1 = 7;
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 77aaa2d..0906435 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -17,6 +17,7 @@
 package android.app.servertransaction;
 
 import static android.app.servertransaction.TestUtils.config;
+import static android.app.servertransaction.TestUtils.mergedConfig;
 import static android.app.servertransaction.TestUtils.referrerIntentList;
 import static android.app.servertransaction.TestUtils.resultInfoList;
 
@@ -27,7 +28,6 @@
 import android.app.IInstrumentationWatcher;
 import android.app.IUiAutomationConnection;
 import android.app.ProfilerInfo;
-import android.app.ResultInfo;
 import android.content.ComponentName;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -53,7 +53,6 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.content.ReferrerIntent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -243,6 +242,22 @@
     }
 
     @Test
+    public void testRelaunch() {
+        // Write to parcel
+        Configuration overrideConfig = new Configuration();
+        overrideConfig.assetsSeq = 5;
+        ActivityRelaunchItem item = ActivityRelaunchItem.obtain(resultInfoList(),
+                referrerIntentList(), 35, mergedConfig(), true);
+        writeAndPrepareForReading(item);
+
+        // Read from parcel and assert
+        ActivityRelaunchItem result = ActivityRelaunchItem.CREATOR.createFromParcel(mParcel);
+
+        assertEquals(item.hashCode(), result.hashCode());
+        assertTrue(item.equals(result));
+    }
+
+    @Test
     public void testPause() {
         // Write to parcel
         PauseActivityItem item = PauseActivityItem.obtain(true /* finished */,
@@ -435,12 +450,6 @@
         }
 
         @Override
-        public void scheduleRelaunchActivity(IBinder iBinder, List<ResultInfo> list,
-                List<ReferrerIntent> list1, int i, boolean b, Configuration configuration,
-                Configuration configuration1, boolean b1) throws RemoteException {
-        }
-
-        @Override
         public void scheduleSleeping(IBinder iBinder, boolean b) throws RemoteException {
         }
 
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
new file mode 100644
index 0000000..c7fdf0f
--- /dev/null
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.Uri;
+
+import com.android.internal.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class VibrationEffectTest {
+    private static final String RINGTONE_URI_1 = "content://test/system/ringtone_1";
+    private static final String RINGTONE_URI_2 = "content://test/system/ringtone_2";
+    private static final String RINGTONE_URI_3 = "content://test/system/ringtone_3";
+    private static final String UNKNOWN_URI = "content://test/system/other_audio";
+
+    @Test
+    public void getRingtones_noPrebakedRingtones() {
+        Resources r = mockRingtoneResources(new String[0]);
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_1), context);
+        assertNull(effect);
+    }
+
+    @Test
+    public void getRingtones_noPrebakedRingtoneForUri() {
+        Resources r = mockRingtoneResources();
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(UNKNOWN_URI), context);
+        assertNull(effect);
+    }
+
+    @Test
+    public void getRingtones_getPrebakedRingtone() {
+        Resources r = mockRingtoneResources();
+        Context context = mockContext(r);
+        VibrationEffect effect = VibrationEffect.get(Uri.parse(RINGTONE_URI_2), context);
+        VibrationEffect expectedEffect = VibrationEffect.get(VibrationEffect.RINGTONES[1]);
+        assertNotNull(expectedEffect);
+        assertEquals(expectedEffect, effect);
+    }
+
+
+    private Resources mockRingtoneResources() {
+        return mockRingtoneResources(new String[] {
+                RINGTONE_URI_1,
+                RINGTONE_URI_2,
+                RINGTONE_URI_3
+        });
+    }
+
+    private Resources mockRingtoneResources(String[] ringtoneUris) {
+        Resources mockResources = mock(Resources.class);
+        when(mockResources.getStringArray(R.array.config_ringtoneEffectUris))
+                .thenReturn(ringtoneUris);
+        return mockResources;
+    }
+
+    private Context mockContext(Resources r) {
+        Context ctx = mock(Context.class);
+        when(ctx.getResources()).thenReturn(r);
+        return ctx;
+    }
+}
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index f5bf754..7ea35e7 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -18,6 +18,8 @@
 
 import static android.graphics.BitmapFactory.Options.validate;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.os.Trace;
@@ -518,8 +520,9 @@
      *         is not {@link ColorSpace.Model#RGB RGB}, or if the specified color space's transfer
      *         function is not an {@link ColorSpace.Rgb.TransferParameters ICC parametric curve}
      */
-    public static Bitmap decodeResourceStream(Resources res, TypedValue value,
-            InputStream is, Rect pad, Options opts) {
+    @Nullable
+    public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value,
+            @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) {
         validate(opts);
         if (opts == null) {
             opts = new Options();
@@ -707,7 +710,9 @@
      * <code>is.mark(1024)</code> would be called. As of
      * {@link android.os.Build.VERSION_CODES#KITKAT}, this is no longer the case.</p>
      */
-    public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
+    @Nullable
+    public static Bitmap decodeStream(@Nullable InputStream is, @Nullable Rect outPadding,
+            @Nullable Options opts) {
         // we don't throw in this case, thus allowing the caller to only check
         // the cache, and not force the image to be decoded.
         if (is == null) {
@@ -742,7 +747,8 @@
      * Private helper function for decoding an InputStream natively. Buffers the input enough to
      * do a rewind as needed, and supplies temporary storage if necessary. is MUST NOT be null.
      */
-    private static Bitmap decodeStreamInternal(InputStream is, Rect outPadding, Options opts) {
+    private static Bitmap decodeStreamInternal(@NonNull InputStream is,
+            @Nullable Rect outPadding, @Nullable Options opts) {
         // ASSERT(is != null);
         byte [] tempStorage = null;
         if (opts != null) tempStorage = opts.inTempStorage;
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index f5e8633..d925441 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -1219,10 +1219,14 @@
         nFreeTextLayoutCaches();
     }
 
+    /** @hide */
+    public static void setCompatibilityVersion(int apiLevel) { nSetCompatibilityVersion(apiLevel); }
+
     private static native void nFreeCaches();
     private static native void nFreeTextLayoutCaches();
     private static native long nInitRaster(Bitmap bitmap);
     private static native long nGetNativeFinalizer();
+    private static native void nSetCompatibilityVersion(int apiLevel);
 
     // ---------------- @FastNative -------------------
 
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 3cca47b..acefead 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -25,7 +25,7 @@
 import android.annotation.RawRes;
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager.AssetInputStream;
+import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Drawable;
@@ -263,63 +263,6 @@
         }
     }
 
-    /**
-     * Takes ownership of the AssetInputStream.
-     *
-     * @hide
-     */
-    public static class AssetInputStreamSource extends Source {
-        public AssetInputStreamSource(@NonNull AssetInputStream ais,
-                @NonNull Resources res, @NonNull TypedValue value) {
-            mAssetInputStream = ais;
-            mResources = res;
-
-            if (value.density == TypedValue.DENSITY_DEFAULT) {
-                mDensity = DisplayMetrics.DENSITY_DEFAULT;
-            } else if (value.density != TypedValue.DENSITY_NONE) {
-                mDensity = value.density;
-            } else {
-                mDensity = Bitmap.DENSITY_NONE;
-            }
-        }
-
-        private AssetInputStream mAssetInputStream;
-        private final Resources  mResources;
-        private final int        mDensity;
-
-        @Override
-        public Resources getResources() { return mResources; }
-
-        @Override
-        public int getDensity() {
-            return mDensity;
-        }
-
-        @Override
-        public ImageDecoder createImageDecoder() throws IOException {
-            ImageDecoder decoder = null;
-            synchronized (this) {
-                if (mAssetInputStream == null) {
-                    throw new IOException("Cannot reuse AssetInputStreamSource");
-                }
-                AssetInputStream ais = mAssetInputStream;
-                mAssetInputStream = null;
-                try {
-                    long asset = ais.getNativeAsset();
-                    decoder = nCreate(asset);
-                } finally {
-                    if (decoder == null) {
-                        IoUtils.closeQuietly(ais);
-                    } else {
-                        decoder.mInputStream = ais;
-                        decoder.mOwnsInputStream = true;
-                    }
-                }
-                return decoder;
-            }
-        }
-    }
-
     private static class ResourceSource extends Source {
         ResourceSource(@NonNull Resources res, int resId) {
             mResources = res;
@@ -353,7 +296,11 @@
                     mResDensity = value.density;
                 }
 
-                long asset = ((AssetInputStream) is).getNativeAsset();
+                if (!(is instanceof AssetManager.AssetInputStream)) {
+                    // This should never happen.
+                    throw new RuntimeException("Resource is not an asset?");
+                }
+                long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
                 decoder = nCreate(asset);
             } finally {
                 if (decoder == null) {
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 44ba785..8af2fd8 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1174,8 +1174,10 @@
      *
      * @deprecated Prefer the version without an Options object.
      */
-    public static Drawable createFromResourceStream(Resources res, TypedValue value,
-            InputStream is, String srcName, BitmapFactory.Options opts) {
+    @Nullable
+    public static Drawable createFromResourceStream(@Nullable Resources res,
+            @Nullable TypedValue value, @Nullable InputStream is, @Nullable String srcName,
+            @Nullable BitmapFactory.Options opts) {
         if (is == null) {
             return null;
         }
@@ -1199,7 +1201,6 @@
         // an application in compatibility mode, without scaling those down
         // to the compatibility density only to have them scaled back up when
         // drawn to the screen.
-        if (opts == null) opts = new BitmapFactory.Options();
         opts.inScreenDensity = Drawable.resolveDensity(res, 0);
         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
         if (bm != null) {
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index da0205d..60f8a18 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -231,12 +231,16 @@
   while ((result = ::Next(cookie, &entry, &name)) == 0) {
     StringPiece full_file_path(reinterpret_cast<const char*>(name.name), name.name_length);
     StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
-    auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
-    if (iter != leaf_file_path.end()) {
-      dirs.insert(
-          leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string());
-    } else if (!leaf_file_path.empty()) {
-      f(leaf_file_path, kFileTypeRegular);
+
+    if (!leaf_file_path.empty()) {
+      auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
+      if (iter != leaf_file_path.end()) {
+        std::string dir =
+            leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
+        dirs.insert(std::move(dir));
+      } else {
+        f(leaf_file_path, kFileTypeRegular);
+      }
     }
   }
   ::EndIteration(cookie);
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 1d2c597..a65d49b 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -409,14 +409,10 @@
   util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
                                   &loaded_package->package_name_);
 
-  // A TypeSpec builder. We use this to accumulate the set of Types
-  // available for a TypeSpec, and later build a single, contiguous block
-  // of memory that holds all the Types together with the TypeSpec.
-  std::unique_ptr<TypeSpecPtrBuilder> types_builder;
-
-  // Keep track of the last seen type index. Since type IDs are 1-based,
-  // this records their index, which is 0-based (type ID - 1).
-  uint8_t last_type_idx = 0;
+  // A map of TypeSpec builders, each associated with an type index.
+  // We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
+  // contiguous block of memory that holds all the Types together with the TypeSpec.
+  std::unordered_map<int, std::unique_ptr<TypeSpecPtrBuilder>> type_builder_map;
 
   ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
   while (iter.HasNext()) {
@@ -450,28 +446,6 @@
       case RES_TABLE_TYPE_SPEC_TYPE: {
         ATRACE_NAME("LoadTableTypeSpec");
 
-        // Starting a new TypeSpec, so finish the old one if there was one.
-        if (types_builder) {
-          TypeSpecPtr type_spec_ptr = types_builder->Build();
-          if (type_spec_ptr == nullptr) {
-            LOG(ERROR) << "Too many type configurations, overflow detected.";
-            return {};
-          }
-
-          // We only add the type to the package if there is no IDMAP, or if the type is
-          // overlaying something.
-          if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
-            // If this is an overlay, insert it at the target type ID.
-            if (type_spec_ptr->idmap_entries != nullptr) {
-              last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
-            }
-            loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
-          }
-
-          types_builder = {};
-          last_type_idx = 0;
-        }
-
         const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
         if (type_spec == nullptr) {
           LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
@@ -506,8 +480,6 @@
           return {};
         }
 
-        last_type_idx = type_spec->id - 1;
-
         // If this is an overlay, associate the mapping of this type to the target type
         // from the IDMAP.
         const IdmapEntry_header* idmap_entry_header = nullptr;
@@ -515,7 +487,13 @@
           idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id);
         }
 
-        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
+        if (builder_ptr == nullptr) {
+          builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+        } else {
+          LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
+                                       type_spec->id);
+        }
       } break;
 
       case RES_TABLE_TYPE_TYPE: {
@@ -530,12 +508,15 @@
         }
 
         // Type chunks must be preceded by their TypeSpec chunks.
-        if (!types_builder || type->id - 1 != last_type_idx) {
-          LOG(ERROR) << "RES_TABLE_TYPE_TYPE found without preceding RES_TABLE_TYPE_SPEC_TYPE.";
+        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
+        if (builder_ptr != nullptr) {
+          builder_ptr->AddType(type);
+        } else {
+          LOG(ERROR) << StringPrintf(
+              "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
+              type->id);
           return {};
         }
-
-        types_builder->AddType(type);
       } break;
 
       case RES_TABLE_LIBRARY_TYPE: {
@@ -561,7 +542,7 @@
                                           arraysize(entry_iter->packageName), &package_name);
 
           if (dtohl(entry_iter->packageId) >= std::numeric_limits<uint8_t>::max()) {
-            LOG(ERROR) << base::StringPrintf(
+            LOG(ERROR) << StringPrintf(
                 "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.",
                 dtohl(entry_iter->packageId), package_name.c_str());
             return {};
@@ -574,14 +555,20 @@
       } break;
 
       default:
-        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
 
-  // Finish the last TypeSpec.
-  if (types_builder) {
-    TypeSpecPtr type_spec_ptr = types_builder->Build();
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return {};
+  }
+
+  // Flatten and construct the TypeSpecs.
+  for (auto& entry : type_builder_map) {
+    uint8_t type_idx = static_cast<uint8_t>(entry.first);
+    TypeSpecPtr type_spec_ptr = entry.second->Build();
     if (type_spec_ptr == nullptr) {
       LOG(ERROR) << "Too many type configurations, overflow detected.";
       return {};
@@ -592,20 +579,15 @@
     if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
       // If this is an overlay, insert it at the target type ID.
       if (type_spec_ptr->idmap_entries != nullptr) {
-        last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+        type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
       }
-      loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+      loaded_package->type_specs_.editItemAt(type_idx) = std::move(type_spec_ptr);
     }
   }
 
-  if (iter.HadError()) {
-    LOG(ERROR) << iter.GetLastError();
-    return {};
-  }
   return std::move(loaded_package);
 }
 
-
 bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
                            bool load_as_shared_library) {
   ATRACE_CALL();
@@ -655,7 +637,7 @@
       } break;
 
       default:
-        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
@@ -687,7 +669,7 @@
         break;
 
       default:
-        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index eaf79cb..7cac2b3 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -36,6 +36,10 @@
 namespace lib_two = com::android::lib_two;
 namespace libclient = com::android::libclient;
 
+using ::testing::Eq;
+using ::testing::NotNull;
+using ::testing::StrEq;
+
 namespace android {
 
 class AssetManager2Test : public ::testing::Test {
@@ -64,6 +68,9 @@
 
     system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
     ASSERT_NE(nullptr, system_assets_);
+
+    app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
+    ASSERT_THAT(app_assets_, NotNull());
   }
 
  protected:
@@ -75,6 +82,7 @@
   std::unique_ptr<const ApkAssets> libclient_assets_;
   std::unique_ptr<const ApkAssets> appaslib_assets_;
   std::unique_ptr<const ApkAssets> system_assets_;
+  std::unique_ptr<const ApkAssets> app_assets_;
 };
 
 TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -465,8 +473,68 @@
             assetmanager.GetResourceId("main", "layout", "com.android.basic"));
 }
 
-TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({system_assets_.get()});
 
-TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
+  std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+  ASSERT_THAT(asset, NotNull());
+
+  const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+  ASSERT_THAT(data, NotNull());
+  EXPECT_THAT(std::string(data, asset->getLength()), StrEq("file\n"));
+}
+
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+  std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
+  ASSERT_THAT(asset, NotNull());
+
+  const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
+  ASSERT_THAT(data, NotNull());
+  EXPECT_THAT(std::string(data, asset->getLength()), StrEq("app override file\n"));
+}
+
+TEST_F(AssetManager2Test, OpenDir) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({system_assets_.get()});
+
+  std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+  ASSERT_THAT(asset_dir, NotNull());
+  ASSERT_THAT(asset_dir->getFileCount(), Eq(2u));
+
+  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("file.txt")));
+  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+  EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("subdir")));
+  EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeDirectory));
+
+  asset_dir = assetmanager.OpenDir("subdir");
+  ASSERT_THAT(asset_dir, NotNull());
+  ASSERT_THAT(asset_dir->getFileCount(), Eq(1u));
+
+  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("subdir_file.txt")));
+  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+}
+
+TEST_F(AssetManager2Test, OpenDirFromManyApks) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
+
+  std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
+  ASSERT_THAT(asset_dir, NotNull());
+  ASSERT_THAT(asset_dir->getFileCount(), Eq(3u));
+
+  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("app_file.txt")));
+  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
+
+  EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("file.txt")));
+  EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeRegular));
+
+  EXPECT_THAT(asset_dir->getFileName(2), Eq(String8("subdir")));
+  EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
+}
 
 }  // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index bedebd6..cae632d 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,6 +16,7 @@
 
 #include "androidfw/LoadedArsc.h"
 
+#include "android-base/file.h"
 #include "androidfw/ResourceUtils.h"
 
 #include "TestHelpers.h"
@@ -29,6 +30,7 @@
 namespace libclient = com::android::libclient;
 namespace sparse = com::android::sparse;
 
+using ::android::base::ReadFileToString;
 using ::testing::Eq;
 using ::testing::Ge;
 using ::testing::IsNull;
@@ -177,6 +179,46 @@
   ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
 }
 
+// AAPT(2) generates resource tables with chunks in a certain order. The rule is that
+// a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with
+// id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however.
+//
+// AAPT(2) generates something like:
+//   RES_TABLE_TYPE_SPEC_TYPE id=1
+//   RES_TABLE_TYPE_TYPE id=1
+//   RES_TABLE_TYPE_SPEC_TYPE id=2
+//   RES_TABLE_TYPE_TYPE id=2
+//
+// But the following is valid too:
+//   RES_TABLE_TYPE_SPEC_TYPE id=1
+//   RES_TABLE_TYPE_SPEC_TYPE id=2
+//   RES_TABLE_TYPE_TYPE id=1
+//   RES_TABLE_TYPE_TYPE id=2
+//
+TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
+                              "resources.arsc", &contents));
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+  ASSERT_THAT(loaded_arsc, NotNull());
+
+  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+  const auto& package = loaded_arsc->GetPackages()[0];
+  ASSERT_THAT(package, NotNull());
+
+  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
+  ASSERT_THAT(type_spec, NotNull());
+  ASSERT_THAT(type_spec->type_count, Ge(1u));
+  ASSERT_THAT(type_spec->types[0], NotNull());
+
+  type_spec = package->GetTypeSpecByTypeIndex(1);
+  ASSERT_THAT(type_spec, NotNull());
+  ASSERT_THAT(type_spec->type_count, Ge(1u));
+  ASSERT_THAT(type_spec->types[0], NotNull());
+}
+
 class MockLoadedIdmap : public LoadedIdmap {
  public:
   MockLoadedIdmap() : LoadedIdmap() {
diff --git a/libs/androidfw/tests/data/app/app.apk b/libs/androidfw/tests/data/app/app.apk
index ccb0824..c8ad86d 100644
--- a/libs/androidfw/tests/data/app/app.apk
+++ b/libs/androidfw/tests/data/app/app.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/app/assets/app_file.txt b/libs/androidfw/tests/data/app/assets/app_file.txt
new file mode 100644
index 0000000..b214e06
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/app_file.txt
@@ -0,0 +1 @@
+app file
diff --git a/libs/androidfw/tests/data/app/assets/file.txt b/libs/androidfw/tests/data/app/assets/file.txt
new file mode 100644
index 0000000..0811542
--- /dev/null
+++ b/libs/androidfw/tests/data/app/assets/file.txt
@@ -0,0 +1 @@
+app override file
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
index d418158..09af842 100755
--- a/libs/androidfw/tests/data/app/build
+++ b/libs/androidfw/tests/data/app/build
@@ -17,4 +17,11 @@
 
 set -e
 
-aapt package -I ../system/system.apk -M AndroidManifest.xml -S res -F app.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link \
+    --manifest AndroidManifest.xml \
+    -I ../system/system.apk \
+    -A assets \
+    -o app.apk \
+    compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml b/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
new file mode 100644
index 0000000..34016db
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.app" />
diff --git a/libs/androidfw/tests/data/out_of_order_types/build b/libs/androidfw/tests/data/out_of_order_types/build
new file mode 100755
index 0000000..8496f81
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# 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.
+#
+
+set -e
+
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -o out_of_order_types.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
new file mode 100644
index 0000000..eca8f47
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
@@ -0,0 +1,43 @@
+00000000: 0200 0c00 ac02 0000 0100 0000 0100 1c00  ................
+00000010: 1c00 0000 0000 0000 0000 0000 0001 0000  ................
+00000020: 1c00 0000 0000 0000 0002 2001 8402 0000  .......... .....
+00000030: 7f00 0000 6300 6f00 6d00 2e00 6100 6e00  ....c.o.m...a.n.
+00000040: 6400 7200 6f00 6900 6400 2e00 6100 7000  d.r.o.i.d...a.p.
+00000050: 7000 0000 0000 0000 0000 0000 0000 0000  p...............
+00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+000000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000130: 0000 0000 2001 0000 0000 0000 6401 0000  .... .......d...
+00000140: 0000 0000 0000 0000 0100 1c00 4400 0000  ............D...
+00000150: 0200 0000 0000 0000 0000 0000 2400 0000  ............$...
+00000160: 0000 0000 0000 0000 0c00 0000 0400 6200  ..............b.
+00000170: 6f00 6f00 6c00 0000 0700 6900 6e00 7400  o.o.l.....i.n.t.
+00000180: 6500 6700 6500 7200 0000 0000 0100 1c00  e.g.e.r.........
+00000190: 2800 0000 0100 0000 0000 0000 0001 0000  (...............
+000001a0: 2000 0000 0000 0000 0000 0000 0404 7465   .............te
+000001b0: 7374 0000 0202 1000 1400 0000 0100 0000  st..............
+000001c0: 0100 0000 0000 0000 0202 1000 1400 0000
+000001d0: 0200 0000 0100 0000 0000 0000 0102 5400
+000001e0: 6800 0000 0100 0000 0100 0000 5800 0000
+000001f0: 4000 0000 0000 0000 0000 0000 0000 0000
+00000200: 0000 0000 0000 0000 0000 0000 0000 0000
+00000210: 0000 0000 0000 0000 0000 0000 0000 0000
+00000220: 0000 0000 0000 0000 0000 0000 0000 0000
+00000230: 0000 0000 0800 0000 0000 0000 0800 0012
+00000240: ffff ffff 0102 5400 6800 0000 0200 0000  ......T.h.......
+00000250: 0100 0000 5800 0000 4000 0000 0000 0000  ....X...@.......
+00000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000270: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000280: 0000 0000 0000 0000 0000 0000 0000 0000  ................
+00000290: 0000 0000 0000 0000 0000 0000 0800 0000  ................
+000002a0: 0000 0000 0800 0010 0100 0000            ............
diff --git a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
new file mode 100644
index 0000000..75146e0
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
new file mode 100644
index 0000000..7c54fba
--- /dev/null
+++ b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<resources>
+    <bool name="test">true</bool>
+    <integer name="test">1</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/system/assets/file.txt b/libs/androidfw/tests/data/system/assets/file.txt
new file mode 100644
index 0000000..f73f309
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/file.txt
@@ -0,0 +1 @@
+file
diff --git a/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
new file mode 100644
index 0000000..3f74eb6
--- /dev/null
+++ b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
@@ -0,0 +1 @@
+subdir file
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
index bfbdf4c..b65145a 100755
--- a/libs/androidfw/tests/data/system/build
+++ b/libs/androidfw/tests/data/system/build
@@ -17,4 +17,6 @@
 
 set -e
 
-aapt package -x -M AndroidManifest.xml -S res -F system.apk -f
+aapt2 compile --dir res -o compiled.flata
+aapt2 link --manifest AndroidManifest.xml -A assets -o system.apk compiled.flata
+rm compiled.flata
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
index b97bdb6..5f60d21 100644
--- a/libs/androidfw/tests/data/system/res/values-sv/values.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -15,6 +15,5 @@
 -->
 
 <resources>
-    <public type="integer" name="number" id="0x01030000" />
     <integer name="number">1</integer>
 </resources>
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
index 35d43c7..7893c94 100644
--- a/libs/androidfw/tests/data/system/res/values/themes.xml
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -18,6 +18,7 @@
     <public name="background" type="attr" id="0x01010000"/>
     <public name="foreground" type="attr" id="0x01010001"/>
     <public name="Theme.One" type="style" id="0x01020000"/>
+    <public type="integer" name="number" id="0x01030000" />
 
     <attr name="background" format="color|reference"/>
     <attr name="foreground" format="color|reference"/>
diff --git a/libs/androidfw/tests/data/system/system.apk b/libs/androidfw/tests/data/system/system.apk
index 1299016..9045d6c 100644
--- a/libs/androidfw/tests/data/system/system.apk
+++ b/libs/androidfw/tests/data/system/system.apk
Binary files differ
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 9e0d10d..2b0b22d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -742,6 +742,12 @@
     SkPaint paintCopy(paint);
     paintCopy.setTextAlign(SkPaint::kLeft_Align);
     SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+    // Stroke with a hairline is drawn on HW with a fill style for compatibility with Android O and
+    // older.
+    if (!mCanvasOwned && sApiLevel <= 27 && paintCopy.getStrokeWidth() <= 0
+            && paintCopy.getStyle() == SkPaint::kStroke_Style) {
+        paintCopy.setStyle(SkPaint::kFill_Style);
+    }
 
     SkRect bounds =
             SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index a75276f..4f06656 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -66,7 +66,7 @@
     Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
 
     int rowBytesAsPixels() const {
-        return rowBytes() >> SkColorTypeShiftPerPixel(mInfo.colorType());
+        return rowBytes() >> mInfo.shiftPerPixel();
     }
 
     void reconfigure(const SkImageInfo& info, size_t rowBytes);
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 284fd83..ad4c8be 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -225,4 +225,10 @@
     MinikinUtils::forFontRun(layout, &paintCopy, f);
 }
 
+int Canvas::sApiLevel = 1;
+
+void Canvas::setCompatibilityVersion(int apiLevel) {
+    sApiLevel = apiLevel;
+}
+
 }  // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 3ddf1c4..fabb8d2 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -116,6 +116,14 @@
     static Canvas* create_canvas(SkCanvas* skiaCanvas);
 
     /**
+     *  Sets the target SDK version used to build the app.
+     *
+     *  @param apiLevel API level
+     *
+     */
+    static void setCompatibilityVersion(int apiLevel);
+
+    /**
      *  Provides a Skia SkCanvas interface that acts as a proxy to this Canvas.
      *  It is useful for testing and clients (e.g. Picture/Movie) that expect to
      *  draw their contents into an SkCanvas.
@@ -282,6 +290,8 @@
     virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
                                   const SkPaint& paint, const SkPath& path, size_t start,
                                   size_t end) = 0;
+    static int sApiLevel;
+
     friend class DrawTextFunctor;
     friend class DrawTextOnPathFunctor;
     friend class uirenderer::SkiaCanvasProxy;
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index 182e364..15c0ab1 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -471,6 +471,7 @@
         sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
         void onCopyOnWrite(ContentChangeMode) override {}
         int* mDrawCounter;
+        void onWritePixels(const SkPixmap&, int x, int y) {}
     };
 
     auto receiverBackground = TestUtils::createSkiaNode(
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 8fdb0e3..42a92fc 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -250,6 +250,7 @@
     sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
     T* canvas() { return static_cast<T*>(getCanvas()); }
     void onCopyOnWrite(ContentChangeMode) override {}
+    void onWritePixels(const SkPixmap&, int x, int y) override {}
 };
 }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index cd4143c..4c37014 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -16,9 +16,7 @@
 
 package android.media;
 
-import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
-import android.content.ComponentName;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
@@ -31,25 +29,33 @@
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.PlayerBase;
-import android.media.Rating;
 import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
-import android.net.Uri;
-import android.view.KeyEvent;
 
 /**
  * {@hide}
  */
 interface IAudioService {
+    // C++ and Java methods below.
 
-    // WARNING: When methods are inserted or deleted, the transaction IDs in
+    // WARNING: When methods are inserted or deleted in this section, the transaction IDs in
     // frameworks/native/include/audiomanager/IAudioManager.h must be updated to match the order
     // in this file.
     //
     // When a method's argument list is changed, BpAudioManager's corresponding serialization code
     // (if any) in frameworks/native/services/audiomanager/IAudioManager.cpp must be updated.
 
+    int trackPlayer(in PlayerBase.PlayerIdCard pic);
+
+    oneway void playerAttributes(in int piid, in AudioAttributes attr);
+
+    oneway void playerEvent(in int piid, in int event);
+
+    oneway void releasePlayer(in int piid);
+
+    // Java-only methods below.
+
     oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller);
 
@@ -187,14 +193,6 @@
 
     List<AudioPlaybackConfiguration> getActivePlaybackConfigurations();
 
-    int trackPlayer(in PlayerBase.PlayerIdCard pic);
-
-    oneway void playerAttributes(in int piid, in AudioAttributes attr);
-
-    oneway void playerEvent(in int piid, in int event);
-
-    oneway void releasePlayer(in int piid);
-
     void disableRingtoneSync(in int userId);
 
     int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
@@ -210,5 +208,6 @@
     oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
             in IAudioPolicyCallback pcb);
 
-    // WARNING: read warning at top of file, it is recommended to add new methods at the end
+    // WARNING: read warning at top of file, new methods that need to be used by native
+    // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/MediaDataSource.java b/media/java/android/media/MediaDataSource.java
index 948da0b..4ba2120 100644
--- a/media/java/android/media/MediaDataSource.java
+++ b/media/java/android/media/MediaDataSource.java
@@ -34,8 +34,8 @@
     /**
      * Called to request data from the given position.
      *
-     * Implementations should should write up to {@code size} bytes into
-     * {@code buffer}, and return the number of bytes written.
+     * Implementations should fill {@code buffer} with up to {@code size}
+     * bytes of data, and return the number of valid bytes in the buffer.
      *
      * Return {@code 0} if size is zero (thus no bytes are read).
      *
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 77237ae..87fe9ed 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -17,9 +17,10 @@
 #define LOG_TAG "Configuration"
 #include <utils/Log.h>
 
-#include <androidfw/AssetManager.h>
+#include <androidfw/AssetManager2.h>
 
 #include <android_runtime/android_content_res_Configuration.h>
+#include <android_runtime/android_util_AssetManager.h>
 
 using namespace android;
 
@@ -34,7 +35,11 @@
 }
 
 void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
-    ((AssetManager*)am)->getConfiguration(out);
+    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
+    ResTable_config config = locked_mgr->GetConfiguration();
+
+    // AConfiguration is not a virtual subclass, so we can memcpy.
+    memcpy(out, &config, sizeof(config));
 }
 
 void AConfiguration_copy(AConfiguration* dest, AConfiguration* src) {
diff --git a/packages/MtpDocumentsProvider/AndroidManifest.xml b/packages/MtpDocumentsProvider/AndroidManifest.xml
index 8d79f62..c0a59b3 100644
--- a/packages/MtpDocumentsProvider/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/AndroidManifest.xml
@@ -3,6 +3,7 @@
           package="com.android.mtp"
           android:sharedUserId="android.media">
     <uses-feature android:name="android.hardware.usb.host" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index c926e1f..c1aa2dc 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -250,6 +250,19 @@
         <item>Best Effort (Adaptive Bit Rate)</item>
     </string-array>
 
+    <!-- TODO: Enable for translation per b/73007419 -->
+    <!-- Summaries for Bluetooth Audio Active Device status. [CHAR LIMIT=50]-->
+    <string-array name="bluetooth_audio_active_device_summaries" translatable="false" >
+        <!-- Status message when the device is not Active. -->
+        <item></item>
+        <!-- Status message when the device is Active for Media and Phone. -->
+        <item>, active</item>
+        <!-- Status message when the device is Active for Media only. -->
+        <item>, active(media)</item>
+        <!-- Status message when the device is Active for Phone only. -->
+        <item>, active(phone)</item>
+    </string-array>
+
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
     <string-array name="select_logd_size_titles">
         <item>Off</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1cff59c..e557c65 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -128,27 +128,27 @@
      <!-- Bluetooth settings.  Message when connecting to a device -->
     <string name="bluetooth_connecting">Connecting\u2026</string>
     <!-- Bluetooth settings.  Message when connected to a device. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected">Connected</string>
+    <string name="bluetooth_connected">Connected<xliff:g id="active_device">%1$s</xliff:g></string>
     <!--Bluetooth settings screen, summary text under individual Bluetooth devices when pairing -->
     <string name="bluetooth_pairing">Pairing\u2026</string>
 
     <!-- Bluetooth settings.  Message when connected to a device, except for phone audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_headset">Connected (no phone)</string>
+    <string name="bluetooth_connected_no_headset">Connected (no phone)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for media audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_a2dp">Connected (no media)</string>
+    <string name="bluetooth_connected_no_a2dp">Connected (no media)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for map. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_map">Connected (no message access)</string>
+    <string name="bluetooth_connected_no_map">Connected (no message access)<xliff:g id="active_device">%1$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio. [CHAR LIMIT=40] -->
-    <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp">Connected (no phone or media)<xliff:g id="active_device">%1$s</xliff:g></string>
 
     <!-- Bluetooth settings.  Message when connected to a device, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_battery_level">Connected, battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_headset_battery_level">Connected (no phone), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_a2dp_battery_level">Connected (no media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
     <!-- Bluetooth settings.  Message when connected to a device, except for phone/media audio, showing remote device battery level. [CHAR LIMIT=NONE] -->
-    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g></string>
+    <string name="bluetooth_connected_no_headset_no_a2dp_battery_level">Connected (no phone or media), battery <xliff:g id="battery_level_as_percentage">%1$s</xliff:g><xliff:g id="active_device">%2$s</xliff:g></string>
 
     <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
     <string name="bluetooth_profile_a2dp">Media audio</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index fb0f75b..e1ebbc4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -940,60 +940,55 @@
                     com.android.settingslib.Utils.formatPercentage(batteryLevel);
         }
 
-        // TODO: A temporary workaround solution using string description the device is active.
-        // Issue tracked by b/72317067 .
-        // An alternative solution would be visual indication.
-        // Intentionally not adding the strings to strings.xml for now:
-        //  1) If this is just a short-term solution, no need to waste translation effort
-        //  2) The number of strings with all possible combinations becomes enormously large.
-        // If string description becomes part of the final solution, we MUST NOT
-        // concatenate the strings here: this does not translate well.
-        String activeString = null;
+        // Prepare the string for the Active Device summary
+        String[] activeDeviceStringsArray = mContext.getResources().getStringArray(
+                R.array.bluetooth_audio_active_device_summaries);
+        String activeDeviceString = activeDeviceStringsArray[0];  // Default value: not active
         if (mIsActiveDeviceA2dp && mIsActiveDeviceHeadset) {
-            activeString = ", active";
+            activeDeviceString = activeDeviceStringsArray[1];     // Active for Media and Phone
         } else {
             if (mIsActiveDeviceA2dp) {
-                activeString = ", active(media)";
+                activeDeviceString = activeDeviceStringsArray[2]; // Active for Media only
             }
             if (mIsActiveDeviceHeadset) {
-                activeString = ", active(phone)";
+                activeDeviceString = activeDeviceStringsArray[3]; // Active for Phone only
             }
         }
-        if (activeString == null) activeString = "";
 
         if (profileConnected) {
             if (a2dpNotConnected && hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(
                             R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp) +
-                        activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp,
+                            activeDeviceString);
                 }
 
             } else if (a2dpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_a2dp) + activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_a2dp,
+                            activeDeviceString);
                 }
 
             } else if (hfpNotConnected) {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected_no_headset)
-                          + activeString;
+                    return mContext.getString(R.string.bluetooth_connected_no_headset,
+                            activeDeviceString);
                 }
             } else {
                 if (batteryLevelPercentageString != null) {
                     return mContext.getString(R.string.bluetooth_connected_battery_level,
-                            batteryLevelPercentageString) + activeString;
+                            batteryLevelPercentageString, activeDeviceString);
                 } else {
-                    return mContext.getString(R.string.bluetooth_connected) + activeString;
+                    return mContext.getString(R.string.bluetooth_connected, activeDeviceString);
                 }
             }
         }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 4091ce1..1481161 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -80,22 +80,12 @@
         doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
     }
 
-    /**
-     * Test to verify the current test context object works so that we are not checking null
-     * against null
-     */
-    @Test
-    public void testContextMock() {
-        assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected");
-    }
-
     @Test
     public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
         // Test without battery level
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -105,9 +95,7 @@
         mBatteryLevel = 10;
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -118,8 +106,7 @@
 
         // Set PAN profile to be connected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
 
         // Set PAN profile to be disconnected and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -134,28 +121,23 @@
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_CONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, battery 10%");
 
         // Disconnect HFP only and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_headset_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone), battery 10%");
 
         // Disconnect A2DP only and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_a2dp_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no media), battery 10%");
 
         // Disconnect both HFP and A2DP and test connection state summary
         mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
-        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
-                R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
-                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone or media), battery 10%");
 
         // Disconnect all profiles and test connection state summary
         mCachedDevice.onProfileStateChanged(mPanProfile, BluetoothProfile.STATE_DISCONNECTED);
@@ -163,6 +145,117 @@
     }
 
     @Test
+    public void testGetConnectionSummary_testSingleProfileActiveDeviceA2dp() {
+        // Test without battery level
+        // Set A2DP profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for A2DP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active(media)");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set A2DP profile to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(media)");
+
+        // Set A2DP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
+    public void testGetConnectionSummary_testSingleProfileActiveDeviceHfp() {
+        // Test without battery level
+        // Set HFP profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for HFP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active(phone)");
+
+        // Set HFP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set HFP profile to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active(phone)");
+
+        // Set HFP profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
+    public void testGetConnectionSummary_testMultipleProfilesActiveDevice() {
+        // Test without battery level
+        // Set A2DP and HFP profiles to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected");
+
+        // Set device as Active for A2DP and HFP and test connection state summary
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected, battery 10%, active");
+
+        // Disconnect A2DP only and test connection state summary
+        mCachedDevice.setActiveDevice(false, BluetoothProfile.A2DP);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no media), battery 10%, active(phone)");
+
+        // Disconnect HFP only and test connection state summary
+        mCachedDevice.setActiveDevice(false, BluetoothProfile.HEADSET);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
+                "Connected (no phone), battery 10%, active(media)");
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+        // Set A2DP and HFP profiles to be connected, Active and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.A2DP);
+        mCachedDevice.setActiveDevice(true, BluetoothProfile.HEADSET);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Connected, active");
+
+        // Set A2DP and HFP profiles to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
     public void testDeviceName_testAliasNameAvailable() {
         when(mDevice.getAliasName()).thenReturn(DEVICE_ALIAS);
         when(mDevice.getName()).thenReturn(DEVICE_NAME);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 64b2ae6..79299aa 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.USE_RESERVED_DISK" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index e55c65a..a9021ae 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -901,13 +901,28 @@
     <dimen name="fingerprint_dialog_fp_icon_size">60dp</dimen>
     <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
 
-    <!-- WirelessCharging Animation values -->
-    <!-- Starting text size of batteryLevel for wireless charging animation -->
-    <dimen name="config_batteryLevelTextSizeStart" format="float">5.0</dimen>
-    <!-- Ending text size of batteryLevel for wireless charging animation -->
-    <dimen name="config_batteryLevelTextSizeEnd" format="float">32.0</dimen>
-    <!-- Wireless Charging battery level text animation duration -->
-    <integer name="config_batteryLevelTextAnimationDuration">400</integer>
+    <!-- Wireless Charging Animation values -->
+    <dimen name="wireless_charging_dots_radius_start">0dp</dimen>
+    <dimen name="wireless_charging_dots_radius_end">4dp</dimen>
+    <dimen name="wireless_charging_circle_radius_start">28dp</dimen>
+    <dimen name="wireless_charging_circle_radius_end">92dp</dimen>
+    <integer name="wireless_charging_angle_offset">20</integer>
+    <integer name="wireless_charging_scale_dots_duration">83</integer>
+    <integer name="wireless_charging_num_dots">20</integer>
+    <!-- Starting text size in dp of batteryLevel for wireless charging animation -->
+    <dimen name="wireless_charging_anim_battery_level_text_size_start">0dp</dimen>
+    <!-- Ending text size in dp of batteryLevel for wireless charging animation -->
+    <dimen name="wireless_charging_anim_battery_level_text_size_end">14dp</dimen>
+    <!-- time until battery info is at full opacity-->
+    <integer name="wireless_charging_anim_opacity_offset">80</integer>
+    <!-- duration batteryLevel opacity goes from 0 to 1 duration -->
+    <integer name="wireless_charging_battery_level_text_opacity_duration">117</integer>
+    <!-- battery text scale animation duration -->
+    <integer name="wireless_charging_battery_level_text_scale_animation_duration">367</integer>
+    <!--time until wireless charging animation starts to fade-->
+    <integer name="wireless_charging_fade_offset">920</integer>
+    <!-- duration wireless charging animation takes to full fade to 0 opacity -->
+    <integer name="wireless_charging_fade_duration">200</integer>
 
     <!-- Wired charging on AOD, text animation duration -->
     <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index 64fa9c6..cd9e126 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -21,9 +21,40 @@
 
 oneway interface IOverviewProxy {
     void onBind(in ISystemUiProxy sysUiProxy);
+
+    /**
+     * Proxies motion events from the nav bar in SystemUI to the OverviewProxyService. The sender
+     * guarantees the following order of events:
+     *
+     * Normal gesture: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, UP
+     * Quick switch: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SWITCH
+     * Quick scrub: DOWN, (MOVE/POINTER_DOWN/POINTER_UP)*, SCRUB_START, SCRUB_PROGRESS*, SCRUB_END
+     *
+     * Once quick switch/scrub is sent, then no further motion events will be provided.
+     */
     void onMotionEvent(in MotionEvent event);
+
+    /**
+     * Sent when a user has quickly flinged on the nav bar to switch tasks. Once this event is sent
+     * the caller will stop sending any motion events.
+     */
     void onQuickSwitch();
+
+    /**
+     * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
+     * sent the caller will stop sending any motion events.
+     */
     void onQuickScrubStart();
+
+    /**
+     * Sent when the user stops actively scrubbing the nav bar to switch tasks. Once this event is
+     * sent the caller will stop sending any motion events.
+     */
     void onQuickScrubEnd();
+
+    /**
+     * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks. Once
+     * this event is sent the caller will stop sending any motion events.
+     */
     void onQuickScrubProgress(float progress);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
index 348855b..afc9629 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -19,7 +19,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
@@ -36,13 +35,18 @@
  */
 public class WirelessChargingAnimation {
 
-    public static final long DURATION = 1400;
+    public static final long DURATION = 1133;
     private static final String TAG = "WirelessChargingView";
     private static final boolean LOCAL_LOGV = false;
 
     private final WirelessChargingView mCurrentWirelessChargingView;
     private static WirelessChargingView mPreviousWirelessChargingView;
 
+    public interface Callback {
+        void onAnimationStarting();
+        void onAnimationEnded();
+    }
+
     /**
      * Constructs an empty WirelessChargingAnimation object.  If looper is null,
      * Looper.myLooper() is used.  Must set
@@ -51,9 +55,9 @@
      * @hide
      */
     public WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper, int
-            batteryLevel) {
+            batteryLevel, Callback callback) {
         mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
-                batteryLevel);
+                batteryLevel, callback);
     }
 
     /**
@@ -61,8 +65,8 @@
      * @hide
      */
     public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
-            @Nullable Looper looper, int batteryLevel) {
-        return new WirelessChargingAnimation(context, looper, batteryLevel);
+            @Nullable Looper looper, int batteryLevel, Callback callback) {
+        return new WirelessChargingAnimation(context, looper, batteryLevel, callback);
     }
 
     /**
@@ -95,8 +99,11 @@
         private View mView;
         private View mNextView;
         private WindowManager mWM;
+        private Callback mCallback;
 
-        public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel) {
+        public WirelessChargingView(Context context, @Nullable Looper looper, int batteryLevel,
+                Callback callback) {
+            mCallback = callback;
             mNextView = new WirelessChargingLayout(context, batteryLevel);
             mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
 
@@ -149,6 +156,8 @@
         }
 
         public void hide(long duration) {
+            mHandler.removeMessages(HIDE);
+
             if (LOCAL_LOGV) Log.v(TAG, "HIDE: " + this);
             mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);
         }
@@ -169,18 +178,6 @@
                     context = mView.getContext();
                 }
                 mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-                // We can resolve the Gravity here by using the Locale for getting
-                // the layout direction
-                final Configuration config = mView.getContext().getResources().getConfiguration();
-                final int gravity = Gravity.getAbsoluteGravity(mGravity,
-                        config.getLayoutDirection());
-                mParams.gravity = gravity;
-                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
-                    mParams.horizontalWeight = 1.0f;
-                }
-                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
-                    mParams.verticalWeight = 1.0f;
-                }
                 mParams.packageName = packageName;
                 mParams.hideTimeoutMilliseconds = DURATION;
 
@@ -191,6 +188,9 @@
                 if (LOCAL_LOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
 
                 try {
+                    if (mCallback != null) {
+                        mCallback.onAnimationStarting();
+                    }
                     mWM.addView(mView, mParams);
                 } catch (WindowManager.BadTokenException e) {
                     Slog.d(TAG, "Unable to add wireless charging view. " + e);
@@ -203,6 +203,9 @@
             if (mView != null) {
                 if (mView.getParent() != null) {
                     if (LOCAL_LOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
+                    if (mCallback != null) {
+                        mCallback.onAnimationEnded();
+                    }
                     mWM.removeViewImmediate(mView);
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index c78ea56..8f87d64 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -16,13 +16,16 @@
 
 package com.android.systemui.charging;
 
+import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.animation.PathInterpolator;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 import java.text.NumberFormat;
@@ -52,10 +55,9 @@
         init(c, attrs, -1);
     }
 
-    private void init(Context c, AttributeSet attrs, int batteryLevel) {
+    private void init(Context context, AttributeSet attrs, int batteryLevel) {
         final int mBatteryLevel = batteryLevel;
-
-        inflate(c, R.layout.wireless_charging_layout, this);
+        inflate(context, R.layout.wireless_charging_layout, this);
 
         // where the circle animation occurs:
         final WirelessChargingView mChargingView = findViewById(R.id.wireless_charging_view);
@@ -68,14 +70,57 @@
 
         if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
             mPercentage.setText(NumberFormat.getPercentInstance().format(mBatteryLevel / 100f));
-
-            ValueAnimator animator = ObjectAnimator.ofFloat(mPercentage, "textSize",
-                    getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeStart),
-                    getContext().getResources().getFloat(R.dimen.config_batteryLevelTextSizeEnd));
-
-            animator.setDuration((long) getContext().getResources().getInteger(
-                    R.integer.config_batteryLevelTextAnimationDuration));
-            animator.start();
+            mPercentage.setAlpha(0);
         }
+
+        final long chargingAnimationFadeStartOffset = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_fade_offset);
+        final long chargingAnimationFadeDuration = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_fade_duration);
+        final int batteryLevelTextSizeStart = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_anim_battery_level_text_size_start);
+        final int batteryLevelTextSizeEnd = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_anim_battery_level_text_size_end);
+
+        // Animation Scale: battery percentage text scales from 0% to 100%
+        ValueAnimator textSizeAnimator = ObjectAnimator.ofFloat(mPercentage, "textSize",
+                batteryLevelTextSizeStart, batteryLevelTextSizeEnd);
+        textSizeAnimator.setInterpolator(new PathInterpolator(0, 0, 0, 1));
+        textSizeAnimator.setDuration((long) context.getResources().getInteger(
+                R.integer.wireless_charging_battery_level_text_scale_animation_duration));
+
+        // Animation Opacity: battery percentage text transitions from 0 to 1 opacity
+        ValueAnimator textOpacityAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 0, 1);
+        textOpacityAnimator.setInterpolator(Interpolators.LINEAR);
+        textOpacityAnimator.setDuration((long) context.getResources().getInteger(
+                R.integer.wireless_charging_battery_level_text_opacity_duration));
+        textOpacityAnimator.setStartDelay((long) context.getResources().getInteger(
+                R.integer.wireless_charging_anim_opacity_offset));
+
+        // Animation Opacity: battery percentage text fades from 1 to 0 opacity
+        ValueAnimator textFadeAnimator = ObjectAnimator.ofFloat(mPercentage, "alpha", 1, 0);
+        textFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        textFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        textFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // Animation Opacity: wireless charging circle animation fades from 1 to 0 opacity
+        ValueAnimator circleFadeAnimator = ObjectAnimator.ofFloat(mChargingView, "alpha",
+                1, 0);
+        circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        circleFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        circleFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // Animation Opacity: secondary text animation fades from 1 to 0 opacity
+        ValueAnimator secondaryTextFadeAnimator = ObjectAnimator.ofFloat(mSecondaryText, "alpha",
+                1, 0);
+        circleFadeAnimator.setDuration(chargingAnimationFadeDuration);
+        secondaryTextFadeAnimator.setInterpolator(Interpolators.LINEAR);
+        secondaryTextFadeAnimator.setStartDelay(chargingAnimationFadeStartOffset);
+
+        // play all animations together
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator,
+                circleFadeAnimator, secondaryTextFadeAnimator);
+        animatorSet.start();
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
index f5edf52..19c6dc1 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.java
@@ -21,10 +21,10 @@
 import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
 
 import com.android.settingslib.Utils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 
 final class WirelessChargingView extends View {
@@ -33,21 +33,21 @@
     private float mPathGone;
     private float mInterpolatedPathGone;
     private long mAnimationStartTime;
-    private long mStartSpinCircleAnimationTime;
-    private long mAnimationOffset = 500;
-    private long mTotalAnimationDuration = WirelessChargingAnimation.DURATION - mAnimationOffset;
-    private long mExpandingCircle = (long) (mTotalAnimationDuration * .9);
-    private long mSpinCircleAnimationTime = mTotalAnimationDuration - mExpandingCircle;
+    private long mScaleDotsDuration;
 
-    private boolean mFinishedAnimatingSpinningCircles = false;
+    private boolean mFinishedAnimatingDots = false;
+    private int mNumDots;
 
-    private int mStartAngle = -90;
-    private int mNumSmallCircles = 20;
-    private int mSmallCircleRadius = 10;
+    private double mAngleOffset;
+    private double mCurrAngleOffset;
 
-    private int mMainCircleStartRadius = 100;
-    private int mMainCircleEndRadius = 230;
-    private int mMainCircleCurrentRadius = mMainCircleStartRadius;
+    private int mDotsRadiusStart;
+    private int mDotsRadiusEnd;
+    private int mCurrDotRadius;
+
+    private int mMainCircleStartRadius;
+    private int mMainCircleEndRadius;
+    private int mMainCircleCurrentRadius;
 
     private int mCenterX;
     private int mCenterY;
@@ -72,8 +72,25 @@
 
     public void init(Context context, AttributeSet attr) {
         mContext = context;
+
+        mDotsRadiusStart = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_dots_radius_start);
+        mDotsRadiusEnd = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_dots_radius_end);
+
+        mMainCircleStartRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_circle_radius_start);
+        mMainCircleEndRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.wireless_charging_circle_radius_end);
+        mMainCircleCurrentRadius = mMainCircleStartRadius;
+
+        mAngleOffset = context.getResources().getInteger(R.integer.wireless_charging_angle_offset);
+        mScaleDotsDuration = (long) context.getResources().getInteger(
+                R.integer.wireless_charging_scale_dots_duration);
+        mNumDots = context.getResources().getInteger(R.integer.wireless_charging_num_dots);
+
         setupPaint();
-        mInterpolator = new DecelerateInterpolator();
+        mInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
     }
 
     private void setupPaint() {
@@ -92,64 +109,62 @@
         updateDrawingParameters();
         drawCircles(canvas);
 
-        if (!mFinishedAnimatingSpinningCircles) {
+        if (!mFinishedAnimatingDots) {
             invalidate();
         }
     }
 
     /**
      * Draws a larger circle of radius {@link WirelessChargingView#mMainCircleEndRadius} composed of
-     * {@link WirelessChargingView#mNumSmallCircles} smaller circles
+     * {@link WirelessChargingView#mNumDots} smaller circles
      * @param canvas
      */
     private void drawCircles(Canvas canvas) {
         mCenterX = canvas.getWidth() / 2;
         mCenterY = canvas.getHeight() / 2;
 
-        // angleOffset makes small circles look like they're moving around the main circle
-        float angleOffset = mPathGone * 10;
-
-        // draws mNumSmallCircles to compose a larger, main circle
-        for (int circle = 0; circle < mNumSmallCircles; circle++) {
-            double angle = ((mStartAngle + angleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
-                    / mNumSmallCircles));
+        // draws mNumDots to compose a larger, main circle
+        for (int circle = 0; circle < mNumDots; circle++) {
+            double angle = ((mCurrAngleOffset) * Math.PI / 180) + (circle * ((2 * Math.PI)
+                    / mNumDots));
 
             int x = (int) (mCenterX + Math.cos(angle) * (mMainCircleCurrentRadius +
-                    mSmallCircleRadius));
+                    mCurrDotRadius));
             int y = (int) (mCenterY + Math.sin(angle) * (mMainCircleCurrentRadius +
-                    mSmallCircleRadius));
+                    mCurrDotRadius));
 
-            canvas.drawCircle(x, y, mSmallCircleRadius, mPaint);
+            canvas.drawCircle(x, y, mCurrDotRadius, mPaint);
         }
 
-        if (mMainCircleCurrentRadius >= mMainCircleEndRadius && !isSpinCircleAnimationStarted()) {
-            mStartSpinCircleAnimationTime = System.currentTimeMillis();
+        if (mMainCircleCurrentRadius >= mMainCircleEndRadius) {
+            mFinishedAnimatingDots = true;
         }
-
-        if (isSpinAnimationFinished()) {
-            mFinishedAnimatingSpinningCircles = true;
-        }
-    }
-
-    private boolean isSpinCircleAnimationStarted() {
-        return mStartSpinCircleAnimationTime != 0;
-    }
-
-    private boolean isSpinAnimationFinished() {
-        return isSpinCircleAnimationStarted() && System.currentTimeMillis() -
-                mStartSpinCircleAnimationTime > mSpinCircleAnimationTime;
     }
 
     private void updateDrawingParameters() {
-        mPathGone = getPathGone(System.currentTimeMillis());
+        long now = System.currentTimeMillis();
+        long timeSinceStart = now - mAnimationStartTime;
+        mPathGone = getPathGone(now);
         mInterpolatedPathGone = mInterpolator.getInterpolation(mPathGone);
 
+        // Position Dots: update main circle radius (that the dots compose)
         if (mPathGone < 1.0f) {
             mMainCircleCurrentRadius = mMainCircleStartRadius + (int) (mInterpolatedPathGone *
                     (mMainCircleEndRadius - mMainCircleStartRadius));
         } else {
             mMainCircleCurrentRadius = mMainCircleEndRadius;
         }
+
+        // Scale Dots: update dot radius
+        if (timeSinceStart < mScaleDotsDuration) {
+            mCurrDotRadius = mDotsRadiusStart + (int) (mInterpolator.getInterpolation((float)
+                    timeSinceStart / mScaleDotsDuration) * (mDotsRadiusEnd - mDotsRadiusStart));
+        } else {
+            mCurrDotRadius = mDotsRadiusEnd;
+        }
+
+        // Rotation Dot Group: dots rotate from 0 to 20 degrees
+        mCurrAngleOffset = mAngleOffset * mPathGone;
     }
 
     /**
@@ -158,6 +173,6 @@
      * For values > 1.0 the larger circle has been drawn and further animation can occur
      */
     private float getPathGone(long now) {
-        return (float) (now - mAnimationStartTime) / (mExpandingCircle);
+        return (float) (now - mAnimationStartTime) / (WirelessChargingAnimation.DURATION);
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index bfb3a6e..092f3d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -64,7 +64,7 @@
                 createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
                         handler, wakeLock, machine),
                 createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
-                new DozeScreenState(wrappedService, handler),
+                new DozeScreenState(wrappedService, handler, params),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler),
                 new DozeWallpaperState(context)
         });
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 8ec6afc..6ff8e3d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -24,6 +24,7 @@
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.internal.util.Preconditions;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.wakelock.WakeLock;
 
@@ -87,12 +88,11 @@
             }
         }
 
-        int screenState() {
+        int screenState(DozeParameters parameters) {
             switch (this) {
                 case UNINITIALIZED:
                 case INITIALIZED:
                 case DOZE:
-                case DOZE_REQUEST_PULSE:
                 case DOZE_AOD_PAUSED:
                     return Display.STATE_OFF;
                 case DOZE_PULSING:
@@ -100,6 +100,9 @@
                 case DOZE_AOD:
                 case DOZE_AOD_PAUSING:
                     return Display.STATE_DOZE_SUSPEND;
+                case DOZE_REQUEST_PULSE:
+                    return parameters.getDisplayNeedsBlanking() ? Display.STATE_OFF
+                            : Display.STATE_ON;
                 default:
                     return Display.STATE_UNKNOWN;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index bef9cb3..3053de3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -19,6 +19,8 @@
 import android.os.Handler;
 import android.view.Display;
 
+import com.android.systemui.statusbar.phone.DozeParameters;
+
 /**
  * Controls the screen when dozing.
  */
@@ -26,17 +28,20 @@
     private final DozeMachine.Service mDozeService;
     private final Handler mHandler;
     private final Runnable mApplyPendingScreenState = this::applyPendingScreenState;
+    private final DozeParameters mParameters;
 
     private int mPendingScreenState = Display.STATE_UNKNOWN;
 
-    public DozeScreenState(DozeMachine.Service service, Handler handler) {
+    public DozeScreenState(DozeMachine.Service service, Handler handler,
+            DozeParameters parameters) {
         mDozeService = service;
         mHandler = handler;
+        mParameters = parameters;
     }
 
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
-        int screenState = newState.screenState();
+        int screenState = newState.screenState(mParameters);
 
         if (newState == DozeMachine.State.FINISH) {
             // Make sure not to apply the screen state after DozeService was destroyed.
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index ea2a432..ac86c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -53,7 +53,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
 
 public class PowerUI extends SystemUI {
     static final String TAG = "PowerUI";
@@ -72,10 +71,11 @@
     private final Configuration mLastConfiguration = new Configuration();
     private int mBatteryLevel = 100;
     private long mTimeRemaining = Long.MAX_VALUE;
-    private int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
     private int mPlugType = 0;
     private int mInvalidCharger = 0;
     private EnhancedEstimates mEnhancedEstimates;
+    private boolean mLowWarningShownThisChargeCycle;
+    private boolean mSevereWarningShownThisChargeCycle;
 
     private int mLowBatteryAlertCloseLevel;
     private final int[] mLowBatteryReminderLevels = new int[2];
@@ -88,6 +88,8 @@
     private long mNextLogTime;
     private IThermalService mThermalService;
 
+    @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
+
     // by using the same instance (method references are not guaranteed to be the same object
     // We create a method reference here so that we are guaranteed that we can remove a callback
     // each time they are created).
@@ -218,6 +220,12 @@
 
                 final boolean plugged = mPlugType != 0;
                 final boolean oldPlugged = oldPlugType != 0;
+                // if we are now unplugged but we were previously plugged in we should allow the
+                // time based trigger again.
+                if (!plugged && plugged != oldPlugged) {
+                    mLowWarningShownThisChargeCycle = false;
+                    mSevereWarningShownThisChargeCycle = false;
+                }
 
                 int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
                 int bucket = findBatteryLevelBucket(mBatteryLevel);
@@ -268,7 +276,6 @@
         boolean isPowerSaver = mPowerManager.isPowerSaveMode();
         // only play SFX when the dialog comes up or the bucket changes
         final boolean playSound = bucket != oldBucket || oldPlugged;
-        long oldTimeRemaining = mTimeRemaining;
         if (mEnhancedEstimates.isHybridNotificationEnabled()) {
             final Estimate estimate = mEnhancedEstimates.getEstimate();
             // Turbo is not always booted once SysUI is running so we have ot make sure we actually
@@ -281,10 +288,18 @@
             }
         }
 
-        if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket, oldTimeRemaining,
-                mTimeRemaining,
-                isPowerSaver, mBatteryStatus)) {
+        if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket,
+                mTimeRemaining, isPowerSaver, mBatteryStatus)) {
             mWarnings.showLowBatteryWarning(playSound);
+
+            // mark if we've already shown a warning this cycle. This will prevent the time based
+            // trigger from spamming users since the time remaining can vary based on current
+            // device usage.
+            if (mTimeRemaining < mEnhancedEstimates.getSevereWarningThreshold()) {
+                mSevereWarningShownThisChargeCycle = true;
+            } else {
+                mLowWarningShownThisChargeCycle = true;
+            }
         } else if (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
                 isPowerSaver)) {
             mWarnings.dismissLowBatteryWarning();
@@ -295,22 +310,14 @@
 
     @VisibleForTesting
     boolean shouldShowLowBatteryWarning(boolean plugged, boolean oldPlugged, int oldBucket,
-            int bucket, long oldTimeRemaining, long timeRemaining,
-            boolean isPowerSaver, int mBatteryStatus) {
+            int bucket, long timeRemaining, boolean isPowerSaver, int mBatteryStatus) {
         return !plugged
                 && !isPowerSaver
                 && (((bucket < oldBucket || oldPlugged) && bucket < 0)
-                        || (mEnhancedEstimates.isHybridNotificationEnabled()
-                                && timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
-                                && isHourLess(oldTimeRemaining, timeRemaining)))
+                        || isTimeBasedTrigger(timeRemaining))
                 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN;
     }
 
-    private boolean isHourLess(long oldTimeRemaining, long timeRemaining) {
-        final long dif = oldTimeRemaining - timeRemaining;
-        return dif >= TimeUnit.HOURS.toMillis(1);
-    }
-
     @VisibleForTesting
     boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
             long timeRemaining, boolean isPowerSaver) {
@@ -323,6 +330,23 @@
                         || hybridWouldDismiss));
     }
 
+    private boolean isTimeBasedTrigger(long timeRemaining) {
+        if (!mEnhancedEstimates.isHybridNotificationEnabled()) {
+            return false;
+        }
+
+        // Only show the time based warning once per charge cycle
+        final boolean canShowWarning = timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
+                && !mLowWarningShownThisChargeCycle;
+
+        // Only show the severe time based warning once per charge cycle
+        final boolean canShowSevereWarning =
+                timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
+                        && !mSevereWarningShownThisChargeCycle;
+
+        return canShowWarning || canShowSevereWarning;
+    }
+
     private void initTemperatureWarning() {
         ContentResolver resolver = mContext.getContentResolver();
         Resources resources = mContext.getResources();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 11bdf6b3..fa177f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -156,7 +156,7 @@
         default void handleShowGlobalActionsMenu() { }
         default void handleShowShutdownUi(boolean isReboot, String reason) { }
 
-        default void showChargingAnimation(int batteryLevel) {  }
+        default void showWirelessChargingAnimation(int batteryLevel) {  }
 
         default void onRotationProposal(int rotation, boolean isValid) { }
 
@@ -497,7 +497,7 @@
     }
 
     @Override
-    public void showChargingAnimation(int batteryLevel) {
+    public void showWirelessChargingAnimation(int batteryLevel) {
         mHandler.removeMessages(MSG_SHOW_CHARGING_ANIMATION);
         mHandler.obtainMessage(MSG_SHOW_CHARGING_ANIMATION, batteryLevel, 0)
                 .sendToTarget();
@@ -784,7 +784,7 @@
                     break;
                 case MSG_SHOW_CHARGING_ANIMATION:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).showChargingAnimation(msg.arg1);
+                        mCallbacks.get(i).showWirelessChargingAnimation(msg.arg1);
                     }
                     break;
                 case MSG_SHOW_PINNING_TOAST_ENTER_EXIT:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 7db6e28..8d14db7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -16,37 +16,37 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.OverviewProxyService.TAG_OPS;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
-
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
+import com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
 import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.tuner.TunerService;
 
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.OverviewProxyService.TAG_OPS;
-
 /**
  * Class to detect gestures on the navigation bar.
  */
@@ -84,8 +84,16 @@
     private int mTouchDownY;
     private boolean mDownOnRecents;
     private VelocityTracker mVelocityTracker;
-    private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
+    private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
+        @Override
+        public void onRecentsAnimationStarted() {
+            mRecentsAnimationStarted = true;
+            mQuickScrubController.cancelQuickSwitch();
+        }
+    };
 
+    private boolean mRecentsAnimationStarted;
     private boolean mDockWindowEnabled;
     private boolean mDockWindowTouchSlopExceeded;
     private int mDragMode;
@@ -97,10 +105,12 @@
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
         mQuickScrubController = new QuickScrubController(context);
         Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
+        mOverviewProxyService.addCallback(mOverviewProxyListener);
     }
 
     public void destroy() {
         Dependency.get(TunerService.class).removeTunable(this);
+        mOverviewProxyService.removeCallback(mOverviewProxyListener);
     }
 
     public void setComponents(RecentsComponent recentsComponent, Divider divider,
@@ -117,7 +127,7 @@
     }
 
     private boolean proxyMotionEvents(MotionEvent event) {
-        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
         if (overviewProxy != null) {
             mNavigationBarView.requestUnbufferedDispatch(event);
             event.transform(mTransformGlobalMatrix);
@@ -146,6 +156,19 @@
                 mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
                 mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
                 mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
+                mRecentsAnimationStarted = false;
+                break;
+            }
+            case MotionEvent.ACTION_UP: {
+                // If the overview proxy service has not started the recents animation then clean up
+                // after it to ensure that the nav bar buttons still work
+                if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
+                    try {
+                        ActivityManager.getService().cancelRecentsAnimation();
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Could not cancel recents animation", e);
+                    }
+                }
                 break;
             }
         }
@@ -154,13 +177,13 @@
             proxyMotionEvents(event);
             return false;
         }
-        return (mDockWindowEnabled && interceptDockWindowEvent(event));
+        return (mDockWindowEnabled && interceptDockWindowEvent(event)) || mRecentsAnimationStarted;
     }
 
     public boolean onTouchEvent(MotionEvent event) {
         // The same down event was just sent on intercept and therefore can be ignored here
         boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
-                && mOverviewEventSender.getProxy() != null;
+                && mOverviewProxyService.getProxy() != null;
         boolean result = mStatusBar.isPresenterFullyCollapsed()
                 && (mQuickScrubController.onTouchEvent(event)
                 || ignoreProxyDownEvent
@@ -168,11 +191,11 @@
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
-        return result;
+        return result || mRecentsAnimationStarted;
     }
 
     public void onDraw(Canvas canvas) {
-        if (mOverviewEventSender.getProxy() != null) {
+        if (mOverviewProxyService.getProxy() != null) {
             mQuickScrubController.onDraw(canvas);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index ad5144e..af0afbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -103,7 +103,6 @@
     private DeadZone mDeadZone;
     private final NavigationBarTransitions mBarTransitions;
     private final OverviewProxyService mOverviewProxyService;
-    private boolean mRecentsAnimationStarted;
 
     // workaround for LayoutTransitions leaving the nav buttons in a weird state (bug 5549288)
     final static boolean WORKAROUND_INVALID_LAYOUT = true;
@@ -263,7 +262,6 @@
     }
 
     public void setRecentsAnimationStarted(boolean started) {
-        mRecentsAnimationStarted = started;
         if (mRecentsOnboarding != null) {
             mRecentsOnboarding.onRecentsAnimationStarted();
         }
@@ -277,22 +275,7 @@
 
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        int action = event.getActionMasked();
-        if (action == MotionEvent.ACTION_DOWN) {
-            mRecentsAnimationStarted = false;
-        } else if (action == MotionEvent.ACTION_UP) {
-            // If the overview proxy service has not started the recents animation then clean up
-            // after it to ensure that the nav bar buttons still work
-            if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
-                try {
-                    ActivityManager.getService().cancelRecentsAnimation();
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Could not cancel recents animation");
-                }
-            }
-        }
-
-        return mGestureHelper.onInterceptTouchEvent(event) || mRecentsAnimationStarted;
+        return mGestureHelper.onInterceptTouchEvent(event);
     }
 
     @Override
@@ -300,7 +283,7 @@
         if (mGestureHelper.onTouchEvent(event)) {
             return true;
         }
-        return mRecentsAnimationStarted || super.onTouchEvent(event);
+        return super.onTouchEvent(event);
     }
 
     public void abortCurrentGesture() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index 6bfaaf4..dc0835e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -63,7 +63,7 @@
     private static final String TAG = "QuickScrubController";
     private static final int QUICK_SWITCH_FLING_VELOCITY = 0;
     private static final int ANIM_DURATION_MS = 200;
-    private static final long LONG_PRESS_DELAY_MS = 150;
+    private static final long LONG_PRESS_DELAY_MS = 225;
 
     /**
      * For quick step, set a damping value to allow the button to stick closer its origin position
@@ -76,6 +76,7 @@
 
     private boolean mDraggingActive;
     private boolean mQuickScrubActive;
+    private boolean mAllowQuickSwitch;
     private float mDownOffset;
     private float mTranslation;
     private int mTouchDownX;
@@ -95,7 +96,6 @@
     private final Paint mTrackPaint = new Paint();
     private final int mScrollTouchSlop;
     private final OverviewProxyService mOverviewEventSender;
-    private final Display mDisplay;
     private final int mTrackThickness;
     private final int mTrackPadding;
     private final ValueAnimator mTrackAnimator;
@@ -137,7 +137,8 @@
         new GestureDetector.SimpleOnGestureListener() {
             @Override
             public boolean onFling(MotionEvent e1, MotionEvent e2, float velX, float velY) {
-                if (!isQuickScrubEnabled() || mQuickScrubActive) {
+                if (!isQuickScrubEnabled() || mQuickScrubActive || !mAllowQuickSwitch ||
+                        !mHomeButtonRect.contains(mTouchDownX, mTouchDownY)) {
                     return false;
                 }
                 float velocityX = mIsRTL ? -velX : velX;
@@ -167,8 +168,6 @@
     public QuickScrubController(Context context) {
         mContext = context;
         mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mDisplay = ((WindowManager) context.getSystemService(
-                Context.WINDOW_SERVICE)).getDefaultDisplay();
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
         mGestureDetector = new GestureDetector(mContext, mGestureListener);
         mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
@@ -202,8 +201,24 @@
             homeButton.setDelayTouchFeedback(false);
             return false;
         }
+
+        return handleTouchEvent(event);
+    }
+
+    /**
+     * @return true if we want to handle touch events for quick scrub/switch and prevent proxying
+     *         the event to the overview service.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        return handleTouchEvent(event);
+    }
+
+    private boolean handleTouchEvent(MotionEvent event) {
+        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
         if (mGestureDetector.onTouchEvent(event)) {
-            // If the fling has been handled, then skip proxying the UP
+            // If the fling has been handled on UP, then skip proxying the UP
             return true;
         }
         int action = event.getAction();
@@ -220,6 +235,7 @@
                     homeButton.setDelayTouchFeedback(false);
                     mTouchDownX = mTouchDownY = -1;
                 }
+                mAllowQuickSwitch = true;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
@@ -304,22 +320,6 @@
         return mDraggingActive || mQuickScrubActive;
     }
 
-    /**
-     * @return true if we want to handle touch events for quick scrub/switch and prevent proxying
-     *         the event to the overview service.
-     */
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mGestureDetector.onTouchEvent(event)) {
-            // If the fling has been handled, then skip proxying the UP
-            return true;
-        }
-        if (event.getAction() == MotionEvent.ACTION_UP) {
-            endQuickScrub();
-        }
-        return mDraggingActive || mQuickScrubActive;
-    }
-
     @Override
     public void onDraw(Canvas canvas) {
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
@@ -420,6 +420,11 @@
         mDraggingActive = false;
     }
 
+    public void cancelQuickSwitch() {
+        mAllowQuickSwitch = false;
+        mHandler.removeCallbacks(mLongPressRunnable);
+    }
+
     private int getDimensionPixelSize(Context context, @DimenRes int resId) {
         return context.getResources().getDimensionPixelSize(resId);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 2b16e74..1438763 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -166,7 +166,10 @@
     private boolean mScreenBlankingCallbackCalled;
     private Callback mCallback;
     private boolean mWallpaperSupportsAmbientMode;
+
+    // Scrim blanking callbacks
     private Choreographer.FrameCallback mPendingFrameCallback;
+    private Runnable mBlankingTransitionRunnable;
 
     private final WakeLock mWakeLock;
     private boolean mWakeLockHeld;
@@ -249,10 +252,15 @@
         mCurrentInFrontAlpha = state.getFrontAlpha();
         mCurrentBehindAlpha = state.getBehindAlpha();
 
+        // Cancel blanking transitions that were pending before we requested a new state
         if (mPendingFrameCallback != null) {
             Choreographer.getInstance().removeFrameCallback(mPendingFrameCallback);
             mPendingFrameCallback = null;
         }
+        if (getHandler().hasCallbacks(mBlankingTransitionRunnable)) {
+            getHandler().removeCallbacks(mBlankingTransitionRunnable);
+            mBlankingTransitionRunnable = null;
+        }
 
         // Showing/hiding the keyguard means that scrim colors have to be switched, not necessary
         // to do the same when you're just showing the brightness mirror.
@@ -767,7 +775,8 @@
                 mScreenBlankingCallbackCalled = true;
             }
 
-            Runnable blankingCallback = () -> {
+            mBlankingTransitionRunnable = () -> {
+                mBlankingTransitionRunnable = null;
                 mPendingFrameCallback = null;
                 mBlankScreen = false;
                 // Try again.
@@ -776,7 +785,10 @@
 
             // Setting power states can happen after we push out the frame. Make sure we
             // stay fully opaque until the power state request reaches the lower levels.
-            getHandler().postDelayed(blankingCallback, 100);
+            if (DEBUG) {
+                Log.d(TAG, "Waiting for the screen to turn on...");
+            }
+            getHandler().postDelayed(mBlankingTransitionRunnable, 500);
         };
         doOnTheNextFrame(mPendingFrameCallback);
     }
@@ -888,6 +900,20 @@
         }
     }
 
+    /**
+     * Interrupts blanking transitions once the display notifies that it's already on.
+     */
+    public void onScreenTurnedOn() {
+        final Handler handler = getHandler();
+        if (handler.hasCallbacks(mBlankingTransitionRunnable)) {
+            if (DEBUG) {
+                Log.d(TAG, "Shorter blanking because screen turned on. All good.");
+            }
+            handler.removeCallbacks(mBlankingTransitionRunnable);
+            mBlankingTransitionRunnable.run();
+        }
+    }
+
     public interface Callback {
         default void onStart() {
         }
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 3777a6c..458518c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -140,7 +140,6 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.ActivityStarterDelegate;
 import com.android.systemui.AutoReinflateContainer;
-import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.DemoMode;
 import com.android.systemui.Dependency;
 import com.android.systemui.EventLogTags;
@@ -152,6 +151,7 @@
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -181,6 +181,7 @@
 import com.android.systemui.statusbar.ActivatableNotificationView;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.DismissView;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -2460,14 +2461,25 @@
     }
 
     @Override
-    public void showChargingAnimation(int batteryLevel) {
-        if (mDozing) {
-            // ambient
-        } else if (mKeyguardManager.isKeyguardLocked()) {
-            // lockscreen
-        } else {
+    public void showWirelessChargingAnimation(int batteryLevel) {
+        if (mDozing || mKeyguardManager.isKeyguardLocked()) {
+            // on ambient or lockscreen, hide notification panel
             WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
-                    batteryLevel).show();
+                    batteryLevel, new WirelessChargingAnimation.Callback() {
+                        @Override
+                        public void onAnimationStarting() {
+                            CrossFadeHelper.fadeOut(mNotificationPanel, 1);
+                        }
+
+                        @Override
+                        public void onAnimationEnded() {
+                            CrossFadeHelper.fadeIn(mNotificationPanel);
+                        }
+                    }).show();
+        } else {
+            // workspace
+            WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
+                    batteryLevel, null).show();
         }
     }
 
@@ -3883,6 +3895,7 @@
 
     private void instantCollapseNotificationPanel() {
         mNotificationPanel.instantCollapse();
+        runPostCollapseRunnables();
     }
 
     @Override
@@ -4394,6 +4407,7 @@
 
         @Override
         public void onScreenTurnedOn() {
+            mScrimController.onScreenTurnedOn();
         }
 
         @Override
@@ -5044,6 +5058,8 @@
         } else if (!isPresenterFullyCollapsed()) {
             instantCollapseNotificationPanel();
             visibilityChanged(false);
+        } else {
+            runPostCollapseRunnables();
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index 521d2e3..8c4fd73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -28,6 +28,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import android.os.Looper;
 import android.support.test.filters.SmallTest;
@@ -35,11 +36,14 @@
 import android.view.Display;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.utils.os.FakeHandler;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -48,12 +52,16 @@
     DozeServiceFake mServiceFake;
     DozeScreenState mScreen;
     FakeHandler mHandlerFake;
+    @Mock
+    DozeParameters mDozeParameters;
 
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
         mServiceFake = new DozeServiceFake();
         mHandlerFake = new FakeHandler(Looper.getMainLooper());
-        mScreen = new DozeScreenState(mServiceFake, mHandlerFake);
+        mScreen = new DozeScreenState(mServiceFake, mHandlerFake, mDozeParameters);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 0a51e5a..4b455ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -155,7 +155,7 @@
         // hybrid but the threshold has been overriden to be too low
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
@@ -172,7 +172,7 @@
         // hybrid since the threshold has been overriden to be much higher
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, ABOVE_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -188,7 +188,7 @@
         // hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -203,7 +203,7 @@
         // unplugged device that would show the non-hybrid notification and the hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -218,7 +218,7 @@
         // unplugged device that would show the non-hybrid but not the hybrid
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, Long.MAX_VALUE, ABOVE_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertTrue(shouldShow);
     }
@@ -233,7 +233,7 @@
         // unplugged device that would show the neither due to battery level being good
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, ABOVE_HYBRID_THRESHOLD,
+                        ABOVE_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
@@ -248,7 +248,7 @@
         // plugged device that would show the neither due to being plugged
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(!UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
    }
@@ -263,7 +263,7 @@
         // Unknown battery status device that would show the neither due
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         !POWER_SAVER_OFF, BatteryManager.BATTERY_STATUS_UNKNOWN);
         assertFalse(shouldShow);
     }
@@ -278,12 +278,31 @@
         // BatterySaverEnabled device that would show the neither due to battery saver
         boolean shouldShow =
                 mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
-                        BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, BELOW_HYBRID_THRESHOLD,
+                        BELOW_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
                         !POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
         assertFalse(shouldShow);
     }
 
     @Test
+    public void testShouldShowLowBatteryWarning_onlyShowsOncePerChargeCycle() {
+        mPowerUI.start();
+        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
+        when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+        when(mEnhancedEstimates.getEstimate())
+                .thenReturn(new Estimate(BELOW_HYBRID_THRESHOLD, true));
+        mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
+
+        mPowerUI.maybeShowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                ABOVE_WARNING_BUCKET);
+        boolean shouldShow =
+                mPowerUI.shouldShowLowBatteryWarning(UNPLUGGED, UNPLUGGED, ABOVE_WARNING_BUCKET,
+                        ABOVE_WARNING_BUCKET, BELOW_HYBRID_THRESHOLD,
+                        POWER_SAVER_OFF, BatteryManager.BATTERY_HEALTH_GOOD);
+        assertFalse(shouldShow);
+    }
+
+    @Test
     public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabled() {
         mPowerUI.start();
         when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 45b2118..7ab5812 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -4061,6 +4061,7 @@
         /**
          * Deliver an alarm and set up the post-delivery handling appropriately
          */
+        @GuardedBy("mLock")
         public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) {
             if (alarm.operation != null) {
                 // PendingIntent alarm
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/ForceAppStandbyTracker.java
index 100680d..b65d126 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/ForceAppStandbyTracker.java
@@ -497,6 +497,7 @@
     /**
      * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
      */
+    @GuardedBy("mLock")
     private void refreshForcedAppStandbyUidPackagesLocked() {
         mRunAnyRestrictedPackages.clear();
         final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(
@@ -536,6 +537,7 @@
     /**
      * Update {@link #mForceAllAppsStandby} and notifies the listeners.
      */
+    @GuardedBy("mLock")
     private void toggleForceAllAppsStandbyLocked(boolean enable) {
         if (enable == mForceAllAppsStandby) {
             return;
@@ -545,6 +547,7 @@
         mHandler.notifyForceAllAppsStandbyChanged();
     }
 
+    @GuardedBy("mLock")
     private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
         final int size = mRunAnyRestrictedPackages.size();
         if (size > 8) {
@@ -563,6 +566,7 @@
     /**
      * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
      */
+    @GuardedBy("mLock")
     boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
         return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
     }
@@ -570,6 +574,7 @@
     /**
      * Add to / remove from {@link #mRunAnyRestrictedPackages}.
      */
+    @GuardedBy("mLock")
     boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName,
             boolean restricted) {
         final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 93f7f1d..bdeb231 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -1166,6 +1166,7 @@
             mImePackageAppeared = false;
         }
 
+        @GuardedBy("mMethodMap")
         private boolean shouldRebuildInputMethodListLocked() {
             // This method is guaranteed to be called only by getRegisteredHandler().
 
@@ -1467,6 +1468,7 @@
         setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
     }
 
+    @GuardedBy("mMethodMap")
     private void switchUserLocked(int newUserId) {
         if (DEBUG) Slog.d(TAG, "Switching user stage 1/3. newUserId=" + newUserId
                 + " currentUserId=" + mSettings.getCurrentUserId());
@@ -1817,6 +1819,7 @@
         return flags;
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult attachNewInputLocked(
             /* @InputMethodClient.StartInputReason */ final int startInputReason, boolean initial) {
@@ -1846,6 +1849,7 @@
                 mCurId, mCurSeq, mCurUserActionNotificationSequenceNumber);
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult startInputLocked(
             /* @InputMethodClient.StartInputReason */ final int startInputReason,
@@ -1889,6 +1893,7 @@
                 controlFlags, startInputReason);
     }
 
+    @GuardedBy("mMethodMap")
     @NonNull
     InputBindResult startInputUncheckedLocked(@NonNull ClientState cs, IInputContext inputContext,
             /* @InputConnectionInspector.missingMethods */ final int missingMethods,
@@ -3642,6 +3647,7 @@
         return false;
     }
 
+    @GuardedBy("mMethodMap")
     void buildInputMethodListLocked(boolean resetDefaultEnabledIme) {
         if (DEBUG) {
             Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index f4238f2..42c836e 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -199,6 +199,7 @@
      *            bound.
      * @returns {@code true} if a valid package was found to bind to.
      */
+    @GuardedBy("mLock")
     private boolean bindBestPackageLocked(String justCheckThisPackage, boolean forceRebind) {
         Intent intent = new Intent(mAction);
         if (justCheckThisPackage != null) {
@@ -273,6 +274,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     private void unbindLocked() {
         ComponentName component;
         component = mBoundComponent;
@@ -287,6 +289,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void bindToPackageLocked(ComponentName component, int version, int userId) {
         Intent intent = new Intent(mAction);
         intent.setComponent(component);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 84b93e3..1a0068d 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -809,6 +809,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void addInternalVolumeLocked() {
         // Create a stub volume that represents internal storage
         final VolumeInfo internal = new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL,
@@ -1109,6 +1110,7 @@
         }
     };
 
+    @GuardedBy("mLock")
     private void onDiskScannedLocked(DiskInfo disk) {
         int volumeCount = 0;
         for (int i = 0; i < mVolumes.size(); i++) {
@@ -1134,6 +1136,7 @@
         mCallbacks.notifyDiskScanned(disk, volumeCount);
     }
 
+    @GuardedBy("mLock")
     private void onVolumeCreatedLocked(VolumeInfo vol) {
         if (mPms.isOnlyCoreApps()) {
             Slog.d(TAG, "System booted in core-only mode; ignoring volume " + vol.getId());
@@ -1209,6 +1212,7 @@
         return true;
     }
 
+    @GuardedBy("mLock")
     private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
         // Remember that we saw this volume so we're ready to accept user
         // metadata, or so we can annoy them when a private volume is ejected
@@ -1299,6 +1303,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void onMoveStatusLocked(int status) {
         if (mMoveCallback == null) {
             Slog.w(TAG, "Odd, status but no move requested");
@@ -1515,6 +1520,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void readSettingsLocked() {
         mRecords.clear();
         mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
@@ -1559,6 +1565,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void writeSettingsLocked() {
         FileOutputStream fos = null;
         try {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8d22eca..0baa3d0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -25,7 +25,7 @@
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.input.InputManager;
-import android.hardware.vibrator.V1_0.Constants.EffectStrength;
+import android.hardware.vibrator.V1_0.EffectStrength;
 import android.icu.text.DateFormat;
 import android.media.AudioManager;
 import android.os.PowerManager.ServiceType;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 14404f5..230f69d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1043,20 +1043,14 @@
                         throw new SecurityException("Instant app " + r.appInfo.packageName
                                 + " does not have permission to create foreground services");
                     default:
-                        try {
-                            if (AppGlobals.getPackageManager().checkPermission(
-                                    android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
-                                    r.appInfo.packageName, UserHandle.getUserId(r.appInfo.uid))
-                                            != PackageManager.PERMISSION_GRANTED) {
-                                throw new SecurityException("Instant app " + r.appInfo.packageName
-                                        + " does not have permission to create foreground"
-                                        + "services");
-                            }
-                        } catch (RemoteException e) {
-                            throw new SecurityException("Failed to check instant app permission." ,
-                                    e);
-                        }
+                        mAm.enforcePermission(
+                                android.Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+                                r.app.pid, r.appInfo.uid, "startForeground");
                 }
+            } else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.P) {
+                mAm.enforcePermission(
+                        android.Manifest.permission.FOREGROUND_SERVICE,
+                        r.app.pid, r.appInfo.uid, "startForeground");
             }
             if (r.fgRequired) {
                 if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 220014f..608352b 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -657,6 +657,26 @@
         return false;
     }
 
+    void remove() {
+        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+        while (getChildCount() > 0) {
+            final ActivityStack stack = getChildAt(0);
+            if (destroyContentOnRemoval) {
+                mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
+                        false /* onTop */);
+                stack.finishAllActivitiesLocked(true /* immediately */);
+            } else {
+                // Moving all tasks to fullscreen stack, because it's guaranteed to be
+                // a valid launch stack for all activities. This way the task history from
+                // external display will be preserved on primary after move.
+                mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+            }
+        }
+
+        mWindowContainerController.removeContainer();
+        mWindowContainerController = null;
+    }
+
     /** Update and get all UIDs that are present on the display and have access to it. */
     IntArray getPresentUIDs() {
         mDisplayAccessUIDs.clear();
@@ -666,7 +686,7 @@
         return mDisplayAccessUIDs;
     }
 
-    boolean shouldDestroyContentOnRemove() {
+    private boolean shouldDestroyContentOnRemove() {
         return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cee1ff9..e44223b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3292,6 +3292,7 @@
      * Update AMS states when an activity is resumed. This should only be called by
      * {@link ActivityStack#setResumedActivityLocked} when an activity is resumed.
      */
+    @GuardedBy("this")
     void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
         final TaskRecord task = r.getTask();
         if (task.isActivityTypeStandard()) {
@@ -3817,6 +3818,7 @@
             info.className = entryPoint;
             info.packageName = "android";
             info.seInfoUser = SELinuxUtil.COMPLETE_STR;
+            info.targetSdkVersion = Build.VERSION.SDK_INT;
             ProcessRecord proc = startProcessLocked(processName, info /* info */,
                     false /* knownToBeDead */, 0 /* intentFlags */, ""  /* hostingType */,
                     null /* hostingName */, true /* allowWhileBooting */, true /* isolated */,
@@ -3826,6 +3828,7 @@
         }
     }
 
+    @GuardedBy("this")
     final ProcessRecord startProcessLocked(String processName,
             ApplicationInfo info, boolean knownToBeDead, int intentFlags,
             String hostingType, ComponentName hostingName, boolean allowWhileBooting,
@@ -3836,6 +3839,7 @@
                 null /* crashHandler */);
     }
 
+    @GuardedBy("this")
     final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
             boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
             boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
@@ -3952,6 +3956,7 @@
         return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
     }
 
+    @GuardedBy("this")
     private final void startProcessLocked(ProcessRecord app,
             String hostingType, String hostingNameStr) {
         startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */);
@@ -3960,6 +3965,7 @@
     /**
      * @return {@code true} if process start is successful, false otherwise.
      */
+    @GuardedBy("this")
     private final boolean startProcessLocked(ProcessRecord app, String hostingType,
             String hostingNameStr, String abiOverride) {
         if (app.pendingStart) {
@@ -4084,9 +4090,9 @@
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
             }
 
-            if (app.info.isAllowedToUseHiddenApi() || app.instr != null) {
-                // This app is allowed to use undocumented and private APIs or is
-                // being instrumented. Set up its runtime with the appropriate flag.
+            if (app.info.isAllowedToUseHiddenApi()) {
+                // This app is allowed to use undocumented and private APIs. Set
+                // up its runtime with the appropriate flag.
                 runtimeFlags |= Zygote.DISABLE_HIDDEN_API_CHECKS;
             }
 
@@ -5134,6 +5140,7 @@
                 .supportsLocalVoiceInteraction();
     }
 
+    @GuardedBy("this")
     void onLocalVoiceInteractionStartedLocked(IBinder activity,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
         ActivityRecord activityToCallback = ActivityRecord.forTokenLocked(activity);
@@ -5632,6 +5639,7 @@
      * as a result of that process going away.  Clears out all connections
      * to the process.
      */
+    @GuardedBy("this")
     private final void handleAppDiedLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart) {
         int pid = app.pid;
@@ -5778,10 +5786,12 @@
         }
     }
 
+    @GuardedBy("this")
     final void appDiedLocked(ProcessRecord app) {
        appDiedLocked(app, app.pid, app.thread, false);
     }
 
+    @GuardedBy("this")
     final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
             boolean fromBinderDied) {
         // First check if this ProcessRecord is actually active for the pid.
@@ -6239,6 +6249,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void showLaunchWarningLocked(final ActivityRecord cur, final ActivityRecord next) {
         if (!mLaunchWarningShown) {
             mLaunchWarningShown = true;
@@ -6665,6 +6676,7 @@
         }
     }
 
+    @GuardedBy("this")
     void closeSystemDialogsLocked(String reason) {
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -6771,11 +6783,13 @@
         }
     }
 
+    @GuardedBy("this")
     private void forceStopPackageLocked(final String packageName, int uid, String reason) {
         forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
                 false, true, false, false, UserHandle.getUserId(uid), reason);
     }
 
+    @GuardedBy("this")
     private void finishForceStopPackageLocked(final String packageName, int uid) {
         Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
                 Uri.fromParts("package", packageName, null));
@@ -6791,6 +6805,7 @@
     }
 
 
+    @GuardedBy("this")
     private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
             boolean doit, boolean evenPersistent, String reason) {
@@ -6962,6 +6977,7 @@
         return didSomething;
     }
 
+    @GuardedBy("this")
     final boolean forceStopPackageLocked(String packageName, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, boolean uninstalling, int userId, String reason) {
@@ -7173,6 +7189,7 @@
         }
     }
 
+    @GuardedBy("this")
     boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
@@ -7218,7 +7235,7 @@
             handleAppDiedLocked(app, willRestart, allowRestart);
             if (willRestart) {
                 removeLruProcessLocked(app);
-                addAppLocked(app.info, null, false, null /* ABI override */, app.instr);
+                addAppLocked(app.info, null, false, null /* ABI override */);
             }
         } else {
             mRemovedProcesses.add(app);
@@ -7227,6 +7244,7 @@
         return needRestart;
     }
 
+    @GuardedBy("this")
     private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
         cleanupAppInLaunchingProvidersLocked(app, true);
         removeProcessLocked(app, false, true, "timeout publishing content providers");
@@ -7287,6 +7305,7 @@
         }
     }
 
+    @GuardedBy("this")
     private final boolean attachApplicationLocked(IApplicationThread thread,
             int pid, int callingUid, long startSeq) {
 
@@ -8870,6 +8889,20 @@
     /**
      * This can be called with or without the global lock held.
      */
+    void enforcePermission(String permission, int pid, int uid, String func) {
+        if (checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED) {
+            return;
+        }
+
+        String msg = "Permission Denial: " + func + " from pid=" + pid + ", uid=" + uid
+                + " requires " + permission;
+        Slog.w(TAG, msg);
+        throw new SecurityException(msg);
+    }
+
+    /**
+     * This can be called with or without the global lock held.
+     */
     void enforceCallerIsRecentsOrHasPermission(String permission, String func) {
         if (!mRecentTasks.isCallerRecents(Binder.getCallingUid())) {
             enforceCallingPermission(permission, func);
@@ -9140,6 +9173,7 @@
                 grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId);
     }
 
+    @GuardedBy("this")
     private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
         final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris != null) {
@@ -9148,6 +9182,7 @@
         return null;
     }
 
+    @GuardedBy("this")
     private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
             String targetPkg, int targetUid, GrantUri grantUri) {
         ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
@@ -9165,6 +9200,7 @@
         return perm;
     }
 
+    @GuardedBy("this")
     private final boolean checkUriPermissionLocked(GrantUri grantUri, int uid,
             final int modeFlags) {
         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
@@ -9235,6 +9271,7 @@
      * If you already know the uid of the target, you can supply it in
      * lastTargetUid else set that to -1.
      */
+    @GuardedBy("this")
     int checkGrantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, int lastTargetUid) {
         if (!Intent.isAccessUriMode(modeFlags)) {
@@ -9397,6 +9434,7 @@
         }
     }
 
+    @GuardedBy("this")
     void grantUriPermissionUncheckedLocked(int targetUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner) {
         if (!Intent.isAccessUriMode(modeFlags)) {
@@ -9426,6 +9464,7 @@
         perm.grantModes(modeFlags, owner);
     }
 
+    @GuardedBy("this")
     void grantUriPermissionLocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner, int targetUserId) {
         if (targetPkg == null) {
@@ -9477,6 +9516,7 @@
     /**
      * Like checkGrantUriPermissionLocked, but takes an Intent.
      */
+    @GuardedBy("this")
     NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
@@ -9563,6 +9603,7 @@
     /**
      * Like grantUriPermissionUncheckedLocked, but takes an Intent.
      */
+    @GuardedBy("this")
     void grantUriPermissionUncheckedFromIntentLocked(NeededUriGrants needed,
             UriPermissionOwner owner) {
         if (needed != null) {
@@ -9574,6 +9615,7 @@
         }
     }
 
+    @GuardedBy("this")
     void grantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, UriPermissionOwner owner, int targetUserId) {
         NeededUriGrants needed = checkGrantUriPermissionFromIntentLocked(callingUid, targetPkg,
@@ -9618,6 +9660,7 @@
         }
     }
 
+    @GuardedBy("this")
     void removeUriPermissionIfNeededLocked(UriPermission perm) {
         if (perm.modeFlags == 0) {
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
@@ -9634,6 +9677,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
             final int modeFlags) {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
@@ -9768,6 +9812,7 @@
      * @param targetOnly When {@code true}, only remove permissions where the app is the target,
      * not source.
      */
+    @GuardedBy("this")
     private void removeUriPermissionsForPackageLocked(
             String packageName, int userHandle, boolean persistable, boolean targetOnly) {
         if (userHandle == UserHandle.USER_ALL && packageName == null) {
@@ -9954,6 +9999,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void readGrantedUriPermissionsLocked() {
         if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
 
@@ -10116,6 +10162,7 @@
      *
      * @return if any mutations occured that require persisting.
      */
+    @GuardedBy("this")
     private boolean maybePrunePersistedUriGrantsLocked(int uid) {
         final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
         if (perms == null) return false;
@@ -12490,8 +12537,7 @@
                         .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
                 for (ApplicationInfo app : apps) {
                     if (!"android".equals(app.packageName)) {
-                        addAppLocked(app, null, false, null /* ABI override */,
-                                null /* instrumentation */);
+                        addAppLocked(app, null, false, null /* ABI override */);
                     }
                 }
             } catch (RemoteException ex) {
@@ -12617,6 +12663,7 @@
     // GLOBAL MANAGEMENT
     // =========================================================
 
+    @GuardedBy("this")
     final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
             boolean isolated, int isolatedUid) {
         String proc = customProcess != null ? customProcess : info.processName;
@@ -12706,8 +12753,9 @@
         }
     }
 
+    @GuardedBy("this")
     final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated,
-            String abiOverride, ActiveInstrumentation instrumentation) {
+            String abiOverride) {
         ProcessRecord app;
         if (!isolated) {
             app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName,
@@ -12736,9 +12784,6 @@
             app.persistent = true;
             app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
         }
-
-        app.instr = instrumentation;
-
         if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
             mPersistentStartingProcesses.add(app);
             startProcessLocked(app, "added application",
@@ -12825,6 +12870,7 @@
         }
     }
 
+    @GuardedBy("this")
     void finishRunningVoiceLocked() {
         if (mRunningVoice != null) {
             mRunningVoice = null;
@@ -12840,6 +12886,7 @@
         }
     }
 
+    @GuardedBy("this")
     void updateSleepIfNeededLocked() {
         final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
         final boolean wasSleeping = mSleeping;
@@ -12944,6 +12991,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    @GuardedBy("this")
     void startRunningVoiceLocked(IVoiceInteractionSession session, int targetUid) {
         Slog.d(TAG, "<<<  startRunningVoiceLocked()");
         mVoiceWakeLock.setWorkSource(new WorkSource(targetUid));
@@ -16179,6 +16227,7 @@
         return false;
     }
 
+    @GuardedBy("this")
     void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, int dumpAppId) {
         boolean needSep = false;
@@ -16632,6 +16681,7 @@
         pw.println("  mForceBackgroundCheck=" + mForceBackgroundCheck);
     }
 
+    @GuardedBy("this")
     void writeProcessesToProtoLocked(ProtoOutputStream proto, String dumpPackage) {
         int numPers = 0;
 
@@ -17459,6 +17509,7 @@
         }
     }
 
+    @GuardedBy("this")
     void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
@@ -19531,6 +19582,7 @@
      * @return Returns true if the given process has been restarted, so the
      * app that was passed in must remain on the process lists.
      */
+    @GuardedBy("this")
     private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
             boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
         if (index >= 0) {
@@ -20620,6 +20672,7 @@
         }
     }
 
+    @GuardedBy("this")
     final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
@@ -21543,7 +21596,8 @@
                 mUsageStatsService.reportEvent(ii.targetPackage, userId,
                         UsageEvents.Event.SYSTEM_INTERACTION);
             }
-            ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride, activeInstr);
+            ProcessRecord app = addAppLocked(ai, defProcess, false, abiOverride);
+            app.instr = activeInstr;
             activeInstr.mFinished = false;
             activeInstr.mRunningProcesses.add(app);
             if (!mActiveInstrumentation.contains(activeInstr)) {
@@ -21609,6 +21663,7 @@
         }
     }
 
+    @GuardedBy("this")
     void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
         if (app.instr == null) {
             Slog.w(TAG, "finishInstrumentation called on non-instrumented: " + app);
@@ -21893,7 +21948,7 @@
         }
         try {
             if (values != null) {
-                changes = updateGlobalConfiguration(values, initLocale, persistent, userId,
+                changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId,
                         deferResume);
             }
 
@@ -21911,8 +21966,16 @@
         return kept;
     }
 
+    /**
+     * Returns true if this configuration change is interesting enough to send an
+     * {@link Intent#ACTION_SPLIT_CONFIGURATION_CHANGED} broadcast.
+     */
+    private static boolean isSplitConfigurationChange(int configDiff) {
+        return (configDiff & (ActivityInfo.CONFIG_LOCALE | ActivityInfo.CONFIG_DENSITY)) != 0;
+    }
+
     /** Update default (global) configuration and notify listeners about changes. */
-    private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
+    private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
             boolean persistent, int userId, boolean deferResume) {
         mTempConfig.setTo(getGlobalConfiguration());
         final int changes = mTempConfig.updateFrom(values);
@@ -22015,6 +22078,19 @@
                     UserHandle.USER_ALL);
         }
 
+        // Send a broadcast to PackageInstallers if the configuration change is interesting
+        // for the purposes of installing additional splits.
+        if (!initLocale && isSplitConfigurationChange(changes)) {
+            intent = new Intent(Intent.ACTION_SPLIT_CONFIGURATION_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+
+            // Typically only app stores will have this permission.
+            String[] permissions = new String[] { android.Manifest.permission.INSTALL_PACKAGES };
+            broadcastIntentLocked(null, null, intent, null, null, 0, null, null, permissions,
+                    OP_NONE, null, false, false, MY_PID, SYSTEM_UID, UserHandle.USER_ALL);
+        }
+
         // Override configuration of the default display duplicates global config, so we need to
         // update it also. This will also notify WindowManager about changes.
         performDisplayOverrideConfigUpdate(mStackSupervisor.getConfiguration(), deferResume,
@@ -22087,7 +22163,7 @@
                     // Override configuration of the default display duplicates global config, so
                     // we're calling global config update instead for default display. It will also
                     // apply the correct override config.
-                    changes = updateGlobalConfiguration(values, false /* initLocale */,
+                    changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
                             false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
                 } else {
                     changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
@@ -24007,6 +24083,7 @@
         return applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime());
     }
 
+    @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             boolean oomAdj) {
         if (isForeground != proc.foregroundServices) {
@@ -24076,6 +24153,7 @@
      *                  if necessary, or skip.
      * @return whether updateOomAdjLocked(app) was successful.
      */
+    @GuardedBy("this")
     final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -24100,6 +24178,7 @@
         return success;
     }
 
+    @GuardedBy("this")
     final void updateOomAdjLocked() {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
@@ -24820,6 +24899,7 @@
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
      */
+    @GuardedBy("this")
     void tempWhitelistForPendingIntentLocked(int callerPid, int callerUid, int targetUid,
             long duration, String tag) {
         if (DEBUG_WHITELISTS) {
@@ -24852,6 +24932,7 @@
     /**
      * Whitelists {@code targetUid} to temporarily bypass Power Save mode.
      */
+    @GuardedBy("this")
     void tempWhitelistUidLocked(int targetUid, long duration, String tag) {
         mPendingTempWhitelist.put(targetUid, new PendingTempWhitelist(targetUid, duration, tag));
         setUidTempWhitelistStateLocked(targetUid, true);
@@ -24891,6 +24972,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void setAppIdTempWhitelistStateLocked(int appId, boolean onWhitelist) {
         boolean changed = false;
         for (int i=mActiveUids.size()-1; i>=0; i--) {
@@ -24905,6 +24987,7 @@
         }
     }
 
+    @GuardedBy("this")
     final void setUidTempWhitelistStateLocked(int uid, boolean onWhitelist) {
         boolean changed = false;
         final UidRecord uidRec = mActiveUids.get(uid);
@@ -24942,7 +25025,7 @@
                     mRemovedProcesses.remove(i);
 
                     if (app.persistent) {
-                        addAppLocked(app.info, null, false, null /* ABI override */, app.instr);
+                        addAppLocked(app.info, null, false, null /* ABI override */);
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cae0d2b..9838851 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -133,11 +133,16 @@
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
 import android.app.ResultInfo;
+import android.app.servertransaction.ActivityLifecycleItem;
+import android.app.servertransaction.ActivityRelaunchItem;
+import android.app.servertransaction.ClientTransaction;
+import android.app.servertransaction.ClientTransactionItem;
 import android.app.servertransaction.MoveToDisplayItem;
 import android.app.servertransaction.MultiWindowModeChangeItem;
 import android.app.servertransaction.NewIntentItem;
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.PipModeChangeItem;
+import android.app.servertransaction.ResumeActivityItem;
 import android.app.servertransaction.WindowVisibilityItem;
 import android.app.servertransaction.ActivityConfigurationChangeItem;
 import android.content.ComponentName;
@@ -375,7 +380,8 @@
     }
 
     String getLifecycleDescription(String reason) {
-        return "packageName=" + packageName + ", state=" + state + ", reason=" + reason;
+        return "component:" + intent.getComponent().flattenToShortString() + ", state=" + state
+                + ", reason=" + reason + ", time=" + System.currentTimeMillis();
     }
 
     void dump(PrintWriter pw, String prefix) {
@@ -2370,6 +2376,15 @@
 
         setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig);
 
+        if (state == INITIALIZING) {
+            // No need to relaunch or schedule new config for activity that hasn't been launched
+            // yet. We do, however, return after applying the config to activity record, so that
+            // it will use it for launch transaction.
+            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+                    "Skipping config check for initializing activity: " + this);
+            return true;
+        }
+
         if (changes == 0 && !forceNewConfig) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Configuration no differences in " + this);
@@ -2559,12 +2574,23 @@
                             + " callers=" + Debug.getCallers(6));
             forceNewConfig = false;
             mStackSupervisor.activityRelaunchingLocked(this);
-            app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
-                    configChangeFlags, !andResume,
-                    new Configuration(service.getGlobalConfiguration()),
-                    new Configuration(getMergedOverrideConfiguration()), preserveWindow);
+            final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults,
+                    pendingNewIntents, configChangeFlags,
+                    new MergedConfiguration(service.getGlobalConfiguration(),
+                            getMergedOverrideConfiguration()),
+                    preserveWindow);
+            final ActivityLifecycleItem lifecycleItem;
+            if (andResume) {
+                lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
+            } else {
+                lifecycleItem = PauseActivityItem.obtain();
+            }
+            final ClientTransaction transaction = ClientTransaction.obtain(app.thread, appToken);
+            transaction.addCallback(callbackItem);
+            transaction.setLifecycleStateRequest(lifecycleItem);
+            service.mLifecycleManager.scheduleTransaction(transaction);
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
-            // pass in 'andResume' if this activity is currently resumed, which implies we aren't
+            // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
         } catch (RemoteException e) {
             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ab2dc36..055a1aa 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -138,6 +138,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.BatteryStatsImpl;
@@ -2211,6 +2212,7 @@
      *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
      *       right activity for the current system state.
      */
+    @GuardedBy("mService")
     boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
         if (mStackSupervisor.inResumeTopActivity) {
             // Don't even start recursing.
@@ -2250,6 +2252,7 @@
         mStackSupervisor.mRecentTasks.add(r.getTask());
     }
 
+    @GuardedBy("mService")
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
@@ -4214,7 +4217,8 @@
                 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
                 mService.mLifecycleManager.scheduleTransaction(r.app.thread, r.appToken,
                         DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)
-                            .setDescription(r.getLifecycleDescription("destroyActivityLocked")));
+                            .setDescription(
+                                    r.getLifecycleDescription("destroyActivityLocked:" + reason)));
             } catch (Exception e) {
                 // We can just ignore exceptions here...  if the process
                 // has crashed, our death notification will clean things
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index a0f31cd..4928e90 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -166,6 +166,7 @@
 import android.view.Display;
 import android.view.RemoteAnimationAdapter;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.ReferrerIntent;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
@@ -1508,6 +1509,8 @@
             Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
         }
 
+        // TODO(lifecycler): Resume or pause requests are done as part of launch transaction,
+        // so updating the state should be done accordingly.
         if (andResume && readyToResume()) {
             // As part of the process of launching, ActivityThread also performs
             // a resume.
@@ -1858,6 +1861,7 @@
      * Called when the frontmost task is idle.
      * @return the state of mService.mBooting before this was called.
      */
+    @GuardedBy("mService")
     private boolean checkFinishBootingLocked() {
         final boolean booting = mService.mBooting;
         boolean enableScreen = false;
@@ -1873,6 +1877,7 @@
     }
 
     // Checked.
+    @GuardedBy("mService")
     final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
             boolean processPausingActivities, Configuration config) {
         if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
@@ -4087,25 +4092,12 @@
             if (activityDisplay == null) {
                 return;
             }
-            final boolean destroyContentOnRemoval
-                    = activityDisplay.shouldDestroyContentOnRemove();
-            while (activityDisplay.getChildCount() > 0) {
-                final ActivityStack stack = activityDisplay.getChildAt(0);
-                if (destroyContentOnRemoval) {
-                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */);
-                    stack.finishAllActivitiesLocked(true /* immediately */);
-                } else {
-                    // Moving all tasks to fullscreen stack, because it's guaranteed to be
-                    // a valid launch stack for all activities. This way the task history from
-                    // external display will be preserved on primary after move.
-                    moveTasksToFullscreenStackLocked(stack, true /* onTop */);
-                }
-            }
+
+            activityDisplay.remove();
 
             releaseSleepTokens(activityDisplay);
 
             mActivityDisplays.remove(displayId);
-            mWindowManager.onDisplayRemoved(displayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 927b72c..ef82f36 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -182,6 +182,7 @@
         mExecutorService.shutdownNow();
     }
 
+    @GuardedBy("this")
     private Future<?> scheduleSyncLocked(String reason, int flags) {
         if (mExecutorService.isShutdown()) {
             return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
@@ -248,6 +249,7 @@
         }
     };
 
+    @GuardedBy("mWorkerLock")
     private void updateExternalStatsLocked(final String reason, int updateFlags) {
         // We will request data from external processes asynchronously, and wait on a timeout.
         SynchronousResultReceiver wifiReceiver = null;
@@ -372,6 +374,7 @@
         return null;
     }
 
+    @GuardedBy("mWorkerLock")
     private WifiActivityEnergyInfo extractDeltaLocked(WifiActivityEnergyInfo latest) {
         final long timePeriodMs = latest.mTimestamp - mLastInfo.mTimestamp;
         final long lastScanMs = mLastInfo.mControllerScanTimeMs;
diff --git a/services/core/java/com/android/server/am/PersistentConnection.java b/services/core/java/com/android/server/am/PersistentConnection.java
index 52eaca1..c5edb26 100644
--- a/services/core/java/com/android/server/am/PersistentConnection.java
+++ b/services/core/java/com/android/server/am/PersistentConnection.java
@@ -220,6 +220,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     public final void bindInnerLocked(boolean resetBackoff) {
         unscheduleRebindLocked();
 
@@ -260,6 +261,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void cleanUpConnectionLocked() {
         mIsConnected = false;
         mService = null;
@@ -276,6 +278,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private final void unbindLocked() {
         unscheduleRebindLocked();
 
@@ -289,11 +292,13 @@
         cleanUpConnectionLocked();
     }
 
+    @GuardedBy("mLock")
     void unscheduleRebindLocked() {
         injectRemoveCallbacks(mBindForBackoffRunnable);
         mRebindScheduled = false;
     }
 
+    @GuardedBy("mLock")
     void scheduleRebindLocked() {
         unbindLocked();
 
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index edf565a..c10d81b 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -135,6 +135,7 @@
         return mMemFactorLowered;
     }
 
+    @GuardedBy("mAm")
     public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
         mMemFactorLowered = memFactor < mLastMemOnlyState;
         mLastMemOnlyState = memFactor;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8635cff..e95608f 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -285,7 +285,7 @@
     private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
 
    /** Maximum volume index values for audio streams */
-    private static int[] MAX_STREAM_VOLUME = new int[] {
+    protected static int[] MAX_STREAM_VOLUME = new int[] {
         5,  // STREAM_VOICE_CALL
         7,  // STREAM_SYSTEM
         7,  // STREAM_RING
@@ -300,7 +300,7 @@
     };
 
     /** Minimum volume index values for audio streams */
-    private static int[] MIN_STREAM_VOLUME = new int[] {
+    protected static int[] MIN_STREAM_VOLUME = new int[] {
         1,  // STREAM_VOICE_CALL
         0,  // STREAM_SYSTEM
         0,  // STREAM_RING
@@ -1410,7 +1410,7 @@
                 Binder.getCallingUid());
     }
 
-    private void adjustStreamVolume(int streamType, int direction, int flags,
+    protected void adjustStreamVolume(int streamType, int direction, int flags,
             String callingPackage, String caller, int uid) {
         if (mUseFixedVolume) {
             return;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 1ee0548..c3f020a 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1116,6 +1116,7 @@
         return (pi != null) ? pi.packageName : null;
     }
 
+    @GuardedBy("mCache")
     private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
             String providerPackageName) {
         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
@@ -1131,6 +1132,7 @@
         return packageCache;
     }
 
+    @GuardedBy("mCache")
     private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
         if (userCache == null) return;
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index 75c0181..20aec7e 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -194,6 +194,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void openLogLocked(long now) {
             // If we already have a log file opened and the date has't changed, just use it.
             final long day = now % DateUtils.DAY_IN_MILLIS;
@@ -219,6 +220,7 @@
             }
         }
 
+        @GuardedBy("mLock")
         private void closeCurrentLogLocked() {
             IoUtils.closeQuietly(mLogWriter);
             mLogWriter = null;
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 6b4666a..524de91 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -115,12 +115,10 @@
             = new RingBuffer<>(BrightnessChangeEvent.class, MAX_EVENTS);
     @GuardedBy("mEventsLock")
     private boolean mEventsDirty;
-    private final Runnable mEventsWriter = () -> writeEvents();
-    private volatile boolean mWriteEventsScheduled;
+
+    private volatile boolean mWriteBrightnessTrackerStateScheduled;
 
     private AmbientBrightnessStatsTracker mAmbientBrightnessStatsTracker;
-    private final Runnable mAmbientBrightnessStatsWriter = () -> writeAmbientBrightnessStats();
-    private volatile boolean mWriteBrightnessStatsScheduled;
 
     private UserManager mUserManager;
     private final Context mContext;
@@ -167,13 +165,7 @@
         }
         mBgHandler = new TrackerHandler(mInjector.getBackgroundHandler().getLooper());
         mUserManager = mContext.getSystemService(UserManager.class);
-        try {
-            final ActivityManager.StackInfo focusedStack = mInjector.getFocusedStack();
-            mCurrentUserId = focusedStack.userId;
-        } catch (RemoteException e) {
-            // Really shouldn't be possible.
-            return;
-        }
+        mCurrentUserId = ActivityManager.getCurrentUser();
         mBgHandler.obtainMessage(MSG_BACKGROUND_START, (Float) initialBrightness).sendToTarget();
     }
 
@@ -355,18 +347,17 @@
     }
 
     private void scheduleWriteBrightnessTrackerState() {
-        if (!mWriteEventsScheduled) {
-            mBgHandler.post(mEventsWriter);
-            mWriteEventsScheduled = true;
-        }
-        if (!mWriteBrightnessStatsScheduled) {
-            mBgHandler.post(mAmbientBrightnessStatsWriter);
-            mWriteBrightnessStatsScheduled = true;
+        if (!mWriteBrightnessTrackerStateScheduled) {
+            mBgHandler.post(() -> {
+                mWriteBrightnessTrackerStateScheduled = false;
+                writeEvents();
+                writeAmbientBrightnessStats();
+            });
+            mWriteBrightnessTrackerStateScheduled = true;
         }
     }
 
     private void writeEvents() {
-        mWriteEventsScheduled = false;
         synchronized (mEventsLock) {
             if (!mEventsDirty) {
                 // Nothing to write
@@ -398,7 +389,6 @@
     }
 
     private void writeAmbientBrightnessStats() {
-        mWriteBrightnessStatsScheduled = false;
         final AtomicFile writeTo = mInjector.getFile(AMBIENT_BRIGHTNESS_STATS_FILE);
         if (writeTo == null) {
             return;
@@ -642,6 +632,7 @@
             }
         }
         if (mAmbientBrightnessStatsTracker != null) {
+            pw.println();
             mAmbientBrightnessStatsTracker.dump(pw);
         }
     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index b27f1ec..23de592 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -51,7 +51,6 @@
 import android.provider.Settings;
 import android.util.MathUtils;
 import android.util.Slog;
-import android.util.Spline;
 import android.util.TimeUtils;
 import android.view.Display;
 
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
index 0976a22..b0cde2d 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintsUserState.java
@@ -202,6 +202,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void readStateSyncLocked() {
         FileInputStream in;
         if (!mFile.exists()) {
@@ -226,6 +227,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void parseStateLocked(XmlPullParser parser)
             throws IOException, XmlPullParserException {
         final int outerDepth = parser.getDepth();
@@ -243,6 +245,7 @@
         }
     }
 
+    @GuardedBy("this")
     private void parseFingerprintsLocked(XmlPullParser parser)
             throws IOException, XmlPullParserException {
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 1e09383..de0f298 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1299,6 +1299,7 @@
     /**
      * Return external input devices.
      */
+    @GuardedBy("mLock")
     List<HdmiDeviceInfo> getSafeExternalInputsLocked() {
         return mSafeExternalInputs;
     }
@@ -1421,6 +1422,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
         ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
         for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 3d079cc..b06dba9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1097,6 +1097,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private List<HdmiDeviceInfo> getMhlDevicesLocked() {
         return mMhlDevices;
     }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 37b3990..4988974 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -295,10 +295,12 @@
     }
 
     /** Called externally when a job that was scheduled for execution should be cancelled. */
+    @GuardedBy("mLock")
     void cancelExecutingJobLocked(int reason, String debugReason) {
         doCancelLocked(reason, debugReason);
     }
 
+    @GuardedBy("mLock")
     void preemptExecutingJobLocked() {
         doCancelLocked(JobParameters.REASON_PREEMPT, "cancelled due to preemption");
     }
@@ -319,6 +321,7 @@
         return mTimeoutElapsed;
     }
 
+    @GuardedBy("mLock")
     boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId,
             String reason) {
         final JobStatus executing = getRunningJobLocked();
@@ -512,6 +515,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doServiceBoundLocked() {
         removeOpTimeOutLocked();
         handleServiceBoundLocked();
@@ -531,6 +535,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doCallbackLocked(boolean reschedule, String reason) {
         if (DEBUG) {
             Slog.d(TAG, "doCallback of : " + mRunningJob
@@ -550,6 +555,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     void doCancelLocked(int arg1, String debugReason) {
         if (mVerb == VERB_FINISHED) {
             if (DEBUG) {
@@ -567,6 +573,7 @@
     }
 
     /** Start the job on the service. */
+    @GuardedBy("mLock")
     private void handleServiceBoundLocked() {
         if (DEBUG) {
             Slog.d(TAG, "handleServiceBound for " + getRunningJobNameLocked());
@@ -605,6 +612,7 @@
      *     _EXECUTING  -> Error
      *     _STOPPING   -> Error
      */
+    @GuardedBy("mLock")
     private void handleStartedLocked(boolean workOngoing) {
         switch (mVerb) {
             case VERB_STARTING:
@@ -637,6 +645,7 @@
      *     _STARTING   -> Error
      *     _PENDING    -> Error
      */
+    @GuardedBy("mLock")
     private void handleFinishedLocked(boolean reschedule, String reason) {
         switch (mVerb) {
             case VERB_EXECUTING:
@@ -659,6 +668,7 @@
      *                      in the message queue.
      *     _ENDING     -> No point in doing anything here, so we ignore.
      */
+    @GuardedBy("mLock")
     private void handleCancelLocked(String reason) {
         if (JobSchedulerService.DEBUG) {
             Slog.d(TAG, "Handling cancel for: " + mRunningJob.getJobId() + " "
@@ -683,6 +693,7 @@
     }
 
     /** Process MSG_TIMEOUT here. */
+    @GuardedBy("mLock")
     private void handleOpTimeoutLocked() {
         switch (mVerb) {
             case VERB_BINDING:
@@ -722,6 +733,7 @@
      * Already running, need to stop. Will switch {@link #mVerb} from VERB_EXECUTING ->
      * VERB_STOPPING.
      */
+    @GuardedBy("mLock")
     private void sendStopMessageLocked(String reason) {
         removeOpTimeOutLocked();
         if (mVerb != VERB_EXECUTING) {
@@ -747,6 +759,7 @@
      * or from acknowledging the stop message we sent. Either way, we're done tracking it and
      * we want to clean up internally.
      */
+    @GuardedBy("mLock")
     private void closeAndCleanupJobLocked(boolean reschedule, String reason) {
         final JobStatus completedJob;
         if (mVerb == VERB_FINISHED) {
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 13873e4..77e813e 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -92,6 +92,7 @@
         mNetPolicyManager.registerListener(mNetPolicyListener);
     }
 
+    @GuardedBy("mLock")
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
         if (jobStatus.hasConnectivityConstraint()) {
@@ -101,6 +102,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
             boolean forUpdate) {
@@ -325,6 +327,7 @@
         }
     };
 
+    @GuardedBy("mLock")
     @Override
     public void dumpControllerStateLocked(PrintWriter pw, int filterUid) {
         pw.print("Connectivity: connected=");
@@ -348,6 +351,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Override
     public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, int filterUid) {
         final long token = proto.start(fieldId);
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 7881a95..648c782 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -289,6 +289,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void sendAudioPlayerActiveStateChangedMessageLocked(
             final AudioPlaybackConfiguration config, final boolean isRemoved) {
         for (MessageHandler messageHandler : mListenerMap.values()) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index a17dd12..f346629 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -4678,10 +4678,12 @@
         return subId;
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private int getSubIdLocked(Network network) {
         return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
     }
 
+    @GuardedBy("mNetworkPoliciesSecondLock")
     private SubscriptionPlan getPrimarySubscriptionPlanLocked(int subId) {
         final SubscriptionPlan[] plans = mSubscriptionPlans.get(subId);
         return ArrayUtils.isEmpty(plans) ? null : plans[0];
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 961a451..3cc4d83 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -187,6 +187,7 @@
      */
     @VisibleForTesting
     public static long multiplySafe(long value, long num, long den) {
+        if (den == 0) den = 1;
         long x = value;
         long y = num;
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index bfc150e..76c4db1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -405,6 +405,7 @@
                 mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags);
     }
 
+    @GuardedBy("mStatsLock")
     private void shutdownLocked() {
         mContext.unregisterReceiver(mTetherReceiver);
         mContext.unregisterReceiver(mPollReceiver);
@@ -431,6 +432,7 @@
         mSystemReady = false;
     }
 
+    @GuardedBy("mStatsLock")
     private void maybeUpgradeLegacyStatsLocked() {
         File file;
         try {
@@ -909,6 +911,7 @@
      * reflect current {@link #mPersistThreshold} value. Always defers to
      * {@link Global} values when defined.
      */
+    @GuardedBy("mStatsLock")
     private void updatePersistThresholdsLocked() {
         mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold));
         mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold));
@@ -1029,6 +1032,7 @@
      * are active on a single {@code iface}, they are combined under a single
      * {@link NetworkIdentitySet}.
      */
+    @GuardedBy("mStatsLock")
     private void updateIfacesLocked(Network[] defaultNetworks) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "updateIfacesLocked()");
@@ -1128,6 +1132,7 @@
         return ident;
     }
 
+    @GuardedBy("mStatsLock")
     private void recordSnapshotLocked(long currentTime) throws RemoteException {
         // snapshot and record current counters; read UID stats first to
         // avoid over counting dev stats.
@@ -1163,6 +1168,7 @@
      * Bootstrap initial stats snapshot, usually during {@link #systemReady()}
      * so we have baseline values without double-counting.
      */
+    @GuardedBy("mStatsLock")
     private void bootstrapStatsLocked() {
         final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
                 : System.currentTimeMillis();
@@ -1197,6 +1203,7 @@
      * Periodic poll operation, reading current statistics and recording into
      * {@link NetworkStatsHistory}.
      */
+    @GuardedBy("mStatsLock")
     private void performPollLocked(int flags) {
         if (!mSystemReady) return;
         if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")");
@@ -1258,6 +1265,7 @@
     /**
      * Sample recent statistics summary into {@link EventLog}.
      */
+    @GuardedBy("mStatsLock")
     private void performSampleLocked() {
         // TODO: migrate trustedtime fixes to separate binary log events
         final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
@@ -1295,6 +1303,7 @@
     /**
      * Clean up {@link #mUidRecorder} after UID is removed.
      */
+    @GuardedBy("mStatsLock")
     private void removeUidsLocked(int... uids) {
         if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids));
 
@@ -1313,6 +1322,7 @@
     /**
      * Clean up {@link #mUidRecorder} after user is removed.
      */
+    @GuardedBy("mStatsLock")
     private void removeUserLocked(int userId) {
         if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId);
 
@@ -1434,6 +1444,7 @@
         }
     }
 
+    @GuardedBy("mStatsLock")
     private void dumpProtoLocked(FileDescriptor fd) {
         final ProtoOutputStream proto = new ProtoOutputStream(fd);
 
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index 81fe641..e8b39c0 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -22,12 +22,14 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.DropBoxManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -238,20 +240,34 @@
      * if an app is really visited C&C site.
      * (2) App digests that previously recorded in database.
      */
-    private List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
+    @VisibleForTesting
+    List<String> getAllDigestsForReport(WatchlistReportDbHelper.AggregatedResult record) {
         // Step 1: Get all installed application digests.
+        final List<UserInfo> users = ((UserManager) mContext.getSystemService(
+                Context.USER_SERVICE)).getUsers();
+        final int totalUsers = users.size();
         final List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(
                 PackageManager.MATCH_ANY_USER | PackageManager.MATCH_ALL);
         final HashSet<String> result = new HashSet<>(apps.size() + record.appDigestCNCList.size());
         final int size = apps.size();
         for (int i = 0; i < size; i++) {
-            byte[] digest = getDigestFromUid(apps.get(i).uid);
-            if (digest == null) {
+            final int appUid = apps.get(i).uid;
+            boolean added = false;
+            // As the uid returned by getInstalledApplications() is for primary user only, it
+            // may exist in secondary users but not primary user, so we need to loop and see if
+            // that user has the app enabled.
+            for (int j = 0; j < totalUsers && !added; j++) {
+                int uid = UserHandle.getUid(users.get(j).id, appUid);
+                byte[] digest = getDigestFromUid(uid);
+                if (digest != null) {
+                    result.add(HexDump.toHexString(digest));
+                    added = true;
+                }
+            }
+            if (!added) {
                 Slog.e(TAG, "Cannot get digest from uid: " + apps.get(i).uid
                         + ",pkg: " + apps.get(i).packageName);
-                continue;
             }
-            result.add(HexDump.toHexString(digest));
         }
         // Step 2: Add all digests from records
         result.addAll(record.appDigestCNCList.keySet());
@@ -288,9 +304,9 @@
                         return null;
                     }
                 }
-            } else {
-                Slog.e(TAG, "Should not happen");
             }
+            // Not able to find a package name for this uid, possibly the package is installed on
+            // another user.
             return null;
         });
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ada002c..3800017 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -686,6 +686,7 @@
                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
                         REASON_CLICK, null);
+                reportUserInteraction(r);
             }
         }
 
@@ -706,7 +707,7 @@
                         .setSubtype(actionIndex));
                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
-                // TODO: Log action click via UsageStats.
+                reportUserInteraction(r);
             }
         }
 
@@ -827,6 +828,7 @@
                 NotificationRecord r = mNotificationsByKey.get(key);
                 if (r != null) {
                     r.recordDirectReplied();
+                    reportUserInteraction(r);
                 }
             }
         }
@@ -1758,6 +1760,10 @@
         return INotificationManager.Stub.asInterface(mService);
     }
 
+    /**
+     * Report to usage stats that the notification was seen.
+     * @param r notification record
+     */
     protected void reportSeen(NotificationRecord r) {
         final int userId = r.sbn.getUserId();
         mAppUsageStats.reportEvent(r.sbn.getPackageName(),
@@ -1766,6 +1772,17 @@
                 UsageEvents.Event.NOTIFICATION_SEEN);
     }
 
+    /**
+     * Report to usage stats that the notification was clicked.
+     * @param r notification record
+     */
+    protected void reportUserInteraction(NotificationRecord r) {
+        final int userId = r.sbn.getUserId();
+        mAppUsageStats.reportEvent(r.sbn.getPackageName(),
+                userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
+                UsageEvents.Event.USER_INTERACTION);
+    }
+
     @VisibleForTesting
     NotificationManagerInternal getInternalService() {
         return mInternalService;
@@ -3909,6 +3926,7 @@
         return true;
     }
 
+    @GuardedBy("mNotificationLock")
     protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
             String excludedTag) {
         int count = 0;
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 30088dd..fb81ebf 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -274,7 +274,7 @@
             }
 
             // Propagate permissions before removing any state
-            propagateInstantAppPermissionsIfNeeded(pkg.packageName, userId);
+            propagateInstantAppPermissionsIfNeeded(pkg, userId);
 
             // Track instant apps
             if (ps.getInstantApp(userId)) {
@@ -869,10 +869,10 @@
         return uninstalledApps;
     }
 
-    private void propagateInstantAppPermissionsIfNeeded(@NonNull String packageName,
+    private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
             @UserIdInt int userId) {
         InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
-                packageName, userId);
+                pkg.packageName, userId);
         if (appInfo == null) {
             return;
         }
@@ -884,8 +884,8 @@
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
                 final boolean propagatePermission =
                         mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
-                if (propagatePermission) {
-                    mService.grantRuntimePermission(packageName, grantedPermission, userId);
+                if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
+                    mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index a9ee411..98f421e 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -141,6 +141,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void waitForBindLocked(String token) throws TimeoutException, InterruptedException {
         final long startMillis = SystemClock.uptimeMillis();
         while (mBindState != STATE_IDLE) {
@@ -250,6 +251,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void handleBinderDiedLocked() {
         if (mRemoteInstance != null) {
             try {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 59f9dae..0b32d1a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -226,6 +226,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) {
         final File stagingDir = buildStagingDir(volumeUuid, isEphemeral);
         final ArraySet<File> unclaimedStages = newArraySet(
@@ -283,6 +284,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void readSessionsLocked() {
         if (LOGD) Slog.v(TAG, "readSessionsLocked()");
 
@@ -340,6 +342,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private void addHistoricalSessionLocked(PackageInstallerSession session) {
         CharArrayWriter writer = new CharArrayWriter();
         IndentingPrintWriter pw = new IndentingPrintWriter(writer, "    ");
@@ -352,6 +355,7 @@
                 mHistoricalSessionsByInstaller.get(installerUid) + 1);
     }
 
+    @GuardedBy("mSessions")
     private void writeSessionsLocked() {
         if (LOGD) Slog.v(TAG, "writeSessionsLocked()");
 
@@ -612,6 +616,7 @@
         }
     }
 
+    @GuardedBy("mSessions")
     private int allocateSessionIdLocked() {
         int n = 0;
         int sessionId;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 3dd5a34..9c69281 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -318,6 +318,7 @@
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
+    @GuardedBy("mLock")
     private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() {
         DevicePolicyManagerInternal dpmi =
                 LocalServices.getService(DevicePolicyManagerInternal.class);
@@ -334,6 +335,7 @@
      *
      * @return {@code true} iff we need to ask to confirm the permissions?
      */
+    @GuardedBy("mLock")
     private boolean needToAskForPermissionsLocked() {
         if (mPermissionsManuallyAccepted) {
             return false;
@@ -456,6 +458,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotSealedLocked(String cookie) {
         assertPreparedAndNotCommittedOrDestroyedLocked(cookie);
         if (mSealed) {
@@ -463,6 +466,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotCommittedOrDestroyedLocked(String cookie) {
         assertPreparedAndNotDestroyedLocked(cookie);
         if (mCommitted) {
@@ -470,6 +474,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertPreparedAndNotDestroyedLocked(String cookie) {
         if (!mPrepared) {
             throw new IllegalStateException(cookie + " before prepared");
@@ -484,6 +489,7 @@
      * might point at an ASEC mount point, which is why we delay path resolution
      * until someone actively works with the session.
      */
+    @GuardedBy("mLock")
     private File resolveStageDirLocked() throws IOException {
         if (mResolvedStageDir == null) {
             if (stageDir != null) {
@@ -516,6 +522,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void computeProgressLocked(boolean forcePublish) {
         mProgress = MathUtils.constrain(mClientProgress * 0.8f, 0f, 0.8f)
                 + MathUtils.constrain(mInternalProgress * 0.2f, 0f, 0.2f);
@@ -728,6 +735,7 @@
      * Check if the caller is the owner of this session. Otherwise throw a
      * {@link SecurityException}.
      */
+    @GuardedBy("mLock")
     private void assertCallerIsOwnerOrRootLocked() {
         final int callingUid = Binder.getCallingUid();
         if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid) {
@@ -738,6 +746,7 @@
     /**
      * If anybody is reading or writing data of the session, throw an {@link SecurityException}.
      */
+    @GuardedBy("mLock")
     private void assertNoWriteFileTransfersOpenLocked() {
         // Verify that all writers are hands-off
         for (RevocableFileDescriptor fd : mFds) {
@@ -820,6 +829,7 @@
      * @throws PackageManagerException if the session was sealed but something went wrong. If the
      *                                 session was sealed this is the only possible exception.
      */
+    @GuardedBy("mLock")
     private void sealAndValidateLocked() throws PackageManagerException, IOException {
         assertNoWriteFileTransfersOpenLocked();
         assertPreparedAndNotDestroyedLocked("sealing of session");
@@ -901,6 +911,7 @@
         mCallback.onSessionSealedBlocking(this);
     }
 
+    @GuardedBy("mLock")
     private void commitLocked()
             throws PackageManagerException {
         if (mDestroyed) {
@@ -1016,6 +1027,7 @@
      * Note that upgrade compatibility is still performed by
      * {@link PackageManagerService}.
      */
+    @GuardedBy("mLock")
     private void validateInstallLocked(@Nullable PackageInfo pkgInfo)
             throws PackageManagerException {
         mPackageName = null;
@@ -1228,6 +1240,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void assertApkConsistentLocked(String tag, ApkLite apk)
             throws PackageManagerException {
         if (!mPackageName.equals(apk.packageName)) {
@@ -1511,6 +1524,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void dumpLocked(IndentingPrintWriter pw) {
         pw.println("Session " + sessionId + ":");
         pw.increaseIndent();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 25960c8..384b074 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -797,6 +797,7 @@
             return overlayPackages;
         }
 
+        @GuardedBy("mInstallLock")
         final String[] getStaticOverlayPathsLocked(Collection<PackageParser.Package> allPackages,
                 String targetPackageName, String targetPath) {
             if ("android".equals(targetPackageName)) {
@@ -9015,6 +9016,7 @@
         }
     }
 
+    @GuardedBy("mPackages")
     private void notifyPackageUseLocked(String packageName, int reason) {
         final PackageParser.Package p = mPackages.get(packageName);
         if (p == null) {
@@ -13954,6 +13956,7 @@
         }
     }
 
+    @GuardedBy("mPackages")
     private boolean canSuspendPackageForUserLocked(String packageName, int userId) {
         if (isPackageDeviceAdmin(packageName, userId)) {
             Slog.w(TAG, "Cannot suspend/un-suspend package \"" + packageName
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a85d6d8..034fd23 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -530,6 +530,7 @@
         return processState <= PROCESS_STATE_FOREGROUND_THRESHOLD;
     }
 
+    @GuardedBy("mLock")
     boolean isUidForegroundLocked(int uid) {
         if (uid == Process.SYSTEM_UID) {
             // IUidObserver doesn't report the state of SYSTEM, but it always has bound services,
@@ -545,6 +546,7 @@
         return isProcessStateForeground(mActivityManagerInternal.getUidProcessState(uid));
     }
 
+    @GuardedBy("mLock")
     long getUidLastForegroundElapsedTimeLocked(int uid) {
         return mUidLastForegroundElapsedTime.get(uid);
     }
@@ -638,6 +640,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void unloadUserLocked(int userId) {
         if (DEBUG) {
             Slog.d(TAG, "unloadUserLocked: user=" + userId);
@@ -864,6 +867,7 @@
         writeAttr(out, name, intent.toUri(/* flags =*/ 0));
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     void saveBaseStateLocked() {
         final AtomicFile file = getBaseStateFile();
@@ -896,6 +900,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void loadBaseStateLocked() {
         mRawLastResetTime = 0;
 
@@ -948,6 +953,7 @@
         return new File(injectUserDataPath(userId), FILENAME_USER_PACKAGES);
     }
 
+    @GuardedBy("mLock")
     private void saveUserLocked(@UserIdInt int userId) {
         final File path = getUserFile(userId);
         if (DEBUG) {
@@ -974,6 +980,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void saveUserInternalLocked(@UserIdInt int userId, OutputStream os,
             boolean forBackup) throws IOException, XmlPullParserException {
 
@@ -1107,12 +1114,14 @@
     }
 
     /** Return the last reset time. */
+    @GuardedBy("mLock")
     long getLastResetTimeLocked() {
         updateTimesLocked();
         return mRawLastResetTime;
     }
 
     /** Return the next reset time. */
+    @GuardedBy("mLock")
     long getNextResetTimeLocked() {
         updateTimesLocked();
         return mRawLastResetTime + mResetInterval;
@@ -1125,6 +1134,7 @@
     /**
      * Update the last reset time.
      */
+    @GuardedBy("mLock")
     private void updateTimesLocked() {
 
         final long now = injectCurrentTimeMillis();
@@ -1220,6 +1230,7 @@
         return ret;
     }
 
+    @GuardedBy("mLock")
     void forEachLoadedUserLocked(@NonNull Consumer<ShortcutUser> c) {
         for (int i = mUsers.size() - 1; i >= 0; i--) {
             c.accept(mUsers.valueAt(i));
@@ -1279,6 +1290,7 @@
      * {@link ShortcutBitmapSaver#waitForAllSavesLocked()} to make sure there's no pending bitmap
      * saves are going on.
      */
+    @GuardedBy("mLock")
     private void cleanupDanglingBitmapDirectoriesLocked(@UserIdInt int userId) {
         if (DEBUG) {
             Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
@@ -2108,6 +2120,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName,
             @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> query) {
 
@@ -2418,6 +2431,7 @@
      *
      * This is called when an app is uninstalled, or an app gets "clear data"ed.
      */
+    @GuardedBy("mLock")
     @VisibleForTesting
     void cleanUpPackageLocked(String packageName, int owningUserId, int packageUserId,
             boolean appStillExists) {
@@ -2508,6 +2522,7 @@
             return setReturnedByServer(ret);
         }
 
+        @GuardedBy("ShortcutService.this.mLock")
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
                 @Nullable String packageName, @Nullable List<String> shortcutIds, long changedSince,
                 @Nullable ComponentName componentName, int queryFlags,
@@ -2579,6 +2594,7 @@
             }
         }
 
+        @GuardedBy("ShortcutService.this.mLock")
         private ShortcutInfo getShortcutInfoLocked(
                 int launcherUserId, @NonNull String callingPackage,
                 @NonNull String packageName, @NonNull String shortcutId, int userId,
@@ -2940,6 +2956,7 @@
         verifyStates();
     }
 
+    @GuardedBy("mLock")
     private void rescanUpdatedPackagesLocked(@UserIdInt int userId, long lastScanTime) {
         final ShortcutUser user = getUserShortcutsLocked(userId);
 
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b53d83b..a0577b1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1547,6 +1547,7 @@
         return result;
     }
 
+    @GuardedBy("mRestrictionsLock")
     private EnforcingUser getEnforcingUserLocked(@UserIdInt int userId) {
         int source = mDeviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER
                 : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
@@ -2896,6 +2897,7 @@
         }
     }
 
+    @GuardedBy("mUsersLock")
     @VisibleForTesting
     void addRemovingUserIdLocked(int userId) {
         // We remember deleted user IDs to prevent them from being
@@ -3405,6 +3407,7 @@
         return nextId;
     }
 
+    @GuardedBy("mUsersLock")
     private int scanNextAvailableIdLocked() {
         for (int i = MIN_USER_ID; i < MAX_USER_ID; i++) {
             if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 08f8bbd..3f8a1e8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1210,6 +1210,7 @@
         return false;
     }
 
+    @GuardedBy("mLock")
     private void grantRuntimePermissionsGrantedToDisabledPackageLocked(
             PackageParser.Package pkg, int callingUid, PermissionCallback callback) {
         if (pkg.parentPackage == null) {
@@ -1499,6 +1500,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private int[] revokeUnusedSharedUserPermissionsLocked(
             SharedUserSetting suSetting, int[] allUserIds) {
         // Collect all used permissions in the UID
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index f6c4990..b3f2833 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -201,34 +201,42 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Nullable BasePermission getPermissionLocked(@NonNull String permName) {
         return mPermissions.get(permName);
     }
 
+    @GuardedBy("mLock")
     @Nullable BasePermission getPermissionTreeLocked(@NonNull String permName) {
         return mPermissionTrees.get(permName);
     }
 
+    @GuardedBy("mLock")
     void putPermissionLocked(@NonNull String permName, @NonNull BasePermission permission) {
         mPermissions.put(permName, permission);
     }
 
+    @GuardedBy("mLock")
     void putPermissionTreeLocked(@NonNull String permName, @NonNull BasePermission permission) {
         mPermissionTrees.put(permName, permission);
     }
 
+    @GuardedBy("mLock")
     void removePermissionLocked(@NonNull String permName) {
         mPermissions.remove(permName);
     }
 
+    @GuardedBy("mLock")
     void removePermissionTreeLocked(@NonNull String permName) {
         mPermissionTrees.remove(permName);
     }
 
+    @GuardedBy("mLock")
     @NonNull Collection<BasePermission> getAllPermissionsLocked() {
         return mPermissions.values();
     }
 
+    @GuardedBy("mLock")
     @NonNull Collection<BasePermission> getAllPermissionTreesLocked() {
         return mPermissionTrees.values();
     }
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 847c90a..08dc97e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -306,6 +306,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
         mSettings = setting;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 1bb85c4..38dc820 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -120,9 +120,6 @@
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_SPEW = DEBUG && true;
 
-    // if DEBUG_WIRELESS=true, plays wireless charging animation w/ sound on every plug + unplug
-    private static final boolean DEBUG_WIRELESS = false;
-
     // Message: Sent when a user activity timeout occurs to update the power state.
     private static final int MSG_USER_ACTIVITY_TIMEOUT = 1;
     // Message: Sent when the device enters or exits a dreaming or dozing state.
@@ -1743,14 +1740,15 @@
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
 
-                // Tell the notifier whether wireless charging has started so that
-                // it can provide feedback to the user.
-                if (dockedOnWirelessCharger || DEBUG_WIRELESS) {
-                    mNotifier.onWirelessChargingStarted(mBatteryLevel);
-                } else if (mIsPowered && !wasPowered
-                        && (mPlugType == BatteryManager.BATTERY_PLUGGED_AC
-                        || mPlugType == BatteryManager.BATTERY_PLUGGED_USB)) {
-                    mNotifier.onWiredChargingStarted();
+                // only play charging sounds if boot is completed so charging sounds don't play
+                // with potential notification sounds
+                if (mBootCompleted) {
+                    if (mIsPowered && !BatteryManager.isPlugWired(oldPlugType)
+                            && BatteryManager.isPlugWired(mPlugType)) {
+                        mNotifier.onWiredChargingStarted();
+                    } else if (dockedOnWirelessCharger) {
+                        mNotifier.onWirelessChargingStarted(mBatteryLevel);
+                    }
                 }
             }
 
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
index 671d7a6..37df94f 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySavingStats.java
@@ -285,6 +285,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void transitionStateLocked(int newState) {
         if (mCurrentState == newState) {
             return;
@@ -298,6 +299,7 @@
         mMetricsLoggerHelper.transitionState(newState, now, batteryLevel, batteryPercent);
     }
 
+    @GuardedBy("mLock")
     private void endLastStateLocked(long now, int batteryLevel, int batteryPercent) {
         if (mCurrentState < 0) {
             return;
@@ -338,6 +340,7 @@
 
     }
 
+    @GuardedBy("mLock")
     private void startNewStateLocked(int newState, long now, int batteryLevel, int batteryPercent) {
         if (DEBUG) {
             Slog.d(TAG, "New state: " + stateToString(newState));
diff --git a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
index e0ab9e9..c08b610 100644
--- a/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
+++ b/services/core/java/com/android/server/power/batterysaver/FileUpdater.java
@@ -306,6 +306,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void saveDefaultValuesLocked() {
         final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
 
@@ -334,6 +335,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
     boolean loadDefaultValuesLocked() {
         final AtomicFile file = new AtomicFile(injectDefaultValuesFilename());
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index a82b559..ef6067a 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -85,7 +85,7 @@
     public static final String RESULT_RECEIVER_CONTROLLER_KEY = "controller_activity";
 
     static final String TAG = "StatsCompanionService";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     public static final int CODE_DATA_BROADCAST = 1;
     public static final int CODE_SUBSCRIBER_BROADCAST = 1;
@@ -211,6 +211,7 @@
     }
 
     // Assumes that sStatsdLock is held.
+    @GuardedBy("sStatsdLock")
     private final void informAllUidsLocked(Context context) throws RemoteException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
         PackageManager pm = context.getPackageManager();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 7c170ae..343fb91 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -321,7 +321,7 @@
         public void showChargingAnimation(int batteryLevel) {
             if (mBar != null) {
                 try {
-                    mBar.showChargingAnimation(batteryLevel);
+                    mBar.showWirelessChargingAnimation(batteryLevel);
                 } catch (RemoteException ex){
                 }
             }
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 853c7eb..0ac853b 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -22,7 +22,6 @@
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
-import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -43,7 +42,6 @@
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
 
 /**
  * A manager for TextClassifier services.
@@ -54,9 +52,6 @@
 
     private static final String LOG_TAG = "TextClassificationManagerService";
 
-    // How long after the last interaction with the service we would unbind
-    private static final long TIMEOUT_IDLE_BIND_MILLIS = TimeUnit.MINUTES.toMillis(1);
-
     public static final class Lifecycle extends SystemService {
 
         private final TextClassificationManagerService mManagerService;
@@ -79,10 +74,8 @@
     }
 
     private final Context mContext;
-    private final Handler mHandler;
     private final Intent mServiceIntent;
     private final ServiceConnection mConnection;
-    private final Runnable mUnbind;
     private final Object mLock;
     @GuardedBy("mLock")
     private final Queue<PendingRequest> mPendingRequests;
@@ -94,7 +87,6 @@
 
     private TextClassificationManagerService(Context context) {
         mContext = Preconditions.checkNotNull(context);
-        mHandler = new Handler();
         mServiceIntent = new Intent(TextClassifierService.SERVICE_INTERFACE)
                 .setComponent(TextClassifierService.getServiceComponentName(mContext));
         mConnection = new ServiceConnection() {
@@ -131,7 +123,6 @@
             }
         };
         mPendingRequests = new LinkedList<>();
-        mUnbind = this::unbind;
         mLock = new Object();
     }
 
@@ -152,7 +143,6 @@
             if (isBoundLocked()) {
                 mService.onSuggestSelection(
                         text, selectionStartIndex, selectionEndIndex, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onSuggestSelection(
@@ -184,7 +174,6 @@
         synchronized (mLock) {
             if (isBoundLocked()) {
                 mService.onClassifyText(text, startIndex, endIndex, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onClassifyText(text, startIndex, endIndex, options, callback);
@@ -213,7 +202,6 @@
         synchronized (mLock) {
             if (isBoundLocked()) {
                 mService.onGenerateLinks(text, options, callback);
-                scheduleUnbindLocked();
             } else {
                 final Callable<Void> request = () -> {
                     onGenerateLinks(text, options, callback);
@@ -270,27 +258,6 @@
         mBinding = binding;
     }
 
-    private void unbind() {
-        synchronized (mLock) {
-            if (!isBoundLocked()) {
-                return;
-            }
-
-            Slog.d(LOG_TAG, "Unbinding from " + mServiceIntent.getComponent());
-            mContext.unbindService(mConnection);
-
-            synchronized (mLock) {
-                mService = null;
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void scheduleUnbindLocked() {
-        mHandler.removeCallbacks(mUnbind);
-        mHandler.postDelayed(mUnbind, TIMEOUT_IDLE_BIND_MILLIS);
-    }
-
     @GuardedBy("mLock")
     private void enqueueRequestLocked(
             Callable<Void> request, Callable<Void> onServiceFailure, IBinder binder) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2512dbd..41a6e2b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -725,8 +725,9 @@
      *                            wallpaper windows in the window list.
      */
     DisplayContent(Display display, WindowManagerService service,
-            WallpaperController wallpaperController) {
+            WallpaperController wallpaperController, DisplayWindowController controller) {
         super(service);
+        setController(controller);
         if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
                     + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1941,6 +1942,8 @@
         } finally {
             mRemovingDisplay = false;
         }
+
+        mService.onDisplayRemoved(mDisplayId);
     }
 
     /** Returns true if a removal action is still being deferred. */
@@ -1950,7 +1953,6 @@
 
         if (!stillDeferringRemoval && mDeferredRemoval) {
             removeImmediately();
-            mService.onDisplayRemoved(mDisplayId);
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index ad4957e..0e12838 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -16,11 +16,14 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.content.res.Configuration;
+import android.os.Binder;
 import android.util.Slog;
+import android.view.Display;
 
 /**
  * Controller for the display container. This is created by activity manager to link activity
@@ -36,9 +39,16 @@
         mDisplayId = displayId;
 
         synchronized (mWindowMap) {
-            // TODO: Convert to setContainer() from DisplayContent once everything is hooked up.
-            // Currently we are not setup to register for config changes.
-            mContainer = mRoot.getDisplayContentOrCreate(displayId);
+            final Display display = mService.mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mRoot.createDisplayContent(display, this /* controller */);
+                } finally {
+                    Binder.restoreCallingIdentity(callingIdentity);
+                }
+            }
+
             if (mContainer == null) {
                 throw new IllegalArgumentException("Trying to add displayId=" + displayId);
             }
@@ -47,14 +57,22 @@
 
     @Override
     public void removeContainer() {
-        // TODO: Pipe through from ActivityDisplay to remove the display
-        throw new UnsupportedOperationException("To be implemented");
+        synchronized (mWindowMap) {
+            if(mContainer == null) {
+                if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
+                        + mDisplayId);
+                return;
+            }
+            mContainer.removeIfPossible();
+            super.removeContainer();
+        }
     }
 
     @Override
     public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        // TODO: Pipe through from ActivityDisplay to update the configuration for the display
-        throw new UnsupportedOperationException("To be implemented");
+        // TODO: The container receives override configuration changes through other means. enabling
+        // callbacks through the controller causes layout issues. Investigate consolidating
+        // override configuration propagation to just here.
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c535fe5..f5760e5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -193,30 +193,6 @@
         }
     }
 
-    /**
-     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
-     * there is a Display for the displayId.
-     *
-     * @param displayId The display the caller is interested in.
-     * @return The DisplayContent associated with displayId or null if there is no Display for it.
-     */
-    DisplayContent getDisplayContentOrCreate(int displayId) {
-        DisplayContent dc = getDisplayContent(displayId);
-
-        if (dc == null) {
-            final Display display = mService.mDisplayManager.getDisplay(displayId);
-            if (display != null) {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    dc = createDisplayContent(display);
-                } finally {
-                    Binder.restoreCallingIdentity(callingIdentity);
-                }
-            }
-        }
-        return dc;
-    }
-
     DisplayContent getDisplayContent(int displayId) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final DisplayContent current = mChildren.get(i);
@@ -227,9 +203,9 @@
         return null;
     }
 
-    private DisplayContent createDisplayContent(final Display display) {
-        final DisplayContent dc = new DisplayContent(display, mService,
-                mWallpaperController);
+    DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+        final DisplayContent dc =
+                new DisplayContent(display, mService, mWallpaperController, controller);
         final int displayId = display.getDisplayId();
 
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
@@ -748,19 +724,6 @@
                     (mSustainedPerformanceModeEnabled ? 1 : 0));
         }
 
-        if (mService.mTurnOnScreen) {
-            if (mService.mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
-                    Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
-                        "android.server.wm:TURN_ON");
-            }
-            mService.mTurnOnScreen = false;
-        }
-
         if (mUpdateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             // TODO(multi-display): Update rotation for different displays separately.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index dc62cc8..1b2f954 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -151,6 +151,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void startPendingAnimationsLocked() {
         for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
             startAnimationLocked(mPendingAnimations.valueAt(i));
@@ -158,6 +159,7 @@
         mPendingAnimations.clear();
     }
 
+    @GuardedBy("mLock")
     private void startAnimationLocked(RunningAnimation a) {
         final ValueAnimator anim = mAnimatorFactory.makeAnimator();
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 7b047a8..621bee7 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -281,11 +281,13 @@
             mSnapshot = snapshot;
         }
 
+        @GuardedBy("mLock")
         @Override
         void onQueuedLocked() {
             mStoreQueueItems.offer(this);
         }
 
+        @GuardedBy("mLock")
         @Override
         void onDequeuedLocked() {
             mStoreQueueItems.remove(this);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index cec13ab..49a30d5 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -161,7 +161,7 @@
                 final int numDisplays = mDisplayContentsAnimators.size();
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                     DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                     final ScreenRotationAnimation screenRotationAnimation =
@@ -195,7 +195,7 @@
 
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
 
                     dc.checkAppWindowsReadyToShow();
 
@@ -228,7 +228,7 @@
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
-                final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                 dc.onPendingTransactionApplied();
             }
 
@@ -305,7 +305,7 @@
                     pw.println(":");
             final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
             final DisplayContent dc =
-                    mService.mRoot.getDisplayContentOrCreate(mDisplayContentsAnimators.keyAt(i));
+                    mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
             dc.dumpWindowAnimators(pw, subPrefix);
             if (displayAnimator.mScreenRotationAnimation != null) {
                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
@@ -339,7 +339,7 @@
         if (displayId < 0) {
             return 0;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
@@ -347,7 +347,7 @@
         if (displayId < 0) {
             return;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         if (displayContent != null) {
             displayContent.pendingLayoutChanges |= changes;
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 676fb9f..c2ed2ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -737,7 +737,6 @@
     final InputManagerService mInputManager;
     final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
-    private final Display[] mDisplays;
 
     // Indicates whether this device supports wide color gamut rendering
     private boolean mHasWideColorGamutSupport;
@@ -746,8 +745,6 @@
     private Session mHoldingScreenOn;
     private PowerManager.WakeLock mHoldingScreenWakeLock;
 
-    boolean mTurnOnScreen;
-
     // Whether or not a layout can cause a wake up when theater mode is enabled.
     boolean mAllowTheaterModeWakeFromLayout;
 
@@ -915,7 +912,6 @@
             @Override
             public void run() {
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
-
                 mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
             }
         }, 0);
@@ -974,10 +970,6 @@
         }
 
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        mDisplays = mDisplayManager.getDisplays();
-        for (Display display : mDisplays) {
-            createDisplayContentLocked(display);
-        }
 
         mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
 
@@ -1066,6 +1058,13 @@
         mDragDropController = new DragDropController(this, mH.getLooper());
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
+    }
+
+    /**
+     * Called after all entities (such as the {@link ActivityManagerService}) have been set up and
+     * associated with the {@link WindowManagerService}.
+     */
+    public void onInitReady() {
         initPolicy();
 
         // Add ourself to the Watchdog monitors.
@@ -1081,6 +1080,7 @@
         showEmulatorDisplayOverlayIfNeeded();
     }
 
+
     public InputMonitor getInputMonitor() {
         return mInputMonitor;
     }
@@ -1131,7 +1131,7 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                         + displayId + ".  Aborting.");
@@ -2277,7 +2277,7 @@
         }
 
         synchronized(mWindowMap) {
-            final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
             WindowToken token = dc.getWindowToken(binder);
             if (token != null) {
                 Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder
@@ -3666,7 +3666,7 @@
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
         synchronized(mWindowMap) {
-            displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot returning null. No Display for "
                         + "displayId=" + displayId);
@@ -3885,7 +3885,7 @@
     public boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
             int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 throw new IllegalArgumentException("Trying to register visibility event "
                         + "for invalid display: " + displayId);
@@ -4442,10 +4442,13 @@
     }
 
     public void displayReady() {
-        for (Display display : mDisplays) {
+        final int displayCount = mRoot.mChildren.size();
+        for (int i = 0; i < displayCount; ++i) {
+            final DisplayContent display = mRoot.mChildren.get(i);
             displayReady(display.getDisplayId());
         }
 
+
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             if (mMaxUiWidth > 0) {
@@ -4476,7 +4479,7 @@
 
     private void displayReady(int displayId) {
         synchronized(mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 mAnimator.addDisplayLocked(displayId);
                 displayContent.initializeDisplayBaseInfo();
@@ -5025,7 +5028,7 @@
     @Override
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mInitialDisplayWidth;
                 size.y = displayContent.mInitialDisplayHeight;
@@ -5036,7 +5039,7 @@
     @Override
     public void getBaseDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mBaseDisplayWidth;
                 size.y = displayContent.mBaseDisplayHeight;
@@ -5063,7 +5066,7 @@
                 final int MIN_WIDTH = 200;
                 final int MIN_HEIGHT = 200;
                 final int MAX_SCALE = 2;
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     width = Math.min(Math.max(width, MIN_WIDTH),
                             displayContent.mInitialDisplayWidth * MAX_SCALE);
@@ -5093,7 +5096,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     if (mode < 0 || mode > 1) {
                         mode = 0;
@@ -5175,7 +5178,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
                             displayContent.mInitialDisplayHeight);
@@ -5191,7 +5194,7 @@
     @Override
     public int getInitialDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mInitialDisplayDensity;
             }
@@ -5202,7 +5205,7 @@
     @Override
     public int getBaseDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mBaseDisplayDensity;
             }
@@ -5228,7 +5231,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == targetUserId) {
                     setForcedDisplayDensityLocked(displayContent, density);
                 }
@@ -5259,7 +5262,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == callingUserId) {
                     setForcedDisplayDensityLocked(displayContent,
                             displayContent.mInitialDisplayDensity);
@@ -5351,7 +5354,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setOverscanLocked(displayContent, left, top, right, bottom);
                 }
@@ -6614,19 +6617,11 @@
         synchronized (mWindowMap) { }
     }
 
-    // TODO: All the display method below should probably be moved into the RootWindowContainer...
-    private void createDisplayContentLocked(final Display display) {
-        if (display == null) {
-            throw new IllegalArgumentException("getDisplayContent: display must not be null");
-        }
-        mRoot.getDisplayContentOrCreate(display.getDisplayId());
-    }
-
     // There is an inherent assumption that this will never return null.
     // TODO(multi-display): Inspect all the call-points of this method to see if they make sense to
     // support non-default display.
     DisplayContent getDefaultDisplayContentLocked() {
-        return mRoot.getDisplayContentOrCreate(DEFAULT_DISPLAY);
+        return mRoot.getDisplayContent(DEFAULT_DISPLAY);
     }
 
     public void onDisplayAdded(int displayId) {
@@ -6641,10 +6636,6 @@
 
     public void onDisplayRemoved(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
-            if (displayContent != null) {
-                displayContent.removeIfPossible();
-            }
             mAnimator.removeDisplayLocked(displayId);
             mWindowPlacerLocked.requestTraversal();
         }
@@ -6660,7 +6651,7 @@
 
     public void onDisplayChanged(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 displayContent.updateDisplayInfo();
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 240e7fd..21b4361 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.Transaction;
@@ -167,6 +168,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
@@ -265,7 +267,7 @@
     // This is a non-system overlay window that is currently force hidden.
     private boolean mForceHideNonSystemOverlayWindow;
     boolean mAppFreezing;
-    boolean mHidden;    // Used to determine if to show child windows.
+    boolean mHidden = true;    // Used to determine if to show child windows.
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
     private boolean mDragResizing;
     private boolean mDragResizingChangeReported = true;
@@ -285,7 +287,6 @@
     int mLayer;
     boolean mHaveFrame;
     boolean mObscured;
-    boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
 
@@ -635,6 +636,11 @@
     private TapExcludeRegionHolder mTapExcludeRegionHolder;
 
     /**
+     * Used for testing because the real PowerManager is final.
+     */
+    private PowerManagerWrapper mPowerManagerWrapper;
+
+    /**
      * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
      */
@@ -663,9 +669,34 @@
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
 
+    interface PowerManagerWrapper {
+        void wakeUp(long time, String reason);
+
+        boolean isInteractive();
+
+    }
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
-           WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-           int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+        this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId,
+                ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
+                    @Override
+                    public void wakeUp(long time, String reason) {
+                        service.mPowerManager.wakeUp(time, reason);
+                    }
+
+                    @Override
+                    public boolean isInteractive() {
+                        return service.mPowerManager.isInteractive();
+                    }
+                });
+    }
+
+    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
+            PowerManagerWrapper powerManagerWrapper) {
         super(service);
         mSession = s;
         mClient = c;
@@ -682,6 +713,7 @@
         DeathRecipient deathRecipient = new DeathRecipient();
         mSeq = seq;
         mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
+        mPowerManagerWrapper = powerManagerWrapper;
         if (localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -2275,9 +2307,34 @@
 
     void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         // We need to turn on screen regardless of visibility.
-        if ((mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG, "Relayout window turning screen on: " + this);
-            mTurnOnScreen = true;
+        boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
+        boolean allowTheaterMode =
+                mService.mAllowTheaterModeWakeFromLayout || Settings.Global.getInt(
+                        mService.mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0)
+                        == 0;
+        boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+
+        // The screen will turn on if the following conditions are met
+        // 1. The window has the flag FLAG_TURN_SCREEN_ON
+        // 2. The WMS allows theater mode.
+        // 3. No AWT or the AWT allows the screen to be turned on. This should only be true once
+        // per resume to prevent the screen getting getting turned on for each relayout. Set
+        // canTurnScreenOn will be set to false so the window doesn't turn the screen on again
+        // during this resume.
+        // 4. When the screen is not interactive. This is because when the screen is already
+        // interactive, the value may persist until the next animation, which could potentially
+        // be occurring while turning off the screen. This would lead to the screen incorrectly
+        // turning back on.
+        if (hasTurnScreenOnFlag && allowTheaterMode && canTurnScreenOn
+                && !mPowerManagerWrapper.isInteractive()) {
+            if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                Slog.v(TAG, "Relayout window turning screen on: " + this);
+            }
+            mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
+                    "android.server.wm:TURN_ON");
+        }
+        if (mAppToken != null) {
+            mAppToken.setCanTurnScreenOn(false);
         }
 
         // If we were already visible, skip rest of preparation.
@@ -2571,8 +2628,7 @@
                 // in wake lock statistics.  So in particular, we don't want to include the
                 // window's hash code as in toString().
                 final CharSequence tag = getWindowTag();
-                mDrawLock = mService.mPowerManager.newWakeLock(
-                        PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
+                mDrawLock = mService.mPowerManager.newWakeLock(DRAW_WAKE_LOCK, "Window:" + tag);
                 mDrawLock.setReferenceCounted(false);
                 mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
             }
@@ -3327,15 +3383,13 @@
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
         }
-        if (getOrientationChanging() || mAppFreezing || mTurnOnScreen
-                || mReportOrientationChanged) {
+        if (getOrientationChanging() || mAppFreezing || mReportOrientationChanged) {
             pw.print(prefix); pw.print("mOrientationChanging=");
                     pw.print(mOrientationChanging);
                     pw.print(" configOrientationChanging=");
                     pw.print(getLastReportedConfiguration().orientation
                             != getConfiguration().orientation);
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
-                    pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
                     pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
         }
         if (mLastFreezeDuration != 0) {
@@ -4505,13 +4559,12 @@
         if (!mAnimatingExit && mAppDied) {
             mIsDimming = true;
             dimmer.dimAbove(getPendingTransaction(), this, DEFAULT_DIM_AMOUNT_DEAD_WINDOW);
-        } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isVisibleNow()
-                && !mWinAnimator.mLastHidden) {
+        } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isVisibleNow() && !mHidden) {
             // Only show a dim behind when the following is satisfied:
             // 1. The window has the flag FLAG_DIM_BEHIND
             // 2. The WindowToken is not hidden so dims aren't shown when the window is exiting.
             // 3. The WS is considered visible according to the isVisible() method
-            // 4. The WSA is not hidden.
+            // 4. The WS is not hidden.
             mIsDimming = true;
             dimmer.dimBelow(getPendingTransaction(), this, mAttrs.dimAmount);
         }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index dd23b6f..9621ee5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1108,31 +1108,6 @@
                         w.setOrientationChanging(false);
                     }
                 }
-                // We process mTurnOnScreen even for windows which have already
-                // been shown, to handle cases where windows are not necessarily
-                // hidden while the screen is turning off.
-                // TODO(b/63773439): These cases should be eliminated, though we probably still
-                // want to process mTurnOnScreen in this way for clarity.
-                if (mWin.mTurnOnScreen &&
-                        (mWin.mAppToken == null || mWin.mAppToken.canTurnScreenOn())) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
-                    mWin.mTurnOnScreen = false;
-
-                    // The window should only turn the screen on once per resume, but
-                    // prepareSurfaceLocked can be called multiple times. Set canTurnScreenOn to
-                    // false so the window doesn't turn the screen on again during this resume.
-                    if (mWin.mAppToken != null) {
-                        mWin.mAppToken.setCanTurnScreenOn(false);
-                    }
-
-                    // We do not add {@code SET_TURN_ON_SCREEN} when the screen is already
-                    // interactive as the value may persist until the next animation, which could
-                    // potentially occurring while turning off the screen. This would lead to the
-                    // screen incorrectly turning back on.
-                    if (!mService.mPowerManager.isInteractive()) {
-                        mService.mTurnOnScreen = true;
-                    }
-                }
             }
             if (hasSurface()) {
                 w.mToken.hasVisible = true;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 5e003ff..4045b72 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -124,6 +124,7 @@
         "android.hardware.tv.input@1.0",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
+        "android.hardware.vibrator@1.2",
         "android.hardware.vr@1.0",
         "android.frameworks.schedulerservice@1.0",
         "android.frameworks.sensorservice@1.0",
diff --git a/services/core/jni/com_android_server_ArcVideoService.cpp b/services/core/jni/com_android_server_ArcVideoService.cpp
index 7df8276..f93cd90 100644
--- a/services/core/jni/com_android_server_ArcVideoService.cpp
+++ b/services/core/jni/com_android_server_ArcVideoService.cpp
@@ -32,7 +32,7 @@
 #include <arc/Future.h>
 #include <arc/IArcBridgeService.h>
 #include <arc/MojoProcessSupport.h>
-#include <video.mojom.h>
+#include <components/arc/common/video.mojom.h>
 
 namespace {
 
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index d2f374d..016de14 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -18,7 +18,10 @@
 
 #include <android/hardware/vibrator/1.0/IVibrator.h>
 #include <android/hardware/vibrator/1.0/types.h>
-#include <android/hardware/vibrator/1.1/IVibrator.h>
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <android/hardware/vibrator/1.1/types.h>
+#include <android/hardware/vibrator/1.2/IVibrator.h>
+#include <android/hardware/vibrator/1.2/types.h>
 
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -32,15 +35,15 @@
 #include <stdio.h>
 
 using android::hardware::Return;
-using android::hardware::vibrator::V1_0::Effect;
 using android::hardware::vibrator::V1_0::EffectStrength;
-using android::hardware::vibrator::V1_0::IVibrator;
 using android::hardware::vibrator::V1_0::Status;
 using android::hardware::vibrator::V1_1::Effect_1_1;
-using IVibrator_1_1 = android::hardware::vibrator::V1_1::IVibrator;
 
-namespace android
-{
+namespace V1_0 = android::hardware::vibrator::V1_0;
+namespace V1_1 = android::hardware::vibrator::V1_1;
+namespace V1_2 = android::hardware::vibrator::V1_2;
+
+namespace android {
 
 static constexpr int NUM_TRIES = 2;
 
@@ -84,19 +87,29 @@
     return ret;
 }
 
+template<class R>
+bool isValidEffect(jlong effect) {
+    if (effect < 0) {
+        return false;
+    }
+    R val = static_cast<R>(effect);
+    auto iter = hardware::hidl_enum_iterator<R>();
+    return val >= *iter.begin() && val < *std::prev(iter.end());
+}
+
 static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
 {
-    halCall(&IVibrator::ping).isOk();
+    halCall(&V1_0::IVibrator::ping).isOk();
 }
 
 static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
 {
-    return halCall(&IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
+    return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE;
 }
 
 static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
 {
-    Status retStatus = halCall(&IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
+    Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
         ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
     }
@@ -104,18 +117,18 @@
 
 static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
 {
-    Status retStatus = halCall(&IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
+    Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
     if (retStatus != Status::OK) {
         ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
     }
 }
 
 static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jobject) {
-    return halCall(&IVibrator::supportsAmplitudeControl).withDefault(false);
+    return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
 }
 
 static void vibratorSetAmplitude(JNIEnv*, jobject, jint amplitude) {
-    Status status = halCall(&IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
+    Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
         .withDefault(Status::UNKNOWN_ERROR);
     if (status != Status::OK) {
       ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
@@ -132,22 +145,25 @@
     };
     EffectStrength effectStrength(static_cast<EffectStrength>(strength));
 
-    if (effect < 0  || effect > static_cast<uint32_t>(Effect_1_1::TICK)) {
+    Return<void> ret;
+    if (isValidEffect<V1_0::Effect>(effect)) {
+        ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect),
+                effectStrength, callback);
+    } else if (isValidEffect<Effect_1_1>(effect)) {
+        ret = halCall(&V1_1::IVibrator::perform_1_1, static_cast<Effect_1_1>(effect),
+                           effectStrength, callback);
+    } else if (isValidEffect<V1_2::Effect>(effect)) {
+        ret = halCall(&V1_2::IVibrator::perform_1_2, static_cast<V1_2::Effect>(effect),
+                           effectStrength, callback);
+    } else {
         ALOGW("Unable to perform haptic effect, invalid effect ID (%" PRId32 ")",
                 static_cast<int32_t>(effect));
-    } else if (effect == static_cast<uint32_t>(Effect_1_1::TICK)) {
-        auto ret = halCall(&IVibrator_1_1::perform_1_1, static_cast<Effect_1_1>(effect),
-                           effectStrength, callback);
-        if (!ret.isOk()) {
-            ALOGW("Failed to perform effect (%" PRId32 "), insufficient HAL version",
-                    static_cast<int32_t>(effect));
-        }
-    } else {
-        auto ret = halCall(&IVibrator::perform, static_cast<Effect>(effect), effectStrength,
-                           callback);
-        if (!ret.isOk()) {
-            ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
-        }
+        return -1;
+    }
+
+    if (!ret.isOk()) {
+        ALOGW("Failed to perform effect (%" PRId32 ")", static_cast<int32_t>(effect));
+        return -1;
     }
 
     if (status == Status::OK) {
@@ -160,6 +176,7 @@
                 ", error=%" PRIu32 ").", static_cast<int64_t>(effect),
                 static_cast<int32_t>(strength), static_cast<uint32_t>(status));
     }
+
     return -1;
 }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5ea113b..75bb5e4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -842,6 +842,14 @@
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
             traceEnd();
 
+            traceBeginAndSlog("SetWindowManagerService");
+            mActivityManagerService.setWindowManager(wm);
+            traceEnd();
+
+            traceBeginAndSlog("WindowManagerServiceOnInitReady");
+            wm.onInitReady();
+            traceEnd();
+
             // Start receiving calls from HIDL services. Start in in a separate thread
             // because it need to connect to SensorManager. This have to start
             // after START_SENSOR_SERVICE is done.
@@ -859,10 +867,6 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("SetWindowManagerService");
-            mActivityManagerService.setWindowManager(wm);
-            traceEnd();
-
             traceBeginAndSlog("StartInputManager");
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
             inputManager.start();
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index e103464..cd9311f 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -26,6 +26,8 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -40,7 +42,9 @@
 import android.app.IActivityManager;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupTransport;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.IBackupManager;
 import android.app.backup.IBackupManagerMonitor;
@@ -53,6 +57,7 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
@@ -80,6 +85,8 @@
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadow.api.Shadow;
@@ -88,6 +95,7 @@
 import org.robolectric.shadows.ShadowQueuedWork;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Stream;
@@ -184,32 +192,33 @@
 
     @Test
     public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
         when(mTransportBinder.getTransportFlags()).thenReturn(flags);
         PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+        verify(agentMock.agent)
+                .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
     }
 
     @Test
     public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
         PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
+        verify(agentMock.agent).onBackup(any(), argThat(dataOutputWithTransportFlags(0)), any());
     }
 
     @Test
     public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
             throws Exception {
-        List<BackupAgent> agents = setUpAgents(PACKAGE_1, PACKAGE_2);
-        BackupAgent agent1 = agents.get(0);
-        BackupAgent agent2 = agents.get(1);
+        List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
+        BackupAgent agent1 = agentMocks.get(0).agent;
+        BackupAgent agent2 = agentMocks.get(1).agent;
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
         when(mTransportBinder.getTransportFlags()).thenReturn(flags);
         PerformBackupTask task =
@@ -223,14 +232,103 @@
 
     @Test
     public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
-        BackupAgent agent = setUpAgent(PACKAGE_1);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
         PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
         when(mTransportBinder.getTransportFlags()).thenReturn(flags);
 
         runTask(task);
 
-        verify(agent).onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+        verify(agentMock.agent)
+                .onBackup(any(), argThat(dataOutputWithTransportFlags(flags)), any());
+    }
+
+    @Test
+    public void testRunTask_callsListenerOnTaskFinished() throws Exception {
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+
+        runTask(task);
+
+        verify(mListener).onFinished(any());
+    }
+
+    @Test
+    public void testRunTask_callsTransportPerformBackup() throws Exception {
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        agentOnBackupDo(
+                agentMock.agent,
+                (oldState, dataOutput, newState) -> {
+                    writeData(dataOutput, "key1", "foo".getBytes());
+                    writeData(dataOutput, "key2", "bar".getBytes());
+                });
+        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        // We need to verify at call time because the file is deleted right after
+        when(mTransportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .then(this::mockAndVerifyTransportPerformBackupData);
+
+        runTask(task);
+
+        // Already verified data in mockAndVerifyPerformBackupData
+        verify(mTransportBinder).performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+    }
+
+    private int mockAndVerifyTransportPerformBackupData(InvocationOnMock invocation)
+            throws IOException {
+        ParcelFileDescriptor data = invocation.getArgument(1);
+
+        // Verifying that what we passed to the transport is what the agent wrote
+        BackupDataInput dataInput = new BackupDataInput(data.getFileDescriptor());
+
+        // "key1" => "foo"
+        assertThat(dataInput.readNextHeader()).isTrue();
+        assertThat(dataInput.getKey()).isEqualTo("key1");
+        int size1 = dataInput.getDataSize();
+        byte[] data1 = new byte[size1];
+        dataInput.readEntityData(data1, 0, size1);
+        assertThat(data1).isEqualTo("foo".getBytes());
+
+        // "key2" => "bar"
+        assertThat(dataInput.readNextHeader()).isTrue();
+        assertThat(dataInput.getKey()).isEqualTo("key2");
+        int size2 = dataInput.getDataSize();
+        byte[] data2 = new byte[size2];
+        dataInput.readEntityData(data2, 0, size2);
+        assertThat(data2).isEqualTo("bar".getBytes());
+
+        // No more
+        assertThat(dataInput.readNextHeader()).isFalse();
+
+        return BackupTransport.TRANSPORT_OK;
+    }
+
+    @Test
+    public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
+            throws Exception {
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        when(mTransportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+
+        runTask(task);
+
+        verify(mTransportBinder).finishBackup();
+    }
+
+    @Test
+    public void testRunTask_whenProhibitedKey_failsAgent() throws Exception {
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        agentOnBackupDo(
+                agentMock.agent,
+                (oldState, dataOutput, newState) -> {
+                    char prohibitedChar = 0xff00;
+                    writeData(dataOutput, prohibitedChar + "key", "foo".getBytes());
+                });
+        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+
+        runTask(task);
+
+        verify(agentMock.agentBinder).fail(any());
     }
 
     private void runTask(PerformBackupTask task) {
@@ -241,26 +339,34 @@
         }
     }
 
-    private List<BackupAgent> setUpAgents(String... packageNames) {
+    private List<AgentMock> setUpAgents(String... packageNames) {
         return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
     }
 
-    private BackupAgent setUpAgent(String packageName) {
-        PackageInfo packageInfo = new PackageInfo();
-        packageInfo.packageName = packageName;
-        packageInfo.applicationInfo = new ApplicationInfo();
-        packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
-        packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
-        packageInfo.applicationInfo.packageName = packageName;
-        mShadowPackageManager.setApplicationEnabledSetting(
-                packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
-        mShadowPackageManager.addPackage(packageInfo);
-        BackupAgent backupAgent = spy(BackupAgent.class);
-        IBackupAgent backupAgentBinder = IBackupAgent.Stub.asInterface(backupAgent.onBind());
-        when(mBackupManagerService.bindToAgentSynchronous(
-                        eq(packageInfo.applicationInfo), anyInt()))
-                .thenReturn(backupAgentBinder);
-        return backupAgent;
+    private AgentMock setUpAgent(String packageName) {
+        try {
+            PackageInfo packageInfo = new PackageInfo();
+            packageInfo.packageName = packageName;
+            packageInfo.applicationInfo = new ApplicationInfo();
+            packageInfo.applicationInfo.flags = ApplicationInfo.FLAG_ALLOW_BACKUP;
+            packageInfo.applicationInfo.backupAgentName = "BackupAgent" + packageName;
+            packageInfo.applicationInfo.packageName = packageName;
+            mShadowPackageManager.setApplicationEnabledSetting(
+                    packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0);
+            mShadowPackageManager.addPackage(packageInfo);
+            BackupAgent backupAgent = spy(BackupAgent.class);
+            IBackupAgent backupAgentBinder =
+                    spy(IBackupAgent.Stub.asInterface(backupAgent.onBind()));
+            // Don't crash our only process (in production code this would crash the app, not us)
+            doNothing().when(backupAgentBinder).fail(any());
+            when(mBackupManagerService.bindToAgentSynchronous(
+                            eq(packageInfo.applicationInfo), anyInt()))
+                    .thenReturn(backupAgentBinder);
+            return new AgentMock(backupAgentBinder, backupAgent);
+        } catch (RemoteException e) {
+            // Never happens, compiler happy
+            throw new AssertionError(e);
+        }
     }
 
     private PerformBackupTask createPerformBackupTask(
@@ -288,10 +394,53 @@
         return task;
     }
 
-    private ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
+    private static ArgumentMatcher<PackageInfo> packageInfo(String packageName) {
+        return packageInfo -> packageName.equals(packageInfo.packageName);
+    }
+
+    private static ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
         return dataOutput -> dataOutput.getTransportFlags() == flags;
     }
 
+    private static void writeData(BackupDataOutput dataOutput, String key, byte[] data)
+            throws IOException {
+        dataOutput.writeEntityHeader(key, data.length);
+        dataOutput.writeEntityData(data, data.length);
+    }
+
+    private static void agentOnBackupDo(BackupAgent agent, BackupAgentOnBackup function)
+            throws Exception {
+        doAnswer(function).when(agent).onBackup(any(), any(), any());
+    }
+
+    @FunctionalInterface
+    private interface BackupAgentOnBackup extends Answer<Void> {
+        void onBackup(
+                ParcelFileDescriptor oldState,
+                BackupDataOutput dataOutput,
+                ParcelFileDescriptor newState)
+                throws IOException;
+
+        @Override
+        default Void answer(InvocationOnMock invocation) throws Throwable {
+            onBackup(
+                    invocation.getArgument(0),
+                    invocation.getArgument(1),
+                    invocation.getArgument(2));
+            return null;
+        }
+    }
+
+    private static class AgentMock {
+        private final IBackupAgent agentBinder;
+        private final BackupAgent agent;
+
+        public AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
+            this.agentBinder = agentBinder;
+            this.agent = agent;
+        }
+    }
+
     private abstract static class FakeIBackupManager extends IBackupManager.Stub {
         private Handler mBackupHandler;
         private BackupRestoreTask mTask;
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
index 28489af..8016a8b 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataInput.java
@@ -21,41 +21,76 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.io.EOFException;
 import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
 
+/**
+ * Shadow for {@link BackupDataInput}. Format read does NOT match implementation. To write data to
+ * be read by this shadow, you should also declare shadow {@link ShadowBackupDataOutput}.
+ */
 @Implements(BackupDataInput.class)
 public class ShadowBackupDataInput {
-    @Implementation
-    public void __constructor__(FileDescriptor fd) {
-    }
+    private ObjectInputStream mInput;
+    private int mSize;
+    private String mKey;
+    private boolean mHeaderReady;
 
     @Implementation
-    protected void finalize() throws Throwable {
+    public void __constructor__(FileDescriptor fd) {
+        try {
+            mInput = new ObjectInputStream(new FileInputStream(fd));
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
     }
 
     @Implementation
     public boolean readNextHeader() throws IOException {
-        return false;
+        mHeaderReady = false;
+        try {
+            mSize = mInput.readInt();
+        } catch (EOFException e) {
+            return false;
+        }
+        mKey = mInput.readUTF();
+        mHeaderReady = true;
+        return true;
     }
 
     @Implementation
     public String getKey() {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        return mKey;
     }
 
     @Implementation
     public int getDataSize() {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        return mSize;
     }
 
     @Implementation
     public int readEntityData(byte[] data, int offset, int size) throws IOException {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        int result = mInput.read(data, offset, size);
+        if (result < 0) {
+            throw new IOException("result=0x" + Integer.toHexString(result));
+        }
+        return result;
     }
 
     @Implementation
     public void skipEntityData() throws IOException {
-        throw new AssertionError("Can't call because readNextHeader() returned false");
+        checkHeaderReady();
+        mInput.read(new byte[mSize], 0, mSize);
+    }
+
+    private void checkHeaderReady() {
+        if (!mHeaderReady) {
+            throw new IllegalStateException("Entity header not read");
+        }
     }
 }
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
index c7deada..e78a4b3 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupDataOutput.java
@@ -21,16 +21,29 @@
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
+import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.ObjectOutputStream;
 
+/**
+ * Shadow for {@link BackupDataOutput}. Format written does NOT match implementation. To read data
+ * written with this shadow you should also declare shadow {@link ShadowBackupDataInput}.
+ */
 @Implements(BackupDataOutput.class)
 public class ShadowBackupDataOutput {
     private long mQuota;
     private int mTransportFlags;
+    private ObjectOutputStream mOutput;
 
     @Implementation
     public void __constructor__(FileDescriptor fd, long quota, int transportFlags) {
+        try {
+            mOutput = new ObjectOutputStream(new FileOutputStream(fd));
+        } catch (IOException e) {
+            throw new AssertionError(e);
+        }
         mQuota = quota;
         mTransportFlags = transportFlags;
     }
@@ -47,11 +60,27 @@
 
     @Implementation
     public int writeEntityHeader(String key, int dataSize) throws IOException {
-        return 0;
+        final int size;
+        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
+            writeEntityHeader(new ObjectOutputStream(byteStream), key, dataSize);
+            size = byteStream.size();
+        }
+        writeEntityHeader(mOutput, key, dataSize);
+        return size;
+    }
+
+    private void writeEntityHeader(ObjectOutputStream stream, String key, int dataSize)
+            throws IOException {
+        // Write the int first because readInt() throws EOFException, to know when stream ends
+        stream.writeInt(dataSize);
+        stream.writeUTF(key);
+        stream.flush();
     }
 
     @Implementation
     public int writeEntityData(byte[] data, int size) throws IOException {
-        return 0;
+        mOutput.write(data, 0, size);
+        mOutput.flush();
+        return size;
     }
 }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 5d8aca1..97d6c43 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -60,6 +60,7 @@
     <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
     <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
index 070de5b..a38b353 100644
--- a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -16,18 +16,43 @@
 
 package com.android.server.net.watchlist;
 
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doAnswer;
+
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
+import android.os.Looper;
+import android.os.UserManager;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.InstrumentationRegistry;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
 
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 
 /**
  * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistLoggingHandlerTests
@@ -36,18 +61,126 @@
 @SmallTest
 public class WatchlistLoggingHandlerTests {
 
+    private static final String APK_A = "A.apk";
+    private static final String APK_B = "B.apk";
+    private static final String APK_A_CONTENT = "AAA";
+    private static final String APK_B_CONTENT = "BBB";
+    // Sha256 of "AAA"
+    private static final String APK_A_CONTENT_HASH =
+            "CB1AD2119D8FAFB69566510EE712661F9F14B83385006EF92AEC47F523A38358";
+    // Sha256 of "BBB"
+    private static final String APK_B_CONTENT_HASH =
+            "DCDB704109A454784B81229D2B05F368692E758BFA33CB61D04C1B93791B0273";
+
+    private Context mServiceContext;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        final Context context = InstrumentationRegistry.getContext();
+        final UserManager mockUserManager = mock(UserManager.class);
+        final PackageManager mockPackageManager = mock(PackageManager.class);
+
+        // Context that will be used by WatchlistLoggingHandler
+        mServiceContext = new ContextWrapper(context) {
+            @Override
+            public PackageManager getPackageManager() {
+                return mockPackageManager;
+            }
+
+            @Override
+            public Object getSystemService(String name) {
+                switch (name) {
+                    case Context.USER_SERVICE:
+                        return mockUserManager;
+                    default:
+                        return super.getSystemService(name);
+                }
+            }
+        };
+
+        // Returns 2 users, user 0 and user 10
+        doAnswer((InvocationOnMock invocation) -> {
+            final ArrayList<UserInfo> info = new ArrayList<>();
+            info.add(new UserInfo(0, "user1", 0));
+            info.add(new UserInfo(10, "user2", 0));
+            return info;
+        }).when(mockUserManager).getUsers();
+
+        // Returns 2 apps, with uid 1 and uid 2
+        doAnswer((InvocationOnMock invocation) -> {
+            final List<ApplicationInfo> result = new ArrayList<>();
+            ApplicationInfo info1 = new ApplicationInfo();
+            info1.uid = 1;
+            result.add(info1);
+            ApplicationInfo info2 = new ApplicationInfo();
+            info2.uid = 2;
+            result.add(info2);
+            return result;
+        }).when(mockPackageManager).getInstalledApplications(anyInt());
+
+        // Uid 1 app with is installed in primary user and package name is "A"
+        // Uid 2 app is installed in secondary user and package name is "B"
+        doAnswer((InvocationOnMock invocation) -> {
+            int uid = (int) invocation.getArguments()[0];
+            if (uid == 1) {
+                return new String[]{"A"};
+            } else if (uid == 1000001) {
+                return null;
+            } else if (uid == 2) {
+                return null;
+            } else if (uid == 1000002) {
+                return new String[]{"B"};
+            }
+            return null;
+        }).when(mockPackageManager).getPackagesForUid(anyInt());
+
+        String fileDir = InstrumentationRegistry.getContext().getFilesDir().getAbsolutePath();
+        // Simulate app's apk file path
+        doAnswer((InvocationOnMock invocation) -> {
+            String pkg = (String) invocation.getArguments()[0];
+            PackageInfo result = new PackageInfo();
+            result.applicationInfo = new ApplicationInfo();
+            result.applicationInfo.publicSourceDir = fileDir + "/" + pkg + ".apk";
+            return result;
+        }).when(mockPackageManager).getPackageInfoAsUser(anyString(), anyInt(), anyInt());
+
+        FileUtils.bytesToFile(fileDir + "/" + APK_A, APK_A_CONTENT.getBytes());
+        FileUtils.bytesToFile(fileDir + "/" + APK_B, APK_B_CONTENT.getBytes());
+    }
+
+    @After
+    public void tearDown() {
+        String fileDir = InstrumentationRegistry.getContext().getFilesDir().getAbsolutePath();
+        new File(fileDir, APK_A).delete();
+        new File(fileDir, APK_B).delete();
+    }
+
+    @Test
+    public void testWatchlistLoggingHandler_getAllDigestsForReportWithMultiUsers()
+            throws Exception {
+        List<String> result = new WatchlistLoggingHandler(mServiceContext,
+                Looper.getMainLooper()).getAllDigestsForReport(
+                new WatchlistReportDbHelper.AggregatedResult(new HashSet<String>(), null,
+                        new HashMap<String, String>()));
+        assertEquals(2, result.size());
+        assertEquals(APK_A_CONTENT_HASH, result.get(0));
+        assertEquals(APK_B_CONTENT_HASH, result.get(1));
+    }
+
     @Test
     public void testWatchlistLoggingHandler_getAllSubDomains() throws Exception {
         String[] subDomains = WatchlistLoggingHandler.getAllSubDomains("abc.def.gh.i.jkl.mm");
-        assertTrue(Arrays.equals(subDomains, new String[] {"abc.def.gh.i.jkl.mm",
+        assertTrue(Arrays.equals(subDomains, new String[]{"abc.def.gh.i.jkl.mm",
                 "def.gh.i.jkl.mm", "gh.i.jkl.mm", "i.jkl.mm", "jkl.mm", "mm"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains(null);
         assertNull(subDomains);
         subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm");
-        assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm", "mm"}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"jkl.mm", "mm"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains("abc");
-        assertTrue(Arrays.equals(subDomains, new String[] {"abc"}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"abc"}));
         subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm.");
-        assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm.", "mm."}));
+        assertTrue(Arrays.equals(subDomains, new String[]{"jkl.mm.", "mm."}));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 2284bbb..63ac4af 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -28,6 +28,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -38,7 +39,6 @@
 import android.annotation.SuppressLint;
 import android.content.res.Configuration;
 import android.graphics.Path;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
@@ -166,6 +166,7 @@
         assertTrue(appWin.canBeImeTarget());
         WindowState imeTarget = mDisplayContent.computeImeTarget(false /* updateImeTarget */);
         assertEquals(appWin, imeTarget);
+        appWin.mHidden = false;
 
         // Verify that an child window can be an ime target.
         final WindowState childWin = createWindow(appWin,
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 000cf38..7a55904 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
@@ -107,6 +108,13 @@
 
             sWm = WindowManagerService.main(context, ims, true, false,
                     false, new TestWindowManagerPolicy());
+
+            sWm.onInitReady();
+
+            // Display creation is driven by the ActivityManagerService via ActivityStackSupervisor.
+            // We emulate those steps here.
+            sWm.mRoot.createDisplayContent(sWm.mDisplayManager.getDisplay(DEFAULT_DISPLAY),
+                    mock(DisplayWindowController.class));
         }
         return sWm;
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 6a4710b..74c72bf 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -36,10 +36,15 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+
 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 static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -57,15 +62,17 @@
         final WindowState child1 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child1");
         final WindowState child2 = createWindow(parentWindow, FIRST_SUB_WINDOW, "child2");
 
-        assertFalse(parentWindow.mHidden);
+        // parentWindow is initially set to hidden.
+        assertTrue(parentWindow.mHidden);
+        assertFalse(parentWindow.isParentWindowHidden());
+        assertTrue(child1.isParentWindowHidden());
+        assertTrue(child2.isParentWindowHidden());
+
+        parentWindow.mHidden = false;
         assertFalse(parentWindow.isParentWindowHidden());
         assertFalse(child1.isParentWindowHidden());
         assertFalse(child2.isParentWindowHidden());
 
-        parentWindow.mHidden = true;
-        assertFalse(parentWindow.isParentWindowHidden());
-        assertTrue(child1.isParentWindowHidden());
-        assertTrue(child2.isParentWindowHidden());
     }
 
     @Test
@@ -237,11 +244,11 @@
     }
 
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
+        reset(mPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-        root.mTurnOnScreen = false;
 
         root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        assertTrue(root.mTurnOnScreen);
+        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 69b1378..91d5ea4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -29,6 +29,7 @@
 import org.junit.Assert;
 import org.junit.After;
 import org.junit.Before;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import android.content.Context;
@@ -84,6 +85,9 @@
     WindowState mChildAppWindowBelow;
     HashSet<WindowState> mCommonWindows;
 
+    @Mock
+    static WindowState.PowerManagerWrapper mPowerManagerWrapper;
+
     @Before
     public void setUp() throws Exception {
         if (!sOneTimeSetupDone) {
@@ -245,7 +249,7 @@
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow);
+                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, mPowerManagerWrapper);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
@@ -284,7 +288,8 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        return new DisplayContent(display, sWm, new WallpaperController(sWm));
+        return new DisplayContent(display, sWm, new WallpaperController(sWm),
+                mock(DisplayWindowController.class));
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index d6f61cd..7b2c040 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -188,6 +188,11 @@
         protected void reportSeen(NotificationRecord r) {
             return;
         }
+
+        @Override
+        protected void reportUserInteraction(NotificationRecord r) {
+            return;
+        }
     }
 
     @Before
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index f0aeb62..32db752 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -177,6 +177,12 @@
     long mAppIdleParoleDurationMillis;
     long[] mAppStandbyScreenThresholds = SCREEN_TIME_THRESHOLDS;
     long[] mAppStandbyElapsedThresholds = ELAPSED_TIME_THRESHOLDS;
+    /** Minimum time a strong usage event should keep the bucket elevated. */
+    long mStrongUsageTimeoutMillis;
+    /** Minimum time a notification seen event should keep the bucket elevated. */
+    long mNotificationSeenTimeoutMillis;
+    /** Minimum time a system update event should keep the buckets elevated. */
+    long mSystemUpdateUsageTimeoutMillis;
 
     volatile boolean mAppIdleEnabled;
     boolean mAppIdleTempParoled;
@@ -330,7 +336,7 @@
                     synchronized (mAppIdleLock) {
                         AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                                 STANDBY_BUCKET_ACTIVE, elapsedRealtime,
-                                elapsedRealtime + 2 * ONE_HOUR);
+                                elapsedRealtime + mStrongUsageTimeoutMillis);
                         maybeInformListeners(packageName, userId, elapsedRealtime,
                                 appUsage.currentBucket, false);
                     }
@@ -628,11 +634,11 @@
                 if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
                     mAppIdleHistory.reportUsage(appHistory, event.mPackage,
                             STANDBY_BUCKET_WORKING_SET,
-                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
+                            elapsedRealtime, elapsedRealtime + mNotificationSeenTimeoutMillis);
                 } else {
                     mAppIdleHistory.reportUsage(event.mPackage, userId,
                             STANDBY_BUCKET_ACTIVE,
-                            elapsedRealtime, elapsedRealtime + 2 * ONE_HOUR);
+                            elapsedRealtime, elapsedRealtime + mStrongUsageTimeoutMillis);
                 }
 
                 final boolean userStartedInteracting =
@@ -1114,10 +1120,10 @@
                 final PackageInfo pi = packages.get(i);
                 String packageName = pi.packageName;
                 if (pi.applicationInfo != null && pi.applicationInfo.isSystemApp()) {
-                    // Mark app as used for 4 hours. After that it can timeout to whatever the
+                    // Mark app as used for 2 hours. After that it can timeout to whatever the
                     // past usage pattern was.
                     mAppIdleHistory.reportUsage(packageName, userId, STANDBY_BUCKET_ACTIVE, 0,
-                            elapsedRealtime + 4 * ONE_HOUR);
+                            elapsedRealtime + mSystemUpdateUsageTimeoutMillis);
                 }
             }
         }
@@ -1396,6 +1402,12 @@
         private static final String KEY_PAROLE_DURATION = "parole_duration";
         private static final String KEY_SCREEN_TIME_THRESHOLDS = "screen_thresholds";
         private static final String KEY_ELAPSED_TIME_THRESHOLDS = "elapsed_thresholds";
+        private static final String KEY_STRONG_USAGE_HOLD_DURATION = "strong_usage_duration";
+        private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
+                "notification_seen_duration";
+        private static final String KEY_SYSTEM_UPDATE_HOLD_DURATION =
+                "system_update_usage_duration";
+
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -1456,7 +1468,15 @@
                         ELAPSED_TIME_THRESHOLDS);
                 mCheckIdleIntervalMillis = Math.min(mAppStandbyElapsedThresholds[1] / 4,
                         COMPRESS_TIME ? ONE_MINUTE : 4 * 60 * ONE_MINUTE); // 4 hours
-
+                mStrongUsageTimeoutMillis = mParser.getDurationMillis
+                        (KEY_STRONG_USAGE_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE : 1 * ONE_HOUR);
+                mNotificationSeenTimeoutMillis = mParser.getDurationMillis
+                        (KEY_NOTIFICATION_SEEN_HOLD_DURATION,
+                                COMPRESS_TIME ? 12 * ONE_MINUTE : 12 * ONE_HOUR);
+                mSystemUpdateUsageTimeoutMillis = mParser.getDurationMillis
+                        (KEY_SYSTEM_UPDATE_HOLD_DURATION,
+                                COMPRESS_TIME ? 2 * ONE_MINUTE : 2 * ONE_HOUR);
             }
         }
 
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index dcf5c27..1de67a5 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -33,47 +33,48 @@
 public final class DisconnectCause implements Parcelable {
 
     /** Disconnected because of an unknown or unspecified reason. */
-    public static final int UNKNOWN = 0;
+    public static final int UNKNOWN = TelecomProtoEnums.UNKNOWN; // = 0
     /** Disconnected because there was an error, such as a problem with the network. */
-    public static final int ERROR = 1;
+    public static final int ERROR = TelecomProtoEnums.ERROR; // = 1
     /** Disconnected because of a local user-initiated action, such as hanging up. */
-    public static final int LOCAL = 2;
+    public static final int LOCAL = TelecomProtoEnums.LOCAL; // = 2
     /**
      * Disconnected because of a remote user-initiated action, such as the other party hanging up
      * up.
      */
-    public static final int REMOTE = 3;
+    public static final int REMOTE = TelecomProtoEnums.REMOTE; // = 3
     /** Disconnected because it has been canceled. */
-    public static final int CANCELED = 4;
+    public static final int CANCELED = TelecomProtoEnums.CANCELED; // = 4
     /** Disconnected because there was no response to an incoming call. */
-    public static final int MISSED = 5;
+    public static final int MISSED = TelecomProtoEnums.MISSED; // = 5
     /** Disconnected because the user rejected an incoming call. */
-    public static final int REJECTED = 6;
+    public static final int REJECTED = TelecomProtoEnums.REJECTED; // = 6
     /** Disconnected because the other party was busy. */
-    public static final int BUSY = 7;
+    public static final int BUSY = TelecomProtoEnums.BUSY; // = 7
     /**
      * Disconnected because of a restriction on placing the call, such as dialing in airplane
      * mode.
      */
-    public static final int RESTRICTED = 8;
+    public static final int RESTRICTED = TelecomProtoEnums.RESTRICTED; // = 8
     /** Disconnected for reason not described by other disconnect codes. */
-    public static final int OTHER = 9;
+    public static final int OTHER = TelecomProtoEnums.OTHER; // = 9
     /**
      * Disconnected because the connection manager did not support the call. The call will be tried
      * again without a connection manager. See {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
      */
-    public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10;
+    public static final int CONNECTION_MANAGER_NOT_SUPPORTED =
+            TelecomProtoEnums.CONNECTION_MANAGER_NOT_SUPPORTED; // = 10
 
     /**
      * Disconnected because the user did not locally answer the incoming call, but it was answered
      * on another device where the call was ringing.
      */
-    public static final int ANSWERED_ELSEWHERE = 11;
+    public static final int ANSWERED_ELSEWHERE = TelecomProtoEnums.ANSWERED_ELSEWHERE; // = 11
 
     /**
      * Disconnected because the call was pulled from the current device to another device.
      */
-    public static final int CALL_PULLED = 12;
+    public static final int CALL_PULLED = TelecomProtoEnums.CALL_PULLED; // = 12
 
     /**
      * Reason code (returned via {@link #getReason()}) which indicates that a call could not be
diff --git a/tests/FrameworkPerf/AndroidManifest.xml b/tests/FrameworkPerf/AndroidManifest.xml
index 2591aaf..d62ef9e 100644
--- a/tests/FrameworkPerf/AndroidManifest.xml
+++ b/tests/FrameworkPerf/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworkperf">
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-sdk android:minSdkVersion="5" />
 
diff --git a/tests/OneMedia/AndroidManifest.xml b/tests/OneMedia/AndroidManifest.xml
index c6824ec..8697f1b 100644
--- a/tests/OneMedia/AndroidManifest.xml
+++ b/tests/OneMedia/AndroidManifest.xml
@@ -5,6 +5,7 @@
     android:versionName="1.0" >
 
     <uses-sdk android:minSdkVersion="19"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 669afe1..734a5ab 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4848,6 +4848,7 @@
     const String16 pathInterpolator16("pathInterpolator");
     const String16 objectAnimator16("objectAnimator");
     const String16 gradient16("gradient");
+    const String16 animatedSelector16("animated-selector");
 
     const int minSdk = getMinSdkVersion(bundle);
     if (minSdk >= SDK_LOLLIPOP_MR1) {
@@ -4876,7 +4877,8 @@
                     node->getElementName() == animatedVector16 ||
                     node->getElementName() == objectAnimator16 ||
                     node->getElementName() == pathInterpolator16 ||
-                    node->getElementName() == gradient16)) {
+                    node->getElementName() == gradient16 ||
+                    node->getElementName() == animatedSelector16)) {
             // We were told not to version vector tags, so skip the children here.
             continue;
         }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1afd283..15c5eae 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -450,7 +450,7 @@
 
 static bool IsVectorElement(const std::string& name) {
   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
-         name == "objectAnimator" || name == "gradient";
+         name == "objectAnimator" || name == "gradient" || name == "animated-selector";
 }
 
 template <typename T>
diff --git a/wifi/java/android/net/wifi/rtt/RangingRequest.java b/wifi/java/android/net/wifi/rtt/RangingRequest.java
index 32f21b9..52b3d86 100644
--- a/wifi/java/android/net/wifi/rtt/RangingRequest.java
+++ b/wifi/java/android/net/wifi/rtt/RangingRequest.java
@@ -156,14 +156,18 @@
         /**
          * Add the device specified by the {@code peerMacAddress} to the list of devices with
          * which to measure range.
-         *
+         * <p>
          * The MAC address may be obtained out-of-band from a peer Wi-Fi Aware device. A Wi-Fi
          * Aware device may obtain its MAC address using the {@link IdentityChangedListener}
          * provided to
          * {@link WifiAwareManager#attach(AttachCallback, IdentityChangedListener, Handler)}.
-         *
-         * * Note: in order to use this API the device must support Wi-Fi Aware
-         * {@link android.net.wifi.aware}.
+         * <p>
+         * Note: in order to use this API the device must support Wi-Fi Aware
+         * {@link android.net.wifi.aware}. The peer device which is being ranged to must be
+         * configured to publish a service (with any name) with:
+         * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}.
+         * <li>Ranging enabled
+         * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}.
          *
          * @param peerMacAddress The MAC address of the Wi-Fi Aware peer.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
@@ -179,12 +183,16 @@
         /**
          * Add a device specified by a {@link PeerHandle} to the list of devices with which to
          * measure range.
-         *
+         * <p>
          * The {@link PeerHandle} may be obtained as part of the Wi-Fi Aware discovery process. E.g.
          * using {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)}.
-         *
+         * <p>
          * Note: in order to use this API the device must support Wi-Fi Aware
-         * {@link android.net.wifi.aware}.
+         * {@link android.net.wifi.aware}. The peer device which is being ranged to must be
+         * configured to publish a service (with any name) with:
+         * <li>Type {@link android.net.wifi.aware.PublishConfig#PUBLISH_TYPE_UNSOLICITED}.
+         * <li>Ranging enabled
+         * {@link android.net.wifi.aware.PublishConfig.Builder#setRangingEnabled(boolean)}.
          *
          * @param peerHandle The peer handler of the peer Wi-Fi Aware device.
          * @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.