Merge "Update IpSecManager to use InetAddress and prefixLen" into pi-dev
diff --git a/Android.bp b/Android.bp
index ce93568..9c76e14 100644
--- a/Android.bp
+++ b/Android.bp
@@ -145,7 +145,7 @@
         ":libcamera_client_framework_aidl",
         "core/java/android/hardware/IConsumerIrService.aidl",
         "core/java/android/hardware/ISerialManager.aidl",
-        "core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl",
+        "core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
         "core/java/android/hardware/display/IDisplayManager.aidl",
         "core/java/android/hardware/display/IDisplayManagerCallback.aidl",
         "core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
diff --git a/api/current.txt b/api/current.txt
index 08f5d00..c351bee 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13658,17 +13658,17 @@
     method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
     method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
     method public int getAllocator();
-    method public boolean getConserveMemory();
     method public android.graphics.Rect getCrop();
+    method public int getMemorySizePolicy();
     method public android.graphics.ImageDecoder.OnPartialImageListener getOnPartialImageListener();
     method public android.graphics.PostProcessor getPostProcessor();
     method public boolean isDecodeAsAlphaMaskEnabled();
     method public boolean isMutableRequired();
     method public boolean isUnpremultipliedRequired();
     method public void setAllocator(int);
-    method public void setConserveMemory(boolean);
     method public void setCrop(android.graphics.Rect);
     method public void setDecodeAsAlphaMaskEnabled(boolean);
+    method public void setMemorySizePolicy(int);
     method public void setMutableRequired(boolean);
     method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
     method public void setPostProcessor(android.graphics.PostProcessor);
@@ -13680,6 +13680,8 @@
     field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
     field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
     field public static final int ALLOCATOR_SOFTWARE = 1; // 0x1
+    field public static final int MEMORY_POLICY_DEFAULT = 1; // 0x1
+    field public static final int MEMORY_POLICY_LOW_RAM = 0; // 0x0
   }
 
   public static final class ImageDecoder.DecodeException extends java.io.IOException {
@@ -15756,9 +15758,9 @@
 
 package android.hardware.biometrics {
 
-  public class BiometricDialog {
-    method public void authenticate(android.hardware.biometrics.BiometricDialog.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
-    method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricDialog.AuthenticationCallback);
+  public class BiometricPrompt {
+    method public void authenticate(android.hardware.biometrics.BiometricPrompt.CryptoObject, android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
+    method public void authenticate(android.os.CancellationSignal, java.util.concurrent.Executor, android.hardware.biometrics.BiometricPrompt.AuthenticationCallback);
     field public static final int BIOMETRIC_ACQUIRED_GOOD = 0; // 0x0
     field public static final int BIOMETRIC_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
     field public static final int BIOMETRIC_ACQUIRED_INSUFFICIENT = 2; // 0x2
@@ -15778,31 +15780,31 @@
     field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8
   }
 
-  public static abstract class BiometricDialog.AuthenticationCallback {
-    ctor public BiometricDialog.AuthenticationCallback();
+  public static abstract class BiometricPrompt.AuthenticationCallback {
+    ctor public BiometricPrompt.AuthenticationCallback();
     method public void onAuthenticationError(int, java.lang.CharSequence);
     method public void onAuthenticationFailed();
     method public void onAuthenticationHelp(int, java.lang.CharSequence);
-    method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricDialog.AuthenticationResult);
+    method public void onAuthenticationSucceeded(android.hardware.biometrics.BiometricPrompt.AuthenticationResult);
   }
 
-  public static class BiometricDialog.AuthenticationResult {
-    method public android.hardware.biometrics.BiometricDialog.CryptoObject getCryptoObject();
+  public static class BiometricPrompt.AuthenticationResult {
+    method public android.hardware.biometrics.BiometricPrompt.CryptoObject getCryptoObject();
   }
 
-  public static class BiometricDialog.Builder {
-    ctor public BiometricDialog.Builder(android.content.Context);
-    method public android.hardware.biometrics.BiometricDialog build();
-    method public android.hardware.biometrics.BiometricDialog.Builder setDescription(java.lang.CharSequence);
-    method public android.hardware.biometrics.BiometricDialog.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
-    method public android.hardware.biometrics.BiometricDialog.Builder setSubtitle(java.lang.CharSequence);
-    method public android.hardware.biometrics.BiometricDialog.Builder setTitle(java.lang.CharSequence);
+  public static class BiometricPrompt.Builder {
+    ctor public BiometricPrompt.Builder(android.content.Context);
+    method public android.hardware.biometrics.BiometricPrompt build();
+    method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(java.lang.CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(java.lang.CharSequence, java.util.concurrent.Executor, android.content.DialogInterface.OnClickListener);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(java.lang.CharSequence);
+    method public android.hardware.biometrics.BiometricPrompt.Builder setTitle(java.lang.CharSequence);
   }
 
-  public static final class BiometricDialog.CryptoObject {
-    ctor public BiometricDialog.CryptoObject(java.security.Signature);
-    ctor public BiometricDialog.CryptoObject(javax.crypto.Cipher);
-    ctor public BiometricDialog.CryptoObject(javax.crypto.Mac);
+  public static final class BiometricPrompt.CryptoObject {
+    ctor public BiometricPrompt.CryptoObject(java.security.Signature);
+    ctor public BiometricPrompt.CryptoObject(javax.crypto.Cipher);
+    ctor public BiometricPrompt.CryptoObject(javax.crypto.Mac);
     method public javax.crypto.Cipher getCipher();
     method public javax.crypto.Mac getMac();
     method public java.security.Signature getSignature();
@@ -36684,6 +36686,7 @@
     field public static final java.lang.String PARENTAL_CONTROL_ENABLED = "parental_control_enabled";
     field public static final java.lang.String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
     field public static final java.lang.String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
+    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
     field public static final java.lang.String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
     field public static final java.lang.String SETTINGS_CLASSNAME = "settings_classname";
     field public static final java.lang.String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
@@ -36789,7 +36792,6 @@
     field public static final deprecated java.lang.String RADIO_NFC = "nfc";
     field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
     field public static final java.lang.String RINGTONE = "ringtone";
-    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
     field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
     field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
     field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -38461,23 +38463,10 @@
 
   public abstract class ConfirmationCallback {
     ctor public ConfirmationCallback();
-    method public void onConfirmedByUser(byte[]);
-    method public void onDismissedByApplication();
-    method public void onDismissedByUser();
-    method public void onError(java.lang.Exception);
-  }
-
-  public class ConfirmationDialog {
-    method public void cancelPrompt();
-    method public static boolean isSupported();
-    method public void presentPrompt(java.util.concurrent.Executor, android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
-  }
-
-  public static class ConfirmationDialog.Builder {
-    ctor public ConfirmationDialog.Builder();
-    method public android.security.ConfirmationDialog build(android.content.Context);
-    method public android.security.ConfirmationDialog.Builder setExtraData(byte[]);
-    method public android.security.ConfirmationDialog.Builder setPromptText(java.lang.CharSequence);
+    method public void onCanceled();
+    method public void onConfirmed(byte[]);
+    method public void onDismissed();
+    method public void onError(java.lang.Throwable);
   }
 
   public class ConfirmationNotAvailableException extends java.lang.Exception {
@@ -38485,6 +38474,19 @@
     ctor public ConfirmationNotAvailableException(java.lang.String);
   }
 
+  public class ConfirmationPrompt {
+    method public void cancelPrompt();
+    method public static boolean isSupported(android.content.Context);
+    method public void presentPrompt(java.util.concurrent.Executor, android.security.ConfirmationCallback) throws android.security.ConfirmationAlreadyPresentingException, android.security.ConfirmationNotAvailableException;
+  }
+
+  public static final class ConfirmationPrompt.Builder {
+    ctor public ConfirmationPrompt.Builder(android.content.Context);
+    method public android.security.ConfirmationPrompt build();
+    method public android.security.ConfirmationPrompt.Builder setExtraData(byte[]);
+    method public android.security.ConfirmationPrompt.Builder setPromptText(java.lang.CharSequence);
+  }
+
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
diff --git a/api/removed.txt b/api/removed.txt
index af2b25e..1d6a8c2 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -178,10 +178,12 @@
 
   public final class ImageDecoder implements java.lang.AutoCloseable {
     method public deprecated boolean getAsAlphaMask();
+    method public deprecated boolean getConserveMemory();
     method public deprecated boolean getDecodeAsAlphaMask();
     method public deprecated boolean getMutable();
     method public deprecated boolean getRequireUnpremultiplied();
     method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
+    method public deprecated void setConserveMemory(boolean);
     method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
     method public deprecated android.graphics.ImageDecoder setMutable(boolean);
     method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 69e27f0..656001c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -163,6 +163,7 @@
     field public static final java.lang.String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
     field public static final java.lang.String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
     field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE";
+    field public static final java.lang.String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS";
     field public static final java.lang.String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION";
     field public static final java.lang.String SERIAL_PORT = "android.permission.SERIAL_PORT";
     field public static final java.lang.String SET_ACTIVITY_WATCHER = "android.permission.SET_ACTIVITY_WATCHER";
@@ -878,6 +879,7 @@
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     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 java.lang.String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
     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";
diff --git a/api/test-current.txt b/api/test-current.txt
index 9153a39..4878690 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -467,6 +467,14 @@
 
 }
 
+package android.media.audiofx {
+
+  public class AudioEffect {
+    field public static final java.util.UUID EFFECT_TYPE_NULL;
+  }
+
+}
+
 package android.net {
 
   public final class IpSecManager {
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 6cd2fe1..d753e5e 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -34,7 +34,7 @@
 void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) {
     uint8_t wireType = read_wire_type(fieldTag);
     size_t bytesToWrite = 0;
-    uint32_t varint = 0;
+    uint64_t varint = 0;
 
     switch (wireType) {
         case WIRE_TYPE_VARINT:
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 34a3613..20ecdb1 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -31,7 +31,7 @@
 namespace os {
 namespace incidentd {
 
-const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000;  // 10 seconds
+const int64_t REMOTE_CALL_TIMEOUT_MS = 30 * 1000;  // 30 seconds
 
 /**
  * Base class for sections
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index bc1c51a..8e46714 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -210,7 +210,8 @@
     tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp \
     tests/e2e/Anomaly_count_e2e_test.cpp \
     tests/e2e/Anomaly_duration_sum_e2e_test.cpp \
-    tests/e2e/ConfigTtl_e2e_test.cpp
+    tests/e2e/ConfigTtl_e2e_test.cpp \
+    tests/e2e/PartialBucket_e2e_test.cpp
 
 LOCAL_STATIC_LIBRARIES := \
     $(statsd_common_static_libraries) \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index de8dfe4..41527f6 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -158,7 +158,10 @@
 void StatsLogProcessor::OnLogEvent(LogEvent* event) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     const int64_t currentTimestampNs = event->GetElapsedTimestampNs();
+
     if (currentTimestampNs < mLastLogTimestamp) {
+        StatsdStats::getInstance().noteLogEventSkipped(
+            event->GetTagId(), event->GetElapsedTimestampNs());
         return;
     }
 
@@ -316,7 +319,7 @@
 
     // Fill in UidMap.
     uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP);
-    mUidMap->appendUidMap(key, proto);
+    mUidMap->appendUidMap(dumpTimeStampNs, key, proto);
     proto->end(uidMapToken);
 
     // Fill in the timestamps.
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index adc2664..dac73ef 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -640,7 +640,7 @@
                                          "Only system uid can call informAllUidData");
     }
 
-    mUidMap->updateMap(uid, version, app);
+    mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app);
     VLOG("StatsService::informAllUidData succeeded");
 
     return Status::ok();
@@ -653,7 +653,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackage");
     }
-    mUidMap->updateApp(app, uid, version);
+    mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version);
     return Status::ok();
 }
 
@@ -664,7 +664,7 @@
         return Status::fromExceptionCode(Status::EX_SECURITY,
                                          "Only system uid can call informOnePackageRemoved");
     }
-    mUidMap->removeApp(app, uid);
+    mUidMap->removeApp(getElapsedRealtimeNs(), app, uid);
     mConfigManager->RemoveConfigs(uid);
     return Status::ok();
 }
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 8d2fd33..a4552e1 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -262,6 +262,10 @@
     FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
+    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp);
+    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade);
+    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval);
+    FRIEND_TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 0c076e9..7b2881d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -49,21 +49,25 @@
 const int FIELD_ID_ANOMALY_ALARM_STATS = 9;
 // const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp
 const int FIELD_ID_LOGGER_ERROR_STATS = 11;
-const int FIELD_ID_SUBSCRIBER_ALARM_STATS = 12;
+const int FIELD_ID_PERIODIC_ALARM_STATS = 12;
+const int FIELD_ID_SKIPPED_LOG_EVENT_STATS = 13;
 
 const int FIELD_ID_ATOM_STATS_TAG = 1;
 const int FIELD_ID_ATOM_STATS_COUNT = 2;
 
 const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1;
-const int FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED = 1;
+const int FIELD_ID_PERIODIC_ALARMS_REGISTERED = 1;
 
 const int FIELD_ID_LOGGER_STATS_TIME = 1;
 const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2;
 
+const int FIELD_ID_SKIPPED_LOG_EVENT_STATS_TAG = 1;
+const int FIELD_ID_SKIPPED_LOG_EVENT_STATS_TIMESTAMP = 2;
+
 const int FIELD_ID_CONFIG_STATS_UID = 1;
 const int FIELD_ID_CONFIG_STATS_ID = 2;
 const int FIELD_ID_CONFIG_STATS_CREATION = 3;
-const int FIELD_ID_CONFIG_STATS_RESET = 18;
+const int FIELD_ID_CONFIG_STATS_RESET = 19;
 const int FIELD_ID_CONFIG_STATS_DELETION = 4;
 const int FIELD_ID_CONFIG_STATS_METRIC_COUNT = 5;
 const int FIELD_ID_CONFIG_STATS_CONDITION_COUNT = 6;
@@ -91,11 +95,10 @@
 const int FIELD_ID_ALERT_STATS_ID = 1;
 const int FIELD_ID_ALERT_STATS_COUNT = 2;
 
-const int FIELD_ID_UID_MAP_SNAPSHOTS = 1;
-const int FIELD_ID_UID_MAP_CHANGES = 2;
-const int FIELD_ID_UID_MAP_BYTES_USED = 3;
-const int FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS = 4;
-const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 5;
+const int FIELD_ID_UID_MAP_CHANGES = 1;
+const int FIELD_ID_UID_MAP_BYTES_USED = 2;
+const int FIELD_ID_UID_MAP_DROPPED_CHANGES = 3;
+const int FIELD_ID_UID_MAP_DELETED_APPS = 4;
 
 const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
         {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
@@ -229,15 +232,14 @@
     it->second->dump_report_time_sec.push_back(timeSec);
 }
 
-void StatsdStats::noteUidMapDropped(int snapshots, int deltas) {
+void StatsdStats::noteUidMapDropped(int deltas) {
     lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.dropped_snapshots += mUidMapStats.dropped_snapshots + snapshots;
     mUidMapStats.dropped_changes += mUidMapStats.dropped_changes + deltas;
 }
 
-void StatsdStats::setUidMapSnapshots(int snapshots) {
+void StatsdStats::noteUidMapAppDeletionDropped() {
     lock_guard<std::mutex> lock(mLock);
-    mUidMapStats.snapshots = snapshots;
+    mUidMapStats.deleted_apps++;
 }
 
 void StatsdStats::setUidMapChanges(int changes) {
@@ -346,6 +348,15 @@
     mPushedAtomStats[atomId]++;
 }
 
+void StatsdStats::noteLogEventSkipped(int tag, int64_t timestamp) {
+    lock_guard<std::mutex> lock(mLock);
+    // grows strictly one at a time. so it won't > kMaxSkippedLogEvents
+    if (mSkippedLogEvents.size() == kMaxSkippedLogEvents) {
+        mSkippedLogEvents.pop_front();
+    }
+    mSkippedLogEvents.push_back(std::make_pair(tag, timestamp));
+}
+
 void StatsdStats::noteLoggerError(int error) {
     lock_guard<std::mutex> lock(mLock);
     // grows strictly one at a time. so it won't > kMaxLoggerErrors
@@ -368,6 +379,7 @@
     mAnomalyAlarmRegisteredStats = 0;
     mPeriodicAlarmRegisteredStats = 0;
     mLoggerErrors.clear();
+    mSkippedLogEvents.clear();
     for (auto& config : mConfigStats) {
         config.second->broadcast_sent_time_sec.clear();
         config.second->data_drop_time_sec.clear();
@@ -478,11 +490,9 @@
         fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats);
     }
 
-    fprintf(out,
-            "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes "
-            "lost=%d\n",
-            mUidMapStats.bytes_used, mUidMapStats.snapshots, mUidMapStats.changes,
-            mUidMapStats.dropped_snapshots, mUidMapStats.dropped_changes);
+    fprintf(out, "UID map stats: bytes=%d, changes=%d, deleted=%d, changes lost=%d\n",
+            mUidMapStats.bytes_used, mUidMapStats.changes, mUidMapStats.deleted_apps,
+            mUidMapStats.dropped_changes);
 
     for (const auto& error : mLoggerErrors) {
         time_t error_time = error.first;
@@ -491,6 +501,9 @@
         strftime(buffer, sizeof(buffer), "%Y-%m-%d %I:%M%p\n", error_tm);
         fprintf(out, "Logger error %d at %s\n", error.second, buffer);
     }
+    for (const auto& skipped : mSkippedLogEvents) {
+        fprintf(out, "Log event (%d) skipped at %lld\n", skipped.first, (long long)skipped.second);
+    }
 }
 
 void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
@@ -617,19 +630,17 @@
     }
 
     if (mPeriodicAlarmRegisteredStats > 0) {
-        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SUBSCRIBER_ALARM_STATS);
-        proto.write(FIELD_TYPE_INT32 | FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED,
+        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_PERIODIC_ALARM_STATS);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_PERIODIC_ALARMS_REGISTERED,
                     mPeriodicAlarmRegisteredStats);
         proto.end(token);
     }
 
     uint64_t uidMapToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_UIDMAP_STATS);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_SNAPSHOTS, mUidMapStats.snapshots);
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_CHANGES, mUidMapStats.changes);
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_BYTES_USED, mUidMapStats.bytes_used);
-    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DROPPED_SNAPSHOTS,
-                mUidMapStats.dropped_snapshots);
     proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DROPPED_CHANGES, mUidMapStats.dropped_changes);
+    proto.write(FIELD_TYPE_INT32 | FIELD_ID_UID_MAP_DELETED_APPS, mUidMapStats.deleted_apps);
     proto.end(uidMapToken);
 
     for (const auto& error : mLoggerErrors) {
@@ -640,6 +651,15 @@
         proto.end(token);
     }
 
+    for (const auto& skipped : mSkippedLogEvents) {
+        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SKIPPED_LOG_EVENT_STATS |
+                                      FIELD_COUNT_REPEATED);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_SKIPPED_LOG_EVENT_STATS_TAG, skipped.first);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_SKIPPED_LOG_EVENT_STATS_TIMESTAMP,
+                    (long long)skipped.second);
+        proto.end(token);
+    }
+
     output->clear();
     size_t bufferSize = proto.size();
     output->resize(bufferSize);
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 00bef75..914d2af 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -73,11 +73,10 @@
 };
 
 struct UidMapStats {
-    int32_t snapshots;
     int32_t changes;
     int32_t bytes_used;
-    int32_t dropped_snapshots;
     int32_t dropped_changes;
+    int32_t deleted_apps = 0;
 };
 
 // Keeps track of stats of statsd.
@@ -105,6 +104,8 @@
 
     const static int kMaxLoggerErrors = 10;
 
+    const static int kMaxSkippedLogEvents = 200;
+
     const static int kMaxTimestampCount = 20;
 
     const static int kMaxLogSourceCount = 50;
@@ -121,6 +122,9 @@
     // is critical for understanding the metrics.
     const static size_t kMaxBytesUsedUidMap = 50 * 1024;
 
+    // The number of deleted apps that are stored in the uid map.
+    const static int kMaxDeletedAppsInUidMap = 100;
+
     /* Minimum period between two broadcasts in nanoseconds. */
     static const int64_t kMinBroadcastPeriodNs = 60 * NS_PER_SEC;
 
@@ -244,14 +248,18 @@
     void noteRegisteredPeriodicAlarmChanged();
 
     /**
-     * Records the number of snapshot and delta entries that are being dropped from the uid map.
+     * Records the number of delta entries that are being dropped from the uid map.
      */
-    void noteUidMapDropped(int snapshots, int deltas);
+    void noteUidMapDropped(int deltas);
 
     /**
-     * Updates the number of snapshots currently stored in the uid map.
+     * Records that an app was deleted (from statsd's map).
      */
-    void setUidMapSnapshots(int snapshots);
+    void noteUidMapAppDeletionDropped();
+
+    /**
+     * Updates the number of changes currently stored in the uid map.
+     */
     void setUidMapChanges(int changes);
     void setCurrentUidMapMemory(int bytes);
 
@@ -270,6 +278,11 @@
     void noteLoggerError(int error);
 
     /**
+     * Records statsd skipped an event.
+     */
+    void noteLogEventSkipped(int tag, int64_t timestamp);
+
+    /**
      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
      * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
      * to collect stats after reset() has been called.
@@ -324,6 +337,9 @@
     // Logd errors. Size capped by kMaxLoggerErrors.
     std::list<const std::pair<int, int>> mLoggerErrors;
 
+    // Skipped log events.
+    std::list<const std::pair<int, int64_t>> mSkippedLogEvents;
+
     // Stores the number of times statsd modified the anomaly alarm registered with
     // StatsCompanionService.
     int mAnomalyAlarmRegisteredStats = 0;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 139a407..db5d32c 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -80,11 +80,13 @@
     };
 
     void notifyAppRemoved(const int64_t& eventTimeNs, const string& apk, const int uid) override{
-            // TODO: Implement me.
+        // Force buckets to split on removal also.
+        notifyAppUpgrade(eventTimeNs, apk, uid, 0);
     };
 
     void onUidMapReceived(const int64_t& eventTimeNs) override{
-            // TODO: Implement me.
+            // Purposefully don't flush partial buckets on a new snapshot.
+            // This occurs if a new user is added/removed or statsd crashes.
     };
 
     // Consume the parsed stats log entry that already matched the "what" of the metric.
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index b7c5795..566d34e 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -263,15 +263,14 @@
 }
 
 bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
-                 const unordered_map<int64_t, int>& logTrackerMap,
+                 UidMap& uidMap, const unordered_map<int64_t, int>& logTrackerMap,
                  const unordered_map<int64_t, int>& conditionTrackerMap,
                  const vector<sp<LogMatchingTracker>>& allAtomMatchers,
                  vector<sp<ConditionTracker>>& allConditionTrackers,
                  vector<sp<MetricProducer>>& allMetricProducers,
                  unordered_map<int, std::vector<int>>& conditionToMetricMap,
                  unordered_map<int, std::vector<int>>& trackerToMetricMap,
-                 unordered_map<int64_t, int>& metricMap,
-                 std::set<int64_t> &noReportMetricIds) {
+                 unordered_map<int64_t, int>& metricMap, std::set<int64_t>& noReportMetricIds) {
     sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
     const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
                                 config.event_metric_size() + config.value_metric_size();
@@ -538,6 +537,9 @@
         }
         noReportMetricIds.insert(no_report_metric);
     }
+    for (auto it : allMetricProducers) {
+        uidMap.addListener(it);
+    }
     return true;
 }
 
@@ -642,12 +644,10 @@
     return true;
 }
 
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
-                      const UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
                       const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor,
-                      const long timeBaseSec, const long currentTimeSec,
-                      set<int>& allTagIds,
+                      const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
+                      const long currentTimeSec, set<int>& allTagIds,
                       vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       vector<sp<ConditionTracker>>& allConditionTrackers,
                       vector<sp<MetricProducer>>& allMetricProducers,
@@ -656,7 +656,7 @@
                       unordered_map<int, std::vector<int>>& conditionToMetricMap,
                       unordered_map<int, std::vector<int>>& trackerToMetricMap,
                       unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                      std::set<int64_t> &noReportMetricIds) {
+                      std::set<int64_t>& noReportMetricIds) {
     unordered_map<int64_t, int> logTrackerMap;
     unordered_map<int64_t, int> conditionTrackerMap;
     unordered_map<int64_t, int> metricProducerMap;
@@ -673,9 +673,10 @@
         return false;
     }
 
-    if (!initMetrics(key, config, timeBaseSec, logTrackerMap, conditionTrackerMap, allAtomMatchers,
-                     allConditionTrackers, allMetricProducers, conditionToMetricMap,
-                     trackerToMetricMap, metricProducerMap, noReportMetricIds)) {
+    if (!initMetrics(key, config, timeBaseSec, uidMap, logTrackerMap, conditionTrackerMap,
+                     allAtomMatchers, allConditionTrackers, allMetricProducers,
+                     conditionToMetricMap, trackerToMetricMap, metricProducerMap,
+                     noReportMetricIds)) {
         ALOGE("initMetricProducers failed");
         return false;
     }
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 3754ae0..0ebdcf9 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -81,7 +81,7 @@
 //                          the list of MetricProducer index
 // [trackerToMetricMap]: contains the mapping from log tracker to MetricProducer index.
 bool initMetrics(
-        const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec,
+        const ConfigKey& key, const StatsdConfig& config, const long timeBaseSec, UidMap& uidMap,
         const std::unordered_map<int64_t, int>& logTrackerMap,
         const std::unordered_map<int64_t, int>& conditionTrackerMap,
         const std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
@@ -90,16 +90,14 @@
         std::vector<sp<MetricProducer>>& allMetricProducers,
         std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
         std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
-        std::set<int64_t> &noReportMetricIds);
+        std::set<int64_t>& noReportMetricIds);
 
 // Initialize MetricsManager from StatsdConfig.
 // Parameters are the members of MetricsManager. See MetricsManager for declaration.
-bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config,
-                      const UidMap& uidMap,
+bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap& uidMap,
                       const sp<AlarmMonitor>& anomalyAlarmMonitor,
-                      const sp<AlarmMonitor>& periodicAlarmMonitor,
-                      const long timeBaseSec, const long currentTimeSec,
-                      std::set<int>& allTagIds,
+                      const sp<AlarmMonitor>& periodicAlarmMonitor, const long timeBaseSec,
+                      const long currentTimeSec, std::set<int>& allTagIds,
                       std::vector<sp<LogMatchingTracker>>& allAtomMatchers,
                       std::vector<sp<ConditionTracker>>& allConditionTrackers,
                       std::vector<sp<MetricProducer>>& allMetricProducers,
@@ -108,7 +106,7 @@
                       std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
                       std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
                       std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
-                      std::set<int64_t> &noReportMetricIds);
+                      std::set<int64_t>& noReportMetricIds);
 
 bool isStateTracker(const SimplePredicate& simplePredicate, std::vector<Matcher>* primaryKeys);
 
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 8c8152d..b3425a4 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -45,6 +45,7 @@
 const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1;
 const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2;
 const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3;
+const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4;
 const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1;
 const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2;
 const int FIELD_ID_SNAPSHOTS = 1;
@@ -53,7 +54,8 @@
 const int FIELD_ID_CHANGE_TIMESTAMP = 2;
 const int FIELD_ID_CHANGE_PACKAGE = 3;
 const int FIELD_ID_CHANGE_UID = 4;
-const int FIELD_ID_CHANGE_VERSION = 5;
+const int FIELD_ID_CHANGE_NEW_VERSION = 5;
+const int FIELD_ID_CHANGE_PREV_VERSION = 6;
 
 UidMap::UidMap() : mBytesUsed(0) {}
 
@@ -62,13 +64,8 @@
 bool UidMap::hasApp(int uid, const string& packageName) const {
     lock_guard<mutex> lock(mMutex);
 
-    auto range = mMap.equal_range(uid);
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == packageName) {
-            return true;
-        }
-    }
-    return false;
+    auto it = mMap.find(std::make_pair(uid, packageName));
+    return it != mMap.end() && !it->second.deleted;
 }
 
 string UidMap::normalizeAppName(const string& appName) const {
@@ -84,10 +81,10 @@
 
 std::set<string> UidMap::getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const {
     std::set<string> names;
-    auto range = mMap.equal_range(uid);
-    for (auto it = range.first; it != range.second; ++it) {
-        names.insert(returnNormalized ?
-            normalizeAppName(it->second.packageName) : it->second.packageName);
+    for (const auto& kv : mMap) {
+        if (kv.first.first == uid && !kv.second.deleted) {
+            names.insert(returnNormalized ? normalizeAppName(kv.first.second) : kv.first.second);
+        }
     }
     return names;
 }
@@ -95,18 +92,11 @@
 int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
     lock_guard<mutex> lock(mMutex);
 
-    auto range = mMap.equal_range(uid);
-    for (auto it = range.first; it != range.second; ++it) {
-        if (it->second.packageName == packageName) {
-            return it->second.versionCode;
-        }
+    auto it = mMap.find(std::make_pair(uid, packageName));
+    if (it == mMap.end() || it->second.deleted) {
+        return 0;
     }
-    return 0;
-}
-
-void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
-                       const vector<String16>& packageName) {
-    updateMap(getElapsedRealtimeNs(), uid, versionCode, packageName);
+    return it->second.versionCode;
 }
 
 void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
@@ -115,20 +105,31 @@
     {
         lock_guard<mutex> lock(mMutex);  // Exclusively lock for updates.
 
-        mMap.clear();
-        vector<const SnapshotPackageInfo> infos;
-        for (size_t j = 0; j < uid.size(); j++) {
-            string package = string(String8(packageName[j]).string());
-            mMap.insert(make_pair(uid[j], AppData(package, versionCode[j])));
-            infos.emplace_back(package, versionCode[j], uid[j]);
+        std::unordered_map<std::pair<int, string>, AppData, PairHash> deletedApps;
+
+        // Copy all the deleted apps.
+        for (const auto& kv : mMap) {
+            if (kv.second.deleted) {
+                deletedApps[kv.first] = kv.second;
+            }
         }
 
-        mSnapshots.emplace_back(timestamp, infos);
+        mMap.clear();
+        for (size_t j = 0; j < uid.size(); j++) {
+            string package = string(String8(packageName[j]).string());
+            mMap[std::make_pair(uid[j], package)] = AppData(versionCode[j]);
+        }
 
-        mBytesUsed += mSnapshots.back().bytes;
+        for (const auto& kv : deletedApps) {
+            auto mMapIt = mMap.find(kv.first);
+            if (mMapIt != mMap.end()) {
+                // Insert this deleted app back into the current map.
+                mMap[kv.first] = kv.second;
+            }
+        }
+
         ensureBytesUsedBelowLimit();
         StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
-        StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
         getListenerListCopyLocked(&broadcastList);
     }
     // To avoid invoking callback while holding the internal lock. we get a copy of the listener
@@ -144,38 +145,34 @@
     }
 }
 
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
-    updateApp(getElapsedRealtimeNs(), app_16, uid, versionCode);
-}
-
 void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
                        const int64_t& versionCode) {
     vector<wp<PackageInfoListener>> broadcastList;
     string appName = string(String8(app_16).string());
     {
         lock_guard<mutex> lock(mMutex);
-
-        mChanges.emplace_back(false, timestamp, appName, uid, versionCode);
+        int32_t prevVersion = 0;
+        bool found = false;
+        auto it = mMap.find(std::make_pair(uid, appName));
+        if (it != mMap.end()) {
+            found = true;
+            prevVersion = it->second.versionCode;
+            it->second.versionCode = versionCode;
+            it->second.deleted = false;
+        }
+        if (!found) {
+            // Otherwise, we need to add an app at this uid.
+            mMap[std::make_pair(uid, appName)] = AppData(versionCode);
+        } else {
+            // Only notify the listeners if this is an app upgrade. If this app is being installed
+            // for the first time, then we don't notify the listeners.
+            getListenerListCopyLocked(&broadcastList);
+        }
+        mChanges.emplace_back(false, timestamp, appName, uid, versionCode, prevVersion);
         mBytesUsed += kBytesChangeRecord;
         ensureBytesUsedBelowLimit();
         StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
         StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-
-        auto range = mMap.equal_range(int(uid));
-        bool found = false;
-        for (auto it = range.first; it != range.second; ++it) {
-            // If we find the exact same app name and uid, update the app version directly.
-            if (it->second.packageName == appName) {
-                it->second.versionCode = versionCode;
-                found = true;
-                break;
-            }
-        }
-        if (!found) {
-            // Otherwise, we need to add an app at this uid.
-            mMap.insert(make_pair(uid, AppData(appName, versionCode)));
-        }
-        getListenerListCopyLocked(&broadcastList);
     }
 
     for (auto weakPtr : broadcastList) {
@@ -195,22 +192,14 @@
     }
     while (mBytesUsed > limit) {
         ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit);
-        if (mSnapshots.size() > 0) {
-            mBytesUsed -= mSnapshots.front().bytes;
-            mSnapshots.pop_front();
-            StatsdStats::getInstance().noteUidMapDropped(1, 0);
-        } else if (mChanges.size() > 0) {
+        if (mChanges.size() > 0) {
             mBytesUsed -= kBytesChangeRecord;
             mChanges.pop_front();
-            StatsdStats::getInstance().noteUidMapDropped(0, 1);
+            StatsdStats::getInstance().noteUidMapDropped(1);
         }
     }
 }
 
-void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
-    removeApp(getElapsedRealtimeNs(), app_16, uid);
-}
-
 void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) {
     for (auto weakIt = mSubscribers.begin(); weakIt != mSubscribers.end();) {
         auto strongPtr = weakIt->promote();
@@ -230,19 +219,26 @@
     {
         lock_guard<mutex> lock(mMutex);
 
-        mChanges.emplace_back(true, timestamp, app, uid, 0);
+        int32_t prevVersion = 0;
+        auto key = std::make_pair(uid, app);
+        auto it = mMap.find(key);
+        if (it != mMap.end() && !it->second.deleted) {
+            prevVersion = it->second.versionCode;
+            it->second.deleted = true;
+            mDeletedApps.push_back(key);
+        }
+        if (mDeletedApps.size() > StatsdStats::kMaxDeletedAppsInUidMap) {
+            // Delete the oldest one.
+            auto oldest = mDeletedApps.front();
+            mDeletedApps.pop_front();
+            mMap.erase(oldest);
+            StatsdStats::getInstance().noteUidMapAppDeletionDropped();
+        }
+        mChanges.emplace_back(true, timestamp, app, uid, 0, prevVersion);
         mBytesUsed += kBytesChangeRecord;
         ensureBytesUsedBelowLimit();
         StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
         StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-
-        auto range = mMap.equal_range(int(uid));
-        for (auto it = range.first; it != range.second; ++it) {
-            if (it->second.packageName == app) {
-                mMap.erase(it);
-                break;
-            }
-        }
         getListenerListCopyLocked(&broadcastList);
     }
 
@@ -290,22 +286,20 @@
 }
 
 void UidMap::clearOutput() {
-    mSnapshots.clear();
     mChanges.clear();
     // Also update the guardrail trackers.
     StatsdStats::getInstance().setUidMapChanges(0);
-    StatsdStats::getInstance().setUidMapSnapshots(1);
     mBytesUsed = 0;
     StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
 }
 
 int64_t UidMap::getMinimumTimestampNs() {
     int64_t m = 0;
-    for (auto it : mLastUpdatePerConfigKey) {
+    for (const auto& kv : mLastUpdatePerConfigKey) {
         if (m == 0) {
-            m = it.second;
-        } else if (it.second < m) {
-            m = it.second;
+            m = kv.second;
+        } else if (kv.second < m) {
+            m = kv.second;
         }
     }
     return m;
@@ -315,10 +309,6 @@
     return mBytesUsed;
 }
 
-void UidMap::appendUidMap(const ConfigKey& key, ProtoOutputStream* proto) {
-    appendUidMap(getElapsedRealtimeNs(), key, proto);
-}
-
 void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key,
                           ProtoOutputStream* proto) {
     lock_guard<mutex> lock(mMutex);  // Lock for updates
@@ -332,34 +322,27 @@
                          (long long)record.timestampNs);
             proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package);
             proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid);
-            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_VERSION, (int)record.version);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_NEW_VERSION, (int)record.version);
+            proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_PREV_VERSION, (int)record.prevVersion);
             proto->end(changesToken);
         }
     }
 
-    bool atLeastOneSnapshot = false;
-    unsigned int count = 0;
-    for (const SnapshotRecord& record : mSnapshots) {
-        // Ensure that we include at least the latest snapshot.
-        if ((count == mSnapshots.size() - 1 && !atLeastOneSnapshot) ||
-            record.timestampNs > mLastUpdatePerConfigKey[key]) {
-            uint64_t snapshotsToken =
-                    proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
-            atLeastOneSnapshot = true;
-            count++;
-            proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP,
-                         (long long)record.timestampNs);
-            for (const SnapshotPackageInfo& info : record.infos) {
-                uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
-                                              FIELD_ID_SNAPSHOT_PACKAGE_INFO);
-                proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, info.package);
-                proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, info.version);
-                proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, info.uid);
-                proto->end(token);
-            }
-            proto->end(snapshotsToken);
-        }
+    // Write snapshot from current uid map state.
+    uint64_t snapshotsToken =
+            proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS);
+    proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp);
+    for (const auto& kv : mMap) {
+        uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                      FIELD_ID_SNAPSHOT_PACKAGE_INFO);
+        proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second);
+        proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION,
+                     (int)kv.second.versionCode);
+        proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first);
+        proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted);
+        proto->end(token);
     }
+    proto->end(snapshotsToken);
 
     int64_t prevMin = getMinimumTimestampNs();
     mLastUpdatePerConfigKey[key] = timestamp;
@@ -368,14 +351,6 @@
     if (newMin > prevMin) {  // Delete anything possible now that the minimum has
                              // moved forward.
         int64_t cutoff_nanos = newMin;
-        for (auto it_snapshots = mSnapshots.begin(); it_snapshots != mSnapshots.end();) {
-            if (it_snapshots->timestampNs < cutoff_nanos) {
-                mBytesUsed -= it_snapshots->bytes;
-                it_snapshots = mSnapshots.erase(it_snapshots);
-            } else {
-                ++it_snapshots;
-            }
-        }
         for (auto it_changes = mChanges.begin(); it_changes != mChanges.end();) {
             if (it_changes->timestampNs < cutoff_nanos) {
                 mBytesUsed -= kBytesChangeRecord;
@@ -384,53 +359,24 @@
                 ++it_changes;
             }
         }
-
-        if (mSnapshots.size() == 0) {
-            // Produce another snapshot. This results in extra data being uploaded but
-            // helps ensure we can re-construct the UID->app name, versionCode mapping
-            // in server.
-            vector<const SnapshotPackageInfo> infos;
-            for (const auto& it : mMap) {
-                infos.emplace_back(it.second.packageName, it.second.versionCode, it.first);
-            }
-
-            mSnapshots.emplace_back(timestamp, infos);
-            mBytesUsed += mSnapshots.back().bytes;
-        }
     }
     StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed);
     StatsdStats::getInstance().setUidMapChanges(mChanges.size());
-    StatsdStats::getInstance().setUidMapSnapshots(mSnapshots.size());
 }
 
 void UidMap::printUidMap(FILE* out) const {
     lock_guard<mutex> lock(mMutex);
 
-    for (auto it : mMap) {
-        fprintf(out, "%s, v%" PRId64 " (%i)\n", it.second.packageName.c_str(),
-                it.second.versionCode, it.first);
+    for (const auto& kv : mMap) {
+        if (!kv.second.deleted) {
+            fprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode,
+                    kv.first.first);
+        }
     }
 }
 
 void UidMap::OnConfigUpdated(const ConfigKey& key) {
     mLastUpdatePerConfigKey[key] = -1;
-
-    // Ensure there is at least one snapshot available since this configuration also needs to know
-    // what all the uid's represent.
-    if (mSnapshots.size() == 0) {
-        sp<IStatsCompanionService> statsCompanion = nullptr;
-        // Get statscompanion service from service manager
-        const sp<IServiceManager> sm(defaultServiceManager());
-        if (sm != nullptr) {
-            const String16 name("statscompanion");
-            statsCompanion = interface_cast<IStatsCompanionService>(sm->checkService(name));
-            if (statsCompanion == nullptr) {
-                ALOGW("statscompanion service unavailable!");
-                return;
-            }
-            statsCompanion->triggerUidSnapshot();
-        }
-    }
 }
 
 void UidMap::OnConfigRemoved(const ConfigKey& key) {
@@ -441,9 +387,9 @@
     lock_guard<mutex> lock(mMutex);
 
     set<int32_t> results;
-    for (const auto& pair : mMap) {
-        if (pair.second.packageName == package) {
-            results.insert(pair.first);
+    for (const auto& kv : mMap) {
+        if (kv.first.second == package && !kv.second.deleted) {
+            results.insert(kv.first.first);
         }
     }
     return results;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index a3632d2..7222e85 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -43,10 +43,13 @@
 namespace statsd {
 
 struct AppData {
-    const string packageName;
     int64_t versionCode;
+    bool deleted;
 
-    AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
+    // Empty constructor needed for unordered map.
+    AppData() {
+    }
+    AppData(const int64_t v) : versionCode(v), deleted(false){};
 };
 
 // When calling appendUidMap, we retrieve all the ChangeRecords since the last
@@ -57,55 +60,21 @@
     const string package;
     const int32_t uid;
     const int32_t version;
+    const int32_t prevVersion;
 
     ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package,
-                 const int32_t uid, const int32_t version)
+                 const int32_t uid, const int32_t version, const int32_t prevVersion)
         : deletion(isDeletion),
           timestampNs(timestampNs),
           package(package),
           uid(uid),
-          version(version) {
+          version(version),
+          prevVersion(prevVersion) {
     }
 };
 
 const unsigned int kBytesChangeRecord = sizeof(struct ChangeRecord);
 
-// Storing the int64 for a timestamp is expected to take 10 bytes (could take
-// less because of varint encoding).
-const unsigned int kBytesTimestampField = 10;
-
-struct SnapshotPackageInfo {
-    const string package;
-    const int32_t version;
-    const int32_t uid;
-    SnapshotPackageInfo(const string& package, const int32_t version, const int32_t uid)
-        : package(package), version(version), uid(uid) {
-    }
-};
-
-const unsigned int kBytesSnapshotInfo = sizeof(struct SnapshotPackageInfo);
-
-// When calling appendUidMap, we retrieve all the snapshots since the last
-// timestamp we called appendUidMap for this configuration key.
-struct SnapshotRecord {
-    const int64_t timestampNs;
-
-    // All the package info known.
-    vector<const SnapshotPackageInfo> infos;
-
-    // Tracks the number of bytes this snapshot consumes.
-    uint32_t bytes;
-
-    SnapshotRecord(const int64_t timestampNs, vector<const SnapshotPackageInfo>& infos)
-        : timestampNs(timestampNs), infos(infos) {
-        bytes = 0;
-        for (auto info : infos) {
-            bytes += info.package.size() + kBytesSnapshotInfo;
-        }
-        bytes += kBytesTimestampField;
-    }
-};
-
 // UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
 // at any given moment. This map must be updated by StatsCompanionService.
 class UidMap : public virtual android::RefBase {
@@ -117,11 +86,12 @@
      * All three inputs must be the same size, and the jth element in each array refers to the same
      * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
      */
-    void updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
-                   const vector<String16>& packageName);
+    void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
+                   const vector<int64_t>& versionCode, const vector<String16>& packageName);
 
-    void updateApp(const String16& packageName, const int32_t& uid, const int64_t& versionCode);
-    void removeApp(const String16& packageName, const int32_t& uid);
+    void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
+                   const int64_t& versionCode);
+    void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
 
     // Returns true if the given uid contains the specified app (eg. com.google.android.gms).
     bool hasApp(int uid, const string& packageName) const;
@@ -157,7 +127,8 @@
     // Gets all snapshots and changes that have occurred since the last output.
     // If every config key has received a change or snapshot record, then this
     // record is deleted.
-    void appendUidMap(const ConfigKey& key, util::ProtoOutputStream* proto);
+    void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
+                      util::ProtoOutputStream* proto);
 
     // Forces the output to be cleared. We still generate a snapshot based on the current state.
     // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
@@ -173,25 +144,20 @@
     std::set<string> getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const;
     string normalizeAppName(const string& appName) const;
 
-    void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
-                   const vector<int64_t>& versionCode, const vector<String16>& packageName);
-
-    void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
-                   const int64_t& versionCode);
-    void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
-
-    void appendUidMap(const int64_t& timestamp, const ConfigKey& key,
-                      util::ProtoOutputStream* proto);
-
     void getListenerListCopyLocked(std::vector<wp<PackageInfoListener>>* output);
 
     // TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
     mutable mutex mMutex;
     mutable mutex mIsolatedMutex;
 
-    // Maps uid to application data. This must be multimap since there is a feature in Android for
-    // multiple apps to share the same uid.
-    std::unordered_multimap<int, AppData> mMap;
+    struct PairHash {
+        size_t operator()(std::pair<int, string> p) const noexcept {
+            std::hash<std::string> hash_fn;
+            return hash_fn(std::to_string(p.first) + p.second);
+        }
+    };
+    // Maps uid and package name to application data.
+    std::unordered_map<std::pair<int, string>, AppData, PairHash> mMap;
 
     // Maps isolated uid to the parent uid. Any metrics for an isolated uid will instead contribute
     // to the parent uid.
@@ -200,8 +166,8 @@
     // Record the changes that can be provided with the uploads.
     std::list<ChangeRecord> mChanges;
 
-    // Record the snapshots that can be provided with the uploads.
-    std::list<SnapshotRecord> mSnapshots;
+    // Store which uid and apps represent deleted ones.
+    std::list<std::pair<int, string>> mDeletedApps;
 
     // Metric producers that should be notified if there's an upgrade in any app.
     set<wp<PackageInfoListener>> mSubscribers;
@@ -228,6 +194,8 @@
 
     // Allows unit-test to access private methods.
     FRIEND_TEST(UidMapTest, TestClearingOutput);
+    FRIEND_TEST(UidMapTest, TestRemovedAppRetained);
+    FRIEND_TEST(UidMapTest, TestRemovedAppOverGuardrail);
     FRIEND_TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot);
     FRIEND_TEST(UidMapTest, TestMemoryComputed);
     FRIEND_TEST(UidMapTest, TestMemoryGuardrail);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 4aa3c973..3b86d2d 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -155,6 +155,8 @@
             optional int64 version = 2;
 
             optional int32 uid = 3;
+
+            optional bool deleted = 4;
         }
         optional int64 elapsed_timestamp_nanos = 1;
 
@@ -169,7 +171,8 @@
         optional string app = 3;
         optional int32 uid = 4;
 
-        optional int64 version = 5;
+        optional int64 new_version = 5;
+        optional int64 prev_version = 6;
     }
     repeated Change changes = 2;
 }
@@ -266,11 +269,10 @@
     repeated AtomStats atom_stats = 7;
 
     message UidMapStats {
-        optional int32 snapshots = 1;
-        optional int32 changes = 2;
-        optional int32 bytes_used = 3;
-        optional int32 dropped_snapshots = 4;
-        optional int32 dropped_changes = 5;
+        optional int32 changes = 1;
+        optional int32 bytes_used = 2;
+        optional int32 dropped_changes = 3;
+        optional int32 deleted_apps = 4;
     }
     optional UidMapStats uidmap_stats = 8;
 
@@ -292,4 +294,15 @@
         optional int32 error_code = 2;
     }
     repeated LoggerErrorStats logger_error_stats = 11;
+
+    message PeriodicAlarmStats {
+        optional int32 alarms_registered = 1;
+    }
+    optional PeriodicAlarmStats periodic_alarm_stats = 12;
+
+    message  SkippedLogEventStats {
+        optional int32 tag = 1;
+        optional int64 elapsed_timestamp_nanos = 2;
+    }
+    repeated SkippedLogEventStats skipped_log_event_stats = 13;
 }
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index b0da07b..4c6671d 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -146,11 +146,10 @@
     attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)->set_eq_string("pkg0");
     EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event));
 
-    uidMap.updateMap({1111, 1111, 2222, 3333, 3333} /* uid list */,
-        {1, 1, 2, 1, 2} /* version list */,
-        {android::String16("pkg0"), android::String16("pkg1"),
-         android::String16("pkg1"), android::String16("Pkg2"),
-         android::String16("PkG3")} /* package name list */);
+    uidMap.updateMap(
+            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+            {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
+             android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
 
     EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event));
     attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0)
@@ -297,7 +296,7 @@
 TEST(AtomMatcherTest, TestNeqAnyStringMatcher) {
     UidMap uidMap;
     uidMap.updateMap(
-            {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
             {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
              android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
 
@@ -372,7 +371,7 @@
 TEST(AtomMatcherTest, TestEqAnyStringMatcher) {
     UidMap uidMap;
     uidMap.updateMap(
-            {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
+            1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */,
             {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"),
              android::String16("Pkg2"), android::String16("PkG3")} /* package name list */);
 
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index e6fe3d8..09daf75 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -126,7 +126,7 @@
 TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) {
     // Setup simple config key corresponding to empty config.
     sp<UidMap> m = new UidMap();
-    m->updateMap({1, 2}, {1, 2}, {String16("p1"), String16("p2")});
+    m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")});
     sp<AlarmMonitor> anomalyAlarmMonitor;
     sp<AlarmMonitor> subscriberAlarmMonitor;
     int broadcastCount = 0;
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index a9b67e0..2fab975 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -76,7 +76,7 @@
     apps.push_back(String16(kApp2.c_str()));
     versions.push_back(4);
     versions.push_back(5);
-    m.updateMap(uids, versions, apps);
+    m.updateMap(1, uids, versions, apps);
     EXPECT_TRUE(m.hasApp(1000, kApp1));
     EXPECT_TRUE(m.hasApp(1000, kApp2));
     EXPECT_FALSE(m.hasApp(1000, "not.app"));
@@ -102,7 +102,7 @@
     apps.push_back(String16(kApp2.c_str()));
     versions.push_back(4);
     versions.push_back(5);
-    m.updateMap(uids, versions, apps);
+    m.updateMap(1, uids, versions, apps);
 
     std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
     EXPECT_EQ(name_set.size(), 2u);
@@ -110,7 +110,7 @@
     EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
 
     // Update the app1 version.
-    m.updateApp(String16(kApp1.c_str()), 1000, 40);
+    m.updateApp(2, String16(kApp1.c_str()), 1000, 40);
     EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
 
     name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -118,7 +118,7 @@
     EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
     EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
 
-    m.removeApp(String16(kApp1.c_str()), 1000);
+    m.removeApp(3, String16(kApp1.c_str()), 1000);
     EXPECT_FALSE(m.hasApp(1000, kApp1));
     EXPECT_TRUE(m.hasApp(1000, kApp2));
     name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -127,7 +127,7 @@
     EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
 
     // Remove app2.
-    m.removeApp(String16(kApp2.c_str()), 1000);
+    m.removeApp(4, String16(kApp2.c_str()), 1000);
     EXPECT_FALSE(m.hasApp(1000, kApp1));
     EXPECT_FALSE(m.hasApp(1000, kApp2));
     name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
@@ -136,14 +136,14 @@
 
 TEST(UidMapTest, TestUpdateApp) {
     UidMap m;
-    m.updateMap({1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())});
+    m.updateMap(1, {1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())});
     std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
     EXPECT_EQ(name_set.size(), 2u);
     EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
     EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
 
     // Adds a new name for uid 1000.
-    m.updateApp(String16("NeW_aPP1_NAmE"), 1000, 40);
+    m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40);
     name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
     EXPECT_EQ(name_set.size(), 3u);
     EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
@@ -152,7 +152,7 @@
     EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
 
     // This name is also reused by another uid 2000.
-    m.updateApp(String16("NeW_aPP1_NAmE"), 2000, 1);
+    m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1);
     name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */);
     EXPECT_EQ(name_set.size(), 1u);
     EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
@@ -200,6 +200,66 @@
     EXPECT_EQ(1, results.snapshots_size());
 }
 
+TEST(UidMapTest, TestRemovedAppRetained) {
+    UidMap m;
+    // Initialize single config key.
+    ConfigKey config1(1, StringToId("config1"));
+    m.OnConfigUpdated(config1);
+    vector<int32_t> uids;
+    vector<int64_t> versions;
+    vector<String16> apps;
+    uids.push_back(1000);
+    apps.push_back(String16(kApp2.c_str()));
+    versions.push_back(5);
+    m.updateMap(1, uids, versions, apps);
+    m.removeApp(2, String16(kApp2.c_str()), 1000);
+
+    ProtoOutputStream proto;
+    m.appendUidMap(3, config1, &proto);
+
+    // Snapshot should still contain this item as deleted.
+    UidMapping results;
+    protoOutputStreamToUidMapping(&proto, &results);
+    EXPECT_EQ(1, results.snapshots(0).package_info_size());
+    EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
+}
+
+TEST(UidMapTest, TestRemovedAppOverGuardrail) {
+    UidMap m;
+    // Initialize single config key.
+    ConfigKey config1(1, StringToId("config1"));
+    m.OnConfigUpdated(config1);
+    vector<int32_t> uids;
+    vector<int64_t> versions;
+    vector<String16> apps;
+    const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap;
+    for (int j = 0; j < maxDeletedApps + 10; j++) {
+        uids.push_back(j);
+        apps.push_back(String16(kApp1.c_str()));
+        versions.push_back(j);
+    }
+    m.updateMap(1, uids, versions, apps);
+
+    // First, verify that we have the expected number of items.
+    UidMapping results;
+    ProtoOutputStream proto;
+    m.appendUidMap(3, config1, &proto);
+    protoOutputStreamToUidMapping(&proto, &results);
+    EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
+
+    // Now remove all the apps.
+    m.updateMap(1, uids, versions, apps);
+    for (int j = 0; j < maxDeletedApps + 10; j++) {
+        m.removeApp(4, String16(kApp1.c_str()), j);
+    }
+
+    proto.clear();
+    m.appendUidMap(5, config1, &proto);
+    // Snapshot drops the first nine items.
+    protoOutputStreamToUidMapping(&proto, &results);
+    EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
+}
+
 TEST(UidMapTest, TestClearingOutput) {
     UidMap m;
 
@@ -218,7 +278,6 @@
     versions.push_back(4);
     versions.push_back(5);
     m.updateMap(1, uids, versions, apps);
-    EXPECT_EQ(1U, m.mSnapshots.size());
 
     ProtoOutputStream proto;
     m.appendUidMap(2, config1, &proto);
@@ -227,7 +286,6 @@
     EXPECT_EQ(1, results.snapshots_size());
 
     // We have to keep at least one snapshot in memory at all times.
-    EXPECT_EQ(1U, m.mSnapshots.size());
     proto.clear();
     m.appendUidMap(2, config1, &proto);
     protoOutputStreamToUidMapping(&proto, &results);
@@ -262,7 +320,6 @@
     EXPECT_EQ(1, results.snapshots_size());
     EXPECT_EQ(2, results.changes_size());
     // At this point both should be cleared.
-    EXPECT_EQ(1U, m.mSnapshots.size());
     EXPECT_EQ(0U, m.mChanges.size());
 }
 
@@ -280,11 +337,8 @@
     apps.push_back(String16(kApp1.c_str()));
     versions.push_back(1);
     m.updateMap(1, uids, versions, apps);
-    size_t snapshot_bytes = m.mBytesUsed;
-    EXPECT_TRUE(snapshot_bytes > startBytes);
 
     m.updateApp(3, String16(kApp1.c_str()), 1000, 40);
-    EXPECT_TRUE(m.mBytesUsed > snapshot_bytes);
 
     ProtoOutputStream proto;
     vector<uint8_t> bytes;
@@ -313,16 +367,13 @@
         versions.push_back(1);
     }
     m.updateMap(1, uids, versions, apps);
-    EXPECT_EQ(1U, m.mSnapshots.size());
 
     m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2);
-    EXPECT_EQ(1U, m.mSnapshots.size());
     EXPECT_EQ(1U, m.mChanges.size());
 
     // Now force deletion by limiting the memory to hold one delta change.
     m.maxBytesOverride = 80; // Since the app string alone requires >45 characters.
     m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4);
-    EXPECT_EQ(0U, m.mSnapshots.size());
     EXPECT_EQ(1U, m.mChanges.size());
 }
 #else
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a04a6f9..a97bc41 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -18,6 +18,7 @@
 #include "src/stats_log_util.h"
 #include "tests/statsd_test_util.h"
 
+#include <iostream>
 #include <vector>
 
 namespace android {
@@ -66,14 +67,10 @@
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
     // Here it assumes that GMS core has two uids.
-    processor->getUidMap()->updateApp(
-        android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("app1"), 111 /* uid */, 2 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+    processor->getUidMap()->updateMap(
+            1, {222, 444, 111, 333}, {1, 1, 2, 2},
+            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+             String16("APP3")});
 
     // GMS core node is in the middle.
     std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
@@ -212,14 +209,10 @@
     EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
 
     // Here it assumes that GMS core has two uids.
-    processor->getUidMap()->updateApp(
-        android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("app1"), 111 /* uid */, 2 /* version code*/);
-    processor->getUidMap()->updateApp(
-        android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+    processor->getUidMap()->updateMap(
+            1, {222, 444, 111, 333}, {1, 1, 2, 2},
+            {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+             String16("APP3")});
 
     // GMS core node is in the middle.
     std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
new file mode 100644
index 0000000..d4892ed
--- /dev/null
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -0,0 +1,137 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <gtest/gtest.h>
+
+#include "src/StatsLogProcessor.h"
+#include "src/StatsService.h"
+#include "src/stats_log_util.h"
+#include "tests/statsd_test_util.h"
+
+#include <vector>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+#ifdef __ANDROID__
+
+const string kApp1 = "app1.sharing.1";
+const int kConfigKey = 789130123;  // Randomly chosen to avoid collisions with existing configs.
+
+void SendConfig(StatsService& service, const StatsdConfig& config) {
+    string str;
+    config.SerializeToString(&str);
+    std::vector<uint8_t> configAsVec(str.begin(), str.end());
+    bool success;
+    service.addConfiguration(kConfigKey, configAsVec, &success);
+}
+
+ConfigMetricsReport GetReports(StatsService& service) {
+    vector<uint8_t> output;
+    service.getData(kConfigKey, &output);
+    ConfigMetricsReportList reports;
+    reports.ParseFromArray(output.data(), output.size());
+    EXPECT_EQ(1, reports.reports_size());
+    return reports.reports(0);
+}
+
+StatsdConfig MakeConfig() {
+    StatsdConfig config;
+    config.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+
+    auto appCrashMatcher = CreateProcessCrashAtomMatcher();
+    *config.add_atom_matcher() = appCrashMatcher;
+    auto countMetric = config.add_count_metric();
+    countMetric->set_id(StringToId("AppCrashes"));
+    countMetric->set_what(appCrashMatcher.id());
+    countMetric->set_bucket(FIVE_MINUTES);
+    return config;
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
+    StatsService service(nullptr);
+    SendConfig(service, MakeConfig());
+    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                                // initialized with.
+
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
+
+    ConfigMetricsReport report = GetReports(service);
+    // Expect no metrics since the bucket has not finished yet.
+    EXPECT_EQ(0, report.metrics_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
+    StatsService service(nullptr);
+    SendConfig(service, MakeConfig());
+    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                                // initialized with.
+
+    // Force the uidmap to update at timestamp 2.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+    // This is a new installation, so there shouldn't be a split (should be same as the without
+    // split case).
+    service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
+    // Goes into the second bucket.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+    ConfigMetricsReport report = GetReports(service);
+    EXPECT_EQ(0, report.metrics_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
+    StatsService service(nullptr);
+    SendConfig(service, MakeConfig());
+    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                                // initialized with.
+    service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
+
+    // Force the uidmap to update at timestamp 2.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+    service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2);
+    // Goes into the second bucket.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+    ConfigMetricsReport report = GetReports(service);
+    EXPECT_EQ(1, report.metrics_size());
+    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
+    StatsService service(nullptr);
+    SendConfig(service, MakeConfig());
+    const long start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
+                                                // initialized with.
+    service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())});
+
+    // Force the uidmap to update at timestamp 2.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
+    service.mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
+    // Goes into the second bucket.
+    service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
+
+    ConfigMetricsReport report = GetReports(service);
+    EXPECT_EQ(1, report.metrics_size());
+    EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
\ No newline at end of file
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9017736..479fe27 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -763,7 +763,6 @@
 Landroid/graphics/GraphicBuffer;->CREATOR:Landroid/os/Parcelable$Creator;
 Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
 Landroid/graphics/GraphicBuffer;->mNativeObject:J
-Landroid/graphics/ImageDecoder;-><init>(JIIZ)V
 Landroid/graphics/ImageDecoder;->postProcessAndRelease(Landroid/graphics/Canvas;)I
 Landroid/graphics/LinearGradient;->mColors:[I
 Landroid/graphics/Matrix;->native_instance:J
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index a68136b..27bbc4b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2155,10 +2155,10 @@
     public String[] setPackagesSuspended(String[] packageNames, boolean suspended,
             PersistableBundle appExtras, PersistableBundle launcherExtras,
             String dialogMessage) {
-        // TODO (b/75332201): Pass in the dialogMessage and use it in the interceptor dialog
         try {
             return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
-                    launcherExtras, mContext.getOpPackageName(), mContext.getUserId());
+                    launcherExtras, dialogMessage, mContext.getOpPackageName(),
+                    mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 4326ee3..86fedb1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6678,7 +6678,8 @@
         public RemoteViews makeContentView(boolean increasedHeight) {
             mBuilder.mOriginalActions = mBuilder.mActions;
             mBuilder.mActions = new ArrayList<>();
-            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
+            RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+                    true /* showReplyIcon */);
             mBuilder.mActions = mBuilder.mOriginalActions;
             mBuilder.mOriginalActions = null;
             return remoteViews;
@@ -6765,11 +6766,19 @@
          */
         @Override
         public RemoteViews makeBigContentView() {
-            return makeMessagingView(false /* isCollapsed */);
+            return makeMessagingView(false /* displayImagesAtEnd */, false /* showReplyIcon */);
         }
 
+        /**
+         * Create a messaging layout.
+         *
+         * @param displayImagesAtEnd should images be displayed at the end of the content instead
+         *                           of inline.
+         * @param showReplyIcon Should the reply affordance be shown at the end of the notification
+         * @return the created remoteView.
+         */
         @NonNull
-        private RemoteViews makeMessagingView(boolean isCollapsed) {
+        private RemoteViews makeMessagingView(boolean displayImagesAtEnd, boolean showReplyIcon) {
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
@@ -6780,24 +6789,24 @@
                 nameReplacement = conversationTitle;
                 conversationTitle = null;
             }
-            boolean hideLargeIcon = !isCollapsed || isOneToOne;
+            boolean hideLargeIcon = !showReplyIcon || isOneToOne;
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getMessagingLayoutResource(),
                     mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
                             .hideLargeIcon(hideLargeIcon)
                             .headerTextSecondary(conversationTitle)
-                            .alwaysShowReply(isCollapsed));
+                            .alwaysShowReply(showReplyIcon));
             addExtras(mBuilder.mN.extras);
             // also update the end margin if there is an image
             int endMargin = R.dimen.notification_content_margin_end;
-            if (isCollapsed) {
+            if (showReplyIcon) {
                 endMargin = R.dimen.notification_content_plus_picture_margin_end;
             }
             contentView.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
             contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
                     mBuilder.resolveContrastColor());
-            contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsCollapsed",
-                    isCollapsed);
+            contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
+                    displayImagesAtEnd);
             contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
                     mBuilder.mN.mLargeIcon);
             contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
@@ -6864,7 +6873,8 @@
          */
         @Override
         public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
-            RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */);
+            RemoteViews remoteViews = makeMessagingView(true /* displayImagesAtEnd */,
+                    false /* showReplyIcon */);
             remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
             return remoteViews;
         }
diff --git a/core/java/android/app/usage/TimeSparseArray.java b/core/java/android/app/usage/TimeSparseArray.java
index 9ef88e4..4ec0e9e 100644
--- a/core/java/android/app/usage/TimeSparseArray.java
+++ b/core/java/android/app/usage/TimeSparseArray.java
@@ -88,7 +88,7 @@
                 key++;
                 keyIndex++;
             }
-            if (key >= origKey + 10) {
+            if (key >= origKey + 100) {
                 Slog.w(TAG, "Value " + value + " supposed to be inserted at " + origKey
                         + " displaced to " + key);
             }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 000912c..efc9b6d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2282,6 +2282,28 @@
     public static final String ACTION_MY_PACKAGE_SUSPENDED = "android.intent.action.MY_PACKAGE_SUSPENDED";
 
     /**
+     * Activity Action: Started to show more details about why an application was suspended.
+     *
+     * <p>Apps holding {@link android.Manifest.permission#SUSPEND_APPS} must declare an activity
+     * handling this intent and protect it with
+     * {@link android.Manifest.permission#SEND_SHOW_SUSPENDED_APP_DETAILS}.
+     *
+     * <p>Includes an extra {@link #EXTRA_PACKAGE_NAME} which is the name of the suspended package.
+     *
+     * <p class="note">This is a protected intent that can only be sent
+     * by the system.
+     *
+     * @see PackageManager#isPackageSuspended()
+     * @see #ACTION_PACKAGES_SUSPENDED
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS =
+            "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
+
+    /**
      * Broadcast Action: Sent to a package that has been unsuspended.
      *
      * <p class="note">This is a protected intent that can only be sent
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 277738b..02ce47b8 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -273,8 +273,8 @@
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
     String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
-            in PersistableBundle launcherExtras, in PersistableBundle appExtras,
-            String callingPackage, int userId);
+            in PersistableBundle appExtras, in PersistableBundle launcherExtras,
+            String dialogMessage, String callingPackage, int userId);
 
     boolean isPackageSuspendedForUser(String packageName, int userId);
 
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 96aa36c..a9d0911 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -191,10 +191,10 @@
     /**
      * Retrieve launcher extras for a suspended package provided to the system in
      * {@link PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
-     * PersistableBundle, String)}
+     * PersistableBundle, String)}.
      *
      * @param packageName The package for which to return launcher extras.
-     * @param userId The user for which to check,
+     * @param userId The user for which to check.
      * @return The launcher extras.
      *
      * @see PackageManager#setPackagesSuspended(String[], boolean, PersistableBundle,
@@ -214,6 +214,29 @@
     public abstract boolean isPackageSuspended(String packageName, int userId);
 
     /**
+     * Get the name of the package that suspended the given package. Packages can be suspended by
+     * device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
+     * {@link android.Manifest.permission#SUSPEND_APPS}.
+     *
+     * @param suspendedPackage The package that has been suspended.
+     * @param userId The user for which to check.
+     * @return Name of the package that suspended the given package. Returns {@code null} if the
+     * given package is not currently suspended and the platform package name - i.e.
+     * {@code "android"} - if the package was suspended by a device admin.
+     */
+    public abstract String getSuspendingPackage(String suspendedPackage, int userId);
+
+    /**
+     * Get the dialog message to be shown to the user when they try to launch a suspended
+     * application.
+     *
+     * @param suspendedPackage The package that has been suspended.
+     * @param userId The user for which to check.
+     * @return The dialog message to be shown to the user.
+     */
+    public abstract String getSuspendedDialogMessage(String suspendedPackage, int userId);
+
+    /**
      * Do a straight uid lookup for the given package/application in the given user.
      * @see PackageManager#getPackageUidAsUser(String, int, int)
      * @return The app's uid, or < 0 if the package was not found in that user
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index f7b6e09..f471a1d 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -34,6 +34,7 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Per-user state information about a package.
@@ -47,6 +48,7 @@
     public boolean hidden; // Is the app restricted by owner / admin
     public boolean suspended;
     public String suspendingPackage;
+    public String dialogMessage; // Message to show when a suspended package launch attempt is made
     public PersistableBundle suspendedAppExtras;
     public PersistableBundle suspendedLauncherExtras;
     public boolean instantApp;
@@ -82,6 +84,7 @@
         hidden = o.hidden;
         suspended = o.suspended;
         suspendingPackage = o.suspendingPackage;
+        dialogMessage = o.dialogMessage;
         suspendedAppExtras = o.suspendedAppExtras;
         suspendedLauncherExtras = o.suspendedLauncherExtras;
         instantApp = o.instantApp;
@@ -208,6 +211,9 @@
                     || !suspendingPackage.equals(oldState.suspendingPackage)) {
                 return false;
             }
+            if (!Objects.equals(dialogMessage, oldState.dialogMessage)) {
+                return false;
+            }
             if (!BaseBundle.kindofEquals(suspendedAppExtras,
                     oldState.suspendedAppExtras)) {
                 return false;
diff --git a/core/java/android/hardware/biometrics/BiometricDialog.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
similarity index 93%
rename from core/java/android/hardware/biometrics/BiometricDialog.java
rename to core/java/android/hardware/biometrics/BiometricPrompt.java
index dd848a3..1c9de45 100644
--- a/core/java/android/hardware/biometrics/BiometricDialog.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -38,7 +38,7 @@
 /**
  * A class that manages a system-provided biometric dialog.
  */
-public class BiometricDialog implements BiometricAuthenticator, BiometricConstants {
+public class BiometricPrompt implements BiometricAuthenticator, BiometricConstants {
 
     /**
      * @hide
@@ -190,11 +190,11 @@
         }
 
         /**
-         * Creates a {@link BiometricDialog}.
-         * @return a {@link BiometricDialog}
+         * Creates a {@link BiometricPrompt}.
+         * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
          */
-        public BiometricDialog build() {
+        public BiometricPrompt build() {
             final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
             final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
 
@@ -203,7 +203,7 @@
             } else if (TextUtils.isEmpty(negative)) {
                 throw new IllegalArgumentException("Negative text must be set and non-empty");
             }
-            return new BiometricDialog(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
+            return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
         }
     }
 
@@ -213,7 +213,7 @@
     private ButtonInfo mPositiveButtonInfo;
     private ButtonInfo mNegativeButtonInfo;
 
-    IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
+    IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
         @Override
         public void onDialogDismissed(int reason) {
             // Check the reason and invoke OnClickListener(s) if necessary
@@ -229,7 +229,7 @@
         }
     };
 
-    private BiometricDialog(Context context, Bundle bundle,
+    private BiometricPrompt(Context context, Bundle bundle,
             ButtonInfo positiveButtonInfo, ButtonInfo negativeButtonInfo) {
         mBundle = bundle;
         mPositiveButtonInfo = positiveButtonInfo;
@@ -239,7 +239,7 @@
     }
 
     /**
-     * A wrapper class for the crypto objects supported by BiometricDialog. Currently the framework
+     * A wrapper class for the crypto objects supported by BiometricPrompt. Currently the framework
      * supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
      */
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -308,8 +308,8 @@
     }
 
     /**
-     * Callback structure provided to {@link BiometricDialog#authenticate(CancellationSignal,
-     * Executor, AuthenticationCallback)} or {@link BiometricDialog#authenticate(CryptoObject,
+     * Callback structure provided to {@link BiometricPrompt#authenticate(CancellationSignal,
+     * Executor, AuthenticationCallback)} or {@link BiometricPrompt#authenticate(CryptoObject,
      * CancellationSignal, Executor, AuthenticationCallback)}. Users must provide an implementation
      * of this for listening to authentication events.
      */
@@ -378,7 +378,7 @@
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
+        if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
             throw new IllegalArgumentException("Callback cannot be casted");
         }
         authenticate(crypto, cancel, executor, (AuthenticationCallback) callback);
@@ -395,7 +395,7 @@
     public void authenticate(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
-        if (!(callback instanceof BiometricDialog.AuthenticationCallback)) {
+        if (!(callback instanceof BiometricPrompt.AuthenticationCallback)) {
             throw new IllegalArgumentException("Callback cannot be casted");
         }
         authenticate(cancel, executor, (AuthenticationCallback) callback);
@@ -410,8 +410,8 @@
      * operation can be canceled by using the provided cancel object. The application will receive
      * authentication errors through {@link AuthenticationCallback}, and button events through the
      * corresponding callback set in {@link Builder#setNegativeButton(CharSequence, Executor,
-     * DialogInterface.OnClickListener)}. It is safe to reuse the {@link BiometricDialog} object,
-     * and calling {@link BiometricDialog#authenticate( CancellationSignal, Executor,
+     * DialogInterface.OnClickListener)}. It is safe to reuse the {@link BiometricPrompt} object,
+     * and calling {@link BiometricPrompt#authenticate( CancellationSignal, Executor,
      * AuthenticationCallback)} while an existing authentication attempt is occurring will stop the
      * previous client and start a new authentication. The interrupted client will receive a
      * cancelled notification through {@link AuthenticationCallback#onAuthenticationError(int,
@@ -445,8 +445,8 @@
      * provided cancel object. The application will receive authentication errors through {@link
      * AuthenticationCallback}, and button events through the corresponding callback set in {@link
      * Builder#setNegativeButton(CharSequence, Executor, DialogInterface.OnClickListener)}.  It is
-     * safe to reuse the {@link BiometricDialog} object, and calling {@link
-     * BiometricDialog#authenticate(CancellationSignal, Executor, AuthenticationCallback)} while
+     * safe to reuse the {@link BiometricPrompt} object, and calling {@link
+     * BiometricPrompt#authenticate(CancellationSignal, Executor, AuthenticationCallback)} while
      * an existing authentication attempt is occurring will stop the previous client and start a new
      * authentication. The interrupted client will receive a cancelled notification through {@link
      * AuthenticationCallback#onAuthenticationError(int, CharSequence)}.
@@ -470,15 +470,15 @@
     private boolean handlePreAuthenticationErrors(AuthenticationCallback callback,
             Executor executor) {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            sendError(BiometricDialog.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
+            sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT, callback,
                       executor);
             return true;
         } else if (!mFingerprintManager.isHardwareDetected()) {
-            sendError(BiometricDialog.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
+            sendError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE, callback,
                       executor);
             return true;
         } else if (!mFingerprintManager.hasEnrolledFingerprints()) {
-            sendError(BiometricDialog.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
+            sendError(BiometricPrompt.BIOMETRIC_ERROR_NO_BIOMETRICS, callback,
                       executor);
             return true;
         }
diff --git a/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl b/core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
similarity index 87%
rename from core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
rename to core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
index e528aa7..67c9346 100644
--- a/core/java/android/hardware/biometrics/IBiometricDialogReceiver.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl
@@ -19,9 +19,9 @@
 import android.os.UserHandle;
 
 /**
- * Communication channel from the BiometricDialog (SysUI) back to AuthenticationClient.
+ * Communication channel from the BiometricPrompt (SysUI) back to AuthenticationClient.
  * @hide
  */
-oneway interface IBiometricDialogReceiver {
+oneway interface IBiometricPromptReceiver {
     void onDialogDismissed(int reason);
 }
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a6c8c67..40d31bf 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -31,9 +31,9 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.hardware.biometrics.BiometricAuthenticator;
-import android.hardware.biometrics.BiometricDialog;
 import android.hardware.biometrics.BiometricFingerprintConstants;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -57,7 +57,7 @@
 
 /**
  * A class that coordinates access to the fingerprint hardware.
- * @deprecated See {@link BiometricDialog} which shows a system-provided dialog upon starting
+ * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
  * authentication. In a world where devices may have different types of biometric authentication,
  * it's much more realistic to have a system-provided authentication dialog since the method may
  * vary by vendor/device.
@@ -111,7 +111,7 @@
     /**
      * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
-     * @deprecated See {@link android.hardware.biometrics.BiometricDialog.CryptoObject}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
      */
     @Deprecated
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -155,7 +155,7 @@
     /**
      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
      *     CancellationSignal, int, AuthenticationCallback, Handler)}.
-     * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationResult}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
      */
     @Deprecated
     public static class AuthenticationResult {
@@ -204,7 +204,7 @@
      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
      * fingerprint events.
-     * @deprecated See {@link android.hardware.biometrics.BiometricDialog.AuthenticationCallback}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
      */
     @Deprecated
     public static abstract class AuthenticationCallback
@@ -378,10 +378,10 @@
      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
      *         facility</a>.
      * @throws IllegalStateException if the crypto primitive is not initialized.
-     * @deprecated See {@link BiometricDialog#authenticate(CancellationSignal, Executor,
-     * BiometricDialog.AuthenticationCallback)} and {@link BiometricDialog#authenticate(
-     * BiometricDialog.CryptoObject, CancellationSignal, Executor,
-     * BiometricDialog.AuthenticationCallback)}
+     * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+     * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
+     * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
+     * BiometricPrompt.AuthenticationCallback)}
      */
     @Deprecated
     @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -444,7 +444,7 @@
 
     /**
      * Per-user version, see {@link FingerprintManager#authenticate(CryptoObject,
-     * CancellationSignal, Bundle, Executor, IBiometricDialogReceiver, AuthenticationCallback)}
+     * CancellationSignal, Bundle, Executor, IBiometricPromptReceiver, AuthenticationCallback)}
      * @param userId the user ID that the fingerprint hardware will authenticate for.
      */
     private void authenticate(int userId,
@@ -452,7 +452,7 @@
             @NonNull CancellationSignal cancel,
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricDialogReceiver receiver,
+            @NonNull IBiometricPromptReceiver receiver,
             @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         mCryptoObject = crypto;
         if (cancel.isCanceled()) {
@@ -480,8 +480,8 @@
     }
 
     /**
-     * Private method, see {@link BiometricDialog#authenticate(CancellationSignal, Executor,
-     * BiometricDialog.AuthenticationCallback)}
+     * Private method, see {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+     * BiometricPrompt.AuthenticationCallback)}
      * @param cancel
      * @param executor
      * @param callback
@@ -491,7 +491,7 @@
             @NonNull CancellationSignal cancel,
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricDialogReceiver receiver,
+            @NonNull IBiometricPromptReceiver receiver,
             @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         if (cancel == null) {
             throw new IllegalArgumentException("Must supply a cancellation signal");
@@ -512,8 +512,8 @@
     }
 
     /**
-     * Private method, see {@link BiometricDialog#authenticate(BiometricDialog.CryptoObject,
-     * CancellationSignal, Executor, BiometricDialog.AuthenticationCallback)}
+     * Private method, see {@link BiometricPrompt#authenticate(BiometricPrompt.CryptoObject,
+     * CancellationSignal, Executor, BiometricPrompt.AuthenticationCallback)}
      * @param crypto
      * @param cancel
      * @param executor
@@ -524,7 +524,7 @@
             @NonNull CancellationSignal cancel,
             @NonNull Bundle bundle,
             @NonNull @CallbackExecutor Executor executor,
-            @NonNull IBiometricDialogReceiver receiver,
+            @NonNull IBiometricPromptReceiver receiver,
             @NonNull BiometricAuthenticator.AuthenticationCallback callback) {
         if (crypto == null) {
             throw new IllegalArgumentException("Must supply a crypto object");
@@ -743,7 +743,7 @@
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
-     * @deprecated See {@link BiometricDialog} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
      */
     @Deprecated
@@ -777,7 +777,7 @@
      * Determine if fingerprint hardware is present and functional.
      *
      * @return true if hardware is present and functional, false otherwise.
-     * @deprecated See {@link BiometricDialog} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
      */
     @Deprecated
@@ -1158,7 +1158,7 @@
         @Override // binder call
         public void onError(long deviceId, int error, int vendorCode) {
             if (mExecutor != null) {
-                // BiometricDialog case
+                // BiometricPrompt case
                 if (error == FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED) {
                     // User tapped somewhere to cancel, the biometric dialog is already dismissed.
                     mExecutor.execute(() -> {
@@ -1172,7 +1172,7 @@
                         mExecutor.execute(() -> {
                             sendErrorResult(deviceId, error, vendorCode);
                         });
-                    }, BiometricDialog.HIDE_DIALOG_DELAY);
+                    }, BiometricPrompt.HIDE_DIALOG_DELAY);
                 }
             } else {
                 mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 78d01e5..8aa2183 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -16,7 +16,7 @@
 package android.hardware.fingerprint;
 
 import android.os.Bundle;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.hardware.fingerprint.IFingerprintClientActiveCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
@@ -31,7 +31,7 @@
     // Authenticate the given sessionId with a fingerprint
     void authenticate(IBinder token, long sessionId, int userId,
             IFingerprintServiceReceiver receiver, int flags, String opPackageName,
-            in Bundle bundle, IBiometricDialogReceiver dialogReceiver);
+            in Bundle bundle, IBiometricPromptReceiver dialogReceiver);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 98d8666..b2a2c60 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3753,17 +3753,6 @@
                 new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
 
         /**
-         * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
-         * calls when supported by the device and carrier. Boolean value.
-         * 0 = OFF
-         * 1 = ON
-         */
-        public static final String RTT_CALLING_MODE = "rtt_calling_mode";
-
-        /** @hide */
-        public static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
-
-        /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
          * boolean (1 or 0).
          */
@@ -4088,7 +4077,6 @@
             DTMF_TONE_WHEN_DIALING,
             DTMF_TONE_TYPE_WHEN_DIALING,
             HEARING_AID,
-            RTT_CALLING_MODE,
             TTY_MODE,
             MASTER_MONO,
             SOUND_EFFECTS_ENABLED,
@@ -4287,7 +4275,6 @@
             VALIDATORS.put(DTMF_TONE_TYPE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING_VALIDATOR);
             VALIDATORS.put(HEARING_AID, HEARING_AID_VALIDATOR);
             VALIDATORS.put(TTY_MODE, TTY_MODE_VALIDATOR);
-            VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_LIGHT_PULSE, NOTIFICATION_LIGHT_PULSE_VALIDATOR);
             VALIDATORS.put(POINTER_LOCATION, POINTER_LOCATION_VALIDATOR);
             VALIDATORS.put(SHOW_TOUCHES, SHOW_TOUCHES_VALIDATOR);
@@ -6660,6 +6647,17 @@
         private static final Validator TTY_MODE_ENABLED_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+         * calls when supported by the device and carrier. Boolean value.
+         * 0 = OFF
+         * 1 = ON
+         */
+        public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+
+        private static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
+        /**
          * Controls whether settings backup is enabled.
          * Type: int ( 0 = disabled, 1 = enabled )
          * @hide
@@ -7885,6 +7883,7 @@
             PREFERRED_TTY_MODE,
             ENHANCED_VOICE_PRIVACY_ENABLED,
             TTY_MODE_ENABLED,
+            RTT_CALLING_MODE,
             INCALL_POWER_BUTTON_BEHAVIOR,
             NIGHT_DISPLAY_CUSTOM_START_TIME,
             NIGHT_DISPLAY_CUSTOM_END_TIME,
@@ -8014,6 +8013,7 @@
             VALIDATORS.put(ENHANCED_VOICE_PRIVACY_ENABLED,
                     ENHANCED_VOICE_PRIVACY_ENABLED_VALIDATOR);
             VALIDATORS.put(TTY_MODE_ENABLED, TTY_MODE_ENABLED_VALIDATOR);
+            VALIDATORS.put(RTT_CALLING_MODE, RTT_CALLING_MODE_VALIDATOR);
             VALIDATORS.put(INCALL_POWER_BUTTON_BEHAVIOR, INCALL_POWER_BUTTON_BEHAVIOR_VALIDATOR);
             VALIDATORS.put(NIGHT_DISPLAY_CUSTOM_START_TIME,
                     NIGHT_DISPLAY_CUSTOM_START_TIME_VALIDATOR);
@@ -12541,6 +12541,19 @@
          */
          public static final String SWAP_ENABLED = "swap_enabled";
 
+        /**
+         * Blacklist of GNSS satellites.
+         *
+         * This is a list of integers separated by commas to represent pairs of (constellation,
+         * svid). Thus, the number of integers should be even.
+         *
+         * E.g.: "3,0,5,24" denotes (constellation=3, svid=0) and (constellation=5, svid=24) are
+         * blacklisted. Note that svid=0 denotes all svids in the
+         * constellation are blacklisted.
+         *
+         * @hide
+         */
+        public static final String GNSS_SATELLITE_BLACKLIST = "gnss_satellite_blacklist";
     }
 
     /**
diff --git a/core/java/android/security/ConfirmationCallback.java b/core/java/android/security/ConfirmationCallback.java
index 4670bce..fd027f0 100644
--- a/core/java/android/security/ConfirmationCallback.java
+++ b/core/java/android/security/ConfirmationCallback.java
@@ -33,22 +33,22 @@
      *
      * @param dataThatWasConfirmed the data that was confirmed, see above for the format.
      */
-    public void onConfirmedByUser(@NonNull byte[] dataThatWasConfirmed) {}
+    public void onConfirmed(@NonNull byte[] dataThatWasConfirmed) {}
 
     /**
      * Called when the requested prompt was dismissed (not accepted) by the user.
      */
-    public void onDismissedByUser() {}
+    public void onDismissed() {}
 
     /**
      * Called when the requested prompt was dismissed by the application.
      */
-    public void onDismissedByApplication() {}
+    public void onCanceled() {}
 
     /**
      * Called when the requested prompt was dismissed because of a low-level error.
      *
-     * @param e an exception representing the error.
+     * @param e a throwable representing the error.
      */
-    public void onError(Exception e) {}
+    public void onError(Throwable e) {}
 }
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationPrompt.java
similarity index 88%
rename from core/java/android/security/ConfirmationDialog.java
rename to core/java/android/security/ConfirmationPrompt.java
index 1697106..5330cff 100644
--- a/core/java/android/security/ConfirmationDialog.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -68,7 +68,7 @@
  * {@link #presentPrompt presentPrompt()} method. The <i>Relying Party</i> stores the nonce locally
  * since it'll use it in a later step.
  * <li> If the user approves the prompt a <i>Confirmation Response</i> is returned in the
- * {@link ConfirmationCallback#onConfirmedByUser onConfirmedByUser(byte[])} callback as the
+ * {@link ConfirmationCallback#onConfirmed onConfirmed(byte[])} callback as the
  * <code>dataThatWasConfirmed</code> parameter. This blob contains the text that was shown to the
  * user, the <code>extraData</code> parameter, and possibly other data.
  * <li> The application signs the <i>Confirmation Response</i> with the previously created key and
@@ -82,8 +82,8 @@
  * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it
  * along the nonce in the <code>extraData</code> blob.
  */
-public class ConfirmationDialog {
-    private static final String TAG = "ConfirmationDialog";
+public class ConfirmationPrompt {
+    private static final String TAG = "ConfirmationPrompt";
 
     private CharSequence mPromptText;
     private byte[] mExtraData;
@@ -97,15 +97,15 @@
             ConfirmationCallback callback) {
         switch (responseCode) {
             case KeyStore.CONFIRMATIONUI_OK:
-                callback.onConfirmedByUser(dataThatWasConfirmed);
+                callback.onConfirmed(dataThatWasConfirmed);
                 break;
 
             case KeyStore.CONFIRMATIONUI_CANCELED:
-                callback.onDismissedByUser();
+                callback.onDismissed();
                 break;
 
             case KeyStore.CONFIRMATIONUI_ABORTED:
-                callback.onDismissedByApplication();
+                callback.onCanceled();
                 break;
 
             case KeyStore.CONFIRMATIONUI_SYSTEM_ERROR:
@@ -145,21 +145,25 @@
             };
 
     /**
-     * A builder that collects arguments, to be shown on the system-provided confirmation dialog.
+     * A builder that collects arguments, to be shown on the system-provided confirmation prompt.
      */
-    public static class Builder {
+    public static final class Builder {
 
+        private Context mContext;
         private CharSequence mPromptText;
         private byte[] mExtraData;
 
         /**
-         * Creates a builder for the confirmation dialog.
+         * Creates a builder for the confirmation prompt.
+         *
+         * @param context the application context
          */
-        public Builder() {
+        public Builder(Context context) {
+            mContext = context;
         }
 
         /**
-         * Sets the prompt text for the dialog.
+         * Sets the prompt text for the prompt.
          *
          * @param promptText the text to present in the prompt.
          * @return the builder.
@@ -170,7 +174,7 @@
         }
 
         /**
-         * Sets the extra data for the dialog.
+         * Sets the extra data for the prompt.
          *
          * @param extraData data to include in the response data.
          * @return the builder.
@@ -181,24 +185,23 @@
         }
 
         /**
-         * Creates a {@link ConfirmationDialog} with the arguments supplied to this builder.
+         * Creates a {@link ConfirmationPrompt} with the arguments supplied to this builder.
          *
-         * @param context the application context
-         * @return a {@link ConfirmationDialog}
+         * @return a {@link ConfirmationPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
          */
-        public ConfirmationDialog build(Context context) {
+        public ConfirmationPrompt build() {
             if (TextUtils.isEmpty(mPromptText)) {
                 throw new IllegalArgumentException("prompt text must be set and non-empty");
             }
             if (mExtraData == null) {
                 throw new IllegalArgumentException("extraData must be set");
             }
-            return new ConfirmationDialog(context, mPromptText, mExtraData);
+            return new ConfirmationPrompt(mContext, mPromptText, mExtraData);
         }
     }
 
-    private ConfirmationDialog(Context context, CharSequence promptText, byte[] extraData) {
+    private ConfirmationPrompt(Context context, CharSequence promptText, byte[] extraData) {
         mContext = context;
         mPromptText = promptText;
         mExtraData = extraData;
@@ -227,10 +230,10 @@
         return uiOptionsAsFlags;
     }
 
-    private boolean isAccessibilityServiceRunning() {
+    private static boolean isAccessibilityServiceRunning(Context context) {
         boolean serviceRunning = false;
         try {
-            ContentResolver contentResolver = mContext.getContentResolver();
+            ContentResolver contentResolver = context.getContentResolver();
             int a11yEnabled = Settings.Secure.getInt(contentResolver,
                     Settings.Secure.ACCESSIBILITY_ENABLED);
             if (a11yEnabled == 1) {
@@ -249,12 +252,12 @@
      * When the prompt is no longer being presented, one of the methods in
      * {@link ConfirmationCallback} is called on the supplied callback object.
      *
-     * Confirmation dialogs may not be available when accessibility services are running so this
+     * Confirmation prompts may not be available when accessibility services are running so this
      * may fail with a {@link ConfirmationNotAvailableException} exception even if
      * {@link #isSupported} returns {@code true}.
      *
      * @param executor the executor identifying the thread that will receive the callback.
-     * @param callback the callback to use when the dialog is done showing.
+     * @param callback the callback to use when the prompt is done showing.
      * @throws IllegalArgumentException if the prompt text is too long or malfomed.
      * @throws ConfirmationAlreadyPresentingException if another prompt is being presented.
      * @throws ConfirmationNotAvailableException if confirmation prompts are not supported.
@@ -265,7 +268,7 @@
         if (mCallback != null) {
             throw new ConfirmationAlreadyPresentingException();
         }
-        if (isAccessibilityServiceRunning()) {
+        if (isAccessibilityServiceRunning(mContext)) {
             throw new ConfirmationNotAvailableException();
         }
         mCallback = callback;
@@ -301,7 +304,7 @@
      * Cancels a prompt currently being displayed.
      *
      * On success, the
-     * {@link ConfirmationCallback#onDismissedByApplication onDismissedByApplication()} method on
+     * {@link ConfirmationCallback#onCanceled onCanceled()} method on
      * the supplied callback object will be called asynchronously.
      *
      * @throws IllegalStateException if no prompt is currently being presented.
@@ -324,9 +327,13 @@
     /**
      * Checks if the device supports confirmation prompts.
      *
+     * @param context the application context.
      * @return true if confirmation prompts are supported by the device.
      */
-    public static boolean isSupported() {
+    public static boolean isSupported(Context context) {
+        if (isAccessibilityServiceRunning(context)) {
+            return false;
+        }
         return KeyStore.getInstance().isConfirmationPromptSupported();
     }
 }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index cca66d6..08c2d0b 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -610,6 +610,10 @@
                     ViewRootImpl root = mRoots.get(i);
                     // Client might remove the view by "stopped" event.
                     root.setWindowStopped(stopped);
+                    // Recursively forward stopped state to View's attached
+                    // to this Window rather than the root application token,
+                    // e.g. PopupWindow's.
+                    setStoppedState(root.mAttachInfo.mWindowToken, stopped);
                 }
             }
         }
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 4710671..f048d29 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -216,13 +216,17 @@
             @IntRange(from = 0) int selectionStartIndex,
             @IntRange(from = 0) int selectionEndIndex,
             @Nullable TextSelection.Options options) {
-        final TextSelection.Request request = options.getRequest() != null
-                ? options.getRequest()
-                : new TextSelection.Request.Builder(
-                        text, selectionStartIndex, selectionEndIndex)
-                        .setDefaultLocales(options.getDefaultLocales())
-                        .build();
-        return suggestSelection(request);
+        if (options == null) {
+            return suggestSelection(new TextSelection.Request.Builder(
+                    text, selectionStartIndex, selectionEndIndex).build());
+        } else if (options.getRequest() != null) {
+            return suggestSelection(options.getRequest());
+        } else {
+            return suggestSelection(
+                    new TextSelection.Request.Builder(text, selectionStartIndex, selectionEndIndex)
+                            .setDefaultLocales(options.getDefaultLocales())
+                            .build());
+        }
     }
 
     /**
@@ -291,14 +295,17 @@
             @IntRange(from = 0) int startIndex,
             @IntRange(from = 0) int endIndex,
             @Nullable TextClassification.Options options) {
-        final TextClassification.Request request = options.getRequest() != null
-                ? options.getRequest()
-                : new TextClassification.Request.Builder(
-                        text, startIndex, endIndex)
-                        .setDefaultLocales(options.getDefaultLocales())
-                        .setReferenceTime(options.getReferenceTime())
-                        .build();
-        return classifyText(request);
+        if (options == null) {
+            return classifyText(
+                    new TextClassification.Request.Builder(text, startIndex, endIndex).build());
+        } else if (options.getRequest() != null) {
+            return classifyText(options.getRequest());
+        } else {
+            return classifyText(new TextClassification.Request.Builder(text, startIndex, endIndex)
+                    .setDefaultLocales(options.getDefaultLocales())
+                    .setReferenceTime(options.getReferenceTime())
+                    .build());
+        }
     }
 
     /**
@@ -326,13 +333,16 @@
     /** @hide */
     default TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
-        final TextLinks.Request request = options.getRequest() != null
-                ? options.getRequest()
-                : new TextLinks.Request.Builder(text)
-                        .setDefaultLocales(options.getDefaultLocales())
-                        .setEntityConfig(options.getEntityConfig())
-                        .build();
-        return generateLinks(request);
+        if (options == null) {
+            return generateLinks(new TextLinks.Request.Builder(text).build());
+        } else if (options.getRequest() != null) {
+            return generateLinks(options.getRequest());
+        } else {
+            return generateLinks(new TextLinks.Request.Builder(text)
+                    .setDefaultLocales(options.getDefaultLocales())
+                    .setEntityConfig(options.getEntityConfig())
+                    .build());
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
new file mode 100644
index 0000000..322c876
--- /dev/null
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+
+public class SuspendedAppActivity extends AlertActivity
+        implements DialogInterface.OnClickListener {
+    private static final String TAG = "SuspendedAppActivity";
+
+    public static final String EXTRA_DIALOG_MESSAGE = "SuspendedAppActivity.extra.DIALOG_MESSAGE";
+    public static final String EXTRA_MORE_DETAILS_INTENT =
+            "SuspendedAppActivity.extra.MORE_DETAILS_INTENT";
+
+    private Intent mMoreDetailsIntent;
+    private int mUserId;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        Window window = getWindow();
+        window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+        super.onCreate(icicle);
+
+        final Intent intent = getIntent();
+        mMoreDetailsIntent = intent.getParcelableExtra(EXTRA_MORE_DETAILS_INTENT);
+        mUserId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
+        if (mUserId < 0) {
+            Slog.wtf(TAG, "Invalid user: " + mUserId);
+            finish();
+            return;
+        }
+        String dialogMessage = intent.getStringExtra(EXTRA_DIALOG_MESSAGE);
+        if (dialogMessage == null) {
+            dialogMessage = getString(R.string.app_suspended_default_message);
+        }
+
+        final AlertController.AlertParams ap = mAlertParams;
+        ap.mTitle = getString(R.string.app_suspended_title);
+        ap.mMessage = String.format(getResources().getConfiguration().getLocales().get(0),
+                dialogMessage, intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
+        ap.mPositiveButtonText = getString(android.R.string.ok);
+        if (mMoreDetailsIntent != null) {
+            ap.mNeutralButtonText = getString(R.string.app_suspended_more_details);
+        }
+        ap.mPositiveButtonListener = ap.mNeutralButtonListener = this;
+        setupAlert();
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        switch (which) {
+            case AlertDialog.BUTTON_NEUTRAL:
+                startActivityAsUser(mMoreDetailsIntent, UserHandle.of(mUserId));
+                Slog.i(TAG, "Started more details activity");
+                break;
+        }
+        finish();
+    }
+}
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ad5743d..2790324 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -18,7 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
 
@@ -141,7 +141,7 @@
     void showShutdownUi(boolean isReboot, String reason);
 
     // Used to show the dialog when FingerprintService starts authentication
-    void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
+    void showFingerprintDialog(in Bundle bundle, IBiometricPromptReceiver receiver);
     // Used to hide the dialog when a finger is authenticated
     void onFingerprintAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 0c5efe2..24f2fbf 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -20,7 +20,7 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.service.notification.StatusBarNotification;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -88,7 +88,7 @@
     void showPinningEscapeToast();
 
     // Used to show the dialog when FingerprintService starts authentication
-    void showFingerprintDialog(in Bundle bundle, IBiometricDialogReceiver receiver);
+    void showFingerprintDialog(in Bundle bundle, IBiometricPromptReceiver receiver);
     // Used to hide the dialog when a finger is authenticated
     void onFingerprintAuthenticated();
     // Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 239beaa..f73b607 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -64,7 +64,7 @@
     private boolean mIsHidingAnimated;
     private boolean mNeedsGeneratedAvatar;
     private Notification.Person mSender;
-    private boolean mAvatarsAtEnd;
+    private boolean mImagesAtEnd;
     private ViewGroup mImageContainer;
     private MessagingImageMessage mIsolatedMessage;
     private boolean mTransformingImages;
@@ -342,7 +342,7 @@
                 mAddedMessages.add(message);
             }
             boolean isImage = message instanceof MessagingImageMessage;
-            if (mAvatarsAtEnd && isImage) {
+            if (mImagesAtEnd && isImage) {
                 isolatedMessage = (MessagingImageMessage) message;
             } else {
                 if (removeFromParentIfDifferent(message, mMessageContainer)) {
@@ -474,9 +474,9 @@
         mTransformingImages = transformingImages;
     }
 
-    public void setDisplayAvatarsAtEnd(boolean atEnd) {
-        if (mAvatarsAtEnd != atEnd) {
-            mAvatarsAtEnd = atEnd;
+    public void setDisplayImagesAtEnd(boolean atEnd) {
+        if (mImagesAtEnd != atEnd) {
+            mImagesAtEnd = atEnd;
             mImageContainer.setVisibility(atEnd ? View.VISIBLE : View.GONE);
         }
     }
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 5279636..292df60 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -81,7 +81,7 @@
     private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
     private Notification.Person mUser;
     private CharSequence mNameReplacement;
-    private boolean mIsCollapsed;
+    private boolean mDisplayImagesAtEnd;
 
     public MessagingLayout(@NonNull Context context) {
         super(context);
@@ -128,8 +128,8 @@
     }
 
     @RemotableViewMethod
-    public void setIsCollapsed(boolean isCollapsed) {
-        mIsCollapsed = isCollapsed;
+    public void setDisplayImagesAtEnd(boolean atEnd) {
+        mDisplayImagesAtEnd = atEnd;
     }
 
     @RemotableViewMethod
@@ -337,7 +337,7 @@
                 newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
                 mAddedGroups.add(newGroup);
             }
-            newGroup.setDisplayAvatarsAtEnd(mIsCollapsed);
+            newGroup.setDisplayImagesAtEnd(mDisplayImagesAtEnd);
             newGroup.setLayoutColor(mLayoutColor);
             Notification.Person sender = senders.get(groupIndex);
             CharSequence nameOverride = null;
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index bf1c5ca..a2cc7cf 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.app.ActivityManager;
 import android.app.Notification;
 import android.view.View;
 
@@ -33,7 +34,7 @@
 
     static MessagingMessage createMessage(MessagingLayout layout,
             Notification.MessagingStyle.Message m) {
-        if (hasImage(m)) {
+        if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) {
             return MessagingImageMessage.createMessage(layout, m);
         } else {
             return MessagingTextMessage.createMessage(layout, m);
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 825b7a0..3ea6049 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -116,9 +116,10 @@
     const auto& info = decoder->mCodec->getInfo();
     const int width = info.width();
     const int height = info.height();
+    const bool isNinePatch = decoder->mPeeker->mPatch != nullptr;
     return env->NewObject(gImageDecoder_class, gImageDecoder_constructorMethodID,
                           reinterpret_cast<jlong>(decoder.release()), width, height,
-                          animated);
+                          animated, isNinePatch);
 }
 
 static jobject ImageDecoder_nCreateFd(JNIEnv* env, jobject /*clazz*/,
@@ -332,13 +333,6 @@
         }
     }
 
-    float scaleX = 1.0f;
-    float scaleY = 1.0f;
-    if (scale) {
-        scaleX = (float) desiredWidth  / decodeInfo.width();
-        scaleY = (float) desiredHeight / decodeInfo.height();
-    }
-
     jbyteArray ninePatchChunk = nullptr;
     jobject ninePatchInsets = nullptr;
 
@@ -346,9 +340,6 @@
     if (!jpostProcess) {
         // FIXME: Share more code with BitmapFactory.cpp.
         if (decoder->mPeeker->mPatch != nullptr) {
-            if (scale) {
-                decoder->mPeeker->scale(scaleX, scaleY, desiredWidth, desiredHeight);
-            }
             size_t ninePatchArraySize = decoder->mPeeker->mPatch->serializedSize();
             ninePatchChunk = env->NewByteArray(ninePatchArraySize);
             if (ninePatchChunk == nullptr) {
@@ -408,7 +399,12 @@
 
         SkCanvas canvas(scaledBm, SkCanvas::ColorBehavior::kLegacy);
         canvas.translate(translateX, translateY);
-        canvas.scale(scaleX, scaleY);
+        if (scale) {
+            float scaleX = (float) desiredWidth  / decodeInfo.width();
+            float scaleY = (float) desiredHeight / decodeInfo.height();
+            canvas.scale(scaleX, scaleY);
+        }
+
         canvas.drawBitmap(bm, 0.0f, 0.0f, &paint);
 
         bm.swap(scaledBm);
@@ -532,7 +528,7 @@
 
 int register_android_graphics_ImageDecoder(JNIEnv* env) {
     gImageDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ImageDecoder"));
-    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZ)V");
+    gImageDecoder_constructorMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "<init>", "(JIIZZ)V");
     gImageDecoder_postProcessMethodID = GetMethodIDOrDie(env, gImageDecoder_class, "postProcessAndRelease", "(Landroid/graphics/Canvas;)I");
 
     gSize_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/util/Size"));
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 6467976..2a7c256 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -170,7 +170,7 @@
     ];
 
     optional BatteryTypeProto battery_type = 2006 [
-        (section).type = SECTION_FILE,
+        (section).type = SECTION_NONE, // disabled since the path is device specific!
         (section).args = "/sys/class/power_supply/bms/battery_type"
     ];
 
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index b5303c8..05686a0 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -451,6 +451,7 @@
         // If set to 1, {@link Secure#LOCATION_MODE} will be set to {@link
         // Secure#LOCATION_MODE_OFF} temporarily for all users.
         optional SettingProto global_kill_switch = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto gnss_satellite_blacklist = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Location location = 69;
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 593747d..3de8c39 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -340,6 +340,11 @@
     }
     optional Rotation rotation = 46;
 
+    // User-selected RTT mode. When on, outgoing and incoming calls will be
+    // answered as RTT calls when supported by the device and carrier. Boolean
+    // value.
+    optional SettingProto rtt_calling_mode = 69 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
     message Screensaver {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
 
@@ -474,5 +479,5 @@
 
     // Please insert fields in alphabetical order and group them into messages
     // if possible (to avoid reaching the method limit).
-    // Next tag = 69;
+    // Next tag = 70;
 }
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 6b6edd2..dfc4081 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -151,10 +151,7 @@
     }
     optional Rotation rotation = 20;
 
-    // User-selected RTT mode. When on, outgoing and incoming calls will be
-    // answered as RTT calls when supported by the device and carrier. Boolean
-    // value.
-    optional SettingProto rtt_calling_mode = 21 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    reserved 21; // rtt_calling_mode moved to Settings.Secure
 
     message Screen {
         option (android.msg_privacy).dest = DEST_EXPLICIT;
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index cccd2fe..bcd7f29 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -65,7 +65,7 @@
     optional bool can_vibrate = 7;
     optional bool can_show_light = 8;
     optional string group_key = 9 [ (.android.privacy).dest = DEST_EXPLICIT ];
-    optional int32 importance = 10;
+    optional sint32 importance = 10;
 }
 
 message ListenersDisablingEffectsProto {
@@ -122,11 +122,11 @@
         // Default value is UNKNOWN_UID = USER_NULL = -10000.
         optional int32 uid = 2;
         // Default is IMPORTANCE_UNSPECIFIED (-1000).
-        optional int32 importance = 3;
+        optional sint32 importance = 3;
         // Default is PRIORITY_DEFAULT (0).
         optional int32 priority = 4;
         // Default is VISIBILITY_NO_OVERRIDE (-1000).
-        optional int32 visibility = 5;
+        optional sint32 visibility = 5;
         // Default is true.
         optional bool show_badge = 6;
         repeated android.app.NotificationChannelProto channels = 7;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b7b5f23..da15506 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2030,6 +2030,15 @@
     <permission android:name="android.permission.START_ANY_ACTIVITY"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Must be required by activities that handle the intent action
+         {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
+         hold {@link Manifest.permission#SUSPEND_APPS} to interact with the system.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"
+                android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS" />
+
     <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
         API is no longer supported. -->
     <permission android:name="android.permission.RESTART_PACKAGES"
@@ -4116,6 +4125,12 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="com.android.internal.app.SuspendedAppActivity"
+                  android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:excludeFromRecents="true"
+                  android:process=":ui">
+        </activity>
+
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog.Alert"
                 android:excludeFromRecents="true"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3cd80f2..12e5dfe 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2249,6 +2249,10 @@
          mirror the content of the default display. -->
     <bool name="config_localDisplaysMirrorContent">true</bool>
 
+    <!-- Indicates whether local non-default displays are private.
+         {@see android.view.Display#FLAG_PRIVATE} -->
+    <bool name="config_localDisplaysPrivate">false</bool>
+
     <!-- The default mode for the default display. One of the following values (See Display.java):
              0 - COLOR_MODE_DEFAULT
              7 - COLOR_MODE_SRGB
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 17b9d28..715be5b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4703,6 +4703,13 @@
     <!-- Menu item in the locale menu  [CHAR LIMIT=30] -->
     <string name="locale_search_menu">Search</string>
 
+    <!-- Title of the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=30] -->
+    <string name="app_suspended_title">Action not allowed</string>
+    <!-- Default message shown in the dialog that is shown when the user tries to launch a suspended application [CHAR LIMIT=NONE] -->
+    <string name="app_suspended_default_message">The application <xliff:g id="app_name" example="GMail">%1$s</xliff:g> is currently disabled.</string>
+    <!-- Title of the button to show users more details about why the app has been suspended [CHAR LIMIT=50]-->
+    <string name="app_suspended_more_details">More details</string>
+
     <!-- Title of a dialog. The string is asking if the user wants to turn on their work profile, which contains work apps that are managed by their employer. "Work" is an adjective. [CHAR LIMIT=30] -->
     <string name="work_mode_off_title">Turn on work profile?</string>
     <!-- Text in a dialog. This string describes what will happen if a user decides to turn on their work profile. "Work profile" is used as an adjective. [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ac5c3ab..5856648 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -352,6 +352,7 @@
   <java-symbol type="bool" name="config_noHomeScreen" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="bool" name="config_localDisplaysMirrorContent" />
+  <java-symbol type="bool" name="config_localDisplaysPrivate" />
   <java-symbol type="integer" name="config_defaultDisplayDefaultColorMode" />
   <java-symbol type="bool" name="config_enableAppWidgetService" />
   <java-symbol type="string" name="config_defaultPictureInPictureScreenEdgeInsets" />
@@ -2877,6 +2878,10 @@
 
   <java-symbol type="string" name="suspended_widget_accessibility" />
 
+  <java-symbol type="string" name="app_suspended_title" />
+  <java-symbol type="string" name="app_suspended_more_details" />
+  <java-symbol type="string" name="app_suspended_default_message" />
+
   <!-- Used internally for assistant to launch activity transitions -->
   <java-symbol type="id" name="cross_task_transition" />
 
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 002c9e2..b1936b9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -239,6 +239,7 @@
                     Settings.Global.GLOBAL_HTTP_PROXY_HOST,
                     Settings.Global.GLOBAL_HTTP_PROXY_PAC,
                     Settings.Global.GLOBAL_HTTP_PROXY_PORT,
+                    Settings.Global.GNSS_SATELLITE_BLACKLIST,
                     Settings.Global.GPRS_REGISTER_CHECK_PERIOD_MS,
                     Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
                     Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 4210c5c..098f100 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -581,7 +581,7 @@
     /** @removed
      * @deprecated Subsumed by {@link #DecodeException}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public static class IncompleteException extends IOException {};
 
     /**
@@ -613,19 +613,19 @@
     /** @removed
      * @deprecated Replaced by {@link #DecodeException#SOURCE_EXCEPTION}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public static final int ERROR_SOURCE_EXCEPTION  = 1;
 
     /** @removed
      * @deprecated Replaced by {@link #DecodeException#SOURCE_INCOMPLETE}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public static final int ERROR_SOURCE_INCOMPLETE = 2;
 
     /** @removed
      * @deprecated Replaced by {@link #DecodeException#SOURCE_MALFORMED_DATA}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public static final int ERROR_SOURCE_ERROR      = 3;
 
     /**
@@ -748,6 +748,7 @@
     private final int     mWidth;
     private final int     mHeight;
     private final boolean mAnimated;
+    private final boolean mIsNinePatch;
 
     private int        mDesiredWidth;
     private int        mDesiredHeight;
@@ -778,13 +779,14 @@
      */
     @SuppressWarnings("unused")
     private ImageDecoder(long nativePtr, int width, int height,
-            boolean animated) {
+            boolean animated, boolean isNinePatch) {
         mNativePtr = nativePtr;
         mWidth = width;
         mHeight = height;
         mDesiredWidth = width;
         mDesiredHeight = height;
         mAnimated = animated;
+        mIsNinePatch = isNinePatch;
         mCloseGuard.open("close");
     }
 
@@ -1000,7 +1002,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setTargetSize}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setResize(int width, int height) {
         this.setTargetSize(width, height);
         return this;
@@ -1039,7 +1041,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setTargetSampleSize}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setResize(int sampleSize) {
         this.setTargetSampleSize(sampleSize);
         return this;
@@ -1125,7 +1127,7 @@
     /**
      *  Use a software allocation for the pixel memory.
      *
-     *  Useful for drawing to a software {@link Canvas} or for
+     *  <p>Useful for drawing to a software {@link Canvas} or for
      *  accessing the pixels on the final output.
      */
     public static final int ALLOCATOR_SOFTWARE = 1;
@@ -1133,14 +1135,14 @@
     /**
      *  Use shared memory for the pixel memory.
      *
-     *  Useful for sharing across processes.
+     *  <p>Useful for sharing across processes.
      */
     public static final int ALLOCATOR_SHARED_MEMORY = 2;
 
     /**
      *  Require a {@link Bitmap.Config#HARDWARE} {@link Bitmap}.
      *
-     *  When this is combined with incompatible options, like
+     *  <p>When this is combined with incompatible options, like
      *  {@link #setMutableRequired setMutableRequired(true)} or
      *  {@link #setDecodeAsAlphaMaskEnabled setDecodeAsAlphaMaskEnabled(true)},
      *  {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap decodeBitmap}
@@ -1203,7 +1205,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setUnpremultipliedRequired}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setRequireUnpremultiplied(boolean unpremultipliedRequired) {
         this.setUnpremultipliedRequired(unpremultipliedRequired);
         return this;
@@ -1219,7 +1221,7 @@
     /** @removed
      * @deprecated Renamed to {@link #isUnpremultipliedRequired}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public boolean getRequireUnpremultiplied() {
         return this.isUnpremultipliedRequired();
     }
@@ -1348,7 +1350,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setMutableRequired}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setMutable(boolean mutable) {
         this.setMutableRequired(mutable);
         return this;
@@ -1364,37 +1366,68 @@
     /** @removed
      * @deprecated Renamed to {@link #isMutableRequired}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public boolean getMutable() {
         return this.isMutableRequired();
     }
 
     /**
-     *  Specify whether to potentially save RAM at the expense of quality.
+     * Save memory if possible by using a denser {@link Bitmap.Config} at the
+     * cost of some image quality.
      *
-     *  <p>Setting this to {@code true} may result in a {@link Bitmap} with a
-     *  denser {@link Bitmap.Config}, depending on the image. For example, an
-     *  opaque {@link Bitmap} with 8 bits or precision for each of its red,
-     *  green and blue components would decode to
-     *  {@link Bitmap.Config#ARGB_8888} by default, but setting this to
-     *  {@code true} will result in decoding to {@link Bitmap.Config#RGB_565}.
-     *  This necessarily lowers the quality of the output, but saves half
-     *  the memory used.</p>
+     * <p>For example an opaque 8-bit image may be compressed into an
+     * {@link Bitmap.Config#RGB_565} configuration, sacrificing image
+     * quality to save memory.
+     */
+    public static final int MEMORY_POLICY_LOW_RAM = 0;
+
+    /**
+     * Use the most natural {@link Bitmap.Config} for the internal {@link Bitmap}.
+     *
+     * <p>This is the recommended default for most applications and usages. This
+     * will use the closest {@link Bitmap.Config} for the encoded source. If the
+     * encoded source does not exactly match any {@link Bitmap.Config}, the next
+     * highest quality {@link Bitmap.Config} will be used avoiding any loss in
+     * image quality.
+     */
+    public static final int MEMORY_POLICY_DEFAULT  = 1;
+
+    /** @hide **/
+    @Retention(SOURCE)
+    @IntDef(value = { MEMORY_POLICY_DEFAULT, MEMORY_POLICY_LOW_RAM },
+              prefix = {"MEMORY_POLICY_"})
+    public @interface MemoryPolicy {};
+
+    /**
+     *  Specify the memory policy for the decoded {@link Bitmap}.
      *
      *  <p>Like all setters on ImageDecoder, this must be called inside
      *  {@link OnHeaderDecodedListener#onHeaderDecoded onHeaderDecoded}.</p>
      */
+    public void setMemorySizePolicy(@MemoryPolicy int policy) {
+        mConserveMemory = (policy == MEMORY_POLICY_LOW_RAM);
+    }
+
+    /**
+     *  Retrieve the memory policy for the decoded {@link Bitmap}.
+     */
+    @MemoryPolicy
+    public int getMemorySizePolicy() {
+        return mConserveMemory ? MEMORY_POLICY_LOW_RAM : MEMORY_POLICY_DEFAULT;
+    }
+
+    /** @removed
+     * @deprecated Replaced by {@link #setMemorySizePolicy}.
+     */
+    @Deprecated
     public void setConserveMemory(boolean conserveMemory) {
         mConserveMemory = conserveMemory;
     }
 
-    /**
-     *  Return whether this object will try to save RAM at the expense of quality.
-     *
-     *  <p>This returns whether {@link #setConserveMemory} was set to {@code true}.
-     *  It may still return {@code true} even if the {@code ImageDecoder} does not
-     *  have a way to save RAM at the expense of quality for this image.</p>
+    /** @removed
+     * @deprecated Replaced by {@link #getMemorySizePolicy}.
      */
+    @Deprecated
     public boolean getConserveMemory() {
         return mConserveMemory;
     }
@@ -1421,7 +1454,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setDecodeAsAlphaMask(boolean enabled) {
         this.setDecodeAsAlphaMaskEnabled(enabled);
         return this;
@@ -1430,7 +1463,7 @@
     /** @removed
      * @deprecated Renamed to {@link #setDecodeAsAlphaMaskEnabled}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public ImageDecoder setAsAlphaMask(boolean asAlphaMask) {
         this.setDecodeAsAlphaMask(asAlphaMask);
         return this;
@@ -1451,7 +1484,7 @@
     /** @removed
      * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public boolean getDecodeAsAlphaMask() {
         return mDecodeAsAlphaMask;
     }
@@ -1459,7 +1492,7 @@
     /** @removed
      * @deprecated Renamed to {@link #isDecodeAsAlphaMaskEnabled}.
      */
-    @java.lang.Deprecated
+    @Deprecated
     public boolean getAsAlphaMask() {
         return this.getDecodeAsAlphaMask();
     }
@@ -1634,7 +1667,7 @@
 
             // this call potentially manipulates the decoder so it must be performed prior to
             // decoding the bitmap and after decode set the density on the resulting bitmap
-            final int srcDensity = computeDensity(src, decoder);
+            final int srcDensity = decoder.computeDensity(src);
             if (decoder.mAnimated) {
                 // AnimatedImageDrawable calls postProcessAndRelease only if
                 // mPostProcessor exists.
@@ -1724,7 +1757,7 @@
 
             // this call potentially manipulates the decoder so it must be performed prior to
             // decoding the bitmap
-            final int srcDensity = computeDensity(src, decoder);
+            final int srcDensity = decoder.computeDensity(src);
             Bitmap bm = decoder.decodeBitmapInternal();
             bm.setDensity(srcDensity);
 
@@ -1741,12 +1774,26 @@
     }
 
     // This method may modify the decoder so it must be called prior to performing the decode
-    private static int computeDensity(@NonNull Source src, @NonNull ImageDecoder decoder) {
+    private int computeDensity(@NonNull Source src) {
         // if the caller changed the size then we treat the density as unknown
-        if (decoder.requestedResize()) {
+        if (this.requestedResize()) {
             return Bitmap.DENSITY_NONE;
         }
 
+        final int srcDensity = src.getDensity();
+        if (srcDensity == Bitmap.DENSITY_NONE) {
+            return srcDensity;
+        }
+
+        // Scaling up nine-patch divs is imprecise and is better handled
+        // at draw time. An app won't be relying on the internal Bitmap's
+        // size, so it is safe to let NinePatchDrawable handle scaling.
+        // mPostProcessor disables nine-patching, so behave normally if
+        // it is present.
+        if (mIsNinePatch && mPostProcessor == null) {
+            return srcDensity;
+        }
+
         // Special stuff for compatibility mode: if the target density is not
         // the same as the display density, but the resource -is- the same as
         // the display density, then don't scale it down to the target density.
@@ -1755,23 +1802,25 @@
         // to the compatibility density only to have them scaled back up when
         // drawn to the screen.
         Resources res = src.getResources();
-        final int srcDensity = src.getDensity();
         if (res != null && res.getDisplayMetrics().noncompatDensityDpi == srcDensity) {
             return srcDensity;
         }
 
+        final int dstDensity = src.computeDstDensity();
+        if (srcDensity == dstDensity) {
+            return srcDensity;
+        }
+
         // For P and above, only resize if it would be a downscale. Scale up prior
         // to P in case the app relies on the Bitmap's size without considering density.
-        final int dstDensity = src.computeDstDensity();
-        if (srcDensity == Bitmap.DENSITY_NONE || srcDensity == dstDensity
-                || (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P)) {
+        if (srcDensity < dstDensity && sApiLevel >= Build.VERSION_CODES.P) {
             return srcDensity;
         }
 
         float scale = (float) dstDensity / srcDensity;
-        int scaledWidth = (int) (decoder.mWidth * scale + 0.5f);
-        int scaledHeight = (int) (decoder.mHeight * scale + 0.5f);
-        decoder.setTargetSize(scaledWidth, scaledHeight);
+        int scaledWidth = (int) (mWidth * scale + 0.5f);
+        int scaledHeight = (int) (mHeight * scale + 0.5f);
+        this.setTargetSize(scaledWidth, scaledHeight);
         return dstDensity;
     }
 
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index 4f1d2d5..7ad83ca 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -37,3 +37,20 @@
         "liblog",
     ],
 }
+
+cc_test {
+    name: "libprotoutil_test",
+
+    srcs: [
+        "tests/EncodedBuffer_test.cpp",
+    ],
+
+    shared_libs: [
+        "libcutils",
+        "libprotoutil",
+    ],
+
+    static_libs: [
+        "libgmock",
+    ],
+}
diff --git a/libs/protoutil/AndroidTest.xml b/libs/protoutil/AndroidTest.xml
new file mode 100644
index 0000000..46d418e
--- /dev/null
+++ b/libs/protoutil/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<configuration description="Config for libprotoutil_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libprotoutil_test->/data/nativetest/libprotoutil_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/nativetest" />
+        <option name="module-name" value="libprotoutil_test" />
+    </test>
+</configuration>
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
index 3a5e2e9..c017851 100644
--- a/libs/protoutil/src/EncodedBuffer.cpp
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -13,11 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_TAG "libprotoutil"
+
+#include <stdlib.h>
 
 #include <android/util/EncodedBuffer.h>
 #include <android/util/protobuf.h>
-
-#include <stdlib.h>
+#include <cutils/log.h>
 
 namespace android {
 namespace util {
@@ -228,7 +230,7 @@
     size_t start = mEp.pos();
     while (true) {
         uint8_t byte = readRawByte();
-        val += (byte & 0x7F) << shift;
+        val |= (UINT64_C(0x7F) & byte) << shift;
         if ((byte & 0x80) == 0) break;
         shift += 7;
     }
@@ -345,7 +347,7 @@
     uint64_t val = 0, shift = 0;
     while (true) {
         uint8_t byte = next();
-        val += (byte & 0x7F) << shift;
+        val |= (INT64_C(0x7F) & byte) << shift;
         if ((byte & 0x80) == 0) break;
         shift += 7;
     }
diff --git a/libs/protoutil/tests/EncodedBuffer_test.cpp b/libs/protoutil/tests/EncodedBuffer_test.cpp
new file mode 100644
index 0000000..615ab4a
--- /dev/null
+++ b/libs/protoutil/tests/EncodedBuffer_test.cpp
@@ -0,0 +1,25 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <android/util/EncodedBuffer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace android::util;
+
+TEST(EncodedBufferTest, ReadVarint) {
+    EncodedBuffer buffer;
+    uint64_t val = UINT64_C(1522865904593);
+    buffer.writeRawVarint64(val);
+    EXPECT_EQ(val, buffer.begin().readRawVarint());
+}
diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java
index 21d6873..1cb4d67 100644
--- a/media/java/android/media/audiofx/AudioEffect.java
+++ b/media/java/android/media/audiofx/AudioEffect.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.os.Handler;
 import android.os.Looper;
@@ -133,9 +134,10 @@
               .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e");
 
     /**
-     * Null effect UUID. Used when the UUID for effect type of
+     * Null effect UUID. See {@link AudioEffect(UUID, UUID, int, int)} for use.
      * @hide
      */
+    @TestApi
     public static final UUID EFFECT_TYPE_NULL = UUID
             .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index f43e719..67053d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -742,6 +742,9 @@
         dumpSetting(s, p,
                 Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
                 GlobalSettingsProto.Location.GLOBAL_KILL_SWITCH);
+        dumpSetting(s, p,
+                Settings.Global.GNSS_SATELLITE_BLACKLIST,
+                GlobalSettingsProto.Location.GNSS_SATELLITE_BLACKLIST);
         p.end(locationToken);
 
         final long lpmToken = p.start(GlobalSettingsProto.LOW_POWER_MODE);
@@ -2019,6 +2022,10 @@
                 SecureSettingsProto.Rotation.NUM_ROTATION_SUGGESTIONS_ACCEPTED);
         p.end(rotationToken);
 
+        dumpSetting(s, p,
+                Settings.Secure.RTT_CALLING_MODE,
+                SecureSettingsProto.RTT_CALLING_MODE);
+
         final long screensaverToken = p.start(SecureSettingsProto.SCREENSAVER);
         dumpSetting(s, p,
                 Settings.Secure.SCREENSAVER_ENABLED,
@@ -2402,10 +2409,6 @@
                 SystemSettingsProto.Rotation.HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
         p.end(rotationToken);
 
-        dumpSetting(s, p,
-                Settings.System.RTT_CALLING_MODE,
-                SystemSettingsProto.RTT_CALLING_MODE);
-
         final long screenToken = p.start(SystemSettingsProto.SCREEN);
         dumpSetting(s, p,
                 Settings.System.SCREEN_OFF_TIMEOUT,
diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
index e765320c..babaa9f 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ethernet.xml
@@ -20,11 +20,11 @@
         android:viewportWidth="53.0"
         android:viewportHeight="48.0">
     <path
-        android:fillColor="?attr/singleToneColor"
+        android:fillColor="#FFF"
         android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
     <path
-        android:fillColor="?attr/singleToneColor"
+        android:fillColor="#FFF"
         android:pathData="M49.000000,40.000000l4.000000,0.000000l0.000000,4.000000l-4.000000,0.000000z"/>
     <path
-        android:fillColor="?attr/singleToneColor"
+        android:fillColor="#FFF"
         android:pathData="M49.000000,20.000000l4.000000,0.000000l0.000000,16.100000l-4.000000,0.000000z"/></vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml b/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
index b7b154c..08a9993 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ethernet_fully.xml
@@ -19,6 +19,6 @@
         android:viewportWidth="53.0"
         android:viewportHeight="48.0">
     <path
-        android:fillColor="?attr/singleToneColor"
+        android:fillColor="#FFF"
         android:pathData="M15.54 13.52l-3.08-2.55L1.64 24l10.82 13.04 3.08-2.55L6.84 24l8.7-10.48zM14 26h4v-4h-4v4zm20-4h-4v4h4v-4zm-12 4h4v-4h-4v4zm13.54-15.04l-3.08 2.55L41.16 24l-8.7 10.48 3.08 2.55L46.36 24 35.54 10.96z"/>
 </vector>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 107249b..ca5b034 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -71,6 +71,9 @@
 
     private static final ActivityManagerWrapper sInstance = new ActivityManagerWrapper();
 
+    // Should match the values in PhoneWindowManager
+    public static final String CLOSE_SYSTEM_WINDOWS_REASON_RECENTS = "recentapps";
+
     private final PackageManager mPackageManager;
     private final BackgroundExecutor mBackgroundExecutor;
     private final TaskStackChangeListeners mTaskStackChangeListeners;
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
index 3577c0f..c238e54 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogImpl.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.hardware.biometrics.BiometricDialog;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
@@ -48,7 +48,7 @@
 
     private FingerprintDialogView mDialogView;
     private WindowManager mWindowManager;
-    private IBiometricDialogReceiver mReceiver;
+    private IBiometricPromptReceiver mReceiver;
     private boolean mDialogShowing;
 
     private Handler mHandler = new Handler() {
@@ -97,7 +97,7 @@
     }
 
     @Override
-    public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+    public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
         if (DEBUG) Log.d(TAG, "showFingerprintDialog");
         // Remove these messages as they are part of the previous client
         mHandler.removeMessages(MSG_FINGERPRINT_ERROR);
@@ -139,7 +139,7 @@
             Log.w(TAG, "Dialog already showing");
             return;
         }
-        mReceiver = (IBiometricDialogReceiver) args.arg2;
+        mReceiver = (IBiometricPromptReceiver) args.arg2;
         mDialogView.setBundle((Bundle)args.arg1);
         mWindowManager.addView(mDialogView, mDialogView.getLayoutParams());
         mDialogShowing = true;
@@ -177,7 +177,7 @@
         }
         if (userCanceled) {
             try {
-                mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_USER_CANCEL);
+                mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException when hiding dialog", e);
             }
@@ -193,7 +193,7 @@
             return;
         }
         try {
-            mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_NEGATIVE);
+            mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_NEGATIVE);
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling negative button", e);
         }
@@ -206,7 +206,7 @@
             return;
         }
         try {
-            mReceiver.onDialogDismissed(BiometricDialog.DISMISSED_REASON_POSITIVE);
+            mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_POSITIVE);
         } catch (RemoteException e) {
             Log.e(TAG, "Remote exception when handling positive button", e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
index 3e1ac02..6921836 100644
--- a/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/fingerprint/FingerprintDialogView.java
@@ -22,7 +22,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricDialog;
+import android.hardware.biometrics.BiometricPrompt;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -161,10 +161,10 @@
         mLastState = STATE_NONE;
         updateFingerprintIcon(STATE_FINGERPRINT);
 
-        title.setText(mBundle.getCharSequence(BiometricDialog.KEY_TITLE));
+        title.setText(mBundle.getCharSequence(BiometricPrompt.KEY_TITLE));
         title.setSelected(true);
 
-        final CharSequence subtitleText = mBundle.getCharSequence(BiometricDialog.KEY_SUBTITLE);
+        final CharSequence subtitleText = mBundle.getCharSequence(BiometricPrompt.KEY_SUBTITLE);
         if (subtitleText == null) {
             subtitle.setVisibility(View.GONE);
         } else {
@@ -172,18 +172,18 @@
             subtitle.setText(subtitleText);
         }
 
-        final CharSequence descriptionText = mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION);
+        final CharSequence descriptionText = mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION);
         if (descriptionText == null) {
             subtitle.setVisibility(View.VISIBLE);
             description.setVisibility(View.GONE);
         } else {
-            description.setText(mBundle.getCharSequence(BiometricDialog.KEY_DESCRIPTION));
+            description.setText(mBundle.getCharSequence(BiometricPrompt.KEY_DESCRIPTION));
         }
 
-        negative.setText(mBundle.getCharSequence(BiometricDialog.KEY_NEGATIVE_TEXT));
+        negative.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
 
         final CharSequence positiveText =
-                mBundle.getCharSequence(BiometricDialog.KEY_POSITIVE_TEXT);
+                mBundle.getCharSequence(BiometricPrompt.KEY_POSITIVE_TEXT);
         positive.setText(positiveText); // needs to be set for marquee to work
         if (positiveText != null) {
             positive.setVisibility(View.VISIBLE);
@@ -269,7 +269,7 @@
         mErrorText.setTextColor(mErrorColor);
         mErrorText.setContentDescription(message);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_CLEAR_MESSAGE),
-                BiometricDialog.HIDE_DIALOG_DELAY);
+                BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
     public void showHelpMessage(String message) {
@@ -279,7 +279,7 @@
     public void showErrorMessage(String error) {
         showTemporaryMessage(error);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(FingerprintDialogImpl.MSG_HIDE_DIALOG,
-                false /* userCanceled */), BiometricDialog.HIDE_DIALOG_DELAY);
+                false /* userCanceled */), BiometricPrompt.HIDE_DIALOG_DELAY);
     }
 
     private void updateFingerprintIcon(int newState) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 0f85c5b..8bb3c02 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -22,6 +22,7 @@
 import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
 
 import android.app.ActivityManager;
+import android.app.trust.TrustManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -51,6 +52,7 @@
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
+import com.android.systemui.SystemUIApplication;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.events.EventBus;
@@ -70,6 +72,7 @@
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
 
+import com.android.systemui.statusbar.phone.StatusBar;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -107,6 +110,7 @@
 
     private Handler mHandler;
     private RecentsImpl mImpl;
+    private TrustManager mTrustManager;
     private int mDraggingInRecentsCurrentUser;
 
     // Only For system user, this is the callbacks instance we return to each secondary user
@@ -235,6 +239,8 @@
             registerWithSystemUser();
         }
         putComponent(Recents.class, this);
+
+        mTrustManager = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
     }
 
     @Override
@@ -342,12 +348,28 @@
         // If connected to launcher service, let it handle the toggle logic
         IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
         if (overviewProxy != null) {
-            try {
-                overviewProxy.onOverviewToggle();
-                return;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+            final Runnable toggleRecents = () -> {
+                try {
+                    if (mOverviewProxyService.getProxy() != null) {
+                        mOverviewProxyService.getProxy().onOverviewToggle();
+                    }
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Cannot send toggle recents through proxy service.", e);
+                }
+            };
+            // Preload only if device for current user is unlocked
+            final StatusBar statusBar = getComponent(StatusBar.class);
+            if (statusBar != null && statusBar.isKeyguardShowing()) {
+                statusBar.executeRunnableDismissingKeyguard(() -> {
+                        // Flush trustmanager before checking device locked per user
+                        mTrustManager.reportKeyguardShowingChanged();
+                        mHandler.post(toggleRecents);
+                    }, null,  true /* dismissShade */, false /* afterKeyguardGone */,
+                    true /* deferred */);
+            } else {
+                toggleRecents.run();
             }
+            return;
         }
 
         int growTarget = getComponent(Divider.class).getView().growsRecents();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 65037f9..6fd0aa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -18,7 +18,7 @@
 
 import android.content.ComponentName;
 import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -160,7 +160,7 @@
 
         default void onRotationProposal(int rotation, boolean isValid) { }
 
-        default void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) { }
+        default void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) { }
         default void onFingerprintAuthenticated() { }
         default void onFingerprintHelp(String message) { }
         default void onFingerprintError(String error) { }
@@ -513,7 +513,7 @@
     }
 
     @Override
-    public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+    public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = bundle;
@@ -759,7 +759,7 @@
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).showFingerprintDialog(
                                 (Bundle)((SomeArgs)msg.obj).arg1,
-                                (IBiometricDialogReceiver)((SomeArgs)msg.obj).arg2);
+                                (IBiometricPromptReceiver)((SomeArgs)msg.obj).arg2);
                     }
                     break;
                 case MSG_FINGERPRINT_AUTHENTICATED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index f81671b..51b4239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -142,12 +142,14 @@
         if (mState.strengthId != state.strengthId) {
             mMobileDrawable.setLevel(state.strengthId);
         }
-        if (mState.typeId != state.typeId && state.typeId != 0) {
-            mMobileType.setContentDescription(state.typeContentDescription);
-            mMobileType.setImageResource(state.typeId);
-            mMobileType.setVisibility(View.VISIBLE);
-        } else {
-            mMobileType.setVisibility(View.GONE);
+        if (mState.typeId != state.typeId) {
+            if (state.typeId != 0) {
+                mMobileType.setContentDescription(state.typeContentDescription);
+                mMobileType.setImageResource(state.typeId);
+                mMobileType.setVisibility(View.VISIBLE);
+            } else {
+                mMobileType.setVisibility(View.GONE);
+            }
         }
 
         mMobileRoaming.setVisibility(state.roaming ? View.VISIBLE : View.GONE);
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 4c4eb60..db2139d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,7 +39,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemProperties;
-import android.os.VibrationEffect;
 import android.support.annotation.ColorInt;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -69,7 +68,6 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.NavigationBarCompat;
 import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.DeadZone;
 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
 import com.android.systemui.statusbar.policy.TintedKeyButtonDrawable;
@@ -150,7 +148,6 @@
     private Divider mDivider;
     private RecentsOnboarding mRecentsOnboarding;
     private NotificationPanelView mPanelView;
-    private final VibratorHelper mVibratorHelper;
 
     private int mRotateBtnStyle = R.style.RotateButtonCCWStart90;
 
@@ -246,7 +243,6 @@
 
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
-        mVibratorHelper = Dependency.get(VibratorHelper.class);
 
         mConfiguration = new Configuration();
         mConfiguration.updateFrom(context.getResources().getConfiguration());
@@ -314,9 +310,6 @@
                 } else if (mRecentsButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_OVERVIEW;
                 }
-
-                // Vibrate tick whenever down occurs on navigation bar
-                mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
                 break;
         }
         return mGestureHelper.onInterceptTouchEvent(event);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 9adf923..8c257fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -370,11 +370,15 @@
         float layoutEnd = getLayoutEnd();
         float overflowStart = getMaxOverflowStart();
         mVisualOverflowStart = 0;
+        mFirstVisibleIconState = null;
         boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount();
         for (int i = 0; i < childCount; i++) {
             View view = getChildAt(i);
             IconState iconState = mIconStates.get(view);
             iconState.xTranslation = translationX;
+            if (mFirstVisibleIconState == null) {
+                mFirstVisibleIconState = iconState;
+            }
             boolean forceOverflow = mSpeedBumpIndex != -1 && i >= mSpeedBumpIndex
                     && iconState.iconAppearAmount > 0.0f || i >= maxVisibleIcons;
             boolean noOverflowAfter = i == childCount - 1;
@@ -401,7 +405,6 @@
         mNumDots = 0;
         if (firstOverflowIndex != -1) {
             translationX = mVisualOverflowStart;
-            mFirstVisibleIconState = null;
             for (int i = firstOverflowIndex; i < childCount; i++) {
                 View view = getChildAt(i);
                 IconState iconState = mIconStates.get(view);
@@ -416,9 +419,6 @@
                     }
                     translationX += (mNumDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth)
                             * iconState.iconAppearAmount;
-                    if (mFirstVisibleIconState == null) {
-                        mFirstVisibleIconState = iconState;
-                    }
                     mLastVisibleIconState = iconState;
                 } else {
                     iconState.visibleState = StatusBarIconView.STATE_HIDDEN;
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 2d2d708..3dbac51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -395,7 +395,7 @@
             // Darken scrim as you pull down the shade when unlocked
             float behindFraction = getInterpolatedFraction();
             behindFraction = (float) Math.pow(behindFraction, 0.8f);
-            mCurrentBehindAlpha = behindFraction * mScrimBehindAlphaKeyguard;
+            mCurrentBehindAlpha = behindFraction * GRADIENT_SCRIM_ALPHA_BUSY;
             mCurrentInFrontAlpha = 0;
         } else if (mState == ScrimState.KEYGUARD) {
             // Either darken of make the scrim transparent when you
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 510af03..b4e7575 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -306,17 +306,6 @@
         mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
     }
 
-    /**
-     * For mobile essentially (an array of holders in one slot)
-     */
-    private void handleSet(int slotIndex, List<StatusBarIconHolder> holders) {
-        for (StatusBarIconHolder holder : holders) {
-            int viewIndex = getViewIndex(slotIndex, holder.getTag());
-            mIconLogger.onIconVisibility(getSlotName(slotIndex), holder.isVisible());
-            mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
-        }
-    }
-
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println(TAG + " state:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index c5a3a0d..94ac4f62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -414,7 +414,7 @@
 
         @Override public String toString() {
             return "MobileIconState(subId=" + subId + ", strengthId=" + strengthId + ", roaming="
-                    + roaming + ", visible=" + visible + ")";
+                    + roaming + ", typeId=" + typeId + ", visible=" + visible + ")";
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 2fed3fc..1b02e15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -28,7 +28,6 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.SystemClock;
-import android.os.VibrationEffect;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
@@ -50,7 +49,6 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.statusbar.VibratorHelper;
 
 import static android.view.KeyEvent.KEYCODE_HOME;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
@@ -75,7 +73,6 @@
     private OnClickListener mOnClickListener;
     private final KeyButtonRipple mRipple;
     private final OverviewProxyService mOverviewProxyService;
-    private final VibratorHelper mVibratorHelper;
     private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
 
     private final Runnable mCheckLongPress = new Runnable() {
@@ -121,7 +118,6 @@
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
 
         mRipple = new KeyButtonRipple(context, this);
-        mVibratorHelper = Dependency.get(VibratorHelper.class);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         setBackground(mRipple);
     }
@@ -262,9 +258,8 @@
                 final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
                 if (showSwipeUI) {
                     if (doIt) {
-                        if (doHapticFeedback) {
-                            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
-                        }
+                        // Apply haptic feedback on touch up since there is none on touch down
+                        performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                         playSoundEffect(SoundEffectConstants.CLICK);
                     }
                 } else if (doHapticFeedback && !mLongClicked) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index da7dc07..d282f25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -3023,6 +3023,11 @@
     public void setAnimationsEnabled(boolean animationsEnabled) {
         mAnimationsEnabled = animationsEnabled;
         updateNotificationAnimationStates();
+        if (!animationsEnabled) {
+            mSwipedOutViews.clear();
+            mChildrenToRemoveAnimated.clear();
+            clearTemporaryViewsInGroup(this);
+        }
     }
 
     private void updateNotificationAnimationStates() {
@@ -3090,6 +3095,21 @@
     @Override
     public void changeViewPosition(View child, int newIndex) {
         int currentIndex = indexOfChild(child);
+
+        if (currentIndex == -1) {
+            boolean isTransient = false;
+            if (child instanceof ExpandableNotificationRow
+                    && ((ExpandableNotificationRow)child).getTransientContainer() != null) {
+                isTransient = true;
+            }
+            Log.e(TAG, "Attempting to re-position "
+                    + (isTransient ? "transient" : "")
+                    + " view {"
+                    + child
+                    + "}");
+            return;
+        }
+
         if (child != null && child.getParent() == this && currentIndex != newIndex) {
             mChangePositionInProgress = true;
             ((ExpandableView)child).setChangingPosition(true);
@@ -3569,17 +3589,17 @@
 
     private void clearTemporaryViews() {
         // lets make sure nothing is in the overlay / transient anymore
-        clearTemporaryViews(this);
+        clearTemporaryViewsInGroup(this);
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView child = (ExpandableView) getChildAt(i);
             if (child instanceof ExpandableNotificationRow) {
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                clearTemporaryViews(row.getChildrenContainer());
+                clearTemporaryViewsInGroup(row.getChildrenContainer());
             }
         }
     }
 
-    private void clearTemporaryViews(ViewGroup viewGroup) {
+    private void clearTemporaryViewsInGroup(ViewGroup viewGroup) {
         while (viewGroup != null && viewGroup.getTransientViewCount() != 0) {
             viewGroup.removeTransientView(viewGroup.getTransientView(0));
         }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index c66c7b0..a3dcd45 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5572,6 +5572,12 @@
     // OS: P
     ACTION_SETTINGS_SLICE_CHANGED = 1372;
 
+    // OPEN: Settings > Network & Internet > Wi-Fi > Wi-Fi Preferences > Turn on Wi-Fi automatically
+    //       note: Wifi Scanning must be off for this dialog to show
+    // CATEGORY: SETTINGS
+    // OS: P
+    WIFI_SCANNING_NEEDED_DIALOG = 1373;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 75b651da..067566d 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2645,6 +2645,8 @@
                 Message msg = mAm.mHandler.obtainMessage(
                         ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
                 msg.obj = r.app;
+                msg.getData().putCharSequence(
+                    ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
                 mAm.mHandler.sendMessage(msg);
             }
         }
@@ -3563,13 +3565,15 @@
 
         if (app != null) {
             mAm.mAppErrors.appNotResponding(app, null, null, false,
-                    "Context.startForegroundService() did not then call Service.startForeground()");
+                    "Context.startForegroundService() did not then call Service.startForeground(): "
+                        + r);
         }
     }
 
-    void serviceForegroundCrash(ProcessRecord app) {
+    void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
         mAm.crashApplication(app.uid, app.pid, app.info.packageName, app.userId,
-                "Context.startForegroundService() did not then call Service.startForeground()");
+                "Context.startForegroundService() did not then call Service.startForeground(): "
+                    + serviceRecord);
     }
 
     void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2e87a44..adf3480 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1920,6 +1920,8 @@
     static final int FIRST_COMPAT_MODE_MSG = 300;
     static final int FIRST_SUPERVISOR_STACK_MSG = 100;
 
+    static final String SERVICE_RECORD_KEY = "servicerecord";
+
     static ServiceThread sKillThread = null;
     static KillHandler sKillHandler = null;
 
@@ -2168,7 +2170,8 @@
                 mServices.serviceForegroundTimeout((ServiceRecord)msg.obj);
             } break;
             case SERVICE_FOREGROUND_CRASH_MSG: {
-                mServices.serviceForegroundCrash((ProcessRecord)msg.obj);
+                mServices.serviceForegroundCrash(
+                    (ProcessRecord) msg.obj, msg.getData().getCharSequence(SERVICE_RECORD_KEY));
             } break;
             case DISPATCH_PENDING_INTENT_CANCEL_MSG: {
                 RemoteCallbackList<IResultReceiver> callbacks
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 2ac389d..6ca8a92 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -32,8 +32,10 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
 
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
+import android.Manifest;
 import android.app.ActivityOptions;
-import android.app.AppGlobals;
 import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
@@ -41,6 +43,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.os.Binder;
@@ -51,6 +54,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.HarmfulAppWarningActivity;
+import com.android.internal.app.SuspendedAppActivity;
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
 
@@ -151,7 +155,7 @@
         mInTask = inTask;
         mActivityOptions = activityOptions;
 
-        if (interceptSuspendPackageIfNeed()) {
+        if (interceptSuspendedPackageIfNeeded()) {
             // Skip the rest of interceptions as the package is suspended by device admin so
             // no user action can undo this.
             return true;
@@ -204,12 +208,7 @@
         return true;
     }
 
-    private boolean interceptSuspendPackageIfNeed() {
-        // Do not intercept if the admin did not suspend the package
-        if (mAInfo == null || mAInfo.applicationInfo == null ||
-                (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
-            return false;
-        }
+    private boolean interceptSuspendedByAdminPackage() {
         DevicePolicyManagerInternal devicePolicyManager = LocalServices
                 .getService(DevicePolicyManagerInternal.class);
         if (devicePolicyManager == null) {
@@ -232,6 +231,55 @@
         return true;
     }
 
+    private Intent createSuspendedAppInterceptIntent(String suspendedPackage,
+            String suspendingPackage, String dialogMessage, int userId) {
+        final Intent interceptIntent = new Intent(mServiceContext, SuspendedAppActivity.class)
+                .putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
+                .putExtra(SuspendedAppActivity.EXTRA_DIALOG_MESSAGE, dialogMessage)
+                .putExtra(Intent.EXTRA_USER_ID, userId)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+
+        final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
+                .setPackage(suspendingPackage);
+        final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
+        final ResolveInfo resolvedInfo = mSupervisor.resolveIntent(moreDetailsIntent, null, userId);
+        if (resolvedInfo != null && resolvedInfo.activityInfo != null
+                && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
+            moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            interceptIntent.putExtra(SuspendedAppActivity.EXTRA_MORE_DETAILS_INTENT,
+                    moreDetailsIntent);
+        }
+        return interceptIntent;
+    }
+
+    private boolean interceptSuspendedPackageIfNeeded() {
+        // Do not intercept if the package is not suspended
+        if (mAInfo == null || mAInfo.applicationInfo == null ||
+                (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) == 0) {
+            return false;
+        }
+        final PackageManagerInternal pmi = mService.getPackageManagerInternalLocked();
+        if (pmi == null) {
+            return false;
+        }
+        final String suspendedPackage = mAInfo.applicationInfo.packageName;
+        final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+        if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
+            return interceptSuspendedByAdminPackage();
+        }
+        final String dialogMessage = pmi.getSuspendedDialogMessage(suspendedPackage, mUserId);
+        mIntent = createSuspendedAppInterceptIntent(suspendedPackage, suspendingPackage,
+                dialogMessage, mUserId);
+        mCallingPid = mRealCallingPid;
+        mCallingUid = mRealCallingUid;
+        mResolvedType = null;
+        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, 0);
+        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, null /*profilerInfo*/);
+        return true;
+    }
+
     private boolean interceptWorkProfileChallengeIfNeeded() {
         final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(mAInfo, mUserId);
         if (interceptingIntent == null) {
@@ -293,9 +341,9 @@
     private boolean interceptHarmfulAppIfNeeded() {
         CharSequence harmfulAppWarning;
         try {
-            harmfulAppWarning = AppGlobals.getPackageManager().getHarmfulAppWarning(
-                    mAInfo.packageName, mUserId);
-        } catch (RemoteException e) {
+            harmfulAppWarning = mService.getPackageManager()
+                    .getHarmfulAppWarning(mAInfo.packageName, mUserId);
+        } catch (RemoteException ex) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 8faf931..5337566 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -28,6 +28,7 @@
 import static android.app.ActivityManager.START_TASK_TO_FRONT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -902,14 +903,22 @@
         final int clearTaskFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK;
         boolean clearedTask = (mLaunchFlags & clearTaskFlags) == clearTaskFlags
                 && mReuseTask != null;
-        if (startedActivityStack.inPinnedWindowingMode()
-                && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP
-                || clearedTask)) {
-            // The activity was already running in the pinned stack so it wasn't started, but either
-            // brought to the front or the new intent was delivered to it since it was already in
-            // front. Notify anyone interested in this piece of information.
-            mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
-                    clearedTask);
+        if (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP || clearedTask) {
+            // The activity was already running so it wasn't started, but either brought to the
+            // front or the new intent was delivered to it since it was already in front. Notify
+            // anyone interested in this piece of information.
+            switch (startedActivityStack.getWindowingMode()) {
+                case WINDOWING_MODE_PINNED:
+                    mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
+                            clearedTask);
+                    break;
+                case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+                    final ActivityStack homeStack = mSupervisor.mHomeStack;
+                    if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) {
+                        mService.mWindowManager.showRecentApps();
+                    }
+                    break;
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5ca9abc..b9a279a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -436,6 +436,10 @@
                                 com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
                     }
+
+                    if (res.getBoolean(com.android.internal.R.bool.config_localDisplaysPrivate)) {
+                        mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+                    }
                 }
             }
             return mInfo;
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 8be2c9e..afd1a94 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
-import android.hardware.biometrics.BiometricDialog;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.BiometricPrompt;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -46,8 +46,8 @@
     public static final int LOCKOUT_PERMANENT = 2;
 
     // Callback mechanism received from the client
-    // (BiometricDialog -> FingerprintManager -> FingerprintService -> AuthenticationClient)
-    private IBiometricDialogReceiver mDialogReceiverFromClient;
+    // (BiometricPrompt -> FingerprintManager -> FingerprintService -> AuthenticationClient)
+    private IBiometricPromptReceiver mDialogReceiverFromClient;
     private Bundle mBundle;
     private IStatusBarService mStatusBarService;
     private boolean mInLockout;
@@ -55,13 +55,13 @@
     protected boolean mDialogDismissed;
 
     // Receives events from SystemUI and handles them before forwarding them to FingerprintDialog
-    protected IBiometricDialogReceiver mDialogReceiver = new IBiometricDialogReceiver.Stub() {
+    protected IBiometricPromptReceiver mDialogReceiver = new IBiometricPromptReceiver.Stub() {
         @Override // binder call
         public void onDialogDismissed(int reason) {
             if (mBundle != null && mDialogReceiverFromClient != null) {
                 try {
                     mDialogReceiverFromClient.onDialogDismissed(reason);
-                    if (reason == BiometricDialog.DISMISSED_REASON_USER_CANCEL) {
+                    if (reason == BiometricPrompt.DISMISSED_REASON_USER_CANCEL) {
                         onError(FingerprintManager.FINGERPRINT_ERROR_USER_CANCELED,
                                 0 /* vendorCode */);
                     }
@@ -88,7 +88,7 @@
     public AuthenticationClient(Context context, long halDeviceId, IBinder token,
             IFingerprintServiceReceiver receiver, int targetUserId, int groupId, long opId,
             boolean restricted, String owner, Bundle bundle,
-            IBiometricDialogReceiver dialogReceiver, IStatusBarService statusBarService) {
+            IBiometricPromptReceiver dialogReceiver, IStatusBarService statusBarService) {
         super(context, halDeviceId, token, receiver, targetUserId, groupId, restricted, owner);
         mOpId = opId;
         mBundle = bundle;
@@ -299,7 +299,7 @@
             // If the user already cancelled authentication (via some interaction with the
             // dialog, we do not need to hide it since it's already hidden.
             // If the device is in lockout, don't hide the dialog - it will automatically hide
-            // after BiometricDialog.HIDE_DIALOG_DELAY
+            // after BiometricPrompt.HIDE_DIALOG_DELAY
             if (mBundle != null && !mDialogDismissed && !mInLockout) {
                 try {
                     mStatusBarService.hideFingerprintDialog();
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 92d3772..4e95bdf 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -38,7 +38,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
 import android.hardware.fingerprint.Fingerprint;
@@ -849,7 +849,7 @@
 
     private void startAuthentication(IBinder token, long opId, int callingUserId, int groupId,
                 IFingerprintServiceReceiver receiver, int flags, boolean restricted,
-                String opPackageName, Bundle bundle, IBiometricDialogReceiver dialogReceiver) {
+                String opPackageName, Bundle bundle, IBiometricPromptReceiver dialogReceiver) {
         updateActiveGroup(groupId, opPackageName);
 
         if (DEBUG) Slog.v(TAG, "startAuthentication(" + opPackageName + ")");
@@ -1160,7 +1160,7 @@
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName, final Bundle bundle,
-                final IBiometricDialogReceiver dialogReceiver) {
+                final IBiometricPromptReceiver dialogReceiver) {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 5ba7380..58bca19 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -83,7 +83,11 @@
 import com.android.internal.location.ProviderProperties;
 import com.android.internal.location.ProviderRequest;
 import com.android.internal.location.gnssmetrics.GnssMetrics;
+import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
+
+import libcore.io.IoUtils;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -99,14 +103,13 @@
 import java.util.Map.Entry;
 import java.util.Properties;
 
-import libcore.io.IoUtils;
-
 /**
  * A GNSS implementation of LocationProvider used by LocationManager.
  *
  * {@hide}
  */
-public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback {
+public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback,
+        GnssSatelliteBlacklistCallback {
 
     private static final String TAG = "GnssLocationProvider";
 
@@ -308,7 +311,7 @@
         }
     }
 
-    private Object mLock = new Object();
+    private final Object mLock = new Object();
 
     // current status
     private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
@@ -411,6 +414,7 @@
     private final ILocationManager mILocationManager;
     private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mListenerHelper;
+    private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
@@ -577,6 +581,16 @@
                 }
             };
 
+    /**
+     * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
+     */
+    @Override
+    public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
+        mHandler.post(()->{
+            native_set_satellite_blacklist(constellations, svids);
+        });
+    }
+
     private void subscriptionOrSimChanged(Context context) {
         if (DEBUG) Log.d(TAG, "received SIM related action: ");
         TelephonyManager phone = (TelephonyManager)
@@ -869,7 +883,10 @@
         };
         mGnssMetrics = new GnssMetrics(mBatteryStats);
 
-        mNtpTimeHelper = new NtpTimeHelper(mContext, Looper.myLooper(), this);
+        mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
+        mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext,
+                looper, this);
+        mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
     }
 
     /**
@@ -2900,6 +2917,8 @@
 
     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
 
+    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+
     // GNSS Batching
     private static native int native_get_batch_size();
 
diff --git a/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java b/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java
new file mode 100644
index 0000000..77951aa
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java
@@ -0,0 +1,102 @@
+package com.android.server.location;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Detects blacklist change and updates the blacklist.
+ */
+class GnssSatelliteBlacklistHelper {
+
+    private static final String TAG = "GnssBlacklistHelper";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final String BLACKLIST_DELIMITER = ",";
+
+    private final Context mContext;
+    private final GnssSatelliteBlacklistCallback mCallback;
+
+    interface GnssSatelliteBlacklistCallback {
+        void onUpdateSatelliteBlacklist(int[] constellations, int[] svids);
+    }
+
+    GnssSatelliteBlacklistHelper(Context context, Looper looper,
+            GnssSatelliteBlacklistCallback callback) {
+        mContext = context;
+        mCallback = callback;
+        ContentObserver contentObserver = new ContentObserver(new Handler(looper)) {
+            @Override
+            public void onChange(boolean selfChange) {
+                updateSatelliteBlacklist();
+            }
+        };
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(
+                        Settings.Global.GNSS_SATELLITE_BLACKLIST),
+                true,
+                contentObserver, UserHandle.USER_ALL);
+    }
+
+    void updateSatelliteBlacklist() {
+        ContentResolver resolver = mContext.getContentResolver();
+        String blacklist = Settings.Global.getString(
+                resolver,
+                Settings.Global.GNSS_SATELLITE_BLACKLIST);
+        if (blacklist == null) {
+            blacklist = "";
+        }
+        if (DEBUG) {
+            Log.d(TAG, String.format("Update GNSS satellite blacklist: %s", blacklist));
+        }
+
+        List<Integer> blacklistValues;
+        try {
+            blacklistValues = parseSatelliteBlacklist(blacklist);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Exception thrown when parsing blacklist string.", e);
+            return;
+        }
+
+        if (blacklistValues.size() % 2 != 0) {
+            Log.e(TAG, "blacklist string has odd number of values."
+                    + "Aborting updateSatelliteBlacklist");
+            return;
+        }
+
+        int length = blacklistValues.size() / 2;
+        int[] constellations = new int[length];
+        int[] svids = new int[length];
+        for (int i = 0; i < length; i++) {
+            constellations[i] = blacklistValues.get(i * 2);
+            svids[i] = blacklistValues.get(i * 2 + 1);
+        }
+        mCallback.onUpdateSatelliteBlacklist(constellations, svids);
+    }
+
+    @VisibleForTesting
+    static List<Integer> parseSatelliteBlacklist(String blacklist) throws NumberFormatException {
+        String[] strings = blacklist.split(BLACKLIST_DELIMITER);
+        List<Integer> parsed = new ArrayList<>(strings.length);
+        for (String string : strings) {
+            string = string.trim();
+            if (!"".equals(string)) {
+                int value = Integer.parseInt(string);
+                if (value < 0) {
+                    throw new NumberFormatException("Negative value is invalid.");
+                }
+                parsed.add(value);
+            }
+        }
+        return parsed;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 33c7681..26d4037 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -274,6 +274,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
+import com.android.internal.app.SuspendedAppActivity;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.logging.MetricsLogger;
@@ -14006,8 +14007,8 @@
 
     @Override
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-            PersistableBundle appExtras, PersistableBundle launcherExtras, String callingPackage,
-            int userId) {
+            PersistableBundle appExtras, PersistableBundle launcherExtras, String dialogMessage,
+            String callingPackage, int userId) {
         try {
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SUSPEND_APPS, null);
         } catch (SecurityException e) {
@@ -14055,7 +14056,7 @@
                             unactionedPackages.add(packageName);
                             continue;
                         }
-                        pkgSetting.setSuspended(suspended, callingPackage, appExtras,
+                        pkgSetting.setSuspended(suspended, callingPackage, dialogMessage, appExtras,
                                 launcherExtras, userId);
                         changedPackagesList.add(packageName);
                     }
@@ -14177,7 +14178,7 @@
                 for (int user : userIds) {
                     final PackageUserState pus = ps.readUserState(user);
                     if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
-                        ps.setSuspended(false, null, null, null, user);
+                        ps.setSuspended(false, null, null, null, null, user);
                     }
                 }
             }
@@ -18911,6 +18912,7 @@
                     false /*hidden*/,
                     false /*suspended*/,
                     null, /*suspendingPackage*/
+                    null, /*dialogMessage*/
                     null, /*suspendedAppExtras*/
                     null, /*suspendedLauncherExtras*/
                     false /*instantApp*/,
@@ -23803,6 +23805,22 @@
         }
 
         @Override
+        public String getSuspendingPackage(String suspendedPackage, int userId) {
+            synchronized (mPackages) {
+                final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+                return (ps != null) ? ps.readUserState(userId).suspendingPackage : null;
+            }
+        }
+
+        @Override
+        public String getSuspendedDialogMessage(String suspendedPackage, int userId) {
+            synchronized (mPackages) {
+                final PackageSetting ps = mSettings.mPackages.get(suspendedPackage);
+                return (ps != null) ? ps.readUserState(userId).dialogMessage : null;
+            }
+        }
+
+        @Override
         public int getPackageUid(String packageName, int flags, int userId) {
             return PackageManagerService.this
                     .getPackageUid(packageName, flags, userId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 28e32a5..a92fbb6 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1505,6 +1505,7 @@
     private int runSuspend(boolean suspendedState) {
         final PrintWriter pw = getOutPrintWriter();
         int userId = UserHandle.USER_SYSTEM;
+        String dialogMessage = null;
         final PersistableBundle appExtras = new PersistableBundle();
         final PersistableBundle launcherExtras = new PersistableBundle();
         String opt;
@@ -1513,6 +1514,9 @@
                 case "--user":
                     userId = UserHandle.parseUserArg(getNextArgRequired());
                     break;
+                case "--dialogMessage":
+                    dialogMessage = getNextArgRequired();
+                    break;
                 case "--ael":
                 case "--aes":
                 case "--aed":
@@ -1553,7 +1557,7 @@
                 (Binder.getCallingUid() == Process.ROOT_UID) ? "root" : "com.android.shell";
         try {
             mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
-                    appExtras, launcherExtras, callingPackage, userId);
+                    appExtras, launcherExtras, dialogMessage, callingPackage, userId);
             pw.println("Package " + packageName + " new suspended state: "
                     + mInterface.isPackageSuspendedForUser(packageName, userId));
             return 0;
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 008a81c..fd4c5e9 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -398,11 +398,12 @@
         return readUserState(userId).suspended;
     }
 
-    void setSuspended(boolean suspended, String suspendingPackage, PersistableBundle appExtras,
-            PersistableBundle launcherExtras, int userId) {
+    void setSuspended(boolean suspended, String suspendingPackage, String dialogMessage,
+            PersistableBundle appExtras, PersistableBundle launcherExtras, int userId) {
         final PackageUserState existingUserState = modifyUserState(userId);
         existingUserState.suspended = suspended;
         existingUserState.suspendingPackage = suspended ? suspendingPackage : null;
+        existingUserState.dialogMessage = suspended ? dialogMessage : null;
         existingUserState.suspendedAppExtras = suspended ? appExtras : null;
         existingUserState.suspendedLauncherExtras = suspended ? launcherExtras : null;
     }
@@ -425,8 +426,8 @@
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
             boolean notLaunched, boolean hidden, boolean suspended, String suspendingPackage,
-            PersistableBundle suspendedAppExtras, PersistableBundle suspendedLauncherExtras,
-            boolean instantApp,
+            String dialogMessage, PersistableBundle suspendedAppExtras,
+            PersistableBundle suspendedLauncherExtras, boolean instantApp,
             boolean virtualPreload, String lastDisableAppCaller,
             ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
             int domainVerifState, int linkGeneration, int installReason,
@@ -440,6 +441,7 @@
         state.hidden = hidden;
         state.suspended = suspended;
         state.suspendingPackage = suspendingPackage;
+        state.dialogMessage = dialogMessage;
         state.suspendedAppExtras = suspendedAppExtras;
         state.suspendedLauncherExtras = suspendedLauncherExtras;
         state.lastDisableAppCaller = lastDisableAppCaller;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d0e8544..898ecf3 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -222,6 +222,7 @@
     private static final String ATTR_HIDDEN = "hidden";
     private static final String ATTR_SUSPENDED = "suspended";
     private static final String ATTR_SUSPENDING_PACKAGE = "suspending-package";
+    private static final String ATTR_SUSPEND_DIALOG_MESSAGE = "suspend_dialog_message";
     // Legacy, uninstall blocks are stored separately.
     @Deprecated
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
@@ -734,6 +735,7 @@
                                 false /*hidden*/,
                                 false /*suspended*/,
                                 null, /*suspendingPackage*/
+                                null, /*dialogMessage*/
                                 null, /*suspendedAppExtras*/
                                 null, /*suspendedLauncherExtras*/
                                 instantApp,
@@ -1628,6 +1630,7 @@
                                 false /*hidden*/,
                                 false /*suspended*/,
                                 null, /*suspendingPackage*/
+                                null, /*dialogMessage*/
                                 null, /*suspendedAppExtras*/
                                 null, /*suspendedLauncherExtras*/
                                 false /*instantApp*/,
@@ -1704,6 +1707,8 @@
                             false);
                     String suspendingPackage = parser.getAttributeValue(null,
                             ATTR_SUSPENDING_PACKAGE);
+                    final String dialogMessage = parser.getAttributeValue(null,
+                            ATTR_SUSPEND_DIALOG_MESSAGE);
                     if (suspended && suspendingPackage == null) {
                         suspendingPackage = PLATFORM_PACKAGE_NAME;
                     }
@@ -1767,7 +1772,7 @@
                         setBlockUninstallLPw(userId, name, true);
                     }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
-                            hidden, suspended, suspendingPackage, suspendedAppExtras,
+                            hidden, suspended, suspendingPackage, dialogMessage, suspendedAppExtras,
                             suspendedLauncherExtras, instantApp, virtualPreload, enabledCaller,
                             enabledComponents, disabledComponents, verifState, linkGeneration,
                             installReason, harmfulAppWarning);
@@ -2077,7 +2082,14 @@
                 }
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
-                    serializer.attribute(null, ATTR_SUSPENDING_PACKAGE, ustate.suspendingPackage);
+                    if (ustate.suspendingPackage != null) {
+                        serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
+                                ustate.suspendingPackage);
+                    }
+                    if (ustate.dialogMessage != null) {
+                        serializer.attribute(null, ATTR_SUSPEND_DIALOG_MESSAGE,
+                                ustate.dialogMessage);
+                    }
                     if (ustate.suspendedAppExtras != null) {
                         serializer.startTag(null, TAG_SUSPENDED_APP_EXTRAS);
                         try {
@@ -4750,8 +4762,11 @@
             pw.print(" suspended=");
             pw.print(ps.getSuspended(user.id));
             if (ps.getSuspended(user.id)) {
+                final PackageUserState pus = ps.readUserState(user.id);
                 pw.print(" suspendingPackage=");
-                pw.print(ps.readUserState(user.id).suspendingPackage);
+                pw.print(pus.suspendingPackage);
+                pw.print(" dialogMessage=");
+                pw.print(pus.dialogMessage);
             }
             pw.print(" stopped=");
             pw.print(ps.getStopped(user.id));
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index d4625e9..5f2ac4f 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -273,7 +273,8 @@
 
         // Add in all the apps for every user/profile.
         for (UserInfo profile : users) {
-            List<PackageInfo> pi = pm.getInstalledPackagesAsUser(0, profile.id);
+            List<PackageInfo> pi =
+                pm.getInstalledPackagesAsUser(PackageManager.MATCH_DISABLED_COMPONENTS, profile.id);
             for (int j = 0; j < pi.size(); j++) {
                 if (pi.get(j).applicationInfo != null) {
                     uids.add(pi.get(j).applicationInfo.uid);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8af1101..2db8039 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -23,7 +23,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Rect;
-import android.hardware.biometrics.IBiometricDialogReceiver;
+import android.hardware.biometrics.IBiometricPromptReceiver;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -547,7 +547,7 @@
     }
 
     @Override
-    public void showFingerprintDialog(Bundle bundle, IBiometricDialogReceiver receiver) {
+    public void showFingerprintDialog(Bundle bundle, IBiometricPromptReceiver receiver) {
         if (mBar != null) {
             try {
                 mBar.showFingerprintDialog(bundle, receiver);
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 21fea1c..e18eee2 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -81,6 +81,7 @@
 using android::hardware::Void;
 using android::hardware::hidl_vec;
 using android::hardware::hidl_death_recipient;
+using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocation;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 
@@ -91,7 +92,6 @@
 using android::hardware::gnss::V1_0::IAGnssRilCallback;
 using android::hardware::gnss::V1_0::IGnssBatching;
 using android::hardware::gnss::V1_0::IGnssBatchingCallback;
-using android::hardware::gnss::V1_0::IGnssConfiguration;
 using android::hardware::gnss::V1_0::IGnssDebug;
 using android::hardware::gnss::V1_0::IGnssGeofenceCallback;
 using android::hardware::gnss::V1_0::IGnssGeofencing;
@@ -108,6 +108,8 @@
 
 using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
 using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
+using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
+using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
 using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
@@ -137,7 +139,8 @@
 sp<IAGnss> agnssIface = nullptr;
 sp<IGnssBatching> gnssBatchingIface = nullptr;
 sp<IGnssDebug> gnssDebugIface = nullptr;
-sp<IGnssConfiguration> gnssConfigurationIface = nullptr;
+sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
+sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
 sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
 sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
@@ -1098,13 +1101,11 @@
     * Methods from ::android::hardware::gps::V1_0::IGnssBatchingCallback
     * follow.
     */
-    Return<void> gnssLocationBatchCb(
-        const ::android::hardware::hidl_vec<GnssLocation> & locations)
+    Return<void> gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations)
         override;
 };
 
-Return<void> GnssBatchingCallback::gnssLocationBatchCb(
-        const ::android::hardware::hidl_vec<GnssLocation> & locations) {
+Return<void> GnssBatchingCallback::gnssLocationBatchCb(const hidl_vec<GnssLocation> & locations) {
     JNIEnv* env = getJniEnv();
 
     jobjectArray jLocations = env->NewObjectArray(locations.size(),
@@ -1257,11 +1258,21 @@
             gnssNiIface = gnssNi;
         }
 
-        auto gnssConfiguration = gnssHal->getExtensionGnssConfiguration();
-        if (!gnssConfiguration.isOk()) {
-            ALOGD("Unable to get a handle to GnssConfiguration");
+        if (gnssHal_V1_1 != nullptr) {
+            auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
+            if (!gnssConfiguration.isOk()) {
+                ALOGD("Unable to get a handle to GnssConfiguration");
+            } else {
+                gnssConfigurationIface_V1_1 = gnssConfiguration;
+                gnssConfigurationIface = gnssConfigurationIface_V1_1;
+            }
         } else {
-            gnssConfigurationIface = gnssConfiguration;
+            auto gnssConfiguration_V1_0 = gnssHal->getExtensionGnssConfiguration();
+            if (!gnssConfiguration_V1_0.isOk()) {
+                ALOGD("Unable to get a handle to GnssConfiguration");
+            } else {
+                gnssConfigurationIface = gnssConfiguration_V1_0;
+            }
         }
 
         auto gnssGeofencing = gnssHal->getExtensionGnssGeofencing();
@@ -1997,6 +2008,48 @@
     }
 }
 
+static jboolean android_location_GnssLocationProvider_set_satellite_blacklist(
+        JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
+    if (gnssConfigurationIface_V1_1 == nullptr) {
+        ALOGI("No GNSS Satellite Blacklist interface available");
+        return JNI_FALSE;
+    }
+
+    jint *constellation_array = env->GetIntArrayElements(constellations, 0);
+    if (NULL == constellation_array) {
+        ALOGI("GetIntArrayElements returns NULL.");
+        return JNI_FALSE;
+    }
+    jsize length = env->GetArrayLength(constellations);
+
+    jint *sv_id_array = env->GetIntArrayElements(sv_ids, 0);
+    if (NULL == sv_id_array) {
+        ALOGI("GetIntArrayElements returns NULL.");
+        return JNI_FALSE;
+    }
+
+    if (length != env->GetArrayLength(sv_ids)) {
+        ALOGI("Lengths of constellations and sv_ids are inconsistent.");
+        return JNI_FALSE;
+    }
+
+    hidl_vec<IGnssConfiguration_V1_1::BlacklistedSource> sources;
+    sources.resize(length);
+
+    for (int i = 0; i < length; i++) {
+        sources[i].constellation = static_cast<GnssConstellationType>(constellation_array[i]);
+        sources[i].svid = sv_id_array[i];
+    }
+
+    auto result = gnssConfigurationIface_V1_1->setBlacklist(sources);
+    if (result.isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
+
 static jint android_location_GnssLocationProvider_get_batch_size(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return 0; // batching not supported, size = 0
@@ -2185,6 +2238,9 @@
     {"native_set_emergency_supl_pdn",
             "(I)Z",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
+    {"native_set_satellite_blacklist",
+            "([I[I)Z",
+            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)},
     {"native_get_batch_size",
             "()I",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_get_batch_size)},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36dc121..9bc5fca 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -9193,7 +9193,7 @@
             long id = mInjector.binderClearCallingIdentity();
             try {
                 return mIPackageManager.setPackagesSuspendedAsUser(
-                        packageNames, suspended, null, null, "android", callingUserId);
+                        packageNames, suspended, null, null, null, "android", callingUserId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed talking to the package manager", re);
diff --git a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java
new file mode 100644
index 0000000..d6f5446
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java
@@ -0,0 +1,130 @@
+package com.android.server.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Looper;
+import android.platform.test.annotations.Presubmit;
+import android.provider.Settings;
+
+import com.android.server.testing.FrameworkRobolectricTestRunner;
+import com.android.server.testing.SystemLoaderPackages;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Unit tests for {@link GnssSatelliteBlacklistHelper}.
+ */
+@RunWith(FrameworkRobolectricTestRunner.class)
+@Config(
+        manifest = Config.NONE,
+        shadows = {
+        },
+        sdk = 27
+)
+@SystemLoaderPackages({"com.android.server.location"})
+@Presubmit
+public class GnssSatelliteBlacklistHelperTest {
+
+    private Context mContext;
+    private ContentResolver mContentResolver;
+    @Mock
+    private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mContentResolver = mContext.getContentResolver();
+        new GnssSatelliteBlacklistHelper(mContext, Looper.myLooper(), mCallback);
+    }
+
+    @Test
+    public void blacklistOf2Satellites_callbackIsCalled() {
+        String blacklist = "3,0,5,24";
+        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    }
+
+    @Test
+    public void blacklistWithSpaces_callbackIsCalled() {
+        String blacklist = "3, 11";
+        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    }
+
+    @Test
+    public void emptyBlacklist_callbackIsCalled() {
+        String blacklist = "";
+        updateBlacklistAndVerifyCallbackIsCalled(blacklist);
+    }
+
+    @Test
+    public void blacklistWithOddNumberOfValues_callbackIsNotCalled() {
+        String blacklist = "3,0,5";
+        updateBlacklistAndNotifyContentObserver(blacklist);
+        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    }
+
+    @Test
+    public void blacklistWithNegativeValue_callbackIsNotCalled() {
+        String blacklist = "3,-11";
+        updateBlacklistAndNotifyContentObserver(blacklist);
+        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    }
+
+    @Test
+    public void blacklistWithNonDigitCharacter_callbackIsNotCalled() {
+        String blacklist = "3,1a,5,11";
+        updateBlacklistAndNotifyContentObserver(blacklist);
+        verify(mCallback, never()).onUpdateSatelliteBlacklist(any(int[].class), any(int[].class));
+    }
+
+    private void updateBlacklistAndNotifyContentObserver(String blacklist) {
+        Settings.Global.putString(mContentResolver,
+                Settings.Global.GNSS_SATELLITE_BLACKLIST, blacklist);
+        notifyContentObserverFor(Settings.Global.GNSS_SATELLITE_BLACKLIST);
+    }
+
+    private void updateBlacklistAndVerifyCallbackIsCalled(String blacklist) {
+        updateBlacklistAndNotifyContentObserver(blacklist);
+
+        ArgumentCaptor<int[]> constellationsCaptor = ArgumentCaptor.forClass(int[].class);
+        ArgumentCaptor<int[]> svIdsCaptor = ArgumentCaptor.forClass(int[].class);
+        verify(mCallback).onUpdateSatelliteBlacklist(constellationsCaptor.capture(),
+                svIdsCaptor.capture());
+
+        int[] constellations = constellationsCaptor.getValue();
+        int[] svIds = svIdsCaptor.getValue();
+        List<Integer> values = GnssSatelliteBlacklistHelper.parseSatelliteBlacklist(blacklist);
+        assertThat(values.size()).isEqualTo(constellations.length * 2);
+        assertThat(svIds.length).isEqualTo(constellations.length);
+        for (int i = 0; i < constellations.length; i++) {
+            assertThat(constellations[i]).isEqualTo(values.get(i * 2));
+            assertThat(svIds[i]).isEqualTo(values.get(i * 2 + 1));
+        }
+    }
+
+    private static void notifyContentObserverFor(String globalSetting) {
+        Collection<ContentObserver> contentObservers =
+                Shadows.shadowOf(RuntimeEnvironment.application.getContentResolver())
+                        .getContentObservers(Settings.Global.getUriFor(globalSetting));
+        assertThat(contentObservers).isNotEmpty();
+        contentObservers.iterator().next().onChange(false /* selfChange */);
+    }
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index cdb339a..a85f21c 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -29,6 +29,7 @@
     truth-prebuilt \
     testables \
     testng \
+    ub-uiautomator\
     platformprotosnano
 
 LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
@@ -69,8 +70,6 @@
 LOCAL_JACK_FLAGS := --multi-dex native
 LOCAL_DX_FLAGS := --multi-dex
 
-LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
-
 LOCAL_PROGUARD_ENABLED := disabled
 
 include $(BUILD_PACKAGE)
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index ce98d65..22bec44 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -63,6 +63,7 @@
     <uses-permission android:name="android.permission.WATCH_APPOPS" />
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
     <uses-permission android:name="android.permission.SUSPEND_APPS"/>
+    <uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
@@ -145,6 +146,15 @@
         <activity android:name="com.android.server.pm.ShortcutTestActivity"
                  android:enabled="true" android:exported="true" />
 
+        <activity android:name="com.android.server.pm.SuspendedDetailsActivity"
+                  android:enabled="true"
+                  android:permission="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS">
+            <intent-filter>
+                <action android:name="android.intent.action.SHOW_SUSPENDED_APP_DETAILS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
 
         <activity-alias android:name="a.ShortcutEnabled"
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
index f76eb56..a14b950 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartInterceptorTest.java
@@ -17,6 +17,9 @@
 package com.android.server.am;
 
 import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
+
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -30,6 +33,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -38,6 +42,7 @@
 
 import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -79,11 +84,15 @@
     @Mock
     private DevicePolicyManagerInternal mDevicePolicyManager;
     @Mock
+    private PackageManagerInternal mPackageManagerInternal;
+    @Mock
     private UserManager mUserManager;
     @Mock
     private UserController mUserController;
     @Mock
     private KeyguardManager mKeyguardManager;
+    @Mock
+    private PackageManagerService mPackageManager;
 
     private ActivityStartInterceptor mInterceptor;
     private ActivityInfo mAInfo = new ActivityInfo();
@@ -103,6 +112,7 @@
         when(mDevicePolicyManager
                         .createShowAdminSupportIntent(TEST_USER_ID, true))
                 .thenReturn(ADMIN_SUPPORT_INTENT);
+        when(mService.getPackageManagerInternalLocked()).thenReturn(mPackageManagerInternal);
 
         // Mock UserManager
         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
@@ -114,16 +124,24 @@
                 nullable(CharSequence.class), nullable(CharSequence.class), eq(TEST_USER_ID))).
                 thenReturn(CONFIRM_CREDENTIALS_INTENT);
 
+        // Mock PackageManager
+        when(mService.getPackageManager()).thenReturn(mPackageManager);
+        when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID))
+                .thenReturn(null);
+
         // Initialise activity info
-        mAInfo.packageName = TEST_PACKAGE_NAME;
         mAInfo.applicationInfo = new ApplicationInfo();
+        mAInfo.packageName = mAInfo.applicationInfo.packageName = TEST_PACKAGE_NAME;
     }
 
     @Test
-    public void testSuspendedPackage() {
+    public void testSuspendedByAdminPackage() {
         // GIVEN the package we're about to launch is currently suspended
         mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
 
+        when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
+                .thenReturn(PLATFORM_PACKAGE_NAME);
+
         // THEN calling intercept returns true
         assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, 0, 0, null));
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index ebb4248..97ff94f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -199,13 +199,13 @@
                 PACKAGE_NAME_1, 1L, 0.01, true, "appString1");
         final PersistableBundle launcherExtras1 = getPersistableBundle(
                 PACKAGE_NAME_1, 10L, 0.1, false, "launcherString1");
-        ps1.setSuspended(true, "suspendingPackage1", appExtras1, launcherExtras1, 0);
+        ps1.setSuspended(true, "suspendingPackage1", "dialogMsg1", appExtras1, launcherExtras1, 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
 
-        ps2.setSuspended(true, "suspendingPackage2", null, null, 0);
+        ps2.setSuspended(true, "suspendingPackage2", "dialogMsg2", null, null, 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
 
-        ps3.setSuspended(false, "irrelevant", null, null, 0);
+        ps3.setSuspended(false, "irrelevant", "irrevelant2", null, null, 0);
         settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
 
         settingsUnderTest.writePackageRestrictionsLPr(0);
@@ -220,6 +220,7 @@
                 readUserState(0);
         assertThat(readPus1.suspended, is(true));
         assertThat(readPus1.suspendingPackage, equalTo("suspendingPackage1"));
+        assertThat(readPus1.dialogMessage, equalTo("dialogMsg1"));
         assertThat(BaseBundle.kindofEquals(readPus1.suspendedAppExtras, appExtras1), is(true));
         assertThat(BaseBundle.kindofEquals(readPus1.suspendedLauncherExtras, launcherExtras1),
                 is(true));
@@ -228,12 +229,17 @@
                 readUserState(0);
         assertThat(readPus2.suspended, is(true));
         assertThat(readPus2.suspendingPackage, equalTo("suspendingPackage2"));
+        assertThat(readPus2.dialogMessage, equalTo("dialogMsg2"));
         assertThat(readPus2.suspendedAppExtras, is(nullValue()));
         assertThat(readPus2.suspendedLauncherExtras, is(nullValue()));
 
         final PackageUserState readPus3 = settingsUnderTest.mPackages.get(PACKAGE_NAME_3).
                 readUserState(0);
         assertThat(readPus3.suspended, is(false));
+        assertThat(readPus3.suspendingPackage, is(nullValue()));
+        assertThat(readPus3.dialogMessage, is(nullValue()));
+        assertThat(readPus3.suspendedAppExtras, is(nullValue()));
+        assertThat(readPus3.suspendedLauncherExtras, is(nullValue()));
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index 4e1418c..2a4ea8c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -184,30 +184,40 @@
         launcherExtras2.putString("name", "launcherExtras2");
         final String suspendingPackage1 = "package1";
         final String suspendingPackage2 = "package2";
+        final String dialogMessage1 = "dialogMessage1";
+        final String dialogMessage2 = "dialogMessage2";
 
         final PackageUserState testUserState1 = new PackageUserState();
         testUserState1.suspended = true;
         testUserState1.suspendedAppExtras = appExtras1;
         testUserState1.suspendedLauncherExtras = launcherExtras1;
         testUserState1.suspendingPackage = suspendingPackage1;
+        testUserState1.dialogMessage = dialogMessage1;
 
-        final PackageUserState testUserState2 = new PackageUserState(testUserState1);
+        PackageUserState testUserState2 = new PackageUserState(testUserState1);
         assertThat(testUserState1.equals(testUserState2), is(true));
         testUserState2.suspendingPackage = suspendingPackage2;
         assertThat(testUserState1.equals(testUserState2), is(false));
 
-        testUserState2.suspendingPackage = testUserState1.suspendingPackage;
+        testUserState2 = new PackageUserState(testUserState1);
         testUserState2.suspendedAppExtras = appExtras2;
         assertThat(testUserState1.equals(testUserState2), is(false));
 
-        testUserState2.suspendedAppExtras = testUserState1.suspendedAppExtras;
+        testUserState2 = new PackageUserState(testUserState1);
         testUserState2.suspendedLauncherExtras = launcherExtras2;
         assertThat(testUserState1.equals(testUserState2), is(false));
 
-        // Everything is different but irrelevant if suspended is false
+        testUserState2 = new PackageUserState(testUserState1);
+        testUserState2.dialogMessage = dialogMessage2;
+        assertThat(testUserState1.equals(testUserState2), is(false));
+
+        testUserState2 = new PackageUserState(testUserState1);
         testUserState2.suspended = testUserState1.suspended = false;
-        testUserState2.suspendedAppExtras = appExtras2;
+        // Everything is different but irrelevant if suspended is false
         testUserState2.suspendingPackage = suspendingPackage2;
+        testUserState2.dialogMessage = dialogMessage2;
+        testUserState2.suspendedAppExtras = appExtras2;
+        testUserState2.suspendedLauncherExtras = launcherExtras2;
         assertThat(testUserState1.equals(testUserState2), is(true));
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index 43a439b..36e4753 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
@@ -41,8 +42,15 @@
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
 import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
 
+import com.android.servicestests.apps.suspendtestapp.SuspendTestActivity;
 import com.android.servicestests.apps.suspendtestapp.SuspendTestReceiver;
 
 import org.junit.After;
@@ -68,14 +76,25 @@
             INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_SUSPENDED";
     public static final String ACTION_REPORT_MY_PACKAGE_UNSUSPENDED =
             INSTRUMENTATION_PACKAGE + ".action.REPORT_MY_PACKAGE_UNSUSPENDED";
+    public static final String ACTION_REPORT_TEST_ACTIVITY_STARTED =
+            INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STARTED";
+    public static final String ACTION_REPORT_TEST_ACTIVITY_STOPPED =
+            INSTRUMENTATION_PACKAGE + ".action.REPORT_TEST_ACTIVITY_STOPPED";
+    public static final String ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED =
+            INSTRUMENTATION_PACKAGE + ".action.REPORT_MORE_DETAILS_ACTIVITY_STARTED";
+    public static final String ACTION_FINISH_TEST_ACTIVITY =
+            INSTRUMENTATION_PACKAGE + ".action.FINISH_TEST_ACTIVITY";
+    public static final String EXTRA_RECEIVED_PACKAGE_NAME =
+            SuspendPackagesTest.INSTRUMENTATION_PACKAGE + ".extra.RECEIVED_PACKAGE_NAME";
+
 
     private Context mContext;
     private PackageManager mPackageManager;
     private LauncherApps mLauncherApps;
     private Handler mReceiverHandler;
-    private ComponentName mTestReceiverComponent;
     private AppCommunicationReceiver mAppCommsReceiver;
     private StubbedCallback mTestCallback;
+    private UiDevice mUiDevice;
 
     private static final class AppCommunicationReceiver extends BroadcastReceiver {
         private Context context;
@@ -86,11 +105,12 @@
             this.context = context;
         }
 
-        void register(Handler handler) {
+        void register(Handler handler, String... actions) {
             registered = true;
             final IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_SUSPENDED);
-            intentFilter.addAction(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+            for (String action : actions) {
+                intentFilter.addAction(action);
+            }
             context.registerReceiver(this, intentFilter, null, handler);
         }
 
@@ -110,19 +130,28 @@
             }
         }
 
-        Intent receiveIntentFromApp() {
+        Intent pollForIntent(long secondsToWait) {
             if (!registered) {
                 throw new IllegalStateException("Receiver not registered");
             }
             final Intent intent;
             try {
-                intent = intentQueue.poll(5, TimeUnit.SECONDS);
+                intent = intentQueue.poll(secondsToWait, TimeUnit.SECONDS);
             } catch (InterruptedException ie) {
                 throw new RuntimeException("Interrupted while waiting for app broadcast", ie);
             }
-            assertNotNull("No intent received from app within 5 seconds", intent);
             return intent;
         }
+
+        void drainPendingBroadcasts() {
+            while (pollForIntent(5) != null);
+        }
+
+        Intent receiveIntentFromApp() {
+            final Intent intentReceived = pollForIntent(5);
+            assertNotNull("No intent received from app within 5 seconds", intentReceived);
+            return intentReceived;
+        }
     }
 
     @Before
@@ -131,8 +160,7 @@
         mPackageManager = mContext.getPackageManager();
         mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
         mReceiverHandler = new Handler(Looper.getMainLooper());
-        mTestReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
-                SuspendTestReceiver.class.getCanonicalName());
+        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             // Otherwise implicit broadcasts will not be delivered.
@@ -151,9 +179,10 @@
     private Bundle requestAppAction(String action) throws InterruptedException {
         final AtomicReference<Bundle> result = new AtomicReference<>();
         final CountDownLatch receiverLatch = new CountDownLatch(1);
-
+        final ComponentName testReceiverComponent = new ComponentName(TEST_APP_PACKAGE_NAME,
+                SuspendTestReceiver.class.getCanonicalName());
         final Intent broadcastIntent = new Intent(action)
-                .setComponent(mTestReceiverComponent)
+                .setComponent(testReceiverComponent)
                 .setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         mContext.sendOrderedBroadcast(broadcastIntent, null, new BroadcastReceiver() {
             @Override
@@ -175,9 +204,10 @@
         return extras;
     }
 
-    private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras) {
+    private void suspendTestPackage(PersistableBundle appExtras, PersistableBundle launcherExtras,
+            String dialogMessage) {
         final String[] unchangedPackages = mPackageManager.setPackagesSuspended(
-                PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, null);
+                PACKAGES_TO_SUSPEND, true, appExtras, launcherExtras, dialogMessage);
         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
     }
 
@@ -187,6 +217,13 @@
         assertTrue("setPackagesSuspended returned non-empty list", unchangedPackages.length == 0);
     }
 
+    private void startTestAppActivity() {
+        final Intent testActivity = new Intent()
+                .setComponent(new ComponentName(TEST_APP_PACKAGE_NAME,
+                        SuspendTestActivity.class.getCanonicalName()))
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(testActivity);
+    }
 
     private static boolean areSameExtras(BaseBundle expected, BaseBundle received) {
         if (expected != null) {
@@ -199,13 +236,14 @@
     }
 
     private static void assertSameExtras(String message, BaseBundle expected, BaseBundle received) {
-        assertTrue(message + ": [expected: " + expected + "; received: " + received + "]",
-                areSameExtras(expected, received));
+        if (!areSameExtras(expected, received)) {
+            fail(message + ": [expected: " + expected + "; received: " + received + "]");
+        }
     }
 
     @Test
     public void testIsPackageSuspended() {
-        suspendTestPackage(null, null);
+        suspendTestPackage(null, null, null);
         assertTrue("isPackageSuspended is false",
                 mPackageManager.isPackageSuspended(TEST_APP_PACKAGE_NAME));
     }
@@ -217,7 +255,7 @@
         assertNull(resultFromApp.getBundle(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
 
         final PersistableBundle appExtras = getExtras("testSuspendedStateFromApp", 20, "20", 0.2);
-        suspendTestPackage(appExtras, null);
+        suspendTestPackage(appExtras, null, null);
 
         resultFromApp = requestAppAction(SuspendTestReceiver.ACTION_GET_SUSPENDED_STATE);
         assertTrue("resultFromApp:suspended is false",
@@ -230,37 +268,39 @@
 
     @Test
     public void testMyPackageSuspendedUnsuspended() {
-        mAppCommsReceiver.register(mReceiverHandler);
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED,
+                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED);
+        mAppCommsReceiver.drainPendingBroadcasts();
         final PersistableBundle appExtras = getExtras("testMyPackageSuspendBroadcasts", 1, "1", .1);
-        suspendTestPackage(appExtras, null);
+        suspendTestPackage(appExtras, null, null);
         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
         assertSameExtras("Received app extras different to the ones supplied", appExtras,
                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
         unsuspendTestPackage();
         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertTrue("MY_PACKAGE_UNSUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED.equals(intentFromApp.getAction()));
+        assertEquals("MY_PACKAGE_UNSUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
     }
 
     @Test
     public void testUpdatingAppExtras() {
-        mAppCommsReceiver.register(mReceiverHandler);
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_SUSPENDED);
         final PersistableBundle extras1 = getExtras("testMyPackageSuspendedOnChangingExtras", 1,
                 "1", 0.1);
-        suspendTestPackage(extras1, null);
+        suspendTestPackage(extras1, null, null);
         Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
         assertSameExtras("Received app extras different to the ones supplied", extras1,
                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
         final PersistableBundle extras2 = getExtras("testMyPackageSuspendedOnChangingExtras", 2,
                 "2", 0.2);
         mPackageManager.setSuspendedPackageAppExtras(TEST_APP_PACKAGE_NAME, extras2);
         intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
-        assertTrue("MY_PACKAGE_SUSPENDED delivery not reported",
-                ACTION_REPORT_MY_PACKAGE_SUSPENDED.equals(intentFromApp.getAction()));
+        assertEquals("MY_PACKAGE_SUSPENDED delivery not reported",
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
         assertSameExtras("Received app extras different to the updated extras", extras2,
                 intentFromApp.getBundleExtra(SuspendTestReceiver.EXTRA_SUSPENDED_APP_EXTRAS));
     }
@@ -274,12 +314,26 @@
     }
 
     @Test
+    public void testActivityStoppedOnSuspend() {
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_TEST_ACTIVITY_STARTED,
+                ACTION_REPORT_TEST_ACTIVITY_STOPPED);
+        startTestAppActivity();
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals("Test activity start not reported",
+                ACTION_REPORT_TEST_ACTIVITY_STARTED, intentFromApp.getAction());
+        suspendTestPackage(null, null, null);
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals("Test activity stop not reported on suspending the test app",
+                ACTION_REPORT_TEST_ACTIVITY_STOPPED, intentFromApp.getAction());
+    }
+
+    @Test
     public void testGetLauncherExtrasNonNull() {
         final Bundle extrasWhenUnsuspended = mLauncherApps.getSuspendedPackageLauncherExtras(
                 TEST_APP_PACKAGE_NAME, mContext.getUser());
         assertNull("Non null extras when package unsuspended:", extrasWhenUnsuspended);
         final PersistableBundle launcherExtras = getExtras("testGetLauncherExtras", 1, "1", 0.1);
-        suspendTestPackage(null, launcherExtras);
+        suspendTestPackage(null, launcherExtras, null);
         final Bundle receivedExtras = mLauncherApps.getSuspendedPackageLauncherExtras(
                 TEST_APP_PACKAGE_NAME, mContext.getUser());
         assertSameExtras("Received launcher extras different to the ones supplied", launcherExtras,
@@ -288,7 +342,7 @@
 
     @Test
     public void testGetLauncherExtrasNull() {
-        suspendTestPackage(null, null);
+        suspendTestPackage(null, null, null);
         final Bundle extrasWhenNoneGiven = mLauncherApps.getSuspendedPackageLauncherExtras(
                 TEST_APP_PACKAGE_NAME, mContext.getUser());
         assertNull("Non null extras when null extras provided:", extrasWhenNoneGiven);
@@ -339,7 +393,7 @@
             }
         };
         mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
-        suspendTestPackage(null, suppliedExtras);
+        suspendTestPackage(null, suppliedExtras, null);
         assertFalse("Both callbacks were invoked", twoCallbackLatch.await(5, TimeUnit.SECONDS));
         twoCallbackLatch.countDown();
         assertTrue("No callback was invoked", twoCallbackLatch.await(2, TimeUnit.SECONDS));
@@ -373,19 +427,53 @@
             }
         };
         mLauncherApps.registerCallback(mTestCallback, mReceiverHandler);
-        suspendTestPackage(null, suppliedExtras);
+        suspendTestPackage(null, suppliedExtras, null);
         assertTrue("Callback not invoked", oneCallbackLatch.await(5, TimeUnit.SECONDS));
         final String result = overridingOneCallbackResult.get();
         assertTrue("Callback did not complete as expected: " + result, result.isEmpty());
     }
 
+    private void turnScreenOn() throws Exception {
+        if (!mUiDevice.isScreenOn()) {
+            mUiDevice.wakeUp();
+        }
+        final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+        wm.dismissKeyguard(null, null);
+    }
+
+    @Test
+    public void testInterceptorActivity() throws Exception {
+        turnScreenOn();
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED,
+                ACTION_REPORT_TEST_ACTIVITY_STARTED);
+        final String testMessage = "This is a test message";
+        suspendTestPackage(null, null, testMessage);
+        startTestAppActivity();
+        assertNull("No broadcast was expected from app", mAppCommsReceiver.pollForIntent(2));
+        assertNotNull("Given dialog message not shown",
+                mUiDevice.wait(Until.findObject(By.text(testMessage)), 5000));
+        final String buttonText = "More details";
+        final UiObject2 moreDetailsButton = mUiDevice.findObject(
+                By.clickable(true).text(buttonText));
+        assertNotNull("\"More Details\" button not shown", moreDetailsButton);
+        moreDetailsButton.click();
+        final Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals("\"More Details\" activity start not reported",
+                ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED, intentFromApp.getAction());
+        final String receivedPackageName = intentFromApp.getStringExtra(
+                EXTRA_RECEIVED_PACKAGE_NAME);
+        assertEquals("Wrong package name received by \"More Details\" activity",
+                TEST_APP_PACKAGE_NAME, receivedPackageName);
+    }
+
     @After
-    public void tearDown() throws Exception {
+    public void tearDown() {
         mAppCommsReceiver.unregister();
         if (mTestCallback != null) {
             mLauncherApps.unregisterCallback(mTestCallback);
         }
-        Thread.sleep(250); // To prevent any race with the next registerReceiver
+        mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
+                .setPackage(TEST_APP_PACKAGE_NAME));
     }
 
     private static abstract class StubbedCallback extends LauncherApps.Callback {
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java b/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java
new file mode 100644
index 0000000..18f0123
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendedDetailsActivity.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm;
+
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED;
+import static com.android.server.pm.SuspendPackagesTest.EXTRA_RECEIVED_PACKAGE_NAME;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class SuspendedDetailsActivity extends Activity {
+    private static final String TAG = SuspendedDetailsActivity.class.getSimpleName();
+
+    @Override
+    protected void onStart() {
+        Log.d(TAG, "onStart");
+        final String suspendedPackage =  getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        super.onStart();
+        final Intent reportStart = new Intent(ACTION_REPORT_MORE_DETAILS_ACTIVITY_STARTED)
+                .putExtra(EXTRA_RECEIVED_PACKAGE_NAME, suspendedPackage)
+                .setPackage(INSTRUMENTATION_PACKAGE);
+        sendBroadcast(reportStart);
+        finish();
+    }
+}
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
index afdde72..ae0b0f9 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_COMPATIBILITY_SUITE := device-tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
index fa5fc58..ab7ddbb 100644
--- a/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/src/com/android/servicestests/apps/suspendtestapp/SuspendTestActivity.java
@@ -16,9 +16,45 @@
 
 package com.android.servicestests.apps.suspendtestapp;
 
+import static com.android.server.pm.SuspendPackagesTest.ACTION_FINISH_TEST_ACTIVITY;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STARTED;
+import static com.android.server.pm.SuspendPackagesTest.ACTION_REPORT_TEST_ACTIVITY_STOPPED;
+import static com.android.server.pm.SuspendPackagesTest.INSTRUMENTATION_PACKAGE;
+
 import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
 
 public class SuspendTestActivity extends Activity {
     private static final String TAG = SuspendTestActivity.class.getSimpleName();
 
-}
\ No newline at end of file
+    private BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.d(TAG, "Finishing test activity from receiver");
+            SuspendTestActivity.this.finish();
+        }
+    };
+
+    @Override
+    public void onStart() {
+        Log.d(TAG, "onStart");
+        final Intent reportStart = new Intent(ACTION_REPORT_TEST_ACTIVITY_STARTED)
+                .setPackage(INSTRUMENTATION_PACKAGE);
+        sendBroadcast(reportStart);
+        registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_TEST_ACTIVITY));
+        super.onStart();
+    }
+    @Override
+    public void onStop() {
+        Log.d(TAG, "onStop");
+        final Intent reportStop = new Intent(ACTION_REPORT_TEST_ACTIVITY_STOPPED)
+                .setPackage(INSTRUMENTATION_PACKAGE);
+        sendBroadcast(reportStop);
+        unregisterReceiver(mFinishReceiver);
+        super.onStop();
+    }
+}
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 948422c..17819db 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -101,7 +101,6 @@
     cflags: [
         "-Wall",
         "-Werror",
-        "-fexceptions",
     ],
     export_generated_headers: ["statslog.h"],
     shared_libs: [
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 499f254..057772f 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -101,7 +101,8 @@
     fprintf(out, "// This file is autogenerated\n");
     fprintf(out, "\n");
 
-    fprintf(out, "#include <exception>\n");
+    fprintf(out, "#include <chrono>\n");
+    fprintf(out, "#include <thread>\n");
     fprintf(out, "#include <log/log_event_list.h>\n");
     fprintf(out, "#include <log/log.h>\n");
     fprintf(out, "#include <statslog.h>\n");
@@ -212,7 +213,7 @@
         int argIndex;
 
         fprintf(out, "int\n");
-        fprintf(out, "stats_write(int32_t code");
+        fprintf(out, "try_stats_write(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -247,10 +248,6 @@
                     if (chainField.javaType == JAVA_TYPE_STRING) {
                         fprintf(out, "    if (%s_length != %s.size()) {\n",
                             attributionDecl.fields.front().name.c_str(), chainField.name.c_str());
-                        fprintf(out, "        throw std::invalid_argument(\"attribution fields with"
-                            " diff length: %s vs %s\");\n",
-                            attributionDecl.fields.front().name.c_str(),
-                            chainField.name.c_str());
                         fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }
@@ -289,12 +286,74 @@
         fprintf(out, "\n");
     }
 
+   for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
+       signature != atoms.signatures.end(); signature++) {
+       int argIndex;
+
+       fprintf(out, "int \n");
+       fprintf(out, "stats_write(int32_t code");
+       argIndex = 1;
+       for (vector<java_type_t>::const_iterator arg = signature->begin();
+           arg != signature->end(); arg++) {
+           if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+               for (auto chainField : attributionDecl.fields) {
+                   if (chainField.javaType == JAVA_TYPE_STRING) {
+                           fprintf(out, ", const std::vector<%s>& %s",
+                                cpp_type_name(chainField.javaType),
+                                chainField.name.c_str());
+                   } else {
+                           fprintf(out, ", const %s* %s, size_t %s_length",
+                                cpp_type_name(chainField.javaType),
+                                chainField.name.c_str(), chainField.name.c_str());
+                   }
+               }
+           } else {
+               fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+           }
+           argIndex++;
+       }
+       fprintf(out, ")\n");
+
+       fprintf(out, "{\n");
+       fprintf(out, "  int ret = 0;\n");
+
+       fprintf(out, "  for(int retry = 0; retry < 3; ++retry) {\n");
+       fprintf(out, "      ret =  try_stats_write(code");
+
+       argIndex = 1;
+       for (vector<java_type_t>::const_iterator arg = signature->begin();
+           arg != signature->end(); arg++) {
+           if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+               for (auto chainField : attributionDecl.fields) {
+                   if (chainField.javaType == JAVA_TYPE_STRING) {
+                           fprintf(out, ", %s",
+                                chainField.name.c_str());
+                   } else {
+                           fprintf(out, ",  %s,  %s_length",
+                                chainField.name.c_str(), chainField.name.c_str());
+                   }
+               }
+           } else {
+               fprintf(out, ", arg%d", argIndex);
+           }
+           argIndex++;
+       }
+       fprintf(out, ");\n");
+       fprintf(out, "      if (ret >= 0) { return retry; }\n");
+       fprintf(out,
+               "      std::this_thread::sleep_for(std::chrono::milliseconds(10 + 10 * retry));\n");
+       fprintf(out, "  }\n");
+       fprintf(out, "  return ret;\n");
+       fprintf(out, "}\n");
+       fprintf(out, "\n");
+   }
+
     for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
         signature != atoms.non_chained_signatures.end(); signature++) {
         int argIndex;
 
         fprintf(out, "int\n");
-        fprintf(out, "stats_write_non_chained(int32_t code");
+        fprintf(out, "try_stats_write_non_chained(int32_t code");
         argIndex = 1;
         for (vector<java_type_t>::const_iterator arg = signature->begin();
             arg != signature->end(); arg++) {
@@ -331,6 +390,45 @@
         fprintf(out, "}\n");
         fprintf(out, "\n");
     }
+
+   for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
+       signature != atoms.non_chained_signatures.end(); signature++) {
+       int argIndex;
+
+       fprintf(out, "int\n");
+       fprintf(out, "stats_write_non_chained(int32_t code");
+       argIndex = 1;
+       for (vector<java_type_t>::const_iterator arg = signature->begin();
+           arg != signature->end(); arg++) {
+           fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
+           argIndex++;
+       }
+       fprintf(out, ")\n");
+
+       fprintf(out, "{\n");
+
+       fprintf(out, "  int ret = 0;\n");
+       fprintf(out, "  for(int retry = 0; retry < 3; ++retry) {\n");
+       fprintf(out, "      ret =  try_stats_write_non_chained(code");
+
+       argIndex = 1;
+       for (vector<java_type_t>::const_iterator arg = signature->begin();
+           arg != signature->end(); arg++) {
+           fprintf(out, ", arg%d",   argIndex);
+           argIndex++;
+       }
+       fprintf(out, ");\n");
+       fprintf(out, "      if (ret >= 0) { return retry; }\n");
+       fprintf(out,
+               "      std::this_thread::sleep_for(std::chrono::milliseconds(10 + 10 * retry));\n");
+       fprintf(out, "  }\n");
+       fprintf(out, "  return ret;\n");
+       fprintf(out, "}\n");
+
+       fprintf(out, "\n");
+   }
+
+
     // Print footer
     fprintf(out, "\n");
     fprintf(out, "} // namespace util\n");
@@ -775,10 +873,6 @@
                         fprintf(out, "    if (%s_length != %s_length) {\n",
                             chainField.name.c_str(),
                             attributionDecl.fields.front().name.c_str());
-                        fprintf(out, "        jniThrowException(env, "
-                            "\"java/lang/IllegalArgumentException\", "
-                            "\"invalid attribution field(%s) length.\");\n",
-                            chainField.name.c_str());
                         fprintf(out, "        return -EINVAL;\n");
                         fprintf(out, "    }\n");
                     }