Merge "Make WindowContainer surfaces container layers by default."
diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING
index 2cdf54b..4d22d0b 100644
--- a/api/TEST_MAPPING
+++ b/api/TEST_MAPPING
@@ -4,6 +4,9 @@
       "name": "CtsCurrentApiSignatureTestCases"
     },
     {
+      "name": "CtsSystemApiSignatureTestCases"
+    },
+    {
       "name": "GtsUnofficialApisUsageTestCases"
     }
   ]
diff --git a/api/current.txt b/api/current.txt
index 2b560a4..9e28ada1 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5473,6 +5473,7 @@
   public static final class Notification.BubbleMetadata implements android.os.Parcelable {
     method public int describeContents();
     method public boolean getAutoExpandBubble();
+    method public android.app.PendingIntent getDeleteIntent();
     method public int getDesiredHeight();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.PendingIntent getIntent();
@@ -5486,6 +5487,7 @@
     ctor public Notification.BubbleMetadata.Builder();
     method public android.app.Notification.BubbleMetadata build();
     method public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+    method public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
     method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
@@ -9511,6 +9513,7 @@
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
     method public static boolean getSyncAutomatically(android.accounts.Account, String);
     method @Nullable public final String getType(@NonNull android.net.Uri);
+    method @NonNull public final android.content.ContentResolver.TypeInfo getTypeInfo(@NonNull String);
     method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
     method public static boolean isSyncActive(android.accounts.Account, String);
     method public static boolean isSyncPending(android.accounts.Account, String);
@@ -9590,6 +9593,12 @@
     field public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1; // 0x1
   }
 
+  public static final class ContentResolver.TypeInfo {
+    method @NonNull public CharSequence getContentDescription();
+    method @NonNull public android.graphics.drawable.Icon getIcon();
+    method @NonNull public CharSequence getLabel();
+  }
+
   public class ContentUris {
     ctor public ContentUris();
     method @NonNull public static android.net.Uri.Builder appendId(@NonNull android.net.Uri.Builder, long);
@@ -16212,7 +16221,7 @@
 
   public final class HardwareBuffer implements java.lang.AutoCloseable android.os.Parcelable {
     method public void close();
-    method @NonNull public static android.hardware.HardwareBuffer create(int, int, int, int, long);
+    method @NonNull public static android.hardware.HardwareBuffer create(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int, long);
     method public int describeContents();
     method public int getFormat();
     method public int getHeight();
@@ -16220,7 +16229,7 @@
     method public long getUsage();
     method public int getWidth();
     method public boolean isClosed();
-    method public static boolean isSupported(int, int, int, int, long);
+    method public static boolean isSupported(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int, long);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int BLOB = 33; // 0x21
     field public static final android.os.Parcelable.Creator<android.hardware.HardwareBuffer> CREATOR;
@@ -23038,6 +23047,7 @@
     ctor public AudioAttributes.Builder();
     ctor public AudioAttributes.Builder(android.media.AudioAttributes);
     method public android.media.AudioAttributes build();
+    method public android.media.AudioAttributes.Builder setAllowCapture(boolean);
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
@@ -23371,6 +23381,18 @@
     method public void onAudioFocusChange(int);
   }
 
+  public final class AudioPlaybackCaptureConfiguration {
+  }
+
+  public static final class AudioPlaybackCaptureConfiguration.Builder {
+    ctor public AudioPlaybackCaptureConfiguration.Builder();
+    method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
+    method public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(@NonNull android.media.AudioAttributes);
+    method public android.media.AudioPlaybackCaptureConfiguration build();
+    method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
+    method public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(@NonNull android.media.AudioAttributes);
+  }
+
   public final class AudioPlaybackConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioAttributes getAudioAttributes();
@@ -23469,6 +23491,7 @@
     ctor public AudioRecord.Builder();
     method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
     method public android.media.AudioRecord.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioRecord.Builder setAudioPlaybackCaptureConfig(@NonNull android.media.AudioPlaybackCaptureConfiguration);
     method public android.media.AudioRecord.Builder setAudioSource(int) throws java.lang.IllegalArgumentException;
     method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
   }
@@ -44259,6 +44282,7 @@
     field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
     field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
     field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
+    field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array";
     field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
     field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
     field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
@@ -45689,12 +45713,9 @@
   @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef({android.telephony.ims.RcsEventQueryParams.SORT_BY_CREATION_ORDER, android.telephony.ims.RcsEventQueryParams.SORT_BY_TIMESTAMP}) public static @interface RcsEventQueryParams.SortingProperty {
   }
 
-  public final class RcsEventQueryResult implements android.os.Parcelable {
-    method public int describeContents();
+  public class RcsEventQueryResult {
     method public android.telephony.ims.RcsQueryContinuationToken getContinuationToken();
     method public java.util.List<android.telephony.ims.RcsEvent> getEvents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsEventQueryResult> CREATOR;
   }
 
   public final class RcsFileTransferCreationParams implements android.os.Parcelable {
@@ -45789,37 +45810,25 @@
     method @NonNull public android.telephony.ims.RcsGroupThread getRcsGroupThread();
   }
 
-  public final class RcsGroupThreadIconChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+  public final class RcsGroupThreadIconChangedEvent extends android.telephony.ims.RcsGroupThreadEvent {
     ctor public RcsGroupThreadIconChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable android.net.Uri);
-    method public int describeContents();
     method @Nullable public android.net.Uri getNewIcon();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadIconChangedEvent> CREATOR;
   }
 
-  public final class RcsGroupThreadNameChangedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+  public final class RcsGroupThreadNameChangedEvent extends android.telephony.ims.RcsGroupThreadEvent {
     ctor public RcsGroupThreadNameChangedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
-    method public int describeContents();
     method @Nullable public String getNewName();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadNameChangedEvent> CREATOR;
   }
 
-  public final class RcsGroupThreadParticipantJoinedEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+  public final class RcsGroupThreadParticipantJoinedEvent extends android.telephony.ims.RcsGroupThreadEvent {
     ctor public RcsGroupThreadParticipantJoinedEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
-    method public int describeContents();
     method public android.telephony.ims.RcsParticipant getJoinedParticipant();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantJoinedEvent> CREATOR;
   }
 
-  public final class RcsGroupThreadParticipantLeftEvent extends android.telephony.ims.RcsGroupThreadEvent implements android.os.Parcelable {
+  public final class RcsGroupThreadParticipantLeftEvent extends android.telephony.ims.RcsGroupThreadEvent {
     ctor public RcsGroupThreadParticipantLeftEvent(long, @NonNull android.telephony.ims.RcsGroupThread, @NonNull android.telephony.ims.RcsParticipant, @NonNull android.telephony.ims.RcsParticipant);
-    method public int describeContents();
-    method @NonNull public android.telephony.ims.RcsParticipant getLeavingParticipantId();
+    method @NonNull public android.telephony.ims.RcsParticipant getLeavingParticipant();
     method public void persist() throws android.telephony.ims.RcsMessageStoreException;
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsGroupThreadParticipantLeftEvent> CREATOR;
   }
 
   public class RcsIncomingMessage extends android.telephony.ims.RcsMessage {
@@ -46011,13 +46020,10 @@
     method @WorkerThread public void setContactId(String) throws android.telephony.ims.RcsMessageStoreException;
   }
 
-  public final class RcsParticipantAliasChangedEvent extends android.telephony.ims.RcsEvent implements android.os.Parcelable {
+  public final class RcsParticipantAliasChangedEvent extends android.telephony.ims.RcsEvent {
     ctor public RcsParticipantAliasChangedEvent(long, @NonNull android.telephony.ims.RcsParticipant, @Nullable String);
-    method public int describeContents();
     method @Nullable public String getNewAlias();
-    method @NonNull public android.telephony.ims.RcsParticipant getParticipantId();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telephony.ims.RcsParticipantAliasChangedEvent> CREATOR;
+    method @NonNull public android.telephony.ims.RcsParticipant getParticipant();
   }
 
   public final class RcsParticipantQueryParams implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index e787927..c831522 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1305,7 +1305,6 @@
 
   public abstract class ContentResolver {
     method @Nullable public android.os.Bundle getCache(@NonNull android.net.Uri);
-    method public android.graphics.drawable.Drawable getTypeDrawable(String);
     method public void putCache(@NonNull android.net.Uri, @Nullable android.os.Bundle);
   }
 
@@ -6386,20 +6385,12 @@
 
 package android.service.contentcapture {
 
-  @Deprecated public final class ContentCaptureEventsRequest implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final android.os.Parcelable.Creator<android.service.contentcapture.ContentCaptureEventsRequest> CREATOR;
-  }
-
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
     method public final void disableContentCaptureServices();
     method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
     method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
-    method @Deprecated public void onContentCaptureEventsRequest(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.ContentCaptureEventsRequest);
     method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDisconnected();
diff --git a/api/test-current.txt b/api/test-current.txt
index fa9a5d3..2a45cd3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -483,6 +483,20 @@
 
 package android.content {
 
+  public final class ContentCaptureOptions implements android.os.Parcelable {
+    ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>);
+    method public int describeContents();
+    method public static android.content.ContentCaptureOptions forWhitelistingItself();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.ContentCaptureOptions> CREATOR;
+    field public final int idleFlushingFrequencyMs;
+    field public final int logHistorySize;
+    field public final int loggingLevel;
+    field public final int maxBufferSize;
+    field public final int textChangeFlushingFrequencyMs;
+    field @Nullable public final android.util.ArraySet<android.content.ComponentName> whitelistedComponents;
+  }
+
   public class ContentProviderClient implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
@@ -496,6 +510,7 @@
     method public android.os.UserHandle getUser();
     method public int getUserId();
     method public void setAutofillCompatibilityEnabled(boolean);
+    method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
   }
 
 }
@@ -1281,6 +1296,10 @@
 
 package android.os {
 
+  public class BatteryManager {
+    method @RequiresPermission("android.permission.POWER_SAVER") public boolean setChargingStateUpdateDelayMillis(int);
+  }
+
   public class Build {
     method public static boolean is64BitAbi(String);
   }
@@ -2107,20 +2126,12 @@
 
 package android.service.contentcapture {
 
-  @Deprecated public final class ContentCaptureEventsRequest implements android.os.Parcelable {
-    method @Deprecated public int describeContents();
-    method @Deprecated @NonNull public java.util.List<android.view.contentcapture.ContentCaptureEvent> getEvents();
-    method @Deprecated public void writeToParcel(android.os.Parcel, int);
-    field @Deprecated public static final android.os.Parcelable.Creator<android.service.contentcapture.ContentCaptureEventsRequest> CREATOR;
-  }
-
   public abstract class ContentCaptureService extends android.app.Service {
     ctor public ContentCaptureService();
     method public final void disableContentCaptureServices();
     method public void onActivitySnapshot(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.SnapshotData);
     method public void onConnected();
     method public void onContentCaptureEvent(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.view.contentcapture.ContentCaptureEvent);
-    method @Deprecated public void onContentCaptureEventsRequest(@NonNull android.view.contentcapture.ContentCaptureSessionId, @NonNull android.service.contentcapture.ContentCaptureEventsRequest);
     method public void onCreateContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureContext, @NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDestroyContentCaptureSession(@NonNull android.view.contentcapture.ContentCaptureSessionId);
     method public void onDisconnected();
@@ -2235,6 +2246,7 @@
   public class TelephonyManager {
     method public int checkCarrierPrivilegesForPackage(String);
     method public int getCarrierIdListVersion();
+    method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
     method public void setCarrierTestOverride(String, String, String, String, String, String, String);
     field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe
diff --git a/cmds/idmap2/OWNERS b/cmds/idmap2/OWNERS
index 23ec5ab..f1903a5 100644
--- a/cmds/idmap2/OWNERS
+++ b/cmds/idmap2/OWNERS
@@ -1,2 +1,3 @@
 set noparent
 toddke@google.com
+rtmitchell@google.com
\ No newline at end of file
diff --git a/cmds/idmap2/libidmap2/Result.cpp b/cmds/idmap2/libidmap2/Result.cpp
index a5c9999..bd4fabd 100644
--- a/cmds/idmap2/libidmap2/Result.cpp
+++ b/cmds/idmap2/libidmap2/Result.cpp
@@ -22,6 +22,7 @@
 
 namespace android::idmap2 {
 
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 v2::Error::Error(const char* fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
@@ -29,6 +30,7 @@
   va_end(ap);
 }
 
+// NOLINTNEXTLINE(cert-dcl50-cpp)
 v2::Error::Error(const Error& parent, const char* fmt, ...) : msg_(parent.msg_) {
   msg_.append(" -> ");
 
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 653ef2e..a6699e7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -298,7 +298,7 @@
 void StatsLogProcessor::OnConfigUpdated(const int64_t timestampNs, const ConfigKey& key,
                                         const StatsdConfig& config) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED);
+    WriteDataToDiskLocked(key, timestampNs, CONFIG_UPDATED, NO_TIME_CONSTRAINTS);
     OnConfigUpdatedLocked(timestampNs, key, config);
 }
 
@@ -355,6 +355,7 @@
                                      const bool include_current_partial_bucket,
                                      const bool erase_data,
                                      const DumpReportReason dumpReportReason,
+                                     const DumpLatency dumpLatency,
                                      ProtoOutputStream* proto) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
 
@@ -378,8 +379,10 @@
         // Start of ConfigMetricsReport (reports).
         uint64_t reportsToken =
                 proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS);
-        onConfigMetricsReportLocked(key, dumpTimeStampNs, include_current_partial_bucket,
-                                    erase_data, dumpReportReason, proto);
+        onConfigMetricsReportLocked(key, dumpTimeStampNs,
+                                    include_current_partial_bucket,
+                                    erase_data, dumpReportReason,
+                                    dumpLatency, proto);
         proto->end(reportsToken);
         // End of ConfigMetricsReport (reports).
     } else {
@@ -394,10 +397,11 @@
                                      const bool include_current_partial_bucket,
                                      const bool erase_data,
                                      const DumpReportReason dumpReportReason,
+                                     const DumpLatency dumpLatency,
                                      vector<uint8_t>* outData) {
     ProtoOutputStream proto;
     onDumpReport(key, dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                 dumpReportReason, &proto);
+                 dumpReportReason, dumpLatency, &proto);
 
     if (outData != nullptr) {
         outData->clear();
@@ -423,6 +427,7 @@
                                                     const bool include_current_partial_bucket,
                                                     const bool erase_data,
                                                     const DumpReportReason dumpReportReason,
+                                                    const DumpLatency dumpLatency,
                                                     ProtoOutputStream* proto) {
     // We already checked whether key exists in mMetricsManagers in
     // WriteDataToDisk.
@@ -438,7 +443,7 @@
     // First, fill in ConfigMetricsReport using current data on memory, which
     // starts from filling in StatsLogReport's.
     it->second->onDumpReport(dumpTimeStampNs, include_current_partial_bucket,
-                             erase_data, &str_set, proto);
+                             erase_data, dumpLatency, &str_set, proto);
 
     // Fill in UidMap if there is at least one metric to report.
     // This skips the uid map if it's an empty config.
@@ -492,7 +497,7 @@
         }
     }
     if (configKeysTtlExpired.size() > 0) {
-        WriteDataToDiskLocked(CONFIG_RESET);
+        WriteDataToDiskLocked(CONFIG_RESET, NO_TIME_CONSTRAINTS);
         resetConfigsLocked(timestampNs, configKeysTtlExpired);
     }
 }
@@ -501,7 +506,8 @@
     std::lock_guard<std::mutex> lock(mMetricsMutex);
     auto it = mMetricsManagers.find(key);
     if (it != mMetricsManagers.end()) {
-        WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED);
+        WriteDataToDiskLocked(key, getElapsedRealtimeNs(), CONFIG_REMOVED, 
+                              NO_TIME_CONSTRAINTS);
         mMetricsManagers.erase(it);
         mUidMap->OnConfigRemoved(key);
     }
@@ -572,14 +578,15 @@
 
 void StatsLogProcessor::WriteDataToDiskLocked(const ConfigKey& key,
                                               const int64_t timestampNs,
-                                              const DumpReportReason dumpReportReason) {
+                                              const DumpReportReason dumpReportReason,
+                                              const DumpLatency dumpLatency) {
     if (mMetricsManagers.find(key) == mMetricsManagers.end() ||
         !mMetricsManagers.find(key)->second->shouldWriteToDisk()) {
         return;
     }
     ProtoOutputStream proto;
     onConfigMetricsReportLocked(key, timestampNs, true /* include_current_partial_bucket*/,
-                                true /* erase_data */, dumpReportReason, &proto);
+                                true /* erase_data */, dumpReportReason, dumpLatency, &proto);
     string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
          (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
     android::base::unique_fd fd(open(file_name.c_str(),
@@ -658,7 +665,8 @@
     StorageManager::deleteFile(file_name.c_str());
 }
 
-void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason) {
+void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
+                                              const DumpLatency dumpLatency) {
     const int64_t timeNs = getElapsedRealtimeNs();
     // Do not write to disk if we already have in the last few seconds.
     // This is to avoid overwriting files that would have the same name if we
@@ -671,13 +679,14 @@
     }
     mLastWriteTimeNs = timeNs;
     for (auto& pair : mMetricsManagers) {
-        WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason);
+        WriteDataToDiskLocked(pair.first, timeNs, dumpReportReason, dumpLatency);
     }
 }
 
-void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason) {
+void StatsLogProcessor::WriteDataToDisk(const DumpReportReason dumpReportReason, 
+                                        const DumpLatency dumpLatency) {
     std::lock_guard<std::mutex> lock(mMetricsMutex);
-    WriteDataToDiskLocked(dumpReportReason);
+    WriteDataToDiskLocked(dumpReportReason, dumpLatency);
 }
 
 void StatsLogProcessor::informPullAlarmFired(const int64_t timestampNs) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index ea9c6e7..e92b897 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -66,10 +66,14 @@
 
     void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                       const bool include_current_partial_bucket, const bool erase_data,
-                      const DumpReportReason dumpReportReason, vector<uint8_t>* outData);
+                      const DumpReportReason dumpReportReason, 
+                      const DumpLatency dumpLatency,
+                      vector<uint8_t>* outData);
     void onDumpReport(const ConfigKey& key, const int64_t dumpTimeNs,
                       const bool include_current_partial_bucket, const bool erase_data,
-                      const DumpReportReason dumpReportReason, ProtoOutputStream* proto);
+                      const DumpReportReason dumpReportReason,
+                      const DumpLatency dumpLatency,
+                      ProtoOutputStream* proto);
 
     /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
     void onAnomalyAlarmFired(
@@ -82,7 +86,8 @@
             unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
 
     /* Flushes data to disk. Data on memory will be gone after written to disk. */
-    void WriteDataToDisk(const DumpReportReason dumpReportReason);
+    void WriteDataToDisk(const DumpReportReason dumpReportReason,
+                         const DumpLatency dumpLatency);
 
     /* Persist metric activation status onto disk. */
     void WriteMetricsActivationToDisk(int64_t currentTimeNs);
@@ -153,14 +158,17 @@
 
     void GetActiveConfigsLocked(const int uid, vector<int64_t>& outActiveConfigs);
 
-    void WriteDataToDiskLocked(const DumpReportReason dumpReportReason);
+    void WriteDataToDiskLocked(const DumpReportReason dumpReportReason,
+                               const DumpLatency dumpLatency);
     void WriteDataToDiskLocked(const ConfigKey& key, const int64_t timestampNs,
-                               const DumpReportReason dumpReportReason);
+                               const DumpReportReason dumpReportReason,
+                               const DumpLatency dumpLatency);
 
     void onConfigMetricsReportLocked(const ConfigKey& key, const int64_t dumpTimeStampNs,
                                      const bool include_current_partial_bucket,
                                      const bool erase_data,
                                      const DumpReportReason dumpReportReason,
+                                     const DumpLatency dumpLatency,
                                      util::ProtoOutputStream* proto);
 
     /* Check if we should send a broadcast if approaching memory limits and if we're over, we
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c542b62..4deb8bd 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -313,7 +313,9 @@
                 proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST);
         mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(),
                                  true /* includeCurrentBucket */, false /* erase_data */,
-                                 ADB_DUMP, &proto);
+                                 ADB_DUMP,
+                                 FAST,
+                                 &proto);
         proto.end(reportsListToken);
         proto.flush(out);
         proto.clear();
@@ -694,7 +696,9 @@
         if (good) {
             vector<uint8_t> data;
             mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
-                                     includeCurrentBucket, eraseData, ADB_DUMP, &data);
+                                     includeCurrentBucket, eraseData, ADB_DUMP,
+                                     NO_TIME_CONSTRAINTS,
+                                     &data);
             if (proto) {
                 for (size_t i = 0; i < data.size(); i ++) {
                     dprintf(out, "%c", data[i]);
@@ -758,7 +762,7 @@
 
 status_t StatsService::cmd_write_data_to_disk(int out) {
     dprintf(out, "Writing data to disk\n");
-    mProcessor->WriteDataToDisk(ADB_DUMP);
+    mProcessor->WriteDataToDisk(ADB_DUMP, NO_TIME_CONSTRAINTS);
     return NO_ERROR;
 }
 
@@ -958,7 +962,7 @@
 Status StatsService::informDeviceShutdown() {
     ENFORCE_UID(AID_SYSTEM);
     VLOG("StatsService::informDeviceShutdown");
-    mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN);
+    mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN, FAST);
     mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
     return Status::ok();
 }
@@ -1000,7 +1004,7 @@
 void StatsService::Terminate() {
     ALOGI("StatsService::Terminating");
     if (mProcessor != nullptr) {
-        mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED);
+        mProcessor->WriteDataToDisk(TERMINATION_SIGNAL_RECEIVED, FAST);
     }
 }
 
@@ -1017,8 +1021,10 @@
     IPCThreadState* ipc = IPCThreadState::self();
     VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
     ConfigKey configKey(ipc->getCallingUid(), key);
+    // The dump latency does not matter here since we do not include the current bucket, we do not
+    // need to pull any new data anyhow.
     mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), false /* include_current_bucket*/,
-                             true /* erase_data */, GET_DATA_CALLED, output);
+                             true /* erase_data */, GET_DATA_CALLED, FAST, output);
     return Status::ok();
 }
 
@@ -1312,7 +1318,7 @@
     StatsdStats::getInstance().noteSystemServerRestart(getWallClockSec());
     if (mProcessor != nullptr) {
         ALOGW("Reset statsd upon system server restarts.");
-        mProcessor->WriteDataToDisk(STATSCOMPANION_DIED);
+        mProcessor->WriteDataToDisk(STATSCOMPANION_DIED, FAST);
         mProcessor->resetConfigs();
     }
     mAnomalyAlarmMonitor->setStatsCompanionService(nullptr);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d78647e..78e994f 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -5455,7 +5455,7 @@
         HEADER_GO_TO_SETTINGS = 9;
         PERMISSION_OPT_IN = 10;
         PERMISSION_OPT_OUT = 11;
-        PERMISSION_IGNORED = 12;
+        PERMISSION_DIALOG_SHOWN = 12;
         SWIPE_LEFT = 13;
         SWIPE_RIGHT = 14;
         STACK_EXPANDED = 15;
@@ -5630,7 +5630,7 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureStageReported {
-  optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
+    optional android.hardware.sensor.assist.AssistGestureStageEnum gesture_stage = 1;
 }
 
 /**
@@ -5640,8 +5640,8 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureFeedbackReported {
-  // Whether or not the gesture was used.
-  optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
+    // Whether or not the gesture was used.
+    optional android.hardware.sensor.assist.AssistGestureFeedbackEnum feedback_type = 1;
 }
 
 /**
@@ -5651,8 +5651,8 @@
  *   frameworks/base/packages/SystemUI/
  */
 message AssistGestureProgressReported {
-  // [0,100] progress for the assist gesture.
-  optional int32 progress = 1;
+    // [0,100] progress for the assist gesture.
+    optional int32 progress = 1;
 }
 
 /*
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index e84f88d..96d1447 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -139,13 +139,13 @@
 
 
 void CountMetricProducer::clearPastBucketsLocked(const int64_t dumpTimeNs) {
-    flushIfNeededLocked(dumpTimeNs);
     mPastBuckets.clear();
 }
 
 void CountMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              const bool erase_data,
+                                             const DumpLatency dumpLatency,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     if (include_current_partial_bucket) {
@@ -319,7 +319,7 @@
         return;
     }
 
-    flushCurrentBucketLocked(eventTimeNs);
+    flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
     // Setup the bucket start time and number.
     int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
     mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
@@ -328,7 +328,8 @@
          (long long)mCurrentBucketStartTimeNs);
 }
 
-void CountMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void CountMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                                   const int64_t& nextBucketStartTimeNs) {
     int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
     CountBucket info;
     info.mBucketStartNs = mCurrentBucketStartTimeNs;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 1ac44264..b4a910c 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -57,6 +57,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             const bool erase_data,
+                            const DumpLatency dumpLatency,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
 
@@ -78,7 +79,8 @@
     // Util function to flush the old packet.
     void flushIfNeededLocked(const int64_t& newEventTime) override;
 
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                  const int64_t& nextBucketStartTimeNs) override;
 
     std::unordered_map<MetricDimensionKey, std::vector<CountBucket>> mPastBuckets;
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index da6b97c..5e4594b 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -456,6 +456,7 @@
 void DurationMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                                 const bool include_current_partial_bucket,
                                                 const bool erase_data,
+                                                const DumpLatency dumpLatency,
                                                 std::set<string> *str_set,
                                                 ProtoOutputStream* protoOutput) {
     if (include_current_partial_bucket) {
@@ -581,7 +582,8 @@
     mCurrentBucketNum += numBucketsForward;
 }
 
-void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void DurationMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                                      const int64_t& nextBucketStartTimeNs) {
     for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin();
             whatIt != mCurrentSlicedDurationTrackerMap.end();) {
         for (auto it = whatIt->second.begin(); it != whatIt->second.end();) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index ec561b5..f711df2 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -64,6 +64,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             const bool erase_data,
+                            const DumpLatency dumpLatency,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
 
@@ -88,7 +89,8 @@
     // Util function to flush the old packet.
     void flushIfNeededLocked(const int64_t& eventTime);
 
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                  const int64_t& nextBucketStartTimeNs) override;
 
     const DurationMetric_AggregationType mAggregationType;
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 3b4af65..5435c84 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -108,6 +108,7 @@
 void EventMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              const bool erase_data,
+                                             const DumpLatency dumpLatency,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 96adfdd..74e6bc8 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -48,6 +48,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             const bool erase_data,
+                            const DumpLatency dumpLatency,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 6301793..7b001b3 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -184,6 +184,7 @@
 void GaugeMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              const bool erase_data,
+                                             const DumpLatency dumpLatency,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     VLOG("Gauge metric %lld report now...", (long long)mMetricId);
@@ -528,7 +529,7 @@
         return;
     }
 
-    flushCurrentBucketLocked(eventTimeNs);
+    flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
 
     // Adjusts the bucket start and end times.
     int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
@@ -538,7 +539,8 @@
          (long long)mCurrentBucketStartTimeNs);
 }
 
-void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                                   const int64_t& nextBucketStartTimeNs) {
     int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
 
     GaugeBucket info;
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 64a1833..9b99fb1 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -82,8 +82,7 @@
             // Flush full buckets on the normal path up to the latest bucket boundary.
             flushIfNeededLocked(eventTimeNs);
         }
-        flushCurrentBucketLocked(eventTimeNs);
-        mCurrentBucketStartTimeNs = eventTimeNs;
+        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
         if (mIsPulled && mSamplingType == GaugeMetric::RANDOM_ONE_SAMPLE) {
             pullAndMatchEventsLocked(eventTimeNs);
         }
@@ -99,6 +98,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             const bool erase_data,
+                            const DumpLatency dumpLatency,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -119,7 +119,8 @@
     // Util function to flush the old packet.
     void flushIfNeededLocked(const int64_t& eventTime) override;
 
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                  const int64_t& nextBucketStartTimeNs) override;
 
     void pullAndMatchEventsLocked(const int64_t timestampNs);
 
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 8ab3b06..99cb5d4 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -46,6 +46,16 @@
     kActiveOnBoot = 2,
 };
 
+enum DumpLatency {
+    // In some cases, we only have a short time range to do the dump, e.g. statsd is being killed.
+    // We might be able to return all the data in this mode. For instance, pull metrics might need
+    // to be pulled when the current bucket is requested.
+    FAST = 1,
+    // In other cases, it is fine for a dump to take more than a few milliseconds, e.g. config
+    // updates.
+    NO_TIME_CONSTRAINTS = 2
+};
+
 // A MetricProducer is responsible for compute one single metrics, creating stats log report, and
 // writing the report to dropbox. MetricProducers should respond to package changes as required in
 // PackageInfoListener, but if none of the metrics are slicing by package name, then the update can
@@ -87,8 +97,7 @@
             flushIfNeededLocked(eventTimeNs);
         }
         // Now flush a partial bucket.
-        flushCurrentBucketLocked(eventTimeNs);
-        mCurrentBucketStartTimeNs = eventTimeNs;
+        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
         // Don't update the current bucket number so that the anomaly tracker knows this bucket
         // is a partial bucket and can merge it with the previous bucket.
     };
@@ -135,11 +144,12 @@
     void onDumpReport(const int64_t dumpTimeNs,
                       const bool include_current_partial_bucket,
                       const bool erase_data,
+                      const DumpLatency dumpLatency,
                       std::set<string> *str_set,
                       android::util::ProtoOutputStream* protoOutput) {
         std::lock_guard<std::mutex> lock(mMutex);
         return onDumpReportLocked(dumpTimeNs, include_current_partial_bucket, erase_data,
-                str_set, protoOutput);
+                dumpLatency, str_set, protoOutput);
     }
 
     void clearPastBuckets(const int64_t dumpTimeNs) {
@@ -239,6 +249,7 @@
     virtual void onDumpReportLocked(const int64_t dumpTimeNs,
                                     const bool include_current_partial_bucket,
                                     const bool erase_data,
+                                    const DumpLatency dumpLatency,
                                     std::set<string> *str_set,
                                     android::util::ProtoOutputStream* protoOutput) = 0;
     virtual void clearPastBucketsLocked(const int64_t dumpTimeNs) = 0;
@@ -270,7 +281,7 @@
      */
     virtual void flushLocked(const int64_t& eventTimeNs) {
         flushIfNeededLocked(eventTimeNs);
-        flushCurrentBucketLocked(eventTimeNs);
+        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
     };
 
     /**
@@ -283,7 +294,8 @@
      * flushIfNeededLocked or the app upgrade handler; the caller MUST update the bucket timestamp
      * and bucket number as needed.
      */
-    virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs){};
+    virtual void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                          const int64_t& nextBucketStartTimeNs) {};
 
     // Convenience to compute the current bucket's end time, which is always aligned with the
     // start time of the metric.
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 4851a8d..4b3bfd3 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -217,6 +217,7 @@
 void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs,
                                   const bool include_current_partial_bucket,
                                   const bool erase_data,
+                                  const DumpLatency dumpLatency,
                                   std::set<string> *str_set,
                                   ProtoOutputStream* protoOutput) {
     VLOG("=========================Metric Reports Start==========================");
@@ -227,10 +228,10 @@
                     FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_METRICS);
             if (mHashStringsInReport) {
                 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                                       str_set, protoOutput);
+                                       dumpLatency, str_set, protoOutput);
             } else {
                 producer->onDumpReport(dumpTimeStampNs, include_current_partial_bucket, erase_data,
-                                       nullptr, protoOutput);
+                                       dumpLatency, nullptr, protoOutput);
             }
             protoOutput->end(token);
         } else {
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index eab1f76..3904460 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -121,6 +121,7 @@
     virtual void onDumpReport(const int64_t dumpTimeNs,
                               const bool include_current_partial_bucket,
                               const bool erase_data,
+                              const DumpLatency dumpLatency,
                               std::set<string> *str_set,
                               android::util::ProtoOutputStream* protoOutput);
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 3cf378d..e94b75c 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -188,13 +188,28 @@
 void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs,
                                              const bool include_current_partial_bucket,
                                              const bool erase_data,
+                                             const DumpLatency dumpLatency,
                                              std::set<string> *str_set,
                                              ProtoOutputStream* protoOutput) {
     VLOG("metric %lld dump report now...", (long long)mMetricId);
+    flushIfNeededLocked(dumpTimeNs);
     if (include_current_partial_bucket) {
-        flushLocked(dumpTimeNs);
-    } else {
-        flushIfNeededLocked(dumpTimeNs);
+        // For pull metrics, we need to do a pull at bucket boundaries. If we do not do that the
+        // current bucket will have incomplete data and the next will have the wrong snapshot to do
+        // a diff against. If the condition is false, we are fine since the base data is reset and
+        // we are not tracking anything.
+        bool pullNeeded = mIsPulled && mCondition == ConditionState::kTrue;
+        if (pullNeeded) {
+            switch (dumpLatency) {
+                case FAST:
+                    invalidateCurrentBucket();
+                    break;
+                case NO_TIME_CONSTRAINTS:
+                    pullAndMatchEventsLocked(dumpTimeNs);
+                    break;
+            }
+        } 
+        flushCurrentBucketLocked(dumpTimeNs, dumpTimeNs);
     }
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_ID, (long long)mMetricId);
     protoOutput->write(FIELD_TYPE_BOOL | FIELD_ID_IS_ACTIVE, isActiveLocked());
@@ -712,23 +727,21 @@
         return;
     }
 
-    flushCurrentBucketLocked(eventTimeNs);
-
     int64_t numBucketsForward = 1 + (eventTimeNs - currentBucketEndTimeNs) / mBucketSizeNs;
-    mCurrentBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
-    mCurrentBucketNum += numBucketsForward;
+    int64_t nextBucketStartTimeNs = currentBucketEndTimeNs + (numBucketsForward - 1) * mBucketSizeNs;
+    flushCurrentBucketLocked(eventTimeNs, nextBucketStartTimeNs);
 
+    mCurrentBucketNum += numBucketsForward;
     if (numBucketsForward > 1) {
         VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
         StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId);
         // take base again in future good bucket.
         resetBase();
     }
-    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
-         (long long)mCurrentBucketStartTimeNs);
 }
 
-void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs) {
+void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                                   const int64_t& nextBucketStartTimeNs) {
     if (mCondition == ConditionState::kUnknown) {
         StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId);
     }
@@ -758,6 +771,9 @@
     }
     initCurrentSlicedBucket();
     mCurrentBucketIsInvalid = false;
+    mCurrentBucketStartTimeNs = nextBucketStartTimeNs;
+    VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId,
+         (long long)mCurrentBucketStartTimeNs);
 }
 
 ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index f26ad85..696d4fa 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -65,8 +65,7 @@
         if (mIsPulled && mCondition) {
             pullAndMatchEventsLocked(eventTimeNs - 1);
         }
-        flushCurrentBucketLocked(eventTimeNs);
-        mCurrentBucketStartTimeNs = eventTimeNs;
+        flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
     };
 
 protected:
@@ -79,6 +78,7 @@
     void onDumpReportLocked(const int64_t dumpTimeNs,
                             const bool include_current_partial_bucket,
                             const bool erase_data,
+                            const DumpLatency dumpLatency,
                             std::set<string> *str_set,
                             android::util::ProtoOutputStream* protoOutput) override;
     void clearPastBucketsLocked(const int64_t dumpTimeNs) override;
@@ -97,7 +97,8 @@
     // Util function to flush the old packet.
     void flushIfNeededLocked(const int64_t& eventTime) override;
 
-    void flushCurrentBucketLocked(const int64_t& eventTimeNs) override;
+    void flushCurrentBucketLocked(const int64_t& eventTimeNs,
+                                  const int64_t& nextBucketStartTimeNs) override;
 
     void dropDataLocked(const int64_t dropTimeNs) override;
 
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index 4579ca6..88aa180 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -173,7 +173,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
@@ -204,7 +204,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
@@ -235,7 +235,7 @@
 
     // Expect to get no metrics, but snapshot specified above in uidmap.
     vector<uint8_t> bytes;
-    p.onDumpReport(key, 1, false, true, ADB_DUMP, &bytes);
+    p.onDumpReport(key, 1, false, true, ADB_DUMP, FAST, &bytes);
 
     ConfigMetricsReportList output;
     output.ParseFromArray(bytes.data(), bytes.size());
@@ -269,21 +269,21 @@
     ConfigMetricsReportList output;
 
     // Dump report WITHOUT erasing data.
-    processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, &bytes);
+    processor->onDumpReport(cfgKey, 3, true, false /* Do NOT erase data. */, ADB_DUMP, FAST, &bytes);
     output.ParseFromArray(bytes.data(), bytes.size());
     EXPECT_EQ(output.reports_size(), 1);
     EXPECT_EQ(output.reports(0).metrics_size(), 1);
     EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
 
     // Dump report WITH erasing data. There should be data since we didn't previously erase it.
-    processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, &bytes);
+    processor->onDumpReport(cfgKey, 4, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
     output.ParseFromArray(bytes.data(), bytes.size());
     EXPECT_EQ(output.reports_size(), 1);
     EXPECT_EQ(output.reports(0).metrics_size(), 1);
     EXPECT_EQ(output.reports(0).metrics(0).count_metrics().data_size(), 1);
 
     // Dump report again. There should be no data since we erased it.
-    processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, &bytes);
+    processor->onDumpReport(cfgKey, 5, true, true /* DO erase data. */, ADB_DUMP, FAST, &bytes);
     output.ParseFromArray(bytes.data(), bytes.size());
     // We don't care whether statsd has a report, as long as it has no count metrics in it.
     bool noData = output.reports_size() == 0
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index a9841c9..3382525 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -147,7 +147,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -295,7 +295,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
index a8914da..e4186b7 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_AND_cond_test.cpp
@@ -212,7 +212,7 @@
                 ConfigMetricsReportList reports;
                 vector<uint8_t> buffer;
                 processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                        true, ADB_DUMP, &buffer);
+                                        true, ADB_DUMP, FAST, &buffer);
                 EXPECT_TRUE(buffer.size() > 0);
                 EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
                 backfillDimensionPath(&reports);
@@ -548,7 +548,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    true, ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, FAST, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -798,7 +798,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    true, ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, FAST, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
index 621b6ed..f3ecd56 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_combination_OR_cond_test.cpp
@@ -131,7 +131,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -347,7 +347,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -531,7 +531,7 @@
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
         processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                                ADB_DUMP, &buffer);
+                                ADB_DUMP, FAST, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
@@ -733,7 +733,7 @@
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
         processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                                ADB_DUMP, &buffer);
+                                ADB_DUMP, FAST, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
index 9f8acaf..489bb0b 100644
--- a/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
+++ b/cmds/statsd/tests/e2e/DimensionInCondition_e2e_simple_cond_test.cpp
@@ -143,7 +143,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    true, ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, FAST, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -438,7 +438,7 @@
             ConfigMetricsReportList reports;
             vector<uint8_t> buffer;
             processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false,
-                                    true, ADB_DUMP, &buffer);
+                                    true, ADB_DUMP, FAST, &buffer);
             EXPECT_TRUE(buffer.size() > 0);
             EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
             backfillDimensionPath(&reports);
@@ -659,7 +659,7 @@
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
         processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                                ADB_DUMP, &buffer);
+                                ADB_DUMP, FAST, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 24a9980..946eccf 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -125,7 +125,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -248,7 +248,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -352,7 +352,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index 3af8212..cd80310 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -150,7 +150,7 @@
         ConfigMetricsReportList reports;
         vector<uint8_t> buffer;
         processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
-                                ADB_DUMP, &buffer);
+                                ADB_DUMP, FAST, &buffer);
         EXPECT_TRUE(buffer.size() > 0);
         EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
         backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index 85d8a56..7fb43f8a 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -211,7 +211,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 9349c85..78fb391 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -200,7 +200,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -319,7 +319,7 @@
     vector<uint8_t> buffer;
 
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index aee0c1f..ef3643f 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -46,7 +46,7 @@
     IPCThreadState* ipc = IPCThreadState::self();
     ConfigKey configKey(ipc->getCallingUid(), kConfigKey);
     processor->onDumpReport(configKey, timestamp, include_current /* include_current_bucket*/,
-                            true /* erase_data */, ADB_DUMP, &output);
+                            true /* erase_data */, ADB_DUMP, FAST, &output);
     ConfigMetricsReportList reports;
     reports.ParseFromArray(output.data(), output.size());
     EXPECT_EQ(1, reports.reports_size());
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index f3c4e12..cdb5a78 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -121,7 +121,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -228,7 +228,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 16be3d7..e13bf14 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -128,7 +128,7 @@
     vector<uint8_t> buffer;
     ConfigMetricsReportList reports;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -165,7 +165,7 @@
     vector<uint8_t> buffer;
     ConfigMetricsReportList reports;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -216,7 +216,7 @@
     }
 
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -249,7 +249,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
 
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
@@ -279,7 +279,7 @@
     ConfigMetricsReportList reports;
     vector<uint8_t> buffer;
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
@@ -325,7 +325,7 @@
     }
 
     processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-                            ADB_DUMP, &buffer);
+                            ADB_DUMP, FAST, &buffer);
     EXPECT_TRUE(buffer.size() > 0);
     EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
     backfillDimensionPath(&reports);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 7e7ffed..a9d2c88 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -2797,7 +2797,6 @@
     EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 }
 
-
 TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
     ValueMetric metric;
     metric.set_id(metricId);
@@ -2864,6 +2863,187 @@
     EXPECT_EQ(true, valueProducer.mHasGlobalBase);
 }
 
+static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
+    vector<uint8_t> bytes;
+    bytes.resize(proto->size());
+    size_t pos = 0;
+    auto iter = proto->data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&((bytes)[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+
+    StatsLogReport report;
+    report.ParseFromArray(bytes.data(), bytes.size());
+    return report;
+}
+
+TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Initial pull.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(1);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer.onDumpReport(bucketStartTimeNs + 10, 
+                               true /* include recent buckets */, true,
+                               FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    // Bucket is invalid since we did not pull when dump report was called.
+    EXPECT_EQ(0, report.value_metrics().data_size());
+}
+
+TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Initial pull.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(1);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(tagId);
+    event->write(2);
+    event->write(2);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer.onDumpReport(bucket4StartTimeNs, 
+                               false /* include recent buckets */, true,
+                               FAST, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    // Previous bucket is part of the report.
+    EXPECT_EQ(1, report.value_metrics().data_size());
+    EXPECT_EQ(0, report.value_metrics().data(0).bucket_info(0).bucket_num());
+}
+
+TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Initial pull.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(1);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
+                event->write(tagId);
+                event->write(3);
+                event->write(3);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    ProtoOutputStream output;
+    std::set<string> strSet;
+    valueProducer.onDumpReport(bucketStartTimeNs + 10, 
+                               true /* include recent buckets */, true,
+                               NO_TIME_CONSTRAINTS, &strSet, &output);
+
+    StatsLogReport report = outputStreamToProto(&output);
+    EXPECT_EQ(1, report.value_metrics().data_size());
+    EXPECT_EQ(1, report.value_metrics().data(0).bucket_info_size());
+    EXPECT_EQ(2, report.value_metrics().data(0).bucket_info(0).values(0).value_long());
+}
+
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d29fedd..89e848b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1110,7 +1110,7 @@
         super.attachBaseContext(newBase);
         if (newBase != null) {
             newBase.setAutofillClient(this);
-            newBase.setContentCaptureSupported(true);
+            newBase.setContentCaptureOptions(getContentCaptureOptions());
         }
     }
 
@@ -1120,12 +1120,6 @@
         return this;
     }
 
-    /** @hide */
-    @Override
-    public boolean isContentCaptureSupported() {
-        return true;
-    }
-
     /**
      * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives
      * lifecycle callbacks for only this Activity.
@@ -7615,6 +7609,7 @@
         mWindow.setColorMode(info.colorMode);
 
         setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
+        setContentCaptureOptions(application.getContentCaptureOptions());
     }
 
     private void enableAutofillCompatibilityIfNeeded() {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7908637..001cd69 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -46,6 +46,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -746,6 +747,14 @@
 
         boolean autofillCompatibilityEnabled;
 
+        /**
+         * Content capture options for the application - when null, it means ContentCapture is not
+         * enabled for the package.
+         */
+        @Nullable
+        ContentCaptureOptions contentCaptureOptions;
+
+        @Override
         public String toString() {
             return "AppBindData{appInfo=" + appInfo + "}";
         }
@@ -966,7 +975,8 @@
                 boolean enableBinderTracking, boolean trackAllocation,
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                 CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
-                String buildSerial, boolean autofillCompatibilityEnabled) {
+                String buildSerial, boolean autofillCompatibilityEnabled,
+                ContentCaptureOptions contentCaptureOptions) {
 
             if (services != null) {
                 if (false) {
@@ -1014,6 +1024,7 @@
             data.initProfilerInfo = profilerInfo;
             data.buildSerial = buildSerial;
             data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
+            data.contentCaptureOptions = contentCaptureOptions;
             sendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -6155,6 +6166,9 @@
             // Propagate autofill compat state
             app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
 
+            // Propagate Content Capture options
+            app.setContentCaptureOptions(data.contentCaptureOptions);
+
             mInitialApplication = app;
 
             // don't bring up providers in restricted mode; they may depend on the
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 38d2f34..a4b763d 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -524,9 +524,10 @@
     private class TaskStackListenerImpl extends TaskStackListener {
 
         @Override
-        public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
+        public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
                 throws RemoteException {
-            if (mVirtualDisplay == null) {
+            if (mVirtualDisplay == null
+                    || taskInfo.displayId != mVirtualDisplay.getDisplay().getDisplayId()) {
                 return;
             }
 
@@ -536,14 +537,17 @@
             }
             // Found the topmost stack on target display. Now check if the topmost task's
             // description changed.
-            if (taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                mSurfaceView.setResizeBackgroundColor(td.getBackgroundColor());
+            if (taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                mSurfaceView.setResizeBackgroundColor(
+                        taskInfo.taskDescription.getBackgroundColor());
             }
         }
 
         @Override
-        public void onTaskMovedToFront(int taskId) throws RemoteException {
-            if (mActivityViewCallback  == null) {
+        public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+                throws RemoteException {
+            if (mActivityViewCallback  == null || mVirtualDisplay == null
+                    || taskInfo.displayId != mVirtualDisplay.getDisplay().getDisplayId()) {
                 return;
             }
 
@@ -551,14 +555,14 @@
             // if StackInfo was null or unrelated to the "move to front" then there's no use
             // notifying the callback
             if (stackInfo != null
-                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
+                    && taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
                 mActivityViewCallback.onTaskMovedToFront(stackInfo);
             }
         }
 
         @Override
         public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException {
-            if (mActivityViewCallback  == null) {
+            if (mActivityViewCallback == null || mVirtualDisplay == null) {
                 return;
             }
 
@@ -572,17 +576,13 @@
         }
 
         @Override
-        public void onTaskRemovalStarted(int taskId) throws RemoteException {
-            if (mActivityViewCallback  == null) {
+        public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo)
+                throws RemoteException {
+            if (mActivityViewCallback == null || mVirtualDisplay == null
+                    || taskInfo.displayId != mVirtualDisplay.getDisplay().getDisplayId()) {
                 return;
             }
-            StackInfo stackInfo = getTopMostStackInfo();
-            // if StackInfo was null or task is on a different display then there's no use
-            // notifying the callback
-            if (stackInfo != null
-                    && taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                mActivityViewCallback.onTaskRemovalStarted(taskId);
-            }
+            mActivityViewCallback.onTaskRemovalStarted(taskInfo.taskId);
         }
 
         private StackInfo getTopMostStackInfo() throws RemoteException {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 6908ca2..3a1e80d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -23,6 +23,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -217,7 +218,7 @@
     private AutofillClient mAutofillClient = null;
     private boolean mIsAutofillCompatEnabled;
 
-    private boolean mIsContentCaptureSupported = false;
+    private ContentCaptureOptions mContentCaptureOptions = null;
 
     private final Object mSync = new Object();
 
@@ -2388,14 +2389,14 @@
 
     /** @hide */
     @Override
-    public boolean isContentCaptureSupported() {
-        return mIsContentCaptureSupported;
+    public ContentCaptureOptions getContentCaptureOptions() {
+        return mContentCaptureOptions;
     }
 
     /** @hide */
     @Override
-    public void setContentCaptureSupported(boolean supported) {
-        mIsContentCaptureSupported = supported;
+    public void setContentCaptureOptions(ContentCaptureOptions options) {
+        mContentCaptureOptions = options;
     }
 
     @UnsupportedAppUsage
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index e7a8c0e..b73092a 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -22,6 +22,7 @@
 import android.app.ResultInfo;
 import android.app.servertransaction.ClientTransaction;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -68,7 +69,8 @@
             int debugMode, boolean enableBinderTracking, boolean trackAllocation,
             boolean restrictedBackupMode, boolean persistent, in Configuration config,
             in CompatibilityInfo compatInfo, in Map services,
-            in Bundle coreSettings, in String buildSerial, boolean isAutofillCompatEnabled);
+            in Bundle coreSettings, in String buildSerial, boolean isAutofillCompatEnabled,
+            in ContentCaptureOptions contentCaptureOptions);
     void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
     void scheduleExit();
     void scheduleServiceArgs(IBinder token, in ParceledListSlice args);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 2e1e988..8615f00 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -73,8 +73,12 @@
     /**
      * Called when an activity was requested to be launched on a secondary display but was not
      * allowed there.
+     *
+     * @param taskInfo info about the Activity's task
+     * @param requestedDisplayId the id of the requested launch display
      */
-    void onActivityLaunchOnSecondaryDisplayFailed();
+    void onActivityLaunchOnSecondaryDisplayFailed(in ActivityManager.RunningTaskInfo taskInfo,
+            int requestedDisplayId);
 
     /**
      * Called when a task is added.
@@ -94,18 +98,17 @@
     /**
      * Called when a task is moved to the front of its stack.
      *
-     * @param taskId id of the task.
+     * @param taskInfo info about the task which moved
     */
-    void onTaskMovedToFront(int taskId);
+    void onTaskMovedToFront(in ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Called when a task’s description is changed due to an activity calling
      * ActivityManagerService.setTaskDescription
      *
-     * @param taskId id of the task.
-     * @param td the new TaskDescription.
+     * @param taskInfo info about the task which changed, with {@link TaskInfo#taskDescription}
     */
-    void onTaskDescriptionChanged(int taskId, in ActivityManager.TaskDescription td);
+    void onTaskDescriptionChanged(in ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Called when a activity’s orientation is changed due to it calling
@@ -120,8 +123,10 @@
      * Called when the task is about to be finished but before its surfaces are
      * removed from the window manager. This allows interested parties to
      * perform relevant animations before the window disappears.
+     *
+     * @param taskInfo info about the task being removed
      */
-    void onTaskRemovalStarted(int taskId);
+    void onTaskRemovalStarted(in ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Called when the task has been put in a locked state because one or more of the
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index dc4f343..0166f52 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8408,6 +8408,7 @@
     public static final class BubbleMetadata implements Parcelable {
 
         private PendingIntent mPendingIntent;
+        private PendingIntent mDeleteIntent;
         private CharSequence mTitle;
         private Icon mIcon;
         private int mDesiredHeight;
@@ -8436,11 +8437,13 @@
          */
         private static final int FLAG_SUPPRESS_INITIAL_NOTIFICATION = 0x00000002;
 
-        private BubbleMetadata(PendingIntent intent, CharSequence title, Icon icon, int height) {
-            mPendingIntent = intent;
+        private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
+                CharSequence title, Icon icon, int height) {
+            mPendingIntent = expandIntent;
             mTitle = title;
             mIcon = icon;
             mDesiredHeight = height;
+            mDeleteIntent = deleteIntent;
         }
 
         private BubbleMetadata(Parcel in) {
@@ -8449,6 +8452,9 @@
             mIcon = Icon.CREATOR.createFromParcel(in);
             mDesiredHeight = in.readInt();
             mFlags = in.readInt();
+            if (in.readInt() != 0) {
+                mDeleteIntent = PendingIntent.CREATOR.createFromParcel(in);
+            }
         }
 
         /**
@@ -8459,6 +8465,13 @@
         }
 
         /**
+         * @return the pending intent to send when the bubble is dismissed by a user, if one exists.
+         */
+        public PendingIntent getDeleteIntent() {
+            return mDeleteIntent;
+        }
+
+        /**
          * @return the title that will appear along with the app content defined by
          * {@link #getIntent()} for this bubble.
          */
@@ -8525,6 +8538,10 @@
             mIcon.writeToParcel(out, 0);
             out.writeInt(mDesiredHeight);
             out.writeInt(mFlags);
+            out.writeInt(mDeleteIntent != null ? 1 : 0);
+            if (mDeleteIntent != null) {
+                mDeleteIntent.writeToParcel(out, 0);
+            }
         }
 
         private void setFlags(int flags) {
@@ -8541,6 +8558,7 @@
             private Icon mIcon;
             private int mDesiredHeight;
             private int mFlags;
+            private PendingIntent mDeleteIntent;
 
             /**
              * Constructs a new builder object.
@@ -8633,6 +8651,14 @@
             }
 
             /**
+             * Sets an optional intent to send when this bubble is explicitly removed by the user.
+             */
+            public BubbleMetadata.Builder setDeleteIntent(PendingIntent deleteIntent) {
+                mDeleteIntent = deleteIntent;
+                return this;
+            }
+
+            /**
              * Creates the {@link BubbleMetadata} defined by this builder.
              * <p>Will throw {@link IllegalStateException} if required fields have not been set
              * on this builder.</p>
@@ -8647,8 +8673,8 @@
                 if (mIcon == null) {
                     throw new IllegalStateException("Must supply an icon for the bubble");
                 }
-                BubbleMetadata data = new BubbleMetadata(mPendingIntent, mTitle, mIcon,
-                        mDesiredHeight);
+                BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent, mTitle,
+                        mIcon, mDesiredHeight);
                 data.setFlags(mFlags);
                 return data;
             }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index c12a92f..1faa2ac 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -41,6 +41,7 @@
 import android.companion.CompanionDeviceManager;
 import android.companion.ICompanionDeviceManager;
 import android.content.ClipboardManager;
+import android.content.ContentCaptureOptions;
 import android.content.Context;
 import android.content.IRestrictionsManager;
 import android.content.RestrictionsManager;
@@ -1125,16 +1126,19 @@
                     throws ServiceNotFoundException {
                 // Get the services without throwing as this is an optional feature
                 Context outerContext = ctx.getOuterContext();
-                if (outerContext.isContentCaptureSupported()) {
+                ContentCaptureOptions options = outerContext.getContentCaptureOptions();
+                // Options is null when the service didn't whitelist the activity or package
+                if (options != null) {
                     IBinder b = ServiceManager
                             .getService(Context.CONTENT_CAPTURE_MANAGER_SERVICE);
                     IContentCaptureManager service = IContentCaptureManager.Stub.asInterface(b);
+                    // Service is null when not provided by OEM or disabled by kill-switch.
                     if (service != null) {
-                        // When feature is disabled, we return a null manager to apps so the
-                        // performance impact is practically zero
-                        return new ContentCaptureManager(outerContext, service);
+                        return new ContentCaptureManager(outerContext, service, options);
                     }
                 }
+                // When feature is disabled or app / package not whitelisted, we return a null
+                // manager to apps so the performance impact is practically zero
                 return null;
             }});
 
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index e23352a..fcc76ac 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -70,6 +70,16 @@
     }
 
     @Override
+    public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo,
+            int requestedDisplayId) throws RemoteException {
+        onActivityLaunchOnSecondaryDisplayFailed();
+    }
+
+    /**
+     * @deprecated see {@link
+     *         #onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo, int)}
+     */
+    @Deprecated
     @UnsupportedAppUsage
     public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
     }
@@ -84,15 +94,42 @@
     }
 
     @Override
+    public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+            throws RemoteException {
+        onTaskMovedToFront(taskInfo.taskId);
+    }
+
+    /**
+     * @deprecated see {@link #onTaskMovedToFront(ActivityManager.RunningTaskInfo)}
+     */
+    @Deprecated
     @UnsupportedAppUsage
     public void onTaskMovedToFront(int taskId) throws RemoteException {
     }
 
     @Override
+    public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo)
+            throws RemoteException {
+        onTaskRemovalStarted(taskInfo.taskId);
+    }
+
+    /**
+     * @deprecated see {@link #onTaskRemovalStarted(ActivityManager.RunningTaskInfo)}
+     */
+    @Deprecated
     public void onTaskRemovalStarted(int taskId) throws RemoteException {
     }
 
     @Override
+    public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
+            throws RemoteException {
+        onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
+    }
+
+    /**
+     * @deprecated see {@link #onTaskDescriptionChanged(ActivityManager.RunningTaskInfo)}
+     */
+    @Deprecated
     public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
             throws RemoteException {
     }
diff --git a/core/java/android/content/ContentCaptureOptions.aidl b/core/java/android/content/ContentCaptureOptions.aidl
new file mode 100644
index 0000000..82ffac42
--- /dev/null
+++ b/core/java/android/content/ContentCaptureOptions.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content;
+
+parcelable ContentCaptureOptions;
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
new file mode 100644
index 0000000..2fe9f14
--- /dev/null
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.ActivityThread;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.contentcapture.ContentCaptureManager;
+
+import java.io.PrintWriter;
+
+/**
+ * Content capture options for a given package.
+ *
+ * <p>This object is created by the Content Capture System Service and passed back to the app when
+ * the application is created.
+ *
+ * @hide
+ */
+@TestApi
+public final class ContentCaptureOptions implements Parcelable {
+
+    private static final String TAG = ContentCaptureOptions.class.getSimpleName();
+
+    /**
+     * Logging level for {@code logcat} statements.
+     */
+    public final int loggingLevel;
+
+    /**
+     * Maximum number of events that are buffered before sent to the app.
+     */
+    public final int maxBufferSize;
+
+    /**
+     * Frequency the buffer is flushed if idle.
+     */
+    public final int idleFlushingFrequencyMs;
+
+    /**
+     * Frequency the buffer is flushed if last event is a text change.
+     */
+    public final int textChangeFlushingFrequencyMs;
+
+    /**
+     * Size of events that are logging on {@code dump}.
+     */
+    public final int logHistorySize;
+
+    /**
+     * List of activities explicitly whitelisted for content capture (or {@code null} if whitelisted
+     * for all acitivites in the package).
+     */
+    @Nullable
+    public final ArraySet<ComponentName> whitelistedComponents;
+
+    public ContentCaptureOptions(int loggingLevel, int maxBufferSize, int idleFlushingFrequencyMs,
+            int textChangeFlushingFrequencyMs, int logHistorySize,
+            @Nullable ArraySet<ComponentName> whitelistedComponents) {
+        this.loggingLevel = loggingLevel;
+        this.maxBufferSize = maxBufferSize;
+        this.idleFlushingFrequencyMs = idleFlushingFrequencyMs;
+        this.textChangeFlushingFrequencyMs = textChangeFlushingFrequencyMs;
+        this.logHistorySize = logHistorySize;
+        this.whitelistedComponents = whitelistedComponents;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public static ContentCaptureOptions forWhitelistingItself() {
+        final ActivityThread at = ActivityThread.currentActivityThread();
+        if (at == null) {
+            throw new IllegalStateException("No ActivityThread");
+        }
+
+        final String packageName = at.getApplication().getPackageName();
+
+        if (!"android.contentcaptureservice.cts".equals(packageName)) {
+            Log.e(TAG, "forWhitelistingItself(): called by " + packageName);
+            throw new SecurityException("Thou shall not pass!");
+        }
+
+        final ContentCaptureOptions options = new ContentCaptureOptions(
+                ContentCaptureManager.LOGGING_LEVEL_VERBOSE,
+                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE,
+                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS,
+                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS,
+                ContentCaptureManager.DEFAULT_LOG_HISTORY_SIZE,
+                /* whitelistedComponents= */ null);
+        // Always log, as it's used by test only
+        Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
+
+        return options;
+    }
+
+    @Override
+    public String toString() {
+        return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
+                + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
+                + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
+                + ", logHistorySize=" + logHistorySize + ", whitelistedComponents="
+                + whitelistedComponents + "]";
+    }
+
+    /** @hide */
+    public void dumpShort(@NonNull PrintWriter pw) {
+        pw.print("logLvl="); pw.print(loggingLevel);
+        pw.print(", bufferSize="); pw.print(maxBufferSize);
+        pw.print(", idle="); pw.print(idleFlushingFrequencyMs);
+        pw.print(", textIdle="); pw.print(textChangeFlushingFrequencyMs);
+        pw.print(", logSize="); pw.print(logHistorySize);
+        if (whitelistedComponents != null) {
+            pw.print(", whitelisted="); pw.print(whitelistedComponents);
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(loggingLevel);
+        parcel.writeInt(maxBufferSize);
+        parcel.writeInt(idleFlushingFrequencyMs);
+        parcel.writeInt(textChangeFlushingFrequencyMs);
+        parcel.writeInt(logHistorySize);
+        parcel.writeArraySet(whitelistedComponents);
+    }
+
+    public static final Parcelable.Creator<ContentCaptureOptions> CREATOR =
+            new Parcelable.Creator<ContentCaptureOptions>() {
+
+                @Override
+                public ContentCaptureOptions createFromParcel(Parcel parcel) {
+                    final int loggingLevel = parcel.readInt();
+                    final int maxBufferSize = parcel.readInt();
+                    final int idleFlushingFrequencyMs = parcel.readInt();
+                    final int textChangeFlushingFrequencyMs = parcel.readInt();
+                    final int logHistorySize = parcel.readInt();
+                    @SuppressWarnings("unchecked")
+                    final ArraySet<ComponentName> whitelistedComponents =
+                            (ArraySet<ComponentName>) parcel.readArraySet(null);
+                    return new ContentCaptureOptions(loggingLevel, maxBufferSize,
+                            idleFlushingFrequencyMs, textChangeFlushingFrequencyMs, logHistorySize,
+                            whitelistedComponents);
+                }
+
+                @Override
+                public ContentCaptureOptions[] newArray(int size) {
+                    return new ContentCaptureOptions[size];
+                }
+
+    };
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0e11d4e..c44520a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -42,6 +42,7 @@
 import android.graphics.ImageDecoder.Source;
 import android.graphics.Point;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -3365,16 +3366,68 @@
         return mContext.getUserId();
     }
 
-    /**
-     * Get the system drawable of the mime type.
-     *
-     * @param mimeType the requested mime type
-     * @return the matched drawable
-     * @hide
-     */
-    @SystemApi
+    /** {@hide} */
+    @Deprecated
     public Drawable getTypeDrawable(String mimeType) {
-        return MimeIconUtils.loadMimeIcon(mContext, mimeType);
+        return getTypeInfo(mimeType).getIcon().loadDrawable(mContext);
+    }
+
+    /**
+     * Return a detailed description of the given MIME type, including an icon
+     * and label that describe the type.
+     *
+     * @param mimeType Valid, concrete MIME type.
+     */
+    public final @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+        Objects.requireNonNull(mimeType);
+        return MimeIconUtils.getTypeInfo(mimeType);
+    }
+
+    /**
+     * Detailed description of a specific MIME type, including an icon and label
+     * that describe the type.
+     */
+    public static final class TypeInfo {
+        private final Icon mIcon;
+        private final CharSequence mLabel;
+        private final CharSequence mContentDescription;
+
+        /** {@hide} */
+        public TypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
+                @NonNull CharSequence contentDescription) {
+            mIcon = Objects.requireNonNull(icon);
+            mLabel = Objects.requireNonNull(label);
+            mContentDescription = Objects.requireNonNull(contentDescription);
+        }
+
+        /**
+         * Return a visual representation of this MIME type. This can be styled
+         * using {@link Icon#setTint(int)} to match surrounding UI.
+         *
+         * @see Icon#loadDrawable(Context)
+         * @see android.widget.ImageView#setImageDrawable(Drawable)
+         */
+        public @NonNull Icon getIcon() {
+            return mIcon;
+        }
+
+        /**
+         * Return a textual representation of this MIME type.
+         *
+         * @see android.widget.TextView#setText(CharSequence)
+         */
+        public @NonNull CharSequence getLabel() {
+            return mLabel;
+        }
+
+        /**
+         * Return a content description for this MIME type.
+         *
+         * @see android.view.View#setContentDescription(CharSequence)
+         */
+        public @NonNull CharSequence getContentDescription() {
+            return mContentDescription;
+        }
     }
 
     /**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 25bfba2..fdb0041 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5353,22 +5353,21 @@
     }
 
     /**
-     * Checks whether this context supports content capture.
+     * Gets the Content Capture options for this context, or {@code null} if it's not whitelisted.
      *
      * @hide
      */
-    // NOTE: for now we just need to check if it's supported so we can optimize calls that can be
-    // skipped when it isn't. Eventually, we might need a full
-    // ContentCaptureManager.ContentCaptureClient interface (as it's done with AutofillClient).
-    //
-    public boolean isContentCaptureSupported() {
-        return false;
+    @Nullable
+    public ContentCaptureOptions getContentCaptureOptions() {
+        return null;
     }
 
     /**
      * @hide
      */
-    public void setContentCaptureSupported(@SuppressWarnings("unused") boolean supported) {
+    @TestApi
+    public void setContentCaptureOptions(
+            @SuppressWarnings("unused") @Nullable ContentCaptureOptions options) {
     }
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 26ed3b7..68b4320 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1044,7 +1044,7 @@
      */
     @TestApi
     @Override
-    public void setAutofillCompatibilityEnabled(boolean  autofillCompatEnabled) {
+    public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
         if (mBase != null) {
             mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
         }
@@ -1054,15 +1054,18 @@
      * @hide
      */
     @Override
-    public boolean isContentCaptureSupported() {
-        return mBase.isContentCaptureSupported();
+    public ContentCaptureOptions getContentCaptureOptions() {
+        return mBase == null ? null : mBase.getContentCaptureOptions();
     }
 
     /**
      * @hide
      */
+    @TestApi
     @Override
-    public void setContentCaptureSupported(boolean supported) {
-        mBase.setContentCaptureSupported(supported);
+    public void setContentCaptureOptions(ContentCaptureOptions options) {
+        if (mBase != null) {
+            mBase.setContentCaptureOptions(options);
+        }
     }
 }
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 1d0ab5a..7e5532c 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -108,6 +108,11 @@
     }
 
     /** @hide */
+    public void addPendingBackup(int userId) {
+        mPendingBackups.add(userId);
+    }
+
+    /** @hide */
     public IntArray getPendingBackups() {
         return mPendingBackups;
     }
@@ -154,6 +159,19 @@
     }
 
     /** @hide */
+    public void removePendingBackup(int userId) {
+        int idx = mPendingBackups.indexOf(userId);
+        if (idx != -1) {
+            mPendingBackups.remove(idx);
+        }
+    }
+
+    /** @hide */
+    public void removePendingRestoreInfo(int userId) {
+        removeRestoreInfo(getRestoreInfo(userId));
+    }
+
+    /** @hide */
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
             @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java
index 475be49..87cffc9 100644
--- a/core/java/android/hardware/HardwareBuffer.java
+++ b/core/java/android/hardware/HardwareBuffer.java
@@ -17,6 +17,7 @@
 package android.hardware;
 
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.LongDef;
 import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
@@ -156,8 +157,9 @@
      *     is less than one or not supported, or if the passed usage flags are not a supported set.
      */
     @NonNull
-    public static HardwareBuffer create(int width, int height, @Format int format, int layers,
-            @Usage long usage) {
+    public static HardwareBuffer create(
+            @IntRange(from = 1) int width, @IntRange(from = 1) int height,
+            @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
         if (!HardwareBuffer.isSupportedFormat(format)) {
             throw new IllegalArgumentException("Invalid pixel format " + format);
         }
@@ -194,8 +196,8 @@
      * @param usage The @Usage flags describing how the buffer will be used
      * @return True if the combination is supported, false otherwise.
      */
-    public static boolean isSupported(int width, int height, @Format int format, int layers,
-            @Usage long usage) {
+    public static boolean isSupported(@IntRange(from = 1) int width, @IntRange(from = 1) int height,
+            @Format int format, @IntRange(from = 1) int layers, @Usage long usage) {
         if (!HardwareBuffer.isSupportedFormat(format)) {
             throw new IllegalArgumentException("Invalid pixel format " + format);
         }
diff --git a/core/java/android/hardware/display/Curve.java b/core/java/android/hardware/display/Curve.java
index ac28fdd..41f66f5 100644
--- a/core/java/android/hardware/display/Curve.java
+++ b/core/java/android/hardware/display/Curve.java
@@ -59,4 +59,18 @@
     public int describeContents() {
         return 0;
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[");
+        final int size = mX.length;
+        for (int i = 0; i < size; i++) {
+            if (i != 0) {
+                sb.append(", ");
+            }
+            sb.append("(").append(mX[i]).append(", ").append(mY[i]).append(")");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
 }
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 3fc5e41..6639f0f 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -20,6 +20,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.Intent;
 import android.hardware.health.V1_0.Constants;
@@ -386,6 +387,7 @@
      */
     @RequiresPermission(permission.POWER_SAVER)
     @SystemApi
+    @TestApi
     public boolean setChargingStateUpdateDelayMillis(int delayMillis) {
         try {
             return mBatteryStats.setChargingStateUpdateDelayMillis(delayMillis);
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 4a14ece..47b1eef 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -60,7 +60,8 @@
     private static final String SYSTEM_DRIVER_VERSION_NAME = "";
     private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
-    private static final String PROPERTY_GFX_DRIVER_BUILD_DATE = "ro.gfx.driver.build_date";
+    private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
+    private static final String METADATA_DRIVER_BUILD_TIME = "driver_build_time";
     private static final String ANGLE_RULES_FILE = "a4a_rules.json";
     private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
     private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
@@ -79,9 +80,8 @@
         setupGpuLayers(context, coreSettings, pm, packageName);
         setupAngle(context, coreSettings, pm, packageName);
         if (!chooseDriver(context, coreSettings, pm, packageName)) {
-            final String driverBuildDate = SystemProperties.get(PROPERTY_GFX_DRIVER_BUILD_DATE);
             setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
-                    driverBuildDate == null ? "" : driverBuildDate, packageName);
+                    SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
         }
     }
 
@@ -667,11 +667,18 @@
         if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths);
         setDriverPath(paths);
 
-        final String driverBuildDate = driverAppInfo.metaData == null
-                ? ""
-                : driverAppInfo.metaData.getString("driver_build_date");
+        if (driverAppInfo.metaData == null) {
+            throw new NullPointerException("apk's meta-data cannot be null");
+        }
+
+        final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
+        if (driverBuildTime == null || driverBuildTime.isEmpty()) {
+            throw new IllegalArgumentException("driver_build_time meta-data is not set");
+        }
+        // driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
+        // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
         setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
-                driverBuildDate == null ? "" : driverBuildDate, packageName);
+                Long.parseLong(driverBuildTime.substring(1)), packageName);
 
         return true;
     }
@@ -695,7 +702,7 @@
     private static native void setDebugLayersGLES(String layers);
     private static native void setDriverPath(String path);
     private static native void setGpuStats(String driverPackageName, String driverVersionName,
-            long driverVersionCode, String driverBuildDate, String appPackageName);
+            long driverVersionCode, long driverBuildTime, String appPackageName);
     private static native void setAngleInfo(String path, String appPackage, String devOptIn,
             FileDescriptor rulesFd, long rulesOffset, long rulesLength);
     private static native boolean getShouldUseAngle(String packageName);
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 1de8117..de378b0 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -398,8 +398,8 @@
             }
         }
 
-        /**
-         * See com.android.internal.os.SystemZygoteInit.readArgumentList()
+        /*
+         * See com.android.internal.os.ZygoteArguments.parseArgs()
          * Presently the wire format to the zygote process is:
          * a) a count of arguments (argc, in essence)
          * b) a number of newline-separated argument strings equal to count
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index ce83a57..792eda7 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -85,6 +85,18 @@
     private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() {
 
         @Override
+        public void onConnected() {
+            mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnConnected,
+                    AugmentedAutofillService.this));
+        }
+
+        @Override
+        public void onDisconnected() {
+            mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnDisconnected,
+                    AugmentedAutofillService.this));
+        }
+
+        @Override
         public void onFillRequest(int sessionId, IBinder client, int taskId,
                 ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
                 long requestTime, IFillCallback callback) {
@@ -174,6 +186,14 @@
     public void onDisconnected() {
     }
 
+    private void handleOnConnected() {
+        onConnected();
+    }
+
+    private void handleOnDisconnected() {
+        onDisconnected();
+    }
+
     private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
             @NonNull ComponentName componentName, @NonNull AutofillId focusedId,
             @Nullable AutofillValue focusedValue, long requestTime,
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index fb6912a..5096811 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -31,7 +31,8 @@
  * @hide
  */
 oneway interface IAugmentedAutofillService {
-
+    void onConnected();
+    void onDisconnected();
     void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
                        in ComponentName activityComponent, in AutofillId focusedId,
                        in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl
deleted file mode 100644
index c032cfdb..0000000
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.service.contentcapture;
-
-parcelable ContentCaptureEventsRequest;
diff --git a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java b/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
deleted file mode 100644
index bbcf7a9..0000000
--- a/core/java/android/service/contentcapture/ContentCaptureEventsRequest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.service.contentcapture;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.contentcapture.ContentCaptureEvent;
-
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Not needed anymore...
- *
- * @deprecated ContentCaptureService should use
- * {@code #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)} instead.
- *
- * @hide
- */
-@SystemApi
-@TestApi
-@Deprecated
-public final class ContentCaptureEventsRequest implements Parcelable {
-// TODO(b/121051220): remove .java and .aidl once service implementation doesn't use it anymore
-
-    private final ContentCaptureEvent mEvent;
-
-    /** @hide */
-    public ContentCaptureEventsRequest(@NonNull ContentCaptureEvent event) {
-        mEvent = event;
-    }
-
-    /**
-     * Gets the events.
-     */
-    @NonNull
-    public List<ContentCaptureEvent> getEvents() {
-        return Arrays.asList(mEvent);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeParcelable(mEvent, flags);
-    }
-
-    public static final Parcelable.Creator<ContentCaptureEventsRequest> CREATOR =
-            new Parcelable.Creator<ContentCaptureEventsRequest>() {
-
-        @Override
-        public ContentCaptureEventsRequest createFromParcel(Parcel parcel) {
-            return new ContentCaptureEventsRequest(parcel.readParcelable(null));
-        }
-
-        @Override
-        public ContentCaptureEventsRequest[] newArray(int size) {
-            return new ContentCaptureEventsRequest[size];
-        }
-    };
-}
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index d361a2c..9c4669f 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -15,6 +15,9 @@
  */
 package android.service.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureHelper.sDebug;
+import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
 import android.annotation.CallSuper;
@@ -66,10 +69,6 @@
 
     private static final String TAG = ContentCaptureService.class.getSimpleName();
 
-    // TODO(b/121044306): STOPSHIP use dynamic value, or change to false
-    static final boolean DEBUG = true;
-    static final boolean VERBOSE = false;
-
     /**
      * The {@link Intent} that must be declared as handled by the service.
      *
@@ -89,7 +88,9 @@
     private final IContentCaptureService mServerInterface = new IContentCaptureService.Stub() {
 
         @Override
-        public void onConnected(IBinder callback) {
+        public void onConnected(IBinder callback, boolean verbose, boolean debug) {
+            sVerbose = verbose;
+            sDebug = debug;
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnConnected,
                     ContentCaptureService.this, callback));
         }
@@ -227,23 +228,12 @@
      */
     public void onCreateContentCaptureSession(@NonNull ContentCaptureContext context,
             @NonNull ContentCaptureSessionId sessionId) {
-        if (VERBOSE) {
+        if (sVerbose) {
             Log.v(TAG, "onCreateContentCaptureSession(id=" + sessionId + ", ctx=" + context + ")");
         }
     }
 
     /**
-     *
-     * @deprecated use {@link #onContentCaptureEvent(ContentCaptureSessionId, ContentCaptureEvent)}
-     * instead.
-     */
-    @Deprecated
-    public void onContentCaptureEventsRequest(@NonNull ContentCaptureSessionId sessionId,
-            @NonNull ContentCaptureEventsRequest request) {
-        if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
-    }
-
-    /**
      * Notifies the service of {@link ContentCaptureEvent events} associated with a content capture
      * session.
      *
@@ -252,8 +242,7 @@
      */
     public void onContentCaptureEvent(@NonNull ContentCaptureSessionId sessionId,
             @NonNull ContentCaptureEvent event) {
-        if (VERBOSE) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
-        onContentCaptureEventsRequest(sessionId, new ContentCaptureEventsRequest(event));
+        if (sVerbose) Log.v(TAG, "onContentCaptureEventsRequest(id=" + sessionId + ")");
     }
 
     /**
@@ -262,7 +251,7 @@
      * @param request the user data requested to be removed
      */
     public void onUserDataRemovalRequest(@NonNull UserDataRemovalRequest request) {
-        if (VERBOSE) Log.v(TAG, "onUserDataRemovalRequest()");
+        if (sVerbose) Log.v(TAG, "onUserDataRemovalRequest()");
     }
 
     /**
@@ -280,14 +269,14 @@
      * @param sessionId the id of the session to destroy
      * */
     public void onDestroyContentCaptureSession(@NonNull ContentCaptureSessionId sessionId) {
-        if (VERBOSE) Log.v(TAG, "onDestroyContentCaptureSession(id=" + sessionId + ")");
+        if (sVerbose) Log.v(TAG, "onDestroyContentCaptureSession(id=" + sessionId + ")");
     }
 
     /**
      * Disables the Content Capture service for the given user.
      */
     public final void disableContentCaptureServices() {
-        if (DEBUG) Log.d(TAG, "disableContentCaptureServices()");
+        if (sDebug) Log.d(TAG, "disableContentCaptureServices()");
 
         final IContentCaptureServiceCallback callback = mCallback;
         if (callback == null) {
@@ -313,6 +302,7 @@
     @Override
     @CallSuper
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.print("Debug: "); pw.print(sDebug); pw.print(" Verbose: "); pw.println(sVerbose);
         final int size = mSessionUids.size();
         pw.print("Number sessions: "); pw.println(size);
         if (size > 0) {
@@ -422,7 +412,7 @@
         }
         final Integer rightUid = mSessionUids.get(sessionId);
         if (rightUid == null) {
-            if (VERBOSE) {
+            if (sVerbose) {
                 Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
                         + ": " + mSessionUids);
             }
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index d92fb3b..eb65032 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -31,7 +31,7 @@
  * @hide
  */
 oneway interface IContentCaptureService {
-    void onConnected(IBinder callback);
+    void onConnected(IBinder callback, boolean verbose, boolean debug);
     void onDisconnected();
     void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
                           in IResultReceiver clientReceiver);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 3e3a623..1d89628 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -52,6 +52,7 @@
         DEFAULT_FLAGS.put("settings_systemui_theme", "true");
         DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
         DEFAULT_FLAGS.put("settings_mainline_module", "false");
+        DEFAULT_FLAGS.put("settings_dynamic_android", "false");
         DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
         DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
         DEFAULT_FLAGS.put(SAFETY_HUB, "false");
diff --git a/core/java/android/view/CompositionSamplingListener.java b/core/java/android/view/CompositionSamplingListener.java
new file mode 100644
index 0000000..e4309a6
--- /dev/null
+++ b/core/java/android/view/CompositionSamplingListener.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Rect;
+import android.os.IBinder;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Listener for sampling the result of the screen composition.
+ * {@hide}
+ */
+public abstract class CompositionSamplingListener {
+
+    private final long mNativeListener;
+    private final Executor mExecutor;
+
+    public CompositionSamplingListener(Executor executor) {
+        mExecutor = executor;
+        mNativeListener = nativeCreate(this);
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mNativeListener != 0) {
+                unregister(this);
+                nativeDestroy(mNativeListener);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Reports a luma sample from the registered region.
+     */
+    public abstract void onSampleCollected(float medianLuma);
+
+    /**
+     * Registers a sampling listener.
+     */
+    public static void register(CompositionSamplingListener listener,
+            int displayId, IBinder stopLayer, Rect samplingArea) {
+        Preconditions.checkArgument(displayId == Display.DEFAULT_DISPLAY,
+                "default display only for now");
+        nativeRegister(listener.mNativeListener, stopLayer, samplingArea.left, samplingArea.top,
+                samplingArea.right, samplingArea.bottom);
+    }
+
+    /**
+     * Unregisters a sampling listener.
+     */
+    public static void unregister(CompositionSamplingListener listener) {
+        nativeUnregister(listener.mNativeListener);
+    }
+
+    /**
+     * Dispatch the collected sample.
+     *
+     * Called from native code on a binder thread.
+     */
+    private static void dispatchOnSampleCollected(CompositionSamplingListener listener,
+            float medianLuma) {
+        listener.mExecutor.execute(() -> listener.onSampleCollected(medianLuma));
+    }
+
+    private static native long nativeCreate(CompositionSamplingListener thiz);
+    private static native void nativeDestroy(long ptr);
+    private static native void nativeRegister(long ptr, IBinder stopLayer,
+            int samplingAreaLeft, int top, int right, int bottom);
+    private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a78f2b0..278b9ff 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9378,7 +9378,7 @@
         AttachInfo ai = mAttachInfo;
 
         // First check if context has client, so it saves a service lookup when it doesn't
-        if (!mContext.isContentCaptureSupported()) return;
+        if (mContext.getContentCaptureOptions() == null) return;
 
         // Then check if it's enabled in the context...
         final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext)
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index b1fee2d..ab4847d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3497,7 +3497,7 @@
         }
         try {
             // First check if context supports it, so it saves a service lookup when it doesn't
-            if (!mContext.isContentCaptureSupported()) return;
+            if (mContext.getContentCaptureOptions() == null) return;
 
             // Then check if it's enabled in the contex itself.
             final ContentCaptureManager ccm = mContext
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index a6b40ed..e9b1683 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -369,6 +369,11 @@
     public static final String DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES =
             "smart_suggestion_supported_modes";
 
+    /** @hide */
+    public static final int RESULT_OK = 0;
+    /** @hide */
+    public static final int RESULT_CODE_NOT_SERVICE = -1;
+
     /**
      * Makes an authentication id from a request id and a dataset id.
      *
@@ -1789,7 +1794,11 @@
     @Deprecated
     public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
             @Nullable List<ComponentName> activities) {
-        // TODO(b/123100824): implement
+        setAugmentedAutofillWhitelist(toSet(packages), toSet(activities));
+    }
+
+    private <T> ArraySet<T> toSet(@Nullable List<T> set) {
+        return set == null ? null : new ArraySet<T>(set);
     }
 
     /**
@@ -1814,7 +1823,32 @@
     @TestApi
     public void setAugmentedAutofillWhitelist(@Nullable Set<String> packages,
             @Nullable Set<ComponentName> activities) {
-        // TODO(b/123100824): implement
+        if (!hasAutofillFeature()) {
+            return;
+        }
+
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        final int resultCode;
+        try {
+            mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities),
+                    resultReceiver);
+            resultCode = resultReceiver.getIntResult();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+        switch (resultCode) {
+            case RESULT_OK:
+                return;
+            case RESULT_CODE_NOT_SERVICE:
+                throw new SecurityException("caller is not user's Augmented Autofill Service");
+            default:
+                Log.wtf(TAG, "setAugmentedAutofillWhitelist(): received invalid result: "
+                        + resultCode);
+        }
+    }
+
+    private <T> ArrayList<T> toList(@Nullable Set<T> set) {
+        return set == null ? null : new ArrayList<T>(set);
     }
 
     private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index 26aeba5..9e6a4af 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -63,4 +63,6 @@
     void getAutofillServiceComponentName(in IResultReceiver result);
     void getAvailableFieldClassificationAlgorithms(in IResultReceiver result);
     void getDefaultFieldClassificationAlgorithm(in IResultReceiver result);
+    void setAugmentedAutofillWhitelist(in List<String> packages, in List<ComponentName> activities,
+        in IResultReceiver result);
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java
index 1cf27fc..6e84ff0 100644
--- a/core/java/android/view/contentcapture/ContentCaptureHelper.java
+++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java
@@ -63,12 +63,27 @@
     }
 
     /**
+     * Gets the default logging level for the device.
+     */
+    @LoggingLevel
+    public static int getDefaultLoggingLevel() {
+        return Build.IS_DEBUGGABLE ? LOGGING_LEVEL_DEBUG : LOGGING_LEVEL_OFF;
+    }
+
+    /**
      * Sets the value of the static logging level constants based on device config.
      */
     public static void setLoggingLevel() {
-        final int defaultLevel = Build.IS_DEBUGGABLE ? LOGGING_LEVEL_DEBUG : LOGGING_LEVEL_OFF;
+        final int defaultLevel = getDefaultLoggingLevel();
         final int level = getIntDeviceConfigProperty(DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL,
                 defaultLevel);
+        setLoggingLevel(level);
+    }
+
+    /**
+     * Sets the value of the static logging level constants based the given level.
+     */
+    public static void setLoggingLevel(@LoggingLevel int level) {
         Log.i(TAG, "Setting logging level to " + getLoggingLevelAsString(level));
         sVerbose = sDebug = false;
         switch (level) {
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 87e358c..336d997 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -26,6 +26,7 @@
 import android.annotation.TestApi;
 import android.annotation.UiThread;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
@@ -150,6 +151,16 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface LoggingLevel {}
 
+
+    /** @hide */
+    public static final int DEFAULT_MAX_BUFFER_SIZE = 100;
+    /** @hide */
+    public static final int DEFAULT_IDLE_FLUSHING_FREQUENCY_MS = 5_000;
+    /** @hide */
+    public static final int DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS = 1_000;
+    /** @hide */
+    public static final int DEFAULT_LOG_HISTORY_SIZE = 10;
+
     private final Object mLock = new Object();
 
     @NonNull
@@ -158,6 +169,9 @@
     @NonNull
     private final IContentCaptureManager mService;
 
+    @NonNull
+    final ContentCaptureOptions mOptions;
+
     // Flags used for starting session.
     @GuardedBy("mLock")
     private int mFlags;
@@ -172,14 +186,12 @@
 
     /** @hide */
     public ContentCaptureManager(@NonNull Context context,
-            @NonNull IContentCaptureManager service) {
+            @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
         mService = Preconditions.checkNotNull(service, "service cannot be null");
+        mOptions = Preconditions.checkNotNull(options, "options cannot be null");
 
-        // TODO(b/123096662): right now we're reading the device config values here, but ideally
-        // it should be read on ContentCaptureManagerService and passed back when the activity
-        // started.
-        ContentCaptureHelper.setLoggingLevel();
+        ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel);
 
         if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());
 
@@ -355,12 +367,13 @@
         synchronized (mLock) {
             pw.print(prefix2); pw.print("isContentCaptureEnabled(): ");
             pw.println(isContentCaptureEnabled());
-            pw.print(prefix); pw.print("Debug: "); pw.print(sDebug);
+            pw.print(prefix2); pw.print("Debug: "); pw.print(sDebug);
             pw.print(" Verbose: "); pw.println(sVerbose);
-            pw.print(prefix); pw.print("Context: "); pw.println(mContext);
-            pw.print(prefix); pw.print("User: "); pw.println(mContext.getUserId());
-            pw.print(prefix); pw.print("Service: "); pw.println(mService);
-            pw.print(prefix); pw.print("Flags: "); pw.println(mFlags);
+            pw.print(prefix2); pw.print("Context: "); pw.println(mContext);
+            pw.print(prefix2); pw.print("User: "); pw.println(mContext.getUserId());
+            pw.print(prefix2); pw.print("Service: "); pw.println(mService);
+            pw.print(prefix2); pw.print("Flags: "); pw.println(mFlags);
+            pw.print(prefix2); pw.print("Options: "); mOptions.dumpShort(pw); pw.println();
             if (mMainSession != null) {
                 final String prefix3 = prefix2 + "  ";
                 pw.print(prefix2); pw.println("Main session:");
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index f4021b1..0abf689 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -23,13 +23,9 @@
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
-import static android.view.contentcapture.ContentCaptureHelper.getIntDeviceConfigProperty;
 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
-import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY;
-import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE;
-import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -76,10 +72,6 @@
      */
     private static final int MSG_FLUSH = 1;
 
-    private static final int DEFAULT_MAX_BUFFER_SIZE = 100;
-    private static final int DEFAULT_FLUSHING_FREQUENCY_MS = 5_000;
-    private static final int DEFAULT_LOG_HISTORY_SIZE = 10;
-
     /**
      * Name of the {@link IResultReceiver} extra used to pass the binder interface to the service.
      * @hide
@@ -128,16 +120,6 @@
     @Nullable
     private ArrayList<ContentCaptureEvent> mEvents;
 
-    /**
-     * Maximum number of events that are buffered before sent to the app.
-     */
-    private final int mMaxBufferSize;
-
-    /**
-     * Frequency the buffer is flushed if idle.
-     */
-    private final int mIdleFlushingFrequencyMs;
-
     // Used just for debugging purposes (on dump)
     private long mNextFlush;
 
@@ -153,16 +135,7 @@
         mHandler = handler;
         mSystemServerInterface = systemServerInterface;
 
-        // TODO(b/123096662): right now we're reading the device config values here, but ideally
-        // it should be read on ContentCaptureManagerService and passed back when the activity
-        // started.
-        mMaxBufferSize = getIntDeviceConfigProperty(DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
-                DEFAULT_MAX_BUFFER_SIZE);
-        mIdleFlushingFrequencyMs = getIntDeviceConfigProperty(
-                DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY, DEFAULT_FLUSHING_FREQUENCY_MS);
-        final int logHistorySize = getIntDeviceConfigProperty(
-                DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, DEFAULT_LOG_HISTORY_SIZE);
-
+        final int logHistorySize = mManager.mOptions.logHistorySize;
         mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null;
     }
 
@@ -302,11 +275,12 @@
             if (sVerbose) Log.v(TAG, "handleSendEvent(): ignoring when disabled");
             return;
         }
+        final int maxBufferSize = mManager.mOptions.maxBufferSize;
         if (mEvents == null) {
             if (sVerbose) {
-                Log.v(TAG, "handleSendEvent(): creating buffer for " + mMaxBufferSize + " events");
+                Log.v(TAG, "handleSendEvent(): creating buffer for " + maxBufferSize + " events");
             }
-            mEvents = new ArrayList<>(mMaxBufferSize);
+            mEvents = new ArrayList<>(maxBufferSize);
         }
 
         // Some type of events can be merged together
@@ -347,14 +321,14 @@
 
         final int numberEvents = mEvents.size();
 
-        final boolean bufferEvent = numberEvents < mMaxBufferSize;
+        final boolean bufferEvent = numberEvents < maxBufferSize;
 
         if (bufferEvent && !forceFlush) {
             scheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
             return;
         }
 
-        if (mState != STATE_ACTIVE && numberEvents >= mMaxBufferSize) {
+        if (mState != STATE_ACTIVE && numberEvents >= maxBufferSize) {
             // Callback from startSession hasn't been called yet - typically happens on system
             // apps that are started before the system service
             // TODO(b/122959591): try to ignore session while system is not ready / boot
@@ -435,13 +409,14 @@
             // "Renew" the flush message by removing the previous one
             mHandler.removeMessages(MSG_FLUSH);
         }
-        mNextFlush = System.currentTimeMillis() + mIdleFlushingFrequencyMs;
+        final int idleFlushingFrequencyMs = mManager.mOptions.idleFlushingFrequencyMs;
+        mNextFlush = System.currentTimeMillis() + idleFlushingFrequencyMs;
         if (sVerbose) {
             Log.v(TAG, "handleScheduleFlush(): scheduled to flush in "
-                    + mIdleFlushingFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
+                    + idleFlushingFrequencyMs + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
         }
         // Post using a Runnable directly to trim a few μs from PooledLambda.obtainMessage()
-        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, mIdleFlushingFrequencyMs);
+        mHandler.postDelayed(() -> flushIfNeeded(reason), MSG_FLUSH, idleFlushingFrequencyMs);
     }
 
     @UiThread
@@ -483,7 +458,8 @@
         if (mFlushHistory != null) {
             // Logs reason, size, max size, idle timeout
             final String logRecord = "r=" + reasonString + " s=" + numberEvents
-                    + " m=" + mMaxBufferSize + " i=" + mIdleFlushingFrequencyMs;
+                    + " m=" + mManager.mOptions.maxBufferSize
+                    + " i=" + mManager.mOptions.idleFlushingFrequencyMs;
             mFlushHistory.log(logRecord);
         }
         try {
@@ -649,7 +625,6 @@
 
         pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
         pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
-        pw.print(prefix); pw.print("mSystemServerInterface: ");
         if (mDirectServiceInterface != null) {
             pw.print(prefix); pw.print("mDirectServiceInterface: ");
             pw.println(mDirectServiceInterface);
@@ -667,7 +642,7 @@
         if (mEvents != null && !mEvents.isEmpty()) {
             final int numberEvents = mEvents.size();
             pw.print(prefix); pw.print("buffered events: "); pw.print(numberEvents);
-            pw.print('/'); pw.println(mMaxBufferSize);
+            pw.print('/'); pw.println(mManager.mOptions.maxBufferSize);
             if (sVerbose && numberEvents > 0) {
                 final String prefix3 = prefix + "  ";
                 for (int i = 0; i < numberEvents; i++) {
@@ -676,7 +651,8 @@
                     pw.println();
                 }
             }
-            pw.print(prefix); pw.print("flush frequency: "); pw.println(mIdleFlushingFrequencyMs);
+            pw.print(prefix); pw.print("flush frequency: ");
+            pw.println(mManager.mOptions.idleFlushingFrequencyMs);
             pw.print(prefix); pw.print("next flush: ");
             TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
             pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index e66596b..7c8f33e 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -42,9 +42,9 @@
 
     /**
      * Constructs a resource response with the given MIME type, character encoding,
-     * and input stream. Callers must implement
-     * {@link InputStream#read(byte[]) InputStream.read(byte[])} for the input
-     * stream.
+     * and input stream. Callers must implement {@link InputStream#read(byte[])} for
+     * the input stream. {@link InputStream#close()} will be called after the WebView
+     * has finished with the response.
      *
      * <p class="note"><b>Note:</b> The MIME type and character encoding must
      * be specified as separate parameters (for example {@code "text/html"} and
@@ -67,9 +67,10 @@
     }
 
     /**
-     * Constructs a resource response with the given parameters. Callers must
-     * implement {@link InputStream#read(byte[]) InputStream.read(byte[])} for
-     * the input stream.
+     * Constructs a resource response with the given parameters. Callers must implement
+     * {@link InputStream#read(byte[])} for the input stream. {@link InputStream#close()} will be
+     * called after the WebView has finished with the response.
+     *
      *
      * <p class="note"><b>Note:</b> See {@link #WebResourceResponse(String,String,InputStream)}
      * for details on what should be specified for {@code mimeType} and {@code encoding}.
@@ -201,7 +202,8 @@
 
     /**
      * Sets the input stream that provides the resource response's data. Callers
-     * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
+     * must implement {@link InputStream#read(byte[])}. {@link InputStream#close()}
+     * will be called after the WebView has finished with the response.
      *
      * @param data the input stream that provides the resource response's data. Must not be a
      *             StringBufferInputStream.
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4ff9948..8679dcb 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -12775,13 +12775,11 @@
                     // charging even if it happens to go down a level.
                     changed |= setChargingLocked(true);
                     mLastChargeStepLevel = level;
-                }
-                if (!mCharging) {
+                } else if (!mCharging) {
                     if (mLastChargeStepLevel < level) {
                         // We have not reported that we are charging, but the level has gone up,
                         // but we would like to not have tons of activity from charging-constraint
                         // jobs, so instead of reporting ACTION_CHARGING immediately, we defer it.
-                        mLastChargeStepLevel = level;
                         if (!mHandler.hasCallbacks(mDeferSetCharging)) {
                             mHandler.postDelayed(
                                     mDeferSetCharging,
@@ -12800,9 +12798,9 @@
                         // power supplied isn't enough, so consider the device to now be
                         // discharging.
                         changed |= setChargingLocked(false);
-                        mLastChargeStepLevel = level;
                     }
                 }
+                mLastChargeStepLevel = level;
                 if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
                     mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
                             modeBits, elapsedRealtime);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 22884ac..0604ab2 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -767,17 +767,6 @@
      * @throws IOException passed straight through
      */
     static String[] readArgumentList(BufferedReader socketReader) throws IOException {
-
-        /**
-         * See android.os.Process.zygoteSendArgsAndGetPid()
-         * Presently the wire format to the zygote process is:
-         * a) a count of arguments (argc, in essence)
-         * b) a number of newline-separated argument strings equal to count
-         *
-         * After the zygote process reads these it will write the pid of
-         * the child or -1 on failure.
-         */
-
         int argc;
 
         try {
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index e6bcd37..c24a9e0 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -217,8 +217,17 @@
      * Per security review bug #1112214, duplicate args are disallowed in critical cases to make
      * injection harder.
      */
-    private void parseArgs(String[] args)
-            throws IllegalArgumentException {
+    private void parseArgs(String[] args) throws IllegalArgumentException {
+        /*
+         * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult()
+         * Presently the wire format to the zygote process is:
+         * a) a count of arguments (argc, in essence)
+         * b) a number of newline-separated argument strings equal to count
+         *
+         * After the zygote process reads these it will write the pid of
+         * the child or -1 on failure.
+         */
+
         int curArg = 0;
 
         boolean seenRuntimeArgs = false;
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index 429c618..67cdd5d 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.policy;
 
+import android.content.ContentCaptureOptions;
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.content.res.Resources;
@@ -93,7 +94,11 @@
     }
 
     @Override
-    public boolean isContentCaptureSupported() {
-        return true;
+    public ContentCaptureOptions getContentCaptureOptions() {
+        Context activityContext = mActivityContext.get();
+        if (activityContext != null) {
+            return activityContext.getContentCaptureOptions();
+        }
+        return null;
     }
 }
diff --git a/core/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java
index 841ec7c..0b5fa6d 100644
--- a/core/java/com/android/internal/util/MimeIconUtils.java
+++ b/core/java/com/android/internal/util/MimeIconUtils.java
@@ -16,215 +16,253 @@
 
 package com.android.internal.util;
 
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.provider.DocumentsContract;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver.TypeInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+import android.util.ArrayMap;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 
-import java.util.HashMap;
+import libcore.net.MimeUtils;
+
+import java.util.Locale;
+import java.util.Objects;
 
 public class MimeIconUtils {
+    @GuardedBy("sCache")
+    private static final ArrayMap<String, TypeInfo> sCache = new ArrayMap<>();
 
-    private static HashMap<String, Integer> sMimeIcons = new HashMap<>();
+    private static TypeInfo buildTypeInfo(String mimeType, int iconId,
+            int labelId, int extLabelId) {
+        final Resources res = Resources.getSystem();
 
-    private static void add(String mimeType, int resId) {
-        if (sMimeIcons.put(mimeType, resId) != null) {
-            throw new RuntimeException(mimeType + " already registered!");
-        }
-    }
-
-    static {
-        int icon;
-
-        // Package
-        icon = R.drawable.ic_doc_apk;
-        add("application/vnd.android.package-archive", icon);
-
-        // Audio
-        icon = R.drawable.ic_doc_audio;
-        add("application/ogg", icon);
-        add("application/x-flac", icon);
-
-        // Certificate
-        icon = R.drawable.ic_doc_certificate;
-        add("application/pgp-keys", icon);
-        add("application/pgp-signature", icon);
-        add("application/x-pkcs12", icon);
-        add("application/x-pkcs7-certreqresp", icon);
-        add("application/x-pkcs7-crl", icon);
-        add("application/x-x509-ca-cert", icon);
-        add("application/x-x509-user-cert", icon);
-        add("application/x-pkcs7-certificates", icon);
-        add("application/x-pkcs7-mime", icon);
-        add("application/x-pkcs7-signature", icon);
-
-        // Source code
-        icon = R.drawable.ic_doc_codes;
-        add("application/rdf+xml", icon);
-        add("application/rss+xml", icon);
-        add("application/x-object", icon);
-        add("application/xhtml+xml", icon);
-        add("text/css", icon);
-        add("text/html", icon);
-        add("text/xml", icon);
-        add("text/x-c++hdr", icon);
-        add("text/x-c++src", icon);
-        add("text/x-chdr", icon);
-        add("text/x-csrc", icon);
-        add("text/x-dsrc", icon);
-        add("text/x-csh", icon);
-        add("text/x-haskell", icon);
-        add("text/x-java", icon);
-        add("text/x-literate-haskell", icon);
-        add("text/x-pascal", icon);
-        add("text/x-tcl", icon);
-        add("text/x-tex", icon);
-        add("application/x-latex", icon);
-        add("application/x-texinfo", icon);
-        add("application/atom+xml", icon);
-        add("application/ecmascript", icon);
-        add("application/json", icon);
-        add("application/javascript", icon);
-        add("application/xml", icon);
-        add("text/javascript", icon);
-        add("application/x-javascript", icon);
-
-        // Compressed
-        icon = R.drawable.ic_doc_compressed;
-        add("application/mac-binhex40", icon);
-        add("application/rar", icon);
-        add("application/zip", icon);
-        add("application/x-apple-diskimage", icon);
-        add("application/x-debian-package", icon);
-        add("application/x-gtar", icon);
-        add("application/x-iso9660-image", icon);
-        add("application/x-lha", icon);
-        add("application/x-lzh", icon);
-        add("application/x-lzx", icon);
-        add("application/x-stuffit", icon);
-        add("application/x-tar", icon);
-        add("application/x-webarchive", icon);
-        add("application/x-webarchive-xml", icon);
-        add("application/gzip", icon);
-        add("application/x-7z-compressed", icon);
-        add("application/x-deb", icon);
-        add("application/x-rar-compressed", icon);
-
-        // Contact
-        icon = R.drawable.ic_doc_contact;
-        add("text/x-vcard", icon);
-        add("text/vcard", icon);
-
-        // Event
-        icon = R.drawable.ic_doc_event;
-        add("text/calendar", icon);
-        add("text/x-vcalendar", icon);
-
-        // Font
-        icon = R.drawable.ic_doc_font;
-        add("application/x-font", icon);
-        add("application/font-woff", icon);
-        add("application/x-font-woff", icon);
-        add("application/x-font-ttf", icon);
-
-        // Image
-        icon = R.drawable.ic_doc_image;
-        add("application/vnd.oasis.opendocument.graphics", icon);
-        add("application/vnd.oasis.opendocument.graphics-template", icon);
-        add("application/vnd.oasis.opendocument.image", icon);
-        add("application/vnd.stardivision.draw", icon);
-        add("application/vnd.sun.xml.draw", icon);
-        add("application/vnd.sun.xml.draw.template", icon);
-
-        // PDF
-        icon = R.drawable.ic_doc_pdf;
-        add("application/pdf", icon);
-
-        // Presentation
-        icon = R.drawable.ic_doc_presentation;
-        add("application/vnd.stardivision.impress", icon);
-        add("application/vnd.sun.xml.impress", icon);
-        add("application/vnd.sun.xml.impress.template", icon);
-        add("application/x-kpresenter", icon);
-        add("application/vnd.oasis.opendocument.presentation", icon);
-
-        // Spreadsheet
-        icon = R.drawable.ic_doc_spreadsheet;
-        add("application/vnd.oasis.opendocument.spreadsheet", icon);
-        add("application/vnd.oasis.opendocument.spreadsheet-template", icon);
-        add("application/vnd.stardivision.calc", icon);
-        add("application/vnd.sun.xml.calc", icon);
-        add("application/vnd.sun.xml.calc.template", icon);
-        add("application/x-kspread", icon);
-
-        // Document
-        icon = R.drawable.ic_doc_document;
-        add("application/vnd.oasis.opendocument.text", icon);
-        add("application/vnd.oasis.opendocument.text-master", icon);
-        add("application/vnd.oasis.opendocument.text-template", icon);
-        add("application/vnd.oasis.opendocument.text-web", icon);
-        add("application/vnd.stardivision.writer", icon);
-        add("application/vnd.stardivision.writer-global", icon);
-        add("application/vnd.sun.xml.writer", icon);
-        add("application/vnd.sun.xml.writer.global", icon);
-        add("application/vnd.sun.xml.writer.template", icon);
-        add("application/x-abiword", icon);
-        add("application/x-kword", icon);
-
-        // Video
-        icon = R.drawable.ic_doc_video;
-        add("application/x-quicktimeplayer", icon);
-        add("application/x-shockwave-flash", icon);
-
-        // Word
-        icon = R.drawable.ic_doc_word;
-        add("application/msword", icon);
-        add("application/vnd.openxmlformats-officedocument.wordprocessingml.document", icon);
-        add("application/vnd.openxmlformats-officedocument.wordprocessingml.template", icon);
-
-        // Excel
-        icon = R.drawable.ic_doc_excel;
-        add("application/vnd.ms-excel", icon);
-        add("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", icon);
-        add("application/vnd.openxmlformats-officedocument.spreadsheetml.template", icon);
-
-        // Powerpoint
-        icon = R.drawable.ic_doc_powerpoint;
-        add("application/vnd.ms-powerpoint", icon);
-        add("application/vnd.openxmlformats-officedocument.presentationml.presentation", icon);
-        add("application/vnd.openxmlformats-officedocument.presentationml.template", icon);
-        add("application/vnd.openxmlformats-officedocument.presentationml.slideshow", icon);
-    }
-
-    public static Drawable loadMimeIcon(Context context, String mimeType) {
-        if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
-            return context.getDrawable(R.drawable.ic_doc_folder);
-        }
-
-        // Look for exact match first
-        Integer resId = sMimeIcons.get(mimeType);
-        if (resId != null) {
-            return context.getDrawable(resId);
-        }
-
-        if (mimeType == null) {
-            // TODO: generic icon?
-            return null;
-        }
-
-        // Otherwise look for partial match
-        final String typeOnly = mimeType.split("/")[0];
-        if ("audio".equals(typeOnly)) {
-            return context.getDrawable(R.drawable.ic_doc_audio);
-        } else if ("image".equals(typeOnly)) {
-            return context.getDrawable(R.drawable.ic_doc_image);
-        } else if ("text".equals(typeOnly)) {
-            return context.getDrawable(R.drawable.ic_doc_text);
-        } else if ("video".equals(typeOnly)) {
-            return context.getDrawable(R.drawable.ic_doc_video);
+        // If this MIME type has an extension, customize the label
+        final CharSequence label;
+        final String ext = MimeUtils.guessExtensionFromMimeType(mimeType);
+        if (!TextUtils.isEmpty(ext) && extLabelId != -1) {
+            label = res.getString(extLabelId, ext.toUpperCase(Locale.US));
         } else {
-            return context.getDrawable(R.drawable.ic_doc_generic);
+            label = res.getString(labelId);
+        }
+
+        return new TypeInfo(Icon.createWithResource(res, iconId), label, label);
+    }
+
+    private static @Nullable TypeInfo buildTypeInfo(@NonNull String mimeType) {
+        switch (mimeType) {
+            case "inode/directory":
+            case "vnd.android.document/directory":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_folder,
+                        R.string.mime_type_folder, -1);
+
+            case "application/vnd.android.package-archive":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_apk,
+                        R.string.mime_type_apk, -1);
+
+            case "application/pgp-keys":
+            case "application/pgp-signature":
+            case "application/x-pkcs12":
+            case "application/x-pkcs7-certreqresp":
+            case "application/x-pkcs7-crl":
+            case "application/x-x509-ca-cert":
+            case "application/x-x509-user-cert":
+            case "application/x-pkcs7-certificates":
+            case "application/x-pkcs7-mime":
+            case "application/x-pkcs7-signature":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_certificate,
+                        R.string.mime_type_generic, R.string.mime_type_generic_ext);
+
+            case "application/rdf+xml":
+            case "application/rss+xml":
+            case "application/x-object":
+            case "application/xhtml+xml":
+            case "text/css":
+            case "text/html":
+            case "text/xml":
+            case "text/x-c++hdr":
+            case "text/x-c++src":
+            case "text/x-chdr":
+            case "text/x-csrc":
+            case "text/x-dsrc":
+            case "text/x-csh":
+            case "text/x-haskell":
+            case "text/x-java":
+            case "text/x-literate-haskell":
+            case "text/x-pascal":
+            case "text/x-tcl":
+            case "text/x-tex":
+            case "application/x-latex":
+            case "application/x-texinfo":
+            case "application/atom+xml":
+            case "application/ecmascript":
+            case "application/json":
+            case "application/javascript":
+            case "application/xml":
+            case "text/javascript":
+            case "application/x-javascript":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_codes,
+                        R.string.mime_type_document, R.string.mime_type_document_ext);
+
+            case "application/mac-binhex40":
+            case "application/rar":
+            case "application/zip":
+            case "application/x-apple-diskimage":
+            case "application/x-debian-package":
+            case "application/x-gtar":
+            case "application/x-iso9660-image":
+            case "application/x-lha":
+            case "application/x-lzh":
+            case "application/x-lzx":
+            case "application/x-stuffit":
+            case "application/x-tar":
+            case "application/x-webarchive":
+            case "application/x-webarchive-xml":
+            case "application/gzip":
+            case "application/x-7z-compressed":
+            case "application/x-deb":
+            case "application/x-rar-compressed":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_compressed,
+                        R.string.mime_type_compressed, R.string.mime_type_compressed_ext);
+
+            case "text/x-vcard":
+            case "text/vcard":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_contact,
+                        R.string.mime_type_generic, R.string.mime_type_generic_ext);
+
+            case "text/calendar":
+            case "text/x-vcalendar":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_event,
+                        R.string.mime_type_generic, R.string.mime_type_generic_ext);
+
+            case "application/x-font":
+            case "application/font-woff":
+            case "application/x-font-woff":
+            case "application/x-font-ttf":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_font,
+                        R.string.mime_type_generic, R.string.mime_type_generic_ext);
+
+            case "application/vnd.oasis.opendocument.graphics":
+            case "application/vnd.oasis.opendocument.graphics-template":
+            case "application/vnd.oasis.opendocument.image":
+            case "application/vnd.stardivision.draw":
+            case "application/vnd.sun.xml.draw":
+            case "application/vnd.sun.xml.draw.template":
+            case "application/vnd.google-apps.drawing":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_image,
+                        R.string.mime_type_image, R.string.mime_type_image_ext);
+
+            case "application/pdf":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_pdf,
+                        R.string.mime_type_document, R.string.mime_type_document_ext);
+
+            case "application/vnd.stardivision.impress":
+            case "application/vnd.sun.xml.impress":
+            case "application/vnd.sun.xml.impress.template":
+            case "application/x-kpresenter":
+            case "application/vnd.oasis.opendocument.presentation":
+            case "application/vnd.google-apps.presentation":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_presentation,
+                        R.string.mime_type_presentation, R.string.mime_type_presentation_ext);
+
+            case "application/vnd.oasis.opendocument.spreadsheet":
+            case "application/vnd.oasis.opendocument.spreadsheet-template":
+            case "application/vnd.stardivision.calc":
+            case "application/vnd.sun.xml.calc":
+            case "application/vnd.sun.xml.calc.template":
+            case "application/x-kspread":
+            case "application/vnd.google-apps.spreadsheet":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_spreadsheet,
+                        R.string.mime_type_spreadsheet, R.string.mime_type_spreadsheet_ext);
+
+            case "application/vnd.oasis.opendocument.text":
+            case "application/vnd.oasis.opendocument.text-master":
+            case "application/vnd.oasis.opendocument.text-template":
+            case "application/vnd.oasis.opendocument.text-web":
+            case "application/vnd.stardivision.writer":
+            case "application/vnd.stardivision.writer-global":
+            case "application/vnd.sun.xml.writer":
+            case "application/vnd.sun.xml.writer.global":
+            case "application/vnd.sun.xml.writer.template":
+            case "application/x-abiword":
+            case "application/x-kword":
+            case "application/vnd.google-apps.document":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_document,
+                        R.string.mime_type_document, R.string.mime_type_document_ext);
+
+            case "application/x-quicktimeplayer":
+            case "application/x-shockwave-flash":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_video,
+                        R.string.mime_type_video, R.string.mime_type_video_ext);
+
+            case "application/msword":
+            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
+            case "application/vnd.openxmlformats-officedocument.wordprocessingml.template":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_word,
+                        R.string.mime_type_document, R.string.mime_type_document_ext);
+
+            case "application/vnd.ms-excel":
+            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
+            case "application/vnd.openxmlformats-officedocument.spreadsheetml.template":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_excel,
+                        R.string.mime_type_spreadsheet, R.string.mime_type_spreadsheet_ext);
+
+            case "application/vnd.ms-powerpoint":
+            case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
+            case "application/vnd.openxmlformats-officedocument.presentationml.template":
+            case "application/vnd.openxmlformats-officedocument.presentationml.slideshow":
+                return buildTypeInfo(mimeType, R.drawable.ic_doc_powerpoint,
+                        R.string.mime_type_presentation, R.string.mime_type_presentation_ext);
+
+            default:
+                return buildGenericTypeInfo(mimeType);
+        }
+    }
+
+    private static @Nullable TypeInfo buildGenericTypeInfo(@NonNull String mimeType) {
+        // Look for partial matches
+        if (mimeType.startsWith("audio/")) {
+            return buildTypeInfo(mimeType, R.drawable.ic_doc_audio,
+                    R.string.mime_type_audio, R.string.mime_type_audio_ext);
+        } else if (mimeType.startsWith("video/")) {
+            return buildTypeInfo(mimeType, R.drawable.ic_doc_video,
+                    R.string.mime_type_video, R.string.mime_type_video_ext);
+        } else if (mimeType.startsWith("image/")) {
+            return buildTypeInfo(mimeType, R.drawable.ic_doc_image,
+                    R.string.mime_type_image, R.string.mime_type_image_ext);
+        } else if (mimeType.startsWith("text/")) {
+            return buildTypeInfo(mimeType, R.drawable.ic_doc_text,
+                    R.string.mime_type_document, R.string.mime_type_document_ext);
+        }
+
+        // As one last-ditch effort, try "bouncing" the MIME type through its
+        // default extension. This handles cases like "application/x-flac" to
+        // ".flac" to "audio/flac".
+        final String bouncedMimeType = MimeUtils
+                .guessMimeTypeFromExtension(MimeUtils.guessExtensionFromMimeType(mimeType));
+        if (bouncedMimeType != null && !Objects.equals(mimeType, bouncedMimeType)) {
+            return buildTypeInfo(bouncedMimeType);
+        }
+
+        // Worst case, return a generic file
+        return buildTypeInfo(mimeType, R.drawable.ic_doc_generic,
+                R.string.mime_type_generic, R.string.mime_type_generic_ext);
+    }
+
+    public static @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+        // Normalize MIME type
+        mimeType = mimeType.toLowerCase(Locale.US);
+
+        synchronized (sCache) {
+            TypeInfo res = sCache.get(mimeType);
+            if (res == null) {
+                res = buildTypeInfo(mimeType);
+                sCache.put(mimeType, res);
+            }
+            return res;
         }
     }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 30e9937..c309f27 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -62,6 +62,7 @@
         "android_graphics_drawable_AnimatedVectorDrawable.cpp",
         "android_graphics_drawable_VectorDrawable.cpp",
         "android_graphics_Picture.cpp",
+        "android_view_CompositionSamplingListener.cpp",
         "android_view_DisplayEventReceiver.cpp",
         "android_view_DisplayListCanvas.cpp",
         "android_view_TextureLayer.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 019ade9..0938e56 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -163,6 +163,7 @@
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
 extern int register_android_view_SurfaceSession(JNIEnv* env);
+extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper(JNIEnv *env);
@@ -1415,6 +1416,7 @@
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
     REG_JNI(register_android_view_SurfaceSession),
+    REG_JNI(register_android_view_CompositionSamplingListener),
     REG_JNI(register_android_view_TextureView),
     REG_JNI(register_com_android_internal_view_animation_NativeInterpolatorFactoryHelper),
     REG_JNI(register_com_google_android_gles_jni_EGLImpl),
diff --git a/core/jni/android/graphics/ImageDecoder.cpp b/core/jni/android/graphics/ImageDecoder.cpp
index 9efcace..98162af 100644
--- a/core/jni/android/graphics/ImageDecoder.cpp
+++ b/core/jni/android/graphics/ImageDecoder.cpp
@@ -203,7 +203,8 @@
                                           jint desiredWidth, jint desiredHeight, jobject jsubset,
                                           jboolean requireMutable, jint allocator,
                                           jboolean requireUnpremul, jboolean preferRamOverQuality,
-                                          jboolean asAlphaMask, jlong colorSpaceHandle) {
+                                          jboolean asAlphaMask, jlong colorSpaceHandle,
+                                          jboolean extended) {
     auto* decoder = reinterpret_cast<ImageDecoder*>(nativePtr);
     SkAndroidCodec* codec = decoder->mCodec.get();
     const SkISize desiredSize = SkISize::Make(desiredWidth, desiredHeight);
@@ -253,8 +254,9 @@
             }
         }
         // Otherwise, stick with N32
+    } else if (extended) {
+        colorType = kRGBA_F16_SkColorType;
     } else {
-        // This is currently the only way to know that we should decode to F16.
         colorType = codec->computeOutputColorType(colorType);
     }
 
@@ -517,7 +519,7 @@
     { "nCreate",        "([BIILandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateByteArray },
     { "nCreate",        "(Ljava/io/InputStream;[BLandroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateInputStream },
     { "nCreate",        "(Ljava/io/FileDescriptor;Landroid/graphics/ImageDecoder$Source;)Landroid/graphics/ImageDecoder;", (void*) ImageDecoder_nCreateFd },
-    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJ)Landroid/graphics/Bitmap;",
+    { "nDecodeBitmap",  "(JLandroid/graphics/ImageDecoder;ZIILandroid/graphics/Rect;ZIZZZJZ)Landroid/graphics/Bitmap;",
                                                                  (void*) ImageDecoder_nDecodeBitmap },
     { "nGetSampledSize","(JI)Landroid/util/Size;",               (void*) ImageDecoder_nGetSampledSize },
     { "nGetPadding",    "(JLandroid/graphics/Rect;)V",           (void*) ImageDecoder_nGetPadding },
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 0ccc327..d9d3cdf 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -34,15 +34,13 @@
 
 void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName,
                         jstring driverVersionName, jlong driverVersionCode,
-                        jstring driverBuildDate, jstring appPackageName) {
+                        jlong driverBuildTime, jstring appPackageName) {
     ScopedUtfChars driverPackageNameChars(env, driverPackageName);
     ScopedUtfChars driverVersionNameChars(env, driverVersionName);
-    ScopedUtfChars driverBuildDateChars(env, driverBuildDate);
     ScopedUtfChars appPackageNameChars(env, appPackageName);
     android::GraphicsEnv::getInstance().setGpuStats(driverPackageNameChars.c_str(),
                                                     driverVersionNameChars.c_str(),
-                                                    driverVersionCode,
-                                                    driverBuildDateChars.c_str(),
+                                                    driverVersionCode, driverBuildTime,
                                                     appPackageNameChars.c_str());
 }
 
@@ -87,7 +85,7 @@
 const JNINativeMethod g_methods[] = {
     { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
     { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
-    { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
+    { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
     { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
     { "getShouldUseAngle", "(Ljava/lang/String;)Z", reinterpret_cast<void*>(shouldUseAngle_native) },
     { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
diff --git a/core/jni/android_view_CompositionSamplingListener.cpp b/core/jni/android_view_CompositionSamplingListener.cpp
new file mode 100644
index 0000000..283ba0d
--- /dev/null
+++ b/core/jni/android_view_CompositionSamplingListener.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CompositionSamplingListener"
+
+#include "android_util_Binder.h"
+
+#include <nativehelper/JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+#include <utils/RefBase.h>
+#include <binder/IServiceManager.h>
+
+#include <gui/IRegionSamplingListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+namespace {
+
+struct {
+    jclass mClass;
+    jmethodID mDispatchOnSampleCollected;
+} gListenerClassInfo;
+
+struct CompositionSamplingListener : public BnRegionSamplingListener {
+    CompositionSamplingListener(JNIEnv* env, jobject listener)
+            : mListener(env->NewGlobalRef(listener)) {}
+
+    void onSampleCollected(float medianLuma) override {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        LOG_ALWAYS_FATAL_IF(env == nullptr, "Unable to retrieve JNIEnv in onSampleCollected.");
+
+        env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+                gListenerClassInfo.mDispatchOnSampleCollected, mListener,
+                static_cast<jfloat>(medianLuma));
+        if (env->ExceptionCheck()) {
+            ALOGE("CompositionSamplingListener.onSampleCollected() failed.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+    }
+
+protected:
+    virtual ~CompositionSamplingListener() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->DeleteGlobalRef(mListener);
+    }
+
+private:
+    jobject mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+    CompositionSamplingListener* listener = new CompositionSamplingListener(env, obj);
+    listener->incStrong((void*)nativeCreate);
+    return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+    CompositionSamplingListener* listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+    listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr, jobject stopLayerTokenObj,
+        jint left, jint top, jint right, jint bottom) {
+    sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+    sp<IBinder> stopLayerHandle = ibinderForJavaObject(env, stopLayerTokenObj);
+
+    // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
+    sp<ISurfaceComposer> composer;
+    if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
+        jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
+        return;
+    }
+
+    composer->addRegionSamplingListener(
+            Rect(left, top, right, bottom), stopLayerHandle, listener);
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<CompositionSamplingListener> listener = reinterpret_cast<CompositionSamplingListener*>(ptr);
+
+    // TODO: Use SurfaceComposerClient once it has addRegionSamplingListener.
+    sp<ISurfaceComposer> composer;
+    if (getService(String16("SurfaceFlinger"), &composer) != NO_ERROR) {
+        jniThrowRuntimeException(env, "Couldn't retrieve SurfaceFlinger");
+        return;
+    }
+
+    composer->removeRegionSamplingListener(listener);
+}
+
+const JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "nativeCreate", "(Landroid/view/CompositionSamplingListener;)J",
+            (void*)nativeCreate },
+    { "nativeDestroy", "(J)V",
+            (void*)nativeDestroy },
+    { "nativeRegister", "(JLandroid/os/IBinder;IIII)V",
+            (void*)nativeRegister },
+    { "nativeUnregister", "(J)V",
+            (void*)nativeUnregister }
+};
+
+} // namespace
+
+int register_android_view_CompositionSamplingListener(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/CompositionSamplingListener",
+            gMethods, NELEM(gMethods));
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass clazz = env->FindClass("android/view/CompositionSamplingListener");
+    gListenerClassInfo.mDispatchOnSampleCollected = env->GetStaticMethodID(
+            clazz, "dispatchOnSampleCollected", "(Landroid/view/CompositionSamplingListener;F)V");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/proto/android/hardware/sensor/assist/enums.proto b/core/proto/android/hardware/sensor/assist/enums.proto
index 8c5841a..012dcb2 100644
--- a/core/proto/android/hardware/sensor/assist/enums.proto
+++ b/core/proto/android/hardware/sensor/assist/enums.proto
@@ -21,14 +21,14 @@
 option java_multiple_files = true;
 
 enum AssistGestureStageEnum {
-  ASSIST_GESTURE_STAGE_UNKNOWN = 0;
-  ASSIST_GESTURE_STAGE_PROGRESS = 1;
-  ASSIST_GESTURE_STAGE_PRIMED = 2;
-  ASSIST_GESTURE_STAGE_DETECTED = 3;
+    ASSIST_GESTURE_STAGE_UNKNOWN = 0;
+    ASSIST_GESTURE_STAGE_PROGRESS = 1;
+    ASSIST_GESTURE_STAGE_PRIMED = 2;
+    ASSIST_GESTURE_STAGE_DETECTED = 3;
 }
 
 enum AssistGestureFeedbackEnum {
-  ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
-  ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
-  ASSIST_GESTURE_FEEDBACK_USED = 2;
+    ASSIST_GESTURE_FEEDBACK_UNKNOWN = 0;
+    ASSIST_GESTURE_FEEDBACK_NOT_USED = 1;
+    ASSIST_GESTURE_FEEDBACK_USED = 2;
 }
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5b74d90..fc896cf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1167,8 +1167,7 @@
     <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that are associated with activity recognition.
-         TODO(zezeozue). STOPSHIP: Add icon -->
+    <!-- Used for permissions that are associated with activity recognition. -->
     <permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
         android:icon="@drawable/perm_group_activity_recognition"
         android:label="@string/permgrouplab_activityRecognition"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 09fb663..dbdc763 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5287,6 +5287,50 @@
     <!-- Summary of notification letting users know why battery saver was turned on automatically [CHAR_LIMIT=NONE]-->
     <string name="dynamic_mode_notification_summary">Battery Saver activated to extend battery life</string>
 
+    <!-- Description of media type: folder or directory that contains additional files. [CHAR LIMIT=32] -->
+    <string name="mime_type_folder">Folder</string>
+    <!-- Description of media type: application file, such as APK. [CHAR LIMIT=32] -->
+    <string name="mime_type_apk">Android application</string>
+
+    <!-- Description of media type: generic file with unknown contents. [CHAR LIMIT=32] -->
+    <string name="mime_type_generic">File</string>
+    <!-- Description of media type: generic file with unknown contents. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_generic_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> file</string>
+
+    <!-- Description of media type: audio file, such as MP3 or WAV. [CHAR LIMIT=32] -->
+    <string name="mime_type_audio">Audio</string>
+    <!-- Description of media type: audio file, such as MP3 or WAV. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_audio_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> audio</string>
+
+    <!-- Description of media type: video file, such as MP4 or MKV. [CHAR LIMIT=32] -->
+    <string name="mime_type_video">Video</string>
+    <!-- Description of media type: video file, such as MP4 or MKV. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_video_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> video</string>
+
+    <!-- Description of media type: image file, such as JPG or PNG. [CHAR LIMIT=32] -->
+    <string name="mime_type_image">Image</string>
+    <!-- Description of media type: image file, such as JPG or PNG. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_image_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> image</string>
+
+    <!-- Description of media type: archive file, such as ZIP or TAR. [CHAR LIMIT=32] -->
+    <string name="mime_type_compressed">Archive</string>
+    <!-- Description of media type: archive file, such as ZIP or TAR. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_compressed_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> archive</string>
+
+    <!-- Description of media type: document file, such as DOC or PDF. [CHAR LIMIT=32] -->
+    <string name="mime_type_document">Document</string>
+    <!-- Description of media type: document file, such as DOC or PDF. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_document_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> document</string>
+
+    <!-- Description of media type: spreadsheet file, such as XLS. [CHAR LIMIT=32] -->
+    <string name="mime_type_spreadsheet">Spreadsheet</string>
+    <!-- Description of media type: spreadsheet file, such as XLS. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_spreadsheet_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> spreadsheet</string>
+
+    <!-- Description of media type: presentation file, such as PPT. [CHAR LIMIT=32] -->
+    <string name="mime_type_presentation">Presentation</string>
+    <!-- Description of media type: presentation file, such as PPT. The 'extension' variable is the file name extension. [CHAR LIMIT=32] -->
+    <string name="mime_type_presentation_ext"><xliff:g id="extension" example="PDF">%1$s</xliff:g> presentation</string>
 
     <!-- Strings for car -->
     <!-- String displayed when loading a user in the car [CHAR LIMIT=30] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1ebd6e9..4ae239e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3661,4 +3661,24 @@
   <java-symbol type="array" name="config_displayWhiteBalanceAmbientColorTemperatures" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayColorTemperatures" />
   <java-symbol type="drawable" name="ic_action_open" />
+
+  <!-- MIME types -->
+  <java-symbol type="string" name="mime_type_folder" />
+  <java-symbol type="string" name="mime_type_apk" />
+  <java-symbol type="string" name="mime_type_generic" />
+  <java-symbol type="string" name="mime_type_generic_ext" />
+  <java-symbol type="string" name="mime_type_audio" />
+  <java-symbol type="string" name="mime_type_audio_ext" />
+  <java-symbol type="string" name="mime_type_video" />
+  <java-symbol type="string" name="mime_type_video_ext" />
+  <java-symbol type="string" name="mime_type_image" />
+  <java-symbol type="string" name="mime_type_image_ext" />
+  <java-symbol type="string" name="mime_type_compressed" />
+  <java-symbol type="string" name="mime_type_compressed_ext" />
+  <java-symbol type="string" name="mime_type_document" />
+  <java-symbol type="string" name="mime_type_document_ext" />
+  <java-symbol type="string" name="mime_type_spreadsheet" />
+  <java-symbol type="string" name="mime_type_spreadsheet_ext" />
+  <java-symbol type="string" name="mime_type_presentation" />
+  <java-symbol type="string" name="mime_type_presentation_ext" />
 </resources>
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index a5ea441..9fabe44 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -29,6 +29,7 @@
 import android.app.IUiAutomationConnection;
 import android.app.ProfilerInfo;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -406,7 +407,7 @@
                 IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
                 boolean b2, boolean b3, Configuration configuration,
                 CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
-                boolean autofillCompatEnabled) throws RemoteException {
+                boolean autofillCompatEnabled, ContentCaptureOptions o) throws RemoteException {
         }
 
         @Override
diff --git a/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java
new file mode 100644
index 0000000..75a2e8a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/CompositionSamplingListenerTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.graphics.Rect;
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class CompositionSamplingListenerTest {
+
+    @Test
+    public void testRegisterUnregister() {
+        CompositionSamplingListener.register(mListener, DEFAULT_DISPLAY, new Binder(),
+                new Rect(1, 1, 10, 10));
+        CompositionSamplingListener.unregister(mListener);
+    }
+
+    private CompositionSamplingListener mListener = new CompositionSamplingListener(Runnable::run) {
+        @Override
+        public void onSampleCollected(float medianLuma) {
+            // Ignore
+        }
+    };
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
index 312e0e0..cd885e0 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureManagerTest.java
@@ -41,7 +41,8 @@
 
     @Before
     public void before() {
-        mManager = new ContentCaptureManager(mMockContext, null);
+        mManager = new ContentCaptureManager(mMockContext, /* service= */ null,
+                /* options= */ null);
     }
 
     @Test
diff --git a/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java
new file mode 100644
index 0000000..4412c2c
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/MimeIconUtilsTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 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.util;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link MimeIconUtils}.
+ */
+public class MimeIconUtilsTest extends TestCase {
+    public void testSimple() throws Exception {
+        assertEquals("PNG image",
+                MimeIconUtils.getTypeInfo("image/png").getLabel());
+        assertEquals("Image",
+                MimeIconUtils.getTypeInfo("image/x-custom").getLabel());
+
+        assertEquals("ALC file",
+                MimeIconUtils.getTypeInfo("chemical/x-alchemy").getLabel());
+        assertEquals("File",
+                MimeIconUtils.getTypeInfo("x-custom/x-custom").getLabel());
+
+        assertEquals("Folder",
+                MimeIconUtils.getTypeInfo("inode/directory").getLabel());
+
+        assertEquals("ZIP archive",
+                MimeIconUtils.getTypeInfo("application/zip").getLabel());
+        assertEquals("RAR archive",
+                MimeIconUtils.getTypeInfo("application/rar").getLabel());
+
+        assertEquals("TXT document",
+                MimeIconUtils.getTypeInfo("text/plain").getLabel());
+        assertEquals("Document",
+                MimeIconUtils.getTypeInfo("text/x-custom").getLabel());
+
+        assertEquals("FLAC audio",
+                MimeIconUtils.getTypeInfo("audio/flac").getLabel());
+        assertEquals("FLAC audio",
+                MimeIconUtils.getTypeInfo("application/x-flac").getLabel());
+    }
+}
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 9b5e330..7016cc7 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -1641,12 +1641,17 @@
     @NonNull
     private Bitmap decodeBitmapInternal() throws IOException {
         checkState();
-        long colorSpacePtr = mDesiredColorSpace == null ? 0 :
-                mDesiredColorSpace.getNativeInstance();
+        long colorSpacePtr = 0;
+        boolean extended = false;
+        if (mDesiredColorSpace != null) {
+            colorSpacePtr = mDesiredColorSpace.getNativeInstance();
+            extended = mDesiredColorSpace == ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)
+                || mDesiredColorSpace == ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB);
+        }
         return nDecodeBitmap(mNativePtr, this, mPostProcessor != null,
                 mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mUnpremultipliedRequired,
-                mConserveMemory, mDecodeAsAlphaMask, colorSpacePtr);
+                mConserveMemory, mDecodeAsAlphaMask, colorSpacePtr, extended);
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1934,7 +1939,7 @@
             @Nullable Rect cropRect, boolean mutable,
             int allocator, boolean unpremulRequired,
             boolean conserveMemory, boolean decodeAsAlphaMask,
-            long desiredColorSpace)
+            long desiredColorSpace, boolean extended)
         throws IOException;
     private static native Size nGetSampledSize(long nativePtr,
                                                int sampleSize);
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index f5a6f86..ea396c6 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -368,6 +368,12 @@
      */
     public final static int FLAG_DEEP_BUFFER = 0x1 << 9;
 
+    /**
+     * @hide
+     * Flag specifying that the audio shall not be captured by other apps.
+     */
+    public static final int FLAG_NO_CAPTURE = 0x1 << 10;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
             FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
             FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER;
@@ -618,6 +624,22 @@
         }
 
         /**
+         * Specifying if audio shall or shall not be captured by other apps.
+         * By default, capture is allowed.
+         * @param allowCapture false to forbid capture of the audio by any apps,
+         *                     true to allow apps to capture the audio
+         * @return the same Builder instance
+         */
+        public Builder setAllowCapture(boolean allowCapture) {
+            if (allowCapture) {
+                mFlags &= ~FLAG_NO_CAPTURE;
+            } else {
+                mFlags |= FLAG_NO_CAPTURE;
+            }
+            return this;
+        }
+
+        /**
          * @hide
          * Replaces flags.
          * @param flags any combination of {@link AudioAttributes#FLAG_ALL}.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f996d38..7de7f8f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3188,6 +3188,10 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public int registerAudioPolicy(@NonNull AudioPolicy policy) {
+        return registerAudioPolicyStatic(policy);
+    }
+
+    static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
         if (policy == null) {
             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
         }
@@ -3214,6 +3218,10 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
+        unregisterAudioPolicyAsyncStatic(policy);
+    }
+
+    static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
         if (policy == null) {
             throw new IllegalArgumentException("Illegal null AudioPolicy argument");
         }
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
new file mode 100644
index 0000000..22f14ae
--- /dev/null
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.NonNull;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioMixingRule;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Configuration for capturing audio played by other apps.
+ *
+ * <p>An example for creating a capture configuration for capturing all media playback:
+ *
+ * <pre>
+ *     AudioAttributes mediaAttr = new AudioAttributes.Builder()
+ *         .setUsage(AudioAttributes.USAGE_MEDIA)
+ *         .build();
+ *     AudioPlaybackCaptureConfiguration config = new AudioPlaybackCaptureConfiguration.Builder()
+ *         .addMatchingUsage(mediaAttr)
+ *         .build();
+ *     AudioRecord record = new AudioRecord.Builder()
+ *         .setPlaybackCaptureConfig(config)
+ *         .build();
+ * </pre>
+ *
+ * @see AudioRecord.Builder#setPlaybackCaptureConfig(AudioPlaybackCaptureConfiguration)
+ */
+public final class AudioPlaybackCaptureConfiguration {
+
+    private final AudioMixingRule mAudioMixingRule;
+
+    private AudioPlaybackCaptureConfiguration(AudioMixingRule audioMixingRule) {
+        mAudioMixingRule = audioMixingRule;
+    }
+
+    /**
+     * Returns a mix that routes audio back into the app while still playing it from the speakers.
+     *
+     * @param audioFormat The format in which to capture the audio.
+     */
+    AudioMix createAudioMix(AudioFormat audioFormat) {
+        return new AudioMix.Builder(mAudioMixingRule)
+                .setFormat(audioFormat)
+                .setRouteFlags(AudioMix.ROUTE_FLAG_LOOP_BACK | AudioMix.ROUTE_FLAG_RENDER)
+                .build();
+    }
+
+    /** Builder for creating {@link AudioPlaybackCaptureConfiguration} instances. */
+    public static final class Builder {
+
+        private static final int MATCH_TYPE_UNSPECIFIED = 0;
+        private static final int MATCH_TYPE_INCLUSIVE = 1;
+        private static final int MATCH_TYPE_EXCLUSIVE = 2;
+
+        private static final String ERROR_MESSAGE_MISMATCHED_RULES =
+                "Inclusive and exclusive usage rules cannot be combined";
+
+        private final AudioMixingRule.Builder mAudioMixingRuleBuilder;
+        private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED;
+        private int mUidMatchType = MATCH_TYPE_UNSPECIFIED;
+
+        public Builder() {
+            mAudioMixingRuleBuilder = new AudioMixingRule.Builder();
+        }
+
+        /**
+         * Only capture audio output with the given {@link AudioAttributes}.
+         *
+         * <p>If called multiple times, will capture audio output that matches any of the given
+         * attributes.
+         *
+         * @throws IllegalStateException if called in conjunction with
+         *     {@link #excludeUsage(AudioAttributes)}.
+         */
+        public Builder addMatchingUsage(@NonNull AudioAttributes audioAttributes) {
+            Preconditions.checkNotNull(audioAttributes);
+            Preconditions.checkState(
+                    mUsageMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+            mAudioMixingRuleBuilder
+                    .addRule(audioAttributes, AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+            mUsageMatchType = MATCH_TYPE_INCLUSIVE;
+            return this;
+        }
+
+        /**
+         * Only capture audio output by app with the matching {@code uid}.
+         *
+         * <p>If called multiple times, will capture audio output by apps whose uid is any of the
+         * given uids.
+         *
+         * @throws IllegalStateException if called in conjunction with {@link #excludeUid(int)}.
+         */
+        public Builder addMatchingUid(int uid) {
+            Preconditions.checkState(
+                    mUidMatchType != MATCH_TYPE_EXCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+            mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+            mUidMatchType = MATCH_TYPE_INCLUSIVE;
+            return this;
+        }
+
+        /**
+         * Only capture audio output that does not match the given {@link AudioAttributes}.
+         *
+         * <p>If called multiple times, will capture audio output that does not match any of the
+         * given attributes.
+         *
+         * @throws IllegalStateException if called in conjunction with
+         *     {@link #addMatchingUsage(AudioAttributes)}.
+         */
+        public Builder excludeUsage(@NonNull AudioAttributes audioAttributes) {
+            Preconditions.checkNotNull(audioAttributes);
+            Preconditions.checkState(
+                    mUsageMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+            mAudioMixingRuleBuilder.excludeRule(audioAttributes,
+                    AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
+            mUsageMatchType = MATCH_TYPE_EXCLUSIVE;
+            return this;
+        }
+
+        /**
+         * Only capture audio output by apps that do not have the matching {@code uid}.
+         *
+         * <p>If called multiple times, will capture audio output by apps whose uid is not any of
+         * the given uids.
+         *
+         * @throws IllegalStateException if called in conjunction with {@link #addMatchingUid(int)}.
+         */
+        public Builder excludeUid(int uid) {
+            Preconditions.checkState(
+                    mUidMatchType != MATCH_TYPE_INCLUSIVE, ERROR_MESSAGE_MISMATCHED_RULES);
+            mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_UID, uid);
+            mUidMatchType = MATCH_TYPE_EXCLUSIVE;
+            return this;
+        }
+
+        /**
+         * Builds the configuration instance.
+         *
+         * @throws UnsupportedOperationException if the parameters set are incompatible.
+         */
+        public AudioPlaybackCaptureConfiguration build() {
+            return new AudioPlaybackCaptureConfiguration(mAudioMixingRuleBuilder.build());
+        }
+    }
+}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 24a3a9b..10accf2 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -24,6 +24,8 @@
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.media.audiopolicy.AudioMix;
+import android.media.audiopolicy.AudioPolicy;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -37,6 +39,7 @@
 import android.util.Pair;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
@@ -182,6 +185,8 @@
     //---------------------------------------------------------
     // Member variables
     //--------------------
+    private AudioPolicy mAudioCapturePolicy;
+
     /**
      * The audio data sampling rate in Hz.
      * Never {@link AudioFormat#SAMPLE_RATE_UNSPECIFIED}.
@@ -429,6 +434,16 @@
     }
 
     /**
+     * Sets an {@link AudioPolicy} to automatically unregister when the record is released.
+     *
+     * <p>This is to prevent users of the audio capture API from having to manually unregister the
+     * policy that was used to create the record.
+     */
+    private void unregisterAudioPolicyOnRelease(AudioPolicy audioPolicy) {
+        mAudioCapturePolicy = audioPolicy;
+    }
+
+    /**
      * @hide
      */
     /* package */ void deferred_connect(long  nativeRecordInJavaObj) {
@@ -491,6 +506,11 @@
      * the minimum buffer size for the source is used.
      */
     public static class Builder {
+
+        private static final String ERROR_MESSAGE_SOURCE_MISMATCH =
+                "Cannot both set audio source and set playback capture config";
+
+        private AudioPlaybackCaptureConfiguration mAudioPlaybackCaptureConfiguration;
         private AudioAttributes mAttributes;
         private AudioFormat mFormat;
         private int mBufferSizeInBytes;
@@ -509,6 +529,9 @@
          * @throws IllegalArgumentException
          */
         public Builder setAudioSource(int source) throws IllegalArgumentException {
+            Preconditions.checkState(
+                    mAudioPlaybackCaptureConfiguration == null,
+                    ERROR_MESSAGE_SOURCE_MISMATCH);
             if ( (source < MediaRecorder.AudioSource.DEFAULT) ||
                     (source > MediaRecorder.getAudioSourceMax()) ) {
                 throw new IllegalArgumentException("Invalid audio source " + source);
@@ -578,6 +601,25 @@
         }
 
         /**
+         * Sets the {@link AudioRecord} to record audio played by other apps.
+         *
+         * @param config Defines what apps to record audio from (i.e., via either their uid or
+         *               the type of audio).
+         * @throws IllegalStateException if called in conjunction with {@link #setAudioSource(int)}.
+         * @throws NullPointerException if {@code config} is null.
+         */
+        public Builder setAudioPlaybackCaptureConfig(
+                @NonNull AudioPlaybackCaptureConfiguration config) {
+            Preconditions.checkNotNull(
+                    config, "Illegal null AudioPlaybackCaptureConfiguration argument");
+            Preconditions.checkState(
+                    mAttributes == null,
+                    ERROR_MESSAGE_SOURCE_MISMATCH);
+            mAudioPlaybackCaptureConfiguration = config;
+            return this;
+        }
+
+        /**
          * @hide
          * To be only used by system components.
          * @param sessionId ID of audio session the AudioRecord must be attached to, or
@@ -595,6 +637,15 @@
             return this;
         }
 
+        private AudioRecord buildAudioPlaybackCaptureRecord() {
+            AudioMix audioMix = mAudioPlaybackCaptureConfiguration.createAudioMix(mFormat);
+            AudioPolicy audioPolicy = new AudioPolicy.Builder(/*context=*/ null)
+                    .addMix(audioMix).build();
+            AudioRecord record = audioPolicy.createAudioRecordSink(audioMix);
+            record.unregisterAudioPolicyOnRelease(audioPolicy);
+            return record;
+        }
+
         /**
          * @return a new {@link AudioRecord} instance successfully initialized with all
          *     the parameters set on this <code>Builder</code>.
@@ -603,6 +654,10 @@
          *     or if the device was not available.
          */
         public AudioRecord build() throws UnsupportedOperationException {
+            if (mAudioPlaybackCaptureConfiguration != null) {
+                return buildAudioPlaybackCaptureRecord();
+            }
+
             if (mFormat == null) {
                 mFormat = new AudioFormat.Builder()
                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
@@ -757,6 +812,9 @@
         } catch(IllegalStateException ise) {
             // don't raise an exception, we're releasing the resources.
         }
+        if (mAudioCapturePolicy != null) {
+            AudioManager.unregisterAudioPolicyAsyncStatic(mAudioCapturePolicy);
+        }
         native_release();
         mState = STATE_UNINITIALIZED;
     }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index e8f188c..d22a298 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -109,7 +109,7 @@
     public @interface VideoUnavailableReason {}
 
     static final int VIDEO_UNAVAILABLE_REASON_START = 0;
-    static final int VIDEO_UNAVAILABLE_REASON_END = 4;
+    static final int VIDEO_UNAVAILABLE_REASON_END = 5;
 
     /**
      * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
@@ -140,7 +140,14 @@
      * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
      * the current TV program is audio-only.
      */
-    public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
+    public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 4;
+    /**
+     * Reason for {@link TvInputService.Session#notifyVideoUnavailable(int)} and
+     * {@link TvView.TvInputCallback#onVideoUnavailable(String, int)}: Video is unavailable because
+     * the source is not physically connected, for example the HDMI cable is not connected.
+     * @hide
+     */
+    public static final int VIDEO_UNAVAILABLE_REASON_NOT_CONNECTED = VIDEO_UNAVAILABLE_REASON_END;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
index 8077431..efa4387 100644
--- a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
+++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java
@@ -16,25 +16,21 @@
 
 package com.android.systemui.notifications;
 
+import android.app.ActivityManager;
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.SuppressLint;
-import android.app.ActivityManager;
 import android.car.Car;
 import android.car.CarNotConnectedException;
 import android.car.drivingstate.CarUxRestrictionsManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.GestureDetector;
@@ -95,28 +91,12 @@
     private static int sSettleOpenPercentage;
     private static int sSettleClosePercentage;
 
-    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(Intent.ACTION_USER_SWITCHED)) {
-                mCarNotificationListener.registerAsSystemService(mContext,
-                        mCarUxRestrictionManagerWrapper,
-                        mClickHandlerFactory);
-                inflateNotificationContent();
-            }
-        }
-    };
-
     /**
      * Inits the window that hosts the notifications and establishes the connections
      * to the car related services.
      */
     @Override
     public void start() {
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
-        mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
         sSettleOpenPercentage = mContext.getResources().getInteger(
                 R.integer.notification_settle_open_percentage);
         sSettleClosePercentage = mContext.getResources().getInteger(
@@ -133,11 +113,12 @@
                         ServiceManager.getService(Context.STATUS_BAR_SERVICE)),
                 launchResult -> {
                     if (launchResult == ActivityManager.START_TASK_TO_FRONT
-                            || launchResult == ActivityManager.START_SUCCESS) {
+                            || launchResult == ActivityManager.START_SUCCESS){
                         closeCarNotifications(DEFAULT_FLING_VELOCITY);
                     }
                 });
-
+        mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper,
+                mClickHandlerFactory);
         mCar = Car.createCar(mContext, mCarConnectionListener);
         mCar.connect();
         NotificationGestureListener gestureListener = new NotificationGestureListener();
@@ -150,6 +131,8 @@
         mCarNotificationWindow
                 .setBackgroundColor(mContext.getColor(R.color.notification_shade_background_color));
 
+        inflateNotificationContent();
+
         WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY,
@@ -220,7 +203,7 @@
         // There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN
         // to set the initial click state.
         mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> {
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
@@ -271,7 +254,7 @@
         public boolean onTouch(View v, MotionEvent event) {
             // reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not
             // get the up event
-            if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+            if (event.getActionMasked() == MotionEvent.ACTION_UP ) {
                 mNotificationListAtBottomAtTimeOfTouch = false;
             }
             boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event);
@@ -355,7 +338,7 @@
         public boolean onFling(MotionEvent event1, MotionEvent event2,
                 float velocityX, float velocityY) {
             if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH
-                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
+                    || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){
                 // swipe was not vertical or was not fast enough
                 return false;
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4f18d45..402ce90 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -420,14 +420,20 @@
     private class ClassChangedHandler implements Handler {
         public void onReceive(Context context, Intent intent,
                 BluetoothDevice device) {
-            mDeviceManager.onBtClassChanged(device);
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice != null) {
+                cachedDevice.refresh();
+            }
         }
     }
 
     private class UuidChangedHandler implements Handler {
         public void onReceive(Context context, Intent intent,
                 BluetoothDevice device) {
-            mDeviceManager.onUuidChanged(device);
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice != null) {
+                cachedDevice.onUuidChanged();
+            }
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 5b4a8b4f..33e7540 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -206,20 +206,6 @@
         }
     }
 
-    public synchronized void onBtClassChanged(BluetoothDevice device) {
-        CachedBluetoothDevice cachedDevice = findDevice(device);
-        if (cachedDevice != null) {
-            cachedDevice.dispatchAttributesChanged();
-        }
-    }
-
-    public synchronized void onUuidChanged(BluetoothDevice device) {
-        CachedBluetoothDevice cachedDevice = findDevice(device);
-        if (cachedDevice != null) {
-            cachedDevice.onUuidChanged();
-        }
-    }
-
     public synchronized void onBluetoothStateChanged(int bluetoothState) {
         // When Bluetooth is turning off, we need to clear the non-bonded devices
         // Otherwise, they end up showing up on the next BT enable
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 43b2894..dc47de8 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -369,21 +369,6 @@
     }
 
     /**
-     * Test to verify onBtClassChanged().
-     */
-    @Test
-    public void onBtClassChanged_validBtClass_classChanged() {
-        CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
-        assertThat(cachedDevice1).isNotNull();
-        assertThat(cachedDevice1.getBtClass()).isEqualTo(DEVICE_CLASS_1);
-
-        final BluetoothClass newBluetoothClass = DEVICE_CLASS_2;
-        when(mDevice1.getBluetoothClass()).thenReturn(newBluetoothClass);
-        mCachedDeviceManager.onBtClassChanged(mDevice1);
-        assertThat(cachedDevice1.getBtClass()).isEqualTo(newBluetoothClass);
-    }
-
-    /**
      * Test to verify onDeviceDisappeared().
      */
     @Test
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
index 804f4f1..6567b6a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
@@ -24,6 +24,7 @@
 import android.view.InputChannel;
 import android.view.InputEvent;
 import android.view.InputEventSender;
+import android.view.MotionEvent;
 
 /**
  * @see android.view.InputChannel
@@ -64,6 +65,19 @@
     }
 
     /**
+     * Version of addBatch method which preserves time accuracy in nanoseconds instead of
+     * converting the time to milliseconds.
+     * @param src old MotionEvent where the target should be appended
+     * @param target new MotionEvent which should be added to the src
+     * @return true if the merge was successful
+     *
+     * @see MotionEvent#addBatch(MotionEvent)
+     */
+    public static boolean mergeMotionEvent(MotionEvent src, MotionEvent target) {
+        return target.addBatch(src);
+    }
+
+    /**
      * @see BatchedInputEventReceiver
      */
     public static class InputEventReceiver {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
index e6acfbe..39da194 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java
@@ -51,7 +51,7 @@
      *               this method to avoid synchronization issues.
      */
     public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) {
-        if (mTargetViewRootImpl == null) {
+        if (mTargetViewRootImpl == null || mTargetViewRootImpl.getView() == null) {
             return;
         }
         mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index f9aa8da..3d2f61e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.shared.system;
 
-import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
 import android.os.UserHandle;
 import android.util.Log;
@@ -43,10 +43,20 @@
     public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
     public void onActivityDismissingDockedStack() { }
     public void onActivityLaunchOnSecondaryDisplayFailed() { }
+
+    public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+        onActivityLaunchOnSecondaryDisplayFailed();
+    }
+
     public void onTaskProfileLocked(int taskId, int userId) { }
     public void onTaskCreated(int taskId, ComponentName componentName) { }
     public void onTaskRemoved(int taskId) { }
     public void onTaskMovedToFront(int taskId) { }
+
+    public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+        onTaskMovedToFront(taskInfo.taskId);
+    }
+
     public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) { }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 628b3c6..a9ac42f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -16,8 +16,9 @@
 
 package com.android.systemui.shared.system;
 
-import android.app.ActivityTaskManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityTaskManager;
 import android.app.IActivityManager;
 import android.app.TaskStackListener;
 import android.content.ComponentName;
@@ -132,8 +133,11 @@
     }
 
     @Override
-    public void onActivityLaunchOnSecondaryDisplayFailed() throws RemoteException {
-        mHandler.sendEmptyMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED);
+    public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
+            int requestedDisplayId) throws RemoteException {
+        mHandler.obtainMessage(H.ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED, requestedDisplayId,
+                0 /* unused */,
+                taskInfo).sendToTarget();
     }
 
     @Override
@@ -157,8 +161,9 @@
     }
 
     @Override
-    public void onTaskMovedToFront(int taskId) throws RemoteException {
-        mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskId, 0).sendToTarget();
+    public void onTaskMovedToFront(RunningTaskInfo taskInfo)
+            throws RemoteException {
+        mHandler.obtainMessage(H.ON_TASK_MOVED_TO_FRONT, taskInfo).sendToTarget();
     }
 
     @Override
@@ -258,8 +263,10 @@
                         break;
                     }
                     case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+                        final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
+                            mTaskStackListeners.get(i)
+                                    .onActivityLaunchOnSecondaryDisplayFailed(info);
                         }
                         break;
                     }
@@ -283,15 +290,16 @@
                         break;
                     }
                     case ON_TASK_MOVED_TO_FRONT: {
+                        final RunningTaskInfo info = (RunningTaskInfo) msg.obj;
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onTaskMovedToFront(msg.arg1);
+                            mTaskStackListeners.get(i).onTaskMovedToFront(info);
                         }
                         break;
                     }
                     case ON_ACTIVITY_REQUESTED_ORIENTATION_CHANGE: {
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityRequestedOrientationChanged(
-                                    msg.arg1, msg.arg2);
+                            mTaskStackListeners.get(i)
+                                    .onActivityRequestedOrientationChanged(msg.arg1, msg.arg2);
                         }
                         break;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 0832296..505fbae 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -25,6 +25,7 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.INotificationManager;
@@ -491,15 +492,8 @@
         }
 
         @Override
-        public void onTaskMovedToFront(int taskId) {
-            ActivityManager.StackInfo stackInfo = null;
-            try {
-                stackInfo = findStackInfo(taskId);
-            } catch (RemoteException e) {
-                e.rethrowAsRuntimeException();
-            }
-            if (stackInfo != null && stackInfo.displayId == Display.DEFAULT_DISPLAY
-                    && mStackView != null) {
+        public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+            if (mStackView != null && taskInfo.displayId == Display.DEFAULT_DISPLAY) {
                 mStackView.collapseStack();
             }
         }
@@ -510,9 +504,9 @@
          * ultimately ended up, displays an error message toast, and calls this method instead of
          * onTaskMovedToFront.
          */
-        // TODO(b/124058588): add requestedDisplayId to this callback, ignore unless matches
         @Override
-        public void onActivityLaunchOnSecondaryDisplayFailed() {
+        public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo) {
+            // TODO(b/124058588): move to ActivityView.StateCallback, filter on virtualDisplay ID
             if (mStackView != null) {
                 mStackView.collapseStack();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index c2327ad..80b5f33 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -321,6 +321,8 @@
             mPermissionView.setVisibility(VISIBLE);
             ((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon);
             ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
+            logBubbleClickEvent(mEntry.notification,
+                    StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 5546e4c..42e3b2812 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -786,7 +786,10 @@
      * @return the index of the bubble view within the bubble stack. The range of the position
      * is between 0 and the bubble count minus 1.
      */
-    int getBubbleIndex(Bubble bubble) {
+    int getBubbleIndex(@Nullable Bubble bubble) {
+        if (bubble == null) {
+            return 0;
+        }
         return mBubbleContainer.indexOfChild(bubble.iconView);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 152b9fc..4d89a39 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -43,6 +43,8 @@
 
     static final String TAG = "DozeMachine";
     static final boolean DEBUG = DozeService.DEBUG;
+    private static final String REASON_CHANGE_STATE = "DozeMachine#requestState";
+    private static final String REASON_HELD_FOR_STATE = "DozeMachine#heldForState";
 
     public enum State {
         /** Default state. Transition to INITIALIZED to get Doze going. */
@@ -167,14 +169,14 @@
         boolean runNow = !isExecutingTransition();
         mQueuedRequests.add(requestedState);
         if (runNow) {
-            mWakeLock.acquire();
+            mWakeLock.acquire(REASON_CHANGE_STATE);
             for (int i = 0; i < mQueuedRequests.size(); i++) {
                 // Transitions in Parts can call back into requestState, which will
                 // cause mQueuedRequests to grow.
                 transitionTo(mQueuedRequests.get(i), pulseReason);
             }
             mQueuedRequests.clear();
-            mWakeLock.release();
+            mWakeLock.release(REASON_CHANGE_STATE);
         }
     }
 
@@ -311,10 +313,10 @@
     private void updateWakeLockState(State newState) {
         boolean staysAwake = newState.staysAwake();
         if (mWakeLockHeldForCurrentState && !staysAwake) {
-            mWakeLock.release();
+            mWakeLock.release(REASON_HELD_FOR_STATE);
             mWakeLockHeldForCurrentState = false;
         } else if (!mWakeLockHeldForCurrentState && staysAwake) {
-            mWakeLock.acquire();
+            mWakeLock.acquire(REASON_HELD_FOR_STATE);
             mWakeLockHeldForCurrentState = true;
         }
     }
@@ -336,6 +338,7 @@
     public void dump(PrintWriter pw) {
         pw.print(" state="); pw.println(mState);
         pw.print(" wakeLockHeldForCurrentState="); pw.println(mWakeLockHeldForCurrentState);
+        pw.print(" wakeLock="); pw.println(mWakeLock);
         pw.println("Parts:");
         for (Part p : mParts) {
             p.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index f14d396..368451a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -57,7 +57,7 @@
         mDozeService = service;
         mHandler = handler;
         mParameters = parameters;
-        mWakeLock = new SettableWakeLock(wakeLock);
+        mWakeLock = new SettableWakeLock(wakeLock, TAG);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index e207cb1..70bf903 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -348,7 +348,7 @@
             mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL, 0,
                     mHandler);
             mHandler.postDelayed(this, TIMEOUT_DELAY_MS);
-            mWakeLock.acquire();
+            mWakeLock.acquire(TAG);
             mRegistered = true;
         }
 
@@ -383,7 +383,7 @@
             }
             onProximityResult(result);
             if (wasRegistered) {
-                mWakeLock.release();
+                mWakeLock.release(TAG);
             }
             mFinished = true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 85d975f..b03b872 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -419,17 +419,16 @@
         return KeyguardUpdateMonitor.getInstance(getContext());
     }
 
+    /**
+     * Called whenever new media metadata is available.
+     * @param metadata New metadata.
+     */
     @Override
     public void onMetadataChanged(MediaMetadata metadata) {
-        final boolean notify;
         synchronized (this) {
-            boolean neededMedia = needsMediaLocked();
             mMediaMetaData = metadata;
-            notify = neededMedia != needsMediaLocked();
         }
-        if (notify) {
-            notifyChange();
-        }
+        notifyChange();
     }
 
     protected void notifyChange() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 164f582..a9fe3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -130,7 +130,7 @@
                 mTextView.getTextColors() : ColorStateList.valueOf(Color.WHITE);
         mDisclosure = indicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure);
         mLockIcon = lockIcon;
-        mWakeLock = new SettableWakeLock(wakeLock);
+        mWakeLock = new SettableWakeLock(wakeLock, TAG);
 
         Resources res = context.getResources();
         mSlowThreshold = res.getInteger(R.integer.config_chargingSlowlyThreshold);
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 ee1e3c0..7bbd3b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -340,7 +340,7 @@
         if (!mWakeLockHeld) {
             if (mWakeLock != null) {
                 mWakeLockHeld = true;
-                mWakeLock.acquire();
+                mWakeLock.acquire(TAG);
             } else {
                 Log.w(TAG, "Cannot hold wake lock, it has not been set yet");
             }
@@ -654,7 +654,7 @@
 
     private void onFinished(Callback callback) {
         if (mWakeLockHeld) {
-            mWakeLock.release();
+            mWakeLock.release(TAG);
             mWakeLockHeld = false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
index b835909..7991e38 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/DelayedWakeLock.java
@@ -23,30 +23,34 @@
  */
 public class DelayedWakeLock implements WakeLock {
 
+    private static final String TO_STRING_PREFIX = "[DelayedWakeLock] ";
     private static final long RELEASE_DELAY_MS = 100;
 
     private final Handler mHandler;
     private final WakeLock mInner;
-    private final Runnable mRelease;
 
     public DelayedWakeLock(Handler h, WakeLock inner) {
         mHandler = h;
         mInner = inner;
-        mRelease = mInner::release;
     }
 
     @Override
-    public void acquire() {
-        mInner.acquire();
+    public void acquire(String why) {
+        mInner.acquire(why);
     }
 
     @Override
-    public void release() {
-        mHandler.postDelayed(mRelease, RELEASE_DELAY_MS);
+    public void release(String why) {
+        mHandler.postDelayed(() -> mInner.release(why), RELEASE_DELAY_MS);
     }
 
     @Override
     public Runnable wrap(Runnable r) {
         return WakeLock.wrapImpl(this, r);
     }
+
+    @Override
+    public String toString() {
+        return TO_STRING_PREFIX + mInner;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
index a54b0e1..283be86 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListener.java
@@ -26,6 +26,7 @@
 
 public class KeepAwakeAnimationListener extends AnimatorListenerAdapter
         implements Animation.AnimationListener {
+    private static final String TAG = "KeepAwakeAnimListener";
     @VisibleForTesting
     static WakeLock sWakeLock;
 
@@ -63,11 +64,11 @@
 
     private void onStart() {
         Assert.isMainThread();
-        sWakeLock.acquire();
+        sWakeLock.acquire(TAG);
     }
 
     private void onEnd() {
         Assert.isMainThread();
-        sWakeLock.release();
+        sWakeLock.release(TAG);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
index 13729df..a797287 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/SettableWakeLock.java
@@ -21,13 +21,15 @@
 public class SettableWakeLock {
 
     private final WakeLock mInner;
+    private final String mWhy;
 
     private boolean mAcquired;
 
-    public SettableWakeLock(WakeLock inner) {
+    public SettableWakeLock(WakeLock inner, String why) {
         Preconditions.checkNotNull(inner, "inner wakelock required");
 
         mInner = inner;
+        mWhy = why;
     }
 
     public synchronized boolean isAcquired() {
@@ -37,9 +39,9 @@
     public synchronized void setAcquired(boolean acquired) {
         if (mAcquired != acquired) {
             if (acquired) {
-                mInner.acquire();
+                mInner.acquire(mWhy);
             } else {
-                mInner.release();
+                mInner.release(mWhy);
             }
             mAcquired = acquired;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
index b0f1b54..bebc20b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
+++ b/packages/SystemUI/src/com/android/systemui/util/wakelock/WakeLock.java
@@ -18,17 +18,29 @@
 
 import android.content.Context;
 import android.os.PowerManager;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
+import java.util.HashMap;
+
 /** WakeLock wrapper for testability */
 public interface WakeLock {
 
-    /** @see android.os.PowerManager.WakeLock#acquire() */
-    void acquire();
+    static final String TAG = "WakeLock";
+    static final String REASON_WRAP = "wrap";
 
-    /** @see android.os.PowerManager.WakeLock#release() */
-    void release();
+    /**
+     * @param why A tag that will be saved for sysui dumps.
+     * @see android.os.PowerManager.WakeLock#acquire()
+     **/
+    void acquire(String why);
+
+    /**
+     * @param why Same tag used in {@link #acquire(String)}
+     * @see android.os.PowerManager.WakeLock#release()
+     **/
+    void release(String why);
 
     /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
     Runnable wrap(Runnable r);
@@ -44,25 +56,38 @@
     }
 
     static Runnable wrapImpl(WakeLock w, Runnable r) {
-        w.acquire();
+        w.acquire(REASON_WRAP);
         return () -> {
             try {
                 r.run();
             } finally {
-                w.release();
+                w.release(REASON_WRAP);
             }
         };
     }
 
     static WakeLock wrap(final PowerManager.WakeLock inner) {
         return new WakeLock() {
+            private final HashMap<String, Integer> mActiveClients = new HashMap<>();
+
             /** @see PowerManager.WakeLock#acquire() */
-            public void acquire() {
+            public void acquire(String why) {
+                mActiveClients.putIfAbsent(why, 0);
+                mActiveClients.put(why, mActiveClients.get(why) + 1);
                 inner.acquire();
             }
 
             /** @see PowerManager.WakeLock#release() */
-            public void release() {
+            public void release(String why) {
+                Integer count = mActiveClients.get(why);
+                if (count == null) {
+                    Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
+                            new Throwable());
+                } else if (count == 1) {
+                    mActiveClients.remove(why);
+                } else {
+                    mActiveClients.put(why, count - 1);
+                }
                 inner.release();
             }
 
@@ -70,6 +95,11 @@
             public Runnable wrap(Runnable runnable) {
                 return wrapImpl(this, runnable);
             }
+
+            @Override
+            public String toString() {
+                return "active clients= " + mActiveClients.toString();
+            }
         };
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 01d7b8b..e1717be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -166,25 +166,22 @@
 
     @Test
     public void onMetadataChanged_updatesSlice() {
-        mProvider.onMetadataChanged(mock(MediaMetadata.class));
         mProvider.onDozingChanged(true);
+        reset(mContentResolver);
+        mProvider.onMetadataChanged(mock(MediaMetadata.class));
         verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
 
         // Hides after waking up
         reset(mContentResolver);
         mProvider.onDozingChanged(false);
         verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
-
-        // And won't update slice if device is awake
-        reset(mContentResolver);
-        mProvider.onMetadataChanged(mock(MediaMetadata.class));
-        verify(mContentResolver, never()).notifyChange(eq(mProvider.getUri()), eq(null));
     }
 
     @Test
     public void onDozingChanged_updatesSliceIfMedia() {
-        // Show media when dozing
         mProvider.onMetadataChanged(mock(MediaMetadata.class));
+        reset(mContentResolver);
+        // Show media when dozing
         mProvider.onDozingChanged(true);
         verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index c20d37f..e4da859 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -441,10 +442,10 @@
     @Test
     public void testHoldsWakeLock_whenAOD() {
         mScrimController.transitionTo(ScrimState.AOD);
-        verify(mWakeLock).acquire();
-        verify(mWakeLock, never()).release();
+        verify(mWakeLock).acquire(anyString());
+        verify(mWakeLock, never()).release(anyString());
         mScrimController.finishAnimationsImmediately();
-        verify(mWakeLock).release();
+        verify(mWakeLock).release(anyString());
     }
 
     @Test
@@ -471,10 +472,10 @@
         reset(mWakeLock);
 
         mScrimController.onHideWallpaperTimeout();
-        verify(mWakeLock).acquire();
-        verify(mWakeLock, never()).release();
+        verify(mWakeLock).acquire(anyString());
+        verify(mWakeLock, never()).release(anyString());
         mScrimController.finishAnimationsImmediately();
-        verify(mWakeLock).release();
+        verify(mWakeLock).release(anyString());
     }
 
     @Test
@@ -486,10 +487,10 @@
         reset(mWakeLock);
 
         mScrimController.onHideWallpaperTimeout();
-        verify(mWakeLock).acquire();
-        verify(mWakeLock, never()).release();
+        verify(mWakeLock).acquire(anyString());
+        verify(mWakeLock, never()).release(anyString());
         mScrimController.finishAnimationsImmediately();
-        verify(mWakeLock).release();
+        verify(mWakeLock).release(anyString());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
index ab9b0c9..0792a05 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/KeepAwakeAnimationListenerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.util.wakelock;
 
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
@@ -52,11 +53,11 @@
     @Test
     public void onAnimationStart_holdsWakeLock() {
         mKeepAwakeAnimationListener.onAnimationStart((Animator) null);
-        verify(mWakeLock).acquire();
-        verify(mWakeLock, never()).release();
+        verify(mWakeLock).acquire(anyString());
+        verify(mWakeLock, never()).release(anyString());
 
         mKeepAwakeAnimationListener.onAnimationEnd((Animator) null);
-        verify(mWakeLock).release();
+        verify(mWakeLock).release(anyString());
     }
 
     @Test(expected = IllegalStateException.class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
index 39316ed..f739fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/SettableWakeLockTest.java
@@ -40,7 +40,7 @@
     @Before
     public void setup() {
         mFake = new WakeLockFake();
-        mSettable = new SettableWakeLock(mFake);
+        mSettable = new SettableWakeLock(mFake, "Fake");
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
index 4cefb99..ef20df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockFake.java
@@ -23,24 +23,24 @@
     private int mAcquired = 0;
 
     @Override
-    public void acquire() {
+    public void acquire(String why) {
         mAcquired++;
     }
 
     @Override
-    public void release() {
+    public void release(String why) {
         Preconditions.checkState(mAcquired > 0);
         mAcquired--;
     }
 
     @Override
     public Runnable wrap(Runnable runnable) {
-        acquire();
+        acquire(WakeLockFake.class.getSimpleName());
         return () -> {
             try {
                 runnable.run();
             } finally {
-                release();
+                release(WakeLockFake.class.getSimpleName());
             }
         };
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
index d925364..4425def 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/wakelock/WakeLockTest.java
@@ -19,9 +19,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import android.content.Context;
 import android.os.PowerManager;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -36,6 +34,7 @@
 @RunWith(AndroidJUnit4.class)
 public class WakeLockTest extends SysuiTestCase {
 
+    private static final String WHY = "test";
     WakeLock mWakeLock;
     PowerManager.WakeLock mInner;
 
@@ -58,22 +57,22 @@
 
     @Test
     public void wakeLock_acquire() {
-        mWakeLock.acquire();
+        mWakeLock.acquire(WHY);
         assertTrue(mInner.isHeld());
     }
 
     @Test
     public void wakeLock_release() {
-        mWakeLock.acquire();
-        mWakeLock.release();
+        mWakeLock.acquire(WHY);
+        mWakeLock.release(WHY);
         assertFalse(mInner.isHeld());
     }
 
     @Test
     public void wakeLock_refCounted() {
-        mWakeLock.acquire();
-        mWakeLock.acquire();
-        mWakeLock.release();
+        mWakeLock.acquire(WHY);
+        mWakeLock.acquire(WHY);
+        mWakeLock.release(WHY);
         assertTrue(mInner.isHeld());
     }
 
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index d9adec8..530d115 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6992,6 +6992,16 @@
     // OS: Q
     ACTION_PANEL_INTERACTION = 1658;
 
+    // ACTION: Change phone orientation
+    // OS: Q
+    // SUBTYPE is orientation defined in Configuration.class
+    ACTION_PHONE_ORIENTATION_CHANGED = 1659;
+
+    // CATEGORY: ACTION_PHONE_ORIENTATION_CHANGED
+    // OS: Q
+    // Different display can have different orientations, so need to log display id
+    FIELD_DISPLAY_ID = 1660;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 4a3f126..e0fb337 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -1026,6 +1026,29 @@
         }
 
         @Override
+        public void setAugmentedAutofillWhitelist(@Nullable List<String> packages,
+                @Nullable List<ComponentName> activities, @NonNull IResultReceiver receiver)
+                throws RemoteException {
+            final int userId = UserHandle.getCallingUserId();
+
+            boolean ok;
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    ok = service.setAugmentedAutofillWhitelistLocked(packages, activities,
+                            getCallingUid());
+                } else {
+                    if (sVerbose) {
+                        Slog.v(TAG, "setAugmentedAutofillWhitelist(): no service for " + userId);
+                    }
+                    ok = false;
+                }
+            }
+            send(receiver,
+                    ok ? AutofillManager.RESULT_OK : AutofillManager.RESULT_CODE_NOT_SERVICE);
+        }
+
+        @Override
         public void getAvailableFieldClassificationAlgorithms(@NonNull IResultReceiver receiver)
                 throws RemoteException {
             final int userId = UserHandle.getCallingUserId();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 1bce11ee..15dce4a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -40,6 +40,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -58,6 +59,7 @@
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.LocalLog;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -165,6 +167,16 @@
     @Nullable
     private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
 
+    @GuardedBy("mLock")
+    @Nullable
+    private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
+
+    /**
+     * List of packages that are whitelisted to be trigger augmented autofill.
+     */
+    @GuardedBy("mLock")
+    private final ArraySet<String> mWhitelistedAugmentAutofillPackages = new ArraySet<>();
+
     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
             AutofillCompatState autofillCompatState,
@@ -844,10 +856,11 @@
     }
 
     @GuardedBy("mLock")
-    private boolean isCalledByServiceLocked(String methodName, int callingUid) {
-        if (getServiceUidLocked() != callingUid) {
+    private boolean isCalledByServiceLocked(@NonNull String methodName, int callingUid) {
+        final int serviceUid = getServiceUidLocked();
+        if (serviceUid != callingUid) {
             Slog.w(TAG, methodName + "() called by UID " + callingUid
-                    + ", but service UID is " + getServiceUidLocked());
+                    + ", but service UID is " + serviceUid);
             return false;
         }
         return true;
@@ -886,6 +899,19 @@
             pw.print(prefix); pw.println("RemoteAugmentedAutofillService: ");
             mRemoteAugmentedAutofillService.dump(prefix2, pw);
         }
+        if (mRemoteAugmentedAutofillServiceInfo != null) {
+            pw.print(prefix); pw.print("RemoteAugmentedAutofillServiceInfo: ");
+            pw.println(mRemoteAugmentedAutofillServiceInfo);
+        }
+
+        final int whitelistSize = mWhitelistedAugmentAutofillPackages.size();
+        pw.print(prefix); pw.print("Packages whitelisted for augmented autofill: ");
+        pw.println(whitelistSize);
+        for (int i = 0; i < whitelistSize; i++) {
+            final String whitelistedPkg = mWhitelistedAugmentAutofillPackages.valueAt(i);
+            pw.print(prefix2); pw.print(i + 1); pw.print(": "); pw.println(whitelistedPkg);
+        }
+
         pw.print(prefix); pw.print("Field classification enabled: ");
             pw.println(isFieldClassificationEnabledLocked());
         pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1037,9 +1063,13 @@
                 }
                 return null;
             }
-            final ComponentName componentName = RemoteAugmentedAutofillService.getComponentName(
-                    serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
-            if (componentName == null) return null;
+            final Pair<ServiceInfo, ComponentName> pair = RemoteAugmentedAutofillService
+                    .getComponentName(
+                            serviceName, mUserId, mAugmentedAutofillResolver.isTemporary(mUserId));
+            if (pair == null) return null;
+
+            mRemoteAugmentedAutofillServiceInfo = pair.first;
+            final ComponentName componentName = pair.second;
             if (sVerbose) {
                 Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
             }
@@ -1067,13 +1097,92 @@
     private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
         if (serviceName == null) {
             if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): time's up!");
-            if (mRemoteAugmentedAutofillService != null) {
-                mRemoteAugmentedAutofillService.destroy();
-                mRemoteAugmentedAutofillService = null;
+            synchronized (mLock) {
+                if (mRemoteAugmentedAutofillService != null) {
+                    mRemoteAugmentedAutofillService.destroy();
+                    mRemoteAugmentedAutofillService = null;
+                }
             }
         }
     }
 
+    /**
+     * Sets which packages and activities can trigger augmented autofill.
+     *
+     * @return whether caller UID is the augmented autofill service for the user
+     */
+    boolean setAugmentedAutofillWhitelistLocked(List<String> packages,
+            List<ComponentName> activities, int callingUid) {
+
+        if (!isCalledByAugmentedAutofillServiceLocked("setAugmentedAutofillWhitelistLocked",
+                callingUid)) {
+            return false;
+        }
+        if (mMaster.verbose) {
+            Slog.v(TAG, "setAugmentedAutofillWhitelistLocked(packages=" + packages + ", activities="
+                    + activities + ")");
+        }
+        whitelistForAugmentedAutofillPackages(packages);
+
+        // TODO(b/123100824): whitelist activities as well
+        // TODO(b/122858578): log metrics
+        return true;
+    }
+
+    @GuardedBy("mLock")
+    private boolean isCalledByAugmentedAutofillServiceLocked(@NonNull String methodName,
+            int callingUid) {
+        // Lazy load service first
+        final RemoteAugmentedAutofillService service = getRemoteAugmentedAutofillServiceLocked();
+        if (service == null) {
+            Slog.w(TAG, methodName + "() called by UID " + callingUid
+                    + ", but there is no augmented autofill service defined for user "
+                    + getUserId());
+            return false;
+        }
+
+        if (getAugmentedAutofillServiceUidLocked() != callingUid) {
+            Slog.w(TAG, methodName + "() called by UID " + callingUid
+                    + ", but service UID is " + getAugmentedAutofillServiceUidLocked()
+                    + " for user " + getUserId());
+            return false;
+        }
+        return true;
+    }
+
+    @GuardedBy("mLock")
+    private int getAugmentedAutofillServiceUidLocked() {
+        if (mRemoteAugmentedAutofillServiceInfo == null) {
+            if (mMaster.verbose) {
+                Slog.v(TAG, "getAugmentedAutofillServiceUid(): "
+                        + "no mRemoteAugmentedAutofillServiceInfo");
+            }
+            return Process.INVALID_UID;
+        }
+        return mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid;
+    }
+
+    @GuardedBy("mLock")
+    boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
+        // TODO(b/122595322): need to check whitelisted activities as well.
+        final String packageName = componentName.getPackageName();
+        return mWhitelistedAugmentAutofillPackages.contains(packageName);
+    }
+
+    private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
+        // TODO(b/123100824): add CTS test for when it's null
+        synchronized (mLock) {
+            if (packages == null) {
+                if (mMaster.verbose) Slog.v(TAG, "clearing all whitelisted augmented packages");
+                mWhitelistedAugmentAutofillPackages.clear();
+            } else {
+                if (mMaster.verbose) Slog.v(TAG, "whitelisting augmented packages: " + packages);
+                mWhitelistedAugmentAutofillPackages.addAll(packages);
+            }
+            mRemoteAugmentedAutofillService = getRemoteAugmentedAutofillServiceLocked();
+        }
+    }
+
     private void sendStateToClients(boolean resetClient) {
         final RemoteCallbackList<IAutoFillManagerClient> clients;
         final int userClientCount;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 61f63d3..88228fb 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -32,6 +32,7 @@
 import android.service.autofill.augmented.IAugmentedAutofillService;
 import android.service.autofill.augmented.IFillCallback;
 import android.text.format.DateUtils;
+import android.util.Pair;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
@@ -54,10 +55,13 @@
             boolean bindInstantServiceAllowed, boolean verbose) {
         super(context, AugmentedAutofillService.SERVICE_INTERFACE, serviceName, userId, callbacks,
                 bindInstantServiceAllowed, verbose);
+
+        // Bind right away.
+        scheduleBind();
     }
 
     @Nullable
-    public static ComponentName getComponentName(@NonNull String componentName,
+    static Pair<ServiceInfo, ComponentName> getComponentName(@NonNull String componentName,
             @UserIdInt int userId, boolean isTemporary) {
         int flags = PackageManager.GET_META_DATA;
         if (!isTemporary) {
@@ -78,7 +82,23 @@
             Slog.e(TAG, "Error getting service info for '" + componentName + "': " + e);
             return null;
         }
-        return serviceComponent;
+        return new Pair<>(serviceInfo, serviceComponent);
+    }
+
+    @Override // from RemoteService
+    protected void handleOnConnectedStateChanged(boolean state) {
+        if (state && getTimeoutIdleBindMillis() != PERMANENT_BOUND_TIMEOUT_MS) {
+            scheduleUnbind();
+        }
+        try {
+            if (state) {
+                mService.onConnected();
+            } else {
+                mService.onDisconnected();
+            }
+        } catch (Exception e) {
+            Slog.w(mTag, "Exception calling onConnectedStateChanged(" + state + "): " + e);
+        }
     }
 
     @Override // from AbstractRemoteService
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 04fc258..848f249 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2613,13 +2613,25 @@
                     + " when server returned null for session " + this.id);
         }
 
+        final boolean isWhitelisted = mService
+                .isWhitelistedForAugmentedAutofillLocked(mComponentName);
+
         final String historyItem =
                 "aug:id=" + id + " u=" + uid + " m=" + mode
                 + " a=" + ComponentName.flattenToShortString(mComponentName)
                 + " f=" + mCurrentViewId
-                + " s=" + remoteService.getComponentName();
+                + " s=" + remoteService.getComponentName()
+                + " w=" + isWhitelisted;
         mService.getMaster().logRequestLocked(historyItem);
 
+        if (!isWhitelisted) {
+            if (sVerbose) {
+                Slog.v(TAG, mComponentName.toShortString() + " is not whitelisted for "
+                        + "augmented autofill");
+            }
+            return null;
+        }
+
         final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
 
         // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 45ceeda..d5713a1 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -25,6 +25,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityThread;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.ActivityPresentationInfo;
@@ -101,6 +102,13 @@
     @Nullable
     private boolean mDisabledByDeviceConfig;
 
+    // Device-config settings that are cached and passed back to apps
+    public int mDevCfgLoggingLevel;
+    public int mDevCfgMaxBufferSize;
+    public int mDevCfgIdleFlushingFrequencyMs;
+    public int mDevCfgTextChangeFlushingFrequencyMs;
+    public int mDevCfgLogHistorySize;
+
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
@@ -108,16 +116,15 @@
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
                 (namespace, key, value) -> onDeviceConfigChange(key, value));
-        setLoggingLevelFromDeviceConfig();
-        setDisabledFromDeviceConfig();
+        setDeviceConfigProperties();
 
-        final int loggingSize = ContentCaptureHelper.getIntDeviceConfigProperty(
-                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
-        if (loggingSize > 0) {
-            if (debug) Slog.d(mTag, "log history size: " + loggingSize);
-            mRequestsHistory = new LocalLog(loggingSize);
+        if (mDevCfgLogHistorySize > 0) {
+            if (debug) Slog.d(mTag, "log history size: " + mDevCfgLogHistorySize);
+            mRequestsHistory = new LocalLog(mDevCfgLogHistorySize);
         } else {
-            if (debug) Slog.d(mTag, "disabled log history because size is " + loggingSize);
+            if (debug) {
+                Slog.d(mTag, "disabled log history because size is " + mDevCfgLogHistorySize);
+            }
             mRequestsHistory = null;
         }
 
@@ -231,34 +238,64 @@
             case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY:
             case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE:
             case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY:
-                // TODO(b/123096662): implement it
-                Slog.d(mTag, "changes on " + key + " not supported yet");
+                setFineTuneParamsFromDeviceConfig();
                 return;
             default:
                 Slog.i(mTag, "Ignoring change on " + key);
         }
     }
 
+    private void setFineTuneParamsFromDeviceConfig() {
+        mDevCfgMaxBufferSize = ContentCaptureHelper.getIntDeviceConfigProperty(
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_MAX_BUFFER_SIZE,
+                ContentCaptureManager.DEFAULT_MAX_BUFFER_SIZE);
+        mDevCfgIdleFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_FLUSH_FREQUENCY,
+                ContentCaptureManager.DEFAULT_IDLE_FLUSHING_FREQUENCY_MS);
+        mDevCfgTextChangeFlushingFrequencyMs = ContentCaptureHelper.getIntDeviceConfigProperty(
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_TEXT_CHANGE_FLUSH_FREQUENCY,
+                ContentCaptureManager.DEFAULT_TEXT_CHANGE_FLUSHING_FREQUENCY_MS);
+        mDevCfgLogHistorySize = ContentCaptureHelper.getIntDeviceConfigProperty(
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOG_HISTORY_SIZE, 20);
+        if (verbose) {
+            Slog.v(mTag, "setFineTuneParamsFromDeviceConfig(): bufferSize=" + mDevCfgMaxBufferSize
+                    + ", idleFlush=" + mDevCfgIdleFlushingFrequencyMs
+                    + ", textFluxh=" + mDevCfgTextChangeFlushingFrequencyMs
+                    + ", logHistory=" + mDevCfgLogHistorySize);
+        }
+    }
+
     private void setLoggingLevelFromDeviceConfig() {
-        ContentCaptureHelper.setLoggingLevel();
+        mDevCfgLoggingLevel = ContentCaptureHelper.getIntDeviceConfigProperty(
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_LOGGING_LEVEL,
+                ContentCaptureHelper.getDefaultLoggingLevel());
+        ContentCaptureHelper.setLoggingLevel(mDevCfgLoggingLevel);
         verbose = ContentCaptureHelper.sVerbose;
         debug = ContentCaptureHelper.sDebug;
+        if (verbose) {
+            Slog.v(mTag, "setLoggingLevelFromDeviceConfig(): level=" + mDevCfgLoggingLevel
+                    + ", debug=" + debug + ", verbose=" + verbose);
+        }
     }
 
-    private void setDisabledFromDeviceConfig() {
-        final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+    private void setDeviceConfigProperties() {
+        setLoggingLevelFromDeviceConfig();
+        setFineTuneParamsFromDeviceConfig();
+        final String enabled = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
-        setDisabledByDeviceConfig(value);
+        setDisabledByDeviceConfig(enabled);
     }
 
-    private void setDisabledByDeviceConfig(@Nullable String value) {
-        if (verbose) Slog.v(mTag, "setDisabledByDeviceConfig(): value=" + value);
+    private void setDisabledByDeviceConfig(@Nullable String explicitlyEnabled) {
+        if (verbose) {
+            Slog.v(mTag, "setDisabledByDeviceConfig(): explicitlyEnabled=" + explicitlyEnabled);
+        }
         final UserManager um = getContext().getSystemService(UserManager.class);
         final List<UserInfo> users = um.getUsers();
 
         final boolean newDisabledValue;
 
-        if (value != null && value.equalsIgnoreCase("false")) {
+        if (explicitlyEnabled != null && explicitlyEnabled.equalsIgnoreCase("false")) {
             newDisabledValue = true;
         } else {
             newDisabledValue = false;
@@ -423,9 +460,18 @@
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
 
+        final String prefix2 = prefix + "  ";
+
         pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
-        pw.print(prefix); pw.print("Disabled by DeviceConfig: ");
-        pw.println(mDisabledByDeviceConfig);
+        pw.print(prefix); pw.println("DeviceConfig Settings: ");
+        pw.print(prefix2); pw.print("disabled: "); pw.println(mDisabledByDeviceConfig);
+        pw.print(prefix2); pw.print("loggingLevel: "); pw.println(mDevCfgLoggingLevel);
+        pw.print(prefix2); pw.print("maxBufferSize: "); pw.println(mDevCfgMaxBufferSize);
+        pw.print(prefix2); pw.print("idleFlushingFrequencyMs: ");
+        pw.println(mDevCfgIdleFlushingFrequencyMs);
+        pw.print(prefix2); pw.print("textChangeFlushingFrequencyMs: ");
+        pw.println(mDevCfgTextChangeFlushingFrequencyMs);
+        pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@@ -534,6 +580,8 @@
                 pw.println();
                 mRequestsHistory.reverseDump(fd, pw, args);
                 pw.println();
+            } else {
+                pw.println();
             }
         }
 
@@ -570,5 +618,16 @@
             }
             return false;
         }
+
+        @Override
+        public ContentCaptureOptions getOptionsForPackage(int userId, String packageName) {
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    return service.getOptionsForPackageLocked(packageName);
+                }
+            }
+            return null;
+        }
     }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 9e15960..5b48046 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -35,6 +35,7 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.pm.ActivityPresentationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -408,6 +409,27 @@
         }
     }
 
+    @GuardedBy("mLock")
+    ContentCaptureOptions getOptionsForPackageLocked(@NonNull String packageName) {
+        if (!mWhitelistedPackages.contains(packageName)) {
+            if (mMaster.verbose) {
+                Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+            }
+            return null;
+        }
+
+        // TODO(b/122595322): need to check whitelisted activities as well.
+        final ArraySet<ComponentName> whitelistedComponents = null;
+        ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
+                mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
+                mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
+                whitelistedComponents);
+        if (mMaster.verbose) {
+            Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+        }
+        return options;
+    }
+
     @Override
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 54eea5d..de9896e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -15,6 +15,9 @@
  */
 package com.android.server.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureHelper.sDebug;
+import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -75,7 +78,7 @@
         }
         try {
             if (state) {
-                mService.onConnected(mServerCallback);
+                mService.onConnected(mServerCallback, sVerbose, sDebug);
             } else {
                 mService.onDisconnected();
             }
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 6e5d316..18c2722 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -36,6 +36,7 @@
 import android.util.SparseArray;
 import android.util.StatsLog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.server.utils.FlagNamespaceUtils;
 
@@ -51,21 +52,35 @@
  * @hide
  */
 public class RescueParty {
-    private static final String TAG = "RescueParty";
+    @VisibleForTesting
+    static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
+    @VisibleForTesting
+    static final int TRIGGER_COUNT = 5;
+    @VisibleForTesting
+    static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
+    @VisibleForTesting
+    static final int LEVEL_NONE = 0;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
+    @VisibleForTesting
+    static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
+    @VisibleForTesting
+    static final int LEVEL_FACTORY_RESET = 4;
+    @VisibleForTesting
+    static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
+    @VisibleForTesting
+    static final long BOOT_TRIGGER_WINDOW_MILLIS = 300 * DateUtils.SECOND_IN_MILLIS;
+    @VisibleForTesting
+    static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS;
+    @VisibleForTesting
+    static final String TAG = "RescueParty";
 
-    private static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
     private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
-    private static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
-    private static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
     private static final String PROP_RESCUE_BOOT_START = "sys.rescue_boot_start";
     private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
 
-    private static final int LEVEL_NONE = 0;
-    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
-    private static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
-    private static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
-    private static final int LEVEL_FACTORY_RESET = 4;
-
     /** Threshold for boot loops */
     private static final Threshold sBoot = new BootThreshold();
     /** Threshold for app crash loops */
@@ -139,6 +154,29 @@
     }
 
     /**
+     * Called when {@code SettingsProvider} has been published, which is a good
+     * opportunity to reset any settings depending on our rescue level.
+     */
+    public static void onSettingsProviderPublished(Context context) {
+        executeRescueLevel(context);
+    }
+
+    @VisibleForTesting
+    static void resetAllThresholds() {
+        sBoot.reset();
+
+        for (int i = 0; i < sApps.size(); i++) {
+            Threshold appThreshold = sApps.get(sApps.keyAt(i));
+            appThreshold.reset();
+        }
+    }
+
+    @VisibleForTesting
+    static long getElapsedRealtime() {
+        return SystemClock.elapsedRealtime();
+    }
+
+    /**
      * Escalate to the next rescue level. After incrementing the level you'll
      * probably want to call {@link #executeRescueLevel(Context)}.
      */
@@ -153,14 +191,6 @@
                 + levelToString(level) + " triggered by UID " + triggerUid);
     }
 
-    /**
-     * Called when {@code SettingsProvider} has been published, which is a good
-     * opportunity to reset any settings depending on our rescue level.
-     */
-    public static void onSettingsProviderPublished(Context context) {
-        executeRescueLevel(context);
-    }
-
     private static void executeRescueLevel(Context context) {
         final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
         if (level == LEVEL_NONE) return;
@@ -255,7 +285,7 @@
          * @return if this threshold has been triggered
          */
         public boolean incrementAndTest() {
-            final long now = SystemClock.elapsedRealtime();
+            final long now = getElapsedRealtime();
             final long window = now - getStart();
             if (window > triggerWindow) {
                 setCount(1);
@@ -278,10 +308,10 @@
      */
     private static class BootThreshold extends Threshold {
         public BootThreshold() {
-            // We're interested in 5 events in any 300 second period; this
-            // window is super relaxed because booting can take a long time if
-            // forced to dexopt things.
-            super(android.os.Process.ROOT_UID, 5, 300 * DateUtils.SECOND_IN_MILLIS);
+            // We're interested in TRIGGER_COUNT events in any
+            // BOOT_TRIGGER_WINDOW_MILLIS second period; this window is super relaxed because
+            // booting can take a long time if forced to dexopt things.
+            super(android.os.Process.ROOT_UID, TRIGGER_COUNT, BOOT_TRIGGER_WINDOW_MILLIS);
         }
 
         @Override
@@ -314,9 +344,10 @@
         private long start;
 
         public AppThreshold(int uid) {
-            // We're interested in 5 events in any 30 second period; apps crash
-            // pretty quickly so we can keep a tight leash on them.
-            super(uid, 5, 30 * DateUtils.SECOND_IN_MILLIS);
+            // We're interested in TRIGGER_COUNT events in any
+            // PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS second period; apps crash pretty quickly
+            // so we can keep a tight leash on them.
+            super(uid, TRIGGER_COUNT, PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS);
         }
 
         @Override public int getCount() { return count; }
diff --git a/services/core/java/com/android/server/ZramWriteback.java b/services/core/java/com/android/server/ZramWriteback.java
index 3a4aff2..49bf29b 100644
--- a/services/core/java/com/android/server/ZramWriteback.java
+++ b/services/core/java/com/android/server/ZramWriteback.java
@@ -174,6 +174,7 @@
         // back at later point if they remain untouched.
         js.schedule(new JobInfo.Builder(MARK_IDLE_JOB_ID, sZramWriteback)
                         .setMinimumLatency(TimeUnit.MINUTES.toMillis(markIdleDelay))
+                        .setOverrideDeadline(TimeUnit.MINUTES.toMillis(markIdleDelay))
                         .build());
 
         // Schedule a one time job to flush idle pages to disk.
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index aebe2b7..fb541e0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1260,10 +1260,11 @@
                 // Check the passed in foreground service type flags is a subset of manifest
                 // foreground service type flags.
                 if ((foregroundServiceType & manifestType) != foregroundServiceType) {
-                    // STOPSHIP(b/120611119): replace log message with IllegalArgumentException.
-                    Slog.w(TAG, "foregroundServiceType must be a subset of "
-                            + "foregroundServiceType attribute in "
-                            + "service element of manifest file");
+                    throw new IllegalArgumentException("foregroundServiceType "
+                        + String.format("0x%08X", foregroundServiceType)
+                        + " is not a subset of foregroundServiceType attribute "
+                        +  String.format("0x%08X", manifestType)
+                        + " in service element of manifest file");
                 }
             }
             boolean alreadyStartedOp = false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bfe1f6a..7c46f1d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -190,6 +190,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
+import android.content.ContentCaptureOptions;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -341,6 +342,7 @@
 import com.android.server.am.ActivityManagerServiceDumpProcessesProto.UidObserverRegistrationProto;
 import com.android.server.am.MemoryStatUtil.MemoryStat;
 import com.android.server.appop.AppOpsService;
+import com.android.server.contentcapture.ContentCaptureManagerInternal;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.job.JobSchedulerInternal;
 import com.android.server.pm.Installer;
@@ -4748,6 +4750,15 @@
                             app.info.packageName, app.info.versionCode, app.userId);
                 }
             }
+            ContentCaptureOptions contentCaptureOptions = null;
+            if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
+                final ContentCaptureManagerInternal ccm =
+                        LocalServices.getService(ContentCaptureManagerInternal.class);
+                if (ccm != null) {
+                    contentCaptureOptions = ccm.getOptionsForPackage(app.userId,
+                            app.info.packageName);
+                }
+            }
 
             checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
             bindApplicationTimeMillis = SystemClock.elapsedRealtime();
@@ -4768,7 +4779,7 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, isAutofillCompatEnabled);
+                        buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
             } else {
                 thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                         null, null, null, testMode,
@@ -4777,7 +4788,7 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, isAutofillCompatEnabled);
+                        buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
             }
             if (profilerInfo != null) {
                 profilerInfo.closeFd();
@@ -5615,7 +5626,7 @@
     int checkCallingPermission(String permission) {
         return checkPermission(permission,
                 Binder.getCallingPid(),
-                UserHandle.getAppId(Binder.getCallingUid()));
+                Binder.getCallingUid());
     }
 
     /**
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 99e0707..8a208a5 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -916,15 +916,17 @@
             extras = new Bundle();
         }
         extras.size(); // Force unpacel.
-        mLogger.log("scheduleSync: account=", requestedAccount,
-                " u", userId,
-                " authority=", requestedAuthority,
-                " reason=", reason,
-                " extras=", extras,
-                " cuid=", callingUid, " cpid=", callingPid, " cpkg=", callingPackage,
-                " mdm=", minDelayMillis,
-                " ciar=", checkIfAccountReady,
-                " sef=", syncExemptionFlag);
+        if (Log.isLoggable(TAG, Log.VERBOSE)) {
+            mLogger.log("scheduleSync: account=", requestedAccount,
+                    " u", userId,
+                    " authority=", requestedAuthority,
+                    " reason=", reason,
+                    " extras=", extras,
+                    " cuid=", callingUid, " cpid=", callingPid, " cpkg=", callingPackage,
+                    " mdm=", minDelayMillis,
+                    " ciar=", checkIfAccountReady,
+                    " sef=", syncExemptionFlag);
+        }
 
         AccountAndUser[] accounts = null;
         if (requestedAccount != null) {
diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index 726362a..d04f920 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -16,7 +16,9 @@
 package com.android.server.contentcapture;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.content.ContentCaptureOptions;
 import android.os.Bundle;
 import android.os.IBinder;
 
@@ -41,4 +43,12 @@
      */
     public abstract boolean sendActivityAssistData(@UserIdInt int userId,
             @NonNull IBinder activityToken, @NonNull Bundle data);
+
+    /**
+     * Gets the content capture options for the given user and package, or {@code null} if the
+     * package is not whitelisted by the service.
+     */
+    @Nullable
+    public abstract ContentCaptureOptions getOptionsForPackage(@UserIdInt int userId,
+            @NonNull String packageName);
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b2509e9..b020997 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -1482,7 +1482,7 @@
             pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
             pw.println("  mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
             pw.println("  mStableDisplaySize=" + mStableDisplaySize);
-
+            pw.println("  mMinimumBrightnessCurve=" + mMinimumBrightnessCurve);
 
             IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
             ipw.increaseIndent();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 4b4788c..924018e 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -194,6 +194,8 @@
     protected IGateKeeperService mGateKeeperService;
     protected IAuthSecret mAuthSecretService;
 
+    private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
+
     /**
      * The UIDs that are used for system credential storage in keystore.
      */
@@ -408,6 +410,10 @@
         public int binderGetCallingUid() {
             return Binder.getCallingUid();
         }
+
+        public boolean isGsiRunning() {
+            return SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
+        }
     }
 
     public LockSettingsService(Context context) {
@@ -2217,6 +2223,11 @@
         }
         tryRemoveUserFromSpCacheLater(userId);
 
+        if (mInjector.isGsiRunning()) {
+            Slog.w(TAG, "AuthSecret disabled in GSI");
+            return;
+        }
+
         // Pass the primary user's auth secret to the HAL
         if (mAuthSecretService != null && mUserManager.getUserInfo(userId).isPrimary()) {
             try {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c2a75ab..bab612d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -616,6 +616,7 @@
      *
      * @param pkg name of the package to snapshot user data for.
      * @param userId id of the user whose data to snapshot.
+     * @param snapshotId id of this snapshot.
      * @param storageFlags flags controlling which data (CE or DE) to snapshot.
      *
      * @return inode of the snapshot of users CE package data, or {@code 0} if a remote calls
@@ -623,12 +624,12 @@
      *
      * @throws InstallerException if failed to snapshot user data.
      */
-    public long snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags)
+    public long snapshotAppData(String pkg, @UserIdInt int userId, int snapshotId, int storageFlags)
             throws InstallerException {
         if (!checkBeforeRemote()) return 0;
 
         try {
-            return mInstalld.snapshotAppData(null, pkg, userId, storageFlags);
+            return mInstalld.snapshotAppData(null, pkg, userId, snapshotId, storageFlags);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
@@ -639,8 +640,8 @@
      *
      * @param pkg name of the package to restore user data for.
      * @param appId id of the package to restore user data for.
-     * @param ceDataInode inode of CE user data folder of this app.
      * @param userId id of the user whose data to restore.
+     * @param snapshotId id of the snapshot to restore.
      * @param storageFlags flags controlling which data (CE or DE) to restore.
      *
      * @return {@code true} if user data restore was successful, or {@code false} if a remote call
@@ -648,12 +649,12 @@
      *
      * @throws InstallerException if failed to restore user data.
      */
-    public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, long ceDataInode,
-            String seInfo, @UserIdInt int userId, int storageFlags) throws InstallerException {
+    public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, String seInfo,
+            @UserIdInt int userId, int snapshotId, int storageFlags) throws InstallerException {
         if (!checkBeforeRemote()) return false;
 
         try {
-            mInstalld.restoreAppDataSnapshot(null, pkg, appId, ceDataInode, seInfo, userId,
+            mInstalld.restoreAppDataSnapshot(null, pkg, appId, seInfo, userId, snapshotId,
                     storageFlags);
             return true;
         } catch (Exception e) {
@@ -667,6 +668,7 @@
      * @param pkg name of the package to delete user data snapshot for.
      * @param userId id of the user whose user data snapshot to delete.
      * @param ceSnapshotInode inode of CE user data snapshot.
+     * @param snapshotId id of the snapshot to delete.
      * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete.
      *
      * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a
@@ -675,11 +677,12 @@
      * @throws InstallerException if failed to delete user data snapshot.
      */
     public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId, long ceSnapshotInode,
-            int storageFlags) throws InstallerException {
+            int snapshotId, int storageFlags) throws InstallerException {
         if (!checkBeforeRemote()) return false;
 
         try {
-            mInstalld.destroyAppDataSnapshot(null, pkg, userId, ceSnapshotInode, storageFlags);
+            mInstalld.destroyAppDataSnapshot(null, pkg, userId, ceSnapshotInode, snapshotId,
+                    storageFlags);
             return true;
         } catch (Exception e) {
             throw InstallerException.from(e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b1c186e..07d460e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13058,6 +13058,7 @@
 
     @Override
     public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) {
+        Preconditions.checkNotNull("packageNames cannot be null", packageNames);
         mContext.enforceCallingOrSelfPermission(Manifest.permission.SUSPEND_APPS,
                 "getUnsuspendablePackagesForUser");
         final int callingUid = Binder.getCallingUid();
@@ -15835,6 +15836,12 @@
 
             if (reconciledPkg.prepareResult.replace) {
                 PackageParser.Package oldPackage = mPackages.get(packageName);
+
+                // Set the update and install times
+                PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
+                setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
+                        System.currentTimeMillis());
+
                 if (reconciledPkg.prepareResult.system) {
                     // Remove existing system package
                     removePackageLI(oldPackage, true);
@@ -15850,11 +15857,6 @@
                         res.removedInfo.args = null;
                     }
 
-                    // Set the update and install times
-                    PackageSetting deletedPkgSetting = (PackageSetting) oldPackage.mExtras;
-                    setInstallAndUpdateTime(pkg, deletedPkgSetting.firstInstallTime,
-                            System.currentTimeMillis());
-
                     // Update the package dynamic state if succeeded
                     // Now that the install succeeded make sure we remove data
                     // directories for any child package the update removed.
diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
index c93af2a..1c86c4f 100644
--- a/services/core/java/com/android/server/pm/dex/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
@@ -9,7 +9,7 @@
       ]
     },
     {
-      "name": "DexLoggerIntegrationTests"
+      "name": "DynamicCodeLoggerIntegrationTests"
     }
   ]
 }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index dacc6cd..6369179 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -642,10 +642,16 @@
         // Location
         if (locationPackageNames != null) {
             for (String packageName : locationPackageNames) {
+                // STOPSHIP: remove this force-granting of legacy storage
+                // permissions once b/124466734 is resolved
+                final Set<String> storageWorkaround = new ArraySet<>();
+                storageWorkaround.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+                storageWorkaround.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+
                 grantPermissionsToSystemPackage(packageName, userId,
                         CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
                         PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
-                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
+                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, storageWorkaround);
                 grantSystemFixedPermissionsToSystemPackage(packageName, userId,
                         LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
             }
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index f3b8385..e9ccea54 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -29,6 +29,8 @@
 import com.android.server.pm.Installer.InstallerException;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -49,16 +51,11 @@
     }
 
     /**
-     * Creates an app data snapshot for a specified {@code packageName} for {@code installedUsers},
-     * a specified set of users for whom the package is installed.
-     *
-     * @return a {@link SnapshotAppDataResult}/
-     * @see SnapshotAppDataResult
+     * Creates an app data snapshot for a specified {@code packageRollbackInfo}. Updates said {@code
+     * packageRollbackInfo} with the inodes of the CE user data snapshot folders.
      */
-    public SnapshotAppDataResult snapshotAppData(String packageName, int[] installedUsers) {
-        final IntArray pendingBackups = new IntArray();
-        final SparseLongArray ceSnapshotInodes = new SparseLongArray();
-
+    public void snapshotAppData(int snapshotId, PackageRollbackInfo packageRollbackInfo) {
+        final int[] installedUsers = packageRollbackInfo.getInstalledUsers().toArray();
         for (int user : installedUsers) {
             final int storageFlags;
             if (isUserCredentialLocked(user)) {
@@ -66,51 +63,38 @@
                 // across app user data until the user unlocks their device.
                 Log.v(TAG, "User: " + user + " isn't unlocked, skipping CE userdata backup.");
                 storageFlags = Installer.FLAG_STORAGE_DE;
-                pendingBackups.add(user);
+                packageRollbackInfo.addPendingBackup(user);
             } else {
                 storageFlags = Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE;
             }
 
             try {
-                long ceSnapshotInode = mInstaller.snapshotAppData(packageName, user, storageFlags);
+                long ceSnapshotInode = mInstaller.snapshotAppData(
+                        packageRollbackInfo.getPackageName(), user, snapshotId, storageFlags);
                 if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) {
-                    ceSnapshotInodes.put(user, ceSnapshotInode);
+                    packageRollbackInfo.putCeSnapshotInode(user, ceSnapshotInode);
                 }
             } catch (InstallerException ie) {
-                Log.e(TAG, "Unable to create app data snapshot for: " + packageName
-                        + ", userId: " + user, ie);
+                Log.e(TAG, "Unable to create app data snapshot for: "
+                        + packageRollbackInfo.getPackageName() + ", userId: " + user, ie);
             }
         }
-
-        return new SnapshotAppDataResult(pendingBackups, ceSnapshotInodes);
     }
 
     /**
-     * Restores an app data snapshot for a specified package ({@code packageName},
-     * {@code rollbackData}) for a specified {@code userId}.
+     * Restores an app data snapshot for a specified {@code packageRollbackInfo}, for a specified
+     * {@code userId}.
      *
-     * @return {@code true} iff. a change to the {@code rollbackData} has been made. Changes to
-     *         {@code rollbackData} are restricted to the removal or addition of {@code userId} to
-     *         the list of pending backups or restores.
+     * @return {@code true} iff. a change to the {@code packageRollbackInfo} has been made. Changes
+     *         to {@code packageRollbackInfo} are restricted to the removal or addition of {@code
+     *         userId} to the list of pending backups or restores.
      */
-    public boolean restoreAppData(String packageName, RollbackData rollbackData,
-            int userId, int appId, long ceDataInode, String seInfo) {
-        if (rollbackData == null) {
-            return false;
-        }
-
-        if (!rollbackData.inProgress) {
-            Log.e(TAG, "Request to restore userData for: " + packageName
-                    + ", but no rollback in progress.");
-            return false;
-        }
-
-        PackageRollbackInfo packageInfo = RollbackManagerServiceImpl.getPackageRollbackInfo(
-                rollbackData, packageName);
+    public boolean restoreAppData(int rollbackId, PackageRollbackInfo packageRollbackInfo,
+            int userId, int appId, String seInfo) {
         int storageFlags = Installer.FLAG_STORAGE_DE;
 
-        final IntArray pendingBackups = packageInfo.getPendingBackups();
-        final List<RestoreInfo> pendingRestores = packageInfo.getPendingRestores();
+        final IntArray pendingBackups = packageRollbackInfo.getPendingBackups();
+        final List<RestoreInfo> pendingRestores = packageRollbackInfo.getPendingRestores();
         boolean changedRollbackData = false;
 
         // If we still have a userdata backup pending for this user, it implies that the user
@@ -134,53 +118,60 @@
         }
 
         try {
-            mInstaller.restoreAppDataSnapshot(packageName, appId, ceDataInode,
-                    seInfo, userId, storageFlags);
+            mInstaller.restoreAppDataSnapshot(packageRollbackInfo.getPackageName(), appId, seInfo,
+                    userId, rollbackId, storageFlags);
         } catch (InstallerException ie) {
-            Log.e(TAG, "Unable to restore app data snapshot: " + packageName, ie);
+            Log.e(TAG, "Unable to restore app data snapshot: "
+                        + packageRollbackInfo.getPackageName(), ie);
         }
 
         return changedRollbackData;
     }
 
     /**
-     * Deletes an app data data snapshot for a specified package {@code packageName} for a
-     * given {@code user}.
+     * Deletes an app data snapshot with a given {@code rollbackId} for a specified package
+     * {@code packageName} for a given {@code user}.
      */
-    public void destroyAppDataSnapshot(String packageName, int user, long ceSnapshotInode) {
+    public void destroyAppDataSnapshot(int rollbackId, PackageRollbackInfo packageRollbackInfo,
+            int user) {
         int storageFlags = Installer.FLAG_STORAGE_DE;
+        final SparseLongArray ceSnapshotInodes = packageRollbackInfo.getCeSnapshotInodes();
+        long ceSnapshotInode = ceSnapshotInodes.get(user);
         if (ceSnapshotInode > 0) {
             storageFlags |= Installer.FLAG_STORAGE_CE;
         }
         try {
-            mInstaller.destroyAppDataSnapshot(packageName, user, ceSnapshotInode, storageFlags);
+            mInstaller.destroyAppDataSnapshot(packageRollbackInfo.getPackageName(), user,
+                    ceSnapshotInode, rollbackId, storageFlags);
+            if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) {
+                ceSnapshotInodes.delete(user);
+            }
         } catch (InstallerException ie) {
-            Log.e(TAG, "Unable to delete app data snapshot for " + packageName, ie);
+            Log.e(TAG, "Unable to delete app data snapshot for "
+                        + packageRollbackInfo.getPackageName(), ie);
         }
     }
 
     /**
-     * Computes the list of pending backups and restores for {@code userId} given lists of
-     * available and recent rollbacks. Packages pending backup for the given user are added
-     * to {@code pendingBackups} and packages pending restore are added to {@code pendingRestores}
-     * along with their corresponding {@code RestoreInfo}.
+     * Computes the list of pending backups for {@code userId} given lists of available rollbacks.
+     * Packages pending backup for the given user are added to {@code pendingBackupPackages} along
+     * with their corresponding {@code PackageRollbackInfo}.
      *
-     * @return the list of {@code RollbackData} that have been modified during this computation.
+     * @return the list of {@code RollbackData} that has pending backups. Note that some of the
+     *         backups won't be performed, because they might be counteracted by pending restores.
      */
-    public List<RollbackData> computePendingBackupsAndRestores(int userId,
-            ArrayList<String> pendingBackupPackages, Map<String, RestoreInfo> pendingRestores,
-            List<RollbackData> availableRollbacks, List<RollbackInfo> recentRollbacks) {
+    private static List<RollbackData> computePendingBackups(int userId,
+            Map<String, PackageRollbackInfo> pendingBackupPackages,
+            List<RollbackData> availableRollbacks) {
         List<RollbackData> rd = new ArrayList<>();
-        // First check with the list of available rollbacks to see whether there are any
-        // pending backup operations that we've not managed to execute.
+
         for (RollbackData data : availableRollbacks) {
             for (PackageRollbackInfo info : data.packages) {
                 final IntArray pendingBackupUsers = info.getPendingBackups();
                 if (pendingBackupUsers != null) {
                     final int idx = pendingBackupUsers.indexOf(userId);
                     if (idx != -1) {
-                        pendingBackupPackages.add(info.getPackageName());
-                        pendingBackupUsers.remove(idx);
+                        pendingBackupPackages.put(info.getPackageName(), info);
                         if (rd.indexOf(data) == -1) {
                             rd.add(data);
                         }
@@ -188,23 +179,30 @@
                 }
             }
         }
+        return rd;
+    }
 
-        // Then check with the list of recently executed rollbacks to see whether there are
-        // any rollback operations
+    /**
+     * Computes the list of pending restores for {@code userId} given lists of recent rollbacks.
+     * Packages pending restore are added to {@code pendingRestores} along with their corresponding
+     * {@code PackageRollbackInfo}.
+     *
+     * @return the list of {@code RollbackInfo} that has pending restores. Note that some of the
+     *         restores won't be performed, because they might be counteracted by pending backups.
+     */
+    private static List<RollbackInfo> computePendingRestores(int userId,
+            Map<String, PackageRollbackInfo> pendingRestorePackages,
+            List<RollbackInfo> recentRollbacks) {
+        List<RollbackInfo> rd = new ArrayList<>();
+
         for (RollbackInfo data : recentRollbacks) {
             for (PackageRollbackInfo info : data.getPackages()) {
                 final RestoreInfo ri = info.getRestoreInfo(userId);
                 if (ri != null) {
-                    if (pendingBackupPackages.contains(info.getPackageName())) {
-                        // This implies that the user hasn't unlocked their device between
-                        // the request to backup data for this user and the request to restore
-                        // it, so we do nothing here.
-                        pendingBackupPackages.remove(info.getPackageName());
-                    } else {
-                        pendingRestores.put(info.getPackageName(), ri);
+                    pendingRestorePackages.put(info.getPackageName(), info);
+                    if (rd.indexOf(data) == -1) {
+                        rd.add(data);
                     }
-
-                    info.removeRestoreInfo(ri);
                 }
             }
         }
@@ -216,47 +214,77 @@
      * Commits the list of pending backups and restores for a given {@code userId}. For the pending
      * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
      * to a inode of theirs CE user data snapshot.
+     *
+     * @return a list {@code RollbackData} that have been changed and should be stored on disk.
      */
-    public void commitPendingBackupAndRestoreForUser(int userId,
-            ArrayList<String> pendingBackups, Map<String, RestoreInfo> pendingRestores,
-            List<RollbackData> changedRollbackData) {
-        if (!pendingBackups.isEmpty()) {
-            for (String packageName : pendingBackups) {
-                try {
-                    long ceSnapshotInode = mInstaller.snapshotAppData(packageName, userId,
-                            Installer.FLAG_STORAGE_CE);
-                    for (RollbackData data : changedRollbackData) {
-                        for (PackageRollbackInfo info : data.packages) {
-                            if (info.getPackageName().equals(packageName)) {
-                                info.putCeSnapshotInode(userId, ceSnapshotInode);
-                            }
+    public List<RollbackData> commitPendingBackupAndRestoreForUser(int userId,
+            List<RollbackData> availableRollbacks, List<RollbackInfo> recentlyExecutedRollbacks) {
+
+        final Map<String, PackageRollbackInfo> pendingBackupPackages = new HashMap<>();
+        final List<RollbackData> pendingBackups = computePendingBackups(userId,
+                pendingBackupPackages, availableRollbacks);
+
+        final Map<String, PackageRollbackInfo> pendingRestorePackages = new HashMap<>();
+        final List<RollbackInfo> pendingRestores = computePendingRestores(userId,
+                pendingRestorePackages, recentlyExecutedRollbacks);
+
+        // First remove unnecessary backups, i.e. when user did not unlock their phone between the
+        // request to backup data and the request to restore it.
+        Iterator<Map.Entry<String, PackageRollbackInfo>> iter =
+                pendingBackupPackages.entrySet().iterator();
+        while (iter.hasNext()) {
+            PackageRollbackInfo backupPackage = iter.next().getValue();
+            PackageRollbackInfo restorePackage =
+                    pendingRestorePackages.get(backupPackage.getPackageName());
+            if (restorePackage != null) {
+                backupPackage.removePendingBackup(userId);
+                backupPackage.removePendingRestoreInfo(userId);
+                iter.remove();
+                pendingRestorePackages.remove(backupPackage.getPackageName());
+            }
+        }
+
+        if (!pendingBackupPackages.isEmpty()) {
+            for (RollbackData data : pendingBackups) {
+                for (PackageRollbackInfo info : data.packages) {
+                    final IntArray pendingBackupUsers = info.getPendingBackups();
+                    final int idx = pendingBackupUsers.indexOf(userId);
+                    if (idx != -1) {
+                        try {
+                            long ceSnapshotInode = mInstaller.snapshotAppData(info.getPackageName(),
+                                    userId, data.rollbackId, Installer.FLAG_STORAGE_CE);
+                            info.putCeSnapshotInode(userId, ceSnapshotInode);
+                            pendingBackupUsers.remove(idx);
+                        } catch (InstallerException ie) {
+                            Log.e(TAG,
+                                    "Unable to create app data snapshot for: "
+                                    + info.getPackageName() + ", userId: " + userId, ie);
                         }
                     }
-                } catch (InstallerException ie) {
-                    Log.e(TAG, "Unable to create app data snapshot for: " + packageName
-                            + ", userId: " + userId, ie);
                 }
             }
         }
 
-        // TODO(narayan): Should we perform the restore before the backup for packages that have
-        // both backups and restores pending ? We could get into this case if we have a pending
-        // restore from a rollback + a snapshot request from a new restore.
-        if (!pendingRestores.isEmpty()) {
-            for (String packageName : pendingRestores.keySet()) {
-                try {
-                    final RestoreInfo ri = pendingRestores.get(packageName);
-
-                    // TODO(narayan): Verify that the user of "0" for ceDataInode is accurate
-                    // here. We know that the user has unlocked (and that their CE data is
-                    // available) so we shouldn't need to resort to the fallback path.
-                    mInstaller.restoreAppDataSnapshot(packageName, ri.appId,
-                            0 /* ceDataInode */, ri.seInfo, userId, Installer.FLAG_STORAGE_CE);
-                } catch (InstallerException ie) {
-                    Log.e(TAG, "Unable to restore app data snapshot for: " + packageName, ie);
+        if (!pendingRestorePackages.isEmpty()) {
+            for (RollbackInfo data : pendingRestores) {
+                for (PackageRollbackInfo info : data.getPackages()) {
+                    final RestoreInfo ri = info.getRestoreInfo(userId);
+                    if (ri != null) {
+                        try {
+                            mInstaller.restoreAppDataSnapshot(info.getPackageName(), ri.appId,
+                                    ri.seInfo, userId, data.getRollbackId(),
+                                    Installer.FLAG_STORAGE_CE);
+                            info.removeRestoreInfo(ri);
+                        } catch (InstallerException ie) {
+                            Log.e(TAG, "Unable to restore app data snapshot for: "
+                                    + info.getPackageName(), ie);
+                        }
+                    }
                 }
             }
         }
+
+        return pendingBackups;
     }
 
     /**
@@ -267,26 +295,4 @@
         return StorageManager.isFileEncryptedNativeOrEmulated()
                 && !StorageManager.isUserKeyUnlocked(userId);
     }
-
-    /**
-     * Encapsulates a result of {@link #snapshotAppData} method.
-     */
-    public static final class SnapshotAppDataResult {
-
-        /**
-         * A list of users for which the snapshot is pending, usually because data for one or more
-         * users is still credential locked.
-         */
-        public final IntArray pendingBackups;
-
-        /**
-         * A mapping between user and an inode of theirs CE data snapshot.
-         */
-        public final SparseLongArray ceSnapshotInodes;
-
-        public SnapshotAppDataResult(IntArray pendingBackups, SparseLongArray ceSnapshotInodes) {
-            this.pendingBackups = pendingBackups;
-            this.ceSnapshotInodes = ceSnapshotInodes;
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 05d3c17..c14f126 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -32,7 +32,6 @@
 import android.content.pm.VersionedPackage;
 import android.content.rollback.IRollbackManager;
 import android.content.rollback.PackageRollbackInfo;
-import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.content.rollback.RollbackInfo;
 import android.content.rollback.RollbackManager;
 import android.os.Binder;
@@ -466,18 +465,17 @@
 
     void onUnlockUser(int userId) {
         getHandler().post(() -> {
-            final ArrayList<String> pendingBackupPackages = new ArrayList<>();
-            final Map<String, RestoreInfo> pendingRestorePackages = new HashMap<>();
-            final List<RollbackData> changed;
+            final List<RollbackData> availableRollbacks;
+            final List<RollbackInfo> recentlyExecutedRollbacks;
             synchronized (mLock) {
                 ensureRollbackDataLoadedLocked();
-                changed = mAppDataRollbackHelper.computePendingBackupsAndRestores(userId,
-                        pendingBackupPackages, pendingRestorePackages, mAvailableRollbacks,
-                        mRecentlyExecutedRollbacks);
+                availableRollbacks = new ArrayList<>(mAvailableRollbacks);
+                recentlyExecutedRollbacks = new ArrayList<>(mRecentlyExecutedRollbacks);
             }
 
-            mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId,
-                    pendingBackupPackages, pendingRestorePackages, changed);
+            final List<RollbackData> changed =
+                    mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId,
+                            availableRollbacks, recentlyExecutedRollbacks);
 
             for (RollbackData rd : changed) {
                 try {
@@ -844,13 +842,7 @@
             for (PackageRollbackInfo info : rd.packages) {
                 if (info.getPackageName().equals(packageName)) {
                     info.getInstalledUsers().addAll(IntArray.wrap(installedUsers));
-                    AppDataRollbackHelper.SnapshotAppDataResult rs =
-                            mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
-                    info.getPendingBackups().addAll(rs.pendingBackups);
-                    for (int i = 0; i < rs.ceSnapshotInodes.size(); i++) {
-                        info.putCeSnapshotInode(rs.ceSnapshotInodes.keyAt(i),
-                                rs.ceSnapshotInodes.valueAt(i));
-                    }
+                    mAppDataRollbackHelper.snapshotAppData(rd.rollbackId, info);
                     try {
                         mRollbackStore.saveAvailableRollback(rd);
                     } catch (IOException ioe) {
@@ -919,18 +911,10 @@
         VersionedPackage installedVersion = new VersionedPackage(packageName,
                 pkgInfo.getLongVersionCode());
 
-        final AppDataRollbackHelper.SnapshotAppDataResult result;
-        if (snapshotUserData && !isApex) {
-            result = mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
-        } else {
-            result = new AppDataRollbackHelper.SnapshotAppDataResult(IntArray.wrap(new int[0]),
-                new SparseLongArray());
-        }
-
         PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion,
-                result.pendingBackups, new ArrayList<>(), isApex, IntArray.wrap(installedUsers),
-                result.ceSnapshotInodes);
-
+                new IntArray() /* pendingBackups */, new ArrayList<>() /* pendingRestores */,
+                isApex, IntArray.wrap(installedUsers),
+                new SparseLongArray() /* ceSnapshotInodes */);
         RollbackData data;
         try {
             int childSessionId = session.getSessionId();
@@ -948,7 +932,7 @@
                     int rollbackId = allocateRollbackIdLocked();
                     if (session.isStaged()) {
                         data = mRollbackStore.createPendingStagedRollback(rollbackId,
-                                parentSessionId);
+                            parentSessionId);
                     } else {
                         data = mRollbackStore.createAvailableRollback(rollbackId);
                     }
@@ -961,6 +945,10 @@
             return false;
         }
 
+        if (snapshotUserData && !isApex) {
+            mAppDataRollbackHelper.snapshotAppData(data.rollbackId, info);
+        }
+
         try {
             RollbackStore.backupPackageCode(data, packageName, pkgInfo.applicationInfo.sourceDir);
         } catch (IOException e) {
@@ -980,8 +968,15 @@
         getHandler().post(() -> {
             final RollbackData rollbackData = getRollbackForPackage(packageName);
             for (int userId : userIds) {
+                if (rollbackData == null || !rollbackData.inProgress) {
+                    Log.e(TAG, "Request to restore userData for: " + packageName
+                                  + ", but no rollback in progress.");
+                    continue;
+                }
+                final PackageRollbackInfo info = getPackageRollbackInfo(rollbackData, packageName);
                 final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
-                        packageName, rollbackData, userId, appId, ceDataInode, seInfo);
+                        rollbackData.rollbackId, info, userId, appId, seInfo);
+
                 // We've updated metadata about this rollback, so save it to flash.
                 if (changedRollbackData) {
                     try {
@@ -1252,7 +1247,7 @@
      * Returns the {@code PackageRollbackInfo} associated with {@code packageName} from
      * a specified {@code RollbackData}.
      */
-    static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
+    private static PackageRollbackInfo getPackageRollbackInfo(RollbackData data,
             String packageName) {
         for (PackageRollbackInfo info : data.packages) {
             if (info.getPackageName().equals(packageName)) {
@@ -1281,11 +1276,10 @@
     private void deleteRollback(RollbackData rollbackData) {
         for (PackageRollbackInfo info : rollbackData.packages) {
             IntArray installedUsers = info.getInstalledUsers();
-            SparseLongArray ceSnapshotInodes = info.getCeSnapshotInodes();
             for (int i = 0; i < installedUsers.size(); i++) {
                 int userId = installedUsers.get(i);
-                mAppDataRollbackHelper.destroyAppDataSnapshot(info.getPackageName(), userId,
-                        ceSnapshotInodes.get(userId, 0));
+                mAppDataRollbackHelper.destroyAppDataSnapshot(rollbackData.rollbackId, info,
+                        userId);
             }
         }
         mRollbackStore.deleteAvailableRollback(rollbackData);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 932cfd3..a4457e2 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -4019,7 +4019,7 @@
                         "Prepare close transition: finishing " + r);
                 if (endTask) {
                     mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
-                            task.taskId);
+                            task.getTaskInfo());
                 }
                 getDisplay().mDisplayContent.prepareAppTransition(transit, false);
 
@@ -4924,8 +4924,7 @@
 
             mRootActivityContainer.resumeFocusedStacksTopActivities();
             EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
-
-            mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.taskId);
+            mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
         } finally {
             getDisplay().continueUpdateImeTarget();
         }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 6ffd554..df76030 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -317,14 +317,14 @@
      * receivers to launch an activity and get that to run before the device
      * goes back to sleep.
      */
-    PowerManager.WakeLock mLaunchingActivity;
+    PowerManager.WakeLock mLaunchingActivityWakeLock;
 
     /**
      * Set when the system is going to sleep, until we have
      * successfully paused the current activity and released our wake lock.
      * At that point the system is allowed to actually sleep.
      */
-    PowerManager.WakeLock mGoingToSleep;
+    PowerManager.WakeLock mGoingToSleepWakeLock;
 
     /**
      * Temporary rect used during docked stack resize calculation so we don't need to create a new
@@ -467,10 +467,10 @@
      */
     void initPowerManagement() {
         mPowerManager = mService.mContext.getSystemService(PowerManager.class);
-        mGoingToSleep = mPowerManager
+        mGoingToSleepWakeLock = mPowerManager
                 .newWakeLock(PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
-        mLaunchingActivity = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "*launch*");
-        mLaunchingActivity.setReferenceCounted(false);
+        mLaunchingActivityWakeLock = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "*launch*");
+        mLaunchingActivityWakeLock.setReferenceCounted(false);
     }
 
     void setWindowManager(WindowManagerService wm) {
@@ -1213,14 +1213,14 @@
     }
 
     void setLaunchSource(int uid) {
-        mLaunchingActivity.setWorkSource(new WorkSource(uid));
+        mLaunchingActivityWakeLock.setWorkSource(new WorkSource(uid));
     }
 
     void acquireLaunchWakelock() {
         if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
             throw new IllegalStateException("Calling must be system uid");
         }
-        mLaunchingActivity.acquire();
+        mLaunchingActivityWakeLock.acquire();
         if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
             // To be safe, don't allow the wake lock to be held for too long.
             mHandler.sendEmptyMessageDelayed(LAUNCH_TIMEOUT_MSG, LAUNCH_TIMEOUT);
@@ -1302,13 +1302,13 @@
                 mService.scheduleAppGcsLocked();
             }
 
-            if (mLaunchingActivity.isHeld()) {
+            if (mLaunchingActivityWakeLock.isHeld()) {
                 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
                 if (VALIDATE_WAKE_LOCK_CALLER &&
                         Binder.getCallingUid() != Process.myUid()) {
                     throw new IllegalStateException("Calling must be system uid");
                 }
-                mLaunchingActivity.release();
+                mLaunchingActivityWakeLock.release();
             }
             mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
         }
@@ -1972,13 +1972,13 @@
 
     void goingToSleepLocked() {
         scheduleSleepTimeout();
-        if (!mGoingToSleep.isHeld()) {
-            mGoingToSleep.acquire();
-            if (mLaunchingActivity.isHeld()) {
+        if (!mGoingToSleepWakeLock.isHeld()) {
+            mGoingToSleepWakeLock.acquire();
+            if (mLaunchingActivityWakeLock.isHeld()) {
                 if (VALIDATE_WAKE_LOCK_CALLER && Binder.getCallingUid() != Process.myUid()) {
                     throw new IllegalStateException("Calling must be system uid");
                 }
-                mLaunchingActivity.release();
+                mLaunchingActivityWakeLock.release();
                 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
             }
         }
@@ -2020,8 +2020,8 @@
 
     void comeOutOfSleepIfNeededLocked() {
         removeSleepTimeouts();
-        if (mGoingToSleep.isHeld()) {
-            mGoingToSleep.release();
+        if (mGoingToSleepWakeLock.isHeld()) {
+            mGoingToSleepWakeLock.release();
         }
     }
 
@@ -2051,8 +2051,8 @@
 
         removeSleepTimeouts();
 
-        if (mGoingToSleep.isHeld()) {
-            mGoingToSleep.release();
+        if (mGoingToSleepWakeLock.isHeld()) {
+            mGoingToSleepWakeLock.release();
         }
         if (mService.mShuttingDown) {
             mService.mGlobalLock.notifyAll();
@@ -2358,7 +2358,8 @@
                 Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
                 // Display a warning toast that we failed to put a task on a secondary display.
                 mService.getTaskChangeNotificationController()
-                        .notifyActivityLaunchOnSecondaryDisplayFailed();
+                        .notifyActivityLaunchOnSecondaryDisplayFailed(task.getTaskInfo(),
+                                preferredDisplayId);
                 return;
             } else if (!forceNonResizable && handleForcedResizableTask(task,
                     FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY)) {
@@ -2561,13 +2562,13 @@
                 } break;
                 case LAUNCH_TIMEOUT_MSG: {
                     synchronized (mService.mGlobalLock) {
-                        if (mLaunchingActivity.isHeld()) {
+                        if (mLaunchingActivityWakeLock.isHeld()) {
                             Slog.w(TAG, "Launch timeout has expired, giving up wake lock!");
                             if (VALIDATE_WAKE_LOCK_CALLER
                                     && Binder.getCallingUid() != Process.myUid()) {
                                 throw new IllegalStateException("Calling must be system uid");
                             }
-                            mLaunchingActivity.release();
+                            mLaunchingActivityWakeLock.release();
                         }
                     }
                 } break;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 538813e..9ea819e 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -938,7 +938,7 @@
             return false;
         }
         // don't abort if the callingUid is in the foreground or is a persistent system process
-        final int callingUidProcState = mService.getUidStateLocked(callingUid);
+        final int callingUidProcState = mService.getUidState(callingUid);
         final boolean callingUidHasAnyVisibleWindow =
                 mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(callingUid);
         final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
@@ -951,7 +951,7 @@
         // take realCallingUid into consideration
         final int realCallingUidProcState = (callingUid == realCallingUid)
                 ? callingUidProcState
-                : mService.getUidStateLocked(realCallingUid);
+                : mService.getUidState(realCallingUid);
         final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
                 ? callingUidHasAnyVisibleWindow
                 : mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(realCallingUid);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 9b35e85..cb4664f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -26,7 +26,6 @@
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.Manifest.permission.STOP_APP_SWITCHES;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
 import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW;
@@ -272,6 +271,10 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.lang.ref.WeakReference;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -363,7 +366,7 @@
     private UserManagerService mUserManager;
     private AppOpsService mAppOpsService;
     /** All active uids in the system. */
-    private final SparseArray<Integer> mActiveUids = new SparseArray<>();
+    private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
     private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
     /** All processes currently running that might have a window organized by name. */
     final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
@@ -647,6 +650,17 @@
         }
     }
 
+    /** Indicates that the method may be invoked frequently or is sensitive to performance. */
+    @Target(ElementType.METHOD)
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HotPath {
+        int NONE = 0;
+        int OOM_ADJUSTMENT = 1;
+        int LRU_UPDATE = 2;
+        int PROCESS_CHANGE = 3;
+        int caller() default NONE;
+    }
+
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public ActivityTaskManagerService(Context context) {
         mContext = context;
@@ -2763,7 +2777,7 @@
                 r.setTaskDescription(td);
                 final TaskRecord task = r.getTaskRecord();
                 task.updateTaskDescription();
-                mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.taskId, td);
+                mTaskChangeNotificationController.notifyTaskDescriptionChanged(task.getTaskInfo());
             }
         }
     }
@@ -5720,12 +5734,12 @@
         return null;
     }
 
-    int getUidStateLocked(int uid) {
-        return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
+    int getUidState(int uid) {
+        return mActiveUids.getUidState(uid);
     }
 
     boolean isUidForeground(int uid) {
-        return (getUidStateLocked(uid) == ActivityManager.PROCESS_STATE_TOP)
+        return (getUidState(uid) == ActivityManager.PROCESS_STATE_TOP)
                 || mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid);
     }
 
@@ -6118,23 +6132,26 @@
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void onProcessAdded(WindowProcessController proc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 mProcessNames.put(proc.mName, proc.mUid, proc);
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void onProcessRemoved(String name, int uid) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 mProcessNames.remove(name, uid);
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void onCleanUpApplicationRecord(WindowProcessController proc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 if (proc == mHomeProcess) {
                     mHomeProcess = null;
                 }
@@ -6144,23 +6161,26 @@
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public int getTopProcessState() {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 return mTopProcessState;
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public boolean isHeavyWeightProcess(WindowProcessController proc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 return proc == mHeavyWeightProcess;
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void clearHeavyWeightProcessIfEquals(WindowProcessController proc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 ActivityTaskManagerService.this.clearHeavyWeightProcessIfEquals(proc);
             }
         }
@@ -6176,9 +6196,10 @@
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public boolean isSleeping() {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 return isSleepingLocked();
             }
         }
@@ -6422,9 +6443,10 @@
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public boolean isFactoryTestProcess(WindowProcessController wpc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 if (mFactoryTest == FACTORY_TEST_OFF) {
                     return false;
                 }
@@ -6477,10 +6499,11 @@
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void handleAppDied(WindowProcessController wpc, boolean restarting,
                 Runnable finishInstrumentationCallback) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 // Remove this application's activities from active lists.
                 boolean hasVisibleActivities = mRootActivityContainer.handleAppDied(wpc);
 
@@ -6579,16 +6602,18 @@
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public void preBindApplication(WindowProcessController wpc) {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(wpc.mInfo);
             }
         }
 
+        @HotPath(caller = HotPath.PROCESS_CHANGE)
         @Override
         public boolean attachApplication(WindowProcessController wpc) throws RemoteException {
-            synchronized (mGlobalLock) {
+            synchronized (mGlobalLockWithoutBoost) {
                 return mRootActivityContainer.attachApplication(wpc);
             }
         }
@@ -6816,8 +6841,9 @@
                         pw.println("  mController=" + mController
                                 + " mControllerIsAMonkey=" + mControllerIsAMonkey);
                     }
-                    pw.println("  mGoingToSleep=" + mStackSupervisor.mGoingToSleep);
-                    pw.println("  mLaunchingActivity=" + mStackSupervisor.mLaunchingActivity);
+                    pw.println("  mGoingToSleepWakeLock=" + mStackSupervisor.mGoingToSleepWakeLock);
+                    pw.println("  mLaunchingActivityWakeLock="
+                            + mStackSupervisor.mLaunchingActivityWakeLock);
                 }
 
                 return needSep;
@@ -6849,8 +6875,9 @@
                         proto.write(IS_A_MONKEY, mControllerIsAMonkey);
                         proto.end(token);
                     }
-                    mStackSupervisor.mGoingToSleep.writeToProto(proto, GOING_TO_SLEEP);
-                    mStackSupervisor.mLaunchingActivity.writeToProto(proto, LAUNCHING_ACTIVITY);
+                    mStackSupervisor.mGoingToSleepWakeLock.writeToProto(proto, GOING_TO_SLEEP);
+                    mStackSupervisor.mLaunchingActivityWakeLock.writeToProto(proto,
+                            LAUNCHING_ACTIVITY);
                 }
 
                 if (mHomeProcess != null && (dumpPackage == null
@@ -6916,6 +6943,7 @@
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public WindowProcessController getTopApp() {
             synchronized (mGlobalLockWithoutBoost) {
@@ -6924,6 +6952,7 @@
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public void rankTaskLayersIfNeeded() {
             synchronized (mGlobalLockWithoutBoost) {
@@ -6968,34 +6997,28 @@
             }
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public void onUidActive(int uid, int procState) {
-            synchronized (mGlobalLockWithoutBoost) {
-                mActiveUids.put(uid, procState);
-            }
+            mActiveUids.onUidActive(uid, procState);
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public void onUidInactive(int uid) {
-            synchronized (mGlobalLockWithoutBoost) {
-                mActiveUids.remove(uid);
-            }
+            mActiveUids.onUidInactive(uid);
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public void onActiveUidsCleared() {
-            synchronized (mGlobalLockWithoutBoost) {
-                mActiveUids.clear();
-            }
+            mActiveUids.onActiveUidsCleared();
         }
 
+        @HotPath(caller = HotPath.OOM_ADJUSTMENT)
         @Override
         public void onUidProcStateChanged(int uid, int procState) {
-            synchronized (mGlobalLockWithoutBoost) {
-                if (mActiveUids.get(uid) != null) {
-                    mActiveUids.put(uid, procState);
-                }
-            }
+            mActiveUids.onUidProcStateChanged(uid, procState);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 28cd930..ae76740 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -37,7 +37,6 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
@@ -145,6 +144,7 @@
 import android.graphics.Region;
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManagerInternal;
+import android.metrics.LogMaker;
 import android.os.Binder;
 import android.os.Debug;
 import android.os.Handler;
@@ -173,11 +173,12 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.function.TriConsumer;
 import com.android.server.AnimationThread;
@@ -260,6 +261,8 @@
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
     BoundsAnimationController mBoundsAnimationController;
 
+    private MetricsLogger mMetricsLogger;
+
     /**
      * List of clients without a transtiton animation that we notify once we are done
      * transitioning since they won't be notified through the app window animator.
@@ -1982,11 +1985,19 @@
 
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
+        final int lastOrientation = getConfiguration().orientation;
         super.onConfigurationChanged(newParentConfig);
         if (mDisplayPolicy != null) {
             mDisplayPolicy.onConfigurationChanged();
         }
 
+        if (lastOrientation != getConfiguration().orientation) {
+            getMetricsLogger().write(
+                    new LogMaker(MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED)
+                    .setSubtype(getConfiguration().orientation)
+                    .addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
+        }
+
         // If there was no pinned stack, we still need to notify the controller of the display info
         // update as a result of the config change.
         if (mPinnedStackControllerLocked != null && !hasPinnedStack()) {
@@ -3259,9 +3270,6 @@
     }
 
     private void updateImeParent() {
-        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE) {
-            return;
-        }
         final SurfaceControl newParent = computeImeParent();
         if (newParent != null) {
             mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent);
@@ -4963,4 +4971,11 @@
         setLayoutNeeded();
         mWmService.mWindowPlacerLocked.requestTraversal();
     }
+
+    protected MetricsLogger getMetricsLogger() {
+        if (mMetricsLogger == null) {
+            mMetricsLogger = new MetricsLogger();
+        }
+        return mMetricsLogger;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/MirrorActiveUids.java b/services/core/java/com/android/server/wm/MirrorActiveUids.java
new file mode 100644
index 0000000..0047942
--- /dev/null
+++ b/services/core/java/com/android/server/wm/MirrorActiveUids.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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.wm;
+
+import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
+
+import android.util.SparseIntArray;
+
+/**
+ * This is a partial mirror of {@link @com.android.server.am.ActiveUids}. It is already thread
+ * safe so the heavy service lock is not needed when updating state from activity manager (oom
+ * adjustment) or getting state from window manager (background start check).
+ */
+class MirrorActiveUids {
+    private SparseIntArray mUidStates = new SparseIntArray();
+
+    synchronized void onUidActive(int uid, int procState) {
+        mUidStates.put(uid, procState);
+    }
+
+    synchronized void onUidInactive(int uid) {
+        mUidStates.delete(uid);
+    }
+
+    synchronized void onActiveUidsCleared() {
+        mUidStates.clear();
+    }
+
+    synchronized void onUidProcStateChanged(int uid, int procState) {
+        final int index = mUidStates.indexOfKey(uid);
+        if (index >= 0) {
+            mUidStates.setValueAt(index, procState);
+        }
+    }
+
+    synchronized int getUidState(int uid) {
+        return mUidStates.get(uid, PROCESS_STATE_NONEXISTENT);
+    }
+}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 15478b4..c6c85fd 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -70,7 +70,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.am.ActivityManagerService;
-import com.android.server.wm.TaskRecord.TaskActivitiesReport;
 
 import com.google.android.collect.Sets;
 
@@ -180,7 +179,6 @@
     private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
     private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
     private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
-    private final TaskActivitiesReport mTmpReport = new TaskActivitiesReport();
 
     @VisibleForTesting
     RecentTasks(ActivityTaskManagerService service, TaskPersister taskPersister) {
@@ -1587,7 +1585,7 @@
      */
     ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
-        tr.fillTaskInfo(rti, mTmpReport);
+        tr.fillTaskInfo(rti);
         // Fill in some deprecated values
         rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
         rti.persistentId = rti.taskId;
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 34282cd..3bf437d 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -35,8 +35,6 @@
     private static final Comparator<TaskRecord> LAST_ACTIVE_TIME_COMPARATOR =
             (o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
 
-    private final TaskRecord.TaskActivitiesReport mTmpReport =
-            new TaskRecord.TaskActivitiesReport();
     private final TreeSet<TaskRecord> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
     private final ArrayList<TaskRecord> mTmpStackTasks = new ArrayList<>();
 
@@ -80,7 +78,7 @@
      */
     private RunningTaskInfo createRunningTaskInfo(TaskRecord task) {
         final RunningTaskInfo rti = new RunningTaskInfo();
-        task.fillTaskInfo(rti, mTmpReport);
+        task.fillTaskInfo(rti);
         // Fill in some deprecated values
         rti.id = rti.taskId;
         return rti;
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index bb3df02..789f987e 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -16,9 +16,11 @@
 
 package com.android.server.wm;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ITaskStackListener;
-import android.app.ActivityManager.TaskDescription;
+import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.Handler;
@@ -80,11 +82,11 @@
     };
 
     private final TaskStackConsumer mNotifyTaskMovedToFront = (l, m) -> {
-        l.onTaskMovedToFront(m.arg1);
+        l.onTaskMovedToFront((RunningTaskInfo) m.obj);
     };
 
     private final TaskStackConsumer mNotifyTaskDescriptionChanged = (l, m) -> {
-        l.onTaskDescriptionChanged(m.arg1, (TaskDescription) m.obj);
+        l.onTaskDescriptionChanged((RunningTaskInfo) m.obj);
     };
 
     private final TaskStackConsumer mNotifyActivityRequestedOrientationChanged = (l, m) -> {
@@ -92,7 +94,7 @@
     };
 
     private final TaskStackConsumer mNotifyTaskRemovalStarted = (l, m) -> {
-        l.onTaskRemovalStarted(m.arg1);
+        l.onTaskRemovalStarted((RunningTaskInfo) m.obj);
     };
 
     private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
@@ -125,7 +127,7 @@
     };
 
     private final TaskStackConsumer mNotifyActivityLaunchOnSecondaryDisplayFailed = (l, m) -> {
-        l.onActivityLaunchOnSecondaryDisplayFailed();
+        l.onActivityLaunchOnSecondaryDisplayFailed((RunningTaskInfo) m.obj, m.arg1);
     };
 
     private final TaskStackConsumer mNotifyTaskProfileLocked = (l, m) -> {
@@ -344,10 +346,11 @@
         msg.sendToTarget();
     }
 
-    void notifyActivityLaunchOnSecondaryDisplayFailed() {
+    void notifyActivityLaunchOnSecondaryDisplayFailed(TaskInfo ti, int requestedDisplayId) {
         mHandler.removeMessages(NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
         final Message msg = mHandler.obtainMessage(
-                NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG);
+                NOTIFY_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED_MSG, requestedDisplayId,
+                0 /* unused */, ti);
         forAllLocalListeners(mNotifyActivityLaunchOnSecondaryDisplayFailed, msg);
         msg.sendToTarget();
     }
@@ -366,16 +369,15 @@
         msg.sendToTarget();
     }
 
-    void notifyTaskMovedToFront(int taskId) {
-        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG,
-                taskId, 0 /* unused */);
+    void notifyTaskMovedToFront(TaskInfo ti) {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_MOVED_TO_FRONT_LISTENERS_MSG, ti);
         forAllLocalListeners(mNotifyTaskMovedToFront, msg);
         msg.sendToTarget();
     }
 
-    void notifyTaskDescriptionChanged(int taskId, TaskDescription taskDescription) {
+    void notifyTaskDescriptionChanged(TaskInfo taskInfo) {
         final Message msg = mHandler.obtainMessage(NOTIFY_TASK_DESCRIPTION_CHANGED_LISTENERS_MSG,
-                taskId, 0 /* unused */, taskDescription);
+                taskInfo);
         forAllLocalListeners(mNotifyTaskDescriptionChanged, msg);
         msg.sendToTarget();
 
@@ -393,12 +395,10 @@
      * the window manager. This allows interested parties to perform relevant animations before
      * the window disappears.
      */
-    void notifyTaskRemovalStarted(int taskId) {
-        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REMOVAL_STARTED_LISTENERS, taskId,
-                0 /* unused */);
+    void notifyTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo) {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_REMOVAL_STARTED_LISTENERS, taskInfo);
         forAllLocalListeners(mNotifyTaskRemovalStarted, msg);
         msg.sendToTarget();
-
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 9d3112f..1392762 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -341,6 +341,9 @@
     // TODO: remove after unification
     Task mTask;
 
+    /** Used by fillTaskInfo */
+    final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
+
     /**
      * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
      * ActivityInfo, Intent, TaskDescription)} instead.
@@ -2319,26 +2322,24 @@
     /**
      * Fills in a {@link TaskInfo} with information from this task.
      * @param info the {@link TaskInfo} to fill in
-     * @param reuseActivitiesReport a temporary activities report that we can reuse to fetch the
-     *                              running activities
      */
-    void fillTaskInfo(TaskInfo info, TaskActivitiesReport reuseActivitiesReport) {
-        getNumRunningActivities(reuseActivitiesReport);
+    void fillTaskInfo(TaskInfo info) {
+        getNumRunningActivities(mReuseActivitiesReport);
         info.userId = userId;
         info.stackId = getStackId();
         info.taskId = taskId;
         info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
         info.isRunning = getTopActivity() != null;
         info.baseIntent = new Intent(getBaseIntent());
-        info.baseActivity = reuseActivitiesReport.base != null
-                ? reuseActivitiesReport.base.intent.getComponent()
+        info.baseActivity = mReuseActivitiesReport.base != null
+                ? mReuseActivitiesReport.base.intent.getComponent()
                 : null;
-        info.topActivity = reuseActivitiesReport.top != null
-                ? reuseActivitiesReport.top.mActivityComponent
+        info.topActivity = mReuseActivitiesReport.top != null
+                ? mReuseActivitiesReport.top.mActivityComponent
                 : null;
         info.origActivity = origActivity;
         info.realActivity = realActivity;
-        info.numActivities = reuseActivitiesReport.numActivities;
+        info.numActivities = mReuseActivitiesReport.numActivities;
         info.lastActiveTime = lastActiveTime;
         info.taskDescription = new ActivityManager.TaskDescription(lastTaskDescription);
         info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
@@ -2346,6 +2347,15 @@
         info.configuration.setTo(getConfiguration());
     }
 
+    /**
+     * Returns a  {@link TaskInfo} with information from this task.
+     */
+    ActivityManager.RunningTaskInfo getTaskInfo() {
+        ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+        fillTaskInfo(info);
+        return info;
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("userId="); pw.print(userId);
                 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b8dae83..241f14e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -71,6 +71,7 @@
 import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.DividerSnapAlgorithm;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.internal.policy.DockedDividerUtils;
@@ -787,6 +788,14 @@
         return 0;
     }
 
+    @Override
+    void getRelativeDisplayedPosition(Point outPos) {
+        super.getRelativeDisplayedPosition(outPos);
+        final int outset = getStackOutset();
+        outPos.x -= outset;
+        outPos.y -= outset;
+    }
+
     private void updateSurfaceSize(SurfaceControl.Transaction transaction) {
         if (mSurfaceControl == null) {
             return;
@@ -807,6 +816,11 @@
         mLastSurfaceSize.set(width, height);
     }
 
+    @VisibleForTesting
+    Point getLastSurfaceSize() {
+        return mLastSurfaceSize;
+    }
+
     @Override
     void onDisplayChanged(DisplayContent dc) {
         if (mDisplayContent != null && mDisplayContent != dc) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 465f413..dceed28 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -57,6 +57,7 @@
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.Watchdog;
+import com.android.server.wm.ActivityTaskManagerService.HotPath;
 
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -408,12 +409,14 @@
         return null;
     }
 
+    @HotPath(caller = HotPath.PROCESS_CHANGE)
     public void addPackage(String packageName) {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             mPkgList.add(packageName);
         }
     }
 
+    @HotPath(caller = HotPath.PROCESS_CHANGE)
     public void clearPackageList() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             mPkgList.clear();
@@ -441,12 +444,14 @@
         mActivities.clear();
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean hasActivities() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             return !mActivities.isEmpty();
         }
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean hasVisibleActivities() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             for (int i = mActivities.size() - 1; i >= 0; --i) {
@@ -459,6 +464,7 @@
         return false;
     }
 
+    @HotPath(caller = HotPath.LRU_UPDATE)
     public boolean hasActivitiesOrRecentTasks() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             return !mActivities.isEmpty() || !mRecentTasks.isEmpty();
@@ -670,6 +676,7 @@
         void onOtherActivity();
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public int computeOomAdjFromActivities(int minTaskLayer, ComputeOomAdjCallback callback) {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             final int activitiesSize = mActivities.size();
@@ -903,6 +910,7 @@
         mRecentTasks.remove(task);
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean hasRecentTasks() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             return !mRecentTasks.isEmpty();
@@ -966,18 +974,21 @@
         return false;
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public void onTopProcChanged() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             mAtm.mVrController.onTopProcChangedLocked(this);
         }
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean isHomeProcess() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             return this == mAtm.mHomeProcess;
         }
     }
 
+    @HotPath(caller = HotPath.OOM_ADJUSTMENT)
     public boolean isPreviousProcess() {
         synchronized (mAtm.mGlobalLockWithoutBoost) {
             return this == mAtm.mPreviousProcess;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 21a557e..ab1b6ae 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -114,6 +114,7 @@
 import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
+import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER;
 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
 import static com.android.server.wm.WindowStateProto.ANIMATING_EXIT;
 import static com.android.server.wm.WindowStateProto.ANIMATOR;
@@ -4777,7 +4778,9 @@
     // then we can drop all negative layering on the windowing side and simply inherit
     // the default implementation here.
     public void assignChildLayers(Transaction t) {
-        int layer = 1;
+        // The surface of the main window might be preserved. So the child window on top of the main
+        // window should be also on top of the preserved surface.
+        int layer = PRESERVED_SURFACE_LAYER + 1;
         for (int i = 0; i < mChildren.size(); i++) {
             final WindowState w = mChildren.get(i);
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6b4d6d2..2e2da6d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -75,6 +75,7 @@
 class WindowStateAnimator {
     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
     static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;
+    static final int PRESERVED_SURFACE_LAYER = 1;
 
     /**
      * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
@@ -373,8 +374,8 @@
         if (mSurfaceController != null) {
             // Our SurfaceControl is always at layer 0 within the parent Surface managed by
             // window-state. We want this old Surface to stay on top of the new one
-            // until we do the swap, so we place it at layer 1.
-            mSurfaceController.mSurfaceControl.setLayer(1);
+            // until we do the swap, so we place it at a positive layer.
+            mSurfaceController.mSurfaceControl.setLayer(PRESERVED_SURFACE_LAYER);
         }
         mDestroyPreservedSurfaceUponRedraw = true;
         mSurfaceDestroyDeferred = true;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aae159c..4700b96 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -278,6 +278,8 @@
     private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
     private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
 
+    private static final String GSI_RUNNING_PROP = "ro.gsid.image_running";
+
     // maximum number of binder threads used for system_server
     // will be higher than the system default
     private static final int sMaxBinderThreads = 31;
@@ -1167,7 +1169,8 @@
             traceEnd();
 
             final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
-            if (hasPdb) {
+            final boolean hasGsi = SystemProperties.getInt(GSI_RUNNING_PROP, 0) > 0;
+            if (hasPdb && !hasGsi) {
                 traceBeginAndSlog("StartPersistentDataBlock");
                 mSystemServiceManager.startService(PersistentDataBlockService.class);
                 traceEnd();
@@ -2215,12 +2218,12 @@
 
     private void startContentCaptureService(@NonNull Context context) {
         // First check if it was explicitly enabled by DeviceConfig
-        boolean explicitlySupported = false;
+        boolean explicitlyEnabled = false;
         String settings = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
         if (settings != null && !settings.equalsIgnoreCase("default")) {
-            explicitlySupported = Boolean.parseBoolean(settings);
-            if (explicitlySupported) {
+            explicitlyEnabled = Boolean.parseBoolean(settings);
+            if (explicitlyEnabled) {
                 Slog.d(TAG, "ContentCaptureService explicitly enabled by DeviceConfig");
             } else {
                 Slog.d(TAG, "ContentCaptureService explicitly disabled by DeviceConfig");
@@ -2229,7 +2232,7 @@
         }
 
         // Then check if OEM overlaid the resource that defines the service.
-        if (!explicitlySupported) {
+        if (!explicitlyEnabled) {
             final String serviceName = context
                     .getString(com.android.internal.R.string.config_defaultContentCaptureService);
             if (TextUtils.isEmpty(serviceName)) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
new file mode 100644
index 0000000..b13735c
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2019 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;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.RecoverySystem;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+
+/**
+ * Test RescueParty.
+ */
+public class RescuePartyTest {
+    private static final int PERSISTENT_APP_UID = 12;
+    private static final long CURRENT_NETWORK_TIME_MILLIS = 0L;
+
+    private MockitoSession mSession;
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mMockContext;
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private ContentResolver mMockContentResolver;
+
+    private HashMap<String, String> mSystemSettingsMap;
+
+    @Before
+    public void setUp() throws Exception {
+        mSession =
+                ExtendedMockito.mockitoSession().initMocks(
+                        this)
+                        .strictness(Strictness.LENIENT)
+                        .spyStatic(SystemProperties.class)
+                        .spyStatic(Settings.Global.class)
+                        .spyStatic(Settings.Secure.class)
+                        .spyStatic(RecoverySystem.class)
+                        .spyStatic(RescueParty.class)
+                        .startMocking();
+        mSystemSettingsMap = new HashMap<>();
+
+        when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
+
+
+        // Mock SystemProperties setter and various getters
+        doAnswer((Answer<Void>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    String value = invocationOnMock.getArgument(1);
+
+                    mSystemSettingsMap.put(key, value);
+                    return null;
+                }
+        ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+        doAnswer((Answer<Boolean>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    boolean defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+                }
+        ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+        doAnswer((Answer<Integer>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    int defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Integer.parseInt(storedValue);
+                }
+        ).when(() -> SystemProperties.getInt(anyString(), anyInt()));
+
+        doAnswer((Answer<Long>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    long defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Long.parseLong(storedValue);
+                }
+        ).when(() -> SystemProperties.getLong(anyString(), anyLong()));
+
+        doReturn(CURRENT_NETWORK_TIME_MILLIS).when(() -> RescueParty.getElapsedRealtime());
+        RescueParty.resetAllThresholds();
+
+        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL,
+                Integer.toString(RescueParty.LEVEL_NONE));
+        SystemProperties.set(RescueParty.PROP_RESCUE_BOOT_COUNT, Integer.toString(0));
+        SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mSession.finishMocking();
+    }
+
+    @Test
+    public void testBootLoopDetectionWithExecutionForAllRescueLevels() {
+        noteBoot(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        noteBoot(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        noteBoot(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        noteBoot(RescueParty.TRIGGER_COUNT);
+
+        verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
+        assertEquals(RescueParty.LEVEL_FACTORY_RESET,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testPersistentAppCrashDetectionWithExecutionForAllRescueLevels() {
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_CHANGES);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+
+        verifySettingsResets(Settings.RESET_MODE_TRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT);
+
+        verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
+        assertEquals(RescueParty.LEVEL_FACTORY_RESET,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testBootLoopDetectionWithWrongInterval() {
+        noteBoot(RescueParty.TRIGGER_COUNT - 1);
+
+        // last boot is just outside of the boot loop detection window
+        doReturn(CURRENT_NETWORK_TIME_MILLIS + RescueParty.BOOT_TRIGGER_WINDOW_MILLIS + 1).when(
+                () -> RescueParty.getElapsedRealtime());
+        noteBoot(/*numTimes=*/1);
+
+        assertEquals(RescueParty.LEVEL_NONE,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testPersistentAppCrashDetectionWithWrongInterval() {
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
+
+        // last persistent app crash is just outside of the boot loop detection window
+        doReturn(CURRENT_NETWORK_TIME_MILLIS
+                + RescueParty.PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS + 1)
+                .when(() -> RescueParty.getElapsedRealtime());
+        notePersistentAppCrash(/*numTimes=*/1);
+
+        assertEquals(RescueParty.LEVEL_NONE,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testBootLoopDetectionWithProperInterval() {
+        noteBoot(RescueParty.TRIGGER_COUNT - 1);
+
+        // last boot is just inside of the boot loop detection window
+        doReturn(CURRENT_NETWORK_TIME_MILLIS + RescueParty.BOOT_TRIGGER_WINDOW_MILLIS).when(
+                () -> RescueParty.getElapsedRealtime());
+        noteBoot(/*numTimes=*/1);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testPersistentAppCrashDetectionWithProperInterval() {
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
+
+        // last persistent app crash is just inside of the boot loop detection window
+        doReturn(CURRENT_NETWORK_TIME_MILLIS
+                + RescueParty.PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS)
+                .when(() -> RescueParty.getElapsedRealtime());
+        notePersistentAppCrash(/*numTimes=*/1);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testBootLoopDetectionWithWrongTriggerCount() {
+        noteBoot(RescueParty.TRIGGER_COUNT - 1);
+        assertEquals(RescueParty.LEVEL_NONE,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testPersistentAppCrashDetectionWithWrongTriggerCount() {
+        notePersistentAppCrash(RescueParty.TRIGGER_COUNT - 1);
+        assertEquals(RescueParty.LEVEL_NONE,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    @Test
+    public void testIsAttemptingFactoryReset() {
+        noteBoot(RescueParty.TRIGGER_COUNT * 4);
+
+        verify(() -> RecoverySystem.rebootPromptAndWipeUserData(mMockContext, RescueParty.TAG));
+        assertTrue(RescueParty.isAttemptingFactoryReset());
+    }
+
+    @Test
+    public void testOnSettingsProviderPublishedExecutesRescueLevels() {
+        SystemProperties.set(RescueParty.PROP_RESCUE_LEVEL, Integer.toString(1));
+
+        RescueParty.onSettingsProviderPublished(mMockContext);
+
+        verifySettingsResets(Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
+        assertEquals(RescueParty.LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS,
+                SystemProperties.getInt(RescueParty.PROP_RESCUE_LEVEL, RescueParty.LEVEL_NONE));
+    }
+
+    private void verifySettingsResets(int resetMode) {
+        verify(() -> Settings.Global.resetToDefaultsAsUser(mMockContentResolver, null,
+                resetMode,
+                UserHandle.USER_SYSTEM));
+        verify(() -> Settings.Secure.resetToDefaultsAsUser(eq(mMockContentResolver), isNull(),
+                eq(resetMode), anyInt()));
+    }
+
+    private void noteBoot(int numTimes) {
+        for (int i = 0; i < numTimes; i++) {
+            RescueParty.noteBoot(mMockContext);
+        }
+    }
+
+    private void notePersistentAppCrash(int numTimes) {
+        for (int i = 0; i < numTimes; i++) {
+            RescueParty.notePersistentAppCrash(mMockContext, PERSISTENT_APP_UID);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index cf89cb8..aadf924 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -87,6 +87,7 @@
     MockSyntheticPasswordManager mSpManager;
     IAuthSecret mAuthSecretService;
     WindowManagerInternal mMockWindowManager;
+    FakeGsiService mGsiService;
     protected boolean mHasSecureLockScreen;
 
     @Override
@@ -101,6 +102,7 @@
         mDevicePolicyManager = mock(DevicePolicyManager.class);
         mDevicePolicyManagerInternal = mock(DevicePolicyManagerInternal.class);
         mMockWindowManager = mock(WindowManagerInternal.class);
+        mGsiService = new FakeGsiService();
 
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -137,7 +139,7 @@
         mAuthSecretService = mock(IAuthSecret.class);
         mService = new LockSettingsServiceTestable(mContext, mLockPatternUtils, mStorage,
                 mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
-                mSpManager, mAuthSecretService);
+                mSpManager, mAuthSecretService, mGsiService);
         when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
         mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
         installChildProfile(MANAGED_PROFILE_USER_ID);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeGsiService.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeGsiService.java
new file mode 100644
index 0000000..1033163
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/locksettings/FakeGsiService.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.locksettings;
+
+public class FakeGsiService {
+    private boolean mIsGsiRunning;
+
+    public boolean isGsiRunning() {
+        return mIsGsiRunning;
+    }
+
+    public void setIsGsiRunning(boolean isGsiRunning) {
+        mIsGsiRunning = isGsiRunning;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index fe683ab..74d4739 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -44,11 +44,12 @@
         private IStorageManager mStorageManager;
         private SyntheticPasswordManager mSpManager;
         private IAuthSecret mAuthSecretService;
+        private FakeGsiService mGsiService;
 
         public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
                 IActivityManager activityManager, LockPatternUtils lockPatternUtils,
                 IStorageManager storageManager, SyntheticPasswordManager spManager,
-                IAuthSecret authSecretService) {
+                IAuthSecret authSecretService, FakeGsiService gsiService) {
             super(context);
             mLockSettingsStorage = storage;
             mKeyStore = keyStore;
@@ -56,6 +57,7 @@
             mLockPatternUtils = lockPatternUtils;
             mStorageManager = storageManager;
             mSpManager = spManager;
+            mGsiService = gsiService;
         }
 
         @Override
@@ -107,14 +109,20 @@
         public int binderGetCallingUid() {
             return Process.SYSTEM_UID;
         }
+
+        @Override
+        public boolean isGsiRunning() {
+            return mGsiService.isGsiRunning();
+        }
     }
 
     protected LockSettingsServiceTestable(Context context, LockPatternUtils lockPatternUtils,
             LockSettingsStorage storage, FakeGateKeeperService gatekeeper, KeyStore keystore,
             IStorageManager storageManager, IActivityManager mActivityManager,
-            SyntheticPasswordManager spManager, IAuthSecret authSecretService) {
+            SyntheticPasswordManager spManager, IAuthSecret authSecretService,
+            FakeGsiService gsiService) {
         super(new MockInjector(context, storage, keystore, mActivityManager, lockPatternUtils,
-                storageManager, spManager, authSecretService));
+                storageManager, spManager, authSecretService, gsiService));
         mGateKeeperService = gatekeeper;
         mAuthSecretService = authSecretService;
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 0595a5b..89e155e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -554,6 +554,18 @@
         assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
     }
 
+    public void testGsiDisablesAuthSecret() throws RemoteException {
+        mGsiService.setIsGsiRunning(true);
+
+        final String password = "testGsiDisablesAuthSecret-password";
+
+        initializeCredentialUnderSP(password, PRIMARY_USER_ID);
+        assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
+                password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
+                        .getResponseCode());
+        verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class));
+    }
+
     // b/62213311
     //TODO: add non-migration work profile case, and unify/un-unify transition.
     //TODO: test token after user resets password
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 50dbaf5..d848b2d 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -16,19 +16,22 @@
 
 package com.android.server.rollback;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
+import android.content.rollback.RollbackInfo;
 import android.util.IntArray;
 import android.util.SparseLongArray;
 
@@ -42,7 +45,9 @@
 
 import java.io.File;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 @RunWith(JUnit4.class)
 public class AppDataRollbackHelperTest {
@@ -55,72 +60,54 @@
         // All users are unlocked so we should snapshot data for them.
         doReturn(true).when(helper).isUserCredentialLocked(eq(10));
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
-        AppDataRollbackHelper.SnapshotAppDataResult result = helper.snapshotAppData("com.foo.bar",
-                new int[]{10, 11});
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
+        helper.snapshotAppData(5, info);
 
-        assertEquals(2, result.pendingBackups.size());
-        assertEquals(10, result.pendingBackups.get(0));
-        assertEquals(11, result.pendingBackups.get(1));
+        assertEquals(2, info.getPendingBackups().size());
+        assertEquals(10, info.getPendingBackups().get(0));
+        assertEquals(11, info.getPendingBackups().get(1));
 
-        assertEquals(0, result.ceSnapshotInodes.size());
+        assertEquals(0, info.getCeSnapshotInodes().size());
 
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).snapshotAppData(
-                eq("com.foo.bar"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo.bar"), eq(10), eq(5), eq(Installer.FLAG_STORAGE_DE));
         inOrder.verify(installer).snapshotAppData(
-                eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo.bar"), eq(11), eq(5), eq(Installer.FLAG_STORAGE_DE));
         inOrder.verifyNoMoreInteractions();
 
         // One of the users is unlocked but the other isn't
         doReturn(false).when(helper).isUserCredentialLocked(eq(10));
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
-        when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
+        when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(239L);
 
-        result = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
-        assertEquals(1, result.pendingBackups.size());
-        assertEquals(11, result.pendingBackups.get(0));
+        PackageRollbackInfo info2 = createPackageRollbackInfo("com.foo.bar", new int[]{10, 11});
+        helper.snapshotAppData(7, info2);
+        assertEquals(1, info2.getPendingBackups().size());
+        assertEquals(11, info2.getPendingBackups().get(0));
 
-        assertEquals(1, result.ceSnapshotInodes.size());
-        assertEquals(239L, result.ceSnapshotInodes.get(10));
+        assertEquals(1, info2.getCeSnapshotInodes().size());
+        assertEquals(239L, info2.getCeSnapshotInodes().get(10));
 
         inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).snapshotAppData(
-                eq("com.foo.bar"), eq(10),
+                eq("com.foo.bar"), eq(10), eq(7),
                 eq(Installer.FLAG_STORAGE_CE | Installer.FLAG_STORAGE_DE));
         inOrder.verify(installer).snapshotAppData(
-                eq("com.foo.bar"), eq(11), eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo.bar"), eq(11), eq(7), eq(Installer.FLAG_STORAGE_DE));
         inOrder.verifyNoMoreInteractions();
     }
 
-    private static RollbackData createInProgressRollbackData(String packageName) {
-        RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1, true);
-        data.packages.add(new PackageRollbackInfo(
-                new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1),
-                new IntArray(), new ArrayList<>(), false, new IntArray(), new SparseLongArray()));
-        data.inProgress = true;
-
-        return data;
+    private static PackageRollbackInfo createPackageRollbackInfo(String packageName,
+            final int[] installedUsers) {
+        return new PackageRollbackInfo(
+                new VersionedPackage(packageName, 2), new VersionedPackage(packageName, 1),
+                new IntArray(), new ArrayList<>(), false, IntArray.wrap(installedUsers),
+                new SparseLongArray());
     }
 
-    @Test
-    public void testRestoreAppDataSnapshot_noRollbackData() throws Exception {
-        Installer installer = mock(Installer.class);
-        AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
-
-        assertFalse(helper.restoreAppData("com.foo", null, 0, 0, 0, "seinfo"));
-        verifyZeroInteractions(installer);
-    }
-
-    @Test
-    public void testRestoreAppDataSnapshot_noRollbackInProgress() throws Exception {
-        Installer installer = mock(Installer.class);
-        AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
-
-        RollbackData rd = createInProgressRollbackData("com.foo");
-        // Override the in progress flag.
-        rd.inProgress = false;
-        assertFalse(helper.restoreAppData("com.foo", rd, 0, 0, 0, "seinfo"));
-        verifyZeroInteractions(installer);
+    private static PackageRollbackInfo createPackageRollbackInfo(String packageName) {
+        return createPackageRollbackInfo(packageName, new int[] {});
     }
 
     @Test
@@ -128,18 +115,20 @@
         Installer installer = mock(Installer.class);
         AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
 
-        RollbackData rd = createInProgressRollbackData("com.foo");
-        IntArray pendingBackups = rd.packages.get(0).getPendingBackups();
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
+        IntArray pendingBackups = info.getPendingBackups();
         pendingBackups.add(10);
         pendingBackups.add(11);
 
-        assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+        assertTrue(helper.restoreAppData(13 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
+                      "seinfo"));
 
         // Should only require FLAG_STORAGE_DE here because we have a pending backup that we
         // didn't manage to execute.
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).restoreAppDataSnapshot(
-                eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
+                eq(13) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
         inOrder.verifyNoMoreInteractions();
 
         assertEquals(1, pendingBackups.size());
@@ -152,16 +141,18 @@
         AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
         doReturn(true).when(helper).isUserCredentialLocked(eq(10));
 
-        RollbackData rd = createInProgressRollbackData("com.foo");
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
 
-        assertTrue(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+        assertTrue(helper.restoreAppData(73 /* rollbackId */, info, 10 /* userId */, 1 /* appId */,
+                      "seinfo"));
 
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).restoreAppDataSnapshot(
-                eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10), eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
+                eq(73) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
         inOrder.verifyNoMoreInteractions();
 
-        ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
+        ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
         assertEquals(1, pendingRestores.size());
         assertEquals(10, pendingRestores.get(0).userId);
         assertEquals(1, pendingRestores.get(0).appId);
@@ -169,21 +160,23 @@
     }
 
     @Test
-    public void testRestoreAppDataSnapshot_availableBackupForUnockedUser() throws Exception {
+    public void testRestoreAppDataSnapshot_availableBackupForUnlockedUser() throws Exception {
         Installer installer = mock(Installer.class);
         AppDataRollbackHelper helper = spy(new AppDataRollbackHelper(installer));
         doReturn(false).when(helper).isUserCredentialLocked(eq(10));
 
-        RollbackData rd = createInProgressRollbackData("com.foo");
-        assertFalse(helper.restoreAppData("com.foo", rd, 10 /* userId */, 1, 2, "seinfo"));
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo");
+        assertFalse(helper.restoreAppData(101 /* rollbackId */, info, 10 /* userId */,
+                      1 /* appId */, "seinfo"));
 
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).restoreAppDataSnapshot(
-                eq("com.foo"), eq(1), eq(2L), eq("seinfo"), eq(10),
+                eq("com.foo"), eq(1) /* appId */, eq("seinfo"), eq(10) /* userId */,
+                eq(101) /* rollbackId */,
                 eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
         inOrder.verifyNoMoreInteractions();
 
-        ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
+        ArrayList<RestoreInfo> pendingRestores = info.getPendingRestores();
         assertEquals(0, pendingRestores.size());
     }
 
@@ -191,48 +184,99 @@
     public void destroyAppData() throws Exception {
         Installer installer = mock(Installer.class);
         AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
-        SparseLongArray ceSnapshotInodes = new SparseLongArray();
-        ceSnapshotInodes.put(11, 239L);
 
-        helper.destroyAppDataSnapshot("com.foo.bar", 10, 0L);
-        helper.destroyAppDataSnapshot("com.foo.bar", 11, 239L);
+        PackageRollbackInfo info = createPackageRollbackInfo("com.foo.bar");
+        info.putCeSnapshotInode(11, 239L);
+        helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 10 /* userId */);
+        helper.destroyAppDataSnapshot(5 /* rollbackId */, info, 11 /* userId */);
 
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).destroyAppDataSnapshot(
-                eq("com.foo.bar"), eq(10), eq(0L),
-                eq(Installer.FLAG_STORAGE_DE));
+                eq("com.foo.bar"), eq(10) /* userId */, eq(0L) /* ceSnapshotInode */,
+                eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE));
         inOrder.verify(installer).destroyAppDataSnapshot(
-                eq("com.foo.bar"), eq(11), eq(239L),
-                eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
+                eq("com.foo.bar"), eq(11) /* userId */, eq(239L) /* ceSnapshotInode */,
+                eq(5) /* rollbackId */, eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
         inOrder.verifyNoMoreInteractions();
+
+        assertEquals(0, info.getCeSnapshotInodes().size());
     }
 
     @Test
-    public void commitPendingBackupAndRestoreForUser_updatesRollbackData() throws Exception {
+    public void commitPendingBackupAndRestoreForUser() throws Exception {
         Installer installer = mock(Installer.class);
         AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
 
-        ArrayList<RollbackData> changedRollbackData = new ArrayList<>();
-        changedRollbackData.add(createInProgressRollbackData("com.foo.bar"));
+        when(installer.snapshotAppData(anyString(), anyInt(), anyInt(), anyInt())).thenReturn(53L);
 
-        when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
+        // This one should be backed up.
+        PackageRollbackInfo pendingBackup = createPackageRollbackInfo("com.foo", new int[]{37, 73});
+        pendingBackup.addPendingBackup(37);
 
-        ArrayList<String> pendingBackups = new ArrayList<>();
-        pendingBackups.add("com.foo.bar");
+        // Nothing should be done for this one.
+        PackageRollbackInfo wasRecentlyRestored = createPackageRollbackInfo("com.bar",
+                new int[]{37, 73});
+        wasRecentlyRestored.addPendingBackup(37);
+        wasRecentlyRestored.getPendingRestores().add(
+                new RestoreInfo(37 /* userId */, 239 /* appId*/, "seInfo"));
 
-        helper.commitPendingBackupAndRestoreForUser(11, pendingBackups,
-                new HashMap<>() /* pendingRestores */, changedRollbackData);
+        // This one should be restored
+        PackageRollbackInfo pendingRestore = createPackageRollbackInfo("com.abc",
+                new int[]{37, 73});
+        pendingRestore.putCeSnapshotInode(37, 1543L);
+        pendingRestore.getPendingRestores().add(
+                new RestoreInfo(37 /* userId */, 57 /* appId*/, "seInfo"));
 
-        assertEquals(1, changedRollbackData.size());
-        assertEquals(1, changedRollbackData.get(0).packages.size());
-        PackageRollbackInfo info = changedRollbackData.get(0).packages.get(0);
+        // This one shouldn't be processed, because it hasn't pending backups/restores for userId
+        // 37.
+        PackageRollbackInfo ignoredInfo = createPackageRollbackInfo("com.bar",
+                new int[]{3, 73});
+        wasRecentlyRestored.addPendingBackup(3);
+        wasRecentlyRestored.addPendingBackup(73);
+        wasRecentlyRestored.getPendingRestores().add(
+                new RestoreInfo(73 /* userId */, 239 /* appId*/, "seInfo"));
 
-        assertEquals(1, info.getCeSnapshotInodes().size());
-        assertEquals(239L, info.getCeSnapshotInodes().get(11));
+        RollbackData dataWithPendingBackup = new RollbackData(101, new File("/does/not/exist"), -1,
+                true);
+        dataWithPendingBackup.packages.add(pendingBackup);
 
+        RollbackData dataWithRecentRestore = new RollbackData(17239, new File("/does/not/exist"),
+                -1, true);
+        dataWithRecentRestore.packages.add(wasRecentlyRestored);
+
+        RollbackData dataForDifferentUser = new RollbackData(17239, new File("/does/not/exist"),
+                -1, true);
+        dataForDifferentUser.packages.add(ignoredInfo);
+
+        RollbackInfo rollbackInfo = new RollbackInfo(17239,
+                Arrays.asList(pendingRestore, wasRecentlyRestored), false);
+
+        List<RollbackData> changed = helper.commitPendingBackupAndRestoreForUser(37,
+                Arrays.asList(dataWithPendingBackup, dataWithRecentRestore, dataForDifferentUser),
+                Collections.singletonList(rollbackInfo));
         InOrder inOrder = Mockito.inOrder(installer);
-        inOrder.verify(installer).snapshotAppData("com.foo.bar", 11 /* userId */,
-                Installer.FLAG_STORAGE_CE);
+
+        // Check that pending backup and restore for the same package mutually destroyed each other.
+        assertEquals(-1, wasRecentlyRestored.getPendingBackups().indexOf(37));
+        assertNull(wasRecentlyRestored.getRestoreInfo(37));
+
+        // Check that backup was performed.
+        inOrder.verify(installer).snapshotAppData(eq("com.foo"), eq(37), eq(101),
+                eq(Installer.FLAG_STORAGE_CE));
+        assertEquals(-1, pendingBackup.getPendingBackups().indexOf(37));
+        assertEquals(53, pendingBackup.getCeSnapshotInodes().get(37));
+
+        // Check that changed returns correct RollbackData.
+        assertEquals(2, changed.size());
+        assertEquals(dataWithPendingBackup, changed.get(0));
+        assertEquals(dataWithRecentRestore, changed.get(1));
+
+        // Check that restore was performed.
+        inOrder.verify(installer).restoreAppDataSnapshot(
+                eq("com.abc"), eq(57) /* appId */, eq("seInfo"), eq(37) /* userId */,
+                eq(17239) /* rollbackId */, eq(Installer.FLAG_STORAGE_CE));
+        assertNull(pendingRestore.getRestoreInfo(37));
+
         inOrder.verifyNoMoreInteractions();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 8d9b3cf..e74b959 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -22,13 +22,14 @@
 
 import static org.testng.Assert.assertEquals;
 
-import android.app.usage.EventList;
+import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.util.AtomicFile;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +39,7 @@
 import org.junit.runner.RunWith;
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.List;
 import java.util.Locale;
@@ -127,10 +129,6 @@
         mIntervalStats.keyguardHiddenTracker.count = 5;
         mIntervalStats.keyguardHiddenTracker.duration = 4444444;
 
-        if (mIntervalStats.events == null) {
-            mIntervalStats.events = new EventList();
-        }
-
         for (int i = 0; i < numberOfEvents; i++) {
             Event event = new Event();
             final int packageInt = ((i / 3) % 7); //clusters of 3 events from 7 "apps"
@@ -317,20 +315,9 @@
             }
         }
         assertEquals(stats1.activeConfiguration, stats2.activeConfiguration);
-
-        if (stats1.events == null) {
-            // If stats1 events are null, stats2 should be null or empty
-            if (stats2.events != null) {
-                assertEquals(stats2.events.size(), 0);
-            }
-        } else if (stats2.events == null) {
-            // If stats2 events are null, stats1 should be null or empty
-            assertEquals(stats1.events.size(), 0);
-        } else {
-            assertEquals(stats1.events.size(), stats2.events.size());
-            for (int i = 0; i < stats1.events.size(); i++) {
-                compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i, minVersion);
-            }
+        assertEquals(stats1.events.size(), stats2.events.size());
+        for (int i = 0; i < stats1.events.size(); i++) {
+            compareUsageEvent(stats1.events.get(i), stats2.events.get(i), i, minVersion);
         }
     }
 
@@ -418,7 +405,7 @@
         // Clear non backed up data from expected IntervalStats
         mIntervalStats.activeConfiguration = null;
         mIntervalStats.configurations.clear();
-        if (mIntervalStats.events != null) mIntervalStats.events.clear();
+        mIntervalStats.events.clear();
 
         // The written and read IntervalStats should match
         compareIntervalStats(mIntervalStats, stats.get(0), version);
@@ -448,4 +435,45 @@
         runBackupRestoreTest(0);
         runBackupRestoreTest(99999);
     }
+
+    /**
+     * Test the pruning in indexFilesLocked() that only allow up to 100 daily files, 50 weekly files
+     * , 12 monthly files, 10 yearly files.
+     */
+    @Test
+    public void testMaxFiles() throws IOException {
+        final File[] intervalDirs = new File[]{
+            new File(mTestDir, "daily"),
+            new File(mTestDir, "weekly"),
+            new File(mTestDir, "monthly"),
+            new File(mTestDir, "yearly"),
+        };
+        // Create 10 extra files under each interval dir.
+        final int extra = 10;
+        final int length = intervalDirs.length;
+        for (int i = 0; i < length; i++) {
+            final int numFiles = UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra;
+            for (int f = 0; f < numFiles; f++) {
+                final AtomicFile file = new AtomicFile(new File(intervalDirs[i], Long.toString(f)));
+                FileOutputStream fos = file.startWrite();
+                fos.write(1);
+                file.finishWrite(fos);
+            }
+        }
+        // indexFilesLocked() list files under each interval dir, if number of files are more than
+        // the max allowed files for each interval type, it deletes the lowest numbered files.
+        mUsageStatsDatabase.forceIndexFiles();
+        final int len = mUsageStatsDatabase.mSortedStatFiles.length;
+        for (int i = 0; i < len; i++) {
+            final TimeSparseArray<AtomicFile> files =  mUsageStatsDatabase.mSortedStatFiles[i];
+            // The stats file for each interval type equals to max allowed.
+            assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i],
+                    files.size());
+            // The highest numbered file,
+            assertEquals(UsageStatsDatabase.MAX_FILES_PER_INTERVAL_TYPE[i] + extra - 1,
+                    files.keyAt(files.size() - 1));
+            // The lowest numbered file:
+            assertEquals(extra, files.keyAt(0));
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 392b010..606ab31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -661,8 +661,8 @@
         doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
                 .isAnyNonToastWindowVisibleForUid(realCallingUid);
         // process importance
-        doReturn(callingUidProcState).when(mService).getUidStateLocked(callingUid);
-        doReturn(realCallingUidProcState).when(mService).getUidStateLocked(realCallingUid);
+        doReturn(callingUidProcState).when(mService).getUidState(callingUid);
+        doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
         // foreground activities
         final IApplicationThread caller = mock(IApplicationThread.class);
         final ApplicationInfo ai = new ApplicationInfo();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index abc0bd6..afd4ec1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -74,7 +74,6 @@
 import com.android.server.wm.utils.MockTracker;
 
 import org.junit.After;
-import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -89,8 +88,6 @@
 class ActivityTestsBase {
     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
 
-    private static MockTracker sMockTracker;
-
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
@@ -102,6 +99,8 @@
     RootActivityContainer mRootActivityContainer;
     ActivityStackSupervisor mSupervisor;
 
+    private MockTracker mMockTracker;
+
     // Default package name
     static final String DEFAULT_COMPONENT_PACKAGE_NAME = "com.foo";
 
@@ -110,19 +109,13 @@
 
     @BeforeClass
     public static void setUpOnceBase() {
-        sMockTracker = new MockTracker();
-
         AttributeCache.init(getInstrumentation().getTargetContext());
     }
 
-    @AfterClass
-    public static void tearDownOnceBase() {
-        sMockTracker.close();
-        sMockTracker = null;
-    }
-
     @Before
     public void setUpBase() {
+        mMockTracker = new MockTracker();
+
         mTestInjector.setUp();
 
         mService = new TestActivityTaskManagerService(mContext);
@@ -137,6 +130,9 @@
             mService.setWindowManager(null);
             mService = null;
         }
+
+        mMockTracker.close();
+        mMockTracker = null;
     }
 
     /** Creates a {@link TestActivityDisplay}. */
@@ -598,7 +594,7 @@
             doNothing().when(this).acquireLaunchWakelock();
             doReturn(mKeyguardController).when(this).getKeyguardController();
 
-            mLaunchingActivity = mock(PowerManager.WakeLock.class);
+            mLaunchingActivityWakeLock = mock(PowerManager.WakeLock.class);
 
             initialize();
         }
@@ -651,7 +647,10 @@
 
         @Override
         protected DisplayContent createDisplayContent() {
-            return WindowTestUtils.createTestDisplayContent();
+            final DisplayContent displayContent = mock(DisplayContent.class);
+            DockedStackDividerController divider = mock(DockedStackDividerController.class);
+            doReturn(divider).when(displayContent).getDockedDividerController();
+            return displayContent;
         }
 
         void removeAllTasks() {
@@ -732,14 +731,13 @@
 
         @Override
         protected void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
-            mTaskStack = WindowTestUtils.createMockTaskStack();
+            mTaskStack = mock(TaskStack.class);
 
             // Primary pinned stacks require a non-empty out bounds to be set or else all tasks
             // will be moved to the full screen stack.
             if (getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                 outBounds.set(0, 0, 100, 100);
             }
-
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 123de2d..afadc79 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -24,14 +24,13 @@
 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -39,9 +38,7 @@
 
 import androidx.test.filters.SmallTest;
 
-import org.junit.AfterClass;
 import org.junit.Before;
-import org.junit.BeforeClass;
 import org.junit.Test;
 
 /**
@@ -54,33 +51,12 @@
 @Presubmit
 public class AppTransitionTests extends WindowTestsBase {
 
-    private static RootWindowContainer sOriginalRootWindowContainer;
-
     private DisplayContent mDc;
 
-    @BeforeClass
-    public static void setUpRootWindowContainerMock() {
-        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
-        // For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
-        // interaction with surfaceflinger native side.
-        sOriginalRootWindowContainer = wm.mRoot;
-        // Creating spied mock of RootWindowContainer shouldn't be done in @Before, since it will
-        // create unnecessary nested spied objects chain, because WindowManagerService object under
-        // test is a single instance shared among all tests that extend WindowTestsBase class.
-        // Instead it should be done once before running all tests in this test class.
-        wm.mRoot = spy(wm.mRoot);
-        doNothing().when(wm.mRoot).performSurfacePlacement(anyBoolean());
-    }
-
-    @AfterClass
-    public static void tearDownRootWindowContainerMock() {
-        final WindowManagerService wm = TestSystemServices.getWindowManagerService();
-        wm.mRoot = sOriginalRootWindowContainer;
-        sOriginalRootWindowContainer = null;
-    }
-
     @Before
     public void setUp() throws Exception {
+        spyOn(mWm.mRoot);
+        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
         mDc = mWm.getDefaultDisplayContentLocked();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index dd5f32d..108ee180b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -27,10 +27,9 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 
+import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 
-import androidx.test.filters.SmallTest;
-
 import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
 
 import org.junit.Before;
@@ -39,13 +38,18 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
 /**
  * Animation related tests for the {@link AppWindowToken} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:AppWindowTokenAnimationTests
+ *  atest AppWindowTokenAnimationTests
  */
 @SmallTest
+@Presubmit
+@FlakyTest(bugId = 124357362)
 public class AppWindowTokenAnimationTests extends WindowTestsBase {
 
     private TestAppWindowToken mToken;
@@ -60,7 +64,7 @@
         MockitoAnnotations.initMocks(this);
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
-                ACTIVITY_TYPE_STANDARD);
+                ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
         mToken.setPendingTransaction(mTransaction);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 2452ef0..b1b8e8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -57,6 +57,7 @@
 import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.metrics.LogMaker;
 import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
@@ -71,10 +72,13 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -669,6 +673,28 @@
         }
     }
 
+    @Test
+    public void testOrientationChangeLogging() {
+        MetricsLogger mockLogger = mock(MetricsLogger.class);
+        Configuration oldConfig = new Configuration();
+        oldConfig.orientation = Configuration.ORIENTATION_LANDSCAPE;
+
+        Configuration newConfig = new Configuration();
+        newConfig.orientation = Configuration.ORIENTATION_PORTRAIT;
+        final DisplayContent displayContent = spy(createNewDisplay());
+        Mockito.doReturn(mockLogger).when(displayContent).getMetricsLogger();
+        Mockito.doReturn(oldConfig).doReturn(newConfig).when(displayContent).getConfiguration();
+
+        displayContent.onConfigurationChanged(newConfig);
+
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        verify(mockLogger).write(logMakerCaptor.capture());
+        assertThat(logMakerCaptor.getValue().getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_PHONE_ORIENTATION_CHANGED));
+        assertThat(logMakerCaptor.getValue().getSubtype(),
+                is(Configuration.ORIENTATION_PORTRAIT));
+    }
+
     private boolean isOptionsPanelAtRight(int displayId) {
         return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 7be331c..85b2f7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -26,11 +26,11 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -65,8 +65,7 @@
     DisplayPolicy mDisplayPolicy;
 
     @Before
-    public void setUpBase() {
-        super.setUpBase();
+    public void setUpDisplayPolicy() {
         mDisplayPolicy = spy(mDisplayContent.getDisplayPolicy());
 
         final TestContextWrapper context =
@@ -77,9 +76,9 @@
         resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
         resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
         resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
-        when(mDisplayPolicy.getSystemUiContext()).thenReturn(context);
-        when(mDisplayPolicy.hasNavigationBar()).thenReturn(true);
-        when(mDisplayPolicy.hasStatusBar()).thenReturn(true);
+        doReturn(context).when(mDisplayPolicy).getSystemUiContext();
+        doReturn(true).when(mDisplayPolicy).hasNavigationBar();
+        doReturn(true).when(mDisplayPolicy).hasStatusBar();
 
         final int shortSizeDp =
                 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index b15e99a..8733674 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -807,7 +807,7 @@
         private void build() throws Exception {
             mMockContext = mock(Context.class);
 
-            mMockDisplayContent = mock(WindowTestUtils.TestDisplayContent.class);
+            mMockDisplayContent = mock(DisplayContent.class);
             mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
             when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
                     .thenReturn(WmDisplayCutout.NO_CUTOUT);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
similarity index 66%
rename from services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
rename to services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index e540b3a..712cd1e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -57,44 +57,61 @@
 import com.android.server.Watchdog;
 import com.android.server.input.InputManagerService;
 import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.utils.MockTracker;
 
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.quality.Strictness;
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * A Test utility class to create a mock {@link WindowManagerService} instance for tests.
+ * JUnit test rule to create a mock {@link WindowManagerService} instance for tests.
  */
-class TestSystemServices {
-    private static StaticMockitoSession sMockitoSession;
-    private static WindowManagerService sService;
-    private static TestWindowManagerPolicy sPolicy;
+public class SystemServicesTestRule implements TestRule {
 
-    static AtomicBoolean sCurrentMessagesProcessed = new AtomicBoolean(false);
+    private static final String TAG = SystemServicesTestRule.class.getSimpleName();
 
-    static void setUpWindowManagerService() {
-        sMockitoSession = mockitoSession()
-                .spyStatic(LockGuard.class)
-                .spyStatic(Watchdog.class)
+    private final AtomicBoolean mCurrentMessagesProcessed = new AtomicBoolean(false);
+
+    private MockTracker mMockTracker;
+    private StaticMockitoSession mMockitoSession;
+    private WindowManagerService mWindowManagerService;
+    private TestWindowManagerPolicy mWindowManagerPolicy;
+
+    /** {@link MockTracker} to track mocks created by {@link SystemServicesTestRule}. */
+    private static class Tracker extends MockTracker {
+        // This empty extended class is necessary since Mockito distinguishes a listener by it
+        // class.
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    runWithDexmakerShareClassLoader(SystemServicesTestRule.this::setUp);
+                    base.evaluate();
+                } finally {
+                    tearDown();
+                }
+            }
+        };
+    }
+
+    private void setUp() {
+        mMockTracker = new Tracker();
+
+        mMockitoSession = mockitoSession()
+                .spyStatic(LocalServices.class)
+                .mockStatic(LockGuard.class)
+                .mockStatic(Watchdog.class)
                 .strictness(Strictness.LENIENT)
                 .startMocking();
 
-        runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService);
-    }
-
-    static void tearDownWindowManagerService() {
-        waitUntilWindowManagerHandlersIdle();
-        removeLocalServices();
-        sService = null;
-        sPolicy = null;
-
-        sMockitoSession.finishMocking();
-        sMockitoSession = null;
-    }
-
-    private static void setUpTestWindowService() {
-        doReturn(null).when(() -> LockGuard.installLock(any(), anyInt()));
         doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
 
         final Context context = getInstrumentation().getTargetContext();
@@ -116,21 +133,18 @@
         doReturn(appOpsManager).when(context)
                 .getSystemService(eq(Context.APP_OPS_SERVICE));
 
-        removeLocalServices();
-
         final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
-        LocalServices.addService(DisplayManagerInternal.class, dmi);
+        doReturn(dmi).when(() -> LocalServices.getService(eq(DisplayManagerInternal.class)));
 
         final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
-        LocalServices.addService(PowerManagerInternal.class, pmi);
         final PowerSaveState state = new PowerSaveState.Builder().build();
         doReturn(state).when(pmi).getLowPowerState(anyInt());
+        doReturn(pmi).when(() -> LocalServices.getService(eq(PowerManagerInternal.class)));
 
         final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
-        LocalServices.addService(ActivityManagerInternal.class, ami);
+        doReturn(ami).when(() -> LocalServices.getService(eq(ActivityManagerInternal.class)));
 
         final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
-        LocalServices.addService(ActivityTaskManagerInternal.class, atmi);
         doAnswer((InvocationOnMock invocationOnMock) -> {
             final Runnable runnable = invocationOnMock.getArgument(0);
             if (runnable != null) {
@@ -138,6 +152,7 @@
             }
             return null;
         }).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
+        doReturn(atmi).when(() -> LocalServices.getService(eq(ActivityTaskManagerInternal.class)));
 
         final InputManagerService ims = mock(InputManagerService.class);
         // InputChannel is final and can't be mocked.
@@ -150,31 +165,46 @@
         final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
         doReturn(wmLock).when(atms).getGlobalLock();
 
-        sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService);
-        sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
+        mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService);
+        mWindowManagerService = WindowManagerService.main(
+                context, ims, false, false, mWindowManagerPolicy, atms);
 
-        sService.onInitReady();
+        mWindowManagerService.onInitReady();
 
-        final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+        final Display display = mWindowManagerService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
         // Display creation is driven by the ActivityManagerService via
         // ActivityStackSupervisor. We emulate those steps here.
-        sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+        mWindowManagerService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
+
+        mMockTracker.stopTracking();
+    }
+
+    private void tearDown() {
+        waitUntilWindowManagerHandlersIdle();
+        removeLocalServices();
+        mWindowManagerService = null;
+        mWindowManagerPolicy = null;
+        if (mMockitoSession != null) {
+            mMockitoSession.finishMocking();
+            mMockitoSession = null;
+        }
+
+        if (mMockTracker != null) {
+            mMockTracker.close();
+            mMockTracker = null;
+        }
     }
 
     private static void removeLocalServices() {
-        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
-        LocalServices.removeServiceForTest(PowerManagerInternal.class);
-        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
-        LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.removeServiceForTest(WindowManagerPolicy.class);
     }
 
-    static WindowManagerService getWindowManagerService() {
-        return sService;
+    WindowManagerService getWindowManagerService() {
+        return mWindowManagerService;
     }
 
-    static void cleanupWindowManagerHandlers() {
+    void cleanupWindowManagerHandlers() {
         final WindowManagerService wm = getWindowManagerService();
         if (wm == null) {
             return;
@@ -184,7 +214,7 @@
         SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null);
     }
 
-    static void waitUntilWindowManagerHandlersIdle() {
+    void waitUntilWindowManagerHandlersIdle() {
         final WindowManagerService wm = getWindowManagerService();
         if (wm == null) {
             return;
@@ -196,21 +226,21 @@
         waitHandlerIdle(SurfaceAnimationThread.getHandler());
     }
 
-    private static void waitHandlerIdle(Handler handler) {
-        synchronized (sCurrentMessagesProcessed) {
+    private void waitHandlerIdle(Handler handler) {
+        synchronized (mCurrentMessagesProcessed) {
             // Add a message to the handler queue and make sure it is fully processed before we move
             // on. This makes sure all previous messages in the handler are fully processed vs. just
             // popping them from the message queue.
-            sCurrentMessagesProcessed.set(false);
+            mCurrentMessagesProcessed.set(false);
             handler.post(() -> {
-                synchronized (sCurrentMessagesProcessed) {
-                    sCurrentMessagesProcessed.set(true);
-                    sCurrentMessagesProcessed.notifyAll();
+                synchronized (mCurrentMessagesProcessed) {
+                    mCurrentMessagesProcessed.set(true);
+                    mCurrentMessagesProcessed.notifyAll();
                 }
             });
-            while (!sCurrentMessagesProcessed.get()) {
+            while (!mCurrentMessagesProcessed.get()) {
                 try {
-                    sCurrentMessagesProcessed.wait();
+                    mCurrentMessagesProcessed.wait();
                 } catch (InterruptedException e) {
                 }
             }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 1e58e41..1b396f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -18,6 +18,8 @@
 
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -26,7 +28,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
 
 import android.platform.test.annotations.Presubmit;
 import android.view.InputChannel;
@@ -63,8 +64,7 @@
         }
 
         spyOn(mDisplayContent);
-        InputMonitor inputMonitor = mock(InputMonitor.class);
-        when(mDisplayContent.getInputMonitor()).thenReturn(inputMonitor);
+        doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 388f98f..5d07888 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -38,6 +38,7 @@
 import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager;
+import android.app.TaskInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
@@ -109,8 +110,7 @@
     public void testCopyBaseIntentForTaskInfo() {
         final TaskRecord task = createTaskRecord(1);
         task.lastTaskDescription = new ActivityManager.TaskDescription();
-        final ActivityManager.RecentTaskInfo info = new ActivityManager.RecentTaskInfo();
-        task.fillTaskInfo(info, new TaskRecord.TaskActivitiesReport());
+        final TaskInfo info = task.getTaskInfo();
 
         // The intent of info should be a copy so assert that they are different instances.
         assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index 2554237..b1f942e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -19,6 +19,9 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
@@ -168,4 +171,22 @@
         assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
         assertTrue(task1.mOnDisplayChangedCalled);
     }
+
+    @Test
+    public void testStackOutset() {
+        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        spyOn(stack);
+
+        final int stackOutset = 10;
+        doReturn(stackOutset).when(stack).getStackOutset();
+
+        final Rect stackBounds = new Rect(200, 200, 800, 1000);
+        // Update surface position and size by the given bounds.
+        stack.setBounds(stackBounds);
+
+        assertEquals(stackBounds.width() + 2 * stackOutset, stack.getLastSurfaceSize().x);
+        assertEquals(stackBounds.height() + 2 * stackOutset, stack.getLastSurfaceSize().y);
+        assertEquals(stackBounds.left - stackOutset, stack.getLastSurfacePosition().x);
+        assertEquals(stackBounds.top - stackOutset, stack.getLastSurfacePosition().y);
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
index fb30f8b..61c1d39 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowFrameTests.java
@@ -118,7 +118,7 @@
     public void setUp() throws Exception {
         mWindowToken = createAppWindowToken(mWm.getDefaultDisplayContentLocked(),
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
-        mStubStack = WindowTestUtils.createMockTaskStack();
+        mStubStack = mock(TaskStack.class);
     }
 
     // Do not use this function directly in the tests below. Instead, use more explicit function
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 114eac9..5bfa0c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -20,97 +20,25 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 import android.app.ActivityManager;
 import android.content.ComponentName;
-import android.content.Context;
-import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.view.Display;
 import android.view.IApplicationToken;
 import android.view.IWindow;
-import android.view.Surface;
 import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
 /**
- * A collection of static functions that can be referenced by other test packages to provide access
- * to WindowManager related test functionality.
+ * A collection of static functions that provide access to WindowManager related test functionality.
  */
-public class WindowTestUtils {
+class WindowTestUtils {
     private static int sNextTaskId = 0;
 
-    /** An extension of {@link DisplayContent} to gain package scoped access. */
-    public static class TestDisplayContent extends DisplayContent {
-
-        private TestDisplayContent(Display display, WindowManagerService service,
-                ActivityDisplay activityDisplay) {
-            super(display, service, activityDisplay);
-        }
-
-        /**
-         * Stubbing method of non-public parent class isn't supported, so here explicitly overrides.
-         */
-        @Override
-        public DisplayRotation getDisplayRotation() {
-            return null;
-        }
-
-        /**
-         * Stubbing method of non-public parent class isn't supported, so here explicitly overrides.
-         */
-        @Override
-        DockedStackDividerController getDockedDividerController() {
-            return null;
-        }
-
-        /** Create a mocked default {@link DisplayContent}. */
-        public static TestDisplayContent create(Context context) {
-            final TestDisplayContent displayContent = mock(TestDisplayContent.class);
-            displayContent.isDefaultDisplay = true;
-
-            final DisplayPolicy displayPolicy = mock(DisplayPolicy.class);
-            when(displayPolicy.navigationBarCanMove()).thenReturn(true);
-            when(displayPolicy.hasNavigationBar()).thenReturn(true);
-
-            final DisplayRotation displayRotation = new DisplayRotation(
-                    mock(WindowManagerService.class), displayContent, displayPolicy,
-                    mock(DisplayWindowSettings.class), context, new Object());
-            displayRotation.mPortraitRotation = Surface.ROTATION_0;
-            displayRotation.mLandscapeRotation = Surface.ROTATION_90;
-            displayRotation.mUpsideDownRotation = Surface.ROTATION_180;
-            displayRotation.mSeascapeRotation = Surface.ROTATION_270;
-
-            when(displayContent.getDisplayRotation()).thenReturn(displayRotation);
-
-            return displayContent;
-        }
-    }
-
-    /** Create a mocked default {@link DisplayContent}. */
-    public static TestDisplayContent createTestDisplayContent() {
-        final TestDisplayContent displayContent = mock(TestDisplayContent.class);
-        DockedStackDividerController divider = mock(DockedStackDividerController.class);
-        when(displayContent.getDockedDividerController()).thenReturn(divider);
-
-        return displayContent;
-    }
-
-    /**
-     * Creates a mock instance of {@link TestTaskStack}.
-     */
-    public static TaskStack createMockTaskStack() {
-        return mock(TestTaskStack.class);
-    }
-
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
-    public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
+    static Task createTaskInStack(WindowManagerService service, TaskStack stack,
             int userId) {
         synchronized (service.mGlobalLock) {
             final Task newTask = new Task(sNextTaskId++, stack, userId, service, 0, false,
@@ -121,41 +49,33 @@
     }
 
     /** Creates an {@link AppWindowToken} and adds it to the specified {@link Task}. */
-    public static TestAppWindowToken createAppWindowTokenInTask(DisplayContent dc, Task task) {
+    static TestAppWindowToken createAppWindowTokenInTask(DisplayContent dc, Task task) {
         final TestAppWindowToken newToken = createTestAppWindowToken(dc);
         task.addChild(newToken, POSITION_TOP);
         return newToken;
     }
 
-    /**
-     * An extension of {@link TestTaskStack}, which overrides package scoped methods that would not
-     * normally be mocked out.
-     */
-    public static class TestTaskStack extends TaskStack {
-        TestTaskStack(WindowManagerService service, int stackId) {
-            super(service, stackId, null);
-        }
-
-        @Override
-        void addTask(Task task, int position, boolean showForAllUsers, boolean moveParents) {
-            // Do nothing.
+    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
+        synchronized (dc.mWmService.mGlobalLock) {
+            return new TestAppWindowToken(dc, true /* skipOnParentChanged */);
         }
     }
 
-    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc) {
+    static TestAppWindowToken createTestAppWindowToken(DisplayContent dc,
+            boolean skipOnParentChanged) {
         synchronized (dc.mWmService.mGlobalLock) {
-            return new TestAppWindowToken(dc);
+            return new TestAppWindowToken(dc, skipOnParentChanged);
         }
     }
 
     /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
-    public static class TestAppWindowToken extends AppWindowToken {
+    static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
         private boolean mSkipPrepareSurfaces;
         private Transaction mPendingTransactionOverride;
         boolean mSkipOnParentChanged = true;
 
-        private TestAppWindowToken(DisplayContent dc) {
+        private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
             super(dc.mWmService, new IApplicationToken.Stub() {
                 @Override
                 public String getName() {
@@ -163,17 +83,7 @@
                 }
             }, new ComponentName("", ""), false, dc, true /* fillsParent */);
             mTargetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT;
-        }
-
-        TestAppWindowToken(WindowManagerService service, IApplicationToken token,
-                ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
-                long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
-                int targetSdk, int orientation, int rotationAnimationHint, int configChanges,
-                boolean launchTaskBehind, boolean alwaysFocusable, ActivityRecord activityRecord) {
-            super(service, token, activityComponent, voiceInteraction, dc,
-                    inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk,
-                    orientation, rotationAnimationHint, configChanges, launchTaskBehind,
-                    alwaysFocusable, activityRecord);
+            mSkipOnParentChanged = skipOnParentChanged;
         }
 
         int getWindowsCount() {
@@ -192,14 +102,6 @@
             return mChildren.peekLast();
         }
 
-        int positionInParent() {
-            return getParent().mChildren.indexOf(this);
-        }
-
-        void setIsOnTop(boolean onTop) {
-            mOnTop = onTop;
-        }
-
         @Override
         void onParentChanged() {
             if (!mSkipOnParentChanged) {
@@ -264,7 +166,7 @@
     }
 
     /* Used so we can gain access to some protected members of the {@link WindowToken} class */
-    public static class TestWindowToken extends WindowToken {
+    static class TestWindowToken extends WindowToken {
 
         private TestWindowToken(int type, DisplayContent dc, boolean persistOnEmpty) {
             super(dc.mWmService, mock(IBinder.class), type, persistOnEmpty, dc,
@@ -281,7 +183,7 @@
     }
 
     /* Used so we can gain access to some protected members of the {@link Task} class */
-    public static class TestTask extends Task {
+    static class TestTask extends Task {
         boolean mShouldDeferRemoval = false;
         boolean mOnDisplayChangedCalled = false;
         private boolean mIsAnimating = false;
@@ -318,26 +220,13 @@
         }
     }
 
-    public static TestTask createTestTask(TaskStack stack) {
+    static TestTask createTestTask(TaskStack stack) {
         return new TestTask(sNextTaskId++, stack, 0, stack.mWmService, RESIZE_MODE_UNRESIZEABLE,
                 false, mock(TaskRecord.class));
     }
 
-    public static class TestIApplicationToken implements IApplicationToken {
-
-        private final Binder mBinder = new Binder();
-        @Override
-        public IBinder asBinder() {
-            return mBinder;
-        }
-        @Override
-        public String getName() {
-            return null;
-        }
-    }
-
     /** Used to track resize reports. */
-    public static class TestWindowState extends WindowState {
+    static class TestWindowState extends WindowState {
         boolean mResizeReported;
 
         TestWindowState(WindowManagerService service, Session session, IWindow window,
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index a83bf2a..0d7d085 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -58,6 +58,7 @@
 import org.junit.BeforeClass;
 import org.junit.Rule;
 
+import java.io.IOException;
 import java.util.HashSet;
 import java.util.LinkedList;
 
@@ -78,8 +79,6 @@
     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
     static int sNextStackId = 1000;
 
-    private static MockTracker sMockTracker;
-
     /** Non-default display. */
     DisplayContent mDisplayContent;
     DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -94,6 +93,8 @@
     WindowState mChildAppWindowBelow;
     HashSet<WindowState> mCommonWindows;
 
+    private MockTracker mMockTracker;
+
     /**
      * To restore the original SurfaceControl.Transaction factory if any tests changed
      * {@link WindowManagerService#mTransactionFactory}.
@@ -103,6 +104,8 @@
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
+    @Rule
+    public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule();
 
     static WindowState.PowerManagerWrapper sPowerManagerWrapper;
 
@@ -110,25 +113,18 @@
     public static void setUpOnceBase() {
         AttributeCache.init(getInstrumentation().getTargetContext());
 
-        TestSystemServices.setUpWindowManagerService();
-
-        // MockTracker needs to be initialized after TestSystemServices because we don't want to
-        // track static mocks.
-        sMockTracker = new MockTracker();
-
         sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
     }
 
     @AfterClass
-    public static void tearDownOnceBase() {
-        sMockTracker.close();
-        sMockTracker = null;
-
-        TestSystemServices.tearDownWindowManagerService();
+    public static void tearDownOnceBase() throws IOException {
+        sPowerManagerWrapper = null;
     }
 
     @Before
     public void setUpBase() {
+        mMockTracker = new MockTracker();
+
         // If @Before throws an exception, the error isn't logged. This will make sure any failures
         // in the set up are clear. This can be removed when b/37850063 is fixed.
         try {
@@ -136,7 +132,7 @@
 
             final Context context = getInstrumentation().getTargetContext();
 
-            mWm = TestSystemServices.getWindowManagerService();
+            mWm = mSystemServicesTestRule.getWindowManagerService();
             mOriginalTransactionFactory = mWm.mTransactionFactory;
             beforeCreateDisplay();
 
@@ -216,11 +212,14 @@
             }
 
             // Cleaned up everything in Handler.
-            TestSystemServices.cleanupWindowManagerHandlers();
+            mSystemServicesTestRule.cleanupWindowManagerHandlers();
         } catch (Exception e) {
             Log.e(TAG, "Failed to tear down test", e);
             throw e;
         }
+
+        mMockTracker.close();
+        mMockTracker = null;
     }
 
     private WindowState createCommonWindow(WindowState parent, int type, String name) {
@@ -237,7 +236,7 @@
      * Waits until the main handler for WM has processed all messages.
      */
     void waitUntilHandlersIdle() {
-        TestSystemServices.waitUntilWindowManagerHandlersIdle();
+        mSystemServicesTestRule.waitUntilWindowManagerHandlersIdle();
     }
 
     private WindowToken createWindowToken(
@@ -257,10 +256,16 @@
 
     WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
             windowingMode, int activityType) {
+        return createTestAppWindowToken(dc, windowingMode, activityType,
+                true /*skipOnParentChanged */);
+    }
+
+    WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
+            windowingMode, int activityType, boolean skipOnParentChanged) {
         final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final WindowTestUtils.TestAppWindowToken appWindowToken =
-                WindowTestUtils.createTestAppWindowToken(dc);
+                WindowTestUtils.createTestAppWindowToken(dc, skipOnParentChanged);
         task.addChild(appWindowToken, 0);
         return appWindowToken;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index f3b8a62..2907021 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -23,15 +23,20 @@
 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.view.WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
 
+import static com.android.server.wm.WindowStateAnimator.PRESERVED_SURFACE_LAYER;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.platform.test.annotations.Presubmit;
@@ -44,6 +49,7 @@
 import org.junit.After;
 import org.junit.Test;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 
@@ -404,6 +410,28 @@
         assertWindowHigher(mediaOverlayChild, child);
     }
 
+    @Test
+    public void testAssignWindowLayers_ForPostivelyZOrderedSubtype() {
+        final WindowState anyWindow = createWindow("anyWindow");
+        final ArrayList<WindowState> childList = new ArrayList<>();
+        childList.add(createWindow(anyWindow, TYPE_APPLICATION_PANEL, mDisplayContent,
+                "TypeApplicationPanelChild"));
+        childList.add(createWindow(anyWindow, TYPE_APPLICATION_SUB_PANEL, mDisplayContent,
+                "TypeApplicationSubPanelChild"));
+        childList.add(createWindow(anyWindow, TYPE_APPLICATION_ATTACHED_DIALOG, mDisplayContent,
+                "TypeApplicationAttachedDialogChild"));
+        childList.add(createWindow(anyWindow, TYPE_APPLICATION_ABOVE_SUB_PANEL, mDisplayContent,
+                "TypeApplicationAboveSubPanelPanelChild"));
+
+        final LayerRecordingTransaction t = mTransaction;
+        mDisplayContent.assignChildLayers(t);
+
+        for (int i = childList.size() - 1; i >= 0; i--) {
+            assertThat(t.getLayer(childList.get(i).getSurfaceControl()))
+                    .isGreaterThan(PRESERVED_SURFACE_LAYER);
+        }
+    }
+
     @FlakyTest(bugId = 124088319)
     @Test
     public void testDockedDividerPosition() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
index 1ce463b..a6e675a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -21,6 +21,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoFramework;
 import org.mockito.internal.creation.settings.CreationSettings;
+import org.mockito.internal.util.MockUtil;
 import org.mockito.listeners.MockCreationListener;
 import org.mockito.mock.MockCreationSettings;
 
@@ -33,7 +34,7 @@
  * same type registered.
  */
 public class MockTracker implements MockCreationListener, AutoCloseable {
-    private static final String TAG = "MockTracker";
+    private static final String TAG = MockTracker.class.getSimpleName();
 
     private static final Field SPIED_INSTANCE_FIELD;
 
@@ -54,6 +55,10 @@
         mMockitoFramework.addListener(this);
     }
 
+    public void stopTracking() {
+        mMockitoFramework.removeListener(this);
+    }
+
     @Override
     public void onMockCreated(Object mock, MockCreationSettings settings) {
         mMocks.put(mock, null);
@@ -83,10 +88,8 @@
         mMockitoFramework.removeListener(this);
 
         for (final Object mock : mMocks.keySet()) {
-            try {
+            if (MockUtil.isMock(mock)) {
                 Mockito.reset(mock);
-            } catch (Exception e) {
-                Log.e(TAG, "Failed to reset " + mock, e);
             }
         }
         mMocks.clear();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 0e15947..4756fb4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -43,8 +43,8 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.FilenameFilter;
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
@@ -84,6 +84,9 @@
     @VisibleForTesting
     public static final int BACKUP_VERSION = 4;
 
+    @VisibleForTesting
+    static final int[] MAX_FILES_PER_INTERVAL_TYPE = new int[]{100, 50, 12, 10};
+
     // Key under which the payload blob is stored
     // same as UsageStatsBackupHelper.KEY_USAGE_STATS
     static final String KEY_USAGE_STATS = "usage_stats";
@@ -104,7 +107,8 @@
 
     private final Object mLock = new Object();
     private final File[] mIntervalDirs;
-    private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
+    @VisibleForTesting
+    final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
     private final UnixCalendar mCal;
     private final File mVersionFile;
     private final File mBackupsDir;
@@ -126,10 +130,10 @@
     @VisibleForTesting
     public UsageStatsDatabase(File dir, int version) {
         mIntervalDirs = new File[]{
-                new File(dir, "daily"),
-                new File(dir, "weekly"),
-                new File(dir, "monthly"),
-                new File(dir, "yearly"),
+            new File(dir, "daily"),
+            new File(dir, "weekly"),
+            new File(dir, "monthly"),
+            new File(dir, "yearly"),
         };
         mCurrentVersion = version;
         mVersionFile = new File(dir, "version");
@@ -248,6 +252,14 @@
         return true;
     }
 
+    /** @hide */
+    @VisibleForTesting
+    void forceIndexFiles() {
+        synchronized (mLock) {
+            indexFilesLocked();
+        }
+    }
+
     private void indexFilesLocked() {
         final FilenameFilter backupFileFilter = new FilenameFilter() {
             @Override
@@ -255,7 +267,6 @@
                 return !name.endsWith(BAK_SUFFIX);
             }
         };
-
         // Index the available usage stat files on disk.
         for (int i = 0; i < mSortedStatFiles.length; i++) {
             if (mSortedStatFiles[i] == null) {
@@ -268,8 +279,9 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Found " + files.length + " stat files for interval " + i);
                 }
-
-                for (File f : files) {
+                final int len = files.length;
+                for (int j = 0; j < len; j++) {
+                    final File f = files[j];
                     final AtomicFile af = new AtomicFile(f);
                     try {
                         mSortedStatFiles[i].put(parseBeginTime(af), af);
@@ -277,6 +289,16 @@
                         Slog.e(TAG, "failed to index file: " + f, e);
                     }
                 }
+
+                // only keep the max allowed number of files for each interval type.
+                final int toDelete = mSortedStatFiles[i].size() - MAX_FILES_PER_INTERVAL_TYPE[i];
+                if (toDelete > 0) {
+                    for (int j = 0; j < toDelete; j++) {
+                        mSortedStatFiles[i].valueAt(0).delete();
+                        mSortedStatFiles[i].removeAt(0);
+                    }
+                    Slog.d(TAG, "Deleted " + toDelete + " stat files for interval " + i);
+                }
             }
         }
     }
@@ -908,39 +930,37 @@
             }
         }
 
-        if (statsOut.events != null) {
-            final int eventSize = statsOut.events.size();
-            for (int i = 0; i < eventSize; i++) {
-                final UsageEvents.Event event = statsOut.events.get(i);
-                if (event.mPackage.isEmpty()) {
-                    if (failures++ < failureLogLimit) {
-                        sb.append("\nUnexpected empty empty package name loaded");
-                    }
+        final int eventSize = statsOut.events.size();
+        for (int i = 0; i < eventSize; i++) {
+            final UsageEvents.Event event = statsOut.events.get(i);
+            if (event.mPackage.isEmpty()) {
+                if (failures++ < failureLogLimit) {
+                    sb.append("\nUnexpected empty empty package name loaded");
                 }
-                if (event.mTimeStamp < statsOut.beginTime || event.mTimeStamp > statsOut.endTime) {
-                    if (failures++ < failureLogLimit) {
-                        sb.append("\nUnexpected event timestamp ");
-                        sb.append(event.mTimeStamp);
-                        sb.append(" loaded (beginTime : ");
-                        sb.append(statsOut.beginTime);
-                        sb.append(", endTime : ");
-                        sb.append(statsOut.endTime);
-                        sb.append(")");
-                    }
+            }
+            if (event.mTimeStamp < statsOut.beginTime || event.mTimeStamp > statsOut.endTime) {
+                if (failures++ < failureLogLimit) {
+                    sb.append("\nUnexpected event timestamp ");
+                    sb.append(event.mTimeStamp);
+                    sb.append(" loaded (beginTime : ");
+                    sb.append(statsOut.beginTime);
+                    sb.append(", endTime : ");
+                    sb.append(statsOut.endTime);
+                    sb.append(")");
                 }
-                if (event.mEventType < 0 || event.mEventType > UsageEvents.Event.MAX_EVENT_TYPE) {
-                    if (failures++ < failureLogLimit) {
-                        sb.append("\nUnexpected event type ");
-                        sb.append(event.mEventType);
-                        sb.append(" loaded");
-                    }
+            }
+            if (event.mEventType < 0 || event.mEventType > UsageEvents.Event.MAX_EVENT_TYPE) {
+                if (failures++ < failureLogLimit) {
+                    sb.append("\nUnexpected event type ");
+                    sb.append(event.mEventType);
+                    sb.append(" loaded");
                 }
-                if ((event.mFlags & ~UsageEvents.Event.VALID_FLAG_BITS) != 0) {
-                    if (failures++ < failureLogLimit) {
-                        sb.append("\nUnexpected event flag bit 0b");
-                        sb.append(Integer.toBinaryString(event.mFlags));
-                        sb.append(" loaded");
-                    }
+            }
+            if ((event.mFlags & ~UsageEvents.Event.VALID_FLAG_BITS) != 0) {
+                if (failures++ < failureLogLimit) {
+                    sb.append("\nUnexpected event flag bit 0b");
+                    sb.append(Integer.toBinaryString(event.mFlags));
+                    sb.append(" loaded");
                 }
             }
         }
@@ -1176,7 +1196,7 @@
         if (stats == null) return;
         stats.activeConfiguration = null;
         stats.configurations.clear();
-        if (stats.events != null) stats.events.clear();
+        stats.events.clear();
     }
 
     private byte[] serializeIntervalStats(IntervalStats stats, int version) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 11d49eb..63bf7e7 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -16,7 +16,6 @@
 package com.android.server.usage;
 
 import android.app.usage.ConfigurationStats;
-import android.app.usage.EventList;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStats;
 import android.content.res.Configuration;
@@ -303,10 +302,6 @@
         if (event.mPackage == null) {
             throw new ProtocolException("no package field present");
         }
-
-        if (statsOut.events == null) {
-            statsOut.events = new EventList();
-        }
         statsOut.events.insert(event);
     }
 
@@ -514,10 +509,7 @@
         statsOut.packageStats.clear();
         statsOut.configurations.clear();
         statsOut.activeConfiguration = null;
-
-        if (statsOut.events != null) {
-            statsOut.events.clear();
-        }
+        statsOut.events.clear();
 
         while (true) {
             switch (proto.nextField()) {
@@ -607,7 +599,7 @@
             writeConfigStats(proto, IntervalStatsProto.CONFIGURATIONS, stats,
                     stats.configurations.valueAt(i), active);
         }
-        final int eventCount = stats.events != null ? stats.events.size() : 0;
+        final int eventCount = stats.events.size();
         for (int i = 0; i < eventCount; i++) {
             writeEvent(proto, IntervalStatsProto.EVENT_LOG, stats, stats.events.get(i));
         }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index eddf8f9..e39cd87 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -384,10 +384,7 @@
         statsOut.packageStats.clear();
         statsOut.configurations.clear();
         statsOut.activeConfiguration = null;
-
-        if (statsOut.events != null) {
-            statsOut.events.clear();
-        }
+        statsOut.events.clear();
 
         statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
         try {
@@ -481,7 +478,7 @@
         xml.endTag(null, CONFIGURATIONS_TAG);
 
         xml.startTag(null, EVENT_LOG_TAG);
-        final int eventCount = stats.events != null ? stats.events.size() : 0;
+        final int eventCount = stats.events.size();
         for (int i = 0; i < eventCount; i++) {
             writeEvent(xml, stats, stats.events.get(i));
         }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 3cb2216..ebd8e36 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -595,8 +595,8 @@
     private void loadActiveStats(final long currentTimeMillis) {
         for (int intervalType = 0; intervalType < mCurrentStats.length; intervalType++) {
             final IntervalStats stats = mDatabase.getLatestUsageStats(intervalType);
-            if (stats != null && currentTimeMillis - 500 >= stats.endTime &&
-                    currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
+            if (stats != null
+                    && currentTimeMillis < stats.beginTime + INTERVAL_LENGTH[intervalType]) {
                 if (DEBUG) {
                     Slog.d(TAG, mLogPrefix + "Loading existing stats @ " +
                             sDateFormat.format(stats.beginTime) + "(" + stats.beginTime +
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 2462bee..fecdb08 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2186,7 +2186,10 @@
 
             /**
              * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
-             * content provider
+             * content provider. Can also insert to this URI to create a new 1-to-1 thread. When
+             * performing an insert, ensure that the provided content values contain the other
+             * participant's ID under the key
+             * {@link RcsParticipantColumns.RCS_PARTICIPANT_ID_COLUMN}
              */
             Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
                     RCS_1_TO_1_THREAD_URI_PART);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1b7228a..ad98e36 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2481,6 +2481,17 @@
             "opportunistic_network_data_switch_hysteresis_time_long";
 
     /**
+     * Indicates zero or more emergency number prefix(es), because some carrier requires
+     * if users dial an emergency number address with a specific prefix, the combination of the
+     * prefix and the address is also a valid emergency number to dial. For example, an emergency
+     * number prefix is 318, and the emergency number is 911. Both 318911 and 911 can be dialed by
+     * users for emergency call. An empty array of string indicates that current carrier does not
+     * have this requirement.
+     */
+    public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY =
+            "emergency_number_prefix_string_array";
+
+    /**
      * GPS configs. See android.hardware.gnss@1.0 IGnssConfiguration.
      * @hide
      */
@@ -2989,6 +3000,7 @@
                 new int[] {
                         1 /* Roaming Indicator Off */
                 });
+        sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 6958d22..7655834 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 
 import java.util.Objects;
+import java.util.UUID;
 
 /**
  * CellIdentity represents the identity of a unique cell. This is the base class for
@@ -83,6 +84,13 @@
             mMncStr = null;
             log("invalid MNC format: " + mnc);
         }
+
+        if ((mMccStr != null && mMncStr == null) || (mMccStr == null && mMncStr != null)) {
+            DebugEventReporter.sendEvent(
+                    UUID.fromString("a3ab0b9d-f2aa-4baf-911d-7096c0d4645a"),
+                    "CellIdentity Missing Half of PLMN ID");
+        }
+
         mAlphaLong = alphal;
         mAlphaShort = alphas;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ced4f4a..0b72679 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10375,4 +10375,28 @@
         }
         return false;
     }
+
+    /**
+     * Retrieve the Radio HAL Version for this device.
+     *
+     * Get the HAL version for the IRadio interface for test purposes.
+     *
+     * @return a Pair of (major version, minor version) or (-1,-1) if unknown.
+     *
+     * @hide
+     */
+    @TestApi
+    public Pair<Integer, Integer> getRadioHalVersion() {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                int version = service.getRadioHalVersion();
+                if (version == -1) return new Pair<Integer, Integer>(-1, -1);
+                return new Pair<Integer, Integer>(version / 100, version % 100);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "getRadioHalVersion() RemoteException", e);
+        }
+        return new Pair<Integer, Integer>(-1, -1);
+    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsEvent.java b/telephony/java/android/telephony/ims/RcsEvent.java
index df62277..a547c5c0 100644
--- a/telephony/java/android/telephony/ims/RcsEvent.java
+++ b/telephony/java/android/telephony/ims/RcsEvent.java
@@ -15,16 +15,11 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
-
 /**
  * The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s.
  */
 public abstract class RcsEvent {
-    /**
-     * @hide
-     */
-    protected final long mTimestamp;
+    private final long mTimestamp;
 
     protected RcsEvent(long timestamp) {
         mTimestamp = timestamp;
@@ -44,18 +39,4 @@
      * @hide
      */
     abstract void persist() throws RcsMessageStoreException;
-
-    /**
-     * @hide
-     */
-    RcsEvent(Parcel in) {
-        mTimestamp = in.readLong();
-    }
-
-    /**
-     * @hide
-     */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(mTimestamp);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsEvent.aidl b/telephony/java/android/telephony/ims/RcsEventDescriptor.aidl
similarity index 95%
rename from telephony/java/android/telephony/ims/RcsEvent.aidl
rename to telephony/java/android/telephony/ims/RcsEventDescriptor.aidl
index 08974e0..ab1c55e 100644
--- a/telephony/java/android/telephony/ims/RcsEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsEventDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsEvent;
+parcelable RcsEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsEventDescriptor.java b/telephony/java/android/telephony/ims/RcsEventDescriptor.java
new file mode 100644
index 0000000..8e3f6cd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventDescriptor.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public abstract class RcsEventDescriptor implements Parcelable {
+    protected final long mTimestamp;
+
+    RcsEventDescriptor(long timestamp) {
+        mTimestamp = timestamp;
+    }
+
+    /**
+     * Creates an RcsEvent based on this RcsEventDescriptor. Overriding this method practically
+     * allows an injection point for RcsEvent dependencies outside of the values contained in the
+     * descriptor.
+     */
+    @VisibleForTesting(visibility = PROTECTED)
+    public abstract RcsEvent createRcsEvent();
+
+    RcsEventDescriptor(Parcel in) {
+        mTimestamp = in.readLong();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mTimestamp);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
index c30e4cc..92bda81 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
@@ -16,9 +16,6 @@
 
 package android.telephony.ims;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-
 import java.util.List;
 
 /**
@@ -26,7 +23,7 @@
  * call. This class allows getting the token for querying the next batch of events in order to
  * prevent handling large amounts of data at once.
  */
-public final class RcsEventQueryResult implements Parcelable {
+public class RcsEventQueryResult {
     private RcsQueryContinuationToken mContinuationToken;
     private List<RcsEvent> mEvents;
 
@@ -60,30 +57,4 @@
     public List<RcsEvent> getEvents() {
         return mEvents;
     }
-
-    private RcsEventQueryResult(Parcel in) {
-        mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader());
-    }
-
-    public static final Creator<RcsEventQueryResult> CREATOR = new Creator<RcsEventQueryResult>() {
-        @Override
-        public RcsEventQueryResult createFromParcel(Parcel in) {
-            return new RcsEventQueryResult(in);
-        }
-
-        @Override
-        public RcsEventQueryResult[] newArray(int size) {
-            return new RcsEventQueryResult[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mContinuationToken, flags);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.aidl
similarity index 93%
rename from telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
rename to telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.aidl
index 77a2372..0beaaab 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.aidl
@@ -1,4 +1,5 @@
 /*
+ *
  * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadEvent;
+parcelable RcsEventQueryResultDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java b/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java
new file mode 100644
index 0000000..bba56d3
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResultDescriptor.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Contains the raw data backing a {@link RcsEventQueryResult}.
+ *
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsEventQueryResultDescriptor implements Parcelable {
+    private final RcsQueryContinuationToken mContinuationToken;
+    private final List<RcsEventDescriptor> mEvents;
+
+    public RcsEventQueryResultDescriptor(
+            RcsQueryContinuationToken continuationToken,
+            List<RcsEventDescriptor> events) {
+        mContinuationToken = continuationToken;
+        mEvents = events;
+    }
+
+    protected RcsEventQueryResult getRcsEventQueryResult() {
+        List<RcsEvent> rcsEvents = mEvents.stream()
+                .map(RcsEventDescriptor::createRcsEvent)
+                .collect(Collectors.toList());
+
+        return new RcsEventQueryResult(mContinuationToken, rcsEvents);
+    }
+
+    protected RcsEventQueryResultDescriptor(Parcel in) {
+        mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader());
+        mEvents = new LinkedList<>();
+        in.readList(mEvents, null);
+    }
+
+    public static final Creator<RcsEventQueryResultDescriptor> CREATOR =
+            new Creator<RcsEventQueryResultDescriptor>() {
+        @Override
+        public RcsEventQueryResultDescriptor createFromParcel(Parcel in) {
+            return new RcsEventQueryResultDescriptor(in);
+        }
+
+        @Override
+        public RcsEventQueryResultDescriptor[] newArray(int size) {
+            return new RcsEventQueryResultDescriptor[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mContinuationToken, flags);
+        dest.writeList(mEvents);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
index 609b174..99086aa 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
@@ -16,7 +16,6 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
-import android.os.Parcel;
 
 /**
  * An event that happened on an {@link RcsGroupThread}.
@@ -47,22 +46,4 @@
     public RcsParticipant getOriginatingParticipant() {
         return new RcsParticipant(mOriginatingParticipantId);
     }
-
-    /**
-     * @hide
-     */
-    RcsGroupThreadEvent(Parcel in) {
-        super(in);
-        mRcsGroupThreadId = in.readInt();
-        mOriginatingParticipantId = in.readInt();
-    }
-
-    /**
-     * @hide
-     */
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeInt(mRcsGroupThreadId);
-        dest.writeInt(mOriginatingParticipantId);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl
index 77a2372..6299d8a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.aidl
@@ -16,4 +16,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadEvent;
+parcelable RcsGroupThreadEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java
new file mode 100644
index 0000000..662a264
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEventDescriptor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public abstract class RcsGroupThreadEventDescriptor extends RcsEventDescriptor {
+    protected final int mRcsGroupThreadId;
+    protected final int mOriginatingParticipantId;
+
+    RcsGroupThreadEventDescriptor(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId) {
+        super(timestamp);
+        mRcsGroupThreadId = rcsGroupThreadId;
+        mOriginatingParticipantId = originatingParticipantId;
+    }
+
+    RcsGroupThreadEventDescriptor(Parcel in) {
+        super(in);
+        mRcsGroupThreadId = in.readInt();
+        mOriginatingParticipantId = in.readInt();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mRcsGroupThreadId);
+        dest.writeInt(mOriginatingParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl
deleted file mode 100644
index daea792..0000000
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsGroupThreadIconChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
index e768439..cbd762d 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
@@ -18,15 +18,12 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event that indicates an {@link RcsGroupThread}'s icon was changed. Please see R6-2-5 - GSMA
  * RCC.71 (RCS Universal Profile Service Definition Document)
  */
-public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent implements
-        Parcelable {
+public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent {
     private final Uri mNewIcon;
 
     /**
@@ -48,15 +45,6 @@
     }
 
     /**
-     * @hide - internal constructor for queries
-     */
-    public RcsGroupThreadIconChangedEvent(long timestamp, int rcsGroupThreadId,
-            int originatingParticipantId, @Nullable Uri newIcon) {
-        super(timestamp, rcsGroupThreadId, originatingParticipantId);
-        mNewIcon = newIcon;
-    }
-
-    /**
      * @return Returns the {@link Uri} to the icon of the {@link RcsGroupThread} after this
      * {@link RcsGroupThreadIconChangedEvent} occured.
      */
@@ -77,33 +65,4 @@
                 getTimestamp(), getRcsGroupThread().getThreadId(),
                 getOriginatingParticipant().getId(), mNewIcon));
     }
-
-    public static final Creator<RcsGroupThreadIconChangedEvent> CREATOR =
-            new Creator<RcsGroupThreadIconChangedEvent>() {
-                @Override
-                public RcsGroupThreadIconChangedEvent createFromParcel(Parcel in) {
-                    return new RcsGroupThreadIconChangedEvent(in);
-                }
-
-                @Override
-                public RcsGroupThreadIconChangedEvent[] newArray(int size) {
-                    return new RcsGroupThreadIconChangedEvent[size];
-                }
-            };
-
-    private RcsGroupThreadIconChangedEvent(Parcel in) {
-        super(in);
-        mNewIcon = in.readParcelable(Uri.class.getClassLoader());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeParcelable(mNewIcon, flags);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl
similarity index 92%
copy from telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl
index 77a2372..4bcc5a0 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.aidl
@@ -16,4 +16,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadEvent;
+parcelable RcsGroupThreadIconChangedEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
new file mode 100644
index 0000000..b7fe4b2
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEventDescriptor.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsGroupThreadIconChangedEventDescriptor extends RcsGroupThreadEventDescriptor {
+    private final Uri mNewIcon;
+
+    public RcsGroupThreadIconChangedEventDescriptor(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, @Nullable Uri newIcon) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mNewIcon = newIcon;
+    }
+
+    @Override
+    @VisibleForTesting(visibility = PROTECTED)
+    public RcsGroupThreadIconChangedEvent createRcsEvent() {
+        return new RcsGroupThreadIconChangedEvent(mTimestamp, new RcsGroupThread(mRcsGroupThreadId),
+                new RcsParticipant(mOriginatingParticipantId), mNewIcon);
+    }
+
+    public static final Creator<RcsGroupThreadIconChangedEventDescriptor> CREATOR =
+            new Creator<RcsGroupThreadIconChangedEventDescriptor>() {
+                @Override
+                public RcsGroupThreadIconChangedEventDescriptor createFromParcel(Parcel in) {
+                    return new RcsGroupThreadIconChangedEventDescriptor(in);
+                }
+
+                @Override
+                public RcsGroupThreadIconChangedEventDescriptor[] newArray(int size) {
+                    return new RcsGroupThreadIconChangedEventDescriptor[size];
+                }
+            };
+
+    protected RcsGroupThreadIconChangedEventDescriptor(Parcel in) {
+        super(in);
+        mNewIcon = in.readParcelable(Uri.class.getClassLoader());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeParcelable(mNewIcon, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl
deleted file mode 100644
index 3ed9bd1..0000000
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsGroupThreadNameChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
index 02030bc..a2a4fab 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
@@ -17,15 +17,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event that indicates an {@link RcsGroupThread}'s name was changed. Please see R6-2-5 - GSMA
  * RCC.71 (RCS Universal Profile Service Definition Document)
  */
-public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent implements
-        Parcelable {
+public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent {
     private final String mNewName;
 
     /**
@@ -47,15 +44,6 @@
     }
 
     /**
-     * @hide - internal constructor for queries
-     */
-    public RcsGroupThreadNameChangedEvent(long timestamp, int rcsGroupThreadId,
-            int originatingParticipantId, @Nullable String newName) {
-        super(timestamp, rcsGroupThreadId, originatingParticipantId);
-        mNewName = newName;
-    }
-
-    /**
      * @return Returns the name of this {@link RcsGroupThread} after this
      * {@link RcsGroupThreadNameChangedEvent} happened.
      */
@@ -75,33 +63,4 @@
                 getTimestamp(), getRcsGroupThread().getThreadId(),
                 getOriginatingParticipant().getId(), mNewName));
     }
-
-    public static final Creator<RcsGroupThreadNameChangedEvent> CREATOR =
-            new Creator<RcsGroupThreadNameChangedEvent>() {
-                @Override
-                public RcsGroupThreadNameChangedEvent createFromParcel(Parcel in) {
-                    return new RcsGroupThreadNameChangedEvent(in);
-                }
-
-                @Override
-                public RcsGroupThreadNameChangedEvent[] newArray(int size) {
-                    return new RcsGroupThreadNameChangedEvent[size];
-                }
-            };
-
-    private RcsGroupThreadNameChangedEvent(Parcel in) {
-        super(in);
-        mNewName = in.readString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeString(mNewName);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl
similarity index 92%
rename from telephony/java/android/telephony/ims/RcsEventQueryResult.aidl
rename to telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl
index 7d13335..480e86b 100644
--- a/telephony/java/android/telephony/ims/RcsEventQueryResult.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsEventQueryResult;
+parcelable RcsGroupThreadNameChangedEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
new file mode 100644
index 0000000..4ec641f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEventDescriptor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsGroupThreadNameChangedEventDescriptor extends RcsGroupThreadEventDescriptor {
+    private final String mNewName;
+
+    public RcsGroupThreadNameChangedEventDescriptor(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, @Nullable String newName) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mNewName = newName;
+    }
+
+    @Override
+    @VisibleForTesting(visibility = PROTECTED)
+    public RcsGroupThreadNameChangedEvent createRcsEvent() {
+        return new RcsGroupThreadNameChangedEvent(
+                mTimestamp,
+                new RcsGroupThread(mRcsGroupThreadId),
+                new RcsParticipant(mOriginatingParticipantId),
+                mNewName);
+    }
+
+    public static final Creator<RcsGroupThreadNameChangedEventDescriptor> CREATOR =
+            new Creator<RcsGroupThreadNameChangedEventDescriptor>() {
+                @Override
+                public RcsGroupThreadNameChangedEventDescriptor createFromParcel(Parcel in) {
+                    return new RcsGroupThreadNameChangedEventDescriptor(in);
+                }
+
+                @Override
+                public RcsGroupThreadNameChangedEventDescriptor[] newArray(int size) {
+                    return new RcsGroupThreadNameChangedEventDescriptor[size];
+                }
+            };
+
+    protected RcsGroupThreadNameChangedEventDescriptor(Parcel in) {
+        super(in);
+        mNewName = in.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(mNewName);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
index 0d1a573..183cd9a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
@@ -16,16 +16,13 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event that indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 -
  * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
  */
-public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent implements
-        Parcelable {
-    private final int mJoinedParticipantId;
+public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent {
+    private final RcsParticipant mJoinedParticipantId;
 
     /**
      * Creates a new {@link RcsGroupThreadParticipantJoinedEvent}. This event is not persisted into
@@ -44,23 +41,14 @@
             @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant,
             @NonNull RcsParticipant joinedParticipant) {
         super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
-        mJoinedParticipantId = joinedParticipant.getId();
-    }
-
-    /**
-     * @hide - internal constructor for queries
-     */
-    public RcsGroupThreadParticipantJoinedEvent(long timestamp, int rcsGroupThreadId,
-            int originatingParticipantId, int joinedParticipantId) {
-        super(timestamp, rcsGroupThreadId, originatingParticipantId);
-        mJoinedParticipantId = joinedParticipantId;
+        mJoinedParticipantId = joinedParticipant;
     }
 
     /**
      * @return Returns the {@link RcsParticipant} that joined the associated {@link RcsGroupThread}
      */
     public RcsParticipant getJoinedParticipant() {
-        return new RcsParticipant(mJoinedParticipantId);
+        return mJoinedParticipantId;
     }
 
     /**
@@ -75,33 +63,4 @@
                         getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(),
                         getJoinedParticipant().getId()));
     }
-
-    public static final Creator<RcsGroupThreadParticipantJoinedEvent> CREATOR =
-            new Creator<RcsGroupThreadParticipantJoinedEvent>() {
-                @Override
-                public RcsGroupThreadParticipantJoinedEvent createFromParcel(Parcel in) {
-                    return new RcsGroupThreadParticipantJoinedEvent(in);
-                }
-
-                @Override
-                public RcsGroupThreadParticipantJoinedEvent[] newArray(int size) {
-                    return new RcsGroupThreadParticipantJoinedEvent[size];
-                }
-            };
-
-    private RcsGroupThreadParticipantJoinedEvent(Parcel in) {
-        super(in);
-        mJoinedParticipantId = in.readInt();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeInt(mJoinedParticipantId);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl
similarity index 91%
rename from telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
rename to telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl
index 420abff..7210b9f 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadParticipantJoinedEvent;
+parcelable RcsGroupThreadParticipantJoinedEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
new file mode 100644
index 0000000..a4218c2
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEventDescriptor.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.os.Parcel;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsGroupThreadParticipantJoinedEventDescriptor extends RcsGroupThreadEventDescriptor {
+    private final int mJoinedParticipantId;
+
+    public RcsGroupThreadParticipantJoinedEventDescriptor(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, int joinedParticipantId) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mJoinedParticipantId = joinedParticipantId;
+    }
+
+    @Override
+    @VisibleForTesting(visibility = PROTECTED)
+    public RcsGroupThreadParticipantJoinedEvent createRcsEvent() {
+        return new RcsGroupThreadParticipantJoinedEvent(
+                mTimestamp,
+                new RcsGroupThread(mRcsGroupThreadId),
+                new RcsParticipant(mOriginatingParticipantId),
+                new RcsParticipant(mJoinedParticipantId));
+    }
+
+    public static final Creator<RcsGroupThreadParticipantJoinedEventDescriptor> CREATOR =
+            new Creator<RcsGroupThreadParticipantJoinedEventDescriptor>() {
+                @Override
+                public RcsGroupThreadParticipantJoinedEventDescriptor createFromParcel(Parcel in) {
+                    return new RcsGroupThreadParticipantJoinedEventDescriptor(in);
+                }
+
+                @Override
+                public RcsGroupThreadParticipantJoinedEventDescriptor[] newArray(int size) {
+                    return new RcsGroupThreadParticipantJoinedEventDescriptor[size];
+                }
+            };
+
+    protected RcsGroupThreadParticipantJoinedEventDescriptor(Parcel in) {
+        super(in);
+        mJoinedParticipantId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mJoinedParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl
deleted file mode 100644
index ff139ac..0000000
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsGroupThreadParticipantLeftEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
index cd52508..c12549b 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
@@ -16,16 +16,13 @@
 package android.telephony.ims;
 
 import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event that indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 -
  * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
  */
-public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent implements
-        Parcelable {
-    private final int mLeavingParticipantId;
+public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent {
+    private RcsParticipant mLeavingParticipant;
 
     /**
      * Creates a new {@link RcsGroupThreadParticipantLeftEvent}. his event is not persisted into
@@ -46,16 +43,7 @@
             @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant,
             @NonNull RcsParticipant leavingParticipant) {
         super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
-        mLeavingParticipantId = leavingParticipant.getId();
-    }
-
-    /**
-     * @hide - internal constructor for queries
-     */
-    public RcsGroupThreadParticipantLeftEvent(long timestamp, int rcsGroupThreadId,
-            int originatingParticipantId, int leavingParticipantId) {
-        super(timestamp, rcsGroupThreadId, originatingParticipantId);
-        mLeavingParticipantId = leavingParticipantId;
+        mLeavingParticipant = leavingParticipant;
     }
 
     /**
@@ -63,44 +51,15 @@
      * after this {@link RcsGroupThreadParticipantLeftEvent} happened.
      */
     @NonNull
-    public RcsParticipant getLeavingParticipantId() {
-        return new RcsParticipant(mLeavingParticipantId);
+    public RcsParticipant getLeavingParticipant() {
+        return mLeavingParticipant;
     }
 
     @Override
     public void persist() throws RcsMessageStoreException {
         RcsControllerCall.call(
-                iRcs -> iRcs.createGroupThreadParticipantJoinedEvent(getTimestamp(),
+                iRcs -> iRcs.createGroupThreadParticipantLeftEvent(getTimestamp(),
                         getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(),
-                        getLeavingParticipantId().getId()));
-    }
-
-    public static final Creator<RcsGroupThreadParticipantLeftEvent> CREATOR =
-            new Creator<RcsGroupThreadParticipantLeftEvent>() {
-                @Override
-                public RcsGroupThreadParticipantLeftEvent createFromParcel(Parcel in) {
-                    return new RcsGroupThreadParticipantLeftEvent(in);
-                }
-
-                @Override
-                public RcsGroupThreadParticipantLeftEvent[] newArray(int size) {
-                    return new RcsGroupThreadParticipantLeftEvent[size];
-                }
-            };
-
-    private RcsGroupThreadParticipantLeftEvent(Parcel in) {
-        super(in);
-        mLeavingParticipantId = in.readInt();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeInt(mLeavingParticipantId);
+                        getLeavingParticipant().getId()));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl
similarity index 91%
copy from telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl
index 420abff..3ef92100 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadParticipantJoinedEvent;
+parcelable RcsGroupThreadParticipantLeftEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
new file mode 100644
index 0000000..8e91dda
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEventDescriptor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsGroupThreadParticipantLeftEventDescriptor extends RcsGroupThreadEventDescriptor {
+    private int mLeavingParticipantId;
+
+    public RcsGroupThreadParticipantLeftEventDescriptor(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, int leavingParticipantId) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mLeavingParticipantId = leavingParticipantId;
+    }
+
+    @Override
+    @VisibleForTesting(visibility = PROTECTED)
+    public RcsGroupThreadParticipantLeftEvent createRcsEvent() {
+        return new RcsGroupThreadParticipantLeftEvent(
+                mTimestamp,
+                new RcsGroupThread(mRcsGroupThreadId),
+                new RcsParticipant(mOriginatingParticipantId),
+                new RcsParticipant(mLeavingParticipantId));
+    }
+
+    public static final Parcelable.Creator<RcsGroupThreadParticipantLeftEventDescriptor> CREATOR =
+            new Creator<RcsGroupThreadParticipantLeftEventDescriptor>() {
+                @Override
+                public RcsGroupThreadParticipantLeftEventDescriptor createFromParcel(Parcel in) {
+                    return new RcsGroupThreadParticipantLeftEventDescriptor(in);
+                }
+
+                @Override
+                public RcsGroupThreadParticipantLeftEventDescriptor[] newArray(int size) {
+                    return new RcsGroupThreadParticipantLeftEventDescriptor[size];
+                }
+            };
+
+    protected RcsGroupThreadParticipantLeftEventDescriptor(Parcel in) {
+        super(in);
+        mLeavingParticipantId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mLeavingParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index d811c6e..31f2983 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -118,15 +118,16 @@
     /**
      * Returns the first chunk of existing {@link RcsEvent}s in the common storage.
      *
-     * @param queryParameters Parameters to specify to return a subset of all RcsEvents.
+     * @param queryParams Parameters to specify to return a subset of all RcsEvents.
      *                        Passing a value of null will return all events.
      * @throws RcsMessageStoreException if the query could not be completed on the storage
      */
     @WorkerThread
     @NonNull
     public RcsEventQueryResult getRcsEvents(
-            @Nullable RcsEventQueryParams queryParameters) throws RcsMessageStoreException {
-        return RcsControllerCall.call(iRcs -> iRcs.getEvents(queryParameters));
+            @Nullable RcsEventQueryParams queryParams) throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getEvents(queryParams))
+                .getRcsEventQueryResult();
     }
 
     /**
@@ -140,7 +141,8 @@
     @NonNull
     public RcsEventQueryResult getRcsEvents(
             @NonNull RcsQueryContinuationToken continuationToken) throws RcsMessageStoreException {
-        return RcsControllerCall.call(iRcs -> iRcs.getEventsWithToken(continuationToken));
+        return RcsControllerCall.call(iRcs -> iRcs.getEventsWithToken(continuationToken))
+                .getRcsEventQueryResult();
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
deleted file mode 100644
index b9d8190..0000000
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsParticipantAliasChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
index c9a2b0d..cc2613f 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -17,16 +17,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 /**
  * An event that indicates an {@link RcsParticipant}'s alias was changed. Please see US18-2 - GSMA
  * RCC.71 (RCS Universal Profile Service Definition Document)
  */
-public final class RcsParticipantAliasChangedEvent extends RcsEvent implements Parcelable {
-    // The ID of the participant that changed their alias
-    private final int mParticipantId;
+public final class RcsParticipantAliasChangedEvent extends RcsEvent {
+    // The participant that changed their alias
+    private final RcsParticipant mParticipant;
     // The new alias of the above participant
     private final String mNewAlias;
 
@@ -43,17 +41,7 @@
     public RcsParticipantAliasChangedEvent(long timestamp, @NonNull RcsParticipant participant,
             @Nullable String newAlias) {
         super(timestamp);
-        mParticipantId = participant.getId();
-        mNewAlias = newAlias;
-    }
-
-    /**
-     * @hide - internal constructor for queries
-     */
-    public RcsParticipantAliasChangedEvent(long timestamp, int participantId,
-            @Nullable String newAlias) {
-        super(timestamp);
-        mParticipantId = participantId;
+        mParticipant = participant;
         mNewAlias = newAlias;
     }
 
@@ -61,8 +49,8 @@
      * @return Returns the {@link RcsParticipant} whose alias was changed.
      */
     @NonNull
-    public RcsParticipant getParticipantId() {
-        return new RcsParticipant(mParticipantId);
+    public RcsParticipant getParticipant() {
+        return mParticipant;
     }
 
     /**
@@ -81,37 +69,6 @@
     @Override
     public void persist() throws RcsMessageStoreException {
         RcsControllerCall.call(iRcs -> iRcs.createParticipantAliasChangedEvent(
-                getTimestamp(), getParticipantId().getId(), getNewAlias()));
-    }
-
-    public static final Creator<RcsParticipantAliasChangedEvent> CREATOR =
-            new Creator<RcsParticipantAliasChangedEvent>() {
-                @Override
-                public RcsParticipantAliasChangedEvent createFromParcel(Parcel in) {
-                    return new RcsParticipantAliasChangedEvent(in);
-                }
-
-                @Override
-                public RcsParticipantAliasChangedEvent[] newArray(int size) {
-                    return new RcsParticipantAliasChangedEvent[size];
-                }
-            };
-
-    private RcsParticipantAliasChangedEvent(Parcel in) {
-        super(in);
-        mNewAlias = in.readString();
-        mParticipantId = in.readInt();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeString(mNewAlias);
-        dest.writeInt(mParticipantId);
+                getTimestamp(), getParticipant().getId(), getNewAlias()));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl
similarity index 91%
copy from telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
copy to telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl
index 77a2372..64fe3b8 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.aidl
@@ -1,4 +1,5 @@
 /*
+ *
  * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsGroupThreadEvent;
+parcelable RcsParticipantAliasChangedEventDescriptor;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
new file mode 100644
index 0000000..a32e552
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEventDescriptor.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony.ims;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PROTECTED;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * @hide - used only for internal communication with the ircs service
+ */
+public class RcsParticipantAliasChangedEventDescriptor extends RcsEventDescriptor {
+    // The ID of the participant that changed their alias
+    protected int mParticipantId;
+    // The new alias of the above participant
+    protected String mNewAlias;
+
+    public RcsParticipantAliasChangedEventDescriptor(long timestamp, int participantId,
+            @Nullable String newAlias) {
+        super(timestamp);
+        mParticipantId = participantId;
+        mNewAlias = newAlias;
+    }
+
+    @Override
+    @VisibleForTesting(visibility = PROTECTED)
+    public RcsParticipantAliasChangedEvent createRcsEvent() {
+        return new RcsParticipantAliasChangedEvent(
+                mTimestamp, new RcsParticipant(mParticipantId), mNewAlias);
+    }
+
+    public static final Creator<RcsParticipantAliasChangedEventDescriptor> CREATOR =
+            new Creator<RcsParticipantAliasChangedEventDescriptor>() {
+                @Override
+                public RcsParticipantAliasChangedEventDescriptor createFromParcel(Parcel in) {
+                    return new RcsParticipantAliasChangedEventDescriptor(in);
+                }
+
+                @Override
+                public RcsParticipantAliasChangedEventDescriptor[] newArray(int size) {
+                    return new RcsParticipantAliasChangedEventDescriptor[size];
+                }
+            };
+
+    protected RcsParticipantAliasChangedEventDescriptor(Parcel in) {
+        super(in);
+        mNewAlias = in.readString();
+        mParticipantId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(mNewAlias);
+        dest.writeInt(mParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index 2478f8c..6ab01c2 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -18,7 +18,7 @@
 
 import android.net.Uri;
 import android.telephony.ims.RcsEventQueryParams;
-import android.telephony.ims.RcsEventQueryResult;
+import android.telephony.ims.RcsEventQueryResultDescriptor;
 import android.telephony.ims.RcsFileTransferCreationParams;
 import android.telephony.ims.RcsIncomingMessageCreationParams;
 import android.telephony.ims.RcsMessageSnippet;
@@ -54,9 +54,9 @@
     RcsMessageQueryResult getMessagesWithToken(
         in RcsQueryContinuationToken continuationToken);
 
-    RcsEventQueryResult getEvents(in RcsEventQueryParams queryParams);
+    RcsEventQueryResultDescriptor getEvents(in RcsEventQueryParams queryParams);
 
-    RcsEventQueryResult getEventsWithToken(
+    RcsEventQueryResultDescriptor getEventsWithToken(
         in RcsQueryContinuationToken continuationToken);
 
     // returns true if the thread was successfully deleted
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7089ee5..c54a606 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1855,4 +1855,9 @@
      * Get the mapping from logical slots to physical slots.
      */
     int[] getSlotsMapping();
+
+    /**
+     * Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown
+     */
+     int getRadioHalVersion();
 }
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
similarity index 77%
rename from tests/DexLoggerIntegrationTests/Android.mk
rename to tests/DynamicCodeLoggerIntegrationTests/Android.mk
index ee02a72..f324eb1 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -21,12 +21,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DexLoggerTestLibrary
+LOCAL_MODULE := DynamicCodeLoggerTestLibrary
 LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/dcl)
 
 include $(BUILD_JAVA_LIBRARY)
 
-dexloggertest_jar := $(LOCAL_BUILT_MODULE)
+dynamiccodeloggertest_jar := $(LOCAL_BUILT_MODULE)
 
 
 # Also build a native library that the test app can dynamically load
@@ -34,7 +34,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DexLoggerNativeTestLibrary
+LOCAL_MODULE := DynamicCodeLoggerNativeTestLibrary
 LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE)
@@ -48,19 +48,19 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := DexLoggerNativeExecutable
+LOCAL_MODULE := DynamicCodeLoggerNativeExecutable
 LOCAL_SRC_FILES := src/cpp/test_executable.cpp
 
 include $(BUILD_EXECUTABLE)
 
-dexloggertest_executable := $(LOCAL_BUILT_MODULE)
+dynamiccodeloggertest_executable := $(LOCAL_BUILT_MODULE)
 
 # Build the test app itself
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests
+LOCAL_PACKAGE_NAME := DynamicCodeLoggerIntegrationTests
 LOCAL_SDK_VERSION := current
 LOCAL_COMPATIBILITY_SUITE := device-tests
 LOCAL_CERTIFICATE := shared
@@ -73,12 +73,12 @@
 # Include both versions of the .so if we have 2 arch
 LOCAL_MULTILIB := both
 LOCAL_JNI_SHARED_LIBRARIES := \
-    DexLoggerNativeTestLibrary \
+    DynamicCodeLoggerNativeTestLibrary \
 
-# This gets us the javalib.jar built by DexLoggerTestLibrary above as well as the various
+# This gets us the javalib.jar built by DynamicCodeLoggerTestLibrary above as well as the various
 # native binaries.
 LOCAL_JAVA_RESOURCE_FILES := \
-    $(dexloggertest_jar) \
-    $(dexloggertest_executable) \
+    $(dynamiccodeloggertest_jar) \
+    $(dynamiccodeloggertest_executable) \
 
 include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/AndroidManifest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml
similarity index 84%
rename from tests/DexLoggerIntegrationTests/AndroidManifest.xml
rename to tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml
index a9f01ed..4327da2 100644
--- a/tests/DexLoggerIntegrationTests/AndroidManifest.xml
+++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.dexloggertest">
+        package="com.android.frameworks.dynamiccodeloggertest">
 
     <!-- Tests feature introduced in P (28) -->
     <uses-sdk
@@ -30,6 +30,6 @@
 
     <instrumentation
         android:name="android.support.test.runner.AndroidJUnitRunner"
-        android:targetPackage="com.android.frameworks.dexloggertest"
-        android:label="Integration test for DexLogger" />
+        android:targetPackage="com.android.frameworks.dynamiccodeloggertest"
+        android:label="Integration test for DynamicCodeLogger" />
 </manifest>
diff --git a/tests/DexLoggerIntegrationTests/AndroidTest.xml b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
similarity index 78%
rename from tests/DexLoggerIntegrationTests/AndroidTest.xml
rename to tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
index fb1bef6..f70b9c8 100644
--- a/tests/DexLoggerIntegrationTests/AndroidTest.xml
+++ b/tests/DynamicCodeLoggerIntegrationTests/AndroidTest.xml
@@ -13,17 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Runs DexLogger Integration Tests">
+<configuration description="Runs DynamicLogger Integration Tests">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
-        <option name="test-file-name" value="DexLoggerIntegrationTests.apk"/>
+        <option name="test-file-name" value="DynamicCodeLoggerIntegrationTests.apk"/>
         <option name="cleanup-apks" value="true"/>
     </target_preparer>
 
     <option name="test-suite-tag" value="apct"/>
-    <option name="test-tag" value="DexLoggerIntegrationTests"/>
+    <option name="test-tag" value="DynamicCodeLoggerIntegrationTests"/>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
-        <option name="package" value="com.android.frameworks.dexloggertest"/>
+        <option name="package" value="com.android.frameworks.dynamiccodeloggertest"/>
         <option name="runner" value="android.support.test.runner.AndroidJUnitRunner"/>
         <option name="hidden-api-checks" value="false"/>
     </test>
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
similarity index 100%
rename from tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java
rename to tests/DynamicCodeLoggerIntegrationTests/src/com/android/dcl/Simple.java
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
similarity index 96%
rename from tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
rename to tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
index 99d1f5ff4..8ef15d8 100644
--- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -49,7 +49,7 @@
 import java.util.concurrent.TimeUnit;
 
 /**
- * Integration tests for {@link DynamicCodeLogger}, formerly known as {@code DexLogger}.
+ * Integration tests for {@link DynamicCodeLogger}.
  *
  * The setup for the test dynamically loads code in a jar extracted
  * from our assets (a secondary dex file).
@@ -59,11 +59,11 @@
  * file's name and content.  We verify that this message appears in
  * the event log.
  *
- * Run with "atest DexLoggerIntegrationTests".
+ * Run with "atest DynamicCodeLoggerIntegrationTests".
  */
 @LargeTest
 @RunWith(JUnit4.class)
-public final class DexLoggerIntegrationTests {
+public final class DynamicCodeLoggerIntegrationTests {
 
     private static final String SHA_256 = "SHA-256";
 
@@ -162,7 +162,7 @@
                 File privateCopyFile = privateFile(privateCopyName);
                 mExpectedNameHash = hashOf(privateCopyName);
                 mExpectedContentHash = copyAndHashResource(
-                        libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
+                        libraryPath("DynamicCodeLoggerNativeTestLibrary.so"), privateCopyFile);
 
                 System.load(privateCopyFile.toString());
             }
@@ -180,7 +180,7 @@
                 File privateCopyFile = privateFile(privateCopyName);
                 mExpectedNameHash = hashOf(privateCopyName);
                 mExpectedContentHash = copyAndHashResource(
-                        libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
+                        libraryPath("DynamicCodeLoggerNativeTestLibrary.so"), privateCopyFile);
 
                 System.load(privateCopyFile.toString());
             }
@@ -196,7 +196,7 @@
                 File privateCopyFile = privateFile(privateCopyName);
                 mExpectedNameHash = hashOf(privateCopyName);
                 mExpectedContentHash = copyAndHashResource(
-                        "/DexLoggerNativeExecutable", privateCopyFile);
+                        "/DynamicCodeLoggerNativeExecutable", privateCopyFile);
                 assertThat(privateCopyFile.setExecutable(true)).isTrue();
 
                 Process process = Runtime.getRuntime().exec(privateCopyFile.toString());
@@ -211,7 +211,7 @@
         File privateCopyFile = privateFile("spoofed");
 
         String expectedContentHash = copyAndHashResource(
-                "/DexLoggerNativeExecutable", privateCopyFile);
+                "/DynamicCodeLoggerNativeExecutable", privateCopyFile);
 
         EventLog.writeEvent(EventLog.getTagCode("auditd"),
                 "type=1400 avc: granted { execute_no_trans } "
@@ -275,7 +275,7 @@
     public void testGeneratesEvents_spoofed_otherAppFile() throws Exception {
         File ourPath = sContext.getDatabasePath("android_pay");
         File targetPath = new File(ourPath.toString()
-                .replace("com.android.frameworks.dexloggertest", "com.google.android.gms"));
+                .replace("com.android.frameworks.dynamiccodeloggertest", "com.google.android.gms"));
 
         assertWithMessage("Expected " + targetPath + " to not be readable")
                 .that(targetPath.canRead()).isFalse();
@@ -348,7 +348,7 @@
         MessageDigest hasher = MessageDigest.getInstance(SHA_256);
 
         // Copy the jar from our Java resources to a private data directory
-        Class<?> thisClass = DexLoggerIntegrationTests.class;
+        Class<?> thisClass = DynamicCodeLoggerIntegrationTests.class;
         try (InputStream input = thisClass.getResourceAsStream(resourcePath);
              OutputStream output = new FileOutputStream(copyTo)) {
             byte[] buffer = new byte[1024];
diff --git a/tests/DexLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp
similarity index 100%
rename from tests/DexLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp
rename to tests/DynamicCodeLoggerIntegrationTests/src/cpp/com_android_dcl_Jni.cpp
diff --git a/tests/DexLoggerIntegrationTests/src/cpp/test_executable.cpp b/tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp
similarity index 100%
rename from tests/DexLoggerIntegrationTests/src/cpp/test_executable.cpp
rename to tests/DynamicCodeLoggerIntegrationTests/src/cpp/test_executable.cpp
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java
index 915a260..89d32ab 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java
@@ -20,9 +20,8 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsGroupThread;
 import android.telephony.ims.RcsGroupThreadIconChangedEvent;
-import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsGroupThreadIconChangedEventDescriptor;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,20 +31,27 @@
 
     @Test
     public void testCanUnparcel() {
-        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
-        RcsParticipant rcsParticipant = new RcsParticipant(2);
+        int rcsGroupThreadId = 1;
+        int rcsParticipantId = 2;
         Uri newIconUri = Uri.parse("content://new_icon");
 
-        RcsGroupThreadIconChangedEvent iconChangedEvent =
-                new RcsGroupThreadIconChangedEvent(1234567890, rcsGroupThread, rcsParticipant,
-                        newIconUri);
+        RcsGroupThreadIconChangedEventDescriptor iconChangedEventDescriptor =
+                new RcsGroupThreadIconChangedEventDescriptor(1234567890, rcsGroupThreadId,
+                        rcsParticipantId, newIconUri);
 
         Parcel parcel = Parcel.obtain();
-        iconChangedEvent.writeToParcel(parcel, iconChangedEvent.describeContents());
+        iconChangedEventDescriptor.writeToParcel(
+                parcel, iconChangedEventDescriptor.describeContents());
 
         parcel.setDataPosition(0);
 
-        iconChangedEvent = RcsGroupThreadIconChangedEvent.CREATOR.createFromParcel(parcel);
+        iconChangedEventDescriptor =
+                RcsGroupThreadIconChangedEventDescriptor.CREATOR.createFromParcel(parcel);
+
+        RcsGroupThreadIconChangedEvent iconChangedEvent =
+                iconChangedEventDescriptor.createRcsEvent();
+
+
 
         assertThat(iconChangedEvent.getNewIcon()).isEqualTo(newIconUri);
         assertThat(iconChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java
index 1384c01..726b9cd 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java
@@ -19,9 +19,8 @@
 
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsGroupThread;
 import android.telephony.ims.RcsGroupThreadNameChangedEvent;
-import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsGroupThreadNameChangedEventDescriptor;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -32,20 +31,24 @@
     public void testCanUnparcel() {
         String newName = "new name";
 
-        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
-        RcsParticipant rcsParticipant = new RcsParticipant(2);
+        int rcsGroupThreadId = 1;
+        int rcsParticipantId = 2;
 
-        RcsGroupThreadNameChangedEvent nameChangedEvent =
-                new RcsGroupThreadNameChangedEvent(1234567890, rcsGroupThread, rcsParticipant,
-                        newName);
+        RcsGroupThreadNameChangedEventDescriptor nameChangedEventDescriptor =
+                new RcsGroupThreadNameChangedEventDescriptor(
+                        1234567890, rcsGroupThreadId, rcsParticipantId, newName);
 
         Parcel parcel = Parcel.obtain();
-        nameChangedEvent.writeToParcel(parcel, nameChangedEvent.describeContents());
+        nameChangedEventDescriptor.writeToParcel(
+                parcel, nameChangedEventDescriptor.describeContents());
 
         parcel.setDataPosition(0);
 
-        nameChangedEvent = RcsGroupThreadNameChangedEvent.CREATOR.createFromParcel(
-                parcel);
+        nameChangedEventDescriptor = RcsGroupThreadNameChangedEventDescriptor.CREATOR
+                .createFromParcel(parcel);
+
+        RcsGroupThreadNameChangedEvent nameChangedEvent =
+                nameChangedEventDescriptor.createRcsEvent();
 
         assertThat(nameChangedEvent.getNewName()).isEqualTo(newName);
         assertThat(nameChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java
index d0af7db..a109310 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java
@@ -19,9 +19,8 @@
 
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsGroupThread;
 import android.telephony.ims.RcsGroupThreadParticipantJoinedEvent;
-import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsGroupThreadParticipantJoinedEventDescriptor;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,20 +30,24 @@
 
     @Test
     public void testCanUnparcel() {
-        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
-        RcsParticipant rcsParticipant = new RcsParticipant(2);
+        int rcsGroupThreadId = 1;
+        int rcsParticipantId = 2;
 
-        RcsGroupThreadParticipantJoinedEvent participantJoinedEvent =
-                new RcsGroupThreadParticipantJoinedEvent(1234567890, rcsGroupThread, rcsParticipant,
-                        rcsParticipant);
+        RcsGroupThreadParticipantJoinedEventDescriptor participantJoinedEventDescriptor =
+                new RcsGroupThreadParticipantJoinedEventDescriptor(
+                        1234567890, rcsGroupThreadId, rcsParticipantId, rcsParticipantId);
 
         Parcel parcel = Parcel.obtain();
-        participantJoinedEvent.writeToParcel(parcel, participantJoinedEvent.describeContents());
+        participantJoinedEventDescriptor.writeToParcel(
+                parcel, participantJoinedEventDescriptor.describeContents());
 
         parcel.setDataPosition(0);
 
-        participantJoinedEvent = RcsGroupThreadParticipantJoinedEvent.CREATOR.createFromParcel(
-                parcel);
+        participantJoinedEventDescriptor = RcsGroupThreadParticipantJoinedEventDescriptor.CREATOR
+                .createFromParcel(parcel);
+
+        RcsGroupThreadParticipantJoinedEvent participantJoinedEvent =
+                participantJoinedEventDescriptor.createRcsEvent();
 
         assertThat(participantJoinedEvent.getJoinedParticipant().getId()).isEqualTo(2);
         assertThat(participantJoinedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java
index 7ba5fa6..de2688c 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java
@@ -19,9 +19,8 @@
 
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsGroupThread;
 import android.telephony.ims.RcsGroupThreadParticipantLeftEvent;
-import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsGroupThreadParticipantLeftEventDescriptor;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,24 +29,29 @@
 public class RcsGroupThreadParticipantLeftEventTest {
     @Test
     public void testCanUnparcel() {
-        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
-        RcsParticipant rcsParticipant = new RcsParticipant(2);
+        int rcsGroupThreadId = 1;
+        int rcsParticipantId = 2;
 
-        RcsGroupThreadParticipantLeftEvent participantLeftEvent =
-                new RcsGroupThreadParticipantLeftEvent(1234567890, rcsGroupThread, rcsParticipant,
-                        rcsParticipant);
+        RcsGroupThreadParticipantLeftEventDescriptor participantLeftEventDescriptor =
+                new RcsGroupThreadParticipantLeftEventDescriptor(
+                        1234567890, rcsGroupThreadId, rcsParticipantId, rcsParticipantId);
 
         Parcel parcel = Parcel.obtain();
-        participantLeftEvent.writeToParcel(parcel, participantLeftEvent.describeContents());
+        participantLeftEventDescriptor.writeToParcel(
+                parcel, participantLeftEventDescriptor.describeContents());
 
         parcel.setDataPosition(0);
 
         // create from parcel
         parcel.setDataPosition(0);
-        participantLeftEvent = RcsGroupThreadParticipantLeftEvent.CREATOR.createFromParcel(
-                parcel);
+        participantLeftEventDescriptor = RcsGroupThreadParticipantLeftEventDescriptor.CREATOR
+                .createFromParcel(parcel);
+
+        RcsGroupThreadParticipantLeftEvent participantLeftEvent =
+                participantLeftEventDescriptor.createRcsEvent();
+
         assertThat(participantLeftEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
-        assertThat(participantLeftEvent.getLeavingParticipantId().getId()).isEqualTo(2);
+        assertThat(participantLeftEvent.getLeavingParticipant().getId()).isEqualTo(2);
         assertThat(participantLeftEvent.getTimestamp()).isEqualTo(1234567890);
     }
 }
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java
index 3e2bbbf..5724054 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java
@@ -19,10 +19,9 @@
 
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsParticipant;
 import android.telephony.ims.RcsParticipantAliasChangedEvent;
+import android.telephony.ims.RcsParticipantAliasChangedEventDescriptor;
 
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -30,27 +29,27 @@
 public class RcsParticipantAliasChangedEventTest {
     private static final String OLD_ALIAS = "old alias";
     private static final String NEW_ALIAS = "new alias";
-    private RcsParticipant mParticipant;
-
-    @Before
-    public void setUp() {
-        mParticipant = new RcsParticipant(3);
-    }
+    private int mParticipantId = 3;
 
     @Test
     public void testCanUnparcel() {
-        RcsParticipantAliasChangedEvent aliasChangedEvent =
-                new RcsParticipantAliasChangedEvent(1234567890, mParticipant, NEW_ALIAS);
+        RcsParticipantAliasChangedEventDescriptor aliasChangedEventDescriptor =
+                new RcsParticipantAliasChangedEventDescriptor(
+                        1234567890, mParticipantId, NEW_ALIAS);
 
         Parcel parcel = Parcel.obtain();
-        aliasChangedEvent.writeToParcel(parcel, aliasChangedEvent.describeContents());
+        aliasChangedEventDescriptor.writeToParcel(
+                parcel, aliasChangedEventDescriptor.describeContents());
 
         parcel.setDataPosition(0);
 
-        aliasChangedEvent = RcsParticipantAliasChangedEvent.CREATOR.createFromParcel(
-                parcel);
+        aliasChangedEventDescriptor = RcsParticipantAliasChangedEventDescriptor.CREATOR
+                .createFromParcel(parcel);
 
-        assertThat(aliasChangedEvent.getParticipantId().getId()).isEqualTo(3);
+        RcsParticipantAliasChangedEvent aliasChangedEvent =
+                aliasChangedEventDescriptor.createRcsEvent();
+
+        assertThat(aliasChangedEvent.getParticipant().getId()).isEqualTo(mParticipantId);
         assertThat(aliasChangedEvent.getNewAlias()).isEqualTo(NEW_ALIAS);
         assertThat(aliasChangedEvent.getTimestamp()).isEqualTo(1234567890);
     }
diff --git a/tests/RollbackTest/Android.mk b/tests/RollbackTest/Android.mk
index 0967ad3..9e5d8ce 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -76,13 +76,13 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_COMPATIBILITY_SUPPORT_FILES := $(ROLLBACK_TEST_APEX_V1)
 LOCAL_JAVA_RESOURCE_FILES := \
   $(ROLLBACK_TEST_APP_AV1) \
   $(ROLLBACK_TEST_APP_AV2) \
   $(ROLLBACK_TEST_APP_A_CRASHING_V2) \
   $(ROLLBACK_TEST_APP_BV1) \
   $(ROLLBACK_TEST_APP_BV2) \
+  $(ROLLBACK_TEST_APEX_V1) \
   $(ROLLBACK_TEST_APEX_V2)
 LOCAL_MANIFEST_FILE := RollbackTest/AndroidManifest.xml
 LOCAL_SDK_VERSION := system_current
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index f3edf09..bd0881f 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -587,9 +587,13 @@
             RollbackTestUtils.installMultiPackage(false,
                     "RollbackTestAppAv1.apk",
                     "RollbackTestAppBv1.apk");
+            processUserData(TEST_APP_A);
+            processUserData(TEST_APP_B);
             RollbackTestUtils.installMultiPackage(true,
                     "RollbackTestAppAv2.apk",
                     "RollbackTestAppBv2.apk");
+            processUserData(TEST_APP_A);
+            processUserData(TEST_APP_B);
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
             assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
 
@@ -614,6 +618,9 @@
             assertRollbackInfoForAandB(rollbackB);
 
             assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
+
+            processUserData(TEST_APP_A);
+            processUserData(TEST_APP_B);
         } finally {
             RollbackTestUtils.dropShellPermissionIdentity();
         }
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index 280ee1d..097d33d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -66,7 +66,7 @@
         Context context = InstrumentationRegistry.getContext();
         PackageManager pm = context.getPackageManager();
         try {
-            PackageInfo info = pm.getPackageInfo(packageName, 0);
+            PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
             return info.getLongVersionCode();
         } catch (PackageManager.NameNotFoundException e) {
             return -1;
@@ -142,7 +142,7 @@
         session = packageInstaller.openSession(sessionId);
 
         ClassLoader loader = RollbackTest.class.getClassLoader();
-        try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+        try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
              InputStream is = loader.getResourceAsStream(resourceName);) {
             byte[] buffer = new byte[4096];
             int n;
@@ -168,7 +168,8 @@
     }
 
     /**
-     * Installs the apks with the given resource names as an atomic set.
+     * Installs the APKs or APEXs with the given resource names as an atomic
+     * set. A resource is assumed to be an APEX if it has the .apex extension.
      * <p>
      * In case of staged installs, this function will return succesfully after
      * the staged install has been committed and is ready for the device to
@@ -206,6 +207,9 @@
             if (staged) {
                 params.setStaged();
             }
+            if (resourceName.endsWith(".apex")) {
+                params.setInstallAsApex();
+            }
             if (enableRollback) {
                 params.setEnableRollback();
             }
@@ -213,7 +217,7 @@
             session = packageInstaller.openSession(sessionId);
 
             ClassLoader loader = RollbackTest.class.getClassLoader();
-            try (OutputStream packageInSession = session.openWrite("package", 0, -1);
+            try (OutputStream packageInSession = session.openWrite(resourceName, 0, -1);
                  InputStream is = loader.getResourceAsStream(resourceName);) {
                 byte[] buffer = new byte[4096];
                 int n;
@@ -247,7 +251,9 @@
     }
 
     /**
-     * Installs the apks with the given resource names as a staged atomic set.
+     * Installs the APKs or APEXs with the given resource names as a staged
+     * atomic set. A resource is assumed to be an APEX if it has the .apex
+     * extension.
      *
      * @param enableRollback if rollback should be enabled.
      * @param resourceNames names of the class loader resource for the apks to
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 297bf86..b65917b 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -25,6 +25,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
@@ -46,6 +47,11 @@
 
     private static final String TAG = "RollbackTest";
     private static final String TEST_APP_A = "com.android.tests.rollback.testapp.A";
+    private static final String TEST_APEX_PKG = "com.android.tests.rollback.testapex";
+    private static final String TEST_APEX_V1 =
+            "com.android.tests.rollback.testapex.RollbackTestApexV1.apex";
+    private static final String TEST_APEX_V2 =
+            "com.android.tests.rollback.testapex.RollbackTestApexV2.apex";
 
     /**
      * Adopts common shell permissions needed for rollback tests.
@@ -68,10 +74,11 @@
 
 
     /**
-     * Test basic rollbacks. Enable rollback phase.
+     * Test rollbacks of staged installs involving only apks.
+     * Enable rollback phase.
      */
     @Test
-    public void testBasicEnableRollback() throws Exception {
+    public void testApkOnlyEnableRollback() throws Exception {
         RollbackTestUtils.uninstall(TEST_APP_A);
         assertEquals(-1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
@@ -81,14 +88,15 @@
         RollbackTestUtils.installStaged(true, "RollbackTestAppAv2.apk");
 
         // At this point, the host test driver will reboot the device and run
-        // testBasicCommitRollback().
+        // testApkOnlyCommitRollback().
     }
 
     /**
-     * Test basic rollbacks. Commit rollback phase.
+     * Test rollbacks of staged installs involving only apks.
+     * Commit rollback phase.
      */
     @Test
-    public void testBasicCommitRollback() throws Exception {
+    public void testApkOnlyCommitRollback() throws Exception {
         assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
         RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -111,14 +119,15 @@
         assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
         // At this point, the host test driver will reboot the device and run
-        // testBasicConfirmRollback().
+        // testApkOnlyConfirmRollback().
     }
 
     /**
-     * Test basic rollbacks. Confirm rollback phase.
+     * Test rollbacks of staged installs involving only apks.
+     * Confirm rollback phase.
      */
     @Test
-    public void testBasicConfirmRollback() throws Exception {
+    public void testApkOnlyConfirmRollback() throws Exception {
         assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
 
         RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -128,4 +137,83 @@
         assertTrue(rollback.isStaged());
         assertNotEquals(-1, rollback.getCommittedSessionId());
     }
+
+    /**
+     * Test rollbacks of staged installs involving only apex.
+     * Prepare apex phase.
+     */
+    @Test
+    public void testApexOnlyPrepareApex() throws Exception {
+        // Note: We can't uninstall the apex if it is already on device,
+        // because that isn't supported yet (b/123667725). As long as nothing
+        // is failing, this should be fine because we don't expect the tests
+        // to leave the device with v2 of the apex installed.
+        RollbackTestUtils.installStaged(false, TEST_APEX_V1);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApexOnlyEnableRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs involving only apex.
+     * Enable rollback phase.
+     */
+    @Test
+    public void testApexOnlyEnableRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+        RollbackTestUtils.installStaged(true, TEST_APEX_V2);
+
+        // At this point, the host test driver will reboot the device and run
+        // testApexOnlyCommitRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs involving only apks.
+     * Commit rollback phase.
+     */
+    @Test
+    public void testApexOnlyCommitRollback() throws Exception {
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+
+        RollbackManager rm = RollbackTestUtils.getRollbackManager();
+        RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+                rm.getAvailableRollbacks(), TEST_APEX_PKG);
+        assertRollbackInfoEquals(TEST_APEX_PKG, 2, 1, rollback);
+        assertTrue(rollback.isStaged());
+
+        RollbackTestUtils.rollback(rollback.getRollbackId());
+
+        // Note: We can't use getUniqueRollbackInfoForPackage for the apex,
+        // because we can't uninstall the apex (b/123667725), which means
+        // there's no way to clear info about rollbacks from previous tests
+        // run on the device. Look up the info by rollback id instead.
+        RollbackInfo committed = null;
+        for (RollbackInfo info : rm.getRecentlyCommittedRollbacks()) {
+            if (info.getRollbackId() == rollback.getRollbackId()) {
+                assertNull(committed);
+                committed = info;
+                break;
+            }
+        }
+        assertRollbackInfoEquals(TEST_APEX_PKG, 2, 1, committed);
+        assertTrue(committed.isStaged());
+        assertNotEquals(-1, committed.getCommittedSessionId());
+
+        RollbackTestUtils.waitForSessionReady(committed.getCommittedSessionId());
+
+        // The apex should not be rolled back until after reboot.
+        assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+
+        // At this point, the host test driver will reboot the device and run
+        // testApexOnlyConfirmRollback().
+    }
+
+    /**
+     * Test rollbacks of staged installs involving only apks.
+     * Confirm rollback phase.
+     */
+    @Test
+    public void testApexOnlyConfirmRollback() throws Exception {
+        assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APEX_PKG));
+    }
 }
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 6cb0dd0..24a51dc 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -34,7 +34,7 @@
      * Runs the given phase of a test by calling into the device.
      * Throws an exception if the test phase fails.
      * <p>
-     * For example, <code>runPhase("testBasicEnableRollback");</code>
+     * For example, <code>runPhase("testApkOnlyEnableRollback");</code>
      */
     private void runPhase(String phase) throws Exception {
         assertTrue(runDeviceTests("com.android.tests.rollback",
@@ -43,14 +43,28 @@
     }
 
     /**
-     * Tests staged rollbacks.
+     * Tests staged rollbacks involving only apks.
      */
     @Test
-    public void testBasic() throws Exception {
-        runPhase("testBasicEnableRollback");
+    public void testApkOnly() throws Exception {
+        runPhase("testApkOnlyEnableRollback");
         getDevice().reboot();
-        runPhase("testBasicCommitRollback");
+        runPhase("testApkOnlyCommitRollback");
         getDevice().reboot();
-        runPhase("testBasicConfirmRollback");
+        runPhase("testApkOnlyConfirmRollback");
+    }
+
+    /**
+     * Tests staged rollbacks involving only apex.
+     */
+    @Test
+    public void testApexOnly() throws Exception {
+        runPhase("testApexOnlyPrepareApex");
+        getDevice().reboot();
+        runPhase("testApexOnlyEnableRollback");
+        getDevice().reboot();
+        runPhase("testApexOnlyCommitRollback");
+        getDevice().reboot();
+        runPhase("testApexOnlyConfirmRollback");
     }
 }
diff --git a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
index 7a5e732..e2a4c26 100644
--- a/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
+++ b/tests/UsageStatsPerfTests/src/com/android/frameworks/perftests/usage/tests/UsageStatsDatabasePerfTest.java
@@ -18,7 +18,6 @@
 
 import static junit.framework.Assert.assertEquals;
 
-import android.app.usage.EventList;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager;
 import android.content.Context;
@@ -84,9 +83,6 @@
 
     private static void populateIntervalStats(IntervalStats intervalStats, int packageCount,
             int eventsPerPackage) {
-        if (intervalStats.events == null) {
-            intervalStats.events = new EventList();
-        }
         for (int pkg = 0; pkg < packageCount; pkg++) {
             UsageEvents.Event event = new UsageEvents.Event();
             event.mPackage = "fake.package.name" + pkg;